diff --git a/CMakeLists.txt b/CMakeLists.txt
index 74fd74d66b31508df78f68ce00e8f59b3db361e2..5026b4433983cfec600012e73a7f9f3d3f20ac29 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -143,10 +143,11 @@ add_subdirectory ( Framework )
 
 include_directories ( Framework/Kernel/inc )
 include_directories ( Framework/HistogramData/inc )
+include_directories ( Framework/Indexing/inc )
 include_directories ( Framework/Geometry/inc )
 include_directories ( Framework/API/inc )
 
-set ( CORE_MANTIDLIBS Kernel HistogramData Geometry API )
+set ( CORE_MANTIDLIBS Kernel HistogramData Indexing Geometry API )
 
 if (ENABLE_MANTIDPLOT)
   # Add a target for all GUI tests
@@ -269,18 +270,19 @@ if ( ENABLE_CPACK )
       # OCE
       set( CPACK_RPM_PACKAGE_REQUIRES "${CPACK_RPM_PACKAGE_REQUIRES},OCE-draw,OCE-foundation,OCE-modeling,OCE-ocaf,OCE-visualization")
       set ( CPACK_RPM_PACKAGE_REQUIRES "${CPACK_RPM_PACKAGE_REQUIRES},poco-crypto,poco-data,poco-mysql,poco-sqlite,poco-odbc,poco-util,poco-xml,poco-zip,poco-net,poco-netssl,poco-foundation,PyQt4,sip" )
-      set ( CPACK_RPM_PACKAGE_REQUIRES "${CPACK_RPM_PACKAGE_REQUIRES},python-six,python-ipython >= 1.1.0,python-ipython-notebook" )
-      # scipy & matplotlib
-      set ( CPACK_RPM_PACKAGE_REQUIRES "${CPACK_RPM_PACKAGE_REQUIRES},scipy,python-matplotlib" )
+      set ( CPACK_RPM_PACKAGE_REQUIRES "${CPACK_RPM_PACKAGE_REQUIRES},python-six,python-ipython >= 1.1.0,python-ipython-notebook,PyYAML" )
+      # scipy
+      set ( CPACK_RPM_PACKAGE_REQUIRES "${CPACK_RPM_PACKAGE_REQUIRES},scipy" )
       set ( CPACK_RPM_PACKAGE_REQUIRES "${CPACK_RPM_PACKAGE_REQUIRES},mxml,hdf,hdf5,jsoncpp >= 0.7.0" )
 
       if( "${UNIX_CODENAME}" MATCHES "Santiago" )
         # On RHEL6 we have to use an updated qscintilla to fix an auto complete bug
-        set ( CPACK_RPM_PACKAGE_REQUIRES "${CPACK_RPM_PACKAGE_REQUIRES} qscintilla >= 2.4.6, boost157" )
+        set ( CPACK_RPM_PACKAGE_REQUIRES "${CPACK_RPM_PACKAGE_REQUIRES} qscintilla >= 2.4.6, boost157,python-matplotlib" )
         # On RHEL6 we are using SCL packages for Qt
         set ( CPACK_RPM_PACKAGE_REQUIRES "${CPACK_RPM_PACKAGE_REQUIRES},scl-utils,mantidlibs34,mantidlibs34-runtime,mantidlibs34-qt,mantidlibs34-qt-x11,mantidlibs34-qt-webkit,mantidlibs34-qwt5-qt4" )
       else()
-        set ( CPACK_RPM_PACKAGE_REQUIRES "${CPACK_RPM_PACKAGE_REQUIRES} qscintilla,qwt5-qt4,python-matplotlib-qt4,boost >= 1.53.0" )
+        # Require matplotlib >= 1.5 to fix bug in latex rendering
+        set ( CPACK_RPM_PACKAGE_REQUIRES "${CPACK_RPM_PACKAGE_REQUIRES} qscintilla,qwt5-qt4,python2-matplotlib-qt4 >= 1.5.2,boost >= 1.53.0" )
       endif()
 
       # Add software collections for RHEL
@@ -320,7 +322,8 @@ if ( ENABLE_CPACK )
                            "python-scipy,"
                            "libtbb2,"
                            "libpocofoundation${POCO_SOLIB_VERSION},libpocoutil${POCO_SOLIB_VERSION},libpoconet${POCO_SOLIB_VERSION},libpoconetssl${POCO_SOLIB_VERSION},libpococrypto${POCO_SOLIB_VERSION},libpocoxml${POCO_SOLIB_VERSION},"
-                           "python-pycifrw (>= 4.2.1)" )
+                           "python-pycifrw (>= 4.2.1),"
+                           "python-yaml")
         set ( PERFTOOLS_DEB_PACKAGE "libgoogle-perftools4 (>= 1.7)" )
         if( "${UNIX_CODENAME}" STREQUAL "xenial")
             list ( APPEND DEPENDS_LIST ", libhdf5-cpp-11,libnexus0v5 (>= 4.3),libjsoncpp1,libqscintilla2-12v5, libmuparser2v5,libqwtplot3d-qt4-0v5,libgsl2,liboce-foundation10,liboce-modeling10")
diff --git a/Framework/API/CMakeLists.txt b/Framework/API/CMakeLists.txt
index f5a744ee9f4f915b35643cbbe96e4f1895f0a045..aabd85cc6cee8326e244834b5f2a4a5de15512d4 100644
--- a/Framework/API/CMakeLists.txt
+++ b/Framework/API/CMakeLists.txt
@@ -53,6 +53,7 @@ set ( SRC_FILES
 	src/HistogramValidator.cpp
 	src/HistoryItem.cpp
 	src/HistoryView.cpp
+	src/HistoWorkspace.cpp
 	src/IDomainCreator.cpp
 	src/IEventList.cpp
 	src/IEventWorkspace.cpp
@@ -87,6 +88,7 @@ set ( SRC_FILES
 	src/LatticeDomain.cpp
 	src/LinearScale.cpp
 	src/LiveListenerFactory.cpp
+	src/LogFilterGenerator.cpp
 	src/LogManager.cpp
 	src/LogarithmScale.cpp
 	src/MDGeometry.cpp
@@ -100,6 +102,7 @@ set ( SRC_FILES
 	src/MultipleExperimentInfos.cpp
 	src/MultipleFileProperty.cpp
 	src/NearestNeighbourInfo.cpp
+	src/NearestNeighbours.cpp
 	src/NotebookBuilder.cpp
 	src/NotebookWriter.cpp
 	src/NullCoordTransform.cpp
@@ -111,6 +114,7 @@ set ( SRC_FILES
 	src/PeakFunctionIntegrator.cpp
 	src/Progress.cpp
 	src/Projection.cpp
+	src/PropertyWithValue.cpp
 	src/RawCountValidator.cpp
 	src/RefAxis.cpp
 	src/RemoteJobManagerFactory.cpp
@@ -205,6 +209,7 @@ set ( INC_FILES
 	inc/MantidAPI/GridDomain.h
 	inc/MantidAPI/GridDomain1D.h
 	inc/MantidAPI/GroupingLoader.h
+	inc/MantidAPI/HistoWorkspace.h
 	inc/MantidAPI/HistogramValidator.h
 	inc/MantidAPI/HistoryItem.h
 	inc/MantidAPI/HistoryView.h
@@ -269,6 +274,7 @@ set ( INC_FILES
 	inc/MantidAPI/LatticeDomain.h
 	inc/MantidAPI/LinearScale.h
 	inc/MantidAPI/LiveListenerFactory.h
+	inc/MantidAPI/LogFilterGenerator.h
 	inc/MantidAPI/LogManager.h
 	inc/MantidAPI/LogarithmScale.h
 	inc/MantidAPI/MDGeometry.h
@@ -284,6 +290,7 @@ set ( INC_FILES
 	inc/MantidAPI/MultipleExperimentInfos.h
 	inc/MantidAPI/MultipleFileProperty.h
 	inc/MantidAPI/NearestNeighbourInfo.h
+        inc/MantidAPI/NearestNeighbours.h
 	inc/MantidAPI/NotebookBuilder.h
 	inc/MantidAPI/NotebookWriter.h
 	inc/MantidAPI/NullCoordTransform.h
@@ -324,6 +331,7 @@ set ( INC_FILES
 	inc/MantidAPI/WorkspaceHistory.h
 	inc/MantidAPI/WorkspaceOpOverloads.h
 	inc/MantidAPI/WorkspaceProperty.h
+	inc/MantidAPI/WorkspaceProperty.tcc
 	inc/MantidAPI/WorkspaceUnitValidator.h
 	inc/MantidAPI/Workspace_fwd.h
 )
@@ -386,6 +394,7 @@ set ( TEST_FILES
 	InstrumentValidatorTest.h
 	LatticeDomainTest.h
 	LiveListenerFactoryTest.h
+	LogFilterGeneratorTest.h
 	LogManagerTest.h
 	MDGeometryTest.h
 	MatrixWorkspaceMDIteratorTest.h
@@ -397,6 +406,7 @@ set ( TEST_FILES
 	MultipleExperimentInfosTest.h
 	MultipleFilePropertyTest.h
 	NearestNeighbourInfoTest.h
+	NearestNeighboursTest.h
 	NotebookBuilderTest.h
 	NotebookWriterTest.h
 	NumericAxisTest.h
diff --git a/Framework/API/inc/MantidAPI/Column.h b/Framework/API/inc/MantidAPI/Column.h
index f21d28e0702168ea4ef7897088fe520163b965f9..d5ea4e097c24e7ecba277785d1eb76d835456056 100644
--- a/Framework/API/inc/MantidAPI/Column.h
+++ b/Framework/API/inc/MantidAPI/Column.h
@@ -91,6 +91,12 @@ public:
     UNUSED_ARG(index);
   }
 
+  /// Read in from stream and set the value at the given index
+  virtual void read(const size_t index, std::istream &in) {
+    UNUSED_ARG(index)
+    UNUSED_ARG(in)
+  }
+
   /// Specialized type check
   virtual bool isBool() const = 0;
 
diff --git a/Framework/API/inc/MantidAPI/CompositeFunction.h b/Framework/API/inc/MantidAPI/CompositeFunction.h
index bf3053b02fd003e18cddf4ec8ebed1424b4a4908..4a9ebb6f1aeb058aad50d5be71c685423039df35 100644
--- a/Framework/API/inc/MantidAPI/CompositeFunction.h
+++ b/Framework/API/inc/MantidAPI/CompositeFunction.h
@@ -150,10 +150,10 @@ public:
   /// Get the tie of i-th parameter
   ParameterTie *getTie(size_t i) const override;
   /// Add a new tie
-  void addTie(ParameterTie *tie) override;
+  void addTie(std::unique_ptr<ParameterTie> tie) override;
 
   /// Overwrite IFunction methods
-  void addConstraint(IConstraint *ic) override;
+  void addConstraint(std::unique_ptr<IConstraint> ic) override;
   /// Get constraint of i-th parameter
   IConstraint *getConstraint(size_t i) const override;
   /// Prepare function for a fit
diff --git a/Framework/API/inc/MantidAPI/DetectorInfo.h b/Framework/API/inc/MantidAPI/DetectorInfo.h
index 850eb4e37fd11ac0d880c5551f5dcf79e637d64e..1a949421085e4f2568831ce2c2dd122c0c0d3b59 100644
--- a/Framework/API/inc/MantidAPI/DetectorInfo.h
+++ b/Framework/API/inc/MantidAPI/DetectorInfo.h
@@ -13,6 +13,9 @@
 
 namespace Mantid {
 using detid_t = int32_t;
+namespace Beamline {
+class DetectorInfo;
+}
 namespace Geometry {
 class IComponent;
 class IDetector;
@@ -30,8 +33,10 @@ class SpectrumInfo;
   DetectorInfo provides easy access to commonly used parameters of individual
   detectors, such as mask and monitor flags, L1, L2, and 2-theta.
 
-  This class is thread safe with OpenMP BUT NOT WITH ANY OTHER THREADING LIBRARY
-  such as Poco threads or Intel TBB.
+  This class is thread safe for read operations (const access) with OpenMP BUT
+  NOT WITH ANY OTHER THREADING LIBRARY such as Poco threads or Intel TBB. There
+  are no thread-safety guarantees for write operations (non-const access). Reads
+  concurrent with writes or concurrent writes are not allowed.
 
 
   @author Simon Heybrock
@@ -60,9 +65,14 @@ class SpectrumInfo;
 */
 class MANTID_API_DLL DetectorInfo {
 public:
-  DetectorInfo(boost::shared_ptr<const Geometry::Instrument> instrument,
+  DetectorInfo(Beamline::DetectorInfo &detectorInfo,
+               boost::shared_ptr<const Geometry::Instrument> instrument,
                Geometry::ParameterMap *pmap = nullptr);
 
+  DetectorInfo &operator=(const DetectorInfo &rhs);
+
+  size_t size() const;
+
   bool isMonitor(const size_t index) const;
   bool isMasked(const size_t index) const;
   double l2(const size_t index) const;
@@ -71,12 +81,17 @@ public:
   Kernel::V3D position(const size_t index) const;
   Kernel::Quat rotation(const size_t index) const;
 
+  void setMasked(const size_t index, bool masked);
+  void clearMaskFlags();
+
   void setPosition(const size_t index, const Kernel::V3D &position);
   void setRotation(const size_t index, const Kernel::Quat &rotation);
 
   void setPosition(const Geometry::IComponent &comp, const Kernel::V3D &pos);
   void setRotation(const Geometry::IComponent &comp, const Kernel::Quat &rot);
 
+  const Geometry::IDetector &detector(const size_t index) const;
+
   // This does not really belong into DetectorInfo, but it seems to be useful
   // while Instrument-2.0 does not exist.
   Kernel::V3D sourcePosition() const;
@@ -85,6 +100,7 @@ public:
 
   const std::vector<detid_t> &detectorIDs() const;
   /// Returns the index of the detector with the given detector ID.
+  /// This will throw an out of range exception if the detector does not exist.
   size_t indexOf(const detid_t id) const { return m_detIDToIndex.at(id); }
 
   friend class SpectrumInfo;
@@ -108,6 +124,9 @@ private:
   void doCacheSample() const;
   void cacheL1() const;
 
+  /// Reference to the actual DetectorInfo object (non-wrapping part).
+  Beamline::DetectorInfo &m_detectorInfo;
+
   Geometry::ParameterMap *m_pmap;
   boost::shared_ptr<const Geometry::Instrument> m_instrument;
   std::vector<detid_t> m_detectorIDs;
diff --git a/Framework/API/inc/MantidAPI/ExperimentInfo.h b/Framework/API/inc/MantidAPI/ExperimentInfo.h
index cd7a85e8171a4775e000dfdb7a625989f830139b..23a67104bcad2d1c9099eb962fd0ff98ed8681e8 100644
--- a/Framework/API/inc/MantidAPI/ExperimentInfo.h
+++ b/Framework/API/inc/MantidAPI/ExperimentInfo.h
@@ -16,6 +16,9 @@ namespace Mantid {
 namespace Kernel {
 class Property;
 }
+namespace Beamline {
+class DetectorInfo;
+}
 namespace Geometry {
 class ParameterMap;
 class XMLInstrumentParameter;
@@ -50,106 +53,99 @@ public:
   virtual ExperimentInfo *cloneExperimentInfo() const;
 
   /// Returns a string description of the object
-  virtual const std::string toString() const;
+  const std::string toString() const;
 
   /// Instrument accessors
   void setInstrument(const Geometry::Instrument_const_sptr &instr);
   /// Returns the parameterized instrument
-  virtual Geometry::Instrument_const_sptr getInstrument() const;
+  Geometry::Instrument_const_sptr getInstrument() const;
 
   /// Returns the set of parameters modifying the base instrument
   /// (const-version)
-  virtual const Geometry::ParameterMap &instrumentParameters() const;
+  const Geometry::ParameterMap &instrumentParameters() const;
   /// Returns a modifiable set of instrument parameters
-  virtual Geometry::ParameterMap &instrumentParameters();
+  Geometry::ParameterMap &instrumentParameters();
   /// Const version
-  virtual const Geometry::ParameterMap &constInstrumentParameters() const;
+  const Geometry::ParameterMap &constInstrumentParameters() const;
   // Add parameters to the instrument parameter map
-  virtual void populateInstrumentParameters();
+  void populateInstrumentParameters();
 
-  /// Replaces current parameter map with copy of given map
-  virtual void replaceInstrumentParameters(const Geometry::ParameterMap &pmap);
-  /// exchange contents of current parameter map with contents of other map)
-  virtual void swapInstrumentParameters(Geometry::ParameterMap &pmap);
+  void replaceInstrumentParameters(const Geometry::ParameterMap &pmap);
+  void swapInstrumentParameters(Geometry::ParameterMap &pmap);
 
   /// Cache a lookup of grouped detIDs to member IDs
-  virtual void cacheDetectorGroupings(const det2group_map &mapping);
+  void cacheDetectorGroupings(const det2group_map &mapping);
   /// Returns the detector IDs that make up the group that this ID is part of
-  virtual const std::vector<detid_t> &
-  getGroupMembers(const detid_t detID) const;
+  const std::set<detid_t> &getGroupMembers(const detid_t detID) const;
   /// Get a detector or detector group from an ID
-  virtual Geometry::IDetector_const_sptr
-  getDetectorByID(const detid_t detID) const;
+  Geometry::IDetector_const_sptr getDetectorByID(const detid_t detID) const;
 
   /// Set an object describing the source properties and take ownership
-  virtual void setModeratorModel(ModeratorModel *source);
+  void setModeratorModel(ModeratorModel *source);
   /// Returns a reference to the source properties object
-  virtual ModeratorModel &moderatorModel() const;
+  ModeratorModel &moderatorModel() const;
 
   /// Set a chopper description specified by index where 0 is closest to the
   /// source
-  virtual void setChopperModel(ChopperModel *chopper, const size_t index = 0);
+  void setChopperModel(ChopperModel *chopper, const size_t index = 0);
   /// Returns a reference to a chopper description
-  virtual ChopperModel &chopperModel(const size_t index = 0) const;
+  ChopperModel &chopperModel(const size_t index = 0) const;
 
   /// Sample accessors
-  virtual const Sample &sample() const;
+  const Sample &sample() const;
   /// Writable version of the sample object
-  virtual Sample &mutableSample();
+  Sample &mutableSample();
 
   /// Run details object access
-  virtual const Run &run() const;
+  const Run &run() const;
   /// Writable version of the run object
-  virtual Run &mutableRun();
+  Run &mutableRun();
   /// Access a log for this experiment.
-  virtual Kernel::Property *getLog(const std::string &log) const;
+  Kernel::Property *getLog(const std::string &log) const;
   /// Access a single value from a log for this experiment.
-  virtual double getLogAsSingleValue(const std::string &log) const;
+  double getLogAsSingleValue(const std::string &log) const;
 
   /// Utility method to get the run number
-  virtual int getRunNumber() const;
+  int getRunNumber() const;
   /// Returns the emode for this run
-  virtual Kernel::DeltaEMode::Type getEMode() const;
+  Kernel::DeltaEMode::Type getEMode() const;
   /// Easy access to the efixed value for this run & detector ID
-  virtual double getEFixed(const detid_t detID) const;
+  double getEFixed(const detid_t detID) const;
   /// Easy access to the efixed value for this run & optional detector
-  virtual double
-  getEFixed(const Geometry::IDetector_const_sptr
-                detector = Geometry::IDetector_const_sptr()) const;
+  double getEFixed(const Geometry::IDetector_const_sptr detector =
+                       Geometry::IDetector_const_sptr()) const;
   /// Set the efixed value for a given detector ID
-  virtual void setEFixed(const detid_t detID, const double value);
+  void setEFixed(const detid_t detID, const double value);
 
   /// Saves this experiment description to the open NeXus file
-  virtual void saveExperimentInfoNexus(::NeXus::File *file) const;
+  void saveExperimentInfoNexus(::NeXus::File *file) const;
   /// Loads an experiment description from the open NeXus file
-  virtual void loadExperimentInfoNexus(const std::string &nxFilename,
-                                       ::NeXus::File *file,
-                                       std::string &parameterStr);
+  void loadExperimentInfoNexus(const std::string &nxFilename,
+                               ::NeXus::File *file, std::string &parameterStr);
   /// Load the instrument from an open NeXus file.
-  virtual void loadInstrumentInfoNexus(const std::string &nxFilename,
-                                       ::NeXus::File *file,
-                                       std::string &parameterStr);
+  void loadInstrumentInfoNexus(const std::string &nxFilename,
+                               ::NeXus::File *file, std::string &parameterStr);
   /// Load the instrument from an open NeXus file without reading any parameters
-  virtual void loadInstrumentInfoNexus(const std::string &nxFilename,
-                                       ::NeXus::File *file);
+  void loadInstrumentInfoNexus(const std::string &nxFilename,
+                               ::NeXus::File *file);
   /// Load instrument parameters from an open Nexus file in Instument group if
   /// found there
-  virtual void loadInstrumentParametersNexus(::NeXus::File *file,
-                                             std::string &parameterStr);
+  void loadInstrumentParametersNexus(::NeXus::File *file,
+                                     std::string &parameterStr);
 
   /// Load the sample and log info from an open NeXus file.
-  virtual void loadSampleAndLogInfoNexus(::NeXus::File *file);
+  void loadSampleAndLogInfoNexus(::NeXus::File *file);
   /// Populate the parameter map given a string
-  virtual void readParameterMap(const std::string &parameterStr);
+  void readParameterMap(const std::string &parameterStr);
 
   /// Returns the start date for this experiment (or current time if no info
   /// available)
-  virtual std::string getWorkspaceStartDate() const;
+  std::string getWorkspaceStartDate() const;
 
   // run/experiment stat time if available, empty otherwise
-  virtual std::string getAvailableWorkspaceStartDate() const;
+  std::string getAvailableWorkspaceStartDate() const;
   // run end time if available, empty otherwise
-  virtual std::string getAvailableWorkspaceEndDate() const;
+  std::string getAvailableWorkspaceEndDate() const;
 
   /// Utility to retrieve the validity dates for the given IDF
   static void getValidFromTo(const std::string &IDFfilename,
@@ -162,7 +158,13 @@ public:
   const DetectorInfo &detectorInfo() const;
   DetectorInfo &mutableDetectorInfo();
 
+  virtual size_t numberOfDetectorGroups() const;
+  virtual const std::set<detid_t> &detectorIDsInGroup(const size_t index) const;
+
 protected:
+  /// Called as the first operation of most public methods.
+  virtual void populateIfNotLoaded() const;
+
   /// Called when instrument or parameter map is reset to notify child classes.
   virtual void invalidateInstrumentReferences() const {}
 
@@ -201,11 +203,16 @@ private:
   // Loads the xml from an instrument file with some basic error handling
   std::string loadInstrumentXML(const std::string &filename);
   /// Detector grouping information
-  det2group_map m_detgroups;
+  mutable std::vector<std::set<detid_t>> m_detgroups;
+  mutable std::unordered_map<detid_t, size_t> m_det2group;
+  void cacheDefaultDetectorGrouping() const; // Not thread-safe
+  mutable std::once_flag m_defaultDetectorGroupingCached;
+
   /// Mutex to protect against cow_ptr copying
   mutable std::recursive_mutex m_mutex;
 
-  mutable std::unique_ptr<DetectorInfo> m_detectorInfo;
+  boost::shared_ptr<Beamline::DetectorInfo> m_detectorInfo;
+  mutable std::unique_ptr<DetectorInfo> m_detectorInfoWrapper;
   mutable std::mutex m_detectorInfoMutex;
 };
 
diff --git a/Framework/API/inc/MantidAPI/FileBackedExperimentInfo.h b/Framework/API/inc/MantidAPI/FileBackedExperimentInfo.h
index 82e71fb43e54e5c082fe435485756d92558f95b9..22cc12187332212f8072d10868cda35ea9c04435 100644
--- a/Framework/API/inc/MantidAPI/FileBackedExperimentInfo.h
+++ b/Framework/API/inc/MantidAPI/FileBackedExperimentInfo.h
@@ -1,8 +1,6 @@
 #ifndef MANTID_API_FILEBACKEDEXPERIMENTINFO_H_
 #define MANTID_API_FILEBACKEDEXPERIMENTINFO_H_
-//-----------------------------------------------------------------------------
-// Includes
-//-----------------------------------------------------------------------------
+
 #include "MantidAPI/DllConfig.h"
 #include "MantidAPI/ExperimentInfo.h"
 
@@ -36,69 +34,12 @@ namespace API {
   */
 class MANTID_API_DLL FileBackedExperimentInfo : public ExperimentInfo {
 public:
-  /// Constructor
   FileBackedExperimentInfo(const std::string &filename,
                            const std::string &nxpath);
-
   ExperimentInfo *cloneExperimentInfo() const override;
 
-  const std::string toString() const override;
-
-  Geometry::Instrument_const_sptr getInstrument() const override;
-
-  const Geometry::ParameterMap &instrumentParameters() const override;
-
-  Geometry::ParameterMap &instrumentParameters() override;
-
-  const Geometry::ParameterMap &constInstrumentParameters() const override;
-
-  void populateInstrumentParameters() override;
-
-  void replaceInstrumentParameters(const Geometry::ParameterMap &pmap) override;
-
-  void swapInstrumentParameters(Geometry::ParameterMap &pmap) override;
-
-  void cacheDetectorGroupings(const det2group_map &mapping) override;
-
-  const std::vector<detid_t> &
-  getGroupMembers(const detid_t detID) const override;
-
-  Geometry::IDetector_const_sptr
-  getDetectorByID(const detid_t detID) const override;
-
-  void setModeratorModel(ModeratorModel *source) override;
-
-  ModeratorModel &moderatorModel() const override;
-
-  void setChopperModel(ChopperModel *chopper, const size_t index = 0) override;
-
-  ChopperModel &chopperModel(const size_t index = 0) const override;
-
-  const Sample &sample() const override;
-
-  Sample &mutableSample() override;
-
-  const Run &run() const override;
-
-  Run &mutableRun() override;
-
-  Kernel::Property *getLog(const std::string &log) const override;
-
-  double getLogAsSingleValue(const std::string &log) const override;
-
-  int getRunNumber() const override;
-
-  Kernel::DeltaEMode::Type getEMode() const override;
-
-  double getEFixed(const detid_t detID) const override;
-
-  double getEFixed(const Geometry::IDetector_const_sptr detector =
-                       Geometry::IDetector_const_sptr()) const override;
-
-  void setEFixed(const detid_t detID, const double value) override;
-
 private:
-  void populateIfNotLoaded() const;
+  void populateIfNotLoaded() const override;
   void populateFromFile() const;
 
   mutable bool m_loaded;
diff --git a/Framework/API/inc/MantidAPI/FunctionDomain1D.h b/Framework/API/inc/MantidAPI/FunctionDomain1D.h
index 8db1c56b83cb02be26097677633f0b41dd02521d..b1482e0b667f87ea67dff99034c4478c115283ff 100644
--- a/Framework/API/inc/MantidAPI/FunctionDomain1D.h
+++ b/Framework/API/inc/MantidAPI/FunctionDomain1D.h
@@ -59,11 +59,15 @@ public:
   const double *getPointerAt(size_t i) const { return m_data + i; }
   /// Convert to a vector
   std::vector<double> toVector() const;
+  /// Set a peak redius to pass to peak functions.
+  void setPeakRadius(int radius);
+  /// Get the peak radius.
+  int getPeakRadius() const;
 
 protected:
   /// Protected constructor, shouldn't be created directly. Use
   /// FunctionDomain1DView instead.
-  FunctionDomain1D(const double *x, size_t n) : m_data(x), m_n(n) {}
+  FunctionDomain1D(const double *x, size_t n);
   /// Reset the pointer and size of the domain
   void resetData(const double *x, size_t n) {
     m_data = x;
@@ -71,8 +75,12 @@ protected:
   }
 
 private:
-  const double *m_data; ///< pointer to the start of the domain data
-  size_t m_n;           ///< size of the data
+  /// pointer to the start of the domain data
+  const double *m_data;
+  /// size of the data
+  size_t m_n;
+  /// A peak radius that IPeakFunctions should use
+  int m_peakRadius;
 };
 
 /**
diff --git a/Framework/API/inc/MantidAPI/FunctionParameterDecorator.h b/Framework/API/inc/MantidAPI/FunctionParameterDecorator.h
index 700242ddd4cfd655c71ca7772e3510eb7d772484..2ad22fbcc8956be035e59af2402f91f92f6dbe83 100644
--- a/Framework/API/inc/MantidAPI/FunctionParameterDecorator.h
+++ b/Framework/API/inc/MantidAPI/FunctionParameterDecorator.h
@@ -117,8 +117,8 @@ public:
   bool hasAttribute(const std::string &attName) const override;
 
   /// Tie a parameter of decorated function to other parameters (or a constant).
-  ParameterTie *tie(const std::string &parName, const std::string &expr,
-                    bool isDefault = false) override;
+  void tie(const std::string &parName, const std::string &expr,
+           bool isDefault = false) override;
   /// Apply the ties in decorated function.
   void applyTies() override;
   /// Remove all ties of decorated function.
@@ -130,7 +130,7 @@ public:
   ParameterTie *getTie(size_t i) const override;
 
   /// Add a constraint to decorated function.
-  void addConstraint(IConstraint *ic) override;
+  void addConstraint(std::unique_ptr<IConstraint> ic) override;
   /// Get constraint of i-th parameter of decorated function.
   IConstraint *getConstraint(size_t i) const override;
   /// Remove a constraint of decorated function.
@@ -147,7 +147,7 @@ protected:
   void declareParameter(const std::string &name, double initValue,
                         const std::string &description) override;
 
-  void addTie(ParameterTie *tie) override;
+  void addTie(std::unique_ptr<ParameterTie>) override;
 
   virtual void beforeDecoratedFunctionSet(const IFunction_sptr &fn);
   void setDecoratedFunctionPrivate(const IFunction_sptr &fn);
diff --git a/Framework/API/inc/MantidAPI/FunctionValues.h b/Framework/API/inc/MantidAPI/FunctionValues.h
index 115645a16a40f4694f739504fdf497b25a77bfbe..de5cbba735743be3297cdbff926b3ff9be951b04 100644
--- a/Framework/API/inc/MantidAPI/FunctionValues.h
+++ b/Framework/API/inc/MantidAPI/FunctionValues.h
@@ -112,11 +112,12 @@ protected:
   /// buffer
   /// @param to :: Pointer to the buffer, it must be large enough
   void multiply(double *to) const;
-
-  std::vector<double> m_calculated; ///< buffer for calculated values
-  std::vector<double> m_data;       ///< buffer for fit data
-  std::vector<double>
-      m_weights; ///< buffer for fitting weights (reciprocal errors)
+  /// buffer for calculated values
+  std::vector<double> m_calculated;
+  /// buffer for fit data
+  std::vector<double> m_data;
+  /// buffer for fitting weights (reciprocal errors)
+  std::vector<double> m_weights;
 };
 
 /// typedef for a shared pointer
diff --git a/Framework/API/inc/MantidAPI/HistoWorkspace.h b/Framework/API/inc/MantidAPI/HistoWorkspace.h
new file mode 100644
index 0000000000000000000000000000000000000000..1459d231f24d89c685595112d834162aec995057
--- /dev/null
+++ b/Framework/API/inc/MantidAPI/HistoWorkspace.h
@@ -0,0 +1,58 @@
+#ifndef MANTID_API_HISTOWORKSPACE_H_
+#define MANTID_API_HISTOWORKSPACE_H_
+
+#include "MantidAPI/DllConfig.h"
+#include "MantidAPI/MatrixWorkspace.h"
+
+namespace Mantid {
+namespace API {
+
+/** HistoWorkspace is an abstract base class for MatrixWorkspace types that are
+  NOT event workspaces. This type has to exist as a helper for workspace
+  creation: Many algorithms create a new MatrixWorkspace from a parent workspace
+  without keeping the events, but keeping any potential sub type of
+  MatrixWorkspace. HistoWorkspace provides a common base type for all non-event
+  MatrixWorkspaces. See DataObjects/WorkspaceCreation.h for mor details.
+
+  Copyright &copy; 2016 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>
+*/
+class MANTID_API_DLL HistoWorkspace : public MatrixWorkspace {
+public:
+  /// Returns a clone of the workspace
+  std::unique_ptr<HistoWorkspace> clone() const {
+    return std::unique_ptr<HistoWorkspace>(doClone());
+  }
+
+  /// Returns a default-initialized clone of the workspace
+  std::unique_ptr<HistoWorkspace> cloneEmpty() const {
+    return std::unique_ptr<HistoWorkspace>(doCloneEmpty());
+  }
+
+private:
+  HistoWorkspace *doClone() const override = 0;
+  HistoWorkspace *doCloneEmpty() const override = 0;
+};
+
+} // namespace API
+} // namespace Mantid
+
+#endif /* MANTID_API_HISTOWORKSPACE_H_ */
diff --git a/Framework/API/inc/MantidAPI/IEventWorkspace.h b/Framework/API/inc/MantidAPI/IEventWorkspace.h
index d5e415fcc35b4e5eb41029f2d04196339d561bde..fcd06d77672636b1c32d8c844a890cd66f18cb62 100644
--- a/Framework/API/inc/MantidAPI/IEventWorkspace.h
+++ b/Framework/API/inc/MantidAPI/IEventWorkspace.h
@@ -41,6 +41,10 @@ public:
   IEventWorkspace &operator=(const IEventWorkspace &) = delete;
   /// Returns a clone of the workspace
   IEventWorkspace_uptr clone() const { return IEventWorkspace_uptr(doClone()); }
+  /// Returns a default-initialized clone of the workspace
+  IEventWorkspace_uptr cloneEmpty() const {
+    return IEventWorkspace_uptr(doCloneEmpty());
+  }
 
   IEventList &getSpectrum(const size_t index) override = 0;
   const IEventList &getSpectrum(const size_t index) const override = 0;
@@ -71,6 +75,7 @@ protected:
 
 private:
   IEventWorkspace *doClone() const override = 0;
+  IEventWorkspace *doCloneEmpty() const override = 0;
 };
 }
 }
diff --git a/Framework/API/inc/MantidAPI/IFunction.h b/Framework/API/inc/MantidAPI/IFunction.h
index 48aabc80bc3cd8049c57431633c505a5b1f499a2..04e9342df3d8a219fb57886a1be9ff95fbf99fce 100644
--- a/Framework/API/inc/MantidAPI/IFunction.h
+++ b/Framework/API/inc/MantidAPI/IFunction.h
@@ -7,7 +7,6 @@
 #include "MantidAPI/DllConfig.h"
 #include "MantidAPI/FunctionDomain.h"
 #include "MantidAPI/FunctionValues.h"
-#include "MantidAPI/FunctionValues.h"
 #include "MantidAPI/Jacobian.h"
 #include "MantidKernel/Matrix.h"
 #include "MantidKernel/Unit.h"
@@ -318,6 +317,10 @@ public:
         m_chiSquared(0.0) {}
   /// Virtual destructor
   virtual ~IFunction();
+  /// No copying
+  IFunction(const IFunction &) = delete;
+  /// No copying
+  IFunction &operator=(const IFunction &) = delete;
 
   /// Returns the function's name
   virtual std::string name() const = 0;
@@ -450,8 +453,8 @@ public:
   /** @name Ties */
   //@{
   /// Tie a parameter to other parameters (or a constant)
-  virtual ParameterTie *tie(const std::string &parName, const std::string &expr,
-                            bool isDefault = false);
+  virtual void tie(const std::string &parName, const std::string &expr,
+                   bool isDefault = false);
   /// Add several ties
   virtual void addTies(const std::string &ties, bool isDefault = false);
   /// Apply the ties
@@ -465,7 +468,7 @@ public:
   /// Get the tie of i-th parameter
   virtual ParameterTie *getTie(size_t i) const = 0;
   /// Add a new tie. Derived classes must provide storage for ties
-  virtual void addTie(ParameterTie *tie) = 0;
+  virtual void addTie(std::unique_ptr<ParameterTie> tie) = 0;
   //@}
 
   /** @name Constraints */
@@ -473,7 +476,7 @@ public:
   /// Add a list of conatraints from a string
   virtual void addConstraints(const std::string &str, bool isDefault = false);
   /// Add a constraint to function
-  virtual void addConstraint(IConstraint *ic) = 0;
+  virtual void addConstraint(std::unique_ptr<IConstraint> ic) = 0;
   /// Get constraint of i-th parameter
   virtual IConstraint *getConstraint(size_t i) const = 0;
   /// Remove a constraint
@@ -560,6 +563,14 @@ protected:
   /// Store an attribute's value
   void storeAttributeValue(const std::string &name,
                            const API::IFunction::Attribute &value);
+  /// A read-only ("mutable") attribute can be stored in a const method
+  void storeReadOnlyAttribute(const std::string &name,
+                              const API::IFunction::Attribute &value) const;
+
+  /// Write a parameter tie to a string
+  virtual std::string writeTie(size_t iParam) const;
+  /// Write a parameter constraint to a string
+  virtual std::string writeConstraint(size_t iParam) const;
 
   friend class ParameterTie;
   friend class CompositeFunction;
diff --git a/Framework/API/inc/MantidAPI/IFunction1D.h b/Framework/API/inc/MantidAPI/IFunction1D.h
index a84af386955e4be6786aff59123697df2afcc19d..e4fb9302f2543e26a71c4d50fbe8cfecb338b0a8 100644
--- a/Framework/API/inc/MantidAPI/IFunction1D.h
+++ b/Framework/API/inc/MantidAPI/IFunction1D.h
@@ -62,11 +62,11 @@ public:
 
   void function(const FunctionDomain &domain,
                 FunctionValues &values) const override;
+  void functionDeriv(const FunctionDomain &domain, Jacobian &jacobian) override;
+
   virtual void derivative(const FunctionDomain &domain, FunctionValues &values,
                           const size_t order = 1) const;
 
-  void functionDeriv(const FunctionDomain &domain, Jacobian &jacobian) override;
-
   /// Function you want to fit to.
   virtual void function1D(double *out, const double *xValues,
                           const size_t nData) const = 0;
diff --git a/Framework/API/inc/MantidAPI/IMDNode.h b/Framework/API/inc/MantidAPI/IMDNode.h
index 50d3f8cf7c2ad5075bbc50c3f8fbadb70d7eea24..c9c7801bdce3bc22a2ff17acf0a688f55e71925f 100644
--- a/Framework/API/inc/MantidAPI/IMDNode.h
+++ b/Framework/API/inc/MantidAPI/IMDNode.h
@@ -203,10 +203,13 @@ public:
   * @param radiusSquared :: radius^2 below which to integrate
   * @param signal [out] :: set to the integrated signal
   * @param errorSquared [out] :: set to the integrated squared error.
+  * @param innerRadiusSquared :: radius^2 of inner background
    */
-  virtual void integrateSphere(Mantid::API::CoordTransform &radiusTransform,
-                               const coord_t radiusSquared, signal_t &signal,
-                               signal_t &errorSquared) const = 0;
+  virtual void
+  integrateSphere(Mantid::API::CoordTransform &radiusTransform,
+                  const coord_t radiusSquared, signal_t &signal,
+                  signal_t &errorSquared,
+                  const coord_t innerRadiusSquared = 0.0) const = 0;
   /** Find the centroid of all events contained within by doing a weighted
   *average
   * of their coordinates.
diff --git a/Framework/API/inc/MantidAPI/IMDWorkspace.h b/Framework/API/inc/MantidAPI/IMDWorkspace.h
index c13df5c17cb92d4e2838385941af86f8d9f70f88..c851452446b44da13d4f0c99be444f508a32c747 100644
--- a/Framework/API/inc/MantidAPI/IMDWorkspace.h
+++ b/Framework/API/inc/MantidAPI/IMDWorkspace.h
@@ -5,6 +5,7 @@
 #include "MantidAPI/ITableWorkspace_fwd.h"
 #include "MantidAPI/MDGeometry.h"
 #include "MantidAPI/Workspace.h"
+#include "MantidKernel/SpecialCoordinateSystem.h"
 #include <cstdint>
 #include <vector>
 
diff --git a/Framework/API/inc/MantidAPI/IPeakFunction.h b/Framework/API/inc/MantidAPI/IPeakFunction.h
index c5725c8ce59a44609f1e3f76f6a3d93872a23e2f..3636919b41686ed772c00792659cea37e199d881 100644
--- a/Framework/API/inc/MantidAPI/IPeakFunction.h
+++ b/Framework/API/inc/MantidAPI/IPeakFunction.h
@@ -39,6 +39,10 @@ class MANTID_API_DLL IPeakFunction : public IFunctionWithLocation {
 public:
   /// Constructor
   IPeakFunction();
+
+  void function(const FunctionDomain &domain,
+                FunctionValues &values) const override;
+
   /// Returns the peak FWHM
   virtual double fwhm() const = 0;
 
@@ -57,8 +61,11 @@ public:
   /// General implementation of the method for all peaks.
   void functionDeriv1D(Jacobian *out, const double *xValues,
                        const size_t nData) override;
-  /// Set new peak radius
-  static void setPeakRadius(const int &r = 5);
+
+  /// Get the interval on which the peak has all its values above a certain
+  /// level
+  virtual std::pair<double, double>
+  getDomainInterval(double level = DEFAULT_SEARCH_LEVEL) const;
 
   /// Function evaluation method to be implemented in the inherited classes
   virtual void functionLocal(double *out, const double *xValues,
@@ -83,10 +90,14 @@ public:
         "Generic intensity fixing isn't implemented for this function.");
   }
 
-protected:
+private:
+  /// Set new peak radius
+  void setPeakRadius(int r) const;
   /// Defines the area around the centre where the peak values are to be
   /// calculated (in FWHM).
-  static int s_peakRadius;
+  mutable int m_peakRadius;
+  /// The default level for searching a domain interval (getDomainInterval())
+  static constexpr double DEFAULT_SEARCH_LEVEL = 1e-5;
 };
 
 typedef boost::shared_ptr<IPeakFunction> IPeakFunction_sptr;
diff --git a/Framework/API/inc/MantidAPI/IPowderDiffPeakFunction.h b/Framework/API/inc/MantidAPI/IPowderDiffPeakFunction.h
index d9d752943c27d5d35c02bcdcb77ea54b02f8a1a3..c9c0cedae08467bb3d730a42d180f906d6316a1b 100644
--- a/Framework/API/inc/MantidAPI/IPowderDiffPeakFunction.h
+++ b/Framework/API/inc/MantidAPI/IPowderDiffPeakFunction.h
@@ -1,12 +1,10 @@
 #ifndef MANTID_API_IPOWDERDIFFPEAKFUNCTION_H_
 #define MANTID_API_IPOWDERDIFFPEAKFUNCTION_H_
 
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidAPI/ParamFunction.h"
 #include "MantidAPI/IFunction1D.h"
 #include "MantidGeometry/Crystal/UnitCell.h"
+#include <complex>
 
 namespace Mantid {
 namespace API {
diff --git a/Framework/API/inc/MantidAPI/ImplicitFunctionParameter.h b/Framework/API/inc/MantidAPI/ImplicitFunctionParameter.h
index 4c846f12313be81a78104827e3c6b81f2f729107..f8a5a4bcc7d2bc17494c6f9e50a7bc57eb869aba 100644
--- a/Framework/API/inc/MantidAPI/ImplicitFunctionParameter.h
+++ b/Framework/API/inc/MantidAPI/ImplicitFunctionParameter.h
@@ -66,7 +66,7 @@ public:
 protected:
   bool m_isValid;
 
-  std::string parameterXMLTemplate(std::string valueXMLtext) const {
+  std::string parameterXMLTemplate(const std::string &valueXMLtext) const {
     using namespace Poco::XML;
     AutoPtr<Document> pDoc = new Document;
     AutoPtr<Element> paramElement = pDoc->createElement("Parameter");
diff --git a/Framework/API/inc/MantidAPI/LiveListenerFactory.h b/Framework/API/inc/MantidAPI/LiveListenerFactory.h
index 585c40015e3bcc0d703aa25dca64fca477cd01bf..aab4a9157ab35cf7735562b89bec2da838ab05cf 100644
--- a/Framework/API/inc/MantidAPI/LiveListenerFactory.h
+++ b/Framework/API/inc/MantidAPI/LiveListenerFactory.h
@@ -24,6 +24,7 @@
 #include "MantidKernel/DynamicFactory.h"
 #include "MantidKernel/SingletonHolder.h"
 #include "MantidAPI/ILiveListener.h"
+#include "MantidKernel/LiveListenerInfo.h"
 
 namespace Mantid {
 namespace API {
@@ -51,11 +52,16 @@ class MANTID_API_DLL LiveListenerFactoryImpl
     : public Kernel::DynamicFactory<ILiveListener> {
 public:
   boost::shared_ptr<ILiveListener>
-  create(const std::string &instrumentName, bool connect,
+  create(const std::string &instrumentName, bool connect = false,
+         const Kernel::IPropertyManager *properties = nullptr,
+         const std::string &listenerConnectionName = "") const;
+
+  boost::shared_ptr<ILiveListener>
+  create(const Kernel::LiveListenerInfo &info, bool connect = false,
          const Kernel::IPropertyManager *properties = nullptr) const;
+
   LiveListenerFactoryImpl(const LiveListenerFactoryImpl &) = delete;
   LiveListenerFactoryImpl &operator=(const LiveListenerFactoryImpl &) = delete;
-  bool checkConnection(const std::string &instrumentName) const;
 
 private:
   friend struct Kernel::CreateUsingNew<LiveListenerFactoryImpl>;
diff --git a/Framework/API/inc/MantidAPI/LogFilterGenerator.h b/Framework/API/inc/MantidAPI/LogFilterGenerator.h
new file mode 100644
index 0000000000000000000000000000000000000000..c96124ff111f7ba7599cdfd1a9c6a532d7cecc85
--- /dev/null
+++ b/Framework/API/inc/MantidAPI/LogFilterGenerator.h
@@ -0,0 +1,72 @@
+#ifndef MANTID_API_LOGFILTERGENERATOR_H_
+#define MANTID_API_LOGFILTERGENERATOR_H_
+
+#include "MantidAPI/DllConfig.h"
+#include "MantidAPI/MatrixWorkspace_fwd.h"
+#include "MantidAPI/Run.h"
+#include "MantidKernel/LogFilter.h"
+#include "MantidKernel/Property.h"
+#include <memory>
+
+namespace Mantid {
+namespace API {
+
+/** LogFilterGenerator : utility to generate a LogFilter, to filter by running
+  status or period
+
+  This was refactored out of MantidUI::importNumSeriesLog
+
+  Copyright &copy; 2016 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>
+*/
+class MANTID_API_DLL LogFilterGenerator {
+public:
+  /// Types of filter that can be used
+  enum class FilterType { None, Status, Period, StatusAndPeriod };
+
+  /// Constructor taking workspace
+  LogFilterGenerator(const FilterType filterType,
+                     const Mantid::API::MatrixWorkspace_const_sptr &workspace);
+
+  /// Constructor taking run object
+  LogFilterGenerator(const FilterType filterType, const Mantid::API::Run &run);
+
+  /// Generate log filter from given workspace and log name
+  std::unique_ptr<Mantid::Kernel::LogFilter>
+  generateFilter(const std::string &logName) const;
+
+private:
+  /// Filter log by "running" status
+  void filterByStatus(Mantid::Kernel::LogFilter *filter) const;
+  /// Filter log by period
+  void filterByPeriod(Mantid::Kernel::LogFilter *filter) const;
+  /// Get log data from workspace
+  Mantid::Kernel::Property *getLogData(const std::string &logName) const;
+  /// Type of filter
+  const FilterType m_filterType;
+  /// Run object containing logs
+  const Mantid::API::Run m_run;
+};
+
+} // namespace API
+} // namespace Mantid
+
+#endif /* MANTID_API_LOGFILTERGENERATOR_H_ */
\ No newline at end of file
diff --git a/Framework/API/inc/MantidAPI/LogManager.h b/Framework/API/inc/MantidAPI/LogManager.h
index 40dafc25508edfa303a227fd3af62974ce278288..23d3789cef19e4d739e9771ad892f5d446cc1a81 100644
--- a/Framework/API/inc/MantidAPI/LogManager.h
+++ b/Framework/API/inc/MantidAPI/LogManager.h
@@ -2,11 +2,10 @@
 #define MANTID_API_LOGMANAGER_H_
 
 #include "MantidAPI/DllConfig.h"
-#include "MantidKernel/Cache.h"
 #include "MantidKernel/make_unique.h"
 #include "MantidKernel/PropertyManager.h"
 #include "MantidKernel/Statistics.h"
-#include "MantidKernel/TimeSplitter.h"
+#include <memory>
 #include <vector>
 
 namespace NeXus {
@@ -15,7 +14,10 @@ class File;
 
 namespace Mantid {
 namespace Kernel {
+template <class KEYTYPE, class VALUETYPE> class Cache;
 template <typename TYPE> class TimeSeriesProperty;
+class SplittingInterval;
+typedef std::vector<SplittingInterval> TimeSplitterType;
 }
 
 namespace API {
@@ -50,9 +52,12 @@ namespace API {
 */
 class MANTID_API_DLL LogManager {
 public:
+  LogManager();
+  LogManager(const LogManager &other);
   /// Destructor. Doesn't need to be virtual as long as nothing inherits from
   /// this class.
-  virtual ~LogManager() = default;
+  virtual ~LogManager();
+  LogManager &operator=(const LogManager &other);
 
   //-------------------------------------------------------------
   /// Set the run start and end
@@ -194,11 +199,10 @@ protected:
   static const char *PROTON_CHARGE_LOG_NAME;
 
 private:
-  /// Cache type for single value logs
-  typedef Kernel::Cache<std::pair<std::string, Kernel::Math::StatisticType>,
-                        double> SingleValueCache;
   /// Cache for the retrieved single values
-  mutable SingleValueCache m_singleValueCache;
+  std::unique_ptr<Kernel::Cache<
+      std::pair<std::string, Kernel::Math::StatisticType>, double>>
+      m_singleValueCache;
 };
 /// shared pointer to the logManager base class
 typedef boost::shared_ptr<LogManager> LogManager_sptr;
diff --git a/Framework/API/inc/MantidAPI/MDGeometry.h b/Framework/API/inc/MantidAPI/MDGeometry.h
index cb11fc65e3758eef7f09503d570178991a5e6e15..f8d15c5cbbcc0d41af92bb62706c3bccf384a964 100644
--- a/Framework/API/inc/MantidAPI/MDGeometry.h
+++ b/Framework/API/inc/MantidAPI/MDGeometry.h
@@ -2,16 +2,22 @@
 #define MANTID_API_MDGEOMETRY_H_
 
 #include "MantidKernel/System.h"
+#include "MantidKernel/Matrix.h"
 #include "MantidKernel/VMD.h"
-#include "MantidGeometry/MDGeometry/IMDDimension.h"
-#include "MantidAPI/AnalysisDataService.h"
-#include <Poco/NObserver.h>
+#include "MantidGeometry/MDGeometry/MDTypes.h"
 #include <boost/shared_ptr.hpp>
 
+#include <memory>
+
 namespace Mantid {
+namespace Geometry {
+class IMDDimension;
+}
 namespace API {
 class CoordTransform;
 class IMDWorkspace;
+class MDGeometryNotificationHelper;
+class Workspace;
 
 /** Describes the geometry (i.e. dimensions) of an IMDWorkspace.
  * This defines the dimensions contained in the workspace.
@@ -48,8 +54,8 @@ public:
   MDGeometry();
   MDGeometry(const MDGeometry &other);
   virtual ~MDGeometry();
-  void
-  initGeometry(std::vector<Mantid::Geometry::IMDDimension_sptr> &dimensions);
+  void initGeometry(
+      std::vector<boost::shared_ptr<Geometry::IMDDimension>> &dimensions);
 
   // --------------------------------------------------------------------------------------------
   // These are the main methods for dimensions, that CAN be overridden (e.g. by
@@ -61,7 +67,7 @@ public:
   getDimensionWithId(std::string id) const;
   size_t getDimensionIndexByName(const std::string &name) const;
   size_t getDimensionIndexById(const std::string &id) const;
-  Mantid::Geometry::VecIMDDimension_const_sptr
+  std::vector<boost::shared_ptr<const Geometry::IMDDimension>>
   getNonIntegratedDimensions() const;
   virtual std::vector<coord_t> estimateResolution() const;
 
@@ -129,13 +135,15 @@ public:
   /// Clear original workspaces
   void clearOriginalWorkspaces();
 
+  friend class MDGeometryNotificationHelper;
+
 protected:
   /// Function called when observer objects recieves a notification
-  void deleteNotificationReceived(
-      Mantid::API::WorkspacePreDeleteNotification_ptr notice);
+  void
+  deleteNotificationReceived(const boost::shared_ptr<const Workspace> &deleted);
 
   /// Vector of the dimensions used, in the order X Y Z t, etc.
-  std::vector<Mantid::Geometry::IMDDimension_sptr> m_dimensions;
+  std::vector<boost::shared_ptr<Geometry::IMDDimension>> m_dimensions;
 
   /// Pointer to the original workspace(s), if this workspace is a coordinate
   /// transformation from an original workspace.
@@ -155,12 +163,8 @@ protected:
   std::vector<boost::shared_ptr<const Mantid::API::CoordTransform>>
       m_transforms_ToOriginal;
 
-  /// Poco delete notification observer object
-  Poco::NObserver<MDGeometry, Mantid::API::WorkspacePreDeleteNotification>
-      m_delete_observer;
-
-  /// Set to True when the m_delete_observer is observing workspace deletions.
-  bool m_observingDelete;
+  /// Helper that deals with notifications and observing the ADS
+  std::unique_ptr<MDGeometryNotificationHelper> m_notificationHelper;
 
   /** the matrix which transforms momentums from orthogonal Q-system to
      Orthogonal HKL or non-orthogonal HKL system alighned WRT to arbitrary
diff --git a/Framework/API/inc/MantidAPI/MatrixWorkspace.h b/Framework/API/inc/MantidAPI/MatrixWorkspace.h
index 0530f26da3454c93bf73dbbfae811b8326bf5bc5..0079c1a57c8342033e57030496add9e97db83612 100644
--- a/Framework/API/inc/MantidAPI/MatrixWorkspace.h
+++ b/Framework/API/inc/MantidAPI/MatrixWorkspace.h
@@ -8,11 +8,18 @@
 #include "MantidAPI/IMDWorkspace.h"
 #include "MantidAPI/ISpectrum.h"
 #include "MantidAPI/MatrixWorkspace_fwd.h"
+#include "MantidKernel/EmptyValues.h"
 
 namespace Mantid {
-//----------------------------------------------------------------------------
-// Forward declarations
-//----------------------------------------------------------------------------
+
+namespace Indexing {
+class IndexInfo;
+}
+
+namespace Kernel {
+class DateAndTime;
+}
+
 namespace Geometry {
 class ParameterMap;
 }
@@ -67,9 +74,12 @@ public:
   // axes.
   friend class WorkspaceFactoryImpl;
 
-  /// Initialize
   void initialize(const std::size_t &NVectors, const std::size_t &XLength,
                   const std::size_t &YLength);
+  void initialize(const std::size_t &NVectors,
+                  const HistogramData::Histogram &histogram);
+  void initialize(const Indexing::IndexInfo &indexInfo,
+                  const HistogramData::Histogram &histogram);
 
   MatrixWorkspace &operator=(const MatrixWorkspace &other) = delete;
   /// Delete
@@ -78,6 +88,14 @@ public:
   /// Returns a clone of the workspace
   MatrixWorkspace_uptr clone() const { return MatrixWorkspace_uptr(doClone()); }
 
+  /// Returns a default-initialized clone of the workspace
+  MatrixWorkspace_uptr cloneEmpty() const {
+    return MatrixWorkspace_uptr(doCloneEmpty());
+  }
+
+  const Indexing::IndexInfo &indexInfo() const;
+  void setIndexInfo(const Indexing::IndexInfo &indexInfo);
+
   using IMDWorkspace::toString;
   /// String description of state
   const std::string toString() const override;
@@ -421,9 +439,6 @@ public:
   bool isDistribution() const;
   void setDistribution(bool newValue);
 
-  /// Mask a given workspace index, setting the data and error values to zero
-  void maskWorkspaceIndex(const std::size_t index);
-
   // Methods to set and access masked bins
   void maskBin(const size_t &workspaceIndex, const size_t &binIndex,
                const double &weight = 1.0);
@@ -528,6 +543,10 @@ public:
   // End image methods
   //=====================================================================================
 
+  size_t numberOfDetectorGroups() const override;
+  const std::set<detid_t> &
+  detectorIDsInGroup(const size_t index) const override;
+
 protected:
   /// Protected copy constructor. May be used by childs for cloning.
   MatrixWorkspace(const MatrixWorkspace &other);
@@ -538,6 +557,8 @@ protected:
   /// be overloaded.
   virtual void init(const std::size_t &NVectors, const std::size_t &XLength,
                     const std::size_t &YLength) = 0;
+  virtual void init(const std::size_t &NVectors,
+                    const HistogramData::Histogram &histogram) = 0;
 
   /// Invalidates the commons bins flag.  This is generally called when a method
   /// could allow the X values to be changed.
@@ -550,6 +571,7 @@ protected:
 
 private:
   MatrixWorkspace *doClone() const override = 0;
+  virtual MatrixWorkspace *doCloneEmpty() const = 0;
 
   /// Create an MantidImage instance.
   MantidImage_sptr
@@ -560,6 +582,13 @@ private:
   void setImage(MantidVec &(MatrixWorkspace::*dataVec)(const std::size_t),
                 const MantidImage &image, size_t start, bool parallelExecution);
 
+  // Helper functions for IndexInfo, as a workaround while spectrum numbers and
+  // detector IDs are still stored in ISpectrum.
+  specnum_t spectrumNumber(const size_t index) const;
+  const std::set<detid_t> &detectorIDs(const size_t index) const;
+
+  std::unique_ptr<Indexing::IndexInfo> m_indexInfo;
+
   /// Has this workspace been initialised?
   bool m_isInitialized{false};
 
diff --git a/Framework/API/inc/MantidAPI/MatrixWorkspaceMDIterator.h b/Framework/API/inc/MantidAPI/MatrixWorkspaceMDIterator.h
index afa8aca44fbca153bfb90f2a4f8396494fc71a44..9191b13619941a544f8dec5bcfa50ad6c2183b9e 100644
--- a/Framework/API/inc/MantidAPI/MatrixWorkspaceMDIterator.h
+++ b/Framework/API/inc/MantidAPI/MatrixWorkspaceMDIterator.h
@@ -4,6 +4,7 @@
 #include "MantidKernel/System.h"
 #include "MantidAPI/IMDIterator.h"
 #include "MantidAPI/MatrixWorkspace_fwd.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidGeometry/MDGeometry/MDImplicitFunction.h"
 #include "MantidKernel/cow_ptr.h"
 
@@ -138,6 +139,9 @@ private:
   /// For numeric axes, this is the size of the bin in the vertical direction.
   /// It is 1.0 for spectrum axes
   double m_verticalBinSize;
+
+  /// SpectrumInfo object, used for masking information
+  const SpectrumInfo &m_spectrumInfo;
 };
 
 } // namespace API
diff --git a/Framework/API/inc/MantidAPI/NearestNeighbourInfo.h b/Framework/API/inc/MantidAPI/NearestNeighbourInfo.h
index b184b9e7fff58d67b493084c8d4f3d9ab2ba2e0c..894c8c43e130d3a1b806f36936245fb558966757 100644
--- a/Framework/API/inc/MantidAPI/NearestNeighbourInfo.h
+++ b/Framework/API/inc/MantidAPI/NearestNeighbourInfo.h
@@ -2,12 +2,20 @@
 #define MANTID_API_NEARESTNEIGHBOURINFO_H_
 
 #include "MantidAPI/DllConfig.h"
-#include "MantidGeometry/Instrument/NearestNeighbours.h"
+#include "MantidGeometry/IDTypes.h"
+#include "MantidKernel/V3D.h"
+
+#include <memory>
+#include <map>
 
 namespace Mantid {
+namespace Geometry {
+class IDetector;
+}
 namespace API {
 
 class MatrixWorkspace;
+class NearestNeighbours;
 
 /** NearestNeighbourInfo provides easy access to nearest-neighbour information
   for a workspace.
@@ -38,6 +46,7 @@ public:
   NearestNeighbourInfo(const MatrixWorkspace &workspace,
                        const bool ignoreMaskedDetectors,
                        const int nNeighbours = 8);
+  ~NearestNeighbourInfo();
 
   std::map<specnum_t, Kernel::V3D>
   getNeighbours(const Geometry::IDetector *comp,
@@ -48,7 +57,7 @@ public:
 
 private:
   const MatrixWorkspace &m_workspace;
-  Geometry::NearestNeighbours m_nearestNeighbours;
+  std::unique_ptr<NearestNeighbours> m_nearestNeighbours;
 };
 
 } // namespace API
diff --git a/Framework/Geometry/inc/MantidGeometry/Instrument/NearestNeighbours.h b/Framework/API/inc/MantidAPI/NearestNeighbours.h
similarity index 74%
rename from Framework/Geometry/inc/MantidGeometry/Instrument/NearestNeighbours.h
rename to Framework/API/inc/MantidAPI/NearestNeighbours.h
index 3527a025c4da602a638d75c605b427878eca720a..cbe5525b5624ae76218e498894b212283735bacf 100644
--- a/Framework/Geometry/inc/MantidGeometry/Instrument/NearestNeighbours.h
+++ b/Framework/API/inc/MantidAPI/NearestNeighbours.h
@@ -1,7 +1,7 @@
 #ifndef MANTID_GEOMETRY_INSTRUMENT_NEARESTNEIGHBOURS
 #define MANTID_GEOMETRY_INSTRUMENT_NEARESTNEIGHBOURS
 
-#include "MantidGeometry/DllConfig.h"
+#include "MantidAPI/DllConfig.h"
 #include "MantidGeometry/IDTypes.h"
 #include "MantidKernel/V3D.h"
 // Boost graphing
@@ -13,14 +13,14 @@
 
 namespace Mantid {
 namespace Geometry {
-
 class Instrument;
 class IDetector;
-
-typedef std::unordered_map<specnum_t, std::set<detid_t>>
-    ISpectrumDetectorMapping;
-
+}
+namespace API {
+class SpectrumInfo;
 /**
+ * This class is not intended for direct use. Use NearestNeighbourInfo instead!
+ *
  * This class is used to find the nearest neighbours of a detector in the
  * instrument geometry. This class can be queried through calls to the
  * getNeighbours() function on a Detector object.
@@ -58,17 +58,10 @@ typedef std::unordered_map<specnum_t, std::set<detid_t>>
  *  File change history is stored at: <https://github.com/mantidproject/mantid>
  *  Code Documentation is available at: <http://doxygen.mantidproject.org>
  */
-class MANTID_GEOMETRY_DLL NearestNeighbours {
+class MANTID_API_DLL NearestNeighbours {
 public:
-  /// Constructor with an instrument and a spectra map
-  NearestNeighbours(boost::shared_ptr<const Instrument> instrument,
-                    const ISpectrumDetectorMapping &spectraMap,
-                    bool ignoreMaskedDetectors = false);
-
-  /// Constructor with an instrument and a spectra map and number of neighbours
-  NearestNeighbours(int nNeighbours,
-                    boost::shared_ptr<const Instrument> instrument,
-                    const ISpectrumDetectorMapping &spectraMap,
+  NearestNeighbours(int nNeighbours, const SpectrumInfo &spectrumInfo,
+                    std::vector<specnum_t> spectrumNumbers,
                     bool ignoreMaskedDetectors = false);
 
   // Neighbouring spectra by radius
@@ -79,17 +72,14 @@ public:
   std::map<specnum_t, Mantid::Kernel::V3D> neighbours(specnum_t spectrum) const;
 
 protected:
-  /// Get the spectra associated with all in the instrument
-  std::map<specnum_t, boost::shared_ptr<const IDetector>>
-  getSpectraDetectors(boost::shared_ptr<const Instrument> instrument,
-                      const ISpectrumDetectorMapping &spectraMap);
-
-  /// A pointer the the instrument
-  boost::shared_ptr<const Instrument> m_instrument;
-  /// A reference to the spectra map
-  const ISpectrumDetectorMapping &m_spectraMap;
+  std::vector<size_t> getSpectraDetectors();
 
 private:
+  /// A reference to the SpectrumInfo
+  const SpectrumInfo &m_spectrumInfo;
+  /// Vector of spectrum numbers
+  const std::vector<specnum_t> m_spectrumNumbers;
+
   /// typedef for Graph object used to hold the calculated information
   typedef boost::adjacency_list<
       boost::vecS, boost::vecS, boost::directedS,
@@ -127,14 +117,7 @@ private:
   bool m_bIgnoreMaskedDetectors;
 };
 
-/// Typedef for shared pointer to the NearestNeighbours class
-typedef boost::shared_ptr<Mantid::Geometry::NearestNeighbours>
-    NearestNeighbours_sptr;
-/// Typedef for constant shared pointer to the NearestNeighbours class
-typedef boost::shared_ptr<const Mantid::Geometry::NearestNeighbours>
-    NearestNeighbours_const_sptr;
-
-} // namespace Geometry
+} // namespace API
 } // namespace Mantid
 
 #endif
diff --git a/Framework/API/inc/MantidAPI/ParamFunction.h b/Framework/API/inc/MantidAPI/ParamFunction.h
index 3c452deca2e3e1a2308f07d68ae6d1f7a2bc3a11..21fe0a87fb8b3f753f55a79454b3a8a975640bb9 100644
--- a/Framework/API/inc/MantidAPI/ParamFunction.h
+++ b/Framework/API/inc/MantidAPI/ParamFunction.h
@@ -5,8 +5,9 @@
 // Includes
 //----------------------------------------------------------------------
 #include "MantidAPI/DllConfig.h"
-#include "MantidKernel/Unit.h"
+#include "MantidAPI/IConstraint.h"
 #include "MantidAPI/IFunction.h"
+#include "MantidAPI/ParameterTie.h"
 #include <string>
 #include <vector>
 
@@ -16,8 +17,6 @@ namespace API {
 // Forward declaration
 //----------------------------------------------------------------------
 class Jacobian;
-class ParameterTie;
-class IConstraint;
 /** Implements the part of IFunction interface dealing with parameters. This
    function has parameters of its own
     as opposed to a CompositeFunction which list of parameters consists only of
@@ -111,10 +110,10 @@ public:
   /// Get the tie of i-th parameter
   ParameterTie *getTie(size_t i) const override;
   /// Add a new tie
-  void addTie(ParameterTie *tie) override;
+  void addTie(std::unique_ptr<ParameterTie> tie) override;
 
   /// Add a constraint to function
-  void addConstraint(IConstraint *ic) override;
+  void addConstraint(std::unique_ptr<IConstraint> ic) override;
   /// Get constraint of i-th parameter
   IConstraint *getConstraint(size_t i) const override;
   /// Remove a constraint
@@ -143,9 +142,9 @@ private:
   /// Keeps parameter errors
   std::vector<double> m_errors;
   /// Holds parameter ties as <parameter index,tie pointer>
-  std::vector<ParameterTie *> m_ties;
+  std::vector<std::unique_ptr<ParameterTie>> m_ties;
   /// Holds the constraints added to function
-  std::vector<IConstraint *> m_constraints;
+  std::vector<std::unique_ptr<IConstraint>> m_constraints;
   /// Flags of explicitly set parameters
   std::vector<bool> m_explicitlySet;
   /// parameter descriptions
diff --git a/Framework/API/inc/MantidAPI/PrecompiledHeader.h b/Framework/API/inc/MantidAPI/PrecompiledHeader.h
index fa64968355765c1e9b938ac562bed81e326ccdc9..4869d894bee622cffb880d4809900bf0d5a8e614 100644
--- a/Framework/API/inc/MantidAPI/PrecompiledHeader.h
+++ b/Framework/API/inc/MantidAPI/PrecompiledHeader.h
@@ -14,7 +14,6 @@
 #include "MantidGeometry/IComponent.h"
 #include "MantidGeometry/IDetector.h"
 #include "MantidGeometry/Instrument.h"
-#include "MantidGeometry/Instrument/NearestNeighbours.h"
 
 // STL
 #include <vector>
diff --git a/Framework/API/inc/MantidAPI/Run.h b/Framework/API/inc/MantidAPI/Run.h
index fa919615acc399b65782e3069b0f11f81b141c95..e7112752fe701b7565ba3c51fb9d5cf15a129e36 100644
--- a/Framework/API/inc/MantidAPI/Run.h
+++ b/Framework/API/inc/MantidAPI/Run.h
@@ -3,8 +3,8 @@
 
 #include "MantidAPI/DllConfig.h"
 #include "MantidAPI/LogManager.h"
+#include "MantidKernel/Matrix.h"
 #include "MantidKernel/TimeSplitter.h"
-#include "MantidGeometry/Instrument/Goniometer.h"
 
 #include <vector>
 
@@ -14,6 +14,10 @@ class File;
 
 namespace Mantid {
 
+namespace Geometry {
+class Goniometer;
+}
+
 namespace API {
 
 /**
@@ -46,6 +50,11 @@ namespace API {
 */
 class MANTID_API_DLL Run : public LogManager {
 public:
+  Run();
+  Run(const Run &other);
+  ~Run();
+  Run &operator=(const Run &other);
+
   /// Clone
   boost::shared_ptr<Run> clone();
 
@@ -83,10 +92,10 @@ public:
                      const bool useLogValues);
   /** @return A reference to the const Goniometer object for this run */
   inline const Geometry::Goniometer &getGoniometer() const {
-    return m_goniometer;
+    return *m_goniometer;
   }
   /** @return A reference to the non-const Goniometer object for this run */
-  inline Geometry::Goniometer &mutableGoniometer() { return m_goniometer; }
+  inline Geometry::Goniometer &mutableGoniometer() { return *m_goniometer; }
 
   // Retrieve the goniometer rotation matrix
   const Kernel::DblMatrix &getGoniometerMatrix() const;
@@ -103,7 +112,7 @@ private:
   void calculateGoniometerMatrix();
 
   /// Goniometer for this run
-  Mantid::Geometry::Goniometer m_goniometer;
+  std::unique_ptr<Geometry::Goniometer> m_goniometer;
   /// A set of histograms that can be stored here for future reference
   std::vector<double> m_histoBins;
 
diff --git a/Framework/API/inc/MantidAPI/SpectraDetectorTypes.h b/Framework/API/inc/MantidAPI/SpectraDetectorTypes.h
index a6e1fae0e1c9f9abdaf11da04daf03a7ba2198e7..c21655a2b8c82bb3ec0225a0999aecfa763aea24 100644
--- a/Framework/API/inc/MantidAPI/SpectraDetectorTypes.h
+++ b/Framework/API/inc/MantidAPI/SpectraDetectorTypes.h
@@ -5,7 +5,7 @@
 //------------------------------------------------------------------------------
 #include "MantidGeometry/IDTypes.h"
 #include <unordered_map>
-#include <vector>
+#include <set>
 
 namespace Mantid {
 
@@ -14,7 +14,7 @@ typedef std::unordered_map<specnum_t, size_t> spec2index_map;
 /// Map with key = detector ID, value = workspace index
 typedef std::unordered_map<detid_t, size_t> detid2index_map;
 /// Map single det ID of group to its members
-typedef std::unordered_map<detid_t, std::vector<detid_t>> det2group_map;
+typedef std::unordered_map<detid_t, std::set<detid_t>> det2group_map;
 }
 
 #endif // MANTID_API_SPECTRADETECTORMAP_TYPES
diff --git a/Framework/API/inc/MantidAPI/SpectrumInfo.h b/Framework/API/inc/MantidAPI/SpectrumInfo.h
index aed89ecc1015d66abad4250982c34e0301b14669..33d2c94f96feb59c9b6e975115c9e1160954edce 100644
--- a/Framework/API/inc/MantidAPI/SpectrumInfo.h
+++ b/Framework/API/inc/MantidAPI/SpectrumInfo.h
@@ -18,7 +18,7 @@ class ParameterMap;
 namespace API {
 
 class DetectorInfo;
-class MatrixWorkspace;
+class ExperimentInfo;
 
 /** API::SpectrumInfo is an intermediate step towards a SpectrumInfo that is
   part of Instrument-2.0. The aim is to provide a nearly identical interface
@@ -29,8 +29,10 @@ class MatrixWorkspace;
   spectra (which may correspond to one or more detectors), such as mask and
   monitor flags, L1, L2, and 2-theta.
 
-  This class is thread safe with OpenMP BUT NOT WITH ANY OTHER THREADING LIBRARY
-  such as Poco threads or Intel TBB.
+  This class is thread safe for read operations (const access) with OpenMP BUT
+  NOT WITH ANY OTHER THREADING LIBRARY such as Poco threads or Intel TBB. There
+  are no thread-safety guarantees for write operations (non-const access). Reads
+  concurrent with writes or concurrent writes are not allowed.
 
 
   @author Simon Heybrock
@@ -59,8 +61,8 @@ class MatrixWorkspace;
 */
 class MANTID_API_DLL SpectrumInfo {
 public:
-  SpectrumInfo(const MatrixWorkspace &workspace);
-  SpectrumInfo(MatrixWorkspace &workspace);
+  SpectrumInfo(const ExperimentInfo &experimentInfo);
+  SpectrumInfo(ExperimentInfo &experimentInfo);
   ~SpectrumInfo();
 
   bool isMonitor(const size_t index) const;
@@ -72,6 +74,8 @@ public:
   bool hasDetectors(const size_t index) const;
   bool hasUniqueDetector(const size_t index) const;
 
+  void setMasked(const size_t index, bool masked);
+
   // This is likely to be deprecated/removed with the introduction of
   // Instrument-2.0: The concept of detector groups will probably be dropped so
   // returning a single detector for a spectrum will not be possible anymore.
@@ -87,8 +91,9 @@ private:
   const Geometry::IDetector &getDetector(const size_t index) const;
   std::vector<boost::shared_ptr<const Geometry::IDetector>>
   getDetectorVector(const size_t index) const;
+  std::vector<size_t> getDetectorIndices(const size_t index) const;
 
-  const MatrixWorkspace &m_workspace;
+  const ExperimentInfo &m_experimentInfo;
   DetectorInfo *m_mutableDetectorInfo{nullptr};
   const DetectorInfo &m_detectorInfo;
   mutable std::vector<boost::shared_ptr<const Geometry::IDetector>>
diff --git a/Framework/API/inc/MantidAPI/Workspace.h b/Framework/API/inc/MantidAPI/Workspace.h
index e089fb57640b80ad560951268dde19b106a96085..fd2d2e504a985de5dfe395cfefafd8ec5abda140 100644
--- a/Framework/API/inc/MantidAPI/Workspace.h
+++ b/Framework/API/inc/MantidAPI/Workspace.h
@@ -1,29 +1,20 @@
 #ifndef MANTID_API_WORKSPACE_H_
 #define MANTID_API_WORKSPACE_H_
 
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidAPI/Workspace_fwd.h"
-#include "MantidAPI/WorkspaceHistory.h"
 #include "MantidAPI/DllConfig.h"
 #include "MantidKernel/DataItem.h"
 #include "MantidKernel/Exception.h"
 
 namespace Mantid {
 
-//----------------------------------------------------------------------
-// Forward Declaration
-//----------------------------------------------------------------------
 namespace Kernel {
 class Logger;
 }
 
 namespace API {
-//----------------------------------------------------------------------
-// Forward Declaration
-//----------------------------------------------------------------------
 class AnalysisDataServiceImpl;
+class WorkspaceHistory;
 
 /** Base Workspace Abstract Class.
 
@@ -53,7 +44,8 @@ class AnalysisDataServiceImpl;
  */
 class MANTID_API_DLL Workspace : public Kernel::DataItem {
 public:
-  Workspace() = default;
+  Workspace();
+  ~Workspace();
 
   /** Returns a clone (copy) of the workspace with covariant return type in all
    * derived classes.
@@ -77,8 +69,6 @@ public:
   Workspace_uptr clone() const { return Workspace_uptr(doClone()); }
   Workspace &operator=(const Workspace &other) = delete;
   // DataItem interface
-  /// Name
-  const std::string name() const override { return this->getName(); }
   /** Marks the workspace as safe for multiple threads to edit data
    * simutaneously.
    * Workspace creation is always considered to be a single threaded operation.
@@ -91,7 +81,7 @@ public:
   void setComment(const std::string &);
   virtual const std::string getTitle() const;
   const std::string &getComment() const;
-  const std::string &getName() const;
+  const std::string &getName() const override;
   bool isDirty(const int n = 1) const;
   /// Get the footprint in memory in bytes.
   virtual size_t getMemorySize() const = 0;
@@ -99,13 +89,13 @@ public:
   std::string getMemorySizeAsStr() const;
 
   /// Returns a reference to the WorkspaceHistory
-  WorkspaceHistory &history() { return m_history; }
+  WorkspaceHistory &history() { return *m_history; }
   /// Returns a reference to the WorkspaceHistory const
-  const WorkspaceHistory &getHistory() const { return m_history; }
+  const WorkspaceHistory &getHistory() const { return *m_history; }
 
 protected:
   /// Protected copy constructor. May be used by childs for cloning.
-  Workspace(const Workspace &) = default;
+  Workspace(const Workspace &);
 
 private:
   void setName(const std::string &);
@@ -117,7 +107,7 @@ private:
   /// workspace algebra
   std::string m_name;
   /// The history of the workspace, algorithm and environment
-  WorkspaceHistory m_history;
+  std::unique_ptr<WorkspaceHistory> m_history;
 
   /// Virtual clone method. Not implemented to force implementation in childs.
   virtual Workspace *doClone() const = 0;
diff --git a/Framework/API/inc/MantidAPI/WorkspaceFactory.h b/Framework/API/inc/MantidAPI/WorkspaceFactory.h
index 72c840e567f27634e773b241f94afa6787092081..87670e804ae9ef12f73e9d35012842272203ca58 100644
--- a/Framework/API/inc/MantidAPI/WorkspaceFactory.h
+++ b/Framework/API/inc/MantidAPI/WorkspaceFactory.h
@@ -20,6 +20,7 @@
 #include "MantidAPI/DllConfig.h"
 #include "MantidKernel/DynamicFactory.h"
 #include "MantidKernel/SingletonHolder.h"
+#include "MantidKernel/make_unique.h"
 #include "MantidAPI/MatrixWorkspace_fwd.h"
 #include "MantidAPI/Workspace_fwd.h"
 #include <boost/make_shared.hpp>
@@ -77,8 +78,8 @@ public:
                               const size_t &NVectors, const size_t &XLength,
                               const size_t &YLength) const;
 
-  void initializeFromParent(const MatrixWorkspace_const_sptr parent,
-                            const MatrixWorkspace_sptr child,
+  void initializeFromParent(const MatrixWorkspace &parent,
+                            MatrixWorkspace &child,
                             const bool differentSize) const;
   /// Create a ITableWorkspace
   boost::shared_ptr<ITableWorkspace>
diff --git a/Framework/API/inc/MantidAPI/WorkspaceGroup.h b/Framework/API/inc/MantidAPI/WorkspaceGroup.h
index c4ef3930b6dd03f414250a3e27291eb8220abdc1..1525d7724549bf7a9a62f5b468bd5e8d0d11d001 100644
--- a/Framework/API/inc/MantidAPI/WorkspaceGroup.h
+++ b/Framework/API/inc/MantidAPI/WorkspaceGroup.h
@@ -93,16 +93,16 @@ public:
 
   /// Invokes the ADS to sort group members by orkspace name
   void sortByName() {
-    AnalysisDataService::Instance().sortGroupByName(this->name());
+    AnalysisDataService::Instance().sortGroupByName(this->getName());
   }
 
   /// Adds a workspace to the group.
   void add(const std::string &wsName) {
-    AnalysisDataService::Instance().addToGroup(this->name(), wsName);
+    AnalysisDataService::Instance().addToGroup(this->getName(), wsName);
   }
   /// Remove a name from the group
   void remove(const std::string &wsName) {
-    AnalysisDataService::Instance().removeFromGroup(this->name(), wsName);
+    AnalysisDataService::Instance().removeFromGroup(this->getName(), wsName);
   }
   /// Does a workspace exist within the group
   bool contains(const std::string &wsName) const;
diff --git a/Framework/API/inc/MantidAPI/WorkspaceOpOverloads.h b/Framework/API/inc/MantidAPI/WorkspaceOpOverloads.h
index 28b443fd04298ec5bfded9413e61b8679e726d30..8f739f9c9d9c784f62ffaaa4e9e9b505ddb4f133 100644
--- a/Framework/API/inc/MantidAPI/WorkspaceOpOverloads.h
+++ b/Framework/API/inc/MantidAPI/WorkspaceOpOverloads.h
@@ -92,13 +92,13 @@ operator/=(const MatrixWorkspace_sptr lhs, const double &rhsValue);
 */
 struct MANTID_API_DLL WorkspaceHelpers {
   // Checks whether a workspace has common X bins/values
-  static bool commonBoundaries(const MatrixWorkspace_const_sptr WS);
+  static bool commonBoundaries(const MatrixWorkspace &WS);
   // Checks whether the binning is the same in two histograms
-  static bool matchingBins(const MatrixWorkspace_const_sptr ws1,
-                           const MatrixWorkspace_const_sptr ws2,
+  static bool matchingBins(const MatrixWorkspace &ws1,
+                           const MatrixWorkspace &ws2,
                            const bool firstOnly = false);
   // Checks whether a the X vectors in a workspace are actually the same vector
-  static bool sharedXData(const MatrixWorkspace_const_sptr WS);
+  static bool sharedXData(const MatrixWorkspace &WS);
   // Divides the data in a workspace by the bin width to make it a distribution
   // (or the reverse)
   static void makeDistribution(MatrixWorkspace_sptr workspace,
diff --git a/Framework/API/inc/MantidAPI/WorkspaceProperty.h b/Framework/API/inc/MantidAPI/WorkspaceProperty.h
index 125b1f1d66cf17c4f86b232a3d79c0548468b737..02dcb9068bd029994858edd3cce12047662044a5 100644
--- a/Framework/API/inc/MantidAPI/WorkspaceProperty.h
+++ b/Framework/API/inc/MantidAPI/WorkspaceProperty.h
@@ -1,15 +1,9 @@
 #ifndef MANTID_API_WORKSPACEPROPERTY_H_
 #define MANTID_API_WORKSPACEPROPERTY_H_
 
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidKernel/PropertyWithValue.h"
 #include "MantidAPI/IWorkspaceProperty.h"
-#include "MantidAPI/AnalysisDataService.h"
 #include "MantidKernel/Logger.h"
-#include "MantidKernel/Exception.h"
-#include "MantidAPI/WorkspaceGroup.h"
 
 #include <string>
 
@@ -19,6 +13,7 @@ namespace API {
 // Forward decaration
 // -------------------------------------------------------------------------
 class MatrixWorkspace;
+class WorkspaceGroup;
 
 /// Enumeration for a mandatory/optional property
 struct PropertyMode {
@@ -77,430 +72,70 @@ class WorkspaceProperty
     : public Kernel::PropertyWithValue<boost::shared_ptr<TYPE>>,
       public IWorkspaceProperty {
 public:
-  /** Constructor.
-  *  Sets the property and workspace names but initializes the workspace pointer
-  * to null.
-  *  @param name :: The name to assign to the property
-  *  @param wsName :: The name of the workspace
-  *  @param direction :: Whether this is a Direction::Input, Direction::Output
-  * or Direction::InOut (Input & Output) workspace
-  *  @param validator :: The (optional) validator to use for this property
-  *  @throw std::out_of_range if the direction argument is not a member of the
-  * Direction enum (i.e. 0-2)
-  */
   explicit WorkspaceProperty(
       const std::string &name, const std::string &wsName,
       const unsigned int direction,
       Kernel::IValidator_sptr validator =
-          Kernel::IValidator_sptr(new Kernel::NullValidator))
-      : Kernel::PropertyWithValue<boost::shared_ptr<TYPE>>(
-            name, boost::shared_ptr<TYPE>(), validator, direction),
-        m_workspaceName(wsName), m_initialWSName(wsName),
-        m_optional(PropertyMode::Mandatory), m_locking(LockMode::Lock) {}
-
-  /** Constructor.
-  *  Sets the property and workspace names but initialises the workspace pointer
-  * to null.
-  *  @param name :: The name to assign to the property
-  *  @param wsName :: The name of the workspace
-  *  @param direction :: Whether this is a Direction::Input, Direction::Output
-  * or Direction::InOut (Input & Output) workspace
-  *  @param optional :: If true then the property is optional
-  *  @param validator :: The (optional) validator to use for this property
-  *  @throw std::out_of_range if the direction argument is not a member of the
-  * Direction enum (i.e. 0-2)
-  */
+          Kernel::IValidator_sptr(new Kernel::NullValidator));
+
   explicit WorkspaceProperty(
       const std::string &name, const std::string &wsName,
       const unsigned int direction, const PropertyMode::Type optional,
       Kernel::IValidator_sptr validator =
-          Kernel::IValidator_sptr(new Kernel::NullValidator))
-      : Kernel::PropertyWithValue<boost::shared_ptr<TYPE>>(
-            name, boost::shared_ptr<TYPE>(), validator, direction),
-        m_workspaceName(wsName), m_initialWSName(wsName), m_optional(optional),
-        m_locking(LockMode::Lock) {}
-
-  /** Constructor.
-  *  Sets the property and workspace names but initialises the workspace pointer
-  * to null.
-  *  @param name :: The name to assign to the property
-  *  @param wsName :: The name of the workspace
-  *  @param direction :: Whether this is a Direction::Input, Direction::Output
-  * or Direction::InOut (Input & Output) workspace
-  *  @param optional :: A boolean indicating whether the property is mandatory
-  * or not. Only matters
-  *                     for input properties
-  *  @param locking :: A boolean indicating whether the workspace should read or
-  *                    write-locked when an algorithm begins. Default=true.
-  *  @param validator :: The (optional) validator to use for this property
-  *  @throw std::out_of_range if the direction argument is not a member of the
-  * Direction enum (i.e. 0-2)
-  */
+          Kernel::IValidator_sptr(new Kernel::NullValidator));
+
   explicit WorkspaceProperty(
       const std::string &name, const std::string &wsName,
       const unsigned int direction, const PropertyMode::Type optional,
       const LockMode::Type locking,
       Kernel::IValidator_sptr validator =
-          Kernel::IValidator_sptr(new Kernel::NullValidator))
-      : Kernel::PropertyWithValue<boost::shared_ptr<TYPE>>(
-            name, boost::shared_ptr<TYPE>(), validator, direction),
-        m_workspaceName(wsName), m_initialWSName(wsName), m_optional(optional),
-        m_locking(locking) {}
-
-  /// Copy constructor, the default name stored in the new object is the same as
-  /// the default name from the original object
-  WorkspaceProperty(const WorkspaceProperty &right)
-      : Kernel::PropertyWithValue<boost::shared_ptr<TYPE>>(right),
-        m_workspaceName(right.m_workspaceName),
-        m_initialWSName(right.m_initialWSName), m_optional(right.m_optional),
-        m_locking(right.m_locking) {}
-
-  /// Copy assignment operator. Only copies the value (i.e. the pointer to the
-  /// workspace)
-  WorkspaceProperty &operator=(const WorkspaceProperty &right) {
-    if (&right == this)
-      return *this;
-    Kernel::PropertyWithValue<boost::shared_ptr<TYPE>>::operator=(right);
-    return *this;
-  }
-
-  /** Bring in the PropertyWithValue assignment operator explicitly (avoids
-   * VSC++ warning)
-   * @param value :: The value to set to
-   * @return assigned PropertyWithValue
-   */
+          Kernel::IValidator_sptr(new Kernel::NullValidator));
+
+  WorkspaceProperty(const WorkspaceProperty &right);
+
+  WorkspaceProperty &operator=(const WorkspaceProperty &right);
+
   boost::shared_ptr<TYPE> &
-  operator=(const boost::shared_ptr<TYPE> &value) override {
-    std::string wsName = value->name();
-    if (this->direction() == Kernel::Direction::Input && !wsName.empty()) {
-      m_workspaceName = wsName;
-    }
-    return Kernel::PropertyWithValue<boost::shared_ptr<TYPE>>::operator=(value);
-  }
-
-  //--------------------------------------------------------------------------------------
-  /// Add the value of another property
-  WorkspaceProperty &operator+=(Kernel::Property const *) override {
-    throw Kernel::Exception::NotImplementedError(
-        "+= operator is not implemented for WorkspaceProperty.");
-    return *this;
-  }
-
-  /// 'Virtual copy constructor'
-  WorkspaceProperty<TYPE> *clone() const override {
-    return new WorkspaceProperty<TYPE>(*this);
-  }
-
-  /** Get the name of the workspace
-  *  @return The workspace's name
-  */
-  std::string value() const override { return m_workspaceName; }
-
-  /** Get the value the property was initialised with -its default value
-  *  @return The default value
-  */
-  std::string getDefault() const override { return m_initialWSName; }
-
-  /** Set the name of the workspace.
-  *  Also tries to retrieve it from the AnalysisDataService.
-  *  @param value :: The new name for the workspace
-  *  @return
-  */
-  std::string setValue(const std::string &value) override {
-    m_workspaceName = value;
-    if (Kernel::PropertyWithValue<boost::shared_ptr<TYPE>>::autoTrim()) {
-      boost::trim(m_workspaceName);
-    }
-    // Try and get the workspace from the ADS, but don't worry if we can't
-    try {
-      Kernel::PropertyWithValue<boost::shared_ptr<TYPE>>::m_value =
-          AnalysisDataService::Instance().retrieveWS<TYPE>(m_workspaceName);
-    } catch (Kernel::Exception::NotFoundError &) {
-      // Set to null property if not found
-      this->clear();
-      // the workspace name is not reset here, however.
-    }
-
-    return isValid();
-  }
-
-  /** Set a value from a data item
-   *  @param value :: A shared pointer to a DataItem. If it is of the correct
-   *  type it will set validated, if not the property's value will be cleared.
-   *  @return
-   */
+  operator=(const boost::shared_ptr<TYPE> &value) override;
+
+  WorkspaceProperty &operator+=(Kernel::Property const *) override;
+
+  WorkspaceProperty<TYPE> *clone() const override;
+
+  std::string value() const override;
+
+  std::string getDefault() const override;
+
+  std::string setValue(const std::string &value) override;
+
   std::string
-  setDataItem(const boost::shared_ptr<Kernel::DataItem> value) override {
-    boost::shared_ptr<TYPE> typed = boost::dynamic_pointer_cast<TYPE>(value);
-    if (typed) {
-      std::string wsName = typed->name();
-      if (this->direction() == Kernel::Direction::Input && !wsName.empty()) {
-        m_workspaceName = wsName;
-      }
-      Kernel::PropertyWithValue<boost::shared_ptr<TYPE>>::m_value = typed;
-    } else {
-      this->clear();
-    }
-    return isValid();
-  }
-
-  /** Checks whether the entered workspace is valid.
-  *  To be valid, in addition to satisfying the conditions of any validators,
-  *  an output property must not have an empty name and an input one must point
-  * to
-  *  a workspace of the correct type.
-  *  @returns A user level description of the problem or "" if it is valid.
-  */
-  std::string isValid() const override {
-    // start with the no error condition
-    std::string error;
-
-    // If an output workspace it must have a name, although it might not exist
-    // in the ADS yet
-    if (this->direction() == Kernel::Direction::Output) {
-      return isValidOutputWs();
-    }
-
-    // If an input (or inout) workspace, must point to something, although it
-    // doesn't have to have a name
-    // unless it's optional
-    if (this->direction() == Kernel::Direction::Input ||
-        this->direction() == Kernel::Direction::InOut) {
-      // Workspace groups will not have a value since they are not of type TYPE
-      if (!Kernel::PropertyWithValue<boost::shared_ptr<TYPE>>::m_value) {
-        Mantid::API::Workspace_sptr wksp;
-        // if the workspace name is empty then there is no point asking the ADS
-        if (m_workspaceName.empty())
-          return isOptionalWs();
-
-        try {
-          wksp = AnalysisDataService::Instance().retrieve(m_workspaceName);
-        } catch (Kernel::Exception::NotFoundError &) {
-          // Check to see if the workspace is not logged with the ADS because it
-          // is optional.
-          return isOptionalWs();
-        }
-
-        // At this point we have a valid pointer to a Workspace so we need to
-        // test whether it is a group
-        if (boost::dynamic_pointer_cast<Mantid::API::WorkspaceGroup>(wksp)) {
-          return isValidGroup(
-              boost::dynamic_pointer_cast<Mantid::API::WorkspaceGroup>(wksp));
-        } else {
-          error = "Workspace " + this->value() + " is not of the correct type";
-        }
-        return error;
-      }
-    }
-    // Call superclass method to access any attached validators (which do their
-    // own logging)
-    return Kernel::PropertyWithValue<boost::shared_ptr<TYPE>>::isValid();
-  }
-
-  /** Indicates if the object is still pointing to the same workspace, using the
-  * workspace name
-  *  @return true if the value is the same as the initial value or false
-  * otherwise
-  */
-  bool isDefault() const override { return m_initialWSName == m_workspaceName; }
-
-  /** Is the workspace property optional
-   * @return true if the workspace can be blank   */
-  bool isOptional() const override {
-    return (m_optional == PropertyMode::Optional);
-  }
-  /** Does the workspace need to be locked before starting an algorithm?
-   * @return true (default) if the workspace will be locked */
-  bool isLocking() const override { return (m_locking == LockMode::Lock); }
-
-  /** Returns the current contents of the AnalysisDataService for input
-   * workspaces.
-   *  For output workspaces, an empty set is returned
-   *  @return set of objects in AnalysisDataService
-   */
-  std::vector<std::string> allowedValues() const override {
-    if (this->direction() == Kernel::Direction::Input ||
-        this->direction() == Kernel::Direction::InOut) {
-      // If an input workspace, get the list of workspaces currently in the ADS
-      auto vals = AnalysisDataService::Instance().getObjectNames(
-          Mantid::Kernel::DataServiceSort::Sorted);
-      if (isOptional()) // Insert an empty option
-      {
-        vals.push_back("");
-      }
-      // Copy-construct a temporary workspace property to test the validity of
-      // each workspace
-      WorkspaceProperty<TYPE> tester(*this);
-
-      // Remove any workspace that's not valid for this algorithm
-      auto eraseIter = remove_if(vals.begin(), vals.end(),
-                                 [&tester](const std::string &wsName) {
-                                   return !tester.setValue(wsName).empty();
-                                 });
-      // Erase everything past returned iterator afterwards for readability
-      vals.erase(eraseIter, vals.end());
-      return vals;
-    } else {
-      // For output workspaces, just return an empty set
-      return std::vector<std::string>();
-    }
-  }
-
-  /// Create a history record
-  /// @return A populated PropertyHistory for this class
-  const Kernel::PropertyHistory createHistory() const override {
-    std::string wsName = m_workspaceName;
-    bool isdefault = this->isDefault();
-
-    if ((wsName.empty() || this->hasTemporaryValue()) && this->operator()()) {
-      // give the property a temporary name in the history
-      std::ostringstream os;
-      os << "__TMP" << this->operator()().get();
-      wsName = os.str();
-      isdefault = false;
-    }
-    return Kernel::PropertyHistory(this->name(), wsName, this->type(),
-                                   isdefault, this->direction());
-  }
-
-  /** If this is an output workspace, store it into the AnalysisDataService
-  *  @return True if the workspace is an output workspace and has been stored
-  *  @throw std::runtime_error if unable to store the workspace successfully
-  */
-  bool store() override {
-    bool result = false;
-    if (!this->operator()() && isOptional())
-      return result;
-    if (this->direction()) // Output or InOut
-    {
-      // Check that workspace exists
-      if (!this->operator()())
-        throw std::runtime_error(
-            "WorkspaceProperty doesn't point to a workspace");
-      // Note use of addOrReplace rather than add
-      API::AnalysisDataService::Instance().addOrReplace(m_workspaceName,
-                                                        this->operator()());
-      result = true;
-    }
-    // always clear the internal pointer after storing
-    clear();
-
-    return result;
-  }
-
-  Workspace_sptr getWorkspace() const override { return this->operator()(); }
+  setDataItem(const boost::shared_ptr<Kernel::DataItem> value) override;
+
+  std::string isValid() const override;
+
+  bool isDefault() const override;
+
+  bool isOptional() const override;
+  bool isLocking() const override;
+
+  std::vector<std::string> allowedValues() const override;
+
+  const Kernel::PropertyHistory createHistory() const override;
+
+  bool store() override;
+
+  Workspace_sptr getWorkspace() const override;
 
 private:
-  /** Checks whether the entered workspace group is valid.
-  *  To be valid *all* members of the group have to be valid.
-  *  @param wsGroup :: the WorkspaceGroup of which to check the validity
-  *  @returns A user level description of the problem or "" if it is valid.
-  */
-  std::string isValidGroup(boost::shared_ptr<WorkspaceGroup> wsGroup) const {
-    g_log.debug() << " Input WorkspaceGroup found \n";
-
-    std::vector<std::string> wsGroupNames = wsGroup->getNames();
-    std::string error;
-
-    // Cycle through each workspace in the group ...
-    for (const auto &memberWsName : wsGroupNames) {
-      boost::shared_ptr<Workspace> memberWs =
-          AnalysisDataService::Instance().retrieve(memberWsName);
-
-      // Table Workspaces are ignored
-      if ("TableWorkspace" == memberWs->id()) {
-        error = "Workspace " + memberWsName + " is of type TableWorkspace and "
-                                              "will therefore be ignored as "
-                                              "part of the GroupedWorkspace.";
-
-        g_log.debug() << error << '\n';
-      } else {
-        // ... and if it is a workspace of incorrect type, exclude the group by
-        // returning an error.
-        if (!boost::dynamic_pointer_cast<TYPE>(memberWs)) {
-          error = "Workspace " + memberWsName + " is not of type " +
-                  Kernel::PropertyWithValue<boost::shared_ptr<TYPE>>::type() +
-                  ".";
-
-          g_log.debug() << error << '\n';
-
-          return error;
-        }
-        // If it is of the correct type, it may still be invalid. Check.
-        else {
-          Mantid::API::WorkspaceProperty<TYPE> memberWsProperty(*this);
-          std::string memberError = memberWsProperty.setValue(memberWsName);
-          if (!memberError.empty())
-            return memberError; // Since if this member is invalid, then the
-                                // whole group is invalid.
-        }
-      }
-    }
-
-    return ""; // Since all members of the group are valid.
-  }
-
-  /** Checks whether the entered output workspace is valid.
-  *  To be valid the only thing it needs is a name that is allowed by the ADS,
-  * @see AnalysisDataServiceImpl
-  *  @returns A user level description of the problem or "" if it is valid.
-  */
-  std::string isValidOutputWs() const {
-    std::string error;
-    const std::string value = this->value();
-    if (!value.empty()) {
-      // Will the ADS accept it
-      error = AnalysisDataService::Instance().isValid(value);
-    } else {
-      if (isOptional())
-        error = ""; // Optional ones don't need a name
-      else
-        error = "Enter a name for the Output workspace";
-    }
-    return error;
-  }
-
-  /** Checks whether the entered workspace (that by this point we've found is
-  * not in the ADS)
-  *  is actually an optional workspace and so still valid.
-  *  @returns A user level description of the problem or "" if it is valid.
-  */
-  std::string isOptionalWs() const {
-    std::string error;
-
-    if (m_workspaceName.empty()) {
-      if (isOptional()) {
-        error = "";
-      } else {
-        error = "Enter a name for the Input/InOut workspace";
-      }
-    } else {
-      error = "Workspace \"" + this->value() +
-              "\" was not found in the Analysis Data Service";
-    }
-
-    return error;
-  }
-
-  /// Reset the pointer to the workspace
-  void clear() override {
-    Kernel::PropertyWithValue<boost::shared_ptr<TYPE>>::m_value =
-        boost::shared_ptr<TYPE>();
-  }
-
-  /** Attempts to retreive the data from the ADS
-  *  if the data is not foung the internal pointer is set to null.
-  */
-  void retrieveWorkspaceFromADS() {
-    // Try and get the workspace from the ADS, but don't worry if we can't
-    try {
-      Kernel::PropertyWithValue<boost::shared_ptr<TYPE>>::m_value =
-          AnalysisDataService::Instance().retrieveWS<TYPE>(m_workspaceName);
-    } catch (Kernel::Exception::NotFoundError &) {
-      // Set to null property if not found
-      this->clear();
-    }
-  }
+  std::string isValidGroup(boost::shared_ptr<WorkspaceGroup> wsGroup) const;
+
+  std::string isValidOutputWs() const;
+
+  std::string isOptionalWs() const;
+
+  void clear() override;
+
+  void retrieveWorkspaceFromADS();
 
   /// The name of the workspace (as used by the AnalysisDataService)
   std::string m_workspaceName;
diff --git a/Framework/API/inc/MantidAPI/WorkspaceProperty.tcc b/Framework/API/inc/MantidAPI/WorkspaceProperty.tcc
new file mode 100644
index 0000000000000000000000000000000000000000..835b2c8899f64489e053bd67b33b5802f8e39217
--- /dev/null
+++ b/Framework/API/inc/MantidAPI/WorkspaceProperty.tcc
@@ -0,0 +1,466 @@
+#include "MantidAPI/AnalysisDataService.h"
+#include "MantidAPI/WorkspaceGroup.h"
+#include "MantidAPI/Workspace.h"
+#include "MantidAPI/WorkspaceProperty.h"
+#include "MantidKernel/Exception.h"
+#include "MantidKernel/PropertyHistory.h"
+
+namespace Mantid {
+namespace API {
+
+/** Constructor.
+*  Sets the property and workspace names but initializes the workspace pointer
+* to null.
+*  @param name :: The name to assign to the property
+*  @param wsName :: The name of the workspace
+*  @param direction :: Whether this is a Direction::Input, Direction::Output
+* or Direction::InOut (Input & Output) workspace
+*  @param validator :: The (optional) validator to use for this property
+*  @throw std::out_of_range if the direction argument is not a member of the
+* Direction enum (i.e. 0-2)
+*/
+template <typename TYPE>
+WorkspaceProperty<TYPE>::WorkspaceProperty(const std::string &name,
+                                           const std::string &wsName,
+                                           const unsigned int direction,
+                                           Kernel::IValidator_sptr validator)
+    : Kernel::PropertyWithValue<boost::shared_ptr<TYPE>>(
+          name, boost::shared_ptr<TYPE>(), validator, direction),
+      m_workspaceName(wsName), m_initialWSName(wsName),
+      m_optional(PropertyMode::Mandatory), m_locking(LockMode::Lock) {}
+
+/** Constructor.
+*  Sets the property and workspace names but initialises the workspace pointer
+* to null.
+*  @param name :: The name to assign to the property
+*  @param wsName :: The name of the workspace
+*  @param direction :: Whether this is a Direction::Input, Direction::Output
+* or Direction::InOut (Input & Output) workspace
+*  @param optional :: If true then the property is optional
+*  @param validator :: The (optional) validator to use for this property
+*  @throw std::out_of_range if the direction argument is not a member of the
+* Direction enum (i.e. 0-2)
+*/
+template <typename TYPE>
+WorkspaceProperty<TYPE>::WorkspaceProperty(const std::string &name,
+                                           const std::string &wsName,
+                                           const unsigned int direction,
+                                           const PropertyMode::Type optional,
+                                           Kernel::IValidator_sptr validator)
+    : Kernel::PropertyWithValue<boost::shared_ptr<TYPE>>(
+          name, boost::shared_ptr<TYPE>(), validator, direction),
+      m_workspaceName(wsName), m_initialWSName(wsName), m_optional(optional),
+      m_locking(LockMode::Lock) {}
+
+/** Constructor.
+*  Sets the property and workspace names but initialises the workspace pointer
+* to null.
+*  @param name :: The name to assign to the property
+*  @param wsName :: The name of the workspace
+*  @param direction :: Whether this is a Direction::Input, Direction::Output
+* or Direction::InOut (Input & Output) workspace
+*  @param optional :: A boolean indicating whether the property is mandatory
+* or not. Only matters
+*                     for input properties
+*  @param locking :: A boolean indicating whether the workspace should read or
+*                    write-locked when an algorithm begins. Default=true.
+*  @param validator :: The (optional) validator to use for this property
+*  @throw std::out_of_range if the direction argument is not a member of the
+* Direction enum (i.e. 0-2)
+*/
+template <typename TYPE>
+WorkspaceProperty<TYPE>::WorkspaceProperty(const std::string &name,
+                                           const std::string &wsName,
+                                           const unsigned int direction,
+                                           const PropertyMode::Type optional,
+                                           const LockMode::Type locking,
+                                           Kernel::IValidator_sptr validator)
+    : Kernel::PropertyWithValue<boost::shared_ptr<TYPE>>(
+          name, boost::shared_ptr<TYPE>(), validator, direction),
+      m_workspaceName(wsName), m_initialWSName(wsName), m_optional(optional),
+      m_locking(locking) {}
+
+/// Copy constructor, the default name stored in the new object is the same as
+/// the default name from the original object
+template <typename TYPE>
+WorkspaceProperty<TYPE>::WorkspaceProperty(const WorkspaceProperty &right)
+    : Kernel::PropertyWithValue<boost::shared_ptr<TYPE>>(right),
+      m_workspaceName(right.m_workspaceName),
+      m_initialWSName(right.m_initialWSName), m_optional(right.m_optional),
+      m_locking(right.m_locking) {}
+
+/// Copy assignment operator. Only copies the value (i.e. the pointer to the
+/// workspace)
+template <typename TYPE>
+WorkspaceProperty<TYPE> &WorkspaceProperty<TYPE>::
+operator=(const WorkspaceProperty &right) {
+  if (&right == this)
+    return *this;
+  Kernel::PropertyWithValue<boost::shared_ptr<TYPE>>::operator=(right);
+  return *this;
+}
+
+/** Bring in the PropertyWithValue assignment operator explicitly (avoids
+ * VSC++ warning)
+ * @param value :: The value to set to
+ * @return assigned PropertyWithValue
+ */
+template <typename TYPE>
+boost::shared_ptr<TYPE> &WorkspaceProperty<TYPE>::
+operator=(const boost::shared_ptr<TYPE> &value) {
+  std::string wsName = value->getName();
+  if (this->direction() == Kernel::Direction::Input && !wsName.empty()) {
+    m_workspaceName = wsName;
+  }
+  return Kernel::PropertyWithValue<boost::shared_ptr<TYPE>>::operator=(value);
+}
+
+//--------------------------------------------------------------------------------------
+/// Add the value of another property
+template <typename TYPE>
+WorkspaceProperty<TYPE> &WorkspaceProperty<TYPE>::
+operator+=(Kernel::Property const *) {
+  throw Kernel::Exception::NotImplementedError(
+      "+= operator is not implemented for WorkspaceProperty.");
+  return *this;
+}
+
+/// 'Virtual copy constructor'
+template <typename TYPE>
+WorkspaceProperty<TYPE> *WorkspaceProperty<TYPE>::clone() const {
+  return new WorkspaceProperty<TYPE>(*this);
+}
+
+/** Get the name of the workspace
+*  @return The workspace's name
+*/
+template <typename TYPE> std::string WorkspaceProperty<TYPE>::value() const {
+  return m_workspaceName;
+}
+
+/** Get the value the property was initialised with -its default value
+*  @return The default value
+*/
+template <typename TYPE>
+std::string WorkspaceProperty<TYPE>::getDefault() const {
+  return m_initialWSName;
+}
+
+/** Set the name of the workspace.
+*  Also tries to retrieve it from the AnalysisDataService.
+*  @param value :: The new name for the workspace
+*  @return
+*/
+template <typename TYPE>
+std::string WorkspaceProperty<TYPE>::setValue(const std::string &value) {
+  m_workspaceName = value;
+  if (Kernel::PropertyWithValue<boost::shared_ptr<TYPE>>::autoTrim()) {
+    boost::trim(m_workspaceName);
+  }
+  // Try and get the workspace from the ADS, but don't worry if we can't
+  try {
+    Kernel::PropertyWithValue<boost::shared_ptr<TYPE>>::m_value =
+        AnalysisDataService::Instance().retrieveWS<TYPE>(m_workspaceName);
+  } catch (Kernel::Exception::NotFoundError &) {
+    // Set to null property if not found
+    this->clear();
+    // the workspace name is not reset here, however.
+  }
+
+  return isValid();
+}
+
+/** Set a value from a data item
+ *  @param value :: A shared pointer to a DataItem. If it is of the correct
+ *  type it will set validated, if not the property's value will be cleared.
+ *  @return
+ */
+template <typename TYPE>
+std::string WorkspaceProperty<TYPE>::setDataItem(
+    const boost::shared_ptr<Kernel::DataItem> value) {
+  boost::shared_ptr<TYPE> typed = boost::dynamic_pointer_cast<TYPE>(value);
+  if (typed) {
+    std::string wsName = typed->getName();
+    if (this->direction() == Kernel::Direction::Input && !wsName.empty()) {
+      m_workspaceName = wsName;
+    }
+    Kernel::PropertyWithValue<boost::shared_ptr<TYPE>>::m_value = typed;
+  } else {
+    this->clear();
+  }
+  return isValid();
+}
+
+/** Checks whether the entered workspace is valid.
+*  To be valid, in addition to satisfying the conditions of any validators,
+*  an output property must not have an empty name and an input one must point
+* to
+*  a workspace of the correct type.
+*  @returns A user level description of the problem or "" if it is valid.
+*/
+template <typename TYPE> std::string WorkspaceProperty<TYPE>::isValid() const {
+  // start with the no error condition
+  std::string error;
+
+  // If an output workspace it must have a name, although it might not exist
+  // in the ADS yet
+  if (this->direction() == Kernel::Direction::Output) {
+    return isValidOutputWs();
+  }
+
+  // If an input (or inout) workspace, must point to something, although it
+  // doesn't have to have a name
+  // unless it's optional
+  if (this->direction() == Kernel::Direction::Input ||
+      this->direction() == Kernel::Direction::InOut) {
+    // Workspace groups will not have a value since they are not of type TYPE
+    if (!Kernel::PropertyWithValue<boost::shared_ptr<TYPE>>::m_value) {
+      Mantid::API::Workspace_sptr wksp;
+      // if the workspace name is empty then there is no point asking the ADS
+      if (m_workspaceName.empty())
+        return isOptionalWs();
+
+      try {
+        wksp = AnalysisDataService::Instance().retrieve(m_workspaceName);
+      } catch (Kernel::Exception::NotFoundError &) {
+        // Check to see if the workspace is not logged with the ADS because it
+        // is optional.
+        return isOptionalWs();
+      }
+
+      // At this point we have a valid pointer to a Workspace so we need to
+      // test whether it is a group
+      if (boost::dynamic_pointer_cast<Mantid::API::WorkspaceGroup>(wksp)) {
+        return isValidGroup(
+            boost::dynamic_pointer_cast<Mantid::API::WorkspaceGroup>(wksp));
+      } else {
+        error = "Workspace " + this->value() + " is not of the correct type";
+      }
+      return error;
+    }
+  }
+  // Call superclass method to access any attached validators (which do their
+  // own logging)
+  return Kernel::PropertyWithValue<boost::shared_ptr<TYPE>>::isValid();
+}
+
+/** Indicates if the object is still pointing to the same workspace, using the
+* workspace name
+*  @return true if the value is the same as the initial value or false
+* otherwise
+*/
+template <typename TYPE> bool WorkspaceProperty<TYPE>::isDefault() const {
+  return m_initialWSName == m_workspaceName;
+}
+
+/** Is the workspace property optional
+ * @return true if the workspace can be blank   */
+template <typename TYPE> bool WorkspaceProperty<TYPE>::isOptional() const {
+  return (m_optional == PropertyMode::Optional);
+}
+/** Does the workspace need to be locked before starting an algorithm?
+ * @return true (default) if the workspace will be locked */
+template <typename TYPE> bool WorkspaceProperty<TYPE>::isLocking() const {
+  return (m_locking == LockMode::Lock);
+}
+
+/** Returns the current contents of the AnalysisDataService for input
+ * workspaces.
+ *  For output workspaces, an empty set is returned
+ *  @return set of objects in AnalysisDataService
+ */
+template <typename TYPE>
+std::vector<std::string> WorkspaceProperty<TYPE>::allowedValues() const {
+  if (this->direction() == Kernel::Direction::Input ||
+      this->direction() == Kernel::Direction::InOut) {
+    // If an input workspace, get the list of workspaces currently in the ADS
+    auto vals = AnalysisDataService::Instance().getObjectNames(
+        Mantid::Kernel::DataServiceSort::Sorted);
+    if (isOptional()) // Insert an empty option
+    {
+      vals.push_back("");
+    }
+    // Copy-construct a temporary workspace property to test the validity of
+    // each workspace
+    WorkspaceProperty<TYPE> tester(*this);
+
+    // Remove any workspace that's not valid for this algorithm
+    auto eraseIter = remove_if(vals.begin(), vals.end(),
+                               [&tester](const std::string &wsName) {
+                                 return !tester.setValue(wsName).empty();
+                               });
+    // Erase everything past returned iterator afterwards for readability
+    vals.erase(eraseIter, vals.end());
+    return vals;
+  } else {
+    // For output workspaces, just return an empty set
+    return std::vector<std::string>();
+  }
+}
+
+/// Create a history record
+/// @return A populated PropertyHistory for this class
+template <typename TYPE>
+const Kernel::PropertyHistory WorkspaceProperty<TYPE>::createHistory() const {
+  std::string wsName = m_workspaceName;
+  bool isdefault = this->isDefault();
+
+  if ((wsName.empty() || this->hasTemporaryValue()) && this->operator()()) {
+    // give the property a temporary name in the history
+    std::ostringstream os;
+    os << "__TMP" << this->operator()().get();
+    wsName = os.str();
+    isdefault = false;
+  }
+  return Kernel::PropertyHistory(this->name(), wsName, this->type(), isdefault,
+                                 this->direction());
+}
+
+/** If this is an output workspace, store it into the AnalysisDataService
+*  @return True if the workspace is an output workspace and has been stored
+*  @throw std::runtime_error if unable to store the workspace successfully
+*/
+template <typename TYPE> bool WorkspaceProperty<TYPE>::store() {
+  bool result = false;
+  if (!this->operator()() && isOptional())
+    return result;
+  if (this->direction()) // Output or InOut
+  {
+    // Check that workspace exists
+    if (!this->operator()())
+      throw std::runtime_error(
+          "WorkspaceProperty doesn't point to a workspace");
+    // Note use of addOrReplace rather than add
+    API::AnalysisDataService::Instance().addOrReplace(m_workspaceName,
+                                                      this->operator()());
+    result = true;
+  }
+  // always clear the internal pointer after storing
+  clear();
+
+  return result;
+}
+
+template <typename TYPE>
+Workspace_sptr WorkspaceProperty<TYPE>::getWorkspace() const {
+  return this->operator()();
+}
+
+/** Checks whether the entered workspace group is valid.
+*  To be valid *all* members of the group have to be valid.
+*  @param wsGroup :: the WorkspaceGroup of which to check the validity
+*  @returns A user level description of the problem or "" if it is valid.
+*/
+template <typename TYPE>
+std::string WorkspaceProperty<TYPE>::isValidGroup(
+    boost::shared_ptr<WorkspaceGroup> wsGroup) const {
+  g_log.debug() << " Input WorkspaceGroup found \n";
+
+  std::vector<std::string> wsGroupNames = wsGroup->getNames();
+  std::string error;
+
+  // Cycle through each workspace in the group ...
+  for (const auto &memberWsName : wsGroupNames) {
+    boost::shared_ptr<Workspace> memberWs =
+        AnalysisDataService::Instance().retrieve(memberWsName);
+
+    // Table Workspaces are ignored
+    if ("TableWorkspace" == memberWs->id()) {
+      error = "Workspace " + memberWsName + " is of type TableWorkspace and "
+                                            "will therefore be ignored as "
+                                            "part of the GroupedWorkspace.";
+
+      g_log.debug() << error << '\n';
+    } else {
+      // ... and if it is a workspace of incorrect type, exclude the group by
+      // returning an error.
+      if (!boost::dynamic_pointer_cast<TYPE>(memberWs)) {
+        error = "Workspace " + memberWsName + " is not of type " +
+                Kernel::PropertyWithValue<boost::shared_ptr<TYPE>>::type() +
+                ".";
+
+        g_log.debug() << error << '\n';
+
+        return error;
+      }
+      // If it is of the correct type, it may still be invalid. Check.
+      else {
+        Mantid::API::WorkspaceProperty<TYPE> memberWsProperty(*this);
+        std::string memberError = memberWsProperty.setValue(memberWsName);
+        if (!memberError.empty())
+          return memberError; // Since if this member is invalid, then the
+                              // whole group is invalid.
+      }
+    }
+  }
+
+  return ""; // Since all members of the group are valid.
+}
+
+/** Checks whether the entered output workspace is valid.
+*  To be valid the only thing it needs is a name that is allowed by the ADS,
+* @see AnalysisDataServiceImpl
+*  @returns A user level description of the problem or "" if it is valid.
+*/
+template <typename TYPE>
+std::string WorkspaceProperty<TYPE>::isValidOutputWs() const {
+  std::string error;
+  const std::string value = this->value();
+  if (!value.empty()) {
+    // Will the ADS accept it
+    error = AnalysisDataService::Instance().isValid(value);
+  } else {
+    if (isOptional())
+      error = ""; // Optional ones don't need a name
+    else
+      error = "Enter a name for the Output workspace";
+  }
+  return error;
+}
+
+/** Checks whether the entered workspace (that by this point we've found is
+* not in the ADS)
+*  is actually an optional workspace and so still valid.
+*  @returns A user level description of the problem or "" if it is valid.
+*/
+template <typename TYPE>
+std::string WorkspaceProperty<TYPE>::isOptionalWs() const {
+  std::string error;
+
+  if (m_workspaceName.empty()) {
+    if (isOptional()) {
+      error = "";
+    } else {
+      error = "Enter a name for the Input/InOut workspace";
+    }
+  } else {
+    error = "Workspace \"" + this->value() +
+            "\" was not found in the Analysis Data Service";
+  }
+
+  return error;
+}
+
+/// Reset the pointer to the workspace
+template <typename TYPE> void WorkspaceProperty<TYPE>::clear() {
+  Kernel::PropertyWithValue<boost::shared_ptr<TYPE>>::m_value =
+      boost::shared_ptr<TYPE>();
+}
+
+/** Attempts to retreive the data from the ADS
+*  if the data is not foung the internal pointer is set to null.
+*/
+template <typename TYPE>
+void WorkspaceProperty<TYPE>::retrieveWorkspaceFromADS() {
+  // Try and get the workspace from the ADS, but don't worry if we can't
+  try {
+    Kernel::PropertyWithValue<boost::shared_ptr<TYPE>>::m_value =
+        AnalysisDataService::Instance().retrieveWS<TYPE>(m_workspaceName);
+  } catch (Kernel::Exception::NotFoundError &) {
+    // Set to null property if not found
+    this->clear();
+  }
+}
+
+} // namespace API
+} // namespace Mantid
diff --git a/Framework/API/src/ADSValidator.cpp b/Framework/API/src/ADSValidator.cpp
index f65fa6980997e00d5629aaed92cadaea44bdbe8a..ae2fa008d214189484b60801e22b9abe7fcc64d6 100644
--- a/Framework/API/src/ADSValidator.cpp
+++ b/Framework/API/src/ADSValidator.cpp
@@ -3,6 +3,7 @@
 #include "MantidKernel/StringTokenizer.h"
 #include "MantidAPI/AnalysisDataService.h"
 #include <boost/make_shared.hpp>
+#include <sstream>
 
 namespace Mantid {
 namespace API {
@@ -40,7 +41,7 @@ void ADSValidator::setOptional(const bool setOptional) {
 */
 std::string
 ADSValidator::checkValidity(const std::vector<std::string> &value) const {
-  if (!m_isOptional && (value.size() == 0))
+  if (!m_isOptional && value.empty())
     return "Select a value";
   if (!m_AllowMultiSelection && (value.size() > 1)) {
     return "Only one workspace was expected.";
diff --git a/Framework/API/src/Algorithm.cpp b/Framework/API/src/Algorithm.cpp
index 06e3b2873308a5ea26382d68905c24e31102f278..3589c42c8e126913a484ff506578ec99e53a5a52 100644
--- a/Framework/API/src/Algorithm.cpp
+++ b/Framework/API/src/Algorithm.cpp
@@ -6,6 +6,7 @@
 #include "MantidAPI/AlgorithmManager.h"
 #include "MantidAPI/IWorkspaceProperty.h"
 #include "MantidAPI/WorkspaceGroup.h"
+#include "MantidAPI/WorkspaceHistory.h"
 
 #include "MantidKernel/ConfigService.h"
 #include "MantidKernel/EmptyValues.h"
@@ -1123,7 +1124,7 @@ bool Algorithm::checkGroups() {
             AnalysisDataService::Instance().retrieve(name);
         if (!memberWS)
           throw std::invalid_argument("One of the members of " +
-                                      wsGroup->name() + ", " + name +
+                                      wsGroup->getName() + ", " + name +
                                       " was not found!.");
         thisGroup.push_back(memberWS);
       }
@@ -1287,12 +1288,12 @@ bool Algorithm::processGroups() {
         // Append the names together
         if (!outputBaseName.empty())
           outputBaseName += "_";
-        outputBaseName += ws->name();
+        outputBaseName += ws->getName();
 
         // Set the property using the name of that workspace
         if (Property *prop =
                 dynamic_cast<Property *>(m_inputWorkspaceProps[iwp])) {
-          alg->setPropertyValue(prop->name(), ws->name());
+          alg->setPropertyValue(prop->name(), ws->getName());
         } else {
           throw std::logic_error("Found a Workspace property which doesn't "
                                  "inherit from Property.");
@@ -1325,7 +1326,7 @@ bool Algorithm::processGroups() {
           const auto &inputGroup =
               m_groups[inputProp - m_inputWorkspaceProps.begin()];
           if (!inputGroup.empty())
-            outName = inputGroup[entry]->name();
+            outName = inputGroup[entry]->getName();
         }
         // Except if all inputs had similar names, then the name is "out_1"
 
diff --git a/Framework/API/src/AlgorithmFactory.cpp b/Framework/API/src/AlgorithmFactory.cpp
index 2fbb1e7cb52961923f8fcfb0e8e2e80e2860cf95..75b2e500be7b7579c41315dc271b304f97503ef3 100644
--- a/Framework/API/src/AlgorithmFactory.cpp
+++ b/Framework/API/src/AlgorithmFactory.cpp
@@ -2,6 +2,7 @@
 // Includes
 //----------------------------------------------------------------------
 #include <sstream>
+#include <boost/algorithm/string.hpp>
 #include "MantidAPI/AlgorithmFactory.h"
 #include "MantidAPI/Algorithm.h"
 #include "MantidKernel/LibraryManager.h"
diff --git a/Framework/API/src/AlgorithmProxy.cpp b/Framework/API/src/AlgorithmProxy.cpp
index 335a606979c307c4a3638ef0c325882c7d3b3823..b822dcf6a977fb3e5c7e79ca0dd94f15c7e30cf0 100644
--- a/Framework/API/src/AlgorithmProxy.cpp
+++ b/Framework/API/src/AlgorithmProxy.cpp
@@ -1,10 +1,8 @@
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidAPI/AlgorithmProxy.h"
 #include "MantidAPI/AlgorithmObserver.h"
 #include "MantidAPI/AlgorithmManager.h"
 #include "MantidAPI/DeprecatedAlgorithm.h"
+#include <MantidKernel/StringTokenizer.h>
 
 #include <Poco/ActiveMethod.h>
 #include <Poco/ActiveResult.h>
@@ -15,10 +13,6 @@ using namespace Mantid::Kernel;
 namespace Mantid {
 namespace API {
 
-//----------------------------------------------------------------------
-// Public methods
-//----------------------------------------------------------------------
-
 /// Constructor
 AlgorithmProxy::AlgorithmProxy(Algorithm_sptr alg)
     : PropertyManagerOwner(),
diff --git a/Framework/API/src/AnalysisDataService.cpp b/Framework/API/src/AnalysisDataService.cpp
index d88362663d687c9f0c9dceb79e8d59498760b0d5..f500c3692a9940ba4fc670e72ac3291a3d881548 100644
--- a/Framework/API/src/AnalysisDataService.cpp
+++ b/Framework/API/src/AnalysisDataService.cpp
@@ -1,5 +1,6 @@
 #include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/WorkspaceGroup.h"
+#include <sstream>
 
 namespace Mantid {
 namespace API {
@@ -78,7 +79,7 @@ void AnalysisDataServiceImpl::add(
   group->observeADSNotifications(true);
   for (size_t i = 0; i < group->size(); ++i) {
     auto ws = group->getItem(i);
-    std::string wsName = ws->name();
+    std::string wsName = ws->getName();
     // if anonymous make up a name and add
     if (wsName.empty()) {
       wsName = name + "_" + std::to_string(i + 1);
@@ -117,7 +118,7 @@ void AnalysisDataServiceImpl::addOrReplace(
   group->observeADSNotifications(true);
   for (size_t i = 0; i < group->size(); ++i) {
     auto ws = group->getItem(i);
-    std::string wsName = ws->name();
+    std::string wsName = ws->getName();
     // make up a name for an anonymous workspace
     if (wsName.empty()) {
       wsName = name + "_" + std::to_string(i + 1);
@@ -210,9 +211,9 @@ void AnalysisDataServiceImpl::deepRemoveGroup(const std::string &name) {
     WorkspaceGroup_sptr gws = boost::dynamic_pointer_cast<WorkspaceGroup>(ws);
     if (gws) {
       // if a member is a group remove its items as well
-      deepRemoveGroup(gws->name());
+      deepRemoveGroup(gws->getName());
     } else {
-      remove(ws->name());
+      remove(ws->getName());
     }
   }
   remove(name);
diff --git a/Framework/API/src/CompositeFunction.cpp b/Framework/API/src/CompositeFunction.cpp
index cfadf847862f1dfc070e839fa140bdbe0981866c..231f4b38cd01f152bfc3c5ada7bff4f542eb6590 100644
--- a/Framework/API/src/CompositeFunction.cpp
+++ b/Framework/API/src/CompositeFunction.cpp
@@ -416,8 +416,11 @@ size_t CompositeFunction::addFunction(IFunction_sptr f) {
  * @param i :: The index of the function to remove
  */
 void CompositeFunction::removeFunction(size_t i) {
-  if (i >= nFunctions())
-    throw std::out_of_range("Function index out of range.");
+  if (i >= nFunctions()) {
+    throw std::out_of_range("Function index (" + std::to_string(i) +
+                            ") out of range (" + std::to_string(nFunctions()) +
+                            ").");
+  }
 
   IFunction_sptr fun = getFunction(i);
 
@@ -477,8 +480,11 @@ void CompositeFunction::replaceFunctionPtr(const IFunction_sptr f_old,
  * @param f :: A pointer to the new function
  */
 void CompositeFunction::replaceFunction(size_t i, IFunction_sptr f) {
-  if (i >= nFunctions())
-    throw std::out_of_range("Function index out of range.");
+  if (i >= nFunctions()) {
+    throw std::out_of_range("Function index (" + std::to_string(i) +
+                            ") out of range (" + std::to_string(nFunctions()) +
+                            ").");
+  }
 
   IFunction_sptr fun = getFunction(i);
   size_t np_old = fun->nParams();
@@ -522,7 +528,9 @@ void CompositeFunction::replaceFunction(size_t i, IFunction_sptr f) {
  */
 IFunction_sptr CompositeFunction::getFunction(std::size_t i) const {
   if (i >= nFunctions()) {
-    throw std::out_of_range("Function index out of range.");
+    throw std::out_of_range("Function index (" + std::to_string(i) +
+                            ") out of range (" + std::to_string(nFunctions()) +
+                            ").");
   }
   return m_functions[i];
 }
@@ -534,7 +542,9 @@ IFunction_sptr CompositeFunction::getFunction(std::size_t i) const {
  */
 size_t CompositeFunction::functionIndex(std::size_t i) const {
   if (i >= nParams()) {
-    throw std::out_of_range("Function parameter index out of range.");
+    throw std::out_of_range("Function parameter index (" + std::to_string(i) +
+                            ") out of range (" + std::to_string(nParams()) +
+                            ").");
   }
   return m_IFunction[i];
 }
@@ -624,10 +634,10 @@ ParameterTie *CompositeFunction::getTie(size_t i) const {
  * Attaches a tie to this function. The attached tie is owned by the function.
  * @param tie :: A pointer to a new tie
  */
-void CompositeFunction::addTie(ParameterTie *tie) {
+void CompositeFunction::addTie(std::unique_ptr<ParameterTie> tie) {
   size_t i = getParameterIndex(*tie);
   size_t iFun = functionIndex(i);
-  m_functions[iFun]->addTie(tie);
+  m_functions[iFun]->addTie(std::move(tie));
 }
 
 /**
@@ -649,10 +659,10 @@ void CompositeFunction::declareParameter(const std::string &name,
 /** Add a constraint
  *  @param ic :: Pointer to a constraint.
  */
-void CompositeFunction::addConstraint(IConstraint *ic) {
+void CompositeFunction::addConstraint(std::unique_ptr<IConstraint> ic) {
   size_t i = getParameterIndex(*ic);
   size_t iFun = functionIndex(i);
-  getFunction(iFun)->addConstraint(ic);
+  getFunction(iFun)->addConstraint(std::move(ic));
 }
 
 /**
diff --git a/Framework/API/src/DataProcessorAlgorithm.cpp b/Framework/API/src/DataProcessorAlgorithm.cpp
index aaafb7ead939b200a967eae837dd21243e37bd47..1e61e78ce112c5048be2eba7f2840447fa7e7f85 100644
--- a/Framework/API/src/DataProcessorAlgorithm.cpp
+++ b/Framework/API/src/DataProcessorAlgorithm.cpp
@@ -236,8 +236,8 @@ Workspace_sptr DataProcessorAlgorithm::assemble(Workspace_sptr partialWS) {
 Workspace_sptr
 DataProcessorAlgorithm::assemble(const std::string &partialWSName,
                                  const std::string &outputWSName) {
-  std::string threadOutput = partialWSName;
 #ifdef MPI_BUILD
+  std::string threadOutput = partialWSName;
   Workspace_sptr partialWS =
       AnalysisDataService::Instance().retrieve(partialWSName);
   IAlgorithm_sptr gatherAlg = createChildAlgorithm("GatherWorkspaces");
@@ -252,6 +252,8 @@ DataProcessorAlgorithm::assemble(const std::string &partialWSName,
     threadOutput = outputWSName;
 #else
   UNUSED_ARG(outputWSName)
+  const std::string &threadOutput = partialWSName;
+
 #endif
   Workspace_sptr outputWS =
       AnalysisDataService::Instance().retrieve(threadOutput);
@@ -272,7 +274,7 @@ void DataProcessorAlgorithm::saveNexus(const std::string &outputWSName,
     saveOutput = false;
 #endif
 
-  if (saveOutput && outputFile.size() > 0) {
+  if (saveOutput && !outputFile.empty()) {
     IAlgorithm_sptr saveAlg = createChildAlgorithm("SaveNexus");
     saveAlg->setPropertyValue("Filename", outputFile);
     saveAlg->setPropertyValue("InputWorkspace", outputWSName);
diff --git a/Framework/API/src/DetectorInfo.cpp b/Framework/API/src/DetectorInfo.cpp
index 90a4ea42ac6bf384ae97a471187d81d0a5fc67ee..71d72a205ce2ae801aa91b2bd02ba51227ac8fc1 100644
--- a/Framework/API/src/DetectorInfo.cpp
+++ b/Framework/API/src/DetectorInfo.cpp
@@ -3,6 +3,7 @@
 #include "MantidGeometry/Instrument/ComponentHelper.h"
 #include "MantidGeometry/Instrument/Detector.h"
 #include "MantidGeometry/Instrument/ReferenceFrame.h"
+#include "MantidBeamline/DetectorInfo.h"
 #include "MantidKernel/Exception.h"
 #include "MantidKernel/MultiThreaded.h"
 
@@ -17,9 +18,10 @@ namespace API {
  * `instrument`. Non-const methods of DetectorInfo may only be called if `pmap`
  * is not null. */
 DetectorInfo::DetectorInfo(
+    Beamline::DetectorInfo &detectorInfo,
     boost::shared_ptr<const Geometry::Instrument> instrument,
     Geometry::ParameterMap *pmap)
-    : m_pmap(pmap), m_instrument(instrument),
+    : m_detectorInfo(detectorInfo), m_pmap(pmap), m_instrument(instrument),
       m_lastDetector(PARALLEL_GET_MAX_THREADS),
       m_lastIndex(PARALLEL_GET_MAX_THREADS, -1) {
   // Note: This does not seem possible currently (the instrument objects is
@@ -32,14 +34,30 @@ DetectorInfo::DetectorInfo(
     m_detIDToIndex[m_detectorIDs[i]] = i;
 }
 
+/// Assigns the contents of the non-wrapping part of `rhs` to this.
+DetectorInfo &DetectorInfo::operator=(const DetectorInfo &rhs) {
+  if (detectorIDs() != rhs.detectorIDs())
+    throw std::runtime_error("DetectorInfo::operator=: Detector IDs in "
+                             "assignment do not match. Assignment not "
+                             "possible");
+  // Do NOT assign anything in the "wrapping" part of DetectorInfo. We simply
+  // assign the underlying Beamline::DetectorInfo.
+  m_detectorInfo = rhs.m_detectorInfo;
+  return *this;
+}
+
+/// Returns the size of the DetectorInfo, i.e., the number of detectors in the
+/// instrument.
+size_t DetectorInfo::size() const { return m_detectorIDs.size(); }
+
 /// Returns true if the detector is a monitor.
 bool DetectorInfo::isMonitor(const size_t index) const {
-  return getDetector(index).isMonitor();
+  return m_detectorInfo.isMonitor(index);
 }
 
-/// Returns true if the detector is a masked.
+/// Returns true if the detector is masked.
 bool DetectorInfo::isMasked(const size_t index) const {
-  return getDetector(index).isMasked();
+  return m_detectorInfo.isMasked(index);
 }
 
 /** Returns L2 (distance from sample to spectrum).
@@ -93,7 +111,21 @@ Kernel::Quat DetectorInfo::rotation(const size_t index) const {
   return getDetector(index).getRotation();
 }
 
-/// Set the absolute position of the detector with given index.
+/// Set the mask flag of the detector with given index. Not thread safe.
+void DetectorInfo::setMasked(const size_t index, bool masked) {
+  m_detectorInfo.setMasked(index, masked);
+}
+
+/** Sets all mask flags to false (unmasked). Not thread safe.
+ *
+ * This method was introduced to help with refactoring and may be removed in the
+ *future. */
+void DetectorInfo::clearMaskFlags() {
+  for (size_t i = 0; i < size(); ++i)
+    m_detectorInfo.setMasked(i, false);
+}
+
+/// Set the absolute position of the detector with given index. Not thread safe.
 void DetectorInfo::setPosition(const size_t index,
                                const Kernel::V3D &position) {
   const auto &det = getDetector(index);
@@ -102,7 +134,7 @@ void DetectorInfo::setPosition(const size_t index,
   moveComponent(det, *m_pmap, position, positionType);
 }
 
-/// Set the absolute rotation of the detector with given index.
+/// Set the absolute rotation of the detector with given index. Not thread safe.
 void DetectorInfo::setRotation(const size_t index,
                                const Kernel::Quat &rotation) {
   const auto &det = getDetector(index);
@@ -111,7 +143,7 @@ void DetectorInfo::setRotation(const size_t index,
   rotateComponent(det, *m_pmap, rotation, rotationType);
 }
 
-/** Set the absolute position of the component `comp`.
+/** Set the absolute position of the component `comp`. Not thread safe.
  *
  * This may or may not be a detector. Even if it is not a detector it will
  * typically still influence detector positions. */
@@ -135,7 +167,7 @@ void DetectorInfo::setPosition(const Geometry::IComponent &comp,
   }
 }
 
-/** Set the absolute rotation of the component `comp`.
+/** Set the absolute rotation of the component `comp`. Not thread safe.
  *
  * This may or may not be a detector. Even if it is not a detector it will
  * typically still influence detector positions rotations. */
@@ -159,6 +191,11 @@ void DetectorInfo::setRotation(const Geometry::IComponent &comp,
   }
 }
 
+/// Return a const reference to the detector with given index.
+const Geometry::IDetector &DetectorInfo::detector(const size_t index) const {
+  return getDetector(index);
+}
+
 /// Returns the source position.
 Kernel::V3D DetectorInfo::sourcePosition() const {
   cacheSource();
diff --git a/Framework/API/src/ExperimentInfo.cpp b/Framework/API/src/ExperimentInfo.cpp
index dadae0f8977e48a052257134636bcd2c745bfcc6..a814d36768e260ad58fa06dd7d30185812c54926 100644
--- a/Framework/API/src/ExperimentInfo.cpp
+++ b/Framework/API/src/ExperimentInfo.cpp
@@ -9,22 +9,30 @@
 
 #include "MantidGeometry/Instrument/InstrumentDefinitionParser.h"
 #include "MantidGeometry/Crystal/OrientedLattice.h"
+#include "MantidGeometry/Instrument/Detector.h"
+#include "MantidGeometry/Instrument/ParameterFactory.h"
 #include "MantidGeometry/Instrument/ParameterMap.h"
 #include "MantidGeometry/Instrument/ParComponentFactory.h"
 #include "MantidGeometry/Instrument/XMLInstrumentParameter.h"
 
+#include "MantidBeamline/DetectorInfo.h"
+
 #include "MantidKernel/ConfigService.h"
 #include "MantidKernel/DateAndTime.h"
 #include "MantidKernel/InstrumentInfo.h"
 #include "MantidKernel/Property.h"
 #include "MantidKernel/Strings.h"
+#include "MantidKernel/StringTokenizer.h"
+#include "MantidKernel/make_unique.h"
 
 #include <boost/algorithm/string.hpp>
+#include <boost/lexical_cast.hpp>
 #include <boost/make_shared.hpp>
 #include <boost/regex.hpp>
 
 #include <Poco/DirectoryIterator.h>
 #include <Poco/Path.h>
+#include <Poco/SAX/Attributes.h>
 #include <Poco/SAX/ContentHandler.h>
 #include <Poco/SAX/SAXParser.h>
 #include <nexus/NeXusException.hpp>
@@ -45,7 +53,8 @@ Kernel::Logger g_log("ExperimentInfo");
 ExperimentInfo::ExperimentInfo()
     : m_moderatorModel(), m_choppers(), m_sample(new Sample()),
       m_run(new Run()), m_parmap(new ParameterMap()),
-      sptr_instrument(new Instrument()) {}
+      sptr_instrument(new Instrument()),
+      m_detectorInfo(boost::make_shared<Beamline::DetectorInfo>(0)) {}
 
 /**
  * Constructs the object from a copy if the input. This leaves the new mutex
@@ -73,6 +82,7 @@ void ExperimentInfo::copyExperimentInfoFrom(const ExperimentInfo *other) {
   for (const auto &chopper : other->m_choppers) {
     m_choppers.push_back(chopper->clone());
   }
+  *m_detectorInfo = *other->m_detectorInfo;
 }
 
 /** Clone this ExperimentInfo class into a new one
@@ -85,6 +95,13 @@ ExperimentInfo *ExperimentInfo::cloneExperimentInfo() const {
 
 /// @returns A human-readable description of the object
 const std::string ExperimentInfo::toString() const {
+  try {
+    populateIfNotLoaded();
+  } catch (std::exception &) {
+    // Catch any errors so that the string returned has as much information
+    // as possible
+  }
+
   std::ostringstream out;
 
   Geometry::Instrument_const_sptr inst = this->getInstrument();
@@ -134,12 +151,51 @@ const std::string ExperimentInfo::toString() const {
   return out.str();
 }
 
+// Helpers for setInstrument and getInstrument
+namespace {
+void checkDetectorInfoSize(const Instrument &instr,
+                           const Beamline::DetectorInfo &detInfo) {
+  const auto numDets = instr.getNumberDetectors();
+  if (numDets != detInfo.size())
+    throw std::runtime_error("ExperimentInfo: size mismatch between "
+                             "DetectorInfo and number of detectors in "
+                             "instrument");
+}
+
+std::unique_ptr<Beamline::DetectorInfo>
+makeDetectorInfo(const Instrument &oldInstr, const Instrument &newInstr) {
+  if (newInstr.hasDetectorInfo()) {
+    // We allocate a new DetectorInfo in case there is an Instrument holding a
+    // reference to our current DetectorInfo.
+    const auto &detInfo = newInstr.detectorInfo();
+    checkDetectorInfoSize(oldInstr, detInfo);
+    return Kernel::make_unique<Beamline::DetectorInfo>(detInfo);
+  } else {
+    // If there is no DetectorInfo in the instrument we create a default one.
+    const auto numDets = oldInstr.getNumberDetectors();
+    // Currently monitors flags are stored in the detector cache of the base
+    // instrument. The copy being made here is strictly speaking duplicating
+    // that data, but with future refactoring this will no longer be the case.
+    // Note that monitors will not change after creating a workspace.
+    // Instrument::markAsMonitor works only for the base instrument and it is
+    // not possible to obtain a non-const reference to the base instrument in a
+    // workspace. Thus we do not need to worry about the two copies of monitor
+    // flags running out of sync.
+    std::vector<size_t> monitors;
+    for (size_t i = 0; i < numDets; ++i)
+      if (newInstr.isMonitorViaIndex(i))
+        monitors.push_back(i);
+    return Kernel::make_unique<Beamline::DetectorInfo>(numDets, monitors);
+  }
+}
+}
+
 /** Set the instrument
 * @param instr :: Shared pointer to an instrument.
 */
 void ExperimentInfo::setInstrument(const Instrument_const_sptr &instr) {
   invalidateInstrumentReferences();
-  m_detectorInfo = nullptr;
+  m_detectorInfoWrapper = nullptr;
   if (instr->isParametrized()) {
     sptr_instrument = instr->baseInstrument();
     m_parmap = instr->getParameterMap();
@@ -147,6 +203,7 @@ void ExperimentInfo::setInstrument(const Instrument_const_sptr &instr) {
     sptr_instrument = instr;
     m_parmap = boost::make_shared<ParameterMap>();
   }
+  m_detectorInfo = makeDetectorInfo(*sptr_instrument, *instr);
 }
 
 /** Get a shared pointer to the parametrized instrument associated with this
@@ -155,14 +212,19 @@ void ExperimentInfo::setInstrument(const Instrument_const_sptr &instr) {
 *  @return The instrument class
 */
 Instrument_const_sptr ExperimentInfo::getInstrument() const {
-  return Geometry::ParComponentFactory::createInstrument(sptr_instrument,
-                                                         m_parmap);
+  populateIfNotLoaded();
+  checkDetectorInfoSize(*sptr_instrument, *m_detectorInfo);
+  auto instrument = Geometry::ParComponentFactory::createInstrument(
+      sptr_instrument, m_parmap);
+  instrument->setDetectorInfo(m_detectorInfo);
+  return instrument;
 }
 
 /**  Returns a new copy of the instrument parameters
 *    @return a (new) copy of the instruments parameter map
 */
 Geometry::ParameterMap &ExperimentInfo::instrumentParameters() {
+  populateIfNotLoaded();
   // TODO: Here duplicates cow_ptr. Figure out if there's a better way
 
   // Use a double-check for sharing so that we only
@@ -174,7 +236,7 @@ Geometry::ParameterMap &ExperimentInfo::instrumentParameters() {
     // and dropped reference count since previous check
     if (!m_parmap.unique()) {
       invalidateInstrumentReferences();
-      m_detectorInfo = nullptr;
+      m_detectorInfoWrapper = nullptr;
     }
     if (!m_parmap.unique()) {
       ParameterMap_sptr oldData = m_parmap;
@@ -188,6 +250,7 @@ Geometry::ParameterMap &ExperimentInfo::instrumentParameters() {
 *    @return a const reference to the instrument ParameterMap.
 */
 const Geometry::ParameterMap &ExperimentInfo::instrumentParameters() const {
+  populateIfNotLoaded();
   return *m_parmap;
 }
 
@@ -196,6 +259,7 @@ const Geometry::ParameterMap &ExperimentInfo::instrumentParameters() const {
 */
 const Geometry::ParameterMap &
 ExperimentInfo::constInstrumentParameters() const {
+  populateIfNotLoaded();
   return *m_parmap;
 }
 
@@ -247,6 +311,7 @@ struct ParameterValue {
 * method.
 */
 void ExperimentInfo::populateInstrumentParameters() {
+  populateIfNotLoaded();
   // Get instrument and sample
   boost::shared_ptr<const Instrument> instrument =
       getInstrument()->baseInstrument();
@@ -313,24 +378,30 @@ void ExperimentInfo::populateInstrumentParameters() {
 
 /**
  * Replaces current parameter map with a copy of the given map
+ * Careful: Parameters that are stored in DetectorInfo are not automatically
+ * handled.
  * @ pmap const reference to parameter map whose copy replaces the current
  * parameter map
  */
 void ExperimentInfo::replaceInstrumentParameters(
     const Geometry::ParameterMap &pmap) {
+  populateIfNotLoaded();
   invalidateInstrumentReferences();
-  m_detectorInfo = nullptr;
+  m_detectorInfoWrapper = nullptr;
   this->m_parmap.reset(new ParameterMap(pmap));
 }
 
 /**
  * exchanges contents of current parameter map with contents of other map)
+ * Careful: Parameters that are stored in DetectorInfo are not automatically
+ * handled.
  * @ pmap reference to parameter map which would exchange its contents with
  * current map
  */
 void ExperimentInfo::swapInstrumentParameters(Geometry::ParameterMap &pmap) {
+  populateIfNotLoaded();
   invalidateInstrumentReferences();
-  m_detectorInfo = nullptr;
+  m_detectorInfoWrapper = nullptr;
   this->m_parmap->swap(pmap);
 }
 
@@ -342,15 +413,23 @@ void ExperimentInfo::swapInstrumentParameters(Geometry::ParameterMap &pmap) {
  * group.
  */
 void ExperimentInfo::cacheDetectorGroupings(const det2group_map &mapping) {
-  m_detgroups = mapping;
+  populateIfNotLoaded();
+  m_detgroups.clear();
+  for (const auto &item : mapping) {
+    m_det2group[item.first] = m_detgroups.size();
+    m_detgroups.push_back(item.second);
+  }
+  // Create default grouping if `mapping` is empty.
+  cacheDefaultDetectorGrouping();
 }
 
 /// Returns the detector IDs that make up the group that this ID is part of
-const std::vector<detid_t> &
+const std::set<detid_t> &
 ExperimentInfo::getGroupMembers(const detid_t detID) const {
-  auto iter = m_detgroups.find(detID);
-  if (iter != m_detgroups.end()) {
-    return iter->second;
+  populateIfNotLoaded();
+  auto iter = m_det2group.find(detID);
+  if (iter != m_det2group.end()) {
+    return m_detgroups[iter->second];
   } else {
     throw std::runtime_error(
         "ExperimentInfo::getGroupMembers - Unable to find ID " +
@@ -366,10 +445,11 @@ ExperimentInfo::getGroupMembers(const detid_t detID) const {
  */
 Geometry::IDetector_const_sptr
 ExperimentInfo::getDetectorByID(const detid_t detID) const {
+  populateIfNotLoaded();
   if (m_detgroups.empty()) {
     return getInstrument()->getDetector(detID);
   } else {
-    const std::vector<detid_t> &ids = this->getGroupMembers(detID);
+    const auto &ids = this->getGroupMembers(detID);
     return getInstrument()->getDetectorG(ids);
   }
 }
@@ -380,6 +460,7 @@ ExperimentInfo::getDetectorByID(const detid_t detID) const {
  * transferred to this object
  */
 void ExperimentInfo::setModeratorModel(ModeratorModel *source) {
+  populateIfNotLoaded();
   if (!source) {
     throw std::invalid_argument(
         "ExperimentInfo::setModeratorModel - NULL source object found.");
@@ -389,6 +470,7 @@ void ExperimentInfo::setModeratorModel(ModeratorModel *source) {
 
 /// Returns a reference to the source properties object
 ModeratorModel &ExperimentInfo::moderatorModel() const {
+  populateIfNotLoaded();
   if (!m_moderatorModel) {
     throw std::runtime_error("ExperimentInfo::moderatorModel - No source "
                              "desciption has been defined");
@@ -407,6 +489,7 @@ ModeratorModel &ExperimentInfo::moderatorModel() const {
  */
 void ExperimentInfo::setChopperModel(ChopperModel *chopper,
                                      const size_t index) {
+  populateIfNotLoaded();
   if (!chopper) {
     throw std::invalid_argument(
         "ExperimentInfo::setChopper - NULL chopper object found.");
@@ -429,6 +512,7 @@ void ExperimentInfo::setChopperModel(ChopperModel *chopper,
  * @return A reference to a const chopper object
  */
 ChopperModel &ExperimentInfo::chopperModel(const size_t index) const {
+  populateIfNotLoaded();
   if (index < m_choppers.size()) {
     auto iter = m_choppers.begin();
     std::advance(iter, index);
@@ -445,6 +529,7 @@ ChopperModel &ExperimentInfo::chopperModel(const size_t index) const {
 * @return const reference to Sample object
 */
 const Sample &ExperimentInfo::sample() const {
+  populateIfNotLoaded();
   std::lock_guard<std::recursive_mutex> lock(m_mutex);
   return *m_sample;
 }
@@ -456,6 +541,7 @@ const Sample &ExperimentInfo::sample() const {
 * @return reference to sample object
 */
 Sample &ExperimentInfo::mutableSample() {
+  populateIfNotLoaded();
   // Use a double-check for sharing so that we only
   // enter the critical region if absolutely necessary
   if (!m_sample.unique()) {
@@ -474,6 +560,7 @@ Sample &ExperimentInfo::mutableSample() {
 * @return const reference to run object
 */
 const Run &ExperimentInfo::run() const {
+  populateIfNotLoaded();
   std::lock_guard<std::recursive_mutex> lock(m_mutex);
   return *m_run;
 }
@@ -485,6 +572,7 @@ const Run &ExperimentInfo::run() const {
 * @return reference to Run object
 */
 Run &ExperimentInfo::mutableRun() {
+  populateIfNotLoaded();
   // Use a double-check for sharing so that we only
   // enter the critical region if absolutely necessary
   if (!m_run.unique()) {
@@ -512,6 +600,7 @@ Run &ExperimentInfo::mutableRun() {
  * @return A pointer to the property
  */
 Kernel::Property *ExperimentInfo::getLog(const std::string &log) const {
+  populateIfNotLoaded();
   try {
     return run().getProperty(log);
   } catch (Kernel::Exception::NotFoundError &) {
@@ -538,6 +627,7 @@ Kernel::Property *ExperimentInfo::getLog(const std::string &log) const {
  * @return A pointer to the property
  */
 double ExperimentInfo::getLogAsSingleValue(const std::string &log) const {
+  populateIfNotLoaded();
   try {
     return run().getPropertyAsSingleValue(log);
   } catch (Kernel::Exception::NotFoundError &) {
@@ -560,6 +650,7 @@ double ExperimentInfo::getLogAsSingleValue(const std::string &log) const {
  * @return the run number (int) or 0 if not found.
  */
 int ExperimentInfo::getRunNumber() const {
+  populateIfNotLoaded();
   const Run &thisRun = run();
   if (!thisRun.hasProperty("run_number")) {
     // No run_number property, default to 0
@@ -588,6 +679,7 @@ int ExperimentInfo::getRunNumber() const {
  * checks the sample log & instrument in this order
  */
 Kernel::DeltaEMode::Type ExperimentInfo::getEMode() const {
+  populateIfNotLoaded();
   static const char *emodeTag = "deltaE-mode";
   std::string emodeStr;
   if (run().hasProperty(emodeTag)) {
@@ -614,6 +706,7 @@ Kernel::DeltaEMode::Type ExperimentInfo::getEMode() const {
  * @return The current EFixed value
  */
 double ExperimentInfo::getEFixed(const detid_t detID) const {
+  populateIfNotLoaded();
   IDetector_const_sptr det = getInstrument()->getDetector(detID);
   return getEFixed(det);
 }
@@ -626,6 +719,7 @@ double ExperimentInfo::getEFixed(const detid_t detID) const {
  */
 double
 ExperimentInfo::getEFixed(const Geometry::IDetector_const_sptr detector) const {
+  populateIfNotLoaded();
   Kernel::DeltaEMode::Type emode = getEMode();
   if (emode == Kernel::DeltaEMode::Direct) {
     try {
@@ -667,6 +761,7 @@ ExperimentInfo::getEFixed(const Geometry::IDetector_const_sptr detector) const {
 }
 
 void ExperimentInfo::setEFixed(const detid_t detID, const double value) {
+  populateIfNotLoaded();
   IDetector_const_sptr det = getInstrument()->getDetector(detID);
   Geometry::ParameterMap &pmap = instrumentParameters();
   pmap.addDouble(det.get(), "Efixed", value);
@@ -738,6 +833,7 @@ void ExperimentInfo::getValidFromTo(const std::string &IDFfilename,
 *available)
 */
 std::string ExperimentInfo::getWorkspaceStartDate() const {
+  populateIfNotLoaded();
   std::string date;
   try {
     date = run().startTime().toISO8601String();
@@ -756,6 +852,7 @@ std::string ExperimentInfo::getWorkspaceStartDate() const {
  *  @return workspace start date as a string (empty if no date available)
  */
 std::string ExperimentInfo::getAvailableWorkspaceStartDate() const {
+  populateIfNotLoaded();
   std::string date;
   try {
     date = run().startTime().toFormattedString();
@@ -772,6 +869,7 @@ std::string ExperimentInfo::getAvailableWorkspaceStartDate() const {
  *  @return workspace end date as a string (empty if no date available)
  */
 std::string ExperimentInfo::getAvailableWorkspaceEndDate() const {
+  populateIfNotLoaded();
   std::string date;
   try {
     date = run().endTime().toFormattedString();
@@ -887,33 +985,86 @@ ExperimentInfo::getInstrumentFilename(const std::string &instrumentName,
  * this reference.
  */
 const DetectorInfo &ExperimentInfo::detectorInfo() const {
-  if (!m_detectorInfo) {
+  populateIfNotLoaded();
+  if (!m_detectorInfoWrapper) {
     std::lock_guard<std::mutex> lock{m_detectorInfoMutex};
-    if (!m_detectorInfo)
-      m_detectorInfo = Kernel::make_unique<DetectorInfo>(getInstrument());
+    if (!m_detectorInfoWrapper)
+      m_detectorInfoWrapper =
+          Kernel::make_unique<DetectorInfo>(*m_detectorInfo, getInstrument());
   }
-  return *m_detectorInfo;
+  return *m_detectorInfoWrapper;
 }
 
 /** Return a non-const reference to the DetectorInfo object. Not thread safe.
  */
 DetectorInfo &ExperimentInfo::mutableDetectorInfo() {
+  populateIfNotLoaded();
   // No locking here since this non-const method is not thread safe.
 
   // We get the non-const ParameterMap reference *first* such that no copy is
   // triggered unless really necessary. The call to `instrumentParameters`
-  // releases the old m_detectorInfo to drop the reference count to the
+  // releases the old m_detectorInfoWrapper to drop the reference count to the
   // ParameterMap by 1 (DetectorInfo contains a parameterized Instrument, so the
-  // reference count to the ParameterMap is at least 2 if m_detectorInfo is not
-  // nullptr: 1 from the ExperimentInfo, 1 from DetectorInfo). If then the
-  // ExperimentInfo is not the sole owner of the ParameterMap a copy is
+  // reference count to the ParameterMap is at least 2 if m_detectorInfoWrapper
+  // is not nullptr: 1 from the ExperimentInfo, 1 from DetectorInfo). If then
+  // the ExperimentInfo is not the sole owner of the ParameterMap a copy is
   // triggered.
   auto pmap = &instrumentParameters();
   // Here `getInstrument` creates a parameterized instrument, increasing the
   // reference count to the ParameterMap. This has do be done *after* getting
   // the ParameterMap.
-  m_detectorInfo = Kernel::make_unique<DetectorInfo>(getInstrument(), pmap);
-  return *m_detectorInfo;
+  m_detectorInfoWrapper =
+      Kernel::make_unique<DetectorInfo>(*m_detectorInfo, getInstrument(), pmap);
+  return *m_detectorInfoWrapper;
+}
+
+/** Returns the number of detector groups.
+ *
+ * This is a virtual method. The default implementation returns grouping
+ * information cached in the ExperimentInfo. This is used in MDAlgorithms. The
+ * more common case is handled by the overload of this method in
+ * MatrixWorkspace. The purpose of this method is to be able to construct
+ * SpectrumInfo based on an ExperimentInfo object, including grouping
+ * information. Grouping information can be cached in ExperimentInfo, or can be
+ * obtained from child classes (MatrixWorkspace). */
+size_t ExperimentInfo::numberOfDetectorGroups() const {
+  populateIfNotLoaded();
+  std::call_once(m_defaultDetectorGroupingCached,
+                 &ExperimentInfo::cacheDefaultDetectorGrouping, this);
+
+  return m_detgroups.size();
+}
+
+/** Returns a set of detector IDs for a group.
+ *
+ * This is a virtual method. The default implementation returns grouping
+ * information cached in the ExperimentInfo. This is used in MDAlgorithms. The
+ * more common case is handled by the overload of this method in
+ * MatrixWorkspace. The purpose of this method is to be able to construct
+ * SpectrumInfo based on an ExperimentInfo object, including grouping
+ * information. Grouping information can be cached in ExperimentInfo, or can be
+ * obtained from child classes (MatrixWorkspace). */
+const std::set<detid_t> &
+ExperimentInfo::detectorIDsInGroup(const size_t index) const {
+  populateIfNotLoaded();
+  std::call_once(m_defaultDetectorGroupingCached,
+                 &ExperimentInfo::cacheDefaultDetectorGrouping, this);
+
+  return m_detgroups.at(index);
+}
+
+/** Sets up a default detector grouping.
+ *
+ * The purpose of this method is to work around potential issues of MDWorkspaces
+ * that do not have grouping information. In such cases a default 1:1
+ * mapping/grouping is generated by this method. See also issue #18252. */
+void ExperimentInfo::cacheDefaultDetectorGrouping() const {
+  if (!m_detgroups.empty())
+    return;
+  for (const auto detID : sptr_instrument->getDetectorIDs()) {
+    m_det2group[detID] = m_detgroups.size();
+    m_detgroups.push_back({detID});
+  }
 }
 
 /** Save the object to an open NeXus file.
@@ -1178,7 +1329,22 @@ void ExperimentInfo::readParameterMap(const std::string &parameterStr) {
     int size = static_cast<int>(tokens.count());
     for (int i = 4; i < size; i++)
       paramValue += ";" + tokens[4];
-    pmap.add(tokens[1], comp, tokens[2], paramValue);
+
+    if (tokens[2].compare("masked") == 0) {
+      // Do not add masking to ParameterMap, it is stored in DetectorInfo
+      const auto det = dynamic_cast<const Detector *const>(comp);
+      if (!det)
+        throw std::runtime_error(
+            "Found masking for a non-detector component. This is not possible");
+      const auto &type = tokens[1];
+      const std::string name = "dummy";
+      auto param = ParameterFactory::create(type, name);
+      param->fromString(paramValue);
+      bool value = param->value<bool>();
+      m_detectorInfo->setMasked(detectorInfo().indexOf(det->getID()), value);
+    } else {
+      pmap.add(tokens[1], comp, tokens[2], paramValue);
+    }
   }
 }
 
@@ -1203,8 +1369,15 @@ void ExperimentInfo::populateWithParameter(
     pDescription = &paramInfo.m_description;
 
   // Some names are special. Values should be convertible to double
-  if (name.compare("x") == 0 || name.compare("y") == 0 ||
-      name.compare("z") == 0) {
+  if (name.compare("masked") == 0) {
+    // Do not add masking to ParameterMap, it is stored in DetectorInfo
+    const auto det = dynamic_cast<const Detector *const>(paramInfo.m_component);
+    if (!det)
+      throw std::runtime_error(
+          "Found masking for a non-detector component. This is not possible");
+    m_detectorInfo->setMasked(detectorInfo().indexOf(det->getID()), paramValue);
+  } else if (name.compare("x") == 0 || name.compare("y") == 0 ||
+             name.compare("z") == 0) {
     paramMap.addPositionCoordinate(paramInfo.m_component, name, paramValue);
   } else if (name.compare("rot") == 0 || name.compare("rotx") == 0 ||
              name.compare("roty") == 0 || name.compare("rotz") == 0) {
@@ -1232,6 +1405,11 @@ void ExperimentInfo::populateWithParameter(
   }
 }
 
+void ExperimentInfo::populateIfNotLoaded() const {
+  // The default implementation does nothing. Used by subclasses
+  // (FileBackedExperimentInfo) to load content from files upon access.
+}
+
 } // namespace Mantid
 } // namespace API
 
diff --git a/Framework/API/src/FileBackedExperimentInfo.cpp b/Framework/API/src/FileBackedExperimentInfo.cpp
index 6435d659a0185d2583e7e897827364f52af50d4b..69aa290c4c65f943c48554b7cdf0ac557d8c6696 100644
--- a/Framework/API/src/FileBackedExperimentInfo.cpp
+++ b/Framework/API/src/FileBackedExperimentInfo.cpp
@@ -10,7 +10,6 @@ namespace Mantid {
 namespace API {
 
 namespace {
-
 /// static logger object
 Kernel::Logger g_log("FileBackedExperimentInfo");
 }
@@ -34,252 +33,6 @@ ExperimentInfo *FileBackedExperimentInfo::cloneExperimentInfo() const {
   return new FileBackedExperimentInfo(*this);
 }
 
-/// @returns A human-readable description of the object
-const std::string FileBackedExperimentInfo::toString() const {
-  try {
-    populateIfNotLoaded();
-  } catch (std::exception &) {
-    // Catch any errors so that the string returned has as much information
-    // as possible
-  }
-  return ExperimentInfo::toString();
-}
-
-/// @return A pointer to the parametrized instrument
-Geometry::Instrument_const_sptr
-FileBackedExperimentInfo::getInstrument() const {
-  populateIfNotLoaded();
-  return ExperimentInfo::getInstrument();
-}
-
-/**
- * @return A reference to a const version of the parameter map
- */
-const Geometry::ParameterMap &
-FileBackedExperimentInfo::instrumentParameters() const {
-  populateIfNotLoaded();
-  return ExperimentInfo::constInstrumentParameters();
-}
-
-/**
- * @return A reference to a non-const version of the parameter map
- */
-Geometry::ParameterMap &FileBackedExperimentInfo::instrumentParameters() {
-  populateIfNotLoaded();
-  return ExperimentInfo::instrumentParameters();
-}
-
-/**
- * @return A reference to a const version of the parameter map
- */
-const Geometry::ParameterMap &
-FileBackedExperimentInfo::constInstrumentParameters() const {
-  populateIfNotLoaded();
-  return ExperimentInfo::constInstrumentParameters();
-}
-
-/**
- * Populate object with instrument parameters
- */
-void FileBackedExperimentInfo::populateInstrumentParameters() {
-  populateIfNotLoaded();
-  return ExperimentInfo::populateInstrumentParameters();
-}
-
-/**
- * Populate object and then replace parameter map
- * @param pmap The new parameter map
- */
-void FileBackedExperimentInfo::replaceInstrumentParameters(
-    const Geometry::ParameterMap &pmap) {
-  populateIfNotLoaded();
-  ExperimentInfo::replaceInstrumentParameters(pmap);
-}
-
-/**
- * Populate object and then swap parameter map
- * @param pmap The new parameter map
- */
-void FileBackedExperimentInfo::swapInstrumentParameters(
-    Geometry::ParameterMap &pmap) {
-  populateIfNotLoaded();
-  ExperimentInfo::swapInstrumentParameters(pmap);
-}
-
-/**
- * Populate the object and cache the groupings
- * @param mapping A set of the detector mappings
- */
-void FileBackedExperimentInfo::cacheDetectorGroupings(
-    const det2group_map &mapping) {
-  populateIfNotLoaded();
-  ExperimentInfo::cacheDetectorGroupings(mapping);
-}
-
-/**
- * Populate the object and returns the members of the group for a given ID
- * @param detID A detector ID to lookup
- */
-const std::vector<detid_t> &
-FileBackedExperimentInfo::getGroupMembers(const detid_t detID) const {
-  populateIfNotLoaded();
-  return ExperimentInfo::getGroupMembers(detID);
-}
-
-/**
- * Populate the object and return a detector by ID
- * @param detID A detector ID to lookup
- */
-Geometry::IDetector_const_sptr
-FileBackedExperimentInfo::getDetectorByID(const detid_t detID) const {
-  populateIfNotLoaded();
-  return ExperimentInfo::getDetectorByID(detID);
-}
-
-/**
- * Populate the object and set the moderator model
- * @param source A pointer to the model of the moderator
- */
-void FileBackedExperimentInfo::setModeratorModel(ModeratorModel *source) {
-  populateIfNotLoaded();
-  ExperimentInfo::setModeratorModel(source);
-}
-
-/**
- * @return The object governing the moderator model
- */
-ModeratorModel &FileBackedExperimentInfo::moderatorModel() const {
-  populateIfNotLoaded();
-  return ExperimentInfo::moderatorModel();
-}
-
-/**
- * Populate the object & set the model governing the chopper
- * @param chopper The model governing the chopper
- * @param index The index of the chopper
- */
-void FileBackedExperimentInfo::setChopperModel(ChopperModel *chopper,
-                                               const size_t index) {
-  populateIfNotLoaded();
-  ExperimentInfo::setChopperModel(chopper, index);
-}
-
-/**
- * Populate the object & return the model of the chopper
- * @param index The index of the chopper
- */
-ChopperModel &FileBackedExperimentInfo::chopperModel(const size_t index) const {
-  populateIfNotLoaded();
-  return ExperimentInfo::chopperModel(index);
-}
-
-/**
- * Populate object and return the Sample
- * @return A const reference to the Sample
- */
-const Sample &FileBackedExperimentInfo::sample() const {
-  populateIfNotLoaded();
-  return ExperimentInfo::sample();
-}
-
-/**
- * Populate object and return a non-const reference to the sample
- * @return A non-const reference to the Sample
- */
-Sample &FileBackedExperimentInfo::mutableSample() {
-  populateIfNotLoaded();
-  return ExperimentInfo::mutableSample();
-}
-
-/**
- * Populate object and return a const reference to the run
- * @return A const reference to the Run
- */
-const Run &FileBackedExperimentInfo::run() const {
-  populateIfNotLoaded();
-  return ExperimentInfo::run();
-}
-
-/**
- * Populate object and return a non-const reference to the run
- * @return A non-const reference to the Run
- */
-Run &FileBackedExperimentInfo::mutableRun() {
-  populateIfNotLoaded();
-  return ExperimentInfo::mutableRun();
-}
-
-/**
- * Return a pointer to a log entry
- * @param log A string name of the log
- * @return A pointer to the log entry
- */
-Kernel::Property *
-FileBackedExperimentInfo::getLog(const std::string &log) const {
-  populateIfNotLoaded();
-  return ExperimentInfo::getLog(log);
-}
-
-/**
- * Return a pointer to a log entry
- * @param log A string name of the log
- * @return A pointer to the log entry
- */
-double
-FileBackedExperimentInfo::getLogAsSingleValue(const std::string &log) const {
-  populateIfNotLoaded();
-  return ExperimentInfo::getLogAsSingleValue(log);
-}
-
-/**
- * @return The run number
- */
-int FileBackedExperimentInfo::getRunNumber() const {
-  populateIfNotLoaded();
-  return ExperimentInfo::getRunNumber();
-}
-
-/**
- * @return The inelastic energy mode
- */
-Kernel::DeltaEMode::Type FileBackedExperimentInfo::getEMode() const {
-  populateIfNotLoaded();
-  return ExperimentInfo::getEMode();
-}
-
-/**
- * @return The efixed for a given detector
- * @param detID The ID of the detector
- */
-double FileBackedExperimentInfo::getEFixed(const detid_t detID) const {
-  populateIfNotLoaded();
-  return ExperimentInfo::getEFixed(detID);
-}
-
-/**
- * Return the efixed value for a given detector
- * @param detector The detector object
- */
-double FileBackedExperimentInfo::getEFixed(
-    const Geometry::IDetector_const_sptr detector) const {
-  populateIfNotLoaded();
-  return ExperimentInfo::getEFixed(detector);
-}
-
-/**
- * Set the efixed value for a given detector
- * @param detID The ID of the detector
- * @param value The value of EFixed
- */
-void FileBackedExperimentInfo::setEFixed(const detid_t detID,
-                                         const double value) {
-  populateIfNotLoaded();
-  ExperimentInfo::setEFixed(detID, value);
-}
-
-//------------------------------------------------------------------------------------------------------
-// Private members
-//------------------------------------------------------------------------------------------------------
 /**
  * Check if the object has been populated and load the information if
  * it has not
diff --git a/Framework/API/src/FileFinder.cpp b/Framework/API/src/FileFinder.cpp
index a9b808e4915382c2a9bb94d01aab57f77112157d..5e6f1f8d668f249a9344a670f41ae0163bb87779 100644
--- a/Framework/API/src/FileFinder.cpp
+++ b/Framework/API/src/FileFinder.cpp
@@ -134,9 +134,8 @@ std::string FileFinderImpl::getFullPath(const std::string &filename,
     if (fName.find("*") != std::string::npos) {
 #endif
       Poco::Path path(searchPath, fName);
-      Poco::Path pathPattern(path);
       std::set<std::string> files;
-      Kernel::Glob::glob(pathPattern, files, m_globOption);
+      Kernel::Glob::glob(path, files, m_globOption);
       if (!files.empty()) {
         Poco::File matchPath(*files.begin());
         if (ignoreDirs && matchPath.isDirectory()) {
diff --git a/Framework/API/src/FileProperty.cpp b/Framework/API/src/FileProperty.cpp
index fd371724aa95a056925cd70392f2cc21c25eaebb..d2bfd6202604789f323e45051589d7af97d98771 100644
--- a/Framework/API/src/FileProperty.cpp
+++ b/Framework/API/src/FileProperty.cpp
@@ -1,6 +1,3 @@
-//-----------------------------------------------------------------
-// Includes
-//-----------------------------------------------------------------
 #include "MantidAPI/FileProperty.h"
 
 #include "MantidAPI/FileFinder.h"
@@ -13,6 +10,8 @@
 #include <Poco/File.h>
 #include <Poco/Path.h>
 
+#include <boost/make_shared.hpp>
+
 #include <algorithm>
 #include <cctype>
 
diff --git a/Framework/API/src/FunctionDomain1D.cpp b/Framework/API/src/FunctionDomain1D.cpp
index 36c1871078133f84248007f8106e62fdf35ca0d1..68ea72ce43fd83c81b9ed2e38aea68e41d6c717f 100644
--- a/Framework/API/src/FunctionDomain1D.cpp
+++ b/Framework/API/src/FunctionDomain1D.cpp
@@ -6,6 +6,10 @@
 namespace Mantid {
 namespace API {
 
+/// The constructor
+FunctionDomain1D::FunctionDomain1D(const double *x, size_t n)
+    : m_data(x), m_n(n), m_peakRadius(0) {}
+
 /// Convert to a vector
 std::vector<double> FunctionDomain1D::toVector() const {
   std::vector<double> res;
@@ -15,6 +19,17 @@ std::vector<double> FunctionDomain1D::toVector() const {
   return res;
 }
 
+/**
+ * Set a peak redius to pass to peak functions.
+ * @param radius :: New radius value.
+ */
+void FunctionDomain1D::setPeakRadius(int radius) { m_peakRadius = radius; }
+
+/**
+ * Get the peak radius.
+ */
+int FunctionDomain1D::getPeakRadius() const { return m_peakRadius; }
+
 /**
   * Create a domain from a vector.
   * @param xvalues :: Vector with function arguments to be copied from.
diff --git a/Framework/API/src/FunctionFactory.cpp b/Framework/API/src/FunctionFactory.cpp
index 0f41405dfaea7504854c60d91674966cd4ec3888..2f870c01799439d5695a028e68c5ea33aaa22e1d 100644
--- a/Framework/API/src/FunctionFactory.cpp
+++ b/Framework/API/src/FunctionFactory.cpp
@@ -278,9 +278,9 @@ void FunctionFactoryImpl::addConstraints(IFunction_sptr fun,
  */
 void FunctionFactoryImpl::addConstraint(IFunction_sptr fun,
                                         const Expression &expr) const {
-  IConstraint *c =
-      ConstraintFactory::Instance().createInitialized(fun.get(), expr);
-  fun->addConstraint(c);
+  auto c = std::unique_ptr<IConstraint>(
+      ConstraintFactory::Instance().createInitialized(fun.get(), expr));
+  fun->addConstraint(std::move(c));
 }
 
 /**
diff --git a/Framework/API/src/FunctionParameterDecorator.cpp b/Framework/API/src/FunctionParameterDecorator.cpp
index 29426981d226300aa9894c636cbad39f74acc70a..4d37ae9545ca6951a86614a2588899f684077ecf 100644
--- a/Framework/API/src/FunctionParameterDecorator.cpp
+++ b/Framework/API/src/FunctionParameterDecorator.cpp
@@ -1,7 +1,9 @@
 #include "MantidAPI/FunctionParameterDecorator.h"
 #include "MantidAPI/FunctionFactory.h"
 #include "MantidAPI/CompositeFunction.h"
+#include "MantidAPI/IConstraint.h"
 #include "MantidAPI/ParameterReference.h"
+#include "MantidAPI/ParameterTie.h"
 
 namespace Mantid {
 namespace API {
@@ -220,12 +222,11 @@ bool FunctionParameterDecorator::hasAttribute(
   return m_wrappedFunction->hasAttribute(attName);
 }
 
-ParameterTie *FunctionParameterDecorator::tie(const std::string &parName,
-                                              const std::string &expr,
-                                              bool isDefault) {
+void FunctionParameterDecorator::tie(const std::string &parName,
+                                     const std::string &expr, bool isDefault) {
   throwIfNoFunctionSet();
 
-  return m_wrappedFunction->tie(parName, expr, isDefault);
+  m_wrappedFunction->tie(parName, expr, isDefault);
 }
 
 void FunctionParameterDecorator::applyTies() {
@@ -258,10 +259,11 @@ ParameterTie *FunctionParameterDecorator::getTie(size_t i) const {
   return m_wrappedFunction->getTie(i);
 }
 
-void FunctionParameterDecorator::addConstraint(IConstraint *ic) {
+void FunctionParameterDecorator::addConstraint(
+    std::unique_ptr<IConstraint> ic) {
   throwIfNoFunctionSet();
 
-  m_wrappedFunction->addConstraint(ic);
+  m_wrappedFunction->addConstraint(std::move(ic));
 }
 
 IConstraint *FunctionParameterDecorator::getConstraint(size_t i) const {
@@ -298,10 +300,10 @@ void FunctionParameterDecorator::declareParameter(
 }
 
 /// Forwads addTie-call to the decorated function.
-void FunctionParameterDecorator::addTie(ParameterTie *tie) {
+void FunctionParameterDecorator::addTie(std::unique_ptr<ParameterTie> tie) {
   throwIfNoFunctionSet();
 
-  m_wrappedFunction->addTie(tie);
+  m_wrappedFunction->addTie(std::move(tie));
 }
 
 /**
diff --git a/Framework/API/src/HistoWorkspace.cpp b/Framework/API/src/HistoWorkspace.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..53bd0712eb98042c39e87727925fdef7562e9fb0
--- /dev/null
+++ b/Framework/API/src/HistoWorkspace.cpp
@@ -0,0 +1,5 @@
+#include "MantidAPI/HistoWorkspace.h"
+
+namespace Mantid {
+namespace API {}
+}
diff --git a/Framework/API/src/IFunction.cpp b/Framework/API/src/IFunction.cpp
index a6605019e326c1e782f98605d2e363e7096f6166..31a143321f9af999cbab5b0b47bd6c63f89eac64 100644
--- a/Framework/API/src/IFunction.cpp
+++ b/Framework/API/src/IFunction.cpp
@@ -1,26 +1,29 @@
-#include "MantidAPI/Axis.h"
 #include "MantidAPI/IFunction.h"
-#include "MantidAPI/Jacobian.h"
-#include "MantidAPI/IConstraint.h"
-#include "MantidAPI/ParameterTie.h"
-#include "MantidAPI/Expression.h"
+#include "MantidAPI/Axis.h"
 #include "MantidAPI/ConstraintFactory.h"
+#include "MantidAPI/Expression.h"
 #include "MantidAPI/FunctionFactory.h"
+#include "MantidAPI/IConstraint.h"
+#include "MantidAPI/IFunctionWithLocation.h"
+#include "MantidAPI/Jacobian.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/MultiDomainFunction.h"
-#include "MantidAPI/IFunctionWithLocation.h"
+#include "MantidAPI/ParameterTie.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidGeometry/Instrument.h"
-#include "MantidGeometry/Instrument/ParameterMap.h"
 #include "MantidGeometry/Instrument/Component.h"
 #include "MantidGeometry/Instrument/DetectorGroup.h"
 #include "MantidGeometry/Instrument/FitParameter.h"
+#include "MantidGeometry/Instrument/ParameterMap.h"
 #include "MantidGeometry/muParser_Silent.h"
 #include "MantidKernel/Exception.h"
+#include "MantidKernel/IPropertyManager.h"
 #include "MantidKernel/Logger.h"
-#include "MantidKernel/UnitFactory.h"
 #include "MantidKernel/MultiThreaded.h"
 #include "MantidKernel/ProgressBase.h"
-#include "MantidKernel/IPropertyManager.h"
+#include "MantidKernel/Strings.h"
+#include "MantidKernel/UnitFactory.h"
+#include "MantidKernel/make_unique.h"
 
 #include <boost/lexical_cast.hpp>
 
@@ -107,12 +110,16 @@ void IFunction::functionDeriv(const FunctionDomain &domain,
  * with this reference: a tie or a constraint.
  * @return newly ties parameters
  */
-ParameterTie *IFunction::tie(const std::string &parName,
-                             const std::string &expr, bool isDefault) {
-  auto ti = new ParameterTie(this, parName, expr, isDefault);
-  addTie(ti);
+void IFunction::tie(const std::string &parName, const std::string &expr,
+                    bool isDefault) {
+  auto ti = Kernel::make_unique<ParameterTie>(this, parName, expr, isDefault);
   this->fix(getParameterIndex(*ti));
-  return ti;
+  if (!isDefault && ti->isConstant()) {
+    setParameter(parName, ti->eval());
+  } else {
+    addTie(std::move(ti));
+  }
+  //  return ti.get();
 }
 
 /**
@@ -138,6 +145,7 @@ void IFunction::addTies(const std::string &ties, bool isDefault) {
       }
     }
   }
+  applyTies();
 }
 
 /** Removes the tie off a parameter. The parameter becomes active
@@ -149,6 +157,36 @@ void IFunction::removeTie(const std::string &parName) {
   this->removeTie(i);
 }
 
+/// Write a parameter tie to a string
+/// @param iParam :: An index of a parameter.
+/// @return A tie string for the parameter.
+std::string IFunction::writeTie(size_t iParam) const {
+  std::ostringstream tieStream;
+  const ParameterTie *tie = getTie(iParam);
+  if (tie) {
+    if (!tie->isDefault()) {
+      tieStream << tie->asString(this);
+    }
+  } else if (isFixed(iParam)) {
+    tieStream << parameterName(iParam) << "=" << getParameter(iParam);
+  }
+  return tieStream.str();
+}
+
+/// Write a parameter constraint to a string
+/// @param iParam :: An index of a parameter.
+/// @return A constraint string for the parameter.
+std::string IFunction::writeConstraint(size_t iParam) const {
+  const IConstraint *c = getConstraint(iParam);
+  if (c && !c->isDefault()) {
+    std::string constraint = c->asString();
+    if (!constraint.empty()) {
+      return constraint;
+    }
+  }
+  return "";
+}
+
 /**
  * Writes a string that can be used in Fit.IFunction to create a copy of this
  * IFunction
@@ -167,46 +205,38 @@ std::string IFunction::asString() const {
   }
   // print the parameters
   for (size_t i = 0; i < nParams(); i++) {
-    const ParameterTie *tie = getTie(i);
-    if (!tie || !tie->isDefault()) {
+    if (!isFixed(i)) {
       ostr << ',' << parameterName(i) << '=' << getParameter(i);
     }
   }
+
   // collect non-default constraints
-  std::string constraints;
+  std::vector<std::string> constraints;
   for (size_t i = 0; i < nParams(); i++) {
-    const IConstraint *c = getConstraint(i);
-    if (c && !c->isDefault()) {
-      std::string tmp = c->asString();
-      if (!tmp.empty()) {
-        if (!constraints.empty()) {
-          constraints += ",";
-        }
-        constraints += tmp;
-      }
+    auto constraint = writeConstraint(i);
+    if (!constraint.empty()) {
+      constraints.push_back(constraint);
     }
   }
   // print constraints
   if (!constraints.empty()) {
-    ostr << ",constraints=(" << constraints << ")";
+    ostr << ",constraints=("
+         << Kernel::Strings::join(constraints.begin(), constraints.end(), ",")
+         << ")";
   }
+
   // collect the non-default ties
-  std::string ties;
+  std::vector<std::string> ties;
   for (size_t i = 0; i < nParams(); i++) {
-    const ParameterTie *tie = getTie(i);
-    if (tie && !tie->isDefault()) {
-      std::string tmp = tie->asString(this);
-      if (!tmp.empty()) {
-        if (!ties.empty()) {
-          ties += ",";
-        }
-        ties += tmp;
-      }
+    auto tie = writeTie(i);
+    if (!tie.empty()) {
+      ties.push_back(tie);
     }
   }
   // print the ties
   if (!ties.empty()) {
-    ostr << ",ties=(" << ties << ")";
+    ostr << ",ties=(" << Kernel::Strings::join(ties.begin(), ties.end(), ",")
+         << ")";
   }
   return ostr.str();
 }
@@ -222,9 +252,9 @@ void IFunction::addConstraints(const std::string &str, bool isDefault) {
   list.parse(str);
   list.toList();
   for (const auto &expr : list) {
-    IConstraint *c =
-        ConstraintFactory::Instance().createInitialized(this, expr, isDefault);
-    this->addConstraint(c);
+    auto c = std::unique_ptr<IConstraint>(
+        ConstraintFactory::Instance().createInitialized(this, expr, isDefault));
+    this->addConstraint(std::move(c));
   }
 }
 
@@ -599,7 +629,8 @@ void IFunction::Attribute::fromString(const std::string &str) {
 /// parameters different from the declared
 double IFunction::activeParameter(size_t i) const {
   if (!isActive(i)) {
-    throw std::runtime_error("Attempt to use an inactive parameter");
+    throw std::runtime_error("Attempt to use an inactive parameter " +
+                             parameterName(i));
   }
   return getParameter(i);
 }
@@ -608,7 +639,8 @@ double IFunction::activeParameter(size_t i) const {
 /// parameters different from the declared
 void IFunction::setActiveParameter(size_t i, double value) {
   if (!isActive(i)) {
-    throw std::runtime_error("Attempt to use an inactive parameter");
+    throw std::runtime_error("Attempt to use an inactive parameter " +
+                             parameterName(i));
   }
   setParameter(i, value);
 }
@@ -619,7 +651,8 @@ void IFunction::setActiveParameter(size_t i, double value) {
  */
 std::string IFunction::nameOfActive(size_t i) const {
   if (!isActive(i)) {
-    throw std::runtime_error("Attempt to use an inactive parameter");
+    throw std::runtime_error("Attempt to use an inactive parameter " +
+                             parameterName(i));
   }
   return parameterName(i);
 }
@@ -630,7 +663,8 @@ std::string IFunction::nameOfActive(size_t i) const {
  */
 std::string IFunction::descriptionOfActive(size_t i) const {
   if (!isActive(i)) {
-    throw std::runtime_error("Attempt to use an inactive parameter");
+    throw std::runtime_error("Attempt to use an inactive parameter " +
+                             parameterName(i));
   }
   return parameterDescription(i);
 }
@@ -869,7 +903,7 @@ void IFunction::setMatrixWorkspace(
                       << "Can't set penalty factor for constraint\n";
                 }
               }
-              addConstraint(constraint);
+              addConstraint(std::unique_ptr<IConstraint>(constraint));
             }
           }
         }
@@ -940,22 +974,18 @@ void IFunction::convertValue(std::vector<double> &values,
           << "Ignore convertion.";
       return;
     }
-    double l1 = instrument->getSource()->getDistance(*sample);
-    Geometry::IDetector_const_sptr det = ws->getDetector(wsIndex);
-    double l2(-1.0), twoTheta(0.0);
-    if (!det->isMonitor()) {
-      l2 = det->getDistance(*sample);
-      twoTheta = ws->detectorTwoTheta(*det);
-    } else // If this is a monitor then make l1+l2 = source-detector distance
-           // and twoTheta=0
-    {
-      l2 = det->getDistance(*(instrument->getSource()));
-      l2 = l2 - l1;
-      twoTheta = 0.0;
-    }
+    const auto &spectrumInfo = ws->spectrumInfo();
+    double l1 = spectrumInfo.l1();
+    // If this is a monitor then l1+l2 = source-detector distance and twoTheta=0
+    double l2 = spectrumInfo.l2(wsIndex);
+    double twoTheta(0.0);
+    if (!spectrumInfo.isMonitor(wsIndex))
+      twoTheta = spectrumInfo.twoTheta(wsIndex);
     int emode = static_cast<int>(ws->getEMode());
     double efixed(0.0);
     try {
+      boost::shared_ptr<const Geometry::IDetector> det(
+          &spectrumInfo.detector(wsIndex), NoDeleting());
       efixed = ws->getEFixed(det);
     } catch (std::exception &) {
       // assume elastic
@@ -1071,6 +1101,17 @@ void IFunction::storeAttributeValue(const std::string &name,
   }
 }
 
+/**
+*  Store a value to a named attribute if it can be considered "mutable" or
+*  read only, which simply reflects the current state of the function.
+*  @param name :: The name of the attribute
+*  @param value :: The value of the attribute
+*/
+void IFunction::storeReadOnlyAttribute(
+    const std::string &name, const API::IFunction::Attribute &value) const {
+  const_cast<IFunction *>(this)->storeAttributeValue(name, value);
+}
+
 /**
  * Set the covariance matrix. Algorithm Fit sets this matrix to the top-level
  * function
diff --git a/Framework/API/src/IMDWorkspace.cpp b/Framework/API/src/IMDWorkspace.cpp
index 3ab3913bd0051b7087ce51f8f2ae2c94fc081b4c..b2701e8a5318c19e86ce0e56aeab1da30e35b4cf 100644
--- a/Framework/API/src/IMDWorkspace.cpp
+++ b/Framework/API/src/IMDWorkspace.cpp
@@ -1,4 +1,5 @@
 #include "MantidAPI/IMDWorkspace.h"
+#include "MantidGeometry/MDGeometry/IMDDimension.h"
 #include "MantidKernel/Exception.h"
 #include "MantidKernel/IPropertyManager.h"
 #include "MantidKernel/ConfigService.h"
@@ -94,7 +95,7 @@ const std::string IMDWorkspace::toString() const {
   os << id() << "\n"
      << "Title: " + getTitle() << "\n";
   for (size_t i = 0; i < getNumDims(); i++) {
-    Geometry::IMDDimension_const_sptr dim = getDimension(i);
+    const auto &dim = getDimension(i);
     os << "Dim " << i << ": (" << dim->getName() << ") " << dim->getMinimum()
        << " to " << dim->getMaximum() << " in " << dim->getNBins() << " bins";
     // Also show the dimension ID string, if different than name
diff --git a/Framework/API/src/IPeakFunction.cpp b/Framework/API/src/IPeakFunction.cpp
index 63d4f9b66ce2fd173c72825e0d2ea1627330946e..99541fecf29ceac2357ea28ad76a78bb78057ae3 100644
--- a/Framework/API/src/IPeakFunction.cpp
+++ b/Framework/API/src/IPeakFunction.cpp
@@ -7,15 +7,17 @@
 #include "MantidAPI/PeakFunctionIntegrator.h"
 #include "MantidAPI/FunctionParameterDecorator.h"
 #include "MantidKernel/Exception.h"
-#include "MantidKernel/ConfigService.h"
 
 #include <boost/lexical_cast.hpp>
 #include <boost/make_shared.hpp>
 #include <cmath>
+#include <limits>
 
 namespace Mantid {
 namespace API {
 
+namespace {
+
 /** A Jacobian for individual functions
  */
 class PartialJacobian1 : public Jacobian {
@@ -78,21 +80,24 @@ protected:
   std::vector<double> m_J;
 };
 
-/// Default value for the peak radius
-int IPeakFunction::s_peakRadius = 5;
+/// Tolerance for determining the smallest significant value on the peak
+const double PEAK_TOLERANCE = 1e-14;
+/// "Infinite" value for the peak radius
+const int MAX_PEAK_RADIUS = std::numeric_limits<int>::max();
+
+} // namespace
 
 /**
-  * Constructor. Sets peak radius to the value of curvefitting.peakRadius
- * property
+  * Constructor.
   */
-IPeakFunction::IPeakFunction() {
-  int peakRadius;
-  if (Kernel::ConfigService::Instance().getValue("curvefitting.peakRadius",
-                                                 peakRadius)) {
-    if (peakRadius != s_peakRadius) {
-      setPeakRadius(peakRadius);
-    }
-  }
+IPeakFunction::IPeakFunction() : m_peakRadius(MAX_PEAK_RADIUS) {}
+
+void IPeakFunction::function(const FunctionDomain &domain,
+                             FunctionValues &values) const {
+  auto peakRadius =
+      dynamic_cast<const FunctionDomain1D &>(domain).getPeakRadius();
+  setPeakRadius(peakRadius);
+  IFunction1D::function(domain, values);
 }
 
 /**
@@ -108,7 +113,7 @@ IPeakFunction::IPeakFunction() {
 void IPeakFunction::function1D(double *out, const double *xValues,
                                const size_t nData) const {
   double c = this->centre();
-  double dx = fabs(s_peakRadius * this->fwhm());
+  double dx = fabs(m_peakRadius * this->fwhm());
   int i0 = -1;
   int n = 0;
   for (size_t i = 0; i < nData; ++i) {
@@ -139,7 +144,7 @@ void IPeakFunction::function1D(double *out, const double *xValues,
 void IPeakFunction::functionDeriv1D(Jacobian *out, const double *xValues,
                                     const size_t nData) {
   double c = this->centre();
-  double dx = fabs(s_peakRadius * this->fwhm());
+  double dx = fabs(m_peakRadius * this->fwhm());
   int i0 = -1;
   int n = 0;
   for (size_t i = 0; i < nData; ++i) {
@@ -159,23 +164,22 @@ void IPeakFunction::functionDeriv1D(Jacobian *out, const double *xValues,
   this->functionDerivLocal(&J, xValues + i0, n);
 }
 
-void IPeakFunction::setPeakRadius(const int &r) {
+void IPeakFunction::setPeakRadius(int r) const {
   if (r > 0) {
-    s_peakRadius = r;
-    std::string setting = std::to_string(r);
-    Kernel::ConfigService::Instance().setString("curvefitting.peakRadius",
-                                                setting);
+    m_peakRadius = r;
+  } else if (r == 0) {
+    m_peakRadius = MAX_PEAK_RADIUS;
   }
 }
 
 /// Returns the integral intensity of the peak function, using the peak radius
 /// to determine integration borders.
 double IPeakFunction::intensity() const {
-  double x0 = centre();
-  double dx = fabs(s_peakRadius * fwhm());
+  auto interval = getDomainInterval();
 
   PeakFunctionIntegrator integrator;
-  IntegrationResult result = integrator.integrate(*this, x0 - dx, x0 + dx);
+  IntegrationResult result =
+      integrator.integrate(*this, interval.first, interval.second);
 
   if (!result.success) {
     return 0.0;
@@ -226,5 +230,40 @@ std::string IPeakFunction::getCentreParameterName() const {
   return parameterName(jacobian.maxParam(0));
 }
 
+/// Get the interval on which the peak has all its values above a certain
+/// level. All values outside the interval are below that level.
+/// @param level :: A fraction of the peak height.
+/// @return A pair of doubles giving the bounds of the interval.
+std::pair<double, double> IPeakFunction::getDomainInterval(double level) const {
+  if (level < PEAK_TOLERANCE) {
+    level = PEAK_TOLERANCE;
+  }
+  double left = 0.0;
+  double right = 0.0;
+  auto h = height();
+  auto w = fwhm();
+  auto c = centre();
+  if (h == 0.0 || w == 0.0 || level >= 1.0) {
+    return std::make_pair(c, c);
+  }
+
+  auto findBound = [this, c, h, level](double dx) {
+    for (size_t i = 0; i < 100; ++i) {
+      double x = c + dx;
+      double y = 0.0;
+      this->functionLocal(&y, &x, 1);
+      if (fabs(y / h) < level) {
+        return x;
+      }
+      dx *= 2;
+    }
+    return c + dx;
+  };
+
+  left = findBound(-w);
+  right = findBound(w);
+  return std::make_pair(left, right);
+}
+
 } // namespace API
 } // namespace Mantid
diff --git a/Framework/API/src/ImplicitFunctionParserFactory.cpp b/Framework/API/src/ImplicitFunctionParserFactory.cpp
index 9a13f894941560ad6e748903857b93a2fa91e4ef..14e1ab5afd4977a6c9b397a19295fa1e9c31d3aa 100644
--- a/Framework/API/src/ImplicitFunctionParserFactory.cpp
+++ b/Framework/API/src/ImplicitFunctionParserFactory.cpp
@@ -18,7 +18,7 @@ ImplicitFunctionParserFactoryImpl::create(const std::string &xmlString) const {
 ImplicitFunctionParser *
 ImplicitFunctionParserFactoryImpl::createImplicitFunctionParserFromXML(
     Poco::XML::Element *functionElement) const {
-  std::string name = functionElement->localName();
+  const std::string &name = functionElement->localName();
   if (name != "Function") {
     throw std::runtime_error(
         "Root node must be a Funtion element. Unable to determine parsers.");
diff --git a/Framework/API/src/LiveListenerFactory.cpp b/Framework/API/src/LiveListenerFactory.cpp
index 05821e0731d84969193df6fce97de8103ec0a4ff..b4803bb15405533c46af736e66e061e54ac61834 100644
--- a/Framework/API/src/LiveListenerFactory.cpp
+++ b/Framework/API/src/LiveListenerFactory.cpp
@@ -13,103 +13,107 @@ namespace {
 Kernel::Logger g_log("LiveListenerFactory");
 }
 
-/** Creates an instance of the appropriate listener for the given instrument,
- * and establishes the
- *  connection to the data acquisition.
- *  @param instrumentName The name of the instrument to 'listen to' (Note that
- * the argument has
- *                        different semantics to the base class create method).
- *  @param connect        Whether to connect the listener to the data stream for
- * the given instrument.
- *  @param properties     Property manager to copy property values to the
- * listener if it has any.
- *  @returns A shared pointer to the created ILiveListener implementation
- *  @throws Exception::NotFoundError If the requested listener is not registered
- *  @throws std::runtime_error If unable to connect to the listener at the
- * configured address
+/**
+ * Creates an instance of the appropriate listener for the given instrument,
+ * and establishes the connection to the data acquisition.
+ *
+ * @param instrumentName The name of the instrument to 'listen to' (Note that
+ *                       the argument has different semantics to the base class
+ *                       create method).
+ * @param connect        Whether to connect the listener to the data stream for
+ *                       the given instrument.
+ * @param properties     Property manager to copy property values to the
+ *                       listener if it has any.
+ * @param listenerConnectionName Name of LiveListenerInfo connection to use.
+ * @return A shared pointer to the created ILiveListener implementation
+ * @throws Exception::NotFoundError If the requested listener is not registered
+ * @throws std::runtime_error If unable to connect to the listener at the
+ *                            configured address.
  */
 boost::shared_ptr<ILiveListener> LiveListenerFactoryImpl::create(
     const std::string &instrumentName, bool connect,
-    const Kernel::IPropertyManager *properties) const {
-  ILiveListener_sptr listener;
-  // See if we know about the instrument with the given name
+    const Kernel::IPropertyManager *properties,
+    const std::string &listenerConnectionName) const {
   try {
-    Kernel::InstrumentInfo inst =
-        Kernel::ConfigService::Instance().getInstrument(instrumentName);
-    listener =
-        Kernel::DynamicFactory<ILiveListener>::create(inst.liveListener());
-    // set the properties
-    if (properties) {
-      listener->updatePropertyValues(*properties);
+    // Look up LiveListenerInfo based on given instrument and listener names
+    auto inst = Kernel::ConfigService::Instance().getInstrument(instrumentName);
+    auto info = inst.liveListenerInfo(listenerConnectionName);
+
+    // Defer creation logic to other create overload
+    return create(info, connect, properties);
+
+  } catch (Kernel::Exception::NotFoundError &) {
+    // Could not determine LiveListenerInfo for instrumentName
+    // Attempt to interpret instrumentName as listener class name instead, to
+    // support legacy usage in unit tests.
+    Kernel::LiveListenerInfo info(instrumentName);
+    return create(info, connect, properties);
+  }
+}
+
+/**
+ * Creates an instance of a specific LiveListener based on the given
+ * LiveListenerInfo instance. The only required data from LiveListenerInfo is
+ * the listener class name. If connect is set to true, a valid address is also
+ * required.
+ *
+ * @param info       LiveListenerInfo based on which to create the LiveListener
+ * @param connect    Whether to connect the listener to the data stream for the
+ *                   given instrument.
+ * @param properties Property manager to copy property values to the listener
+ *                   if it has any.
+ * @return A shared pointer to the created ILiveListener implementation
+ */
+boost::shared_ptr<ILiveListener> LiveListenerFactoryImpl::create(
+    const Kernel::LiveListenerInfo &info, bool connect,
+    const Kernel::IPropertyManager *properties) const {
+
+  ILiveListener_sptr listener =
+      Kernel::DynamicFactory<ILiveListener>::create(info.listener());
+
+  // Give LiveListener additional properties if provided
+  if (properties) {
+    listener->updatePropertyValues(*properties);
+  }
+
+  if (connect) {
+    try {
+      Poco::Net::SocketAddress address;
+
+      // To allow listener::connect to be called even when no address is given
+      if (!info.address().empty())
+        address = Poco::Net::SocketAddress(info.address());
+
+      // If we can't connect, throw an exception to be handled below
+      if (!listener->connect(address)) {
+        throw Poco::Exception("Connection attempt failed.");
+      }
     }
-    if (connect &&
-        !listener->connect(Poco::Net::SocketAddress(inst.liveDataAddress()))) {
-      // If we can't connect, log and throw an exception
+    // The Poco SocketAddress can throw all manner of exceptions if the address
+    // string it gets is badly formed, or it can't successfully look up the
+    // server given, or .......
+    // Just catch the base class exception
+    catch (Poco::Exception &pocoEx) {
       std::stringstream ss;
-      ss << "Unable to connect listener " << listener->name() << " to "
-         << inst.liveDataAddress();
+      ss << "Unable to connect listener [" << info.listener() << "] to ["
+         << info.address() << "]: " << pocoEx.what();
       g_log.debug(ss.str());
       throw std::runtime_error(ss.str());
     }
-  } catch (Kernel::Exception::NotFoundError &) {
-    // If we get to here either we don't know of the instrument name given, or
-    // the the live
-    // listener class given for the instrument is not known.
-    // During development, and for testing, we allow the direct passing in of a
-    // listener name
-    //   - so try to create that. Will throw if it doesn't exist - let that
-    //   exception get out
-    listener = Kernel::DynamicFactory<ILiveListener>::create(instrumentName);
-    if (connect)
-      listener->connect(Poco::Net::SocketAddress()); // Dummy argument for now
-  }
-  // The Poco SocketAddress can throw all manner of exceptions if the address
-  // string it gets is
-  // badly formed, or it can't successfully look up the server given, or .......
-  // Just catch the base class exception
-  catch (Poco::Exception &pocoEx) {
-    std::stringstream ss;
-    ss << "Unable to connect listener " << listener->name() << " to "
-       << instrumentName << ": " << pocoEx.what();
-    g_log.debug(ss.str());
-    throw std::runtime_error(ss.str());
   }
 
   // If we get to here, it's all good!
   return listener;
 }
 
-/** Tries to connect to the named instrument and returns an indicator of success
- * or failure.
- *  Useful for clients that want to just check whether it's possible to connect
- * to a live stream
- *  but not maintain and use the connection (e.g. for enabling or disabling some
- * GUI button).
- *  @param instrumentName The name of the instrument to connect to
- *  @return True if able to connect, false otherwise
- */
-bool LiveListenerFactoryImpl::checkConnection(
-    const std::string &instrumentName) const {
-  try {
-    // Create the live listener (which will try to connect).
-    // Don't capture the returned listener - just let it die.
-    create(instrumentName, true);
-    // If we get to here we have connected successfully.
-    return true;
-  } catch (std::runtime_error &) {
-    // We couldn't connect. Return false.
-    return false;
-  }
-}
-
-/** Override the DynamicFactory::createUnwrapped() method. We don't want it used
- * here.
- *  Making it private will prevent most accidental usage, though of course this
- * could
- *  be called through a DynamicFactory pointer or reference.
- *  @param className Argument that's ignored
- *  @returns Never
- *  @throws Exception::NotImplementedError every time!
+/**
+ * Override the DynamicFactory::createUnwrapped() method. We don't want it used
+ * here. Making it private will prevent most accidental usage, though of course
+ * this could be called through a DynamicFactory pointer or reference.
+ *
+ * @param className Argument that's ignored
+ * @returns Never
+ * @throws Exception::NotImplementedError every time!
  */
 ILiveListener *
 LiveListenerFactoryImpl::createUnwrapped(const std::string &className) const {
@@ -117,5 +121,6 @@ LiveListenerFactoryImpl::createUnwrapped(const std::string &className) const {
   throw Kernel::Exception::NotImplementedError(
       "Don't use this method - use the safe one!!!");
 }
+
 } // namespace Mantid
 } // namespace API
diff --git a/Framework/API/src/LogFilterGenerator.cpp b/Framework/API/src/LogFilterGenerator.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..bbf0ebbab67e8bdb0fd2758dbe6d12015fd76edd
--- /dev/null
+++ b/Framework/API/src/LogFilterGenerator.cpp
@@ -0,0 +1,147 @@
+#include "MantidAPI/LogFilterGenerator.h"
+#include "MantidAPI/MatrixWorkspace.h"
+#include "MantidKernel/Logger.h"
+#include "MantidKernel/make_unique.h"
+#include "MantidKernel/TimeSeriesProperty.h"
+
+using Mantid::Kernel::LogFilter;
+using Mantid::Kernel::TimeSeriesProperty;
+using Mantid::Kernel::Property;
+
+namespace {
+/// static Logger definition
+Mantid::Kernel::Logger g_log("LogFilterGenerator");
+}
+
+namespace Mantid {
+namespace API {
+
+/**
+ * Constructor
+ * @param filterType :: [input] Filter by status, period, both or neither
+ * @param workspace :: [input] Workspace containing log data
+ */
+LogFilterGenerator::LogFilterGenerator(
+    const LogFilterGenerator::FilterType filterType,
+    const Mantid::API::MatrixWorkspace_const_sptr &workspace)
+    : m_filterType(filterType), m_run(workspace->run()) {}
+
+/**
+ * Constructor
+ * @param filterType :: [input] Filter by status, period, both or neither
+ * @param run :: [input] Run containing log data
+ */
+LogFilterGenerator::LogFilterGenerator(
+    const LogFilterGenerator::FilterType filterType,
+    const Mantid::API::Run &run)
+    : m_filterType(filterType), m_run(run) {}
+
+/**
+ * Generate log filter from given workspace and log name
+ * @param logName :: [input] Name of log to generate filter for
+ * @returns :: LogFilter with selected options
+ */
+std::unique_ptr<LogFilter>
+LogFilterGenerator::generateFilter(const std::string &logName) const {
+  const auto *logData = getLogData(logName);
+  if (!logData) {
+    throw std::invalid_argument("Workspace does not contain log " + logName);
+  }
+
+  // This will throw if the log is not a numeric time series.
+  // This behaviour is what we want, so don't catch the exception
+  auto flt = Mantid::Kernel::make_unique<LogFilter>(logData);
+
+  switch (m_filterType) {
+  case FilterType::None:
+    break; // Do nothing
+  case FilterType::Period:
+    filterByPeriod(flt.get());
+    break;
+  case FilterType::Status:
+    filterByStatus(flt.get());
+    break;
+  case FilterType::StatusAndPeriod:
+    filterByPeriod(flt.get());
+    filterByStatus(flt.get());
+    break;
+  default:
+    break;
+  }
+
+  return flt;
+}
+
+/**
+ * Adds a filter to the given LogFilter based on the "running" status log of the
+ * workspace.
+ * If that log is not present, does nothing.
+ * If the filter records start later than the data, add a value of "not running"
+ * at the start.
+ * @param filter :: [input, output] LogFilter to which filter will be added
+ */
+void LogFilterGenerator::filterByStatus(LogFilter *filter) const {
+  const auto status = dynamic_cast<Mantid::Kernel::TimeSeriesProperty<bool> *>(
+      getLogData("running"));
+  if (!status) {
+    return;
+  }
+  filter->addFilter(*status);
+  const auto &time_value_map = filter->data()->valueAsCorrectMap();
+  const auto &firstTime = time_value_map.begin()->first;
+  // If filter records start later than the data we add a value at the
+  // filter's front
+  if (status->firstTime() > firstTime) {
+    // add a "not running" value to the status filter
+    Mantid::Kernel::TimeSeriesProperty<bool> atStart("tmp");
+    atStart.addValue(firstTime, false);
+    atStart.addValue(status->firstTime(), status->firstValue());
+    filter->addFilter(atStart);
+  }
+}
+
+/**
+ * Adds filters to the given LogFilter based on the first "period *" log in the
+ * workspace.
+ * If no such log is present, does nothing.
+ * @param filter :: [input, output] LogFilter to which filter will be added
+ */
+void LogFilterGenerator::filterByPeriod(LogFilter *filter) const {
+  const auto &logs = m_run.getLogData();
+  for (const auto &log : logs) {
+    if (log->name().find("period ") == 0) {
+      try {
+        const auto periodLog =
+            dynamic_cast<Mantid::Kernel::TimeSeriesProperty<bool> *>(log);
+        if (periodLog) {
+          filter->addFilter(*periodLog);
+        } else {
+          g_log.warning("Could not filter by period");
+          return;
+        }
+      } catch (const std::runtime_error &err) {
+        g_log.warning() << "Could not filter by period: " << err.what();
+        return;
+      }
+      break;
+    }
+  }
+}
+
+/**
+ * Get log data from workspace
+ * @param logName :: [input] Name of log to get
+ * @returns :: Pointer to log, or null if log does not exist in workspace
+ */
+Property *LogFilterGenerator::getLogData(const std::string &logName) const {
+  try {
+    const auto logData = m_run.getLogData(logName);
+    return logData;
+  } catch (const std::runtime_error &) {
+    g_log.warning("Could not find log value " + logName + " in workspace");
+    return nullptr;
+  }
+}
+
+} // namespace API
+} // namespace Mantid
diff --git a/Framework/API/src/LogManager.cpp b/Framework/API/src/LogManager.cpp
index 1bbffa8810d0cafedf603c6eeb89912ea3ef1ade..81780756f18eecf3c85c8c65ad0db5988159f7ad 100644
--- a/Framework/API/src/LogManager.cpp
+++ b/Framework/API/src/LogManager.cpp
@@ -1,11 +1,10 @@
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidAPI/LogManager.h"
+#include "MantidKernel/Cache.h"
 #include "MantidKernel/PropertyNexus.h"
-
 #include "MantidKernel/TimeSeriesProperty.h"
 
+#include <nexus/NeXusFile.hpp>
+
 namespace Mantid {
 namespace API {
 
@@ -93,6 +92,27 @@ const char *LogManager::PROTON_CHARGE_LOG_NAME = "gd_prtn_chrg";
 // Public member functions
 //----------------------------------------------------------------------
 
+LogManager::LogManager()
+    : m_singleValueCache(Kernel::make_unique<Kernel::Cache<
+          std::pair<std::string, Kernel::Math::StatisticType>, double>>()) {}
+
+LogManager::LogManager(const LogManager &other)
+    : m_manager(other.m_manager),
+      m_singleValueCache(Kernel::make_unique<Kernel::Cache<
+          std::pair<std::string, Kernel::Math::StatisticType>, double>>(
+          *other.m_singleValueCache)) {}
+
+// Defined as default in source for forward declaration with std::unique_ptr.
+LogManager::~LogManager() = default;
+
+LogManager &LogManager::operator=(const LogManager &other) {
+  m_manager = other.m_manager;
+  m_singleValueCache = Kernel::make_unique<Kernel::Cache<
+      std::pair<std::string, Kernel::Math::StatisticType>, double>>(
+      *other.m_singleValueCache);
+  return *this;
+}
+
 /**
 * Set the run start and end
 * @param start :: The run start
@@ -211,7 +231,7 @@ void LogManager::splitByTime(TimeSplitterType &splitter,
  */
 void LogManager::filterByLog(const Kernel::TimeSeriesProperty<bool> &filter) {
   // This will invalidate the cache
-  m_singleValueCache.clear();
+  m_singleValueCache->clear();
   m_manager.filterByProperty(filter);
 }
 
@@ -260,7 +280,7 @@ bool LogManager::hasProperty(const std::string &name) const {
 void LogManager::removeProperty(const std::string &name, bool delProperty) {
   // Remove any cached entries for this log. Need to make this more general
   for (unsigned int stat = 0; stat < 7; ++stat) {
-    m_singleValueCache.removeCache(
+    m_singleValueCache->removeCache(
         std::make_pair(name, static_cast<Math::StatisticType>(stat)));
   }
   m_manager.removeProperty(name, delProperty);
@@ -329,7 +349,7 @@ double LogManager::getPropertyAsSingleValue(
     const std::string &name, Kernel::Math::StatisticType statistic) const {
   double singleValue(0.0);
   const auto key = std::make_pair(name, statistic);
-  if (!m_singleValueCache.getCache(key, singleValue)) {
+  if (!m_singleValueCache->getCache(key, singleValue)) {
     const Property *log = getProperty(name);
     if (!convertPropertyToDouble(log, singleValue, statistic)) {
       if (const auto stringLog =
@@ -349,7 +369,7 @@ double LogManager::getPropertyAsSingleValue(
       }
     }
     // Put it in the cache
-    m_singleValueCache.setCache(key, singleValue);
+    m_singleValueCache->setCache(key, singleValue);
   }
   return singleValue;
 }
diff --git a/Framework/API/src/MDGeometry.cpp b/Framework/API/src/MDGeometry.cpp
index eff19ac2c119057b26f94fe0a3624032952160f8..4cb8ebc8853db77e316a6d3a6113664223e7bc4c 100644
--- a/Framework/API/src/MDGeometry.cpp
+++ b/Framework/API/src/MDGeometry.cpp
@@ -1,9 +1,12 @@
 #include "MantidAPI/MDGeometry.h"
 #include "MantidKernel/System.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/CoordTransform.h"
 #include "MantidGeometry/MDGeometry/MDGeometryXMLBuilder.h"
 #include "MantidGeometry/MDGeometry/IMDDimension.h"
 #include "MantidGeometry/MDGeometry/MDHistoDimension.h"
+#include "MantidKernel/make_unique.h"
+#include <Poco/NObserver.h>
 #include <boost/make_shared.hpp>
 
 using namespace Mantid::Kernel;
@@ -13,14 +16,54 @@ using namespace Mantid::Geometry;
 namespace Mantid {
 namespace API {
 
+class MDGeometryNotificationHelper {
+public:
+  explicit MDGeometryNotificationHelper(MDGeometry &parent)
+      : m_parent(parent),
+        m_delete_observer(
+            *this, &MDGeometryNotificationHelper::deleteNotificationReceived) {}
+
+  ~MDGeometryNotificationHelper() {
+    if (m_observingDelete) {
+      // Stop watching once object is deleted
+      API::AnalysisDataService::Instance().notificationCenter.removeObserver(
+          m_delete_observer);
+    }
+  }
+
+  void watchForWorkspaceDeletions() {
+    if (!m_observingDelete) {
+      API::AnalysisDataService::Instance().notificationCenter.addObserver(
+          m_delete_observer);
+      m_observingDelete = true;
+    }
+  }
+
+  void deleteNotificationReceived(
+      Mantid::API::WorkspacePreDeleteNotification_ptr notice) {
+    m_parent.deleteNotificationReceived(notice->object());
+  }
+
+private:
+  MDGeometry &m_parent;
+
+  /// Poco delete notification observer object
+  Poco::NObserver<MDGeometryNotificationHelper, WorkspacePreDeleteNotification>
+      m_delete_observer;
+
+  /// Set to True when the m_delete_observer is observing workspace deletions.
+  bool m_observingDelete{false};
+};
+
 //----------------------------------------------------------------------------------------------
 /** Constructor
  */
 MDGeometry::MDGeometry()
     : m_dimensions(), m_originalWorkspaces(), m_origin(),
       m_transforms_FromOriginal(), m_transforms_ToOriginal(),
-      m_delete_observer(*this, &MDGeometry::deleteNotificationReceived),
-      m_observingDelete(false), m_Wtransf(3, 3, true), m_basisVectors() {}
+      m_notificationHelper(
+          Kernel::make_unique<MDGeometryNotificationHelper>(*this)),
+      m_Wtransf(3, 3, true), m_basisVectors() {}
 
 //----------------------------------------------------------------------------------------------
 /** Copy Constructor
@@ -28,9 +71,9 @@ MDGeometry::MDGeometry()
 MDGeometry::MDGeometry(const MDGeometry &other)
     : m_dimensions(), m_originalWorkspaces(), m_origin(other.m_origin),
       m_transforms_FromOriginal(), m_transforms_ToOriginal(),
-      m_delete_observer(*this, &MDGeometry::deleteNotificationReceived),
-      m_observingDelete(false), m_Wtransf(other.m_Wtransf),
-      m_basisVectors(other.m_basisVectors) {
+      m_notificationHelper(
+          Kernel::make_unique<MDGeometryNotificationHelper>(*this)),
+      m_Wtransf(other.m_Wtransf), m_basisVectors(other.m_basisVectors) {
   // Perform a deep copy of the dimensions
   std::vector<Mantid::Geometry::IMDDimension_sptr> dimensions;
   for (size_t d = 0; d < other.getNumDims(); d++) {
@@ -84,15 +127,7 @@ void MDGeometry::clearOriginalWorkspaces() { m_originalWorkspaces.clear(); }
 //----------------------------------------------------------------------------------------------
 /** Destructor
  */
-MDGeometry::~MDGeometry() {
-
-  if (m_observingDelete) {
-    // Stop watching once object is deleted
-    API::AnalysisDataService::Instance().notificationCenter.removeObserver(
-        m_delete_observer);
-  }
-  m_dimensions.clear();
-}
+MDGeometry::~MDGeometry() { m_dimensions.clear(); }
 
 //----------------------------------------------------------------------------------------------
 /** Initialize the geometry
@@ -343,12 +378,7 @@ void MDGeometry::setOriginalWorkspace(boost::shared_ptr<Workspace> ws,
   if (index >= m_originalWorkspaces.size())
     m_originalWorkspaces.resize(index + 1);
   m_originalWorkspaces[index] = ws;
-  // Watch for workspace deletions
-  if (!m_observingDelete) {
-    API::AnalysisDataService::Instance().notificationCenter.addObserver(
-        m_delete_observer);
-    m_observingDelete = true;
-  }
+  m_notificationHelper->watchForWorkspaceDeletions();
 }
 
 //---------------------------------------------------------------------------------------------------
@@ -398,14 +428,13 @@ void MDGeometry::transformDimensions(std::vector<double> &scaling,
  * This checks if the "original workspace" in this object is being deleted,
  * and removes the reference to it to allow it to be destructed properly.
  *
- * @param notice :: notification of workspace deletion
+ * @param deleted :: The deleted workspace
  */
 void MDGeometry::deleteNotificationReceived(
-    Mantid::API::WorkspacePreDeleteNotification_ptr notice) {
+    const boost::shared_ptr<const Workspace> &deleted) {
   for (auto &original : m_originalWorkspaces) {
     if (original) {
       // Compare the pointer being deleted to the one stored as the original.
-      Workspace_sptr deleted = notice->object();
       if (original == deleted) {
         // Clear the reference
         original.reset();
diff --git a/Framework/API/src/MatrixWorkspace.cpp b/Framework/API/src/MatrixWorkspace.cpp
index 17ceb33f9b486c655c5bf851cdc81e4e66bb13c6..91d460a45374e2f9569bb8623d3acd89d6bc9ed8 100644
--- a/Framework/API/src/MatrixWorkspace.cpp
+++ b/Framework/API/src/MatrixWorkspace.cpp
@@ -14,10 +14,13 @@
 #include "MantidGeometry/MDGeometry/GeneralFrame.h"
 #include "MantidKernel/TimeSeriesProperty.h"
 #include "MantidKernel/MDUnit.h"
+#include "MantidKernel/Strings.h"
 #include "MantidKernel/make_unique.h"
+#include "MantidIndexing/IndexInfo.h"
 
 #include <cmath>
 
+#include <functional>
 #include <numeric>
 
 using Mantid::Kernel::DateAndTime;
@@ -40,10 +43,25 @@ const std::string MatrixWorkspace::xDimensionId = "xDimension";
 const std::string MatrixWorkspace::yDimensionId = "yDimension";
 
 /// Default constructor
-MatrixWorkspace::MatrixWorkspace() = default;
+MatrixWorkspace::MatrixWorkspace()
+    : IMDWorkspace(), ExperimentInfo(), m_axes(),
+      m_indexInfo(Kernel::make_unique<Indexing::IndexInfo>(
+          std::bind(&MatrixWorkspace::getNumberHistograms, this),
+          std::bind(&MatrixWorkspace::spectrumNumber, this,
+                    std::placeholders::_1),
+          std::bind(&MatrixWorkspace::detectorIDs, this,
+                    std::placeholders::_1))),
+      m_isInitialized(false), m_YUnit(), m_YUnitLabel(),
+      m_isCommonBinsFlagSet(false), m_isCommonBinsFlag(false), m_masks() {}
 
 MatrixWorkspace::MatrixWorkspace(const MatrixWorkspace &other)
-    : IMDWorkspace(other), ExperimentInfo(other) {
+    : IMDWorkspace(other), ExperimentInfo(other),
+      m_indexInfo(Kernel::make_unique<Indexing::IndexInfo>(
+          std::bind(&MatrixWorkspace::getNumberHistograms, this),
+          std::bind(&MatrixWorkspace::spectrumNumber, this,
+                    std::placeholders::_1),
+          std::bind(&MatrixWorkspace::detectorIDs, this,
+                    std::placeholders::_1))) {
   m_axes.resize(other.m_axes.size());
   for (size_t i = 0; i < m_axes.size(); ++i)
     m_axes[i] = other.m_axes[i]->clone(this);
@@ -71,6 +89,31 @@ MatrixWorkspace::~MatrixWorkspace() {
   }
 }
 
+/** Returns a const reference to the IndexInfo object of the workspace.
+ *
+ * Used for access to spectrum number and detector ID information of spectra. */
+const Indexing::IndexInfo &MatrixWorkspace::indexInfo() const {
+  return *m_indexInfo;
+}
+
+/** Sets the IndexInfo object of the workspace.
+ *
+ * Used for setting spectrum number and detector ID information of spectra */
+void MatrixWorkspace::setIndexInfo(const Indexing::IndexInfo &indexInfo) {
+  // Comparing the *local* size of the indexInfo.
+  if (indexInfo.size() != getNumberHistograms())
+    throw std::runtime_error("MatrixWorkspace::setIndexInfo: IndexInfo size "
+                             "does not match number of histograms in "
+                             "workspace");
+
+  for (size_t i = 0; i < getNumberHistograms(); ++i) {
+    auto &spectrum = getSpectrum(i);
+    spectrum.setSpectrumNo(indexInfo.spectrumNumber(i));
+    auto ids = indexInfo.detectorIDs(i);
+    spectrum.setDetectorIDs(std::set<detid_t>(ids.begin(), ids.end()));
+  }
+}
+
 /// @returns A human-readable string of the current state
 const std::string MatrixWorkspace::toString() const {
   std::ostringstream os;
@@ -138,6 +181,37 @@ void MatrixWorkspace::initialize(const std::size_t &NVectors,
   m_isInitialized = true;
 }
 
+void MatrixWorkspace::initialize(const std::size_t &NVectors,
+                                 const HistogramData::Histogram &histogram) {
+  // Check validity of arguments
+  if (NVectors == 0 || histogram.x().size() == 0) {
+    throw std::out_of_range(
+        "All arguments to init must be positive and non-zero");
+  }
+
+  // Bypass the initialization if the workspace has already been initialized.
+  if (m_isInitialized)
+    return;
+
+  // Invoke init() method of the derived class inside a try/catch clause
+  try {
+    this->init(NVectors, histogram);
+  } catch (std::runtime_error &) {
+    throw;
+  }
+
+  // Indicate that this workspace has been initialized to prevent duplicate
+  // attempts.
+  m_isInitialized = true;
+}
+
+void MatrixWorkspace::initialize(const Indexing::IndexInfo &indexInfo,
+                                 const HistogramData::Histogram &histogram) {
+  initialize(indexInfo.size(), histogram);
+  setIndexInfo(indexInfo);
+}
+
+//---------------------------------------------------------------------------------------
 /** Set the title of the workspace
 *
 *  @param t :: The title
@@ -680,7 +754,7 @@ MatrixWorkspace::getDetector(const size_t workspaceIndex) const {
   }
   // Else need to construct a DetectorGroup and return that
   auto dets_ptr = localInstrument->getDetectors(dets);
-  return boost::make_shared<Geometry::DetectorGroup>(dets_ptr, false);
+  return boost::make_shared<Geometry::DetectorGroup>(dets_ptr);
 }
 
 /** Returns the signed 2Theta scattering angle for a detector
@@ -895,35 +969,6 @@ bool MatrixWorkspace::isCommonBins() const {
   return m_isCommonBinsFlag;
 }
 
-/**
-* Mask a given workspace index, setting the data and error values to zero
-* @param index :: The index within the workspace to mask
-*/
-void MatrixWorkspace::maskWorkspaceIndex(const std::size_t index) {
-  if (index >= this->getNumberHistograms()) {
-    throw Kernel::Exception::IndexError(
-        index, this->getNumberHistograms(),
-        "MatrixWorkspace::maskWorkspaceIndex,index");
-  }
-
-  auto &spec = this->getSpectrum(index);
-
-  // Virtual method clears the spectrum as appropriate
-  spec.clearData();
-
-  const auto dets = spec.getDetectorIDs();
-  for (auto detId : dets) {
-    try {
-      if (const Geometry::Detector *det =
-              dynamic_cast<const Geometry::Detector *>(
-                  sptr_instrument->getDetector(detId).get())) {
-        m_parmap->addBool(det, "masked", true); // Thread-safe method
-      }
-    } catch (Kernel::Exception::NotFoundError &) {
-    }
-  }
-}
-
 /** Called by the algorithm MaskBins to mask a single bin for the first time,
 * algorithms that later propagate the
 *  the mask from an input to the output should call flagMasked() instead. Here
@@ -1209,7 +1254,7 @@ public:
   /// short name which identify the dimension among other dimension. A dimension
   /// can be usually find by its ID and various
   /// various method exist to manipulate set of dimensions by their names.
-  std::string getDimensionId() const override { return m_dimensionId; }
+  const std::string &getDimensionId() const override { return m_dimensionId; }
 
   /// if the dimension is integrated (e.g. have single bin)
   bool getIsIntegrated() const override { return m_axis.length() == 1; }
@@ -1296,7 +1341,7 @@ public:
   /// short name which identify the dimension among other dimension. A dimension
   /// can be usually find by its ID and various
   /// various method exist to manipulate set of dimensions by their names.
-  std::string getDimensionId() const override { return m_dimensionId; }
+  const std::string &getDimensionId() const override { return m_dimensionId; }
 
   /// if the dimension is integrated (e.g. have single bin)
   bool getIsIntegrated() const override { return m_X.size() == 1; }
@@ -1941,6 +1986,30 @@ void MatrixWorkspace::setImageE(const MantidImage &image, size_t start,
   setImage(&MatrixWorkspace::dataE, image, start, parallelExecution);
 }
 
+/// Private helper method for IndexInfo
+specnum_t MatrixWorkspace::spectrumNumber(const size_t index) const {
+  return getSpectrum(index).getSpectrumNo();
+}
+
+/// Private helper method for IndexInfo
+const std::set<detid_t> &
+MatrixWorkspace::detectorIDs(const size_t index) const {
+  return getSpectrum(index).getDetectorIDs();
+}
+
+/// Returns the number of detector groups. This is equal to the number of
+/// spectra.
+size_t MatrixWorkspace::numberOfDetectorGroups() const {
+  return getNumberHistograms();
+}
+
+/// Returns a set of detector IDs for a group. This is equal to the detector IDs
+/// of the spectrum at given index.
+const std::set<detid_t> &
+MatrixWorkspace::detectorIDsInGroup(const size_t index) const {
+  return getSpectrum(index).getDetectorIDs();
+}
+
 } // namespace API
 } // Namespace Mantid
 
diff --git a/Framework/API/src/MatrixWorkspaceMDIterator.cpp b/Framework/API/src/MatrixWorkspaceMDIterator.cpp
index 94894e7efd3494a1827dadc45ac51aea076e2264..a50a0164233f3888baac601a5f1146975b949cc4 100644
--- a/Framework/API/src/MatrixWorkspaceMDIterator.cpp
+++ b/Framework/API/src/MatrixWorkspaceMDIterator.cpp
@@ -1,6 +1,7 @@
 #include "MantidAPI/MatrixWorkspaceMDIterator.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/NumericAxis.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidGeometry/IDetector.h"
 #include "MantidKernel/System.h"
 #include "MantidKernel/VMD.h"
@@ -25,7 +26,7 @@ MatrixWorkspaceMDIterator::MatrixWorkspaceMDIterator(
     Mantid::Geometry::MDImplicitFunction *function, size_t beginWI,
     size_t endWI)
     : m_ws(workspace), m_pos(0), m_max(0), m_function(function),
-      m_errorIsCached(false) {
+      m_errorIsCached(false), m_spectrumInfo(m_ws->spectrumInfo()) {
   if (!m_ws)
     throw std::runtime_error(
         "MatrixWorkspaceMDIterator::ctor() NULL MatrixWorkspace");
@@ -258,14 +259,10 @@ signal_t MatrixWorkspaceMDIterator::getInnerError(size_t /*index*/) const {
  * masked, or if there is no detector at that index.
 */
 bool MatrixWorkspaceMDIterator::getIsMasked() const {
-  Mantid::Geometry::IDetector_const_sptr det =
-      m_ws->getDetector(m_workspaceIndex);
-  if (det != nullptr) {
-    return det->isMasked();
-  } else {
-    return true; // TODO. Check whether it's better to return true or false
-                 // under these circumstances.
+  if (!m_spectrumInfo.hasDetectors(m_workspaceIndex)) {
+    return true;
   }
+  return m_spectrumInfo.isMasked(m_workspaceIndex);
 }
 
 /**
diff --git a/Framework/API/src/MultiPeriodGroupWorker.cpp b/Framework/API/src/MultiPeriodGroupWorker.cpp
index bc9e3e993c07472a0361231894f6c883d0abfb6d..e6a052ab11e0299c5362e5b8208bf72354481a8d 100644
--- a/Framework/API/src/MultiPeriodGroupWorker.cpp
+++ b/Framework/API/src/MultiPeriodGroupWorker.cpp
@@ -1,10 +1,12 @@
 #include "MantidAPI/MultiPeriodGroupWorker.h"
 #include "MantidKernel/ArrayProperty.h"
 #include "MantidKernel/Property.h"
+#include "MantidKernel/Strings.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/IAlgorithm.h"
 #include "MantidAPI/AlgorithmManager.h"
 #include "MantidAPI/Run.h"
+#include "MantidAPI/WorkspaceGroup.h"
 
 using namespace Mantid::Kernel;
 
@@ -94,8 +96,7 @@ MultiPeriodGroupWorker::findMultiPeriodGroups(
     }
   }
 
-  if ((vecMultiPeriodWorkspaceGroups.size() != 0) &&
-      (vecWorkspaceGroups.size() != 0)) {
+  if (!vecMultiPeriodWorkspaceGroups.empty() && !vecWorkspaceGroups.empty()) {
     throw std::invalid_argument(
         "The input contains a mix of multi-period and other workspaces.");
   }
@@ -135,7 +136,8 @@ std::string MultiPeriodGroupWorker::createFormattedInputWorkspaceNames(
   std::string prefix;
   std::string inputWorkspaces;
   for (const auto &vecWorkspaceGroup : vecWorkspaceGroups) {
-    inputWorkspaces += prefix + vecWorkspaceGroup->getItem(periodIndex)->name();
+    inputWorkspaces +=
+        prefix + vecWorkspaceGroup->getItem(periodIndex)->getName();
     prefix = ",";
   }
   return inputWorkspaces;
@@ -282,7 +284,7 @@ void MultiPeriodGroupWorker::validateMultiPeriodGroupInputs(
         if (nPeriods != benchMarkGroupSize) {
           throw std::runtime_error("Missmatch between nperiods log and the "
                                    "number of workspaces in the input group: " +
-                                   vecMultiPeriodGroups[i]->name());
+                                   vecMultiPeriodGroups[i]->getName());
         }
         Property *currentPeriodProperty =
             currentNestedWS->run().getLogData("current_period");
@@ -290,7 +292,7 @@ void MultiPeriodGroupWorker::validateMultiPeriodGroupInputs(
         if (currentPeriod != (j + 1)) {
           throw std::runtime_error("Multiperiod group workspaces must be "
                                    "ordered by current_period. Correct: " +
-                                   currentNestedWS->name());
+                                   currentNestedWS->getName());
         }
       }
     }
diff --git a/Framework/API/src/MultipleExperimentInfos.cpp b/Framework/API/src/MultipleExperimentInfos.cpp
index 4d2c02a1b56a682adc6fb229796a9378f5d7c560..8838efe6d80c844b59bb3248c1c04629fb2e2b30 100644
--- a/Framework/API/src/MultipleExperimentInfos.cpp
+++ b/Framework/API/src/MultipleExperimentInfos.cpp
@@ -3,6 +3,7 @@
 #include "MantidKernel/System.h"
 
 #include <boost/make_shared.hpp>
+#include <sstream>
 
 using namespace Mantid::Kernel;
 using namespace Mantid::API;
diff --git a/Framework/API/src/MultipleFileProperty.cpp b/Framework/API/src/MultipleFileProperty.cpp
index a961771273cf7a3afdb4243b50f47c407e2e7ebf..39a93061dcae90a6b683be5164f770bd56f3c05f 100644
--- a/Framework/API/src/MultipleFileProperty.cpp
+++ b/Framework/API/src/MultipleFileProperty.cpp
@@ -6,6 +6,7 @@
 #include "MantidKernel/ConfigService.h"
 #include "MantidKernel/MultiFileValidator.h"
 #include "MantidKernel/Property.h"
+#include "MantidKernel/PropertyHelper.h"
 #include "MantidKernel/System.h"
 #include "MantidKernel/VectorHelper.h"
 
diff --git a/Framework/API/src/NearestNeighbourInfo.cpp b/Framework/API/src/NearestNeighbourInfo.cpp
index ab6832c24f4ba4ab8ff38daeff670c549119939c..7612bddd1e6a909f9af5e9dfe101c98d240b3f6a 100644
--- a/Framework/API/src/NearestNeighbourInfo.cpp
+++ b/Framework/API/src/NearestNeighbourInfo.cpp
@@ -1,6 +1,7 @@
 #include "MantidAPI/NearestNeighbourInfo.h"
+#include "MantidAPI/NearestNeighbours.h"
 #include "MantidAPI/MatrixWorkspace.h"
-#include "MantidAPI/SpectrumDetectorMapping.h"
+#include "MantidKernel/make_unique.h"
 
 namespace Mantid {
 namespace API {
@@ -15,10 +16,18 @@ namespace API {
 NearestNeighbourInfo::NearestNeighbourInfo(const MatrixWorkspace &workspace,
                                            const bool ignoreMaskedDetectors,
                                            const int nNeighbours)
-    : m_workspace(workspace),
-      m_nearestNeighbours(nNeighbours, workspace.getInstrument(),
-                          SpectrumDetectorMapping(&workspace).getMapping(),
-                          ignoreMaskedDetectors) {}
+    : m_workspace(workspace) {
+  std::vector<specnum_t> spectrumNumbers;
+  for (size_t i = 0; i < m_workspace.getNumberHistograms(); ++i)
+    spectrumNumbers.push_back(m_workspace.getSpectrum(i).getSpectrumNo());
+
+  m_nearestNeighbours = Kernel::make_unique<NearestNeighbours>(
+      nNeighbours, workspace.spectrumInfo(), std::move(spectrumNumbers),
+      ignoreMaskedDetectors);
+}
+
+// Defined as default in source for forward declaration with std::unique_ptr.
+NearestNeighbourInfo::~NearestNeighbourInfo() = default;
 
 /** Queries the NearestNeighbours object for the selected detector.
 * NOTE! getNeighbours(spectrumNumber, radius) is MUCH faster.
@@ -39,7 +48,7 @@ NearestNeighbourInfo::getNeighbours(const Geometry::IDetector *comp,
                                            "detector",
                                            comp->getID());
   }
-  return m_nearestNeighbours.neighboursInRadius(spectra[0], radius);
+  return m_nearestNeighbours->neighboursInRadius(spectra[0], radius);
 }
 
 /** Queries the NearestNeighbours object for the selected spectrum number.
@@ -50,7 +59,7 @@ NearestNeighbourInfo::getNeighbours(const Geometry::IDetector *comp,
 */
 std::map<specnum_t, Kernel::V3D>
 NearestNeighbourInfo::getNeighbours(specnum_t spec, const double radius) const {
-  return m_nearestNeighbours.neighboursInRadius(spec, radius);
+  return m_nearestNeighbours->neighboursInRadius(spec, radius);
 }
 
 /** Queries the NearestNeighbours object for the selected spectrum number.
@@ -60,7 +69,7 @@ NearestNeighbourInfo::getNeighbours(specnum_t spec, const double radius) const {
 */
 std::map<specnum_t, Kernel::V3D>
 NearestNeighbourInfo::getNeighboursExact(specnum_t spec) const {
-  return m_nearestNeighbours.neighbours(spec);
+  return m_nearestNeighbours->neighbours(spec);
 }
 
 } // namespace API
diff --git a/Framework/Geometry/src/Instrument/NearestNeighbours.cpp b/Framework/API/src/NearestNeighbours.cpp
similarity index 71%
rename from Framework/Geometry/src/Instrument/NearestNeighbours.cpp
rename to Framework/API/src/NearestNeighbours.cpp
index 212183a65365e2e0c64e26c23a68280dafcd6c14..9f094269ade399b5944cac26ba3f19f0ada12663 100644
--- a/Framework/Geometry/src/Instrument/NearestNeighbours.cpp
+++ b/Framework/API/src/NearestNeighbours.cpp
@@ -1,44 +1,35 @@
-#include "MantidGeometry/Instrument/NearestNeighbours.h"
+#include "MantidAPI/NearestNeighbours.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidGeometry/Instrument.h"
 #include "MantidGeometry/Instrument/DetectorGroup.h"
+#include "MantidGeometry/Objects/BoundingBox.h"
 // Nearest neighbours library
 #include "MantidKernel/ANN/ANN.h"
 #include "MantidKernel/Exception.h"
 #include "MantidKernel/Timer.h"
 
 namespace Mantid {
-namespace Geometry {
+using namespace Geometry;
+namespace API {
 using Mantid::detid_t;
 using Kernel::V3D;
 
-/**
-*Constructor
-*@param instrument :: A shared pointer to Instrument object
-*@param spectraMap :: A reference to the spectra-detector mapping
-*@param ignoreMaskedDetectors :: flag indicating that masked detectors should be
-* ignored.
-*/
-NearestNeighbours::NearestNeighbours(
-    boost::shared_ptr<const Instrument> instrument,
-    const ISpectrumDetectorMapping &spectraMap, bool ignoreMaskedDetectors)
-    : m_instrument(instrument), m_spectraMap(spectraMap), m_noNeighbours(8),
-      m_cutoff(-DBL_MAX), m_radius(0),
-      m_bIgnoreMaskedDetectors(ignoreMaskedDetectors) {
-  this->build(m_noNeighbours);
-}
-
 /**
  * Constructor
  * @param nNeighbours :: Number of neighbours to use
- * @param instrument :: A shared pointer to Instrument object
- * @param spectraMap :: A reference to the spectra-detector mapping
+ * @param spectrumInfo :: Reference to the SpectrumInfo of the underlying
+ * workspace
+ * @param spectrumNumbers :: Vector of spectrum numbers, defining the ordering
+ * of spectra
  * @param ignoreMaskedDetectors :: flag indicating that masked detectors should
  * be ignored.
  */
-NearestNeighbours::NearestNeighbours(
-    int nNeighbours, boost::shared_ptr<const Instrument> instrument,
-    const ISpectrumDetectorMapping &spectraMap, bool ignoreMaskedDetectors)
-    : m_instrument(instrument), m_spectraMap(spectraMap),
+NearestNeighbours::NearestNeighbours(int nNeighbours,
+                                     const SpectrumInfo &spectrumInfo,
+                                     std::vector<specnum_t> spectrumNumbers,
+                                     bool ignoreMaskedDetectors)
+    : m_spectrumInfo(spectrumInfo),
+      m_spectrumNumbers(std::move(spectrumNumbers)),
       m_noNeighbours(nNeighbours), m_cutoff(-DBL_MAX), m_radius(0),
       m_bIgnoreMaskedDetectors(ignoreMaskedDetectors) {
   this->build(m_noNeighbours);
@@ -119,14 +110,13 @@ NearestNeighbours::neighboursInRadius(const specnum_t spectrum,
  * the graph
  */
 void NearestNeighbours::build(const int noNeighbours) {
-  std::map<specnum_t, IDetector_const_sptr> spectraDets =
-      getSpectraDetectors(m_instrument, m_spectraMap);
-  if (spectraDets.empty()) {
+  const auto indices = getSpectraDetectors();
+  if (indices.empty()) {
     throw std::runtime_error(
         "NearestNeighbours::build - Cannot find any spectra");
   }
   const int nspectra =
-      static_cast<int>(spectraDets.size()); // ANN only deals with integers
+      static_cast<int>(indices.size()); // ANN only deals with integers
   if (noNeighbours >= nspectra) {
     throw std::invalid_argument(
         "NearestNeighbours::build - Invalid number of neighbours");
@@ -140,18 +130,16 @@ void NearestNeighbours::build(const int noNeighbours) {
   BoundingBox bbox;
   // Base the scaling on the first detector, should be adequate but we can look
   // at this
-  IDetector_const_sptr firstDet = (*spectraDets.begin()).second;
-  firstDet->getBoundingBox(bbox);
+  const auto &firstDet = m_spectrumInfo.detector(indices.front());
+  firstDet.getBoundingBox(bbox);
   m_scale = V3D(bbox.width());
   ANNpointArray dataPoints = annAllocPts(nspectra, 3);
   MapIV pointNoToVertex;
 
-  std::map<specnum_t, IDetector_const_sptr>::const_iterator detIt;
   int pointNo = 0;
-  for (detIt = spectraDets.begin(); detIt != spectraDets.end(); ++detIt) {
-    IDetector_const_sptr detector = detIt->second;
-    const specnum_t spectrum = detIt->first;
-    V3D pos = detector->getPos() / m_scale;
+  for (const auto i : indices) {
+    const specnum_t spectrum = m_spectrumNumbers[i];
+    V3D pos = m_spectrumInfo.position(i) / m_scale;
     dataPoints[pointNo][0] = pos.X();
     dataPoints[pointNo][1] = pos.Y();
     dataPoints[pointNo][2] = pos.Z();
@@ -167,7 +155,7 @@ void NearestNeighbours::build(const int noNeighbours) {
   auto nnIndexList = new ANNidx[m_noNeighbours];
   auto nnDistList = new ANNdist[m_noNeighbours];
 
-  for (detIt = spectraDets.begin(); detIt != spectraDets.end(); ++detIt) {
+  for (const auto idx : indices) {
     ANNpoint scaledPos = dataPoints[pointNo];
     annTree->annkSearch(scaledPos,      // Point to search nearest neighbours of
                         m_noNeighbours, // Number of neighbours to find (8)
@@ -185,8 +173,8 @@ void NearestNeighbours::build(const int noNeighbours) {
                       m_scale;
       V3D distance = neighbour - realPos;
       double separation = distance.norm();
-      boost::add_edge(m_specToVertex[detIt->first], // from
-                      pointNoToVertex[index],       // to
+      boost::add_edge(m_specToVertex[m_spectrumNumbers[idx]], // from
+                      pointNoToVertex[index],                 // to
                       distance, m_graph);
       if (separation > m_cutoff) {
         m_cutoff = separation;
@@ -235,30 +223,17 @@ NearestNeighbours::defaultNeighbours(const specnum_t spectrum) const {
   }
 }
 
-/**
- * Get the list of detectors associated with a spectra
- * @param instrument :: A pointer to the instrument
- * @param spectraMap :: A reference to the spectra map
- * @returns A map of spectra number to detector pointer
- */
-std::map<specnum_t, IDetector_const_sptr>
-NearestNeighbours::getSpectraDetectors(
-    boost::shared_ptr<const Instrument> instrument,
-    const ISpectrumDetectorMapping &spectraMap) {
-  std::map<specnum_t, IDetector_const_sptr> spectra;
-  if (spectraMap.empty())
-    return spectra;
-  auto cend = spectraMap.cend();
-  for (auto citr = spectraMap.cbegin(); citr != cend; ++citr) {
-    const std::vector<detid_t> detIDs(citr->second.begin(), citr->second.end());
-    IDetector_const_sptr det = instrument->getDetectorG(detIDs);
+/// Returns the list of valid spectrum indices
+std::vector<size_t> NearestNeighbours::getSpectraDetectors() {
+  std::vector<size_t> indices;
+  for (size_t i = 0; i < m_spectrumNumbers.size(); ++i) {
     // Always ignore monitors and ignore masked detectors if requested.
-    bool heedMasking = m_bIgnoreMaskedDetectors && det->isMasked();
-    if (!det->isMonitor() && !heedMasking) {
-      spectra.emplace(citr->first, det);
+    bool heedMasking = m_bIgnoreMaskedDetectors && m_spectrumInfo.isMasked(i);
+    if (!m_spectrumInfo.isMonitor(i) && !heedMasking) {
+      indices.push_back(i);
     }
   }
-  return spectra;
+  return indices;
 }
 }
 }
diff --git a/Framework/API/src/ParamFunction.cpp b/Framework/API/src/ParamFunction.cpp
index a7023dbf8733e3b5438c40e98c94e37958f5dda7..e4115ec9b7a1d2c46dfeef34d29acb927c5642c0 100644
--- a/Framework/API/src/ParamFunction.cpp
+++ b/Framework/API/src/ParamFunction.cpp
@@ -4,8 +4,6 @@
 #include "MantidKernel/Exception.h"
 #include "MantidKernel/Logger.h"
 #include "MantidAPI/ParamFunction.h"
-#include "MantidAPI/IConstraint.h"
-#include "MantidAPI/ParameterTie.h"
 
 #include <cmath>
 #include <limits>
@@ -19,13 +17,7 @@ Kernel::Logger g_log("ParamFunction");
 
 /// Destructor
 ParamFunction::~ParamFunction() {
-  for (auto &tie : m_ties) {
-    delete tie;
-  }
   m_ties.clear();
-  for (auto &constraint : m_constraints) {
-    delete constraint;
-  }
   m_constraints.clear();
 }
 
@@ -276,19 +268,18 @@ void ParamFunction::unfix(size_t i) {
  * ParamFunction.
  * @param tie :: A pointer to a new tie
  */
-void ParamFunction::addTie(ParameterTie *tie) {
+void ParamFunction::addTie(std::unique_ptr<ParameterTie> tie) {
   size_t iPar = tie->getIndex();
   bool found = false;
   for (auto &m_tie : m_ties) {
     if (m_tie->getIndex() == iPar) {
       found = true;
-      delete m_tie;
-      m_tie = tie;
+      m_tie = std::move(tie);
       break;
     }
   }
   if (!found) {
-    m_ties.push_back(tie);
+    m_ties.push_back(std::move(tie));
   }
 }
 
@@ -305,16 +296,18 @@ void ParamFunction::applyTies() {
  * Used to find ParameterTie for a parameter i
  */
 class ReferenceEqual {
-  const size_t m_i; ///< index to find
+  /// index to find
+  const size_t m_i;
+
 public:
-  /** Constructor
-   */
+  /// Constructor
   explicit ReferenceEqual(size_t i) : m_i(i) {}
-  /**Bracket operator
-   * @param p :: the parameter you are looking for
-   * @return True if found
-   */
-  bool operator()(ParameterReference *p) { return p->getIndex() == m_i; }
+  /// Bracket operator
+  /// @param p :: the element you are looking for
+  /// @return True if found
+  template <class T> bool operator()(const std::unique_ptr<T> &p) {
+    return p->getIndex() == m_i;
+  }
 };
 
 /** Removes i-th parameter's tie if it is tied or does nothing.
@@ -327,7 +320,6 @@ bool ParamFunction::removeTie(size_t i) {
   }
   auto it = std::find_if(m_ties.begin(), m_ties.end(), ReferenceEqual(i));
   if (it != m_ties.end()) {
-    delete *it;
     m_ties.erase(it);
     unfix(i);
     return true;
@@ -345,7 +337,7 @@ ParameterTie *ParamFunction::getTie(size_t i) const {
   }
   auto it = std::find_if(m_ties.cbegin(), m_ties.cend(), ReferenceEqual(i));
   if (it != m_ties.cend()) {
-    return *it;
+    return it->get();
   }
   return nullptr;
 }
@@ -356,7 +348,6 @@ void ParamFunction::clearTies() {
   for (auto &tie : m_ties) {
     size_t i = getParameterIndex(*tie);
     unfix(i);
-    delete tie;
   }
   m_ties.clear();
 }
@@ -364,19 +355,18 @@ void ParamFunction::clearTies() {
 /** Add a constraint
  *  @param ic :: Pointer to a constraint.
  */
-void ParamFunction::addConstraint(IConstraint *ic) {
+void ParamFunction::addConstraint(std::unique_ptr<IConstraint> ic) {
   size_t iPar = ic->getIndex();
   bool found = false;
   for (auto &constraint : m_constraints) {
     if (constraint->getIndex() == iPar) {
       found = true;
-      delete constraint;
-      constraint = ic;
+      constraint = std::move(ic);
       break;
     }
   }
   if (!found) {
-    m_constraints.push_back(ic);
+    m_constraints.push_back(std::move(ic));
   }
 }
 
@@ -391,7 +381,7 @@ IConstraint *ParamFunction::getConstraint(size_t i) const {
   auto it = std::find_if(m_constraints.cbegin(), m_constraints.cend(),
                          ReferenceEqual(i));
   if (it != m_constraints.cend()) {
-    return *it;
+    return it->get();
   }
   return nullptr;
 }
@@ -403,7 +393,6 @@ void ParamFunction::removeConstraint(const std::string &parName) {
   size_t iPar = parameterIndex(parName);
   for (auto it = m_constraints.begin(); it != m_constraints.end(); ++it) {
     if (iPar == (**it).getIndex()) {
-      delete *it;
       m_constraints.erase(it);
       break;
     }
@@ -418,15 +407,8 @@ void ParamFunction::setUpForFit() {
 
 /// Nonvirtual member which removes all declared parameters
 void ParamFunction::clearAllParameters() {
-  for (auto &tie : m_ties) {
-    delete tie;
-  }
   m_ties.clear();
-  for (auto &constraint : m_constraints) {
-    delete constraint;
-  }
   m_constraints.clear();
-
   m_parameters.clear();
   m_parameterNames.clear();
   m_parameterDescriptions.clear();
diff --git a/Framework/API/src/Progress.cpp b/Framework/API/src/Progress.cpp
index 9e6964bced0cd05c97282e08a3cd7031b27ee9bf..03a976199c1686b9aa22fb051b60d3692805f396 100644
--- a/Framework/API/src/Progress.cpp
+++ b/Framework/API/src/Progress.cpp
@@ -53,8 +53,8 @@ void Progress::doReport(const std::string &msg) {
     p = m_end;
   if (!m_alg)
     return;
-
-  m_alg->progress(p, msg, this->getEstimatedTime(),
+  // progress must be between 0 and 1
+  m_alg->progress(p / (m_end - m_start), msg, this->getEstimatedTime(),
                   this->m_notifyStepPrecision);
   m_alg->interruption_point();
 }
diff --git a/Framework/API/src/PropertyWithValue.cpp b/Framework/API/src/PropertyWithValue.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..0b8b9ba36f1aae87fcd4de1310d04da7936265b8
--- /dev/null
+++ b/Framework/API/src/PropertyWithValue.cpp
@@ -0,0 +1,56 @@
+#include "MantidKernel/PropertyWithValue.h"
+#include "MantidAPI/DllConfig.h"
+#include "MantidAPI/ExperimentInfo.h"
+#include "MantidAPI/IAlgorithm.h"
+#include "MantidAPI/IEventWorkspace.h"
+#include "MantidAPI/IFunction.h"
+#include "MantidAPI/IMaskWorkspace.h"
+#include "MantidAPI/IMDEventWorkspace.h"
+#include "MantidAPI/IMDHistoWorkspace.h"
+#include "MantidAPI/IMDWorkspace.h"
+#include "MantidAPI/IPeaksWorkspace.h"
+#include "MantidAPI/ISplittersWorkspace.h"
+#include "MantidAPI/ITableWorkspace.h"
+#include "MantidAPI/MatrixWorkspace.h"
+#include "MantidAPI/WorkspaceGroup.h"
+#include "MantidAPI/Workspace.h"
+
+// PropertyWithValue implementation
+#include "MantidKernel/PropertyWithValue.tcc"
+
+namespace Mantid {
+namespace Kernel {
+
+/// @cond
+template class MANTID_API_DLL
+    PropertyWithValue<boost::shared_ptr<API::IAlgorithm>>;
+template class MANTID_API_DLL
+    PropertyWithValue<boost::shared_ptr<API::IEventWorkspace>>;
+template class MANTID_API_DLL
+    PropertyWithValue<boost::shared_ptr<API::IFunction>>;
+template class MANTID_API_DLL
+    PropertyWithValue<boost::shared_ptr<API::IMaskWorkspace>>;
+template class MANTID_API_DLL
+    PropertyWithValue<boost::shared_ptr<API::IMDEventWorkspace>>;
+template class MANTID_API_DLL
+    PropertyWithValue<boost::shared_ptr<API::IMDHistoWorkspace>>;
+template class MANTID_API_DLL
+    PropertyWithValue<boost::shared_ptr<API::IMDWorkspace>>;
+template class MANTID_API_DLL
+    PropertyWithValue<boost::shared_ptr<API::IPeaksWorkspace>>;
+template class MANTID_API_DLL
+    PropertyWithValue<boost::shared_ptr<API::ISplittersWorkspace>>;
+template class MANTID_API_DLL
+    PropertyWithValue<boost::shared_ptr<API::ITableWorkspace>>;
+template class MANTID_API_DLL
+    PropertyWithValue<boost::shared_ptr<API::MatrixWorkspace>>;
+template class MANTID_API_DLL
+    PropertyWithValue<boost::shared_ptr<API::Workspace>>;
+template class MANTID_API_DLL
+    PropertyWithValue<boost::shared_ptr<API::WorkspaceGroup>>;
+template class MANTID_API_DLL
+    PropertyWithValue<boost::shared_ptr<API::ExperimentInfo>>;
+/// @endcond
+
+} // namespace Kernel
+} // namespace Mantid
diff --git a/Framework/API/src/Run.cpp b/Framework/API/src/Run.cpp
index 0e256285d942737f7b5d98d3cbfb0aff0d1b0ce3..cba9f55cf7458af81edb42dcd4855b30ad00e715 100644
--- a/Framework/API/src/Run.cpp
+++ b/Framework/API/src/Run.cpp
@@ -1,10 +1,9 @@
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidAPI/Run.h"
+#include "MantidGeometry/Instrument/Goniometer.h"
 #include "MantidKernel/DateAndTime.h"
 #include "MantidKernel/TimeSeriesProperty.h"
 #include "MantidKernel/VectorHelper.h"
+#include "MantidKernel/make_unique.h"
 
 #include <nexus/NeXusFile.hpp>
 
@@ -38,16 +37,30 @@ const char *OUTER_BKG_RADIUS_GROUP = "outer_bkg_radius";
 Kernel::Logger g_log("Run");
 }
 
-//----------------------------------------------------------------------
-// Public member functions
-//----------------------------------------------------------------------
+Run::Run() : m_goniometer(Kernel::make_unique<Geometry::Goniometer>()) {}
+
+Run::Run(const Run &other)
+    : LogManager(other), m_goniometer(Kernel::make_unique<Geometry::Goniometer>(
+                             *other.m_goniometer)),
+      m_histoBins(other.m_histoBins) {}
+
+// Defined as default in source for forward declaration with std::unique_ptr.
+Run::~Run() = default;
+
+Run &Run::operator=(const Run &other) {
+  LogManager::operator=(other);
+  m_goniometer = Kernel::make_unique<Geometry::Goniometer>(*other.m_goniometer);
+  m_histoBins = other.m_histoBins;
+  return *this;
+}
 
 boost::shared_ptr<Run> Run::clone() {
   auto clone = boost::make_shared<Run>();
   for (auto property : this->m_manager.getProperties()) {
     clone->addProperty(property->clone());
   }
-  clone->m_goniometer = this->m_goniometer;
+  clone->m_goniometer =
+      Kernel::make_unique<Geometry::Goniometer>(*this->m_goniometer);
   clone->m_histoBins = this->m_histoBins;
   return clone;
 }
@@ -184,7 +197,7 @@ void Run::integrateProtonCharge(const std::string &logname) const {
   if (log) {
     const std::vector<double> logValues = log->valuesAsVector();
     double total = std::accumulate(logValues.begin(), logValues.end(), 0.0);
-    std::string unit = log->units();
+    const std::string &unit = log->units();
     // Do we need to take account of a unit
     if (unit.find("picoCoulomb") != std::string::npos) {
       /// Conversion factor between picoColumbs and microAmp*hours
@@ -280,7 +293,7 @@ std::vector<double> Run::getBinBoundaries() const {
  */
 size_t Run::getMemorySize() const {
   size_t total = LogManager::getMemorySize();
-  total += sizeof(m_goniometer);
+  total += sizeof(*m_goniometer);
   total += m_histoBins.size() * sizeof(double);
   return total;
 }
@@ -294,13 +307,13 @@ size_t Run::getMemorySize() const {
  */
 void Run::setGoniometer(const Geometry::Goniometer &goniometer,
                         const bool useLogValues) {
-  Geometry::Goniometer old = m_goniometer;
+  auto old = std::move(m_goniometer);
   try {
-    m_goniometer = goniometer; // copy it in
+    m_goniometer = Kernel::make_unique<Geometry::Goniometer>(goniometer);
     if (useLogValues)
       calculateGoniometerMatrix();
   } catch (std::runtime_error &) {
-    m_goniometer = old;
+    m_goniometer = std::move(old);
     throw;
   }
 }
@@ -314,7 +327,7 @@ void Run::setGoniometer(const Geometry::Goniometer &goniometer,
  * @return 3x3 double rotation matrix
  */
 const Mantid::Kernel::DblMatrix &Run::getGoniometerMatrix() const {
-  return m_goniometer.getR();
+  return m_goniometer->getR();
 }
 
 //--------------------------------------------------------------------------------------------
@@ -328,7 +341,7 @@ void Run::saveNexus(::NeXus::File *file, const std::string &group,
   LogManager::saveNexus(file, group, true);
 
   // write the goniometer
-  m_goniometer.saveNexus(file, GONIOMETER_LOG_NAME);
+  m_goniometer->saveNexus(file, GONIOMETER_LOG_NAME);
 
   // write the histogram bins, if there are any
   if (!m_histoBins.empty()) {
@@ -381,7 +394,7 @@ void Run::loadNexus(::NeXus::File *file, const std::string &group,
   for (const auto &name_class : entries) {
     if (name_class.second == "NXpositioner") {
       // Goniometer class
-      m_goniometer.loadNexus(file, name_class.first);
+      m_goniometer->loadNexus(file, name_class.first);
     } else if (name_class.first == HISTO_BINS_LOG_NAME) {
       file->openGroup(name_class.first, "NXdata");
       file->readData("value", m_histoBins);
@@ -435,8 +448,8 @@ void Run::loadNexus(::NeXus::File *file, const std::string &group,
  * Calculate the goniometer matrix
  */
 void Run::calculateGoniometerMatrix() {
-  for (size_t i = 0; i < m_goniometer.getNumberAxes(); ++i) {
-    const std::string axisName = m_goniometer.getAxis(i).name;
+  for (size_t i = 0; i < m_goniometer->getNumberAxes(); ++i) {
+    const std::string axisName = m_goniometer->getAxis(i).name;
     const double minAngle =
         getLogAsSingleValue(axisName, Kernel::Math::Minimum);
     const double maxAngle =
@@ -471,7 +484,7 @@ void Run::calculateGoniometerMatrix() {
                       "1\',Axis1='chi,0,0,1,1',Axis2='phi,0,1,0,1')");
       }
     }
-    m_goniometer.setRotationAngle(i, angle);
+    m_goniometer->setRotationAngle(i, angle);
   }
 }
 
diff --git a/Framework/API/src/ScopedWorkspace.cpp b/Framework/API/src/ScopedWorkspace.cpp
index e3e05df9f1518d3ef7c2c505779b55de42ce81f6..e6b988678bfd6f62281190c2e2506ad8074c43c3 100644
--- a/Framework/API/src/ScopedWorkspace.cpp
+++ b/Framework/API/src/ScopedWorkspace.cpp
@@ -74,9 +74,9 @@ void ScopedWorkspace::remove() {
 void ScopedWorkspace::set(Workspace_sptr newWS) {
   AnalysisDataServiceImpl &ads = AnalysisDataService::Instance();
 
-  if (!newWS->name().empty() && ads.doesExist(newWS->name()))
+  if (!newWS->getName().empty() && ads.doesExist(newWS->getName()))
     throw std::invalid_argument(
-        "Workspace is already in the ADS under the name " + newWS->name());
+        "Workspace is already in the ADS under the name " + newWS->getName());
 
   // Remove previous workspace entry
   remove();
diff --git a/Framework/API/src/SpectrumInfo.cpp b/Framework/API/src/SpectrumInfo.cpp
index 5bab2300f110883b6e0a17d3db731197412e315a..29caca0280d361fc474d574c92b854adbc7481fb 100644
--- a/Framework/API/src/SpectrumInfo.cpp
+++ b/Framework/API/src/SpectrumInfo.cpp
@@ -1,22 +1,25 @@
 #include "MantidAPI/DetectorInfo.h"
-#include "MantidAPI/MatrixWorkspace.h"
+#include "MantidAPI/ExperimentInfo.h"
 #include "MantidAPI/SpectrumInfo.h"
 #include "MantidGeometry/Instrument/DetectorGroup.h"
+#include "MantidKernel/Exception.h"
 #include "MantidKernel/MultiThreaded.h"
 
+#include <boost/make_shared.hpp>
 #include <algorithm>
 
 namespace Mantid {
 namespace API {
 
-SpectrumInfo::SpectrumInfo(const MatrixWorkspace &workspace)
-    : m_workspace(workspace), m_detectorInfo(workspace.detectorInfo()),
+SpectrumInfo::SpectrumInfo(const ExperimentInfo &experimentInfo)
+    : m_experimentInfo(experimentInfo),
+      m_detectorInfo(experimentInfo.detectorInfo()),
       m_lastDetector(PARALLEL_GET_MAX_THREADS),
       m_lastIndex(PARALLEL_GET_MAX_THREADS, -1) {}
 
-SpectrumInfo::SpectrumInfo(MatrixWorkspace &workspace)
-    : m_workspace(workspace),
-      m_mutableDetectorInfo(&workspace.mutableDetectorInfo()),
+SpectrumInfo::SpectrumInfo(ExperimentInfo &experimentInfo)
+    : m_experimentInfo(experimentInfo),
+      m_mutableDetectorInfo(&experimentInfo.mutableDetectorInfo()),
       m_detectorInfo(*m_mutableDetectorInfo),
       m_lastDetector(PARALLEL_GET_MAX_THREADS),
       m_lastIndex(PARALLEL_GET_MAX_THREADS, -1) {}
@@ -26,12 +29,18 @@ SpectrumInfo::~SpectrumInfo() = default;
 
 /// Returns true if the detector(s) associated with the spectrum are monitors.
 bool SpectrumInfo::isMonitor(const size_t index) const {
-  return getDetector(index).isMonitor();
+  for (const auto detIndex : getDetectorIndices(index))
+    if (!m_detectorInfo.isMonitor(detIndex))
+      return false;
+  return true;
 }
 
 /// Returns true if the detector(s) associated with the spectrum are masked.
 bool SpectrumInfo::isMasked(const size_t index) const {
-  return getDetector(index).isMasked();
+  bool masked = true;
+  for (const auto detIndex : getDetectorIndices(index))
+    masked &= m_detectorInfo.isMasked(detIndex);
+  return masked;
 }
 
 /** Returns L2 (distance from sample to spectrum).
@@ -106,7 +115,7 @@ bool SpectrumInfo::hasDetectors(const size_t index) const {
   // Workspaces can contain invalid detector IDs. Those IDs will be silently
   // ignored here until this is fixed.
   const auto &validDetectorIDs = m_detectorInfo.detectorIDs();
-  for (const auto &id : m_workspace.getSpectrum(index).getDetectorIDs()) {
+  for (const auto &id : m_experimentInfo.detectorIDsInGroup(index)) {
     const auto &it = std::lower_bound(validDetectorIDs.cbegin(),
                                       validDetectorIDs.cend(), id);
     if (it != validDetectorIDs.cend() && *it == id) {
@@ -122,7 +131,7 @@ bool SpectrumInfo::hasUniqueDetector(const size_t index) const {
   // Workspaces can contain invalid detector IDs. Those IDs will be silently
   // ignored here until this is fixed.
   const auto &validDetectorIDs = m_detectorInfo.detectorIDs();
-  for (const auto &id : m_workspace.getSpectrum(index).getDetectorIDs()) {
+  for (const auto &id : m_experimentInfo.detectorIDsInGroup(index)) {
     const auto &it = std::lower_bound(validDetectorIDs.cbegin(),
                                       validDetectorIDs.cend(), id);
     if (it != validDetectorIDs.cend() && *it == id) {
@@ -132,6 +141,14 @@ bool SpectrumInfo::hasUniqueDetector(const size_t index) const {
   return count == 1;
 }
 
+/** Set the mask flag of the spectrum with given index. Not thread safe.
+ *
+ * Currently this simply sets the mask flags for the underlying detectors. */
+void SpectrumInfo::setMasked(const size_t index, bool masked) {
+  for (const auto detIndex : getDetectorIndices(index))
+    m_mutableDetectorInfo->setMasked(detIndex, masked);
+}
+
 /// Return a const reference to the detector or detector group of the spectrum
 /// with given index.
 const Geometry::IDetector &SpectrumInfo::detector(const size_t index) const {
@@ -161,7 +178,7 @@ const Geometry::IDetector &SpectrumInfo::getDetector(const size_t index) const {
   // Note: This function body has big overlap with the method
   // MatrixWorkspace::getDetector(). The plan is to eventually remove the
   // latter, once SpectrumInfo is in widespread use.
-  const auto &dets = m_workspace.getSpectrum(index).getDetectorIDs();
+  const auto &dets = m_experimentInfo.detectorIDsInGroup(index);
   const size_t ndets = dets.size();
   if (ndets == 1) {
     // If only 1 detector for the spectrum number, just return it
@@ -176,11 +193,18 @@ const Geometry::IDetector &SpectrumInfo::getDetector(const size_t index) const {
     // Else need to construct a DetectorGroup and use that
     std::vector<boost::shared_ptr<const Geometry::IDetector>> det_ptrs;
     for (const auto &id : dets) {
-      const auto detIndex = m_detectorInfo.indexOf(id);
-      det_ptrs.push_back(m_detectorInfo.getDetectorPtr(detIndex));
+      try {
+        const auto detIndex = m_detectorInfo.indexOf(id);
+        det_ptrs.push_back(m_detectorInfo.getDetectorPtr(detIndex));
+      } catch (std::out_of_range &) {
+        // Workspaces can contain invalid detector IDs. Those IDs will be
+        // silently ignored here until this is fixed. Some valid IDs will exist
+        // if hasDetectors or hasUniqueDetectors has returned true, but there
+        // could still be invalid IDs.
+      }
     }
     m_lastDetector[thread] =
-        boost::make_shared<Geometry::DetectorGroup>(det_ptrs, false);
+        boost::make_shared<Geometry::DetectorGroup>(det_ptrs);
   }
 
   return *m_lastDetector[thread];
@@ -199,5 +223,21 @@ SpectrumInfo::getDetectorVector(const size_t index) const {
   }
 }
 
+std::vector<size_t> SpectrumInfo::getDetectorIndices(const size_t index) const {
+  std::vector<size_t> detIndices;
+  const auto &validDetectorIDs = m_detectorInfo.detectorIDs();
+  for (const auto &id : m_experimentInfo.detectorIDsInGroup(index)) {
+    const auto &it = std::lower_bound(validDetectorIDs.cbegin(),
+                                      validDetectorIDs.cend(), id);
+    if (it != validDetectorIDs.cend() && *it == id) {
+      detIndices.push_back(m_detectorInfo.indexOf(id));
+    }
+  }
+  if (detIndices.empty())
+    throw Kernel::Exception::NotFoundError(
+        "SpectrumInfo: No detectors for this workspace index.", "");
+  return detIndices;
+}
+
 } // namespace API
 } // namespace Mantid
diff --git a/Framework/API/src/Workspace.cpp b/Framework/API/src/Workspace.cpp
index d6d8f9b830042b6f614f45d8b3c73908139ba922..1db52c7be704f4262b1d900b8376bb67e083c879 100644
--- a/Framework/API/src/Workspace.cpp
+++ b/Framework/API/src/Workspace.cpp
@@ -1,12 +1,24 @@
 #include "MantidAPI/Workspace.h"
+#include "MantidAPI/WorkspaceHistory.h"
 #include "MantidKernel/IPropertyManager.h"
 #include "MantidKernel/Memory.h"
+#include "MantidKernel/make_unique.h"
 
 #include <boost/lexical_cast.hpp>
 
 namespace Mantid {
 namespace API {
 
+Workspace::Workspace() : m_history(Kernel::make_unique<WorkspaceHistory>()) {}
+
+// Defined as default in source for forward declaration with std::unique_ptr.
+Workspace::~Workspace() = default;
+
+Workspace::Workspace(const Workspace &other)
+    : Kernel::DataItem(other), m_title(other.m_title),
+      m_comment(other.m_comment), m_name(other.m_name),
+      m_history(Kernel::make_unique<WorkspaceHistory>(other.getHistory())) {}
+
 /** Set the title of the workspace
  *
  *  @param t :: The title
@@ -55,7 +67,7 @@ const std::string &Workspace::getName() const { return m_name; }
  * @param n: number of algorithms defining a clean workspace
  */
 bool Workspace::isDirty(const int n) const {
-  return static_cast<int>(m_history.size()) > n;
+  return static_cast<int>(m_history->size()) > n;
 }
 
 /**
diff --git a/Framework/API/src/WorkspaceFactory.cpp b/Framework/API/src/WorkspaceFactory.cpp
index a5171a123ce31848b201e3e80e62b8c17991ce5e..dbbac1ae3bf5499f35c66ece261cb0d951f7cbce 100644
--- a/Framework/API/src/WorkspaceFactory.cpp
+++ b/Framework/API/src/WorkspaceFactory.cpp
@@ -71,7 +71,7 @@ WorkspaceFactoryImpl::create(const MatrixWorkspace_const_sptr &parent,
   MatrixWorkspace_sptr ws = create(id, NVectors, XLength, YLength);
 
   // Copy over certain parent data members
-  initializeFromParent(parent, ws, differentSize);
+  initializeFromParent(*parent, *ws, differentSize);
 
   return ws;
 }
@@ -86,54 +86,54 @@ WorkspaceFactoryImpl::create(const MatrixWorkspace_const_sptr &parent,
  *different sizes
  */
 void WorkspaceFactoryImpl::initializeFromParent(
-    const MatrixWorkspace_const_sptr parent, const MatrixWorkspace_sptr child,
+    const MatrixWorkspace &parent, MatrixWorkspace &child,
     const bool differentSize) const {
-  child->setTitle(parent->getTitle());
-  child->setComment(parent->getComment());
-  child->setInstrument(parent->getInstrument()); // This call also copies the
-                                                 // SHARED POINTER to the
-                                                 // parameter map
+  child.setTitle(parent.getTitle());
+  child.setComment(parent.getComment());
+  child.setInstrument(parent.getInstrument()); // This call also copies the
+                                               // SHARED POINTER to the
+                                               // parameter map
   // This call will (should) perform a COPY of the parameter map.
-  child->instrumentParameters();
-  child->m_sample = parent->m_sample;
-  child->m_run = parent->m_run;
-  child->setYUnit(parent->m_YUnit);
-  child->setYUnitLabel(parent->m_YUnitLabel);
-  child->setDistribution(parent->isDistribution());
+  child.instrumentParameters();
+  child.m_sample = parent.m_sample;
+  child.m_run = parent.m_run;
+  child.setYUnit(parent.m_YUnit);
+  child.setYUnitLabel(parent.m_YUnitLabel);
+  child.setDistribution(parent.isDistribution());
 
   // Only copy the axes over if new sizes are not given
   if (!differentSize) {
     // Only copy mask map if same size for now. Later will need to check
     // continued validity.
-    child->m_masks = parent->m_masks;
+    child.m_masks = parent.m_masks;
   }
 
   // Same number of histograms = copy over the spectra data
-  if (parent->getNumberHistograms() == child->getNumberHistograms()) {
-    for (size_t wi = 0; wi < parent->getNumberHistograms(); wi++) {
-      auto &childSpec = child->getSpectrum(wi);
-      const auto &parentSpec = parent->getSpectrum(wi);
+  if (parent.getNumberHistograms() == child.getNumberHistograms()) {
+    for (size_t wi = 0; wi < parent.getNumberHistograms(); wi++) {
+      auto &childSpec = child.getSpectrum(wi);
+      const auto &parentSpec = parent.getSpectrum(wi);
       // Copy spectrum number and detector IDs
       childSpec.copyInfoFrom(parentSpec);
     }
   }
 
   // deal with axis
-  for (size_t i = 0; i < parent->m_axes.size(); ++i) {
-    const size_t newAxisLength = child->getAxis(i)->length();
-    const size_t oldAxisLength = parent->getAxis(i)->length();
+  for (size_t i = 0; i < parent.m_axes.size(); ++i) {
+    const size_t newAxisLength = child.getAxis(i)->length();
+    const size_t oldAxisLength = parent.getAxis(i)->length();
 
     if (!differentSize || newAxisLength == oldAxisLength) {
       // Need to delete the existing axis created in init above
-      delete child->m_axes[i];
+      delete child.m_axes[i];
       // Now set to a copy of the parent workspace's axis
-      child->m_axes[i] = parent->m_axes[i]->clone(child.get());
+      child.m_axes[i] = parent.m_axes[i]->clone(&child);
     } else {
-      if (!parent->getAxis(i)->isSpectra()) // WHY???
+      if (!parent.getAxis(i)->isSpectra()) // WHY???
       {
-        delete child->m_axes[i];
+        delete child.m_axes[i];
         // Call the 'different length' clone variant
-        child->m_axes[i] = parent->m_axes[i]->clone(newAxisLength, child.get());
+        child.m_axes[i] = parent.m_axes[i]->clone(newAxisLength, &child);
       }
     }
   }
diff --git a/Framework/API/src/WorkspaceGroup.cpp b/Framework/API/src/WorkspaceGroup.cpp
index cf5e9a08a39e170196caeecdd650cec5b301371d..8d333b9041116226271c6a4d2c40d1f1f78f2f53 100644
--- a/Framework/API/src/WorkspaceGroup.cpp
+++ b/Framework/API/src/WorkspaceGroup.cpp
@@ -4,6 +4,7 @@
 #include "MantidAPI/Run.h"
 #include "MantidKernel/Logger.h"
 #include "MantidKernel/IPropertyManager.h"
+#include "MantidKernel/Strings.h"
 
 namespace Mantid {
 namespace API {
@@ -35,7 +36,7 @@ const std::string WorkspaceGroup::toString() const {
   std::string descr = this->id() + "\n";
   std::lock_guard<std::recursive_mutex> _lock(m_mutex);
   for (const auto &workspace : m_workspaces) {
-    descr += " -- " + workspace->name() + "\n";
+    descr += " -- " + workspace->getName() + '\n';
   }
   return descr;
 }
@@ -93,7 +94,7 @@ void WorkspaceGroup::sortMembersByName() {
   }
   std::sort(m_workspaces.begin(), m_workspaces.end(),
             [](const Workspace_sptr &w1, const Workspace_sptr &w2) {
-              return (w1->name() < w2->name());
+              return (w1->getName() < w2->getName());
             });
 }
 
@@ -122,7 +123,7 @@ void WorkspaceGroup::addWorkspace(Workspace_sptr workspace) {
 bool WorkspaceGroup::contains(const std::string &wsName) const {
   std::lock_guard<std::recursive_mutex> _lock(m_mutex);
   for (const auto &workspace : m_workspaces) {
-    if ((*workspace).name() == wsName)
+    if (workspace->getName() == wsName)
       return true;
   }
   return false;
@@ -157,7 +158,7 @@ std::vector<std::string> WorkspaceGroup::getNames() const {
   std::lock_guard<std::recursive_mutex> _lock(m_mutex);
   std::vector<std::string> out;
   for (const auto &workspace : m_workspaces) {
-    out.push_back((*workspace).name());
+    out.push_back(workspace->getName());
   }
   return out;
 }
@@ -187,7 +188,7 @@ Workspace_sptr WorkspaceGroup::getItem(const size_t index) const {
 Workspace_sptr WorkspaceGroup::getItem(const std::string wsName) const {
   std::lock_guard<std::recursive_mutex> _lock(m_mutex);
   for (const auto &workspace : m_workspaces) {
-    if ((*workspace).name() == wsName)
+    if (workspace->getName() == wsName)
       return workspace;
   }
   throw std::out_of_range("Workspace " + wsName +
@@ -206,7 +207,7 @@ void WorkspaceGroup::removeByADS(const std::string &wsName) {
   std::lock_guard<std::recursive_mutex> _lock(m_mutex);
   auto it = m_workspaces.begin();
   for (; it != m_workspaces.end(); ++it) {
-    if ((**it).name() == wsName) {
+    if ((**it).getName() == wsName) {
       m_workspaces.erase(it);
       break;
     }
@@ -218,8 +219,8 @@ void WorkspaceGroup::removeByADS(const std::string &wsName) {
 void WorkspaceGroup::print() const {
   std::lock_guard<std::recursive_mutex> _lock(m_mutex);
   for (const auto &workspace : m_workspaces) {
-    g_log.debug() << "Workspace name in group vector =  " << (*workspace).name()
-                  << '\n';
+    g_log.debug() << "Workspace name in group vector =  "
+                  << workspace->getName() << '\n';
   }
 }
 
@@ -232,7 +233,7 @@ void WorkspaceGroup::print() const {
 void WorkspaceGroup::removeItem(const size_t index) {
   std::lock_guard<std::recursive_mutex> _lock(m_mutex);
   // do not allow this way of removing for groups in the ADS
-  if (!name().empty()) {
+  if (!this->getName().empty()) {
     throw std::runtime_error(
         "AnalysisDataService must be used to remove a workspace from group.");
   }
@@ -338,7 +339,7 @@ bool WorkspaceGroup::areNamesSimilar() const {
 
   // Check all the members are of similar names
   for (const auto &workspace : m_workspaces) {
-    const std::string wsName = (*workspace).name();
+    const std::string &wsName = workspace->getName();
     // Find the last underscore _
     std::size_t pos = wsName.find_last_of('_');
     // No underscore = not similar
@@ -347,7 +348,7 @@ bool WorkspaceGroup::areNamesSimilar() const {
     // The part before the underscore has to be the same
     // as the group name to be similar
     std::string commonpart(wsName.substr(0, pos));
-    if (this->name() != commonpart)
+    if (this->getName() != commonpart)
       return false;
   }
   return true;
diff --git a/Framework/API/src/WorkspaceHistory.cpp b/Framework/API/src/WorkspaceHistory.cpp
index c93483b3666afdc07481d1cca173519a2a8d6ce1..c501aa008a9b9263d4382692491c17dbf854d44c 100644
--- a/Framework/API/src/WorkspaceHistory.cpp
+++ b/Framework/API/src/WorkspaceHistory.cpp
@@ -1,13 +1,12 @@
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidAPI/Algorithm.h"
 #include "MantidAPI/AlgorithmHistory.h"
 #include "MantidAPI/HistoryView.h"
 #include "MantidAPI/WorkspaceHistory.h"
 #include "MantidKernel/EnvironmentHistory.h"
 #include "MantidKernel/Strings.h"
+#include "MantidKernel/StringTokenizer.h"
 
+#include <boost/algorithm/string/classification.hpp>
 #include <boost/algorithm/string/split.hpp>
 
 #include "Poco/DateTime.h"
diff --git a/Framework/API/src/WorkspaceOpOverloads.cpp b/Framework/API/src/WorkspaceOpOverloads.cpp
index 3be1fd8b086f542a31e47d54d8031b5d25ac7f40..de3ccf96377f8e411406415261fb127b0c3811e8 100644
--- a/Framework/API/src/WorkspaceOpOverloads.cpp
+++ b/Framework/API/src/WorkspaceOpOverloads.cpp
@@ -1,18 +1,13 @@
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidAPI/WorkspaceOpOverloads.h"
 #include "MantidAPI/Algorithm.h"
 #include "MantidAPI/AlgorithmManager.h"
 #include "MantidKernel/Property.h"
-//#include "MantidKernel/Exception.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/IWorkspaceProperty.h"
 #include "MantidAPI/WorkspaceFactory.h"
-//#include "MantidAPI/SpectraAxis.h"
 #include "MantidAPI/IMDWorkspace.h"
 #include "MantidAPI/IMDHistoWorkspace.h"
-#include "MantidAPI/WorkspaceGroup_fwd.h"
+#include "MantidAPI/WorkspaceGroup.h"
 
 #include <numeric>
 
@@ -409,8 +404,8 @@ MatrixWorkspace_sptr operator/=(const MatrixWorkspace_sptr lhs,
  *  @param WS :: The workspace to check
  *  @return True if the bins match
  */
-bool WorkspaceHelpers::commonBoundaries(const MatrixWorkspace_const_sptr WS) {
-  if (!WS->blocksize() || WS->getNumberHistograms() < 2)
+bool WorkspaceHelpers::commonBoundaries(const MatrixWorkspace &WS) {
+  if (!WS.blocksize() || WS.getNumberHistograms() < 2)
     return true;
   // Quickest check is to see if they are actually all the same vector
   if (sharedXData(WS))
@@ -418,21 +413,21 @@ bool WorkspaceHelpers::commonBoundaries(const MatrixWorkspace_const_sptr WS) {
 
   // But even if they're not they could still match...
   const double commonSum =
-      std::accumulate(WS->readX(0).begin(), WS->readX(0).end(), 0.);
+      std::accumulate(WS.readX(0).begin(), WS.readX(0).end(), 0.);
   // If this results in infinity or NaN, then we can't tell - return false
   if (!std::isfinite(commonSum))
     return false;
-  const size_t numHist = WS->getNumberHistograms();
+  const size_t numHist = WS.getNumberHistograms();
   for (size_t j = 1; j < numHist; ++j) {
     const double sum =
-        std::accumulate(WS->readX(j).begin(), WS->readX(j).end(), 0.);
+        std::accumulate(WS.readX(j).begin(), WS.readX(j).end(), 0.);
     // If this results in infinity or NaN, then we can't tell - return false
     if (!std::isfinite(sum))
       return false;
 
     if (std::abs(commonSum) < 1.0E-7 && std::abs(sum) < 1.0E-7) {
-      for (size_t i = 0; i < WS->blocksize(); i++) {
-        if (std::abs(WS->readX(0)[i] - WS->readX(j)[i]) > 1.0E-7)
+      for (size_t i = 0; i < WS.blocksize(); i++) {
+        if (std::abs(WS.readX(0)[i] - WS.readX(j)[i]) > 1.0E-7)
           return false;
       }
     } else if (std::abs(commonSum - sum) /
@@ -452,21 +447,21 @@ bool WorkspaceHelpers::commonBoundaries(const MatrixWorkspace_const_sptr WS) {
  * number of spectra
  *  @return True if the test passes
  */
-bool WorkspaceHelpers::matchingBins(const MatrixWorkspace_const_sptr ws1,
-                                    const MatrixWorkspace_const_sptr ws2,
+bool WorkspaceHelpers::matchingBins(const MatrixWorkspace &ws1,
+                                    const MatrixWorkspace &ws2,
                                     const bool firstOnly) {
   // First of all, the first vector must be the same size
-  if (ws1->readX(0).size() != ws2->readX(0).size())
+  if (ws1.readX(0).size() != ws2.readX(0).size())
     return false;
 
   // Now check the first spectrum
   const double firstWS =
-      std::accumulate(ws1->readX(0).begin(), ws1->readX(0).end(), 0.);
+      std::accumulate(ws1.readX(0).begin(), ws1.readX(0).end(), 0.);
   const double secondWS =
-      std::accumulate(ws2->readX(0).begin(), ws2->readX(0).end(), 0.);
+      std::accumulate(ws2.readX(0).begin(), ws2.readX(0).end(), 0.);
   if (std::abs(firstWS) < 1.0E-7 && std::abs(secondWS) < 1.0E-7) {
-    for (size_t i = 0; i < ws1->readX(0).size(); i++) {
-      if (std::abs(ws1->readX(0)[i] - ws2->readX(0)[i]) > 1.0E-7)
+    for (size_t i = 0; i < ws1.readX(0).size(); i++) {
+      if (std::abs(ws1.readX(0)[i] - ws2.readX(0)[i]) > 1.0E-7)
         return false;
     }
   } else if (std::abs(firstWS - secondWS) /
@@ -479,7 +474,7 @@ bool WorkspaceHelpers::matchingBins(const MatrixWorkspace_const_sptr ws1,
     return true;
 
   // Check that total size of workspace is the same
-  if (ws1->size() != ws2->size())
+  if (ws1.size() != ws2.size())
     return false;
   // If that passes then check whether all the X vectors are shared
   if (sharedXData(ws1) && sharedXData(ws2))
@@ -487,7 +482,7 @@ bool WorkspaceHelpers::matchingBins(const MatrixWorkspace_const_sptr ws1,
 
   // If that didn't pass then explicitly check 1 in 10 of the vectors (min 10,
   // max 100)
-  const size_t numHist = ws1->getNumberHistograms();
+  const size_t numHist = ws1.getNumberHistograms();
   size_t numberToCheck = numHist / 10;
   if (numberToCheck < 10)
     numberToCheck = 10;
@@ -498,12 +493,12 @@ bool WorkspaceHelpers::matchingBins(const MatrixWorkspace_const_sptr ws1,
     step = 1;
   for (size_t i = step; i < numHist; i += step) {
     const double firstWSLoop =
-        std::accumulate(ws1->readX(i).begin(), ws1->readX(i).end(), 0.);
+        std::accumulate(ws1.readX(i).begin(), ws1.readX(i).end(), 0.);
     const double secondWSLoop =
-        std::accumulate(ws2->readX(i).begin(), ws2->readX(i).end(), 0.);
+        std::accumulate(ws2.readX(i).begin(), ws2.readX(i).end(), 0.);
     if (std::abs(firstWSLoop) < 1.0E-7 && std::abs(secondWSLoop) < 1.0E-7) {
-      for (size_t j = 0; j < ws1->readX(i).size(); j++) {
-        if (std::abs(ws1->readX(i)[j] - ws2->readX(i)[j]) > 1.0E-7)
+      for (size_t j = 0; j < ws1.readX(i).size(); j++) {
+        if (std::abs(ws1.readX(i)[j] - ws2.readX(i)[j]) > 1.0E-7)
           return false;
       }
     } else if (std::abs(firstWSLoop - secondWSLoop) /
@@ -517,11 +512,11 @@ bool WorkspaceHelpers::matchingBins(const MatrixWorkspace_const_sptr ws1,
 }
 
 /// Checks whether all the X vectors in a workspace are the same one underneath
-bool WorkspaceHelpers::sharedXData(const MatrixWorkspace_const_sptr WS) {
-  const double &first = WS->readX(0)[0];
-  const size_t numHist = WS->getNumberHistograms();
+bool WorkspaceHelpers::sharedXData(const MatrixWorkspace &WS) {
+  const double &first = WS.readX(0)[0];
+  const size_t numHist = WS.getNumberHistograms();
   for (size_t i = 1; i < numHist; ++i) {
-    if (&first != &(WS->readX(i)[0]))
+    if (&first != &(WS.readX(i)[0]))
       return false;
   }
   return true;
diff --git a/Framework/API/src/WorkspaceProperty.cpp b/Framework/API/src/WorkspaceProperty.cpp
index 7284be35e7295e92e9817ebe53f17d798499c33a..42bc43201755e39b950833a9b35915de896ae7aa 100644
--- a/Framework/API/src/WorkspaceProperty.cpp
+++ b/Framework/API/src/WorkspaceProperty.cpp
@@ -1,10 +1,15 @@
-#include "MantidAPI/Workspace.h"
-#include "MantidAPI/WorkspaceProperty.h"
-#include "MantidAPI/IMDWorkspace.h"
 #include "MantidAPI/IEventWorkspace.h"
 #include "MantidAPI/IMDEventWorkspace.h"
-#include "MantidAPI/ITableWorkspace.h"
+#include "MantidAPI/IMDHistoWorkspace.h"
+#include "MantidAPI/IMDWorkspace.h"
+#include "MantidAPI/IPeaksWorkspace.h"
 #include "MantidAPI/ISplittersWorkspace.h"
+#include "MantidAPI/ITableWorkspace.h"
+#include "MantidAPI/WorkspaceGroup.h"
+#include "MantidAPI/Workspace.h"
+
+// WorkspaceProperty implementation
+#include "MantidAPI/WorkspaceProperty.tcc"
 
 namespace Mantid {
 namespace API {
@@ -15,12 +20,18 @@ template class MANTID_API_DLL
     Mantid::API::WorkspaceProperty<Mantid::API::IEventWorkspace>;
 template class MANTID_API_DLL
     Mantid::API::WorkspaceProperty<Mantid::API::IMDEventWorkspace>;
+template class MANTID_API_DLL
+    Mantid::API::WorkspaceProperty<Mantid::API::IMDHistoWorkspace>;
 template class MANTID_API_DLL
     Mantid::API::WorkspaceProperty<Mantid::API::IMDWorkspace>;
 template class MANTID_API_DLL
     Mantid::API::WorkspaceProperty<Mantid::API::MatrixWorkspace>;
+template class MANTID_API_DLL
+    Mantid::API::WorkspaceProperty<Mantid::API::IPeaksWorkspace>;
 template class MANTID_API_DLL
     Mantid::API::WorkspaceProperty<Mantid::API::ITableWorkspace>;
+template class MANTID_API_DLL
+    Mantid::API::WorkspaceProperty<Mantid::API::WorkspaceGroup>;
 ///@endcond TEMPLATE
 } // namespace API
 } // namespace Mantid
diff --git a/Framework/API/test/AlgorithmManagerTest.h b/Framework/API/test/AlgorithmManagerTest.h
index 741583977f3c061a59bb911a0590b928fb04a700..fcdbcdcb517c2be1450ddaa158082765143d565f 100644
--- a/Framework/API/test/AlgorithmManagerTest.h
+++ b/Framework/API/test/AlgorithmManagerTest.h
@@ -6,6 +6,7 @@
 #include "MantidAPI/Algorithm.h"
 #include "MantidAPI/AlgorithmProxy.h"
 #include "MantidAPI/AlgorithmManager.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidKernel/ConfigService.h"
 #include <stdexcept>
 #include <vector>
diff --git a/Framework/API/test/AlgorithmProxyTest.h b/Framework/API/test/AlgorithmProxyTest.h
index 498e4e0098a64640c55b27e2b04e26335ae69c1b..d8d745c15a792e855eb84fe363c7aff5bc925fab 100644
--- a/Framework/API/test/AlgorithmProxyTest.h
+++ b/Framework/API/test/AlgorithmProxyTest.h
@@ -11,6 +11,8 @@
 #include <Poco/ActiveResult.h>
 #include <Poco/Thread.h>
 
+#include <boost/lexical_cast.hpp>
+
 using namespace Mantid::API;
 using namespace Mantid::Kernel;
 
diff --git a/Framework/API/test/AlgorithmTest.h b/Framework/API/test/AlgorithmTest.h
index 55c704d1deafbffef28effa4c265909e58044211..d6f807e008a2c06172aa0f0d36fcd5b2e2f49859 100644
--- a/Framework/API/test/AlgorithmTest.h
+++ b/Framework/API/test/AlgorithmTest.h
@@ -11,8 +11,10 @@
 #include "MantidKernel/WriteLock.h"
 #include "MantidAPI/WorkspaceProperty.h"
 #include "MantidAPI/FrameworkManager.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidKernel/ArrayProperty.h"
 #include "MantidKernel/RebinParamsValidator.h"
+#include "MantidKernel/Strings.h"
 #include "FakeAlgorithms.h"
 #include "PropertyManagerHelper.h"
 #include <map>
@@ -575,7 +577,7 @@ public:
     WorkspaceGroup_sptr group =
         boost::dynamic_pointer_cast<WorkspaceGroup>(out1);
 
-    TS_ASSERT_EQUALS(group->name(), "D")
+    TS_ASSERT_EQUALS(group->getName(), "D")
     TS_ASSERT_EQUALS(group->getNumberOfEntries(), expectedNumber)
     if (group->getNumberOfEntries() < 1)
       return group;
@@ -601,12 +603,12 @@ public:
     WorkspaceGroup_sptr group = do_test_groups(
         "A", "A_1,A_2,A_3", "B", "B_1,B_2,B_3", "C", "C_1,C_2,C_3");
 
-    TS_ASSERT_EQUALS(ws1->name(), "D_1");
+    TS_ASSERT_EQUALS(ws1->getName(), "D_1");
     TS_ASSERT_EQUALS(ws1->getTitle(), "A_1+B_1+C_1");
     TS_ASSERT_EQUALS(ws1->readY(0)[0], 234);
-    TS_ASSERT_EQUALS(ws2->name(), "D_2");
+    TS_ASSERT_EQUALS(ws2->getName(), "D_2");
     TS_ASSERT_EQUALS(ws2->getTitle(), "A_2+B_2+C_2");
-    TS_ASSERT_EQUALS(ws3->name(), "D_3");
+    TS_ASSERT_EQUALS(ws3->getName(), "D_3");
     TS_ASSERT_EQUALS(ws3->getTitle(), "A_3+B_3+C_3");
   }
 
@@ -615,12 +617,12 @@ public:
     WorkspaceGroup_sptr group = do_test_groups(
         "A", "A_1,A_2,A_3", "B", "B_1,B_2,B_3", "C", "alice,bob,charlie");
 
-    TS_ASSERT_EQUALS(ws1->name(), "A_1_B_1_alice_D");
+    TS_ASSERT_EQUALS(ws1->getName(), "A_1_B_1_alice_D");
     TS_ASSERT_EQUALS(ws1->getTitle(), "A_1+B_1+alice");
     TS_ASSERT_EQUALS(ws1->readY(0)[0], 234);
-    TS_ASSERT_EQUALS(ws2->name(), "A_2_B_2_bob_D");
+    TS_ASSERT_EQUALS(ws2->getName(), "A_2_B_2_bob_D");
     TS_ASSERT_EQUALS(ws2->getTitle(), "A_2+B_2+bob");
-    TS_ASSERT_EQUALS(ws3->name(), "A_3_B_3_charlie_D");
+    TS_ASSERT_EQUALS(ws3->getName(), "A_3_B_3_charlie_D");
     TS_ASSERT_EQUALS(ws3->getTitle(), "A_3+B_3+charlie");
   }
 
@@ -629,12 +631,12 @@ public:
     WorkspaceGroup_sptr group =
         do_test_groups("A", "A_1,A_2,A_3", "B", "", "C", "");
 
-    TS_ASSERT_EQUALS(ws1->name(), "D_1");
+    TS_ASSERT_EQUALS(ws1->getName(), "D_1");
     TS_ASSERT_EQUALS(ws1->getTitle(), "A_1+B+C");
     TS_ASSERT_EQUALS(ws1->readY(0)[0], 234);
-    TS_ASSERT_EQUALS(ws2->name(), "D_2");
+    TS_ASSERT_EQUALS(ws2->getName(), "D_2");
     TS_ASSERT_EQUALS(ws2->getTitle(), "A_2+B+C");
-    TS_ASSERT_EQUALS(ws3->name(), "D_3");
+    TS_ASSERT_EQUALS(ws3->getName(), "D_3");
     TS_ASSERT_EQUALS(ws3->getTitle(), "A_3+B+C");
   }
 
@@ -643,12 +645,12 @@ public:
     WorkspaceGroup_sptr group =
         do_test_groups("A", "A_1,A_2,A_3", "B", "", "", "");
 
-    TS_ASSERT_EQUALS(ws1->name(), "D_1");
+    TS_ASSERT_EQUALS(ws1->getName(), "D_1");
     TS_ASSERT_EQUALS(ws1->getTitle(), "A_1+B+");
     TS_ASSERT_EQUALS(ws1->readY(0)[0], 234);
-    TS_ASSERT_EQUALS(ws2->name(), "D_2");
+    TS_ASSERT_EQUALS(ws2->getName(), "D_2");
     TS_ASSERT_EQUALS(ws2->getTitle(), "A_2+B+");
-    TS_ASSERT_EQUALS(ws3->name(), "D_3");
+    TS_ASSERT_EQUALS(ws3->getName(), "D_3");
     TS_ASSERT_EQUALS(ws3->getTitle(), "A_3+B+");
   }
 
@@ -657,12 +659,12 @@ public:
     WorkspaceGroup_sptr group =
         do_test_groups("A", "A_1,A_2,A_3", "", "", "C", "C_1,C_2,C_3");
 
-    TS_ASSERT_EQUALS(ws1->name(), "D_1");
+    TS_ASSERT_EQUALS(ws1->getName(), "D_1");
     TS_ASSERT_EQUALS(ws1->getTitle(), "A_1++C_1");
     TS_ASSERT_EQUALS(ws1->readY(0)[0], 234);
-    TS_ASSERT_EQUALS(ws2->name(), "D_2");
+    TS_ASSERT_EQUALS(ws2->getName(), "D_2");
     TS_ASSERT_EQUALS(ws2->getTitle(), "A_2++C_2");
-    TS_ASSERT_EQUALS(ws3->name(), "D_3");
+    TS_ASSERT_EQUALS(ws3->getName(), "D_3");
     TS_ASSERT_EQUALS(ws3->getTitle(), "A_3++C_3");
   }
 
@@ -671,7 +673,7 @@ public:
     WorkspaceGroup_sptr group =
         do_test_groups("A", "A_1", "B", "", "C", "", false, 1);
 
-    TS_ASSERT_EQUALS(ws1->name(), "D_1");
+    TS_ASSERT_EQUALS(ws1->getName(), "D_1");
     TS_ASSERT_EQUALS(ws1->getTitle(), "A_1+B+C");
     TS_ASSERT_EQUALS(ws1->readY(0)[0], 234);
   }
@@ -681,7 +683,7 @@ public:
     WorkspaceGroup_sptr group =
         do_test_groups("A", "A_1", "B", "B_1", "C", "", false, 1);
 
-    TS_ASSERT_EQUALS(ws1->name(), "D_1");
+    TS_ASSERT_EQUALS(ws1->getName(), "D_1");
     TS_ASSERT_EQUALS(ws1->getTitle(), "A_1+B_1+C");
     TS_ASSERT_EQUALS(ws1->readY(0)[0], 234);
   }
@@ -713,12 +715,12 @@ public:
     WorkspaceGroup_sptr group =
         do_test_groups("D", "D1,D2,D3", "B", "B1,B2,B3", "C", "C1,C2,C3");
 
-    TS_ASSERT_EQUALS(ws1->name(), "D1");
+    TS_ASSERT_EQUALS(ws1->getName(), "D1");
     TS_ASSERT_EQUALS(ws1->getTitle(), "D1+B1+C1");
     TS_ASSERT_EQUALS(ws1->readY(0)[0], 234);
-    TS_ASSERT_EQUALS(ws2->name(), "D2");
+    TS_ASSERT_EQUALS(ws2->getName(), "D2");
     TS_ASSERT_EQUALS(ws2->getTitle(), "D2+B2+C2");
-    TS_ASSERT_EQUALS(ws3->name(), "D3");
+    TS_ASSERT_EQUALS(ws3->getName(), "D3");
     TS_ASSERT_EQUALS(ws3->getTitle(), "D3+B3+C3");
   }
 
@@ -728,12 +730,12 @@ public:
     WorkspaceGroup_sptr group =
         do_test_groups("A", "A1,A2,A3", "D", "D1,D2,D3", "C", "C1,C2,C3");
 
-    TS_ASSERT_EQUALS(ws1->name(), "D1");
+    TS_ASSERT_EQUALS(ws1->getName(), "D1");
     TS_ASSERT_EQUALS(ws1->getTitle(), "A1+D1+C1");
     TS_ASSERT_EQUALS(ws1->readY(0)[0], 234);
-    TS_ASSERT_EQUALS(ws2->name(), "D2");
+    TS_ASSERT_EQUALS(ws2->getName(), "D2");
     TS_ASSERT_EQUALS(ws2->getTitle(), "A2+D2+C2");
-    TS_ASSERT_EQUALS(ws3->name(), "D3");
+    TS_ASSERT_EQUALS(ws3->getName(), "D3");
     TS_ASSERT_EQUALS(ws3->getTitle(), "A3+D3+C3");
   }
 
@@ -743,12 +745,12 @@ public:
     WorkspaceGroup_sptr group =
         do_test_groups("A", "A1,A2,A3", "D", "D1,D2,D3", "D", "D1,D2,D3");
 
-    TS_ASSERT_EQUALS(ws1->name(), "D1");
+    TS_ASSERT_EQUALS(ws1->getName(), "D1");
     TS_ASSERT_EQUALS(ws1->getTitle(), "A1+D1+D1");
     TS_ASSERT_EQUALS(ws1->readY(0)[0], 234);
-    TS_ASSERT_EQUALS(ws2->name(), "D2");
+    TS_ASSERT_EQUALS(ws2->getName(), "D2");
     TS_ASSERT_EQUALS(ws2->getTitle(), "A2+D2+D2");
-    TS_ASSERT_EQUALS(ws3->name(), "D3");
+    TS_ASSERT_EQUALS(ws3->getName(), "D3");
     TS_ASSERT_EQUALS(ws3->getTitle(), "A3+D3+D3");
   }
 
diff --git a/Framework/API/test/CMakeLists.txt b/Framework/API/test/CMakeLists.txt
index 5a4896343b3ace0052d5f59f5f3ada7bf3a8067a..9f1fe2a12caa434d73abb6902dcfaefd41c08108 100644
--- a/Framework/API/test/CMakeLists.txt
+++ b/Framework/API/test/CMakeLists.txt
@@ -9,12 +9,14 @@ if ( CXXTEST_FOUND )
                         ../../TestHelpers/src/BoxControllerDummyIO.cpp
                         ../../TestHelpers/src/InstrumentCreationHelper.cpp
                         ../../TestHelpers/src/NexusTestHelper.cpp
+                        ../../TestHelpers/src/FakeObjects.cpp
       )
   cxxtest_add_test ( APITest ${TEST_FILES} ${GMOCK_TEST_FILES})
   target_link_libraries( APITest LINK_PRIVATE ${TCMALLOC_LIBRARIES_LINKTIME} 
             API
             Geometry
             HistogramData
+            Indexing
             Kernel
             Nexus
             ${JSONCPP_LIBRARIES}
diff --git a/Framework/API/test/CompositeFunctionTest.h b/Framework/API/test/CompositeFunctionTest.h
index ea85f39e6afd8ceb6cd2f16205d969474aaff357..888746ea812e985abf0fd9e93a7c621240e5d7b2 100644
--- a/Framework/API/test/CompositeFunctionTest.h
+++ b/Framework/API/test/CompositeFunctionTest.h
@@ -59,6 +59,7 @@ public:
   }
   const std::string id(void) const override { return ""; }
   void init(const size_t &, const size_t &, const size_t &) override {}
+  void init(const size_t &, const HistogramData::Histogram &) override {}
   void generateHistogram(const std::size_t, const MantidVec &, MantidVec &,
                          MantidVec &, bool) const override {}
 
@@ -74,6 +75,11 @@ private:
                              "CompositeFunctionTest_MocMatrixWorkspace is not "
                              "implemented.");
   }
+  CompositeFunctionTest_MocMatrixWorkspace *doCloneEmpty() const override {
+    throw std::runtime_error("Cloning of "
+                             "CompositeFunctionTest_MocMatrixWorkspace is not "
+                             "implemented.");
+  }
   std::vector<CompositeFunctionTest_MocSpectrum> m_spectra;
   size_t m_blocksize;
 };
@@ -356,17 +362,17 @@ public:
 
     TS_ASSERT_EQUALS(mfun->nParams(), 12);
 
-    TS_ASSERT_EQUALS(mfun->getParameter(0), 0.8);
+    TS_ASSERT_EQUALS(mfun->getParameter(0), 0.0);
     TS_ASSERT_EQUALS(mfun->getParameter(1), 0.0);
     TS_ASSERT_EQUALS(mfun->getParameter(2), 1.1);
     TS_ASSERT_EQUALS(mfun->getParameter(3), 1.2);
-    TS_ASSERT_EQUALS(mfun->getParameter(4), 1.3);
+    TS_ASSERT_EQUALS(mfun->getParameter(4), 0.0);
     TS_ASSERT_EQUALS(mfun->getParameter(5), 2.1);
-    TS_ASSERT_EQUALS(mfun->getParameter(6), 2.2);
-    TS_ASSERT_EQUALS(mfun->getParameter(7), 2.3);
+    TS_ASSERT_EQUALS(mfun->getParameter(6), 0.0);
+    TS_ASSERT_EQUALS(mfun->getParameter(7), 0.0);
     TS_ASSERT_EQUALS(mfun->getParameter(8), 2.4);
     TS_ASSERT_EQUALS(mfun->getParameter(9), 3.1);
-    TS_ASSERT_EQUALS(mfun->getParameter(10), 3.2);
+    TS_ASSERT_EQUALS(mfun->getParameter(10), 0.0);
     TS_ASSERT_EQUALS(mfun->getParameter(11), 3.3);
 
     TS_ASSERT_EQUALS(mfun->parameterName(0), "f0.a");
@@ -382,17 +388,17 @@ public:
     TS_ASSERT_EQUALS(mfun->parameterName(10), "f3.h");
     TS_ASSERT_EQUALS(mfun->parameterName(11), "f3.s");
 
-    TS_ASSERT_EQUALS(mfun->getParameter("f0.a"), 0.8);
+    TS_ASSERT_EQUALS(mfun->getParameter("f0.a"), 0.0);
     TS_ASSERT_EQUALS(mfun->getParameter("f0.b"), 0.0);
     TS_ASSERT_EQUALS(mfun->getParameter("f1.c"), 1.1);
     TS_ASSERT_EQUALS(mfun->getParameter("f1.h"), 1.2);
-    TS_ASSERT_EQUALS(mfun->getParameter("f1.s"), 1.3);
+    TS_ASSERT_EQUALS(mfun->getParameter("f1.s"), 0.0);
     TS_ASSERT_EQUALS(mfun->getParameter("f2.c0"), 2.1);
-    TS_ASSERT_EQUALS(mfun->getParameter("f2.c1"), 2.2);
-    TS_ASSERT_EQUALS(mfun->getParameter("f2.c2"), 2.3);
+    TS_ASSERT_EQUALS(mfun->getParameter("f2.c1"), 0.0);
+    TS_ASSERT_EQUALS(mfun->getParameter("f2.c2"), 0.0);
     TS_ASSERT_EQUALS(mfun->getParameter("f2.c3"), 2.4);
     TS_ASSERT_EQUALS(mfun->getParameter("f3.c"), 3.1);
-    TS_ASSERT_EQUALS(mfun->getParameter("f3.h"), 3.2);
+    TS_ASSERT_EQUALS(mfun->getParameter("f3.h"), 0.0);
     TS_ASSERT_EQUALS(mfun->getParameter("f3.s"), 3.3);
 
     TS_ASSERT_EQUALS(mfun->parameterIndex("f0.a"), 0);
@@ -461,17 +467,17 @@ public:
 
     TS_ASSERT_EQUALS(mfun->nParams(), 12);
 
-    TS_ASSERT_EQUALS(mfun->getParameter(0), 0.8);
-    TS_ASSERT_EQUALS(mfun->getParameter(1), 0.0);
+    TS_ASSERT_EQUALS(mfun->getParameter(0), -1);
+    TS_ASSERT_EQUALS(mfun->getParameter(1), -2);
     TS_ASSERT_EQUALS(mfun->getParameter(2), 100);
     TS_ASSERT_EQUALS(mfun->getParameter(3), 101);
-    TS_ASSERT_EQUALS(mfun->getParameter(4), 1.3);
+    TS_ASSERT_EQUALS(mfun->getParameter(4), -3);
     TS_ASSERT_EQUALS(mfun->getParameter(5), 102);
-    TS_ASSERT_EQUALS(mfun->getParameter(6), 2.2);
-    TS_ASSERT_EQUALS(mfun->getParameter(7), 2.3);
+    TS_ASSERT_EQUALS(mfun->getParameter(6), -4);
+    TS_ASSERT_EQUALS(mfun->getParameter(7), -5);
     TS_ASSERT_EQUALS(mfun->getParameter(8), 103);
     TS_ASSERT_EQUALS(mfun->getParameter(9), 104);
-    TS_ASSERT_EQUALS(mfun->getParameter(10), 3.2);
+    TS_ASSERT_EQUALS(mfun->getParameter(10), -6);
     TS_ASSERT_EQUALS(mfun->getParameter(11), 105);
 
     delete mfun;
@@ -658,7 +664,7 @@ public:
 
     TS_ASSERT_EQUALS(mfun->nParams(), 12);
 
-    TS_ASSERT_DIFFERS(mfun->getParameter(0), 154);
+    TS_ASSERT_EQUALS(mfun->getParameter(0), 154);
     TS_ASSERT_EQUALS(mfun->getParameter(1), 77);
     TS_ASSERT_EQUALS(mfun->getParameter(2), 1.1);
     TS_ASSERT_EQUALS(mfun->getParameter(3), 1.2);
diff --git a/Framework/API/test/DataProcessorAlgorithmTest.h b/Framework/API/test/DataProcessorAlgorithmTest.h
index 3974a38ce2c5c7fc0be4c9c38eae9dedad7c45e7..c01f25a481ad8ed6910da9cce296ab1e1b83b215 100644
--- a/Framework/API/test/DataProcessorAlgorithmTest.h
+++ b/Framework/API/test/DataProcessorAlgorithmTest.h
@@ -4,11 +4,13 @@
 #include <cxxtest/TestSuite.h>
 #include "MantidKernel/Timer.h"
 #include "MantidKernel/System.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/DataProcessorAlgorithm.h"
+#include "MantidAPI/WorkspaceHistory.h"
 #include "MantidTestHelpers/FakeObjects.h"
 
 using namespace Mantid;
-using namespace Mantid::API;
+using namespace Mantid::Kernel;
 using namespace Mantid::API;
 
 class DataProcessorAlgorithmTest : public CxxTest::TestSuite {
diff --git a/Framework/API/test/DetectorInfoTest.h b/Framework/API/test/DetectorInfoTest.h
index c776afb80814325be10d0cdd92fba242fd3fe805..f5449c542eece9d8c00df355249ceeac8fe59fda 100644
--- a/Framework/API/test/DetectorInfoTest.h
+++ b/Framework/API/test/DetectorInfoTest.h
@@ -10,6 +10,7 @@
 
 #include <algorithm>
 
+using namespace Mantid::Kernel;
 using namespace Mantid::Geometry;
 using namespace Mantid::API;
 
@@ -31,11 +32,10 @@ public:
         m_workspace, includeMonitors, startYNegative, instrumentName);
 
     std::set<int64_t> toMask{0, 3};
-    ParameterMap &pmap = m_workspace.instrumentParameters();
+    auto &detInfo = m_workspace.mutableDetectorInfo();
     for (size_t i = 0; i < m_workspace.getNumberHistograms(); ++i) {
       if (toMask.find(i) != toMask.end()) {
-        IDetector_const_sptr det = m_workspace.getDetector(i);
-        pmap.addBool(det.get(), "masked", true);
+        detInfo.setMasked(i, true);
       }
     }
 
@@ -43,6 +43,8 @@ public:
                                  numberOfBins - 1);
   }
 
+  void test_size() { TS_ASSERT_EQUALS(m_workspace.detectorInfo().size(), 5); }
+
   void test_sourcePosition() {
     TS_ASSERT_EQUALS(m_workspace.detectorInfo().sourcePosition(),
                      V3D(0.0, 0.0, -20.0));
@@ -176,6 +178,20 @@ public:
     TS_ASSERT_EQUALS(detectorInfo.rotation(4), Quat(1.0, 0.0, 0.0, 0.0));
   }
 
+  void test_setMasked() {
+    auto &detectorInfo = m_workspace.mutableDetectorInfo();
+    TS_ASSERT_EQUALS(detectorInfo.isMasked(0), true);
+    detectorInfo.setMasked(0, false);
+    TS_ASSERT_EQUALS(detectorInfo.isMasked(0), false);
+    detectorInfo.setMasked(0, true);
+    TS_ASSERT_EQUALS(detectorInfo.isMasked(0), true);
+    // Make sure no other detectors are affected
+    TS_ASSERT_EQUALS(detectorInfo.isMasked(1), false);
+    TS_ASSERT_EQUALS(detectorInfo.isMasked(2), false);
+    TS_ASSERT_EQUALS(detectorInfo.isMasked(3), true);
+    TS_ASSERT_EQUALS(detectorInfo.isMasked(4), false);
+  }
+
   void test_setRotation() {
     V3D e3{0, 0, 1};
     Quat r3(90.0, e3);
@@ -293,6 +309,22 @@ public:
     TS_ASSERT_EQUALS(ids, sorted_ids);
   }
 
+  void test_assignment() {
+    auto ws1 = makeWorkspace(2);
+    auto ws2 = makeWorkspace(2);
+    TS_ASSERT_THROWS_NOTHING(ws2->mutableDetectorInfo() = ws1->detectorInfo());
+    // TODO Beamline::DetectorInfo is currently not containing data, so there is
+    // nothing we can check here. Once the class is getting populated add more
+    // checks here.
+  }
+
+  void test_assignment_mismatch() {
+    auto ws1 = makeWorkspace(1);
+    auto ws2 = makeWorkspace(2);
+    TS_ASSERT_THROWS(ws2->mutableDetectorInfo() = ws1->detectorInfo(),
+                     std::runtime_error);
+  }
+
 private:
   WorkspaceTester m_workspace;
   WorkspaceTester m_workspaceNoInstrument;
@@ -301,15 +333,17 @@ private:
     auto ws = Kernel::make_unique<WorkspaceTester>();
     ws->initialize(numSpectra, 1, 1);
     auto inst = boost::make_shared<Instrument>("TestInstrument");
-    ws->setInstrument(inst);
-    auto &pmap = ws->instrumentParameters();
     for (size_t i = 0; i < ws->getNumberHistograms(); ++i) {
       auto det = new Detector("pixel", static_cast<detid_t>(i), inst.get());
       inst->add(det);
       inst->markAsDetector(det);
+    }
+    ws->setInstrument(inst);
+    auto &detInfo = ws->mutableDetectorInfo();
+    for (size_t i = 0; i < ws->getNumberHistograms(); ++i) {
       ws->getSpectrum(i).addDetectorID(static_cast<detid_t>(i));
       if (i % 2 == 0)
-        pmap.addBool(det->getComponentID(), "masked", true);
+        detInfo.setMasked(i, true);
     }
     return std::move(ws);
   }
diff --git a/Framework/API/test/ExperimentInfoTest.h b/Framework/API/test/ExperimentInfoTest.h
index f73f2f5272ebd125546f2d8ee4145c8a2956d27d..4252d0d03787f859b44f4cde485b521d01ecc092 100644
--- a/Framework/API/test/ExperimentInfoTest.h
+++ b/Framework/API/test/ExperimentInfoTest.h
@@ -1,6 +1,7 @@
 #ifndef MANTID_API_EXPERIMENTINFOTEST_H_
 #define MANTID_API_EXPERIMENTINFOTEST_H_
 
+#include "MantidAPI/DetectorInfo.h"
 #include "MantidAPI/ExperimentInfo.h"
 #include "MantidAPI/ChopperModel.h"
 #include "MantidAPI/ModeratorModel.h"
@@ -420,7 +421,7 @@ public:
     TS_ASSERT(det);
 
     // Set a mapping
-    std::vector<Mantid::detid_t> group{1, 2};
+    std::set<Mantid::detid_t> group{1, 2};
     Mantid::det2group_map mapping{{1, group}};
     exptInfo->cacheDetectorGroupings(mapping);
 
@@ -429,6 +430,24 @@ public:
     TS_ASSERT(boost::dynamic_pointer_cast<const DetectorGroup>(det));
   }
 
+  void test_detectorIDsInGroup() {
+    using namespace Mantid;
+    ExperimentInfo_sptr exptInfo(new ExperimentInfo);
+    addInstrumentWithParameter(*exptInfo, "a", "b");
+
+    std::set<detid_t> dets;
+    TS_ASSERT_THROWS_NOTHING(dets = exptInfo->detectorIDsInGroup(0));
+    TS_ASSERT_EQUALS(dets, std::set<detid_t>{1});
+
+    // Set a mapping
+    std::set<detid_t> group{1, 2};
+    Mantid::det2group_map mapping{{1, group}};
+    exptInfo->cacheDetectorGroupings(mapping);
+
+    TS_ASSERT_THROWS_NOTHING(dets = exptInfo->detectorIDsInGroup(0));
+    TS_ASSERT_EQUALS(dets, group);
+  }
+
   void test_Setting_Group_Lookup_To_Empty_Map_Does_Not_Throw() {
     ExperimentInfo expt;
     Mantid::det2group_map mappings;
@@ -446,10 +465,10 @@ public:
   test_Setting_Group_Lookup_To_Non_Empty_Map_Allows_Retrieval_Of_Correct_IDs() {
     ExperimentInfo expt;
     Mantid::det2group_map mappings;
-    mappings.emplace(1, std::vector<Mantid::detid_t>(1, 2));
+    mappings.emplace(1, std::set<Mantid::detid_t>{2});
     expt.cacheDetectorGroupings(mappings);
 
-    std::vector<Mantid::detid_t> ids;
+    std::set<Mantid::detid_t> ids;
     TS_ASSERT_THROWS_NOTHING(ids = expt.getGroupMembers(1));
   }
 
@@ -724,6 +743,32 @@ public:
     TS_ASSERT_EQUALS(eiCastConst, eiCastNonConst);
   }
 
+  void test_getInstrument_setInstrument_copies_masking() {
+    auto inst = ComponentCreationHelper::createTestInstrumentCylindrical(1);
+    ExperimentInfo source;
+    ExperimentInfo target;
+    source.setInstrument(inst);
+    target.setInstrument(inst);
+
+    source.mutableDetectorInfo().setMasked(0, true);
+    TS_ASSERT(!target.detectorInfo().isMasked(0));
+    target.setInstrument(source.getInstrument());
+    TS_ASSERT(target.detectorInfo().isMasked(0));
+  }
+
+  void test_getInstrument_setInstrument_copy_on_write_not_broken() {
+    auto inst = ComponentCreationHelper::createTestInstrumentCylindrical(1);
+    ExperimentInfo source;
+    ExperimentInfo target;
+    source.setInstrument(inst);
+    target.setInstrument(inst);
+
+    TS_ASSERT(!target.detectorInfo().isMasked(0));
+    target.setInstrument(source.getInstrument());
+    source.mutableDetectorInfo().setMasked(0, true);
+    TS_ASSERT(!target.detectorInfo().isMasked(0));
+  }
+
 private:
   void addInstrumentWithParameter(ExperimentInfo &expt, const std::string &name,
                                   const std::string &value) {
diff --git a/Framework/API/test/FileBackedExperimentInfoTest.h b/Framework/API/test/FileBackedExperimentInfoTest.h
index 9a5b1005b1f0d7c0dec64bceb3f01ca22faac82e..042cf416cff4a71d17aeee344cf540cd45a58ccf 100644
--- a/Framework/API/test/FileBackedExperimentInfoTest.h
+++ b/Framework/API/test/FileBackedExperimentInfoTest.h
@@ -117,8 +117,7 @@ public:
   void test_cacheDetectorGroupings() {
     auto fileBacked = createTestObject();
 
-    std::vector<Mantid::detid_t> group(2, 1);
-    group[1] = 2;
+    std::set<Mantid::detid_t> group{1, 2};
     Mantid::det2group_map mapping;
     mapping.emplace(1, group);
     fileBacked->cacheDetectorGroupings(mapping);
@@ -127,8 +126,7 @@ public:
   void test_getGroupMembers() {
     auto fileBacked = createTestObject();
 
-    std::vector<Mantid::detid_t> group(2, 1);
-    group[1] = 2;
+    std::set<Mantid::detid_t> group{1, 2};
     Mantid::det2group_map mapping;
     mapping.emplace(1, group);
     fileBacked->cacheDetectorGroupings(mapping);
@@ -142,6 +140,12 @@ public:
     TS_ASSERT(fileBacked->getDetectorByID(10100));
   }
 
+  void test_detectorIDsInGroup() {
+    auto fileBacked = createTestObject();
+
+    TS_ASSERT_EQUALS(fileBacked->detectorIDsInGroup(0).size(), 1);
+  }
+
   void test_ModeratorModelMethods() {
     auto fileBacked = createTestObject();
     ModeratorModel *source = new FakeSource;
diff --git a/Framework/API/test/FunctionFactoryTest.h b/Framework/API/test/FunctionFactoryTest.h
index cbe95cfe30466c1884ab28f04472acbe5115af2c..83a34d7040d8aa71ebbca7131a9527e74aeaaab0 100644
--- a/Framework/API/test/FunctionFactoryTest.h
+++ b/Framework/API/test/FunctionFactoryTest.h
@@ -379,21 +379,21 @@ public:
     IFunction_sptr fun1 =
         FunctionFactory::Instance().createInitialized(fun->asString());
 
-    fun1->setParameter(0, 0.);
-    fun1->setParameter(1, 0.);
+    fun1->setParameter(0, 1.);
+    fun1->setParameter(1, 2.);
     fun1->setParameter(2, 0.);
     fun1->setParameter(3, 789);
 
-    TS_ASSERT_EQUALS(fun1->getParameter(0), 0.);
-    TS_ASSERT_EQUALS(fun1->getParameter(1), 0.);
+    TS_ASSERT_EQUALS(fun1->getParameter(0), 1.);
+    TS_ASSERT_EQUALS(fun1->getParameter(1), 2.);
     TS_ASSERT_EQUALS(fun1->getParameter(2), 0.);
     TS_ASSERT_EQUALS(fun1->getParameter(3), 789);
 
     fun1->applyTies();
 
-    TS_ASSERT_EQUALS(fun1->getParameter(0), 14.);
-    TS_ASSERT_EQUALS(fun1->getParameter(1), 14.);
-    TS_ASSERT_EQUALS(fun1->getParameter(2), 28.);
+    TS_ASSERT_EQUALS(fun1->getParameter(0), 1.);
+    TS_ASSERT_EQUALS(fun1->getParameter(1), 2.);
+    TS_ASSERT_EQUALS(fun1->getParameter(2), 3.);
     TS_ASSERT_EQUALS(fun1->getParameter(3), 789);
   }
 
@@ -433,9 +433,9 @@ public:
   void test_MultiDomainFunction_creation_moreComplex() {
     const std::string fnString =
         "composite=MultiDomainFunction,NumDeriv=true;(name=FunctionFactoryTest_"
-        "FunctA,a0=0,a1=0.5;name=FunctionFactoryTest_FunctB,b0=0.1,b1=0.2,ties="
+        "FunctA,a0=0,a1=0.5;name=FunctionFactoryTest_FunctB,b0=0.1,ties="
         "(b1=0.2),$domains=i);(name=FunctionFactoryTest_FunctA,a0=0,a1=0.5;"
-        "name=FunctionFactoryTest_FunctB,b0=0.1,b1=0.2,$domains=i);ties=(f1.f1."
+        "name=FunctionFactoryTest_FunctB,b0=0.1,$domains=i);ties=(f1.f1."
         "b1=f0.f1.b1)";
     IFunction_sptr fun;
     TS_ASSERT_THROWS_NOTHING(
diff --git a/Framework/API/test/FunctionParameterDecoratorTest.h b/Framework/API/test/FunctionParameterDecoratorTest.h
index 73bd60384bf53ddebe3595b1ef7c3f52bfbe65a1..c2dfbf2fdcc3903cc4e93d8623c4b9532f933ed5 100644
--- a/Framework/API/test/FunctionParameterDecoratorTest.h
+++ b/Framework/API/test/FunctionParameterDecoratorTest.h
@@ -280,7 +280,8 @@ public:
         getFunctionParameterDecoratorGaussian();
     IFunction_sptr decoratedFunction = fn->getDecoratedFunction();
 
-    ParameterTie *tie = fn->tie("Height", "Height=2.0*Sigma");
+    fn->tie("Height", "Height=2.0*Sigma");
+    ParameterTie *tie = fn->getTie(fn->parameterIndex("Height"));
     TS_ASSERT(tie);
     TS_ASSERT_EQUALS(decoratedFunction->getTie(0), tie);
 
diff --git a/Framework/API/test/FunctionTest.h b/Framework/API/test/FunctionTest.h
index ffb716d2a843a2a35c24e951feb7bb6578bfc542..58c89921caf70680c5b55cda7df1e1cbd0d6a195 100644
--- a/Framework/API/test/FunctionTest.h
+++ b/Framework/API/test/FunctionTest.h
@@ -59,6 +59,7 @@ public:
   }
   const std::string id(void) const override { return ""; }
   void init(const size_t &, const size_t &, const size_t &) override {}
+  void init(const size_t &, const HistogramData::Histogram &) override {}
 
 private:
   std::vector<MocSpectrum> m_spectra;
@@ -255,7 +256,7 @@ public:
     f.setParameter("c3", 1.3);
 
     f.tie("c1", "0");
-    f.tie("c3", "0");
+    f.tie("c3", "c2");
 
     TS_ASSERT_EQUALS(f.nParams(), 4);
 
@@ -276,7 +277,7 @@ public:
     TS_ASSERT(!f.isActive(3));
 
     TS_ASSERT(!f.getTie(0));
-    TS_ASSERT(f.getTie(1) && !f.getTie(1)->isDefault());
+    TS_ASSERT(!f.getTie(1));
     TS_ASSERT(!f.getTie(2));
     TS_ASSERT(f.getTie(3) && !f.getTie(3)->isDefault());
   }
diff --git a/Framework/API/test/GroupingLoaderTest.h b/Framework/API/test/GroupingLoaderTest.h
index c906f15ac912f299a9a062c879865109803521d9..c6aa0e50d51f0eb689f9b89a80fba6d220d48da5 100644
--- a/Framework/API/test/GroupingLoaderTest.h
+++ b/Framework/API/test/GroupingLoaderTest.h
@@ -4,6 +4,7 @@
 #include <cxxtest/TestSuite.h>
 #include <Poco/Path.h>
 #include <Poco/File.h>
+#include "MantidKernel/ConfigService.h"
 #include "MantidAPI/FrameworkManager.h"
 #include "MantidAPI/GroupingLoader.h"
 
@@ -75,4 +76,4 @@ private:
   std::string m_tmpDir;
 };
 
-#endif /* MANTID_API_GROUPINGLOADERTEST_H_ */
\ No newline at end of file
+#endif /* MANTID_API_GROUPINGLOADERTEST_H_ */
diff --git a/Framework/API/test/IMDWorkspaceTest.h b/Framework/API/test/IMDWorkspaceTest.h
index b4b09383e9874df1bceeb4540944b60b55ecd8e3..193a4d1c0ebd979a9b1790a4f8fe69d0dd7a3cf1 100644
--- a/Framework/API/test/IMDWorkspaceTest.h
+++ b/Framework/API/test/IMDWorkspaceTest.h
@@ -32,8 +32,6 @@ public:
   IMDWorkspaceTest() {
     workspace.setTitle("workspace");
     workspace.initialize(2, 4, 3);
-    workspace.getSpectrum(0).setSpectrumNo(1);
-    workspace.getSpectrum(1).setSpectrumNo(2);
     for (int i = 0; i < 4; ++i) {
       workspace.dataX(0)[i] = i;
       workspace.dataX(1)[i] = i + 4;
diff --git a/Framework/API/test/ImmutableCompositeFunctionTest.h b/Framework/API/test/ImmutableCompositeFunctionTest.h
index f00fbbe9c38bce24121eaa298f644f0774cd9931..aa130916b7166c9361a286667c349a0242c67e25 100644
--- a/Framework/API/test/ImmutableCompositeFunctionTest.h
+++ b/Framework/API/test/ImmutableCompositeFunctionTest.h
@@ -268,18 +268,6 @@ public:
     TS_ASSERT_EQUALS(icf.getParameter(3), 2.0);
   }
 
-  // BoundaryConstraint isn't defined (it's in CurveFitting) so this test
-  // doesn't work
-  void xtestConstraints() {
-    ImmutableCompositeFunctionTest_Function icf;
-
-    icf.addConstraints("0 < b1 < 5");
-    TS_ASSERT(!icf.getConstraint(0));
-    TS_ASSERT(!icf.getConstraint(1));
-    TS_ASSERT(icf.getConstraint(2));
-    TS_ASSERT(!icf.getConstraint(3));
-  }
-
   void testAsString() {
     ImmutableCompositeFunctionTest_Function icf;
 
@@ -291,9 +279,10 @@ public:
     icf.addTies("b2=b1,a2=a1/5");
     icf.applyTies();
 
-    TS_ASSERT_EQUALS(icf.asString(), "name=ImmutableCompositeFunctionTest_"
-                                     "Function,NumDeriv=false,a1=11,b1=12,a2=2."
-                                     "2,b2=12,ties=(a2=a1/5,b2=b1)");
+    TS_ASSERT_EQUALS(
+        icf.asString(),
+        "name=ImmutableCompositeFunctionTest_"
+        "Function,NumDeriv=false,a1=11,b1=12,ties=(a2=a1/5,b2=b1)");
 
     auto fun = FunctionFactory::Instance().createInitialized(icf.asString());
     TS_ASSERT(fun);
diff --git a/Framework/API/test/InstrumentValidatorTest.h b/Framework/API/test/InstrumentValidatorTest.h
index 3edaddca83aa70324e9fa179fae8492a85d41f67..7c6704f06dd683bfd3b91983812f1459e8bc0a62 100644
--- a/Framework/API/test/InstrumentValidatorTest.h
+++ b/Framework/API/test/InstrumentValidatorTest.h
@@ -8,6 +8,7 @@
 #include "MantidTestHelpers/FakeObjects.h"
 #include "MantidTestHelpers/ComponentCreationHelper.h"
 
+using namespace Mantid::Kernel;
 using Mantid::API::InstrumentValidator;
 
 class InstrumentValidatorTest : public CxxTest::TestSuite {
@@ -46,4 +47,4 @@ public:
   }
 };
 
-#endif /* MANTID_API_INSTRUMENTVALIDATORTEST_H_ */
\ No newline at end of file
+#endif /* MANTID_API_INSTRUMENTVALIDATORTEST_H_ */
diff --git a/Framework/API/test/LiveListenerFactoryTest.h b/Framework/API/test/LiveListenerFactoryTest.h
index 3c380de8b18a51e3db257ae3d527864101b6bd3b..e4a5facfd6e0deb76b03e882c8266370981bad5a 100644
--- a/Framework/API/test/LiveListenerFactoryTest.h
+++ b/Framework/API/test/LiveListenerFactoryTest.h
@@ -58,11 +58,6 @@ public:
     TS_ASSERT_THROWS_NOTHING(factory.create("MINITOPAZ", false));
   }
 
-  void test_checkConnection() {
-    TS_ASSERT(factory.checkConnection("MockILiveListener"));
-    TS_ASSERT(!factory.checkConnection("MINITOPAZ"))
-  }
-
   void test_createUnwrapped_throws() {
     // Make sure this method just throws.
     // Note that you can't even access the method unless you assign to a
diff --git a/Framework/API/test/LogFilterGeneratorTest.h b/Framework/API/test/LogFilterGeneratorTest.h
new file mode 100644
index 0000000000000000000000000000000000000000..19b0cbcd92707d0c96489f7006ad73f6d809f811
--- /dev/null
+++ b/Framework/API/test/LogFilterGeneratorTest.h
@@ -0,0 +1,191 @@
+#ifndef MANTID_API_LOGFILTERGENERATORTEST_H_
+#define MANTID_API_LOGFILTERGENERATORTEST_H_
+
+#include <cxxtest/TestSuite.h>
+
+#include "MantidAPI/LogFilterGenerator.h"
+#include "MantidAPI/Run.h"
+#include "MantidAPI/WorkspaceFactory.h"
+#include "MantidKernel/DateAndTime.h"
+#include "MantidKernel/make_unique.h"
+#include "MantidKernel/TimeSeriesProperty.h"
+#include "MantidTestHelpers/FakeObjects.h"
+
+#include <numeric>
+
+using Mantid::API::MatrixWorkspace_sptr;
+using Mantid::API::LogFilterGenerator;
+using Mantid::Kernel::DateAndTime;
+using Mantid::Kernel::LogFilter;
+using Mantid::Kernel::TimeSeriesProperty;
+
+class LogFilterGeneratorTest : public CxxTest::TestSuite {
+public:
+  // This pair of boilerplate methods prevent the suite being created statically
+  // This means the constructor isn't called when running other tests
+  static LogFilterGeneratorTest *createSuite() {
+    return new LogFilterGeneratorTest();
+  }
+  static void destroySuite(LogFilterGeneratorTest *suite) { delete suite; }
+
+  void test_logDoesNotExist_throws() {
+    auto ws = createTestWorkspace();
+    LogFilterGenerator generator(LogFilterGenerator::FilterType::Status, ws);
+    TS_ASSERT_THROWS(generator.generateFilter("NonExistentLog"),
+                     std::invalid_argument);
+  }
+
+  void test_logExistsButIsNotNumericTimeSeries_throws() {
+    auto ws = createTestWorkspace();
+    LogFilterGenerator generator(LogFilterGenerator::FilterType::Status, ws);
+    TS_ASSERT_THROWS(generator.generateFilter("BadLog"), std::invalid_argument);
+  }
+
+  void test_typeIsNone_noFilterReturned() {
+    auto ws = createTestWorkspace();
+    LogFilterGenerator generator(LogFilterGenerator::FilterType::None, ws);
+    std::unique_ptr<LogFilter> filter;
+    TS_ASSERT_THROWS_NOTHING(filter = generator.generateFilter("TestLog"));
+    TS_ASSERT(!filter->filter());
+  }
+
+  void test_typeIsStatus_noRunningLogPresent_thenNoFilterReturned() {
+    auto ws = createTestWorkspace(false, false, false);
+    LogFilterGenerator generator(LogFilterGenerator::FilterType::Status, ws);
+    std::unique_ptr<LogFilter> filter;
+    TS_ASSERT_THROWS_NOTHING(filter = generator.generateFilter("TestLog"));
+    TS_ASSERT(!filter->filter());
+  }
+
+  void test_typeIsStatus() {
+    auto ws = createTestWorkspace();
+    LogFilterGenerator generator(LogFilterGenerator::FilterType::Status, ws);
+    std::unique_ptr<LogFilter> filter;
+    TS_ASSERT_THROWS_NOTHING(filter = generator.generateFilter("TestLog"));
+    TS_ASSERT(filter->filter());
+    const auto &resultMap = filter->filter()->valueAsCorrectMap();
+    std::map<DateAndTime, bool> expected;
+    expected.emplace(DateAndTime("2007-11-30T16:17:00"), true);
+    expected.emplace(DateAndTime("2007-11-30T16:17:30"), false);
+    expected.emplace(DateAndTime("2007-11-30T16:18:00"), true);
+    TS_ASSERT_EQUALS(resultMap.size(), 3);
+    TS_ASSERT_EQUALS(resultMap, expected);
+  }
+
+  void test_typeIsPeriod_noPeriodLogPresent_thenNoFilterReturned() {
+    auto ws = createTestWorkspace(true, false, false);
+    LogFilterGenerator generator(LogFilterGenerator::FilterType::Period, ws);
+    std::unique_ptr<LogFilter> filter;
+    TS_ASSERT_THROWS_NOTHING(filter = generator.generateFilter("TestLog"));
+    TS_ASSERT(!filter->filter());
+  }
+
+  void test_typeIsPeriod() {
+    auto ws = createTestWorkspace();
+    LogFilterGenerator generator(LogFilterGenerator::FilterType::Period, ws);
+    std::unique_ptr<LogFilter> filter;
+    TS_ASSERT_THROWS_NOTHING(filter = generator.generateFilter("TestLog"));
+    TS_ASSERT(filter->filter());
+    const auto &values = filter->filter()->valueAsCorrectMap();
+    TS_ASSERT(!values.empty());
+    std::map<DateAndTime, bool> expected;
+    expected.emplace(DateAndTime("2007-11-30T16:18:20"), true);
+    expected.emplace(DateAndTime("2007-11-30T16:18:50"), false);
+    TS_ASSERT_EQUALS(expected, values);
+  }
+
+  void test_typeIsStatusAndPeriod() {
+    auto ws = createTestWorkspace();
+    LogFilterGenerator generator(
+        LogFilterGenerator::FilterType::StatusAndPeriod, ws);
+    std::unique_ptr<LogFilter> filter;
+    TS_ASSERT_THROWS_NOTHING(filter = generator.generateFilter("TestLog"));
+    TS_ASSERT(filter->filter());
+    const auto &values = filter->filter()->valueAsCorrectMap();
+    TS_ASSERT(!values.empty());
+    std::map<DateAndTime, bool> expected;
+    // This is an "intersection" (&&):
+    //   Time    Status   Period   Result
+    // 16:17:00    T        F        F
+    // 16:17:30    F        F        F
+    // 16:18:00    T        F        F
+    // 16:18:20    T        T        T
+    // 16:18:50    T        F        F
+    expected.emplace(DateAndTime("2007-11-30T16:17:00"), false);
+    expected.emplace(DateAndTime("2007-11-30T16:17:30"), false);
+    expected.emplace(DateAndTime("2007-11-30T16:18:00"), false);
+    expected.emplace(DateAndTime("2007-11-30T16:18:20"), true);
+    expected.emplace(DateAndTime("2007-11-30T16:18:50"), false);
+    TS_ASSERT_EQUALS(expected, values);
+  }
+
+private:
+  /**
+   * Generate a test workspace.
+   * @param hasStatusLog :: [input] Whether to include a "running" log
+   * @param hasPeriodLog :: [input] Whether to include a "period 1" log
+   * @param hasBadLog :: [input] Whether to include a log that is not a numeric
+   * TSP
+   * @returns :: Test workspace with required logs
+   */
+  MatrixWorkspace_sptr createTestWorkspace(bool hasStatusLog = true,
+                                           bool hasPeriodLog = true,
+                                           bool hasBadLog = true) {
+    MatrixWorkspace_sptr ws = boost::make_shared<WorkspaceTester>();
+    const std::vector<double> xData{0.0, 1.0}, yCounts{25.0}, errors{5.0};
+    ws->initialize(1, xData.size(), yCounts.size());
+    ws->setBinEdges(0, xData);
+    ws->setCounts(0, yCounts);
+    ws->setCountStandardDeviations(0, errors);
+
+    // Create the log to be filtered
+    auto log =
+        Mantid::Kernel::make_unique<TimeSeriesProperty<double>>("TestLog");
+    constexpr size_t logSize(12);
+    const DateAndTime initialTime("2007-11-30T16:17:00");
+    std::vector<DateAndTime> times;
+    std::vector<double> values;
+    times.reserve(logSize);
+    values.reserve(logSize);
+    constexpr double incrementSecs(10.0);
+    for (size_t i = 0; i < logSize; ++i) {
+      const double val = static_cast<double>(i);
+      times.push_back(initialTime + val * incrementSecs);
+      values.push_back(val);
+    }
+    log->addValues(times, values);
+    ws->mutableRun().addLogData(std::move(log));
+
+    // Status ("running") log
+    if (hasStatusLog) {
+      auto status =
+          Mantid::Kernel::make_unique<TimeSeriesProperty<bool>>("running");
+      status->addValue(initialTime, true);
+      status->addValue(initialTime + 30.0, false);
+      status->addValue(initialTime + 60.0, true);
+      ws->mutableRun().addLogData(std::move(status));
+    }
+
+    // Period log
+    if (hasPeriodLog) {
+      auto period =
+          Mantid::Kernel::make_unique<TimeSeriesProperty<bool>>("period 1");
+      period->addValue(initialTime + 80.0, true);
+      period->addValue(initialTime + 110.0, false);
+      ws->mutableRun().addLogData(std::move(period));
+    }
+
+    // Log that isn't a numeric TSP
+    if (hasBadLog) {
+      auto bad = Mantid::Kernel::make_unique<TimeSeriesProperty<std::string>>(
+          "BadLog");
+      bad->addValue(initialTime + 15.0, "hello");
+      bad->addValue(initialTime + 45.0, "string");
+      ws->mutableRun().addLogData(std::move(bad));
+    }
+
+    return ws;
+  }
+};
+
+#endif /* MANTID_API_LOGFILTERGENERATORTEST_H_ */
diff --git a/Framework/API/test/MDGeometryTest.h b/Framework/API/test/MDGeometryTest.h
index 11be178625bb6d6a3b3dd45ce2e17eb728182610..46d2189176b2b5bbc52f5ee93eb45c10850bfc38 100644
--- a/Framework/API/test/MDGeometryTest.h
+++ b/Framework/API/test/MDGeometryTest.h
@@ -1,6 +1,7 @@
 #ifndef MANTID_API_MDGEOMETRYTEST_H_
 #define MANTID_API_MDGEOMETRYTEST_H_
 
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/MDGeometry.h"
 #include "MantidGeometry/MDGeometry/MDHistoDimension.h"
 #include "MantidKernel/System.h"
diff --git a/Framework/API/test/MatrixWorkspaceMDIteratorTest.h b/Framework/API/test/MatrixWorkspaceMDIteratorTest.h
index 529f977705a839f4f05b73b8ed14446e989dcd57..0674d7e6dc24a8fc002bfb68ec130ddbe7a8fc03 100644
--- a/Framework/API/test/MatrixWorkspaceMDIteratorTest.h
+++ b/Framework/API/test/MatrixWorkspaceMDIteratorTest.h
@@ -2,6 +2,7 @@
 #define MANTID_API_MATRIXWORKSPACEMDITERATORTEST_H_
 
 #include "MantidAPI/MatrixWorkspaceMDIterator.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidGeometry/Instrument.h"
 #include "MantidGeometry/Instrument/Detector.h"
 #include "MantidTestHelpers/FakeObjects.h"
@@ -32,7 +33,6 @@ public:
       }
     }
     Instrument_sptr inst(new Instrument("TestInstrument"));
-    ws->setInstrument(inst);
     // We get a 1:1 map by default so the detector ID should match the spectrum
     // number
     for (size_t i = 0; i < ws->getNumberHistograms(); ++i) {
@@ -43,6 +43,7 @@ public:
       inst->markAsDetector(det);
       ws->getSpectrum(i).addDetectorID(static_cast<detid_t>(i));
     }
+    ws->setInstrument(inst);
     ws->replaceAxis(1, ax1);
 
     return ws;
@@ -120,9 +121,9 @@ public:
   void test_get_is_masked() {
     boost::shared_ptr<MatrixWorkspace> ws = makeFakeWS();
     IMDIterator *it = ws->createIterator(NULL);
+    const auto &spectrumInfo = ws->spectrumInfo();
     for (size_t i = 0; i < ws->getNumberHistograms(); ++i) {
-      Mantid::Geometry::IDetector_const_sptr det = ws->getDetector(i);
-      TS_ASSERT_EQUALS(det->isMasked(), it->getIsMasked());
+      TS_ASSERT_EQUALS(spectrumInfo.isMasked(i), it->getIsMasked());
       it->next();
     }
     delete it;
diff --git a/Framework/API/test/MatrixWorkspaceTest.h b/Framework/API/test/MatrixWorkspaceTest.h
index 2700b470276ace129d6914aa90d177b5a6a4523a..97d0ceaf3b2354580a4e2e4d93562b865f8e40d1 100644
--- a/Framework/API/test/MatrixWorkspaceTest.h
+++ b/Framework/API/test/MatrixWorkspaceTest.h
@@ -15,6 +15,7 @@
 #include "MantidKernel/make_cow.h"
 #include "MantidKernel/TimeSeriesProperty.h"
 #include "MantidKernel/VMD.h"
+#include "MantidIndexing/IndexInfo.h"
 #include "MantidTestHelpers/FakeObjects.h"
 #include "MantidTestHelpers/InstrumentCreationHelper.h"
 #include "MantidTestHelpers/ComponentCreationHelper.h"
@@ -35,6 +36,7 @@ using std::size_t;
 using namespace Mantid::Kernel;
 using namespace Mantid::API;
 using namespace Mantid::Geometry;
+using Mantid::Indexing::IndexInfo;
 
 // Declare into the factory.
 DECLARE_WORKSPACE(WorkspaceTester)
@@ -51,7 +53,6 @@ boost::shared_ptr<MatrixWorkspace> makeWorkspaceWithDetectors(size_t numSpectra,
   ws2->initialize(numSpectra, numBins, numBins);
 
   auto inst = boost::make_shared<Instrument>("TestInstrument");
-  ws2->setInstrument(inst);
   // We get a 1:1 map by default so the detector ID should match the spectrum
   // number
   for (size_t i = 0; i < ws2->getNumberHistograms(); ++i) {
@@ -61,6 +62,7 @@ boost::shared_ptr<MatrixWorkspace> makeWorkspaceWithDetectors(size_t numSpectra,
     inst->markAsDetector(det);
     ws2->getSpectrum(i).addDetectorID(static_cast<detid_t>(i));
   }
+  ws2->setInstrument(inst);
   return ws2;
 }
 
@@ -77,6 +79,98 @@ public:
     ws->initialize(1, 1, 1);
   }
 
+  void test_set_bad_IndexInfo() {
+    WorkspaceTester ws;
+    ws.initialize(3, 1, 1);
+    IndexInfo bad(2);
+    TS_ASSERT_THROWS(ws.setIndexInfo(std::move(bad)), std::runtime_error);
+  }
+
+  void test_IndexInfo() {
+    WorkspaceTester ws;
+    ws.initialize(3, 1, 1);
+    const auto &indexInfo = ws.indexInfo();
+
+    IndexInfo indices(3);
+    indices.setSpectrumNumbers({2, 4, 6});
+    indices.setDetectorIDs({{0}, {1}, {2, 3}});
+    TS_ASSERT_THROWS_NOTHING(ws.setIndexInfo(std::move(indices)));
+
+    TS_ASSERT_EQUALS(indexInfo.spectrumNumber(0), 2);
+    TS_ASSERT_EQUALS(indexInfo.spectrumNumber(1), 4);
+    TS_ASSERT_EQUALS(indexInfo.spectrumNumber(2), 6);
+    TS_ASSERT_EQUALS(indexInfo.detectorIDs(0), (std::vector<detid_t>{0}));
+    TS_ASSERT_EQUALS(indexInfo.detectorIDs(1), (std::vector<detid_t>{1}));
+    TS_ASSERT_EQUALS(indexInfo.detectorIDs(2), (std::vector<detid_t>{2, 3}));
+  }
+
+  void test_setIndexInfo() {
+    // NOTE: This test checks if the IndexInfo set via
+    // MatrixWorkspace::setIndexInfo() affects data stored in ISpectrum and
+    // obtained via the legacy interface. THIS TEST SHOULD BE REMOVED ONCE THAT
+    // INTERFACE IS BEING REMOVED.
+    WorkspaceTester ws;
+    ws.initialize(3, 1, 1);
+    IndexInfo indices(3);
+    indices.setSpectrumNumbers({2, 4, 6});
+    indices.setDetectorIDs({{0}, {1}, {2, 3}});
+    TS_ASSERT_THROWS_NOTHING(ws.setIndexInfo(std::move(indices)));
+    TS_ASSERT_EQUALS(ws.getSpectrum(0).getSpectrumNo(), 2);
+    TS_ASSERT_EQUALS(ws.getSpectrum(1).getSpectrumNo(), 4);
+    TS_ASSERT_EQUALS(ws.getSpectrum(2).getSpectrumNo(), 6);
+    TS_ASSERT_EQUALS(ws.getSpectrum(0).getDetectorIDs(),
+                     (std::set<detid_t>{0}));
+    TS_ASSERT_EQUALS(ws.getSpectrum(1).getDetectorIDs(),
+                     (std::set<detid_t>{1}));
+    TS_ASSERT_EQUALS(ws.getSpectrum(2).getDetectorIDs(),
+                     (std::set<detid_t>{2, 3}));
+  }
+
+  void test_indexInfo_legacy_compatibility() {
+    // NOTE: This test checks if the IndexInfo reference returned by
+    // MatrixWorkspace::indexInfo() reflects changes done via the legacy
+    // interface of ISpectrum. THIS TEST SHOULD BE REMOVED ONCE THAT INTERFACE
+    // IS BEING REMOVED.
+    WorkspaceTester ws;
+    ws.initialize(1, 1, 1);
+    const auto &indexInfo = ws.indexInfo();
+    TS_ASSERT_EQUALS(indexInfo.spectrumNumber(0), 1);
+    TS_ASSERT_EQUALS(indexInfo.detectorIDs(0), std::vector<detid_t>({0}));
+    ws.getSpectrum(0).setSpectrumNo(7);
+    ws.getSpectrum(0).addDetectorID(7);
+    TS_ASSERT_EQUALS(indexInfo.spectrumNumber(0), 7);
+    TS_ASSERT_EQUALS(indexInfo.detectorIDs(0), std::vector<detid_t>({0, 7}));
+  }
+
+  void test_IndexInfo_copy() {
+    WorkspaceTester ws;
+    ws.initialize(3, 1, 1);
+    IndexInfo indices(3);
+    indices.setSpectrumNumbers({2, 4, 6});
+    indices.setDetectorIDs({{0}, {1}, {2, 3}});
+    ws.setIndexInfo(std::move(indices));
+
+    // Internally this references data in ISpectrum
+    const auto &indexInfo = ws.indexInfo();
+    // This should create a copy, dropping any links to MatrixWorkspace or
+    // ISpectrum
+    const auto copy(indexInfo);
+
+    TS_ASSERT_EQUALS(copy.spectrumNumber(0), 2);
+    TS_ASSERT_EQUALS(copy.spectrumNumber(1), 4);
+    TS_ASSERT_EQUALS(copy.spectrumNumber(2), 6);
+    TS_ASSERT_EQUALS(copy.detectorIDs(0), (std::vector<detid_t>{0}));
+    TS_ASSERT_EQUALS(copy.detectorIDs(1), (std::vector<detid_t>{1}));
+    TS_ASSERT_EQUALS(copy.detectorIDs(2), (std::vector<detid_t>{2, 3}));
+    // Changing data in workspace affects indexInfo, but not copy
+    ws.getSpectrum(0).setSpectrumNo(7);
+    ws.getSpectrum(0).addDetectorID(7);
+    TS_ASSERT_EQUALS(indexInfo.spectrumNumber(0), 7);
+    TS_ASSERT_EQUALS(indexInfo.detectorIDs(0), (std::vector<detid_t>{0, 7}));
+    TS_ASSERT_EQUALS(copy.spectrumNumber(0), 2);
+    TS_ASSERT_EQUALS(copy.detectorIDs(0), (std::vector<detid_t>{0}));
+  }
+
   void test_toString_Produces_Expected_Contents() {
     auto testWS = boost::make_shared<WorkspaceTester>();
     testWS->initialize(1, 2, 1);
@@ -249,23 +343,21 @@ public:
         makeWorkspaceWithDetectors(3, 1));
 
     // Initially un masked
+    const auto &spectrumInfo = workspace->spectrumInfo();
     for (int i = 0; i < numHist; ++i) {
       TS_ASSERT_EQUALS(workspace->readY(i)[0], 1.0);
       TS_ASSERT_EQUALS(workspace->readE(i)[0], 1.0);
-
-      IDetector_const_sptr det;
-      TS_ASSERT_THROWS_NOTHING(det = workspace->getDetector(i));
-      if (det) {
-        TS_ASSERT_EQUALS(det->isMasked(), false);
-      } else {
-        TS_FAIL("No detector defined");
-      }
+      TS_ASSERT(spectrumInfo.hasDetectors(i));
+      TS_ASSERT_EQUALS(spectrumInfo.isMasked(i), false);
     }
 
     // Mask a spectra
-    workspace->maskWorkspaceIndex(1);
-    workspace->maskWorkspaceIndex(2);
+    workspace->getSpectrum(1).clearData();
+    workspace->getSpectrum(2).clearData();
+    workspace->mutableSpectrumInfo().setMasked(1, true);
+    workspace->mutableSpectrumInfo().setMasked(2, true);
 
+    const auto &spectrumInfo2 = workspace->spectrumInfo();
     for (int i = 0; i < numHist; ++i) {
       double expectedValue(0.0);
       bool expectedMasked(false);
@@ -277,14 +369,8 @@ public:
       }
       TS_ASSERT_EQUALS(workspace->readY(i)[0], expectedValue);
       TS_ASSERT_EQUALS(workspace->readE(i)[0], expectedValue);
-
-      IDetector_const_sptr det;
-      TS_ASSERT_THROWS_NOTHING(det = workspace->getDetector(i));
-      if (det) {
-        TS_ASSERT_EQUALS(det->isMasked(), expectedMasked);
-      } else {
-        TS_FAIL("No detector defined");
-      }
+      TS_ASSERT(spectrumInfo2.hasDetectors(i));
+      TS_ASSERT_EQUALS(spectrumInfo2.isMasked(i), expectedMasked);
     }
   }
 
@@ -292,8 +378,10 @@ public:
     // Workspace has 3 spectra, each 1 in length
     const int numHist(3);
     auto workspace = makeWorkspaceWithDetectors(numHist, 1);
-    workspace->maskWorkspaceIndex(1);
-    workspace->maskWorkspaceIndex(2);
+    workspace->getSpectrum(1).clearData();
+    workspace->getSpectrum(2).clearData();
+    workspace->mutableSpectrumInfo().setMasked(1, true);
+    workspace->mutableSpectrumInfo().setMasked(2, true);
 
     const auto &spectrumInfo = workspace->spectrumInfo();
     for (int i = 0; i < numHist; ++i) {
@@ -523,55 +611,6 @@ public:
     TS_ASSERT_THROWS_NOTHING(ws->saveSpectraMapNexus(th.file, spec););
   }
 
-  /** Properly, this tests a method on Instrument, not MatrixWorkspace, but they
-   * are related.
-   */
-  void test_isDetectorMasked() {
-    auto ws = makeWorkspaceWithDetectors(100, 10);
-    Instrument_const_sptr inst = ws->getInstrument();
-    // Make sure the instrument is parametrized so that the test is thorough
-    TS_ASSERT(inst->isParametrized());
-    TS_ASSERT(!inst->isDetectorMasked(1));
-    TS_ASSERT(!inst->isDetectorMasked(19));
-    // Mask then check that it returns as masked
-    TS_ASSERT(ws->getSpectrum(19).hasDetectorID(19));
-    ws->maskWorkspaceIndex(19);
-    TS_ASSERT(inst->isDetectorMasked(19));
-  }
-
-  /** Check if any of a list of detectors are masked */
-  void test_isDetectorMasked_onASet() {
-    auto ws = makeWorkspaceWithDetectors(100, 10);
-    Instrument_const_sptr inst = ws->getInstrument();
-    // Make sure the instrument is parametrized so that the test is thorough
-    TS_ASSERT(inst->isParametrized());
-
-    // Mask detector IDs 8 and 9
-    ws->maskWorkspaceIndex(8);
-    ws->maskWorkspaceIndex(9);
-
-    std::set<detid_t> dets;
-    TSM_ASSERT("No detector IDs = not masked", !inst->isDetectorMasked(dets));
-    dets.insert(6);
-    TSM_ASSERT("Detector is not masked", !inst->isDetectorMasked(dets));
-    dets.insert(7);
-    TSM_ASSERT("Detectors are not masked", !inst->isDetectorMasked(dets));
-    dets.insert(8);
-    TSM_ASSERT("If any detector is not masked, return false",
-               !inst->isDetectorMasked(dets));
-    // Start again
-    dets.clear();
-    dets.insert(8);
-    TSM_ASSERT("If all detectors are not masked, return true",
-               inst->isDetectorMasked(dets));
-    dets.insert(9);
-    TSM_ASSERT("If all detectors are not masked, return true",
-               inst->isDetectorMasked(dets));
-    dets.insert(10);
-    TSM_ASSERT("If any detector is not masked, return false",
-               !inst->isDetectorMasked(dets));
-  }
-
   void test_hasGroupedDetectors() {
     auto ws = makeWorkspaceWithDetectors(5, 1);
     TS_ASSERT_EQUALS(ws->hasGroupedDetectors(), false);
@@ -628,7 +667,6 @@ public:
     // the detector ID
     // is stored in at least 3 places
     auto inst = boost::make_shared<Instrument>("TestInstrument");
-    ws->setInstrument(inst);
     // We get a 1:1 map by default so the detector ID should match the spectrum
     // number
     for (size_t i = 0; i < ws->getNumberHistograms(); ++i) {
@@ -643,6 +681,7 @@ public:
       inst->markAsDetector(det);
       ws->getSpectrum(i).addDetectorID(detid);
     }
+    ws->setInstrument(inst);
     ws->getSpectrum(66).clearDetectorIDs();
 
     TS_ASSERT_THROWS_NOTHING(
diff --git a/Framework/API/test/MultiDomainFunctionTest.h b/Framework/API/test/MultiDomainFunctionTest.h
index e43d41070fc5a3e79b5158491c6fb2126415a349..9990cdaec30357bb3e0425c611d73c20f9011f88 100644
--- a/Framework/API/test/MultiDomainFunctionTest.h
+++ b/Framework/API/test/MultiDomainFunctionTest.h
@@ -444,8 +444,8 @@ public:
     const std::string expected =
         "composite=MultiDomainFunction,NumDeriv=true;"
         "name=MultiDomainFunctionTest_Function,A=0,B=1,$domains=i;"
-        "name=MultiDomainFunctionTest_Function,A=0,B=2,$domains=i;"
-        "name=MultiDomainFunctionTest_Function,A=0,B=3,$domains=i;ties=(f1.A="
+        "name=MultiDomainFunctionTest_Function,B=2,$domains=i;"
+        "name=MultiDomainFunctionTest_Function,B=3,$domains=i;ties=(f1.A="
         "f0.A,f2.A=f0.A)";
     TS_ASSERT_EQUALS(multi.asString(), expected);
     TS_ASSERT_EQUALS(multi.asString(), multi.clone()->asString());
diff --git a/Framework/API/test/NearestNeighbourInfoTest.h b/Framework/API/test/NearestNeighbourInfoTest.h
index b53ca21b5e256e3bc255f4a5e39224655ab6191b..f8fa58c3e4d72ae8275216a845528f2a378fe4d9 100644
--- a/Framework/API/test/NearestNeighbourInfoTest.h
+++ b/Framework/API/test/NearestNeighbourInfoTest.h
@@ -6,6 +6,7 @@
 #include "MantidTestHelpers/FakeObjects.h"
 #include "MantidTestHelpers/InstrumentCreationHelper.h"
 #include "MantidAPI/NearestNeighbourInfo.h"
+#include "MantidAPI/SpectrumInfo.h"
 
 using Mantid::API::NearestNeighbourInfo;
 
@@ -23,7 +24,8 @@ public:
     InstrumentCreationHelper::addFullInstrumentToWorkspace(workspace, false,
                                                            false, "");
     workspace.rebuildSpectraMapping();
-    workspace.maskWorkspaceIndex(0);
+    workspace.getSpectrum(0).clearData();
+    workspace.mutableSpectrumInfo().setMasked(0, true);
   }
 
   void test_construct() {
diff --git a/Framework/Geometry/test/NearestNeighboursTest.h b/Framework/API/test/NearestNeighboursTest.h
similarity index 55%
rename from Framework/Geometry/test/NearestNeighboursTest.h
rename to Framework/API/test/NearestNeighboursTest.h
index a5609c0933186f6c67b8752e0a388b674fc42a27..0369aaacabbf069c5fff98582b8e0df241163e7e 100644
--- a/Framework/Geometry/test/NearestNeighboursTest.h
+++ b/Framework/API/test/NearestNeighboursTest.h
@@ -1,71 +1,78 @@
 #ifndef MANTID_TEST_GEOMETRY_NEARESTNEIGHBOURS
 #define MANTID_TEST_GEOMETRY_NEARESTNEIGHBOURS
 
+#include "MantidAPI/NearestNeighbours.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidGeometry/IDetector.h"
 #include "MantidGeometry/Instrument/Detector.h"
 #include "MantidGeometry/Instrument.h"
-#include "MantidGeometry/Instrument/NearestNeighbours.h"
 #include "MantidGeometry/Instrument/ParameterMap.h"
 #include "MantidGeometry/Instrument/RectangularDetector.h"
 #include "MantidGeometry/Objects/BoundingBox.h"
 #include "MantidTestHelpers/ComponentCreationHelper.h"
+#include "MantidTestHelpers/FakeObjects.h"
 #include <cxxtest/TestSuite.h>
 #include <map>
 
 using namespace Mantid;
 using namespace Mantid::Geometry;
+using namespace Mantid::API;
 using Mantid::Kernel::V3D;
 
 /**
 * Everything must be in one test or the instrument/detector list goes AWOL.
 */
 
+namespace {
+boost::shared_ptr<MatrixWorkspace> makeWorkspace(const specnum_t start,
+                                                 const specnum_t end) {
+  auto ws = boost::make_shared<WorkspaceTester>();
+  ws->initialize(end - start + 1, 2, 1);
+  for (specnum_t i = start; i <= end; ++i) {
+    ws->getSpectrum(i - start).setSpectrumNo(i);
+    ws->getSpectrum(i - start).setDetectorID(i);
+  }
+  return ws;
+}
+
+std::vector<specnum_t> getSpectrumNumbers(const MatrixWorkspace &workspace) {
+  std::vector<specnum_t> spectrumNumbers;
+  for (size_t i = 0; i < workspace.getNumberHistograms(); ++i)
+    spectrumNumbers.push_back(workspace.getSpectrum(i).getSpectrumNo());
+  return spectrumNumbers;
+}
+}
+
 //=====================================================================================
 // Functional tests
 //=====================================================================================
 class NearestNeighboursTest : public CxxTest::TestSuite {
-public:
-  static ISpectrumDetectorMapping
-  buildSpectrumDetectorMapping(const specnum_t start, const specnum_t end) {
-    std::unordered_map<specnum_t, std::set<detid_t>> map;
-    for (specnum_t i = start; i <= end; ++i) {
-      map[i].insert(i);
-    }
-    return map;
-  }
-
 private:
   /// Helper type giving access to protected methods. Makes testing of NN
   /// internals possible.
-  class ExposedNearestNeighbours : public Mantid::Geometry::NearestNeighbours {
+  class ExposedNearestNeighbours : public Mantid::API::NearestNeighbours {
   public:
-    ExposedNearestNeighbours(boost::shared_ptr<const Instrument> instrument,
-                             const ISpectrumDetectorMapping &spectraMap,
+    ExposedNearestNeighbours(const SpectrumInfo &spectrumInfo,
+                             const std::vector<specnum_t> spectrumNumbers,
                              bool ignoreMasked = false)
-        : NearestNeighbours(instrument, spectraMap, ignoreMasked) {}
+        : NearestNeighbours(8, spectrumInfo, spectrumNumbers, ignoreMasked) {}
 
     // Direct access to intermdiate spectra detectors
-    std::map<specnum_t, IDetector_const_sptr> getSpectraDetectors() {
-      return NearestNeighbours::getSpectraDetectors(m_instrument, m_spectraMap);
+    std::vector<size_t> getSpectraDetectors() {
+      return NearestNeighbours::getSpectraDetectors();
     }
   };
 
 public:
   void doTestWithNeighbourNumbers(int actualNeighboursNumber,
                                   int expectedNeighboursNumber) {
-    // Create Instrument and make it Parameterised
-    Instrument_sptr instrument = boost::dynamic_pointer_cast<Instrument>(
+    const auto ws = makeWorkspace(1, 18);
+    ws->setInstrument(
         ComponentCreationHelper::createTestInstrumentCylindrical(2));
-    const ISpectrumDetectorMapping spectramap =
-        buildSpectrumDetectorMapping(1, 18);
-    TS_ASSERT_EQUALS(spectramap.size(), 18);
-    // Default parameter map.
-    ParameterMap_sptr pmap(new ParameterMap());
-    // Parameterized instrument
-    Instrument_sptr m_instrument(new Instrument(instrument, pmap));
 
     // Create the NearestNeighbours object directly.
-    NearestNeighbours nn(actualNeighboursNumber, m_instrument, spectramap);
+    NearestNeighbours nn(actualNeighboursNumber, ws->spectrumInfo(),
+                         getSpectrumNumbers(*ws));
 
     // Check distances calculated in NearestNeighbours compare with those using
     // getDistance on component
@@ -76,22 +83,15 @@ public:
   }
 
   void testNeighbourFindingWithRadius() {
-    // Create Instrument and make it Parameterised
-    Instrument_sptr instrument = boost::dynamic_pointer_cast<Instrument>(
+    const auto ws = makeWorkspace(1, 18);
+    ws->setInstrument(
         ComponentCreationHelper::createTestInstrumentCylindrical(2));
-    const ISpectrumDetectorMapping spectramap =
-        buildSpectrumDetectorMapping(1, 18);
-    TS_ASSERT_EQUALS(spectramap.size(), 18);
-    // Default parameter map.
-    ParameterMap_sptr pmap(new ParameterMap());
-    // Parameterized instrument
-    Instrument_sptr m_instrument(new Instrument(instrument, pmap));
 
     // Create the NearestNeighbours object directly.
-    NearestNeighbours nn(m_instrument, spectramap);
+    NearestNeighbours nn(8, ws->spectrumInfo(), getSpectrumNumbers(*ws));
 
     detid2det_map m_detectors;
-    m_instrument->getDetectors(m_detectors);
+    ws->getInstrument()->getDetectors(m_detectors);
 
     // Need scaling vector since changes to NN ( 22/12/10 )
     Mantid::Geometry::BoundingBox bbox = Mantid::Geometry::BoundingBox();
@@ -102,8 +102,6 @@ public:
               (bbox.zMax() - bbox.zMin()));
 
     // Check instrument was created to our expectations
-    ParameterMap_sptr p_map;
-    TS_ASSERT_THROWS_NOTHING(p_map = m_instrument->getParameterMap());
     TS_ASSERT_EQUALS(m_detectors.size(), 18);
 
     // Check distances calculated in NearestNeighbours compare with those using
@@ -140,21 +138,15 @@ public:
 
   // Let's try it with a rectangular detector.
   void testNeighbours_RectangularDetector() {
+    const auto ws = makeWorkspace(256, 767);
     // 2 Rectangular detectors, 16x16
-    Instrument_sptr instrument = boost::dynamic_pointer_cast<Instrument>(
+    ws->setInstrument(
         ComponentCreationHelper::createTestInstrumentRectangular(2, 16));
 
-    // Test fails without a parameter map.
-    const ISpectrumDetectorMapping spectramap =
-        buildSpectrumDetectorMapping(256, 767);
-    // Default parameter map.
-    ParameterMap_sptr pmap(new ParameterMap());
-    // Parameterized instrument
-    Instrument_sptr m_instrument(new Instrument(instrument, pmap));
-
     // Create the NearestNeighbours object directly.
-    NearestNeighbours nn(m_instrument, spectramap);
+    NearestNeighbours nn(8, ws->spectrumInfo(), getSpectrumNumbers(*ws));
 
+    const auto &m_instrument = ws->getInstrument();
     // Correct # of detectors
     TS_ASSERT_EQUALS(m_instrument->getDetectorIDs().size(), 512);
 
@@ -177,34 +169,21 @@ public:
   }
 
   void testIgnoreAndApplyMasking() {
-    Instrument_sptr instrument = boost::dynamic_pointer_cast<Instrument>(
+    const auto ws = makeWorkspace(1, 18);
+    ws->setInstrument(
         ComponentCreationHelper::createTestInstrumentCylindrical(2));
-    const ISpectrumDetectorMapping spectramap =
-        buildSpectrumDetectorMapping(1, 18);
-
-    // Default parameter map.
-    ParameterMap_sptr pmap(new ParameterMap());
-
-    // Mask the first 5 detectors
-    for (Mantid::specnum_t i = 1; i < 3; i++) {
-      if (const Geometry::ComponentID det =
-              instrument->getDetector(*spectramap.at(i).begin())
-                  ->getComponentID()) {
-        pmap->addBool(det, "masked", true);
-      }
-    }
 
-    // Parameterized instrument
-    Instrument_sptr m_instrument(new Instrument(instrument, pmap));
-
-    IDetector_const_sptr det =
-        m_instrument->getDetector(*spectramap.at(1).begin());
+    // Mask the first 2 detectors
+    auto &spectrumInfo = ws->mutableSpectrumInfo();
+    spectrumInfo.setMasked(0, true);
+    spectrumInfo.setMasked(1, true);
 
     // Create the NearestNeighbours object directly. Ignore any masking.
-    ExposedNearestNeighbours ignoreMaskedNN(m_instrument, spectramap, true);
+    ExposedNearestNeighbours ignoreMaskedNN(ws->spectrumInfo(),
+                                            getSpectrumNumbers(*ws), true);
     // Create the NearestNeighbours object directly. Account for any masking.
-    ExposedNearestNeighbours accountForMaskedNN(m_instrument, spectramap,
-                                                false);
+    ExposedNearestNeighbours accountForMaskedNN(ws->spectrumInfo(),
+                                                getSpectrumNumbers(*ws), false);
 
     size_t sizeWithoutMasked = ignoreMaskedNN.getSpectraDetectors().size();
     size_t sizeWithMasked = accountForMaskedNN.getSpectraDetectors().size();
@@ -225,52 +204,27 @@ class NearestNeighboursTestPerformance : public CxxTest::TestSuite {
 
 public:
   void testUsingRadius() {
-    Instrument_sptr instrument = boost::dynamic_pointer_cast<Instrument>(
+    const auto ws = makeWorkspace(1, 18);
+    ws->setInstrument(
         ComponentCreationHelper::createTestInstrumentCylindrical(2));
-    const ISpectrumDetectorMapping spectramap =
-        NearestNeighboursTest::buildSpectrumDetectorMapping(1, 18);
-    // Default parameter map.
-    ParameterMap_sptr pmap(new ParameterMap());
-    // Parameterized instrument
-    Instrument_sptr m_instrument(new Instrument(instrument, pmap));
 
     // Create the NearestNeighbours object directly.
-    NearestNeighbours nn(m_instrument, spectramap);
+    NearestNeighbours nn(8, ws->spectrumInfo(), getSpectrumNumbers(*ws));
     for (size_t i = 0; i < 2000; i++) {
       nn.neighboursInRadius(1, 5.0);
     }
   }
 
-  void testUsingDefault() {
-    Instrument_sptr instrument = boost::dynamic_pointer_cast<Instrument>(
-        ComponentCreationHelper::createTestInstrumentCylindrical(2));
-    const ISpectrumDetectorMapping spectramap =
-        NearestNeighboursTest::buildSpectrumDetectorMapping(1, 18);
-    // Default parameter map.
-    ParameterMap_sptr pmap(new ParameterMap());
-    // Parameterized instrument
-    Instrument_sptr m_instrument(new Instrument(instrument, pmap));
-
-    // Create the NearestNeighbours object directly.
-    NearestNeighbours nn(m_instrument, spectramap);
-    for (size_t i = 0; i < 2000; i++) {
-      nn.neighboursInRadius(1, 0.0);
-    }
-  }
-
   void testUsingNumberOfNeighbours() {
-    Instrument_sptr instrument = boost::dynamic_pointer_cast<Instrument>(
+    const auto ws = makeWorkspace(1, 18);
+    ws->setInstrument(
         ComponentCreationHelper::createTestInstrumentCylindrical(2));
-    const ISpectrumDetectorMapping spectramap =
-        NearestNeighboursTest::buildSpectrumDetectorMapping(1, 18);
-    // Default parameter map.
-    ParameterMap_sptr pmap(new ParameterMap());
-    // Parameterized instrument
-    Instrument_sptr m_instrument(new Instrument(instrument, pmap));
 
     // Create the NearestNeighbours object directly.
+    const auto &spectrumInfo = ws->spectrumInfo();
+    const auto spectrumNumbers = getSpectrumNumbers(*ws);
     for (size_t i = 0; i < 2000; i++) {
-      NearestNeighbours nn(8, m_instrument, spectramap);
+      NearestNeighbours nn(8, spectrumInfo, spectrumNumbers);
       nn.neighbours(1);
     }
   }
diff --git a/Framework/API/test/NotebookBuilderTest.h b/Framework/API/test/NotebookBuilderTest.h
index 1e89e68b2f46bc81ee29aa74c7b4e3a1288d4ac0..4de0ec170fd49a35242bbae09e4f01626cd5b3c3 100644
--- a/Framework/API/test/NotebookBuilderTest.h
+++ b/Framework/API/test/NotebookBuilderTest.h
@@ -234,7 +234,7 @@ public:
     view->unrollAll();
     NotebookBuilder builder(view);
     std::string notebookText =
-        builder.build(ws->name(), ws->getTitle(), ws->getComment());
+        builder.build(ws->getName(), ws->getTitle(), ws->getComment());
 
     std::vector<std::string> notebookLines;
     std::string line;
@@ -286,7 +286,7 @@ public:
 
     NotebookBuilder builder(view);
     std::string notebookText =
-        builder.build(ws->name(), ws->getTitle(), ws->getComment());
+        builder.build(ws->getName(), ws->getTitle(), ws->getComment());
 
     std::vector<std::string> notebookLines;
     std::string line;
@@ -329,7 +329,7 @@ public:
 
     NotebookBuilder builder(wsHist.createView());
     std::string notebookText =
-        builder.build(ws->name(), ws->getTitle(), ws->getComment());
+        builder.build(ws->getName(), ws->getTitle(), ws->getComment());
 
     std::vector<std::string> notebookLines;
     std::string line;
@@ -346,4 +346,4 @@ public:
   }
 };
 
-#endif // MANTID_NOTEBOOKBUILDERTEST_H_
\ No newline at end of file
+#endif // MANTID_NOTEBOOKBUILDERTEST_H_
diff --git a/Framework/API/test/NotebookWriterTest.h b/Framework/API/test/NotebookWriterTest.h
index 4e7d46f2eb09d14d7365fb4bfd97c67a77aa0d56..da4a4aa5447846b71434a0376e120db12fe5aeda 100644
--- a/Framework/API/test/NotebookWriterTest.h
+++ b/Framework/API/test/NotebookWriterTest.h
@@ -6,6 +6,9 @@
 #include "MantidAPI/NotebookBuilder.h"
 #include "MantidTestHelpers/FakeObjects.h"
 
+#include <boost/algorithm/string/classification.hpp>
+#include <boost/algorithm/string/split.hpp>
+
 using namespace Mantid::API;
 using namespace Mantid::Kernel;
 
diff --git a/Framework/API/test/ProjectionTest.h b/Framework/API/test/ProjectionTest.h
index caf9d285263c9a628ad072a7c152c09d10d7edad..7e797e6db8231262662f8f9fcb216b2c64bbc217 100644
--- a/Framework/API/test/ProjectionTest.h
+++ b/Framework/API/test/ProjectionTest.h
@@ -10,6 +10,7 @@
 
 using namespace Mantid;
 using namespace Mantid::API;
+using namespace Mantid::Kernel;
 
 namespace {
 // Provides a table that claims to have the given number of rows and columns.
diff --git a/Framework/API/test/SampleShapeValidatorTest.h b/Framework/API/test/SampleShapeValidatorTest.h
index db0804d3a1c688d9bb89e4a8568b3b1cd0d36637..b33619fd000b6def305515575abed1aa369dbffc 100644
--- a/Framework/API/test/SampleShapeValidatorTest.h
+++ b/Framework/API/test/SampleShapeValidatorTest.h
@@ -10,6 +10,7 @@
 
 #include "boost/make_shared.hpp"
 
+using namespace Mantid::Kernel;
 using Mantid::API::SampleShapeValidator;
 
 class SampleShapeValidatorTest : public CxxTest::TestSuite {
diff --git a/Framework/API/test/SampleValidatorTest.h b/Framework/API/test/SampleValidatorTest.h
index 8d07a5e9fae3eac2db62e46a531b4fdfa23dfeec..6b0a1e92c1b9cec479bb82dc316399406f540787 100644
--- a/Framework/API/test/SampleValidatorTest.h
+++ b/Framework/API/test/SampleValidatorTest.h
@@ -9,6 +9,7 @@
 #include "MantidTestHelpers/FakeObjects.h"
 #include "MantidTestHelpers/ComponentCreationHelper.h"
 
+using namespace Mantid::Kernel;
 using Mantid::API::SampleValidator;
 
 class SampleValidatorTest : public CxxTest::TestSuite {
diff --git a/Framework/API/test/ScopedWorkspaceTest.h b/Framework/API/test/ScopedWorkspaceTest.h
index cd5e60f0fbcb9de5447c3dc86270a485597cdb11..1d26978bdd0e5742e90c6310e3ff1f151f021e59 100644
--- a/Framework/API/test/ScopedWorkspaceTest.h
+++ b/Framework/API/test/ScopedWorkspaceTest.h
@@ -179,13 +179,13 @@ public:
     MockWorkspace_sptr ws1 = MockWorkspace_sptr(new MockWorkspace);
     test.set(ws1);
 
-    TS_ASSERT_EQUALS(ws1->name(), test.name());
+    TS_ASSERT_EQUALS(ws1->getName(), test.name());
 
     MockWorkspace_sptr ws2 = MockWorkspace_sptr(new MockWorkspace);
     test.set(ws2);
 
-    TS_ASSERT_EQUALS(ws2->name(), test.name());
-    TS_ASSERT(ws1->name().empty());
+    TS_ASSERT_EQUALS(ws2->getName(), test.name());
+    TS_ASSERT(ws1->getName().empty());
     TS_ASSERT_EQUALS(
         m_ads.getObjectNames(Mantid::Kernel::DataServiceSort::Unsorted,
                              Mantid::Kernel::DataServiceHidden::Include).size(),
diff --git a/Framework/API/test/SpectrumInfoTest.h b/Framework/API/test/SpectrumInfoTest.h
index e363fe27751a95b8b7268e5843d330eb17a725ae..464e57aa49bbd84b3f0c2e7d6755d6bac7611f16 100644
--- a/Framework/API/test/SpectrumInfoTest.h
+++ b/Framework/API/test/SpectrumInfoTest.h
@@ -14,6 +14,15 @@
 
 using namespace Mantid::Geometry;
 using namespace Mantid::API;
+using namespace Mantid::Kernel;
+
+namespace {
+constexpr size_t GroupOfDets2And3 = 0;
+constexpr size_t GroupOfDets1And2 = 1;
+constexpr size_t GroupOfDets1And4 = 2;
+constexpr size_t GroupOfDets4And5 = 3;
+constexpr size_t GroupOfAllDets = 4;
+}
 
 class SpectrumInfoTest : public CxxTest::TestSuite {
 public:
@@ -30,11 +39,15 @@ public:
                                  numberOfBins);
 
     // Workspace has 5 detectors, 1 and 4 are masked, 4 and 5 are monitors.
-    m_grouped.getSpectrum(0).setDetectorIDs({2, 3}); // no mask
-    m_grouped.getSpectrum(1).setDetectorIDs({1, 2}); // partial mask
-    m_grouped.getSpectrum(2).setDetectorIDs({1, 4}); // masked, partial monitor
-    m_grouped.getSpectrum(3).setDetectorIDs({4, 5}); // full monitor
-    m_grouped.getSpectrum(4).setDetectorIDs({1, 2, 3, 4, 5}); // everything
+    m_grouped.getSpectrum(GroupOfDets2And3).setDetectorIDs({2, 3}); // no mask
+    m_grouped.getSpectrum(GroupOfDets1And2)
+        .setDetectorIDs({1, 2}); // partial mask
+    m_grouped.getSpectrum(GroupOfDets1And4)
+        .setDetectorIDs({1, 4}); // masked, partial monitor
+    m_grouped.getSpectrum(GroupOfDets4And5)
+        .setDetectorIDs({4, 5}); // full monitor
+    m_grouped.getSpectrum(GroupOfAllDets)
+        .setDetectorIDs({1, 2, 3, 4, 5}); // everything
   }
 
   void test_constructor() {
@@ -72,11 +85,11 @@ public:
     // This is adopting the old definition from DetectorGroup: Spectra with at
     // least one non-monitor detector are not monitors. Actually it might make
     // more sense to forbid such a grouping.
-    TS_ASSERT_EQUALS(spectrumInfo.isMonitor(0), false);
-    TS_ASSERT_EQUALS(spectrumInfo.isMonitor(1), false);
-    TS_ASSERT_EQUALS(spectrumInfo.isMonitor(2), false);
-    TS_ASSERT_EQUALS(spectrumInfo.isMonitor(3), true);
-    TS_ASSERT_EQUALS(spectrumInfo.isMonitor(4), false);
+    TS_ASSERT_EQUALS(spectrumInfo.isMonitor(GroupOfDets2And3), false);
+    TS_ASSERT_EQUALS(spectrumInfo.isMonitor(GroupOfDets1And2), false);
+    TS_ASSERT_EQUALS(spectrumInfo.isMonitor(GroupOfDets1And4), false);
+    TS_ASSERT_EQUALS(spectrumInfo.isMonitor(GroupOfDets4And5), true);
+    TS_ASSERT_EQUALS(spectrumInfo.isMonitor(GroupOfAllDets), false);
   }
 
   void test_isMasked() {
@@ -90,11 +103,11 @@ public:
 
   void test_grouped_isMasked() {
     const auto &spectrumInfo = m_grouped.spectrumInfo();
-    TS_ASSERT_EQUALS(spectrumInfo.isMasked(0), false);
-    TS_ASSERT_EQUALS(spectrumInfo.isMasked(1), false);
-    TS_ASSERT_EQUALS(spectrumInfo.isMasked(2), true);
-    TS_ASSERT_EQUALS(spectrumInfo.isMasked(3), false);
-    TS_ASSERT_EQUALS(spectrumInfo.isMasked(4), false);
+    TS_ASSERT_EQUALS(spectrumInfo.isMasked(GroupOfDets2And3), false);
+    TS_ASSERT_EQUALS(spectrumInfo.isMasked(GroupOfDets1And2), false);
+    TS_ASSERT_EQUALS(spectrumInfo.isMasked(GroupOfDets1And4), true);
+    TS_ASSERT_EQUALS(spectrumInfo.isMasked(GroupOfDets4And5), false);
+    TS_ASSERT_EQUALS(spectrumInfo.isMasked(GroupOfAllDets), false);
   }
 
   void test_isMasked_unthreaded() {
@@ -131,9 +144,9 @@ public:
     const auto &spectrumInfo = m_grouped.spectrumInfo();
     double x2 = 5.0 * 5.0;
     double y2 = 2.0 * 2.0 * 0.05 * 0.05;
-    TS_ASSERT_EQUALS(spectrumInfo.l2(0),
+    TS_ASSERT_EQUALS(spectrumInfo.l2(GroupOfDets2And3),
                      (sqrt(x2 + 0 * 0 * y2) + sqrt(x2 + 1 * 1 * y2)) / 2.0);
-    TS_ASSERT_EQUALS(spectrumInfo.l2(1),
+    TS_ASSERT_EQUALS(spectrumInfo.l2(GroupOfDets1And2),
                      (sqrt(x2 + 0 * 0 * y2) + sqrt(x2 + 1 * 1 * y2)) / 2.0);
     // Other lengths are not sensible since the detectors include monitors
   }
@@ -164,8 +177,10 @@ public:
 
   void test_grouped_twoTheta() {
     const auto &spectrumInfo = m_grouped.spectrumInfo();
-    TS_ASSERT_DELTA(spectrumInfo.twoTheta(0), 0.0199973 / 2.0, 1e-6);
-    TS_ASSERT_DELTA(spectrumInfo.twoTheta(1), 0.0199973 / 2.0, 1e-6);
+    TS_ASSERT_DELTA(spectrumInfo.twoTheta(GroupOfDets2And3), 0.0199973 / 2.0,
+                    1e-6);
+    TS_ASSERT_DELTA(spectrumInfo.twoTheta(GroupOfDets1And2), 0.0199973 / 2.0,
+                    1e-6);
     // Other theta values are not sensible since the detectors include monitors
   }
 
@@ -182,8 +197,8 @@ public:
   // removed at some point.
   void test_grouped_twoThetaLegacy() {
     const auto &spectrumInfo = m_grouped.spectrumInfo();
-    auto det = m_grouped.getDetector(1);
-    TS_ASSERT_EQUALS(spectrumInfo.twoTheta(1),
+    auto det = m_grouped.getDetector(GroupOfDets1And2);
+    TS_ASSERT_EQUALS(spectrumInfo.twoTheta(GroupOfDets1And2),
                      m_grouped.detectorTwoTheta(*det));
   }
 
@@ -199,8 +214,10 @@ public:
 
   void test_grouped_signedTwoTheta() {
     const auto &spectrumInfo = m_grouped.spectrumInfo();
-    TS_ASSERT_DELTA(spectrumInfo.signedTwoTheta(0), 0.0199973 / 2.0, 1e-6);
-    TS_ASSERT_DELTA(spectrumInfo.signedTwoTheta(1), -0.0199973 / 2.0, 1e-6);
+    TS_ASSERT_DELTA(spectrumInfo.signedTwoTheta(GroupOfDets2And3),
+                    0.0199973 / 2.0, 1e-6);
+    TS_ASSERT_DELTA(spectrumInfo.signedTwoTheta(GroupOfDets1And2),
+                    -0.0199973 / 2.0, 1e-6);
     // Other theta values are not sensible since the detectors include monitors
   }
 
@@ -217,8 +234,8 @@ public:
   // be removed at some point.
   void test_grouped_signedTwoThetaLegacy() {
     const auto &spectrumInfo = m_grouped.spectrumInfo();
-    auto det = m_grouped.getDetector(1);
-    TS_ASSERT_EQUALS(spectrumInfo.signedTwoTheta(1),
+    auto det = m_grouped.getDetector(GroupOfDets1And2);
+    TS_ASSERT_EQUALS(spectrumInfo.signedTwoTheta(GroupOfDets1And2),
                      m_grouped.detectorSignedTwoTheta(*det));
   }
 
@@ -233,18 +250,21 @@ public:
 
   void test_grouped_position() {
     const auto &spectrumInfo = m_grouped.spectrumInfo();
-    TS_ASSERT_EQUALS(spectrumInfo.position(0), V3D(0.0, 0.1 / 2.0, 5.0));
-    TS_ASSERT_EQUALS(spectrumInfo.position(1), V3D(0.0, -0.1 / 2.0, 5.0));
+    TS_ASSERT_EQUALS(spectrumInfo.position(GroupOfDets2And3),
+                     V3D(0.0, 0.1 / 2.0, 5.0));
+    TS_ASSERT_EQUALS(spectrumInfo.position(GroupOfDets1And2),
+                     V3D(0.0, -0.1 / 2.0, 5.0));
     // Other positions are not sensible since the detectors include monitors
   }
 
   void test_grouped_position_tracks_changes() {
     auto &detectorInfo = m_grouped.mutableDetectorInfo();
     const auto &spectrumInfo = m_grouped.spectrumInfo();
-    const auto oldPos = spectrumInfo.position(0);
+    const auto oldPos = detectorInfo.position(1);
     // Change Y pos from 0.0 to -0.1
     detectorInfo.setPosition(1, V3D(0.0, -0.1, 5.0));
-    TS_ASSERT_EQUALS(spectrumInfo.position(0), V3D(0.0, 0.0, 5.0));
+    TS_ASSERT_EQUALS(spectrumInfo.position(GroupOfDets2And3),
+                     V3D(0.0, 0.0, 5.0));
     TS_ASSERT_DELTA(spectrumInfo.twoTheta(0), 0.0199973, 1e-6);
     // Restore old position
     detectorInfo.setPosition(1, oldPos);
@@ -272,11 +292,11 @@ public:
 
   void test_grouped_hasDetectors() {
     const auto &spectrumInfo = m_grouped.spectrumInfo();
-    TS_ASSERT(spectrumInfo.hasDetectors(0));
-    TS_ASSERT(spectrumInfo.hasDetectors(1));
-    TS_ASSERT(spectrumInfo.hasDetectors(2));
-    TS_ASSERT(spectrumInfo.hasDetectors(3));
-    TS_ASSERT(spectrumInfo.hasDetectors(4));
+    TS_ASSERT(spectrumInfo.hasDetectors(GroupOfDets2And3));
+    TS_ASSERT(spectrumInfo.hasDetectors(GroupOfDets1And2));
+    TS_ASSERT(spectrumInfo.hasDetectors(GroupOfDets1And4));
+    TS_ASSERT(spectrumInfo.hasDetectors(GroupOfDets4And5));
+    TS_ASSERT(spectrumInfo.hasDetectors(GroupOfAllDets));
   }
 
   void test_hasDetectors_ignores_bad_IDs() {
@@ -310,11 +330,11 @@ public:
 
   void test_grouped_hasUniqueDetector() {
     const auto &spectrumInfo = m_grouped.spectrumInfo();
-    TS_ASSERT(!spectrumInfo.hasUniqueDetector(0));
-    TS_ASSERT(!spectrumInfo.hasUniqueDetector(1));
-    TS_ASSERT(!spectrumInfo.hasUniqueDetector(2));
-    TS_ASSERT(!spectrumInfo.hasUniqueDetector(3));
-    TS_ASSERT(!spectrumInfo.hasUniqueDetector(4));
+    TS_ASSERT(!spectrumInfo.hasUniqueDetector(GroupOfDets2And3));
+    TS_ASSERT(!spectrumInfo.hasUniqueDetector(GroupOfDets1And2));
+    TS_ASSERT(!spectrumInfo.hasUniqueDetector(GroupOfDets1And4));
+    TS_ASSERT(!spectrumInfo.hasUniqueDetector(GroupOfDets4And5));
+    TS_ASSERT(!spectrumInfo.hasUniqueDetector(GroupOfAllDets));
   }
 
   void test_hasUniqueDetector_ignores_bad_IDs() {
@@ -326,6 +346,62 @@ public:
     m_workspace.getSpectrum(1).setDetectorID(2);
   }
 
+  void test_setMasked() {
+    auto &spectrumInfo = m_workspace.mutableSpectrumInfo();
+    TS_ASSERT_EQUALS(spectrumInfo.isMasked(0), true);
+    spectrumInfo.setMasked(0, false);
+    TS_ASSERT_EQUALS(spectrumInfo.isMasked(0), false);
+    spectrumInfo.setMasked(0, true);
+    TS_ASSERT_EQUALS(spectrumInfo.isMasked(0), true);
+    // Make sure no other detectors are affected
+    TS_ASSERT_EQUALS(spectrumInfo.isMasked(1), false);
+    TS_ASSERT_EQUALS(spectrumInfo.isMasked(2), false);
+    TS_ASSERT_EQUALS(spectrumInfo.isMasked(3), true);
+    TS_ASSERT_EQUALS(spectrumInfo.isMasked(4), false);
+  }
+
+  void test_grouped_setMasked() {
+    auto &spectrumInfo = m_grouped.mutableSpectrumInfo();
+    spectrumInfo.setMasked(GroupOfAllDets, false);
+    // 4 includes all detectors so all other spectra are affected
+    TS_ASSERT_EQUALS(spectrumInfo.isMasked(GroupOfDets2And3), false);
+    TS_ASSERT_EQUALS(spectrumInfo.isMasked(GroupOfDets1And2), false);
+    TS_ASSERT_EQUALS(spectrumInfo.isMasked(GroupOfDets1And4), false);
+    TS_ASSERT_EQUALS(spectrumInfo.isMasked(GroupOfDets4And5), false);
+    TS_ASSERT_EQUALS(spectrumInfo.isMasked(GroupOfAllDets), false);
+    spectrumInfo.setMasked(GroupOfDets2And3, true);
+    // Partial masking => false
+    TS_ASSERT_EQUALS(spectrumInfo.isMasked(GroupOfDets2And3), true);
+    TS_ASSERT_EQUALS(spectrumInfo.isMasked(GroupOfDets1And2), false);
+    TS_ASSERT_EQUALS(spectrumInfo.isMasked(GroupOfDets1And4), false);
+    TS_ASSERT_EQUALS(spectrumInfo.isMasked(GroupOfDets4And5), false);
+    TS_ASSERT_EQUALS(spectrumInfo.isMasked(GroupOfAllDets), false);
+    // Restore initial state
+    spectrumInfo.setMasked(GroupOfAllDets, false);
+    spectrumInfo.setMasked(GroupOfDets1And4, true);
+  }
+
+  void test_grouped_setMasked_reverse_case() {
+    auto &spectrumInfo = m_grouped.mutableSpectrumInfo();
+    spectrumInfo.setMasked(GroupOfAllDets, true);
+    // 4 includes all detectors so all other spectra are affected
+    TS_ASSERT_EQUALS(spectrumInfo.isMasked(GroupOfDets2And3), true);
+    TS_ASSERT_EQUALS(spectrumInfo.isMasked(GroupOfDets1And2), true);
+    TS_ASSERT_EQUALS(spectrumInfo.isMasked(GroupOfDets1And4), true);
+    TS_ASSERT_EQUALS(spectrumInfo.isMasked(GroupOfDets4And5), true);
+    TS_ASSERT_EQUALS(spectrumInfo.isMasked(GroupOfAllDets), true);
+    spectrumInfo.setMasked(GroupOfDets2And3, false);
+    // Partial masking => false
+    TS_ASSERT_EQUALS(spectrumInfo.isMasked(GroupOfDets2And3), false);
+    TS_ASSERT_EQUALS(spectrumInfo.isMasked(GroupOfDets1And2), false);
+    TS_ASSERT_EQUALS(spectrumInfo.isMasked(GroupOfDets1And4), true);
+    TS_ASSERT_EQUALS(spectrumInfo.isMasked(GroupOfDets4And5), true);
+    TS_ASSERT_EQUALS(spectrumInfo.isMasked(GroupOfAllDets), false);
+    // Restore initial state
+    spectrumInfo.setMasked(GroupOfAllDets, false);
+    spectrumInfo.setMasked(GroupOfDets1And4, true);
+  }
+
   void test_detector() {
     const auto &spectrumInfo = m_workspace.spectrumInfo();
     TS_ASSERT_THROWS_NOTHING(spectrumInfo.detector(0));
@@ -341,6 +417,61 @@ public:
     TS_ASSERT_THROWS(spectrumInfo.detector(0), std::out_of_range);
   }
 
+  void test_ExperimentInfo_basics() {
+    const ExperimentInfo expInfo(m_workspace);
+    const SpectrumInfo spectrumInfo(expInfo);
+    TS_ASSERT_EQUALS(spectrumInfo.isMasked(0), true);
+    TS_ASSERT_EQUALS(spectrumInfo.isMasked(1), false);
+    TS_ASSERT_EQUALS(spectrumInfo.isMasked(2), false);
+    TS_ASSERT_EQUALS(spectrumInfo.isMasked(3), true);
+    TS_ASSERT_EQUALS(spectrumInfo.isMasked(4), false);
+  }
+
+  void test_ExperimentInfo_from_grouped() {
+    const ExperimentInfo expInfo(m_grouped);
+    TS_ASSERT_EQUALS(expInfo.numberOfDetectorGroups(), 5);
+    const SpectrumInfo spectrumInfo(expInfo);
+    // We construct from a grouped workspace, but since that information is lost
+    // when constructing expInfo, so we should just see the masking of the
+    // underlying detectors.
+    TS_ASSERT_EQUALS(spectrumInfo.isMasked(0), true);
+    TS_ASSERT_EQUALS(spectrumInfo.isMasked(1), false);
+    TS_ASSERT_EQUALS(spectrumInfo.isMasked(2), false);
+    TS_ASSERT_EQUALS(spectrumInfo.isMasked(3), true);
+    TS_ASSERT_EQUALS(spectrumInfo.isMasked(4), false);
+  }
+
+  void test_ExperimentInfo_grouped() {
+    ExperimentInfo expInfo(m_workspace);
+
+    // We cannot really test anything but a single group, since the grouping
+    // mechanism in ExperimentInfo is currently based on std::unordered_map, so
+    // we have no control over the order and thus cannot write asserts.
+    det2group_map mapping{{1, {1, 2}}};
+    expInfo.cacheDetectorGroupings(mapping);
+    const SpectrumInfo spectrumInfo(expInfo);
+    TS_ASSERT_EQUALS(expInfo.numberOfDetectorGroups(), 1);
+    TS_ASSERT_EQUALS(spectrumInfo.isMasked(0), false);
+
+    mapping = {{1, {1, 4}}};
+    expInfo.cacheDetectorGroupings(mapping);
+    const SpectrumInfo spectrumInfo2(expInfo);
+    TS_ASSERT_EQUALS(expInfo.numberOfDetectorGroups(), 1);
+    TS_ASSERT_EQUALS(spectrumInfo2.isMasked(0), true);
+  }
+
+  void test_grouping_in_ExperimentInfo_ignored_for_MatrixWorkspace() {
+    det2group_map mapping{{1, {1, 2}}};
+    m_workspace.cacheDetectorGroupings(mapping);
+    TS_ASSERT_EQUALS(m_workspace.numberOfDetectorGroups(), 5);
+    const auto &spectrumInfo = m_workspace.spectrumInfo();
+    TS_ASSERT_EQUALS(spectrumInfo.isMasked(0), true);
+    TS_ASSERT_EQUALS(spectrumInfo.isMasked(1), false);
+    TS_ASSERT_EQUALS(spectrumInfo.isMasked(2), false);
+    TS_ASSERT_EQUALS(spectrumInfo.isMasked(3), true);
+    TS_ASSERT_EQUALS(spectrumInfo.isMasked(4), false);
+  }
+
 private:
   WorkspaceTester m_workspace;
   WorkspaceTester m_workspaceNoInstrument;
@@ -350,16 +481,17 @@ private:
     auto ws = Kernel::make_unique<WorkspaceTester>();
     ws->initialize(numSpectra, 1, 1);
     auto inst = boost::make_shared<Instrument>("TestInstrument");
-    ws->setInstrument(inst);
-    auto &pmap = ws->instrumentParameters();
     for (size_t i = 0; i < ws->getNumberHistograms(); ++i) {
       auto det = new Detector("pixel", static_cast<detid_t>(i), inst.get());
       inst->add(det);
       inst->markAsDetector(det);
       ws->getSpectrum(i).addDetectorID(static_cast<detid_t>(i));
-      if (i % 2 == 0)
-        pmap.addBool(det->getComponentID(), "masked", true);
     }
+    ws->setInstrument(inst);
+    auto &detectorInfo = ws->mutableDetectorInfo();
+    for (size_t i = 0; i < ws->getNumberHistograms(); ++i)
+      if (i % 2 == 0)
+        detectorInfo.setMasked(i, true);
     return std::move(ws);
   }
 
@@ -375,13 +507,9 @@ private:
         ws, includeMonitors, startYNegative, instrumentName);
 
     std::set<int64_t> toMask{0, 3};
-    ParameterMap &pmap = ws.instrumentParameters();
-    for (size_t i = 0; i < ws.getNumberHistograms(); ++i) {
-      if (toMask.find(i) != toMask.end()) {
-        IDetector_const_sptr det = ws.getDetector(i);
-        pmap.addBool(det.get(), "masked", true);
-      }
-    }
+    auto &detectorInfo = ws.mutableDetectorInfo();
+    for (const auto &i : toMask)
+      detectorInfo.setMasked(i, true);
     return ws;
   }
 };
diff --git a/Framework/API/test/WorkspaceFactoryTest.h b/Framework/API/test/WorkspaceFactoryTest.h
index c62b9e3d574d7433ec1acabf5ea81e65b428d95a..b10fd94b4742db9c7c14c42370a82b558a35bf84 100644
--- a/Framework/API/test/WorkspaceFactoryTest.h
+++ b/Framework/API/test/WorkspaceFactoryTest.h
@@ -34,6 +34,7 @@ class WorkspaceFactoryTest : public CxxTest::TestSuite {
       size.push_back(YLength);
       WorkspaceTester::init(NVectors, XLength, YLength);
     }
+    using WorkspaceTester::init;
     std::vector<size_t> size;
   };
 
diff --git a/Framework/API/test/WorkspaceGroupTest.h b/Framework/API/test/WorkspaceGroupTest.h
index 8162430c2a77ac9f6d3841cd9a20377831a8e1d1..4b6ca876360bf59d30f86900e001f60e9a0478d7 100644
--- a/Framework/API/test/WorkspaceGroupTest.h
+++ b/Framework/API/test/WorkspaceGroupTest.h
@@ -5,6 +5,7 @@
 #include "MantidAPI/Run.h"
 #include "MantidAPI/WorkspaceGroup.h"
 #include "MantidKernel/Exception.h"
+#include "MantidKernel/Strings.h"
 #include "MantidKernel/System.h"
 #include "MantidKernel/Timer.h"
 #include "MantidKernel/WarningSuppressions.h"
@@ -18,6 +19,7 @@
 
 using namespace Mantid;
 using namespace Mantid::API;
+using namespace Mantid::Kernel;
 
 class WorkspaceGroupTest_WorkspaceGroupObserver {
   Poco::NObserver<WorkspaceGroupTest_WorkspaceGroupObserver,
@@ -190,7 +192,7 @@ public:
   void test_getItem() {
     WorkspaceGroup_sptr group = makeGroup();
     Workspace_sptr ws1 = group->getItem(1);
-    TS_ASSERT_EQUALS(ws1->name(), "ws1");
+    TS_ASSERT_EQUALS(ws1->getName(), "ws1");
     // Test the 'by name' overload
     Workspace_sptr ws11 = group->getItem("ws1");
     TS_ASSERT_EQUALS(ws1, ws11);
diff --git a/Framework/API/test/WorkspaceOpOverloadsTest.h b/Framework/API/test/WorkspaceOpOverloadsTest.h
index a310da4867aeb9cf6756390335bb6b9f8abe4dde..2c49de2ebd0d2468592be5df14a6f81445973eeb 100644
--- a/Framework/API/test/WorkspaceOpOverloadsTest.h
+++ b/Framework/API/test/WorkspaceOpOverloadsTest.h
@@ -19,36 +19,36 @@ public:
     auto singlespectrum = boost::make_shared<WorkspaceTester>();
     singlespectrum->init(1, 6, 5);
     TSM_ASSERT("A single-spectrum workspace should always pass",
-               WorkspaceHelpers::commonBoundaries(singlespectrum));
+               WorkspaceHelpers::commonBoundaries(*singlespectrum));
 
     // A simple success case
     auto ws = boost::make_shared<WorkspaceTester>();
     ws->init(5, 6, 5);
-    TS_ASSERT(WorkspaceHelpers::commonBoundaries(ws));
+    TS_ASSERT(WorkspaceHelpers::commonBoundaries(*ws));
     // Changing Y & E values makes no differenc
     ws->dataY(3).assign(5, -5.0);
     ws->dataE(1).assign(5, 1.0);
-    TS_ASSERT(WorkspaceHelpers::commonBoundaries(ws));
+    TS_ASSERT(WorkspaceHelpers::commonBoundaries(*ws));
     // Simple failure case - change a single X value slightly
     ws->dataX(2)[4] = 1.01;
-    TS_ASSERT(!WorkspaceHelpers::commonBoundaries(ws));
+    TS_ASSERT(!WorkspaceHelpers::commonBoundaries(*ws));
 
     // Check it fails if there are nan's or infinities, even if they match up
     auto ws2 = boost::make_shared<WorkspaceTester>();
     ws2->init(2, 6, 5);
     ws2->dataX(0)[2] = std::numeric_limits<double>::infinity();
     ws2->dataX(1)[2] = std::numeric_limits<double>::infinity();
-    TS_ASSERT(!WorkspaceHelpers::commonBoundaries(ws2));
+    TS_ASSERT(!WorkspaceHelpers::commonBoundaries(*ws2));
     ws2->dataX(0)[2] = std::numeric_limits<double>::quiet_NaN();
     ws2->dataX(1)[2] = std::numeric_limits<double>::quiet_NaN();
-    TS_ASSERT(!WorkspaceHelpers::commonBoundaries(ws2));
+    TS_ASSERT(!WorkspaceHelpers::commonBoundaries(*ws2));
 
     // Check it fails if the sum is the same, but the boundaries are different
     auto ws3 = boost::make_shared<WorkspaceTester>();
     ws3->init(2, 3, 2);
     ws3->dataX(0)[0] = -1;
     ws3->dataX(0)[2] = 0;
-    TS_ASSERT(!WorkspaceHelpers::commonBoundaries(ws3));
+    TS_ASSERT(!WorkspaceHelpers::commonBoundaries(*ws3));
   }
 
   void test_commmonBoundaries_negative_sum() // Added in response to bug #7391
@@ -60,14 +60,14 @@ public:
     ws->getSpectrum(1).dataX()[0] = -2.5;
     ws->getSpectrum(1).dataX()[1] = -1.5;
 
-    TS_ASSERT(!WorkspaceHelpers::commonBoundaries(ws));
+    TS_ASSERT(!WorkspaceHelpers::commonBoundaries(*ws));
   }
 
   void test_matchingBins() {
     auto ws = boost::make_shared<WorkspaceTester>();
     ws->init(2, 2, 1);
     TSM_ASSERT("Passing it the same workspace twice had better work!",
-               WorkspaceHelpers::matchingBins(ws, ws));
+               WorkspaceHelpers::matchingBins(*ws, *ws));
 
     // Different size workspaces fail of course
     auto ws2 = boost::make_shared<WorkspaceTester>();
@@ -75,14 +75,14 @@ public:
     auto ws3 = boost::make_shared<WorkspaceTester>();
     ws3->init(2, 3, 2);
     TSM_ASSERT("Different size workspaces should always fail",
-               !WorkspaceHelpers::matchingBins(ws, ws2));
+               !WorkspaceHelpers::matchingBins(*ws, *ws2));
     TSM_ASSERT("Different size workspaces should always fail",
-               !WorkspaceHelpers::matchingBins(ws, ws3));
+               !WorkspaceHelpers::matchingBins(*ws, *ws3));
 
     ws2->dataX(1)[0] = 99.0;
     TSM_ASSERT("First-spectrum-only check should pass even when things differ "
                "in later spectra",
-               WorkspaceHelpers::matchingBins(ws, ws2, true));
+               WorkspaceHelpers::matchingBins(*ws, *ws2, true));
 
     // Check it fails if the sum is zero but the boundaries differ, both for 1st
     // & later spectra.
@@ -94,7 +94,7 @@ public:
     ws5->init(2, 3, 2);
     ws5->dataX(0)[0] = -1;
     ws5->dataX(0)[2] = 0;
-    TS_ASSERT(!WorkspaceHelpers::matchingBins(ws4, ws5, true))
+    TS_ASSERT(!WorkspaceHelpers::matchingBins(*ws4, *ws5, true))
     auto ws6 = boost::make_shared<WorkspaceTester>();
     ws6->init(2, 3, 2);
     ws6->dataX(1)[0] = -1;
@@ -103,7 +103,7 @@ public:
     ws7->init(2, 3, 2);
     ws7->dataX(1)[0] = -1;
     ws7->dataX(1)[2] = 0;
-    TS_ASSERT(!WorkspaceHelpers::matchingBins(ws6, ws7))
+    TS_ASSERT(!WorkspaceHelpers::matchingBins(*ws6, *ws7))
 
     // N.B. There are known ways to fool this method, but they are considered
     // acceptable because
@@ -127,25 +127,25 @@ public:
     ws2->getSpectrum(1).dataX()[0] = -2.7;
     ws2->getSpectrum(1).dataX()[1] = -1.7;
 
-    TS_ASSERT(WorkspaceHelpers::matchingBins(ws1, ws2, true));
-    TS_ASSERT(!WorkspaceHelpers::matchingBins(ws1, ws2));
+    TS_ASSERT(WorkspaceHelpers::matchingBins(*ws1, *ws2, true));
+    TS_ASSERT(!WorkspaceHelpers::matchingBins(*ws1, *ws2));
 
     ws1->getSpectrum(0).dataX()[0] = -2.0;
     ws1->getSpectrum(0).dataX()[1] = -1.0;
     ws2->getSpectrum(0).dataX()[0] = -3.0;
     ws2->getSpectrum(0).dataX()[1] = -4.0;
 
-    TS_ASSERT(!WorkspaceHelpers::matchingBins(ws1, ws2, true));
+    TS_ASSERT(!WorkspaceHelpers::matchingBins(*ws1, *ws2, true));
   }
 
   void test_sharedXData() {
     auto ws = boost::make_shared<WorkspaceTester>();
     ws->init(2, 2, 1);
     // By default the X vectors are different ones
-    TS_ASSERT(!WorkspaceHelpers::sharedXData(ws));
+    TS_ASSERT(!WorkspaceHelpers::sharedXData(*ws));
     // Force both X spectra to point to the same underlying vector
     ws->getSpectrum(1).setX(ws->getSpectrum(0).ptrX());
-    TS_ASSERT(WorkspaceHelpers::sharedXData(ws));
+    TS_ASSERT(WorkspaceHelpers::sharedXData(*ws));
   }
 
   void test_makeDistribution() {
diff --git a/Framework/API/test/WorkspacePropertyTest.h b/Framework/API/test/WorkspacePropertyTest.h
index fe3a5c20b647a13fa28bf2a9d6acac132454e7f5..6c64b6c1202b2aa1be14506d377fa40278f549be 100644
--- a/Framework/API/test/WorkspacePropertyTest.h
+++ b/Framework/API/test/WorkspacePropertyTest.h
@@ -8,6 +8,10 @@
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidTestHelpers/FakeObjects.h"
 
+// Property implementations
+#include "MantidKernel/PropertyWithValue.tcc"
+#include "MantidAPI/WorkspaceProperty.tcc"
+
 using Mantid::MantidVec;
 using namespace Mantid::Kernel;
 using namespace Mantid::API;
diff --git a/Framework/Algorithms/CMakeLists.txt b/Framework/Algorithms/CMakeLists.txt
index e7e34fdfd88bbb3ed6ebdf2b2d3a87604b186492..e4cb073c014753d63fd01ef7120e319a550d4cff 100644
--- a/Framework/Algorithms/CMakeLists.txt
+++ b/Framework/Algorithms/CMakeLists.txt
@@ -18,9 +18,9 @@ set ( SRC_FILES
 	src/AverageLogData.cpp
 	src/BinaryOperateMasks.cpp
 	src/BinaryOperation.cpp
-	src/CalculateCountRate.cpp
 	src/CalMuonDeadTime.cpp
 	src/CalMuonDetectorPhases.cpp
+	src/CalculateCountRate.cpp
 	src/CalculateDIFC.cpp
 	src/CalculateEfficiency.cpp
 	src/CalculateFlatBackground.cpp
@@ -64,8 +64,8 @@ set ( SRC_FILES
 	src/CopyLogs.cpp
 	src/CopySample.cpp
 	src/CorelliCrossCorrelate.cpp
-	src/CorrectFlightPaths.cpp
 	src/CorrectKiKf.cpp
+	src/CorrectTOFAxis.cpp
 	src/CorrectToFile.cpp
 	src/CreateCalFileByNames.cpp
 	src/CreateDummyCalFile.cpp
@@ -152,6 +152,7 @@ set ( SRC_FILES
 	src/IntegrateByComponent.cpp
 	src/Integration.cpp
 	src/InterpolatingRebin.cpp
+	src/InterpolationOption.cpp
 	src/InvertMask.cpp
 	src/Logarithm.cpp
 	src/LorentzCorrection.cpp
@@ -237,7 +238,6 @@ set ( SRC_FILES
 	src/ResizeRectangularDetector.cpp
 	src/RingProfile.cpp
 	src/SANSCollimationLengthEstimator.cpp
-	src/SANSDirectBeamScaling.cpp
 	src/SampleCorrections/MCAbsorptionStrategy.cpp
 	src/SampleCorrections/MCInteractionVolume.cpp
 	src/SampleCorrections/MayersSampleCorrection.cpp
@@ -326,9 +326,9 @@ set ( INC_FILES
 	inc/MantidAlgorithms/BinaryOperateMasks.h
 	inc/MantidAlgorithms/BinaryOperation.h
 	inc/MantidAlgorithms/BoostOptionalToAlgorithmProperty.h
-	inc/MantidAlgorithms/CalculateCountRate.h
 	inc/MantidAlgorithms/CalMuonDeadTime.h
 	inc/MantidAlgorithms/CalMuonDetectorPhases.h
+	inc/MantidAlgorithms/CalculateCountRate.h
 	inc/MantidAlgorithms/CalculateDIFC.h
 	inc/MantidAlgorithms/CalculateEfficiency.h
 	inc/MantidAlgorithms/CalculateFlatBackground.h
@@ -372,8 +372,8 @@ set ( INC_FILES
 	inc/MantidAlgorithms/CopyLogs.h
 	inc/MantidAlgorithms/CopySample.h
 	inc/MantidAlgorithms/CorelliCrossCorrelate.h
-	inc/MantidAlgorithms/CorrectFlightPaths.h
 	inc/MantidAlgorithms/CorrectKiKf.h
+	inc/MantidAlgorithms/CorrectTOFAxis.h
 	inc/MantidAlgorithms/CorrectToFile.h
 	inc/MantidAlgorithms/CreateCalFileByNames.h
 	inc/MantidAlgorithms/CreateDummyCalFile.h
@@ -461,6 +461,7 @@ set ( INC_FILES
 	inc/MantidAlgorithms/IntegrateByComponent.h
 	inc/MantidAlgorithms/Integration.h
 	inc/MantidAlgorithms/InterpolatingRebin.h
+	inc/MantidAlgorithms/InterpolationOption.h
 	inc/MantidAlgorithms/InvertMask.h
 	inc/MantidAlgorithms/Logarithm.h
 	inc/MantidAlgorithms/LorentzCorrection.h
@@ -549,7 +550,6 @@ set ( INC_FILES
 	inc/MantidAlgorithms/ResizeRectangularDetector.h
 	inc/MantidAlgorithms/RingProfile.h
 	inc/MantidAlgorithms/SANSCollimationLengthEstimator.h
-	inc/MantidAlgorithms/SANSDirectBeamScaling.h
 	inc/MantidAlgorithms/SampleCorrections/IBeamProfile.h
 	inc/MantidAlgorithms/SampleCorrections/MCAbsorptionStrategy.h
 	inc/MantidAlgorithms/SampleCorrections/MCInteractionVolume.h
@@ -646,13 +646,14 @@ set ( TEST_FILES
 	AverageLogDataTest.h
 	BinaryOperateMasksTest.h
 	BinaryOperationTest.h
-	CalculateCountRateTest.h
 	CalMuonDeadTimeTest.h
 	CalMuonDetectorPhasesTest.h
+	CalculateCountRateTest.h
 	CalculateDIFCTest.h
 	CalculateEfficiencyTest.h
 	CalculateFlatBackgroundTest.h
 	CalculateResolutionTest.h
+	CalculateSlitsTest.h
 	CalculateTransmissionBeamSpreaderTest.h
 	CalculateTransmissionTest.h
 	CalculateZscoreTest.h
@@ -693,6 +694,7 @@ set ( TEST_FILES
 	CopySampleTest.h
 	CorelliCrossCorrelateTest.h
 	CorrectKiKfTest.h
+	CorrectTOFAxisTest.h
 	CorrectToFileTest.h
 	CreateCalFileByNamesTest.h
 	CreateDummyCalFileTest.h
@@ -710,6 +712,7 @@ set ( TEST_FILES
 	CreateWorkspaceTest.h
 	CropToComponentTest.h
 	CropWorkspaceTest.h
+	CrossCorrelateTest.h
 	CuboidGaugeVolumeAbsorptionTest.h
 	CylinderAbsorptionTest.h
 	DeleteLogTest.h
@@ -772,6 +775,7 @@ set ( TEST_FILES
 	IntegrateByComponentTest.h
 	IntegrationTest.h
 	InterpolatingRebinTest.h
+	InterpolationOptionTest.h
 	InvertMaskTest.h
 	LogarithmTest.h
 	LorentzCorrectionTest.h
@@ -780,6 +784,7 @@ set ( TEST_FILES
 	MagFormFactorCorrectionTest.h
 	MaskBinsFromTableTest.h
 	MaskBinsTest.h
+	MaskDetectorsIfTest.h
 	MaxEnt/MaxentCalculatorTest.h
 	MaxEnt/MaxentEntropyNegativeValuesTest.h
 	MaxEnt/MaxentEntropyPositiveValuesTest.h
@@ -889,6 +894,7 @@ set ( TEST_FILES
 	TransposeTest.h
 	UnGroupWorkspaceTest.h
 	UnaryOperationTest.h
+	UnwrapMonitorTest.h
 	UnwrapMonitorsInTOFTest.h
 	UnwrapSNSTest.h
 	VesuvioL1ThetaResolutionTest.h
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/AppendSpectra.h b/Framework/Algorithms/inc/MantidAlgorithms/AppendSpectra.h
index 1092691cce0281c87737bf2e81f82ceb14b5863f..0fa090ffc8cf29425346d97bdeb52b6f9bd73c40 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/AppendSpectra.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/AppendSpectra.h
@@ -52,9 +52,9 @@ private:
   void init() override;
   void exec() override;
 
-  void fixSpectrumNumbers(API::MatrixWorkspace_const_sptr ws1,
-                          API::MatrixWorkspace_const_sptr ws2,
-                          API::MatrixWorkspace_sptr output) override;
+  void fixSpectrumNumbers(const API::MatrixWorkspace &ws1,
+                          const API::MatrixWorkspace &ws2,
+                          API::MatrixWorkspace &output) override;
   void combineLogs(const API::Run &lhs, const API::Run &rhs, API::Run &ans);
 };
 
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/BinaryOperation.h b/Framework/Algorithms/inc/MantidAlgorithms/BinaryOperation.h
index e05d58cc4bf837a887d56a034ae4fe1e4bedcb84..4c2a6908c231b4ee191e1b140c13885995dde8cb 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/BinaryOperation.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/BinaryOperation.h
@@ -3,6 +3,7 @@
 
 #include "MantidAPI/Algorithm.h"
 #include "MantidAPI/Run.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidAPI/Workspace_fwd.h"
 #include "MantidAPI/WorkspaceGroup_fwd.h"
 #include "MantidDataObjects/EventList.h"
@@ -107,14 +108,11 @@ protected:
   checkSizeCompatibility(const API::MatrixWorkspace_const_sptr lhs,
                          const API::MatrixWorkspace_const_sptr rhs) const;
 
-  /// Checks if the spectra at the given index of either input workspace is
-  /// masked. If so then the output spectra has zeroed data
-  /// and is also masked. The function returns true if further processing is not
-  /// required on the spectra.
-  virtual bool propagateSpectraMask(const API::MatrixWorkspace_const_sptr lhs,
-                                    const API::MatrixWorkspace_const_sptr rhs,
+  virtual bool propagateSpectraMask(const API::SpectrumInfo &lhsSpectrumInfo,
+                                    const API::SpectrumInfo &rhsSpectrumInfo,
                                     const int64_t index,
-                                    API::MatrixWorkspace_sptr out);
+                                    API::MatrixWorkspace &out,
+                                    API::SpectrumInfo &outSpectrumInfo);
 
   /** Carries out the binary operation on a single spectrum, with another
    *spectrum as the right-hand operand.
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/BoostOptionalToAlgorithmProperty.h b/Framework/Algorithms/inc/MantidAlgorithms/BoostOptionalToAlgorithmProperty.h
index 57466da0d2680fa2b3dfcf535d52276d142fe0e3..a4dc11db02f55d3692f4647b4b0a3d4e18284ae1 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/BoostOptionalToAlgorithmProperty.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/BoostOptionalToAlgorithmProperty.h
@@ -58,7 +58,7 @@ T checkForMandatoryInstrumentDefault(
   auto algProperty = alg->getPointerToProperty(propName);
   if (algProperty->isDefault()) {
     auto defaults = instrument->getNumberParameter(idf_name);
-    if (defaults.size() == 0) {
+    if (defaults.empty()) {
       throw std::runtime_error("No data could be retrieved from the parameters "
                                "and argument wasn't provided: " +
                                propName);
@@ -90,7 +90,7 @@ boost::optional<T> checkForOptionalInstrumentDefault(
   auto algProperty = alg->getPointerToProperty(propName);
   if (algProperty->isDefault()) {
     auto defaults = instrument->getNumberParameter(idf_name);
-    if (defaults.size() != 0) {
+    if (!defaults.empty()) {
       return boost::optional<T>(static_cast<T>(defaults[0]));
     } else {
       return boost::optional<T>();
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/CalMuonDetectorPhases.h b/Framework/Algorithms/inc/MantidAlgorithms/CalMuonDetectorPhases.h
index 42278b78a13b2f0b2cdcd51d19508f851bdfeae7..967762d40cafe3dec1abe2abc6a75c1189f1dc5f 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/CalMuonDetectorPhases.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/CalMuonDetectorPhases.h
@@ -4,6 +4,7 @@
 #include "MantidAlgorithms/DllConfig.h"
 #include "MantidAPI/Algorithm.h"
 #include "MantidAPI/ITableWorkspace_fwd.h"
+#include "MantidAPI/WorkspaceGroup_fwd.h"
 #include "MantidGeometry/IDTypes.h"
 
 namespace Mantid {
@@ -104,4 +105,4 @@ private:
 } // namespace Algorithms
 } // namespace Mantid
 
-#endif /* MANTID_ALGORITHMS_CALMUONDETECTORPHASES_H_ */
\ No newline at end of file
+#endif /* MANTID_ALGORITHMS_CALMUONDETECTORPHASES_H_ */
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/CalculateDIFC.h b/Framework/Algorithms/inc/MantidAlgorithms/CalculateDIFC.h
index 00ae1ed5d1491eb8a5b7aec8f26467fb70f50a5a..1aac013bd2f13cdfa7ab9bd0ddcb5be3ba3abcd4 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/CalculateDIFC.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/CalculateDIFC.h
@@ -3,6 +3,7 @@
 
 #include "MantidKernel/System.h"
 #include "MantidAPI/Algorithm.h"
+#include "MantidAPI/DetectorInfo.h"
 #include "MantidDataObjects/OffsetsWorkspace.h"
 
 namespace Mantid {
@@ -46,7 +47,7 @@ private:
   void calculate(API::Progress &progress, API::MatrixWorkspace_sptr &outputWs,
                  DataObjects::OffsetsWorkspace_sptr &offsetsWS, double l1,
                  double beamlineNorm, Kernel::V3D &beamline,
-                 Kernel::V3D &samplePos, detid2det_map &allDetectors);
+                 Kernel::V3D &samplePos, const API::DetectorInfo &detectorInfo);
 };
 
 } // namespace Algorithms
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/CalculateFlatBackground.h b/Framework/Algorithms/inc/MantidAlgorithms/CalculateFlatBackground.h
index 37e9bd6bb5aad6f5df68372beb4237656e3ee34e..06ef232c26b3b76a1082fd2a9dd82f148c8b3d53 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/CalculateFlatBackground.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/CalculateFlatBackground.h
@@ -7,6 +7,9 @@
 #include "MantidAPI/Algorithm.h"
 
 namespace Mantid {
+namespace HistogramData {
+class Histogram;
+}
 namespace Algorithms {
 /** Finds a constant background value of each desired spectrum
     and optionally subtracts that value from the entire spectrum.
@@ -53,21 +56,15 @@ namespace Algorithms {
 class DLLExport CalculateFlatBackground : public API::Algorithm {
 public:
   /// (Empty) Constructor
-  CalculateFlatBackground()
-      : API::Algorithm(), m_convertedFromRawCounts(false),
-        m_skipMonitors(false), m_nullifyNegative(true), m_progress(nullptr) {}
+  CalculateFlatBackground() : API::Algorithm(), m_progress(nullptr) {}
   /// Virtual destructor
-  ~CalculateFlatBackground() override {
-    if (m_progress)
-      delete m_progress;
-    m_progress = nullptr;
-  }
+  ~CalculateFlatBackground() = default;
+
   /// Algorithm's name
   const std::string name() const override { return "CalculateFlatBackground"; }
   /// Summary of algorithms purpose
   const std::string summary() const override {
-    return "Finds a constant background value of each desired spectrum and "
-           "optionally subtracts that value from the entire spectrum.";
+    return "Finds a constant background value of each desired histogram.";
   }
 
   /// Algorithm's version
@@ -86,24 +83,16 @@ private:
   void convertToDistribution(API::MatrixWorkspace_sptr workspace);
   void restoreDistributionState(API::MatrixWorkspace_sptr workspace);
   void checkRange(double &startX, double &endX);
-  void getWsInds(std::vector<int> &output, const int workspaceTotal);
-  double Mean(const API::MatrixWorkspace_sptr WS, const int wsInd,
-              const double startX, const double endX) const;
-  double LinearFit(API::MatrixWorkspace_sptr WS, int spectrum, double startX,
-                   double endX);
-  double MovingAverage(API::MatrixWorkspace_const_sptr WS, int wsIndex,
-                       size_t windowWidth) const;
-
-  /// variable bin width raw count data must be converted to distributions first
-  /// and then converted back, keep track of this
-  bool m_convertedFromRawCounts;
-  /// the variable which specifies if background should be removed from monitors
-  /// too.
-  bool m_skipMonitors;
-  // if true, negative signals appearing after background removals are set to 0
-  bool m_nullifyNegative;
+  void Mean(const HistogramData::Histogram &histogram, double &background,
+            double &variance, const double startX, const double endX) const;
+  void LinearFit(const HistogramData::Histogram &histogram, double &background,
+                 double &variance, const double startX, const double endX);
+  void MovingAverage(const HistogramData::Histogram &histogram,
+                     double &background, double &variance,
+                     const size_t windowWidth) const;
+
   /// Progress reporting
-  API::Progress *m_progress;
+  std::unique_ptr<API::Progress> m_progress;
 };
 
 } // namespace Algorithms
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/ConjoinWorkspaces.h b/Framework/Algorithms/inc/MantidAlgorithms/ConjoinWorkspaces.h
index 8fc8cb84207fd3077baf74eca216904f382d6348..01dbdb0e5f33aa1626e09cea396ce6791a7c0b30 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/ConjoinWorkspaces.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/ConjoinWorkspaces.h
@@ -62,12 +62,12 @@ private:
   void init() override;
   void exec() override;
 
-  void checkForOverlap(API::MatrixWorkspace_const_sptr ws1,
-                       API::MatrixWorkspace_const_sptr ws2,
+  void checkForOverlap(const API::MatrixWorkspace &ws1,
+                       const API::MatrixWorkspace &ws2,
                        bool checkSpectra) const;
-  void fixSpectrumNumbers(API::MatrixWorkspace_const_sptr ws1,
-                          API::MatrixWorkspace_const_sptr ws2,
-                          API::MatrixWorkspace_sptr output) override;
+  void fixSpectrumNumbers(const API::MatrixWorkspace &ws1,
+                          const API::MatrixWorkspace &ws2,
+                          API::MatrixWorkspace &output) override;
   bool processGroups() override;
 
   /// True if spectra overlap
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/ConvertEmptyToTof.h b/Framework/Algorithms/inc/MantidAlgorithms/ConvertEmptyToTof.h
index 8422d341ea20d3d4a0b4ce943cb1c6157dca1912..6baaec50d8e0d5696dcf2d28414979992319890a 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/ConvertEmptyToTof.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/ConvertEmptyToTof.h
@@ -2,6 +2,7 @@
 #define MANTID_ALGORITHMS_CONVERTEMPTYTOTOF_H_
 
 #include "MantidAPI/Algorithm.h"
+#include "MantidAPI/DeprecatedAlgorithm.h"
 #include "MantidAPI/MatrixWorkspace_fwd.h"
 #include "MantidDataObjects/Workspace2D.h"
 #include "MantidKernel/System.h"
@@ -41,7 +42,8 @@ namespace Algorithms {
  File change history is stored at: <https://github.com/mantidproject/mantid>
  Code Documentation is available at: <http://doxygen.mantidproject.org>
  */
-class DLLExport ConvertEmptyToTof : public API::Algorithm {
+class DLLExport ConvertEmptyToTof : public API::Algorithm,
+                                    public API::DeprecatedAlgorithm {
 public:
   const std::string name() const override;
   int version() const override;
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/ConvertSpectrumAxis.h b/Framework/Algorithms/inc/MantidAlgorithms/ConvertSpectrumAxis.h
index 55cb5e2424cefa0440e5ad2d2cba79ca3959d8c0..c74ee93c9b7229f0448776a393122cb88bcdf442 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/ConvertSpectrumAxis.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/ConvertSpectrumAxis.h
@@ -75,7 +75,7 @@ private:
   /// Execution code
   void exec() override;
   /// Getting Efixed
-  double getEfixed(Geometry::IDetector_const_sptr detector,
+  double getEfixed(const Mantid::Geometry::IDetector &detector,
                    API::MatrixWorkspace_const_sptr inputWS, int emode) const;
 };
 
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/ConvertSpectrumAxis2.h b/Framework/Algorithms/inc/MantidAlgorithms/ConvertSpectrumAxis2.h
index 631d51c4df0fc314a1e717336bd09d3da743813b..b1b72002f44b7ce2e52155ef135081408d8c8750 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/ConvertSpectrumAxis2.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/ConvertSpectrumAxis2.h
@@ -83,7 +83,7 @@ private:
   std::multimap<double, size_t> m_indexMap;
 
   /// Getting Efixed
-  double getEfixed(Geometry::IDetector_const_sptr detector,
+  double getEfixed(const Mantid::Geometry::IDetector &detector,
                    API::MatrixWorkspace_const_sptr inputWS, int emode) const;
 };
 
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/ConvertUnits.h b/Framework/Algorithms/inc/MantidAlgorithms/ConvertUnits.h
index 52ae0fdc3e1314f8190cc14269c65a4973acc6b0..aac896bdafd53216f2d44c6ab89934c0675a045b 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/ConvertUnits.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/ConvertUnits.h
@@ -3,6 +3,7 @@
 
 #include "MantidAPI/Algorithm.h"
 #include "MantidDataObjects/EventWorkspace.h"
+#include "MantidKernel/Unit.h"
 
 namespace Mantid {
 namespace Algorithms {
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/ConvertUnitsUsingDetectorTable.h b/Framework/Algorithms/inc/MantidAlgorithms/ConvertUnitsUsingDetectorTable.h
index 495587a2979ce8fa4cb600f0b5be7774ea092dd8..e802704855b98c2fa5114348a1666f7680faad8c 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/ConvertUnitsUsingDetectorTable.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/ConvertUnitsUsingDetectorTable.h
@@ -3,6 +3,7 @@
 
 #include "MantidKernel/System.h"
 #include "MantidAlgorithms/ConvertUnits.h"
+#include "MantidAPI/DeprecatedAlgorithm.h"
 #include "MantidKernel/Unit.h"
 
 namespace Mantid {
@@ -34,7 +35,9 @@ namespace Algorithms {
   File change history is stored at: <https://github.com/mantidproject/mantid>
   Code Documentation is available at: <http://doxygen.mantidproject.org>
 */
-class DLLExport ConvertUnitsUsingDetectorTable : public ConvertUnits {
+class DLLExport ConvertUnitsUsingDetectorTable
+    : public ConvertUnits,
+      public API::DeprecatedAlgorithm {
 public:
   const std::string name() const override;
   int version() const override;
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/CorrectFlightPaths.h b/Framework/Algorithms/inc/MantidAlgorithms/CorrectFlightPaths.h
deleted file mode 100644
index 7b3698de6b09ad9bd8432d70517e517cb060a5d7..0000000000000000000000000000000000000000
--- a/Framework/Algorithms/inc/MantidAlgorithms/CorrectFlightPaths.h
+++ /dev/null
@@ -1,57 +0,0 @@
-#ifndef MANTID_ALGORITHMS_CorrectFlightPaths_H_
-#define MANTID_ALGORITHMS_CorrectFlightPaths_H_
-
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
-#include "MantidAlgorithms/ConvertToConstantL2.h"
-#include "MantidAPI/Algorithm.h"
-#include "MantidAPI/DeprecatedAlgorithm.h"
-
-namespace Mantid {
-namespace Algorithms {
-/** Correct flight paths
-
- Required Properties:
- <UL>
- <LI> InputWorkspace - The name of the Workspace to take as input </LI>
- <LI> OutputWorkspace - The name of the workspace in which to store the result
- </LI>
- </UL>
-
-
- @author Ricardo Ferraz Leal
- @date 30/01/2013
-
- Copyright &copy; 2008-9 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>
- */
-class DLLExport CorrectFlightPaths : public ConvertToConstantL2,
-                                     public API::DeprecatedAlgorithm {
-public:
-  CorrectFlightPaths();
-  const std::string name() const override { return "CorrectFlightPaths"; }
-};
-
-} // namespace Algorithm
-} // namespace Mantid
-
-#endif /*MANTID_ALGORITHMS_CorrectFlightPaths_H_*/
\ No newline at end of file
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/CorrectKiKf.h b/Framework/Algorithms/inc/MantidAlgorithms/CorrectKiKf.h
index 6eaba56ab05f3b58b88cdf33dfc9c0bd7b1341ff..03a706a7b80da5e2f72d5ecef2b48059d49a26e7 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/CorrectKiKf.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/CorrectKiKf.h
@@ -5,6 +5,7 @@
 // Includes
 //----------------------------------------------------------------------
 #include "MantidAPI/Algorithm.h"
+#include "MantidAPI/SpectrumInfo.h"
 
 namespace Mantid {
 namespace Algorithms {
@@ -90,6 +91,9 @@ private:
   template <class T>
   void correctKiKfEventHelper(std::vector<T> &wevector, double efixed,
                               const std::string emodeStr);
+  void getEfixedFromParameterMap(double &Efi, int64_t i,
+                                 const Mantid::API::SpectrumInfo &spectrumInfo,
+                                 const Mantid::Geometry::ParameterMap &pmap);
 };
 
 } // namespace Algorithm
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/CorrectTOFAxis.h b/Framework/Algorithms/inc/MantidAlgorithms/CorrectTOFAxis.h
new file mode 100644
index 0000000000000000000000000000000000000000..1c0ebc3900a32fcc0c2f372c3f5f91700a6e8302
--- /dev/null
+++ b/Framework/Algorithms/inc/MantidAlgorithms/CorrectTOFAxis.h
@@ -0,0 +1,70 @@
+#ifndef MANTID_ALGORITHMS_CORRECTTOFAXIS_H_
+#define MANTID_ALGORITHMS_CORRECTTOFAXIS_H_
+
+#include "MantidAlgorithms/DllConfig.h"
+#include "MantidAPI/Algorithm.h"
+#include "MantidAPI/ITableWorkspace_fwd.h"
+#include "MantidAPI/MatrixWorkspace_fwd.h"
+
+#include <vector>
+
+namespace Mantid {
+namespace API {
+class SpectrumInfo;
+}
+
+namespace Algorithms {
+
+/** CorrectTOFAxis : Corrects the time-of-flight axis with regards to
+  the incident energy and the L1+L2 distance or a reference workspace.
+
+  Copyright &copy; 2016 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>
+*/
+class MANTID_ALGORITHMS_DLL CorrectTOFAxis : public API::Algorithm {
+public:
+  const std::string name() const override;
+  int version() const override;
+  const std::string category() const override;
+  const std::string summary() const override;
+
+private:
+  size_t m_elasticBinIndex = EMPTY_LONG();
+  API::ITableWorkspace_const_sptr m_eppTable;
+  API::MatrixWorkspace_const_sptr m_inputWs;
+  API::MatrixWorkspace_const_sptr m_referenceWs;
+  std::vector<size_t> m_workspaceIndices;
+
+  void init() override;
+  std::map<std::string, std::string> validateInputs() override;
+  void exec() override;
+  void useReferenceWorkspace(API::MatrixWorkspace_sptr outputWs);
+  void correctManually(API::MatrixWorkspace_sptr outputWs);
+  double averageL2(const API::SpectrumInfo &spectrumInfo);
+  void averageL2AndEPP(const API::SpectrumInfo &spectrumInfo, double &l2,
+                       double &epp);
+  std::vector<size_t> referenceWorkspaceIndices() const;
+};
+
+} // namespace Algorithms
+} // namespace Mantid
+
+#endif /* MANTID_ALGORITHMS_CORRECTTOFAXIS_H_ */
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/CreateSampleWorkspace.h b/Framework/Algorithms/inc/MantidAlgorithms/CreateSampleWorkspace.h
index c5d1586eb7689779aec6d8ff58bb0eec99e8455a..a941ff75854498d4926e327e1ae987e29224f13a 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/CreateSampleWorkspace.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/CreateSampleWorkspace.h
@@ -6,6 +6,7 @@
 #include "MantidDataObjects/EventWorkspace.h"
 #include "MantidAPI/MatrixWorkspace_fwd.h"
 #include "MantidGeometry/Instrument.h"
+#include "MantidGeometry/Objects/Object.h"
 #include "MantidKernel/PseudoRandomNumberGenerator.h"
 
 namespace Mantid {
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/DetectorEfficiencyCor.h b/Framework/Algorithms/inc/MantidAlgorithms/DetectorEfficiencyCor.h
index 74da621cc14e284a474bd380ffd973fc712fef02..f2dd709945ceaf8d8c641400900b4998fbbef9a9 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/DetectorEfficiencyCor.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/DetectorEfficiencyCor.h
@@ -2,6 +2,7 @@
 #define MANTID_ALGORITHM_DETECTEFFICIENCYCOR_H_
 
 #include "MantidAPI/Algorithm.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidKernel/V3D.h"
 #include "MantidGeometry/IDetector.h"
 
@@ -102,7 +103,8 @@ private:
   /// Retrieve algorithm properties
   void retrieveProperties();
   /// Correct the given spectra index for efficiency
-  void correctForEfficiency(int64_t spectraIn);
+  void correctForEfficiency(int64_t spectraIn,
+                            const API::SpectrumInfo &spectrumInfo);
   /// Calculate one over the wave vector for 2 bin bounds
   double calculateOneOverK(double loBinBound, double uppBinBound) const;
   /// Sets the detector geometry cache if necessary
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/EstimateResolutionDiffraction.h b/Framework/Algorithms/inc/MantidAlgorithms/EstimateResolutionDiffraction.h
index 176f4b169e9dc73c23f8bec5c2a067bd06ca2ee3..4f14d5aa2203475ca1f06b84ec8f33a93ad6304e 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/EstimateResolutionDiffraction.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/EstimateResolutionDiffraction.h
@@ -62,9 +62,6 @@ private:
   ///
   void retrieveInstrumentParameters();
 
-  /// Create output workspace
-  void createOutputWorkspace();
-
   /// Calculate detector resolution
   void estimateDetectorResolution();
 
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/FFTSmooth.h b/Framework/Algorithms/inc/MantidAlgorithms/FFTSmooth.h
index 54048ffff2dceebb7b989a7a2baefde34e4c748a..3451483bcf804aa5f0e9850687701b3a95cc4401 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/FFTSmooth.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/FFTSmooth.h
@@ -5,6 +5,7 @@
 // Includes
 //----------------------------------------------------------------------
 #include "MantidAPI/Algorithm.h"
+#include "MantidAPI/DeprecatedAlgorithm.h"
 #include "MantidAPI/MatrixWorkspace_fwd.h"
 
 namespace Mantid {
@@ -35,8 +36,11 @@ namespace Algorithms {
     File change history is stored at: <https://github.com/mantidproject/mantid>
     Code Documentation is available at: <http://doxygen.mantidproject.org>
  */
-class DLLExport FFTSmooth : public API::Algorithm {
+class DLLExport FFTSmooth : public API::Algorithm,
+                            public API::DeprecatedAlgorithm {
 public:
+  /// Constructor
+  FFTSmooth() { this->useAlgorithm("FFTSmooth", 2); }
   /// Algorithm's name for identification overriding a virtual method
   const std::string name() const override { return "FFTSmooth"; }
   /// Summary of algorithms purpose
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/GetEi2.h b/Framework/Algorithms/inc/MantidAlgorithms/GetEi2.h
index ef62ba2d764401a45c6574277ecb017a16903be1..c717122ebd9bc0c80f36732f0e8eaadae56db7ee 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/GetEi2.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/GetEi2.h
@@ -6,6 +6,7 @@
 //----------------------------------------------------------------------
 #include "MantidAPI/Algorithm.h"
 #include "MantidAPI/MatrixWorkspace_fwd.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidKernel/cow_ptr.h"
 #include "MantidKernel/System.h"
 
@@ -87,7 +88,8 @@ private:
   double calculateEi(const double initial_guess);
   /// Get the distance from the source of the detector at the workspace index
   /// given
-  double getDistanceFromSource(const size_t ws_index) const;
+  double getDistanceFromSource(const size_t ws_index,
+                               const API::SpectrumInfo &spectrumInfo) const;
   /// Calculate the peak position within the given window
   double calculatePeakPosition(const size_t ws_index, const double t_min,
                                const double t_max);
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/He3TubeEfficiency.h b/Framework/Algorithms/inc/MantidAlgorithms/He3TubeEfficiency.h
index 67736bd9213a7b84a626884d2eff51476b0a0908..7e9ba5dd978e243ec82472306669b8f44d09a01f 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/He3TubeEfficiency.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/He3TubeEfficiency.h
@@ -2,6 +2,7 @@
 #define MANTID_ALGORITHM_HE3TUBEEFFICIENCY_H_
 
 #include "MantidAPI/Algorithm.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidKernel/V3D.h"
 #include "MantidGeometry/IDTypes.h"
 
@@ -84,11 +85,11 @@ private:
   void execEvent();
 
   /// Correct the given spectra index for efficiency
-  void correctForEfficiency(std::size_t spectraIndex);
+  void correctForEfficiency(std::size_t spectraIndex,
+                            const API::SpectrumInfo &spectrumInfo);
   /// Sets the detector geometry cache if necessary
-  void
-  getDetectorGeometry(const boost::shared_ptr<const Geometry::IDetector> &det,
-                      double &detRadius, Kernel::V3D &detAxis);
+  void getDetectorGeometry(const Geometry::IDetector &det, double &detRadius,
+                           Kernel::V3D &detAxis);
   /// Computes the distance to the given shape from a starting point
   double distToSurface(const Kernel::V3D start,
                        const Geometry::Object *shape) const;
@@ -99,14 +100,12 @@ private:
   void logErrors() const;
   /// Retrieve the detector parameters from workspace or detector properties
   double getParameter(std::string wsPropName, std::size_t currentIndex,
-                      std::string detPropName,
-                      boost::shared_ptr<const Geometry::IDetector> idet);
+                      std::string detPropName, const Geometry::IDetector &idet);
   /// Helper for event handling
   template <class T> void eventHelper(std::vector<T> &events, double expval);
   /// Function to calculate exponential contribution
-  double
-  calculateExponential(std::size_t spectraIndex,
-                       boost::shared_ptr<const Geometry::IDetector> idet);
+  double calculateExponential(std::size_t spectraIndex,
+                              const Geometry::IDetector &idet);
 
   /// The user selected (input) workspace
   API::MatrixWorkspace_const_sptr inputWS;
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/InterpolationOption.h b/Framework/Algorithms/inc/MantidAlgorithms/InterpolationOption.h
new file mode 100644
index 0000000000000000000000000000000000000000..fcc79d49f8128ae4b592cc2b97ce7fb384737e80
--- /dev/null
+++ b/Framework/Algorithms/inc/MantidAlgorithms/InterpolationOption.h
@@ -0,0 +1,65 @@
+#ifndef MANTID_ALGORITHMS_INTERPOLATIONOPTION_H_
+#define MANTID_ALGORITHMS_INTERPOLATIONOPTION_H_
+
+#include "MantidAlgorithms/DllConfig.h"
+#include <memory>
+#include <string>
+
+namespace Mantid {
+namespace HistogramData {
+class Histogram;
+}
+namespace Kernel {
+class Property;
+}
+namespace Algorithms {
+
+/**
+  Class to provide a consistent interface to an interpolation option on
+  algorithms.
+
+  Copyright &copy; 2016 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>
+*/
+class MANTID_ALGORITHMS_DLL InterpolationOption {
+public:
+  // Indices must match the order in static string array
+  enum class Value : uint8_t { Linear, CSpline };
+
+  InterpolationOption();
+  void set(Value kind);
+  void set(const std::string &kind);
+
+  std::unique_ptr<Kernel::Property> property() const;
+  std::string propertyDoc() const;
+
+  void applyInplace(HistogramData::Histogram &inOut, size_t stepSize) const;
+
+private:
+  using MethodImpl = void(HistogramData::Histogram &inOut,
+                          const size_t stepSize);
+  MethodImpl *m_impl = nullptr;
+};
+
+} // namespace Algorithms
+} // namespace Mantid
+
+#endif /* MANTID_ALGORITHMS_INTERPOLATIONOPTION_H_ */
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/MergeRuns.h b/Framework/Algorithms/inc/MantidAlgorithms/MergeRuns.h
index 824bd04017c71d5267c6b8b3d854e646a1667d36..5e6c3e8e67269b38b34931aad3107ed28748a61d 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/MergeRuns.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/MergeRuns.h
@@ -1,14 +1,12 @@
 #ifndef MANTID_ALGORITHMS_MERGERUNS_H_
 #define MANTID_ALGORITHMS_MERGERUNS_H_
 
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include <list>
 #include <vector>
 #include <boost/shared_ptr.hpp>
 #include <MantidAPI/MatrixWorkspace.h>
 #include "MantidAPI/MultiPeriodGroupAlgorithm.h"
+#include "MantidAPI/WorkspaceHistory.h"
 #include "MantidDataObjects/EventWorkspace.h"
 #include "MantidKernel/System.h"
 #include <boost/shared_ptr.hpp>
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/ModeratorTzero.h b/Framework/Algorithms/inc/MantidAlgorithms/ModeratorTzero.h
index c5b0b6621e073e317347b67b2f638233a209513b..fd98511d3727727ad96f5072f6c06a7b57e396df 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/ModeratorTzero.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/ModeratorTzero.h
@@ -96,8 +96,6 @@ public:
   double gett1min();
 
 private:
-  Mantid::Geometry::Instrument_const_sptr m_instrument;
-
   // Initialisation code
   void init() override;
   /// Execution code for histogram workspace
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/ModeratorTzeroLinear.h b/Framework/Algorithms/inc/MantidAlgorithms/ModeratorTzeroLinear.h
index 4a5e508b503057583ce3fc43d25b0521fcd14dd8..9a3ead956e753515297df78533816916d46f2687 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/ModeratorTzeroLinear.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/ModeratorTzeroLinear.h
@@ -1,13 +1,13 @@
 #ifndef MANTID_ALGORITHMS_MODERATORTZEROLINEAR_H_
 #define MANTID_ALGORITHMS_MODERATORTZEROLINEAR_H_
 
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidAPI/Algorithm.h"
 #include "MantidGeometry/Instrument.h"
 
 namespace Mantid {
+namespace API {
+class SpectrumInfo;
+}
 namespace Algorithms {
 /* Corrects the time of flight (TOF) by a time offset that is dependent on the
  velocity of the neutron after passing through the moderator.
@@ -104,7 +104,7 @@ private:
   // Execution code for event workspace
   void execEvent();
   // Calculate time from sample to detector and initial flight path
-  void calculateTfLi(API::MatrixWorkspace_const_sptr inputWS, size_t i,
+  void calculateTfLi(const API::SpectrumInfo &spectrumInfo, size_t i,
                      double &t_f, double &L_i);
 };
 
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/MonteCarloAbsorption.h b/Framework/Algorithms/inc/MantidAlgorithms/MonteCarloAbsorption.h
index 97c6d0ef65b24ec09bf10a340ba76bbfdfd6b0c3..e1688dcb75bfb880d43f70d3af60a2f6b8aa32db 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/MonteCarloAbsorption.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/MonteCarloAbsorption.h
@@ -6,6 +6,7 @@
 //------------------------------------------------------------------------------
 #include "MantidAPI/Algorithm.h"
 #include "MantidAlgorithms/SampleCorrections/IBeamProfile.h"
+#include "MantidAlgorithms/InterpolationOption.h"
 
 namespace Mantid {
 namespace API {
@@ -61,8 +62,9 @@ private:
   void init() override;
   void exec() override;
 
-  API::MatrixWorkspace_sptr doSimulation(const API::MatrixWorkspace &inputWS,
-                                         size_t nevents, int nlambda, int seed);
+  API::MatrixWorkspace_sptr
+  doSimulation(const API::MatrixWorkspace &inputWS, size_t nevents, int nlambda,
+               int seed, const InterpolationOption &interpolateOpt);
   API::MatrixWorkspace_sptr
   createOutputWorkspace(const API::MatrixWorkspace &inputWS) const;
   std::unique_ptr<IBeamProfile>
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/NormaliseToMonitor.h b/Framework/Algorithms/inc/MantidAlgorithms/NormaliseToMonitor.h
index f2db237673529f3326a6e2ba98e1fb1818343be5..de11602a4578e11e7194ac6b698a0e7d3e90f5b4 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/NormaliseToMonitor.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/NormaliseToMonitor.h
@@ -1,12 +1,10 @@
 #ifndef MANTID_ALGORITHMS_NORMALISETOMONITOR_H_
 #define MANTID_ALGORITHMS_NORMALISETOMONITOR_H_
 
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidAPI/Algorithm.h"
 #include "MantidKernel/cow_ptr.h"
 #include "MantidKernel/IPropertyManager.h"
+#include "MantidKernel/IPropertySettings.h"
 
 namespace Mantid {
 namespace HistogramData {
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/PDDetermineCharacterizations.h b/Framework/Algorithms/inc/MantidAlgorithms/PDDetermineCharacterizations.h
index 0e2094499c282f87dea911ab213efd3c3cae27dc..50102fe4a80510dbbda11ad29ae79f1f7190d061 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/PDDetermineCharacterizations.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/PDDetermineCharacterizations.h
@@ -53,7 +53,8 @@ public:
 
 private:
   double getLogValue(API::Run &run, const std::string &propName);
-  void getInformationFromTable(const double frequency, const double wavelength);
+  void getInformationFromTable(const double frequency, const double wavelength,
+                               const std::string &canName);
   void setDefaultsInPropManager();
   void overrideRunNumProperty(const std::string &inputName,
                               const std::string &propName);
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/Qhelper.h b/Framework/Algorithms/inc/MantidAlgorithms/Qhelper.h
index 5b22fd9e98a21a4ee388ac97bdc047cf9cd5e925..0b8ccbaa2e88d065c98c7e16c61cda28852c0416 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/Qhelper.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/Qhelper.h
@@ -2,6 +2,7 @@
 #define MANTID_ALGORITHMS_QHELPER_H_
 
 #include "MantidAPI/Algorithm.h"
+#include "MantidAPI/SpectrumInfo.h"
 
 namespace Mantid {
 namespace Algorithms {
@@ -43,6 +44,7 @@ public:
                     API::MatrixWorkspace_const_sptr detectAdj);
 
   size_t waveLengthCutOff(API::MatrixWorkspace_const_sptr dataWS,
+                          const API::SpectrumInfo &spectrumInfo,
                           const double RCut, const double WCut,
                           const size_t wsInd) const;
 
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/Rebunch.h b/Framework/Algorithms/inc/MantidAlgorithms/Rebunch.h
index e028be89ef129d3f42b5ac42d83ab9c43e7331d7..6ab2eec810516b9831da8158261a60ec28e484f3 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/Rebunch.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/Rebunch.h
@@ -7,6 +7,11 @@
 #include "MantidAPI/Algorithm.h"
 
 namespace Mantid {
+namespace HistogramData {
+class HistogramX;
+class HistogramY;
+class HistogramE;
+}
 namespace Algorithms {
 /**
 
@@ -69,16 +74,26 @@ private:
   // Overridden Algorithm methods
   void init() override;
   void exec() override;
-  void rebunch_hist(const std::vector<double> &xold,
-                    const std::vector<double> &yold,
-                    const std::vector<double> &eold, std::vector<double> &xnew,
-                    std::vector<double> &ynew, std::vector<double> &enew,
-                    const size_t n_bunch, const bool distribution);
-  void rebunch_point(const std::vector<double> &xold,
-                     const std::vector<double> &yold,
-                     const std::vector<double> &eold, std::vector<double> &xnew,
-                     std::vector<double> &ynew, std::vector<double> &enew,
-                     const int n_bunch);
+  void rebunch_hist_counts(const HistogramData::HistogramX &xold,
+                           const HistogramData::HistogramY &yold,
+                           const HistogramData::HistogramE &eold,
+                           HistogramData::HistogramX &xnew,
+                           HistogramData::HistogramY &ynew,
+                           HistogramData::HistogramE &enew,
+                           const size_t n_bunch);
+  void rebunch_hist_frequencies(const HistogramData::HistogramX &xold,
+                                const HistogramData::HistogramY &yold,
+                                const HistogramData::HistogramE &eold,
+                                HistogramData::HistogramX &xnew,
+                                HistogramData::HistogramY &ynew,
+                                HistogramData::HistogramE &enew,
+                                const size_t n_bunch);
+  void rebunch_point(const HistogramData::HistogramX &xold,
+                     const HistogramData::HistogramY &yold,
+                     const HistogramData::HistogramE &eold,
+                     HistogramData::HistogramX &xnew,
+                     HistogramData::HistogramY &ynew,
+                     HistogramData::HistogramE &enew, const size_t n_bunch);
 };
 
 } // namespace Algorithm
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/ReflectometryReductionOneAuto.h b/Framework/Algorithms/inc/MantidAlgorithms/ReflectometryReductionOneAuto.h
index 53a79c01f1ee731c165ba0ec9a1680b4334f47fb..5b84f40d83371650a724a21303f6dbd34a8bdb05 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/ReflectometryReductionOneAuto.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/ReflectometryReductionOneAuto.h
@@ -3,7 +3,7 @@
 
 #include "MantidAPI/Algorithm.h"
 #include "MantidAPI/DataProcessorAlgorithm.h"
-#include "MantidGeometry/Instrument.h"
+#include "MantidAPI/WorkspaceGroup_fwd.h"
 #include "MantidKernel/System.h"
 
 #include <boost/optional.hpp>
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/ReflectometryWorkflowBase.h b/Framework/Algorithms/inc/MantidAlgorithms/ReflectometryWorkflowBase.h
index 98ffb55513f1d7212996655a0ae2970ffd9c31a5..dc7c12f7a8442d196a94d7fe9563bb961a55b3a6 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/ReflectometryWorkflowBase.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/ReflectometryWorkflowBase.h
@@ -10,6 +10,10 @@
 #include <vector>
 
 namespace Mantid {
+
+namespace HistogramData {
+class HistogramX;
+}
 namespace Algorithms {
 
 /** ReflectometryWorkflowBase : Abstract workflow algortithm base class
@@ -117,7 +121,8 @@ private:
                const OptionalMinMax &backgroundMinMax);
 
   /// Make a unity workspace
-  API::MatrixWorkspace_sptr makeUnityWorkspace(const std::vector<double> &x);
+  API::MatrixWorkspace_sptr
+  makeUnityWorkspace(const HistogramData::HistogramX &x);
 };
 } // namespace Algorithms
 } // namespace Mantid
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/Regroup.h b/Framework/Algorithms/inc/MantidAlgorithms/Regroup.h
index d3eacb8c37cca2825c3e470a37956137e6006ae4..a301f7c678caac0359c55a1efa977069a6ede356 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/Regroup.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/Regroup.h
@@ -8,6 +8,11 @@
 #include "MantidAPI/Workspace_fwd.h"
 
 namespace Mantid {
+namespace HistogramData {
+class HistogramX;
+class HistogramY;
+class HistogramE;
+}
 namespace Algorithms {
 /** Takes a 2D workspace as input and regroups the data according to the input
    regroup parameters.
@@ -67,9 +72,11 @@ private:
   void init() override;
   void exec() override;
 
-  void rebin(const std::vector<double> &, const std::vector<double> &,
-             const std::vector<double> &, const std::vector<int> &,
-             std::vector<double> &, std::vector<double> &, bool);
+  void rebin(const HistogramData::HistogramX &xold,
+             const HistogramData::HistogramY &yold,
+             const HistogramData::HistogramE &eold, std::vector<int> &xoldIndex,
+             HistogramData::HistogramY &ynew, HistogramData::HistogramE &enew,
+             bool distribution);
 };
 
 } // namespace Algorithm
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/RemoveBackground.h b/Framework/Algorithms/inc/MantidAlgorithms/RemoveBackground.h
index f50a4df5af4c639939665a18cbd48b0697f95145..b1c592c75aab54fd1a9d90d098707b31ff66c89e 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/RemoveBackground.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/RemoveBackground.h
@@ -2,11 +2,16 @@
 #define MANTID_ALGORITHMS_REMOVEBACKGROUND_H_
 
 #include "MantidAPI/Algorithm.h"
-#include "MantidKernel/cow_ptr.h"
 #include "MantidGeometry/IComponent.h"
+#include "MantidKernel/cow_ptr.h"
 
 namespace Mantid {
 
+namespace HistogramData {
+class HistogramX;
+class HistogramY;
+class HistogramE;
+}
 // forward declarations from other Mantid modules
 namespace Kernel {
 class Unit;
@@ -56,8 +61,10 @@ public:
                   const API::MatrixWorkspace_sptr &sourceWS, int emode,
                   Kernel::Logger *pLog = nullptr, int nThreads = 1,
                   bool inPlace = true, bool nullifyNegative = false);
-  void removeBackground(int nHist, MantidVec &x_data, MantidVec &y_data,
-                        MantidVec &e_data, int threadNum = 0) const;
+  void removeBackground(int nHist, HistogramData::HistogramX &x_data,
+                        HistogramData::HistogramY &y_data,
+                        HistogramData::HistogramE &e_data,
+                        int threadNum = 0) const;
 
 private:
   // vector of pointers to the units conversion class for the working workspace;
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/RemoveBins.h b/Framework/Algorithms/inc/MantidAlgorithms/RemoveBins.h
index a2eb54bb49cbe999a9aa3a9a978351c3ba050ff7..89480678e4fcb80d671e5c43dd48d43684058087 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/RemoveBins.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/RemoveBins.h
@@ -2,10 +2,15 @@
 #define MANTID_ALGORITHMS_REMOVEBINS_H_
 
 #include "MantidAPI/Algorithm.h"
-#include "MantidKernel/cow_ptr.h"
 #include "MantidKernel/Unit.h"
+#include "MantidKernel/cow_ptr.h"
 
 namespace Mantid {
+namespace HistogramData {
+class HistogramX;
+class HistogramY;
+class HistogramE;
+}
 namespace API {
 class SpectrumInfo;
 }
@@ -82,11 +87,13 @@ private:
   void transformRangeUnit(const int index, double &startX, double &endX);
   void calculateDetectorPosition(const int index, double &l1, double &l2,
                                  double &twoTheta);
-  int findIndex(const double &value, const MantidVec &vec);
-  void RemoveFromEnds(int start, int end, MantidVec &Y, MantidVec &E);
+  int findIndex(const double &value, const HistogramData::HistogramX &vec);
+  void RemoveFromEnds(int start, int end, HistogramData::HistogramY &Y,
+                      HistogramData::HistogramE &E);
   void RemoveFromMiddle(const int &start, const int &end,
                         const double &startFrac, const double &endFrac,
-                        MantidVec &Y, MantidVec &E);
+                        HistogramData::HistogramY &Y,
+                        HistogramData::HistogramE &E);
 
   API::MatrixWorkspace_const_sptr m_inputWorkspace; ///< The input workspace
   const API::SpectrumInfo *m_spectrumInfo;
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/ReplaceSpecialValues.h b/Framework/Algorithms/inc/MantidAlgorithms/ReplaceSpecialValues.h
index 8acc55befdcb00a17894f4e97b6f347919a37357..37db6776dad662745c0465fd858c8d3a33a10060 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/ReplaceSpecialValues.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/ReplaceSpecialValues.h
@@ -13,25 +13,10 @@ namespace Algorithms {
  numbers.
  If a replacement value is not provided the check will not occur.
 
- Required Properties:
- <UL>
- <LI> InputWorkspace  - The name of the workspace to correct</LI>
- <LI> OutputWorkspace - The name of the corrected workspace (can be the same as
- the input one)</LI>
- <LI> NaNValue        - The value used to replace occurances of NaN (default do
- not check)</LI>
- <LI> NaNError        - The error value used when replacing a value of NaN
- (default 0)</LI>
- <LI> InfinityValue   - The value used to replace occurances of positive or
- negative infinity (default do not check)</LI>
- <LI> InfinityError   - The error value used when replacing a value of infinity
- (default 0)</LI>
- </UL>
-
  @author Nicholas Draper, Tessella plc
  @date 18/06/2009
 
- Copyright &copy; 2009-2010 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge
+ Copyright &copy; 2009-2016 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge
  National Laboratory & European Spallation Source
 
  This file is part of Mantid.
@@ -81,13 +66,15 @@ private:
                              double &EOut) override;
 
   /// returns true if the value is NaN
-  bool checkIfNan(const double &value) const;
+  bool checkIfNan(const double value) const;
   /// returns true if the value if + or - infinity
-  bool checkIfInfinite(const double &value) const;
+  bool checkIfInfinite(const double value) const;
   /// Returns true if the absolute value is larger than the 'big' threshold
-  bool checkIfBig(const double &value) const;
+  bool checkIfBig(const double value) const;
+  /// Returns true is the absolute value is smaller than the 'small' threshold
+  bool checkIfSmall(const double value) const;
   /// returns true if the value has been set
-  bool checkifPropertyEmpty(const double &value) const;
+  bool checkifPropertyEmpty(const double value) const;
 
   double m_NaNValue;      ///< The replacement value for NaN
   double m_NaNError;      ///< The replacement error value for NaN
@@ -97,6 +84,10 @@ private:
   /// considered 'big'
   double m_bigValue; ///< The replacement value for big numbers
   double m_bigError; ///< The replacement error value for big numbers
+  double
+      m_smallThreshold; ///< The threshold value below which a value is 'small'
+  double m_smallValue;  ///< The replacement value for small numbers
+  double m_smallError;  ///< The replacement error value for small numbers
 
   bool m_performNaNCheck; ///< Flag to indicate if the NaN check is to be
   /// performed
@@ -104,6 +95,9 @@ private:
   /// be performed
   bool m_performBigCheck; ///< Flag to indicate if the 'big number' check is to
   /// be performed
+  bool m_performSmallCheck; ///< Flag to indicate if the 'small number' check is
+  /// to
+  /// be performed
 };
 
 } // namespace Algorithms
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/SANSDirectBeamScaling.h b/Framework/Algorithms/inc/MantidAlgorithms/SANSDirectBeamScaling.h
deleted file mode 100644
index a21b6224de7f6828e5dbae194476e510b5771b44..0000000000000000000000000000000000000000
--- a/Framework/Algorithms/inc/MantidAlgorithms/SANSDirectBeamScaling.h
+++ /dev/null
@@ -1,67 +0,0 @@
-#ifndef MANTID_ALGORITHMS_SANSDIRECTBEAMSCALING_H_
-#define MANTID_ALGORITHMS_SANSDIRECTBEAMSCALING_H_
-
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
-#include "MantidAPI/Algorithm.h"
-#include "MantidAPI/DeprecatedAlgorithm.h"
-
-namespace Mantid {
-namespace Algorithms {
-/**
-    Computes the scaling factor to get reduced SANS data on an absolute scale.
-
-    Required Properties:
-    <UL>
-    <LI> InputWorkspace    - The data in units of wavelength. </LI>
-    <LI> AttenuatorTransmission   - Attenuator transmission for empty direct
-   beam. </LI>
-    <LI> AttenuatorTransmissionError   - Uncertainty in attenuator transmission.
-   </LI>
-    <LI> BeamRadius   - Radius of the beam stop [m]. </LI>
-    <LI> SourceApertureRadius   - Source aperture to be used if it is not found
-   in the instrument parameters [m]. </LI>
-    <LI> SampleApertureRadius   - Sample aperture to be used if it is not found
-   in the instrument parameters [m]. </LI>
-    <LI> BeamMonitor   - The UDET of the incident beam monitor.</LI>
-    </UL>
-
-    Output Properties:
-    <UL>
-    <LI> ScaleFactor   - Scale factor value and uncertainty [n/(monitor
-   count)/(cm^2)/steradian].</LI>
-    </UL>
-
-    File change history is stored at: <https://github.com/mantidproject/mantid>
-    Code Documentation is available at: <http://doxygen.mantidproject.org>
-*/
-class DLLExport SANSDirectBeamScaling : public API::Algorithm,
-                                        public API::DeprecatedAlgorithm {
-public:
-  /// (Empty) Constructor
-  SANSDirectBeamScaling() : API::Algorithm() { deprecatedDate("2014-06-12"); }
-  /// Algorithm's name
-  const std::string name() const override { return "SANSDirectBeamScaling"; }
-  /// Summary of algorithms purpose
-  const std::string summary() const override {
-    return "Computes the scaling factor to get reduced SANS data on an "
-           "absolute scale.";
-  }
-
-  /// Algorithm's version
-  int version() const override { return (1); }
-  /// Algorithm's category for identification
-  const std::string category() const override { return "SANS"; }
-
-private:
-  /// Initialisation code
-  void init() override;
-  /// Execution code
-  void exec() override;
-};
-
-} // namespace Algorithms
-} // namespace Mantid
-
-#endif /*MANTID_ALGORITHMS_SANSDIRECTBEAMSCALING_H_*/
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/SampleCorrections/IBeamProfile.h b/Framework/Algorithms/inc/MantidAlgorithms/SampleCorrections/IBeamProfile.h
index a9305fc807b71a2dfcfc0c9007fd6c00e1efda4b..28a969146ad1ca1c4219b10c101375a227f8f856 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/SampleCorrections/IBeamProfile.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/SampleCorrections/IBeamProfile.h
@@ -2,15 +2,16 @@
 #define MANTID_ALGORITHMS_IBEAMPROFILE_H_
 
 #include "MantidAlgorithms/DllConfig.h"
+#include "MantidGeometry/Objects/BoundingBox.h"
 #include "MantidKernel/V3D.h"
 
 namespace Mantid {
+namespace API {
+class Sample;
+}
 namespace Kernel {
 class PseudoRandomNumberGenerator;
 }
-namespace Geometry {
-class BoundingBox;
-}
 namespace Algorithms {
 
 /**
@@ -49,6 +50,8 @@ public:
   virtual Ray generatePoint(Kernel::PseudoRandomNumberGenerator &rng) const = 0;
   virtual Ray generatePoint(Kernel::PseudoRandomNumberGenerator &rng,
                             const Geometry::BoundingBox &) const = 0;
+  virtual Geometry::BoundingBox
+  defineActiveRegion(const API::Sample &) const = 0;
 };
 
 } // namespace Algorithms
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/SampleCorrections/MCInteractionVolume.h b/Framework/Algorithms/inc/MantidAlgorithms/SampleCorrections/MCInteractionVolume.h
index 0654a72c9d62e0a198655e6453caed28472ee8fc..05533afd2e1011eebe93cf44be17e12fbeef6a4a 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/SampleCorrections/MCInteractionVolume.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/SampleCorrections/MCInteractionVolume.h
@@ -2,13 +2,13 @@
 #define MANTID_ALGORITHMS_MCINTERACTIONVOLUME_H_
 
 #include "MantidAlgorithms/DllConfig.h"
+#include "MantidGeometry/Objects/BoundingBox.h"
 
 namespace Mantid {
 namespace API {
 class Sample;
 }
 namespace Geometry {
-class BoundingBox;
 class Object;
 class SampleEnvironment;
 }
@@ -17,6 +17,7 @@ class PseudoRandomNumberGenerator;
 class V3D;
 }
 namespace Algorithms {
+class IBeamProfile;
 
 /**
   Defines a volume where interactions of Tracks and Objects can take place.
@@ -46,21 +47,23 @@ namespace Algorithms {
 */
 class MANTID_ALGORITHMS_DLL MCInteractionVolume {
 public:
-  MCInteractionVolume(const API::Sample &sample);
+  MCInteractionVolume(const API::Sample &sample,
+                      const Geometry::BoundingBox &activeRegion);
   // No creation from temporaries as we store a reference to the object in
   // the sample
-  MCInteractionVolume(const API::Sample &&sample) = delete;
+  MCInteractionVolume(const API::Sample &&sample,
+                      const Geometry::BoundingBox &&activeRegion) = delete;
 
   const Geometry::BoundingBox &getBoundingBox() const;
   double calculateAbsorption(Kernel::PseudoRandomNumberGenerator &rng,
                              const Kernel::V3D &startPos,
-                             const Kernel::V3D &direc,
                              const Kernel::V3D &endPos, double lambdaBefore,
                              double lambdaAfter) const;
 
 private:
   const Geometry::Object &m_sample;
   const Geometry::SampleEnvironment *m_env;
+  const Geometry::BoundingBox m_activeRegion;
 };
 
 } // namespace Algorithms
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/SampleCorrections/MayersSampleCorrectionStrategy.h b/Framework/Algorithms/inc/MantidAlgorithms/SampleCorrections/MayersSampleCorrectionStrategy.h
index 39c0e121a256f1f1ff2f1a4520754f293e1fe6de..cd457bd0e0b8c3b302b49ac03e7b92635057ae65 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/SampleCorrections/MayersSampleCorrectionStrategy.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/SampleCorrections/MayersSampleCorrectionStrategy.h
@@ -51,12 +51,14 @@ public:
     double l1;        ///< Nominal distance from source to sample (m)
     double l2;        ///< Nominal distance from sample to detector (m)
     double twoTheta;  ///< Scattering angle of the detector (radians)
-    double phi;       ///< Azimuth angle of the detector (radians)
+    double azimuth;   ///< Azimuth angle of the detector (radians)
     double rho;       ///< Number density of scatters (angstroms^-3)
     double sigmaSc;   ///< Total scattering cross-section (barns)
     double sigmaAbs;  ///< Absorption cross-section at 2200m/s (barns)
     double cylRadius; ///< Radius of cylinder (m)
     double cylHeight; ///< Height of cylinder (m)
+    size_t msNEvents; ///< Number of second-order scatters per run
+    size_t msNRuns;   ///< Number of runs to average ms correction over
   };
 
   /// Constructor
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/SampleCorrections/RectangularBeamProfile.h b/Framework/Algorithms/inc/MantidAlgorithms/SampleCorrections/RectangularBeamProfile.h
index f9d9c874561e45ed6ef500d7a71102196acc66bb..567a72db3352d9c17a124397e66fe053710b8310 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/SampleCorrections/RectangularBeamProfile.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/SampleCorrections/RectangularBeamProfile.h
@@ -49,6 +49,7 @@ public:
   IBeamProfile::Ray
   generatePoint(Kernel::PseudoRandomNumberGenerator &rng,
                 const Geometry::BoundingBox &bounds) const override;
+  Geometry::BoundingBox defineActiveRegion(const API::Sample &) const override;
 
 private:
   const unsigned short m_upIdx;
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/SofQWNormalisedPolygon.h b/Framework/Algorithms/inc/MantidAlgorithms/SofQWNormalisedPolygon.h
index d9ed6965778b776a571b5e3176d5914328164df5..89ec0c5bf9440507ac54f4e7c2190875366d8586 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/SofQWNormalisedPolygon.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/SofQWNormalisedPolygon.h
@@ -93,7 +93,7 @@ private:
 
   /// Create the output workspace
   DataObjects::RebinnedOutput_sptr
-  setUpOutputWorkspace(API::MatrixWorkspace_const_sptr inputWorkspace,
+  setUpOutputWorkspace(const API::MatrixWorkspace &inputWorkspace,
                        const std::vector<double> &binParams,
                        std::vector<double> &newAxis);
 
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/SpatialGrouping.h b/Framework/Algorithms/inc/MantidAlgorithms/SpatialGrouping.h
index a2c4efe8403b836b61c6af485f830ce24e922930..a435ab9ec6e035d55ba9fde4d43b0bcfa232e5dc 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/SpatialGrouping.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/SpatialGrouping.h
@@ -78,13 +78,13 @@ private:
   void sortByDistance(std::map<specnum_t, Mantid::Kernel::V3D> &nearest,
                       const size_t noNeighbours);
   /// create expanded bounding box for our purposes
-  void createBox(boost::shared_ptr<const Geometry::IDetector> det,
-                 Geometry::BoundingBox &bndbox, double searchDist);
+  void createBox(const Geometry::IDetector &det, Geometry::BoundingBox &bndbox,
+                 double searchDist);
   /// grow dimensions of our bounding box to the factor
   void growBox(double &min, double &max, const double factor);
 
   /// map of detectors in the instrument
-  std::map<specnum_t, boost::shared_ptr<const Geometry::IDetector>> m_detectors;
+  std::map<specnum_t, Kernel::V3D> m_positions;
   /// flag which detectors are included in a group already
   std::set<specnum_t> m_included;
   /// first and last values for each group
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/Stitch1D.h b/Framework/Algorithms/inc/MantidAlgorithms/Stitch1D.h
index b1f3be04a836d408780db38b53e347bfb3af4cec..a11a01e463b5584b5ee45f701cd48c836cc0bc79 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/Stitch1D.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/Stitch1D.h
@@ -73,15 +73,6 @@ private:
   Mantid::API::MatrixWorkspace_sptr
   integration(Mantid::API::MatrixWorkspace_sptr &input, const double &start,
               const double &stop);
-  /// Perform multiplication over a range
-  Mantid::API::MatrixWorkspace_sptr
-  multiplyRange(Mantid::API::MatrixWorkspace_sptr &input, const int &startBin,
-                const int &endBin, const double &factor);
-  /// Perform multiplication over a range
-  Mantid::API::MatrixWorkspace_sptr
-  multiplyRange(Mantid::API::MatrixWorkspace_sptr &input, const int &startBin,
-                const double &factor);
-  /// Create a single valued workspace
   Mantid::API::MatrixWorkspace_sptr singleValueWS(double val);
   /// Calclate the weighted mean
   Mantid::API::MatrixWorkspace_sptr
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/Stitch1DMany.h b/Framework/Algorithms/inc/MantidAlgorithms/Stitch1DMany.h
index c9e040c667e0f2fbdeac7fe1d7ceb106abde2b74..8ebd8832b3dacdda2a00ff3908b7ff9f2786032c 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/Stitch1DMany.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/Stitch1DMany.h
@@ -1,8 +1,9 @@
 #ifndef MANTID_ALGORITHMS_STITCH1DMANY_H_
 #define MANTID_ALGORITHMS_STITCH1DMANY_H_
 
-#include "MantidKernel/System.h"
 #include "MantidAPI/Algorithm.h"
+#include "MantidAPI/WorkspaceGroup.h"
+#include "MantidKernel/System.h"
 
 namespace Mantid {
 namespace Algorithms {
@@ -45,25 +46,62 @@ public:
   }
   /// Validates algorithm inputs
   std::map<std::string, std::string> validateInputs() override;
+  /// Validates algorithm inputs for group workspaces
+  void validateGroupWorkspacesInputs();
+  /// Validates inputs common to group and non-group workspaces
+  std::map<std::string, std::string> validateCommonInputs();
+
+  /// Performs the Stitch1D algorithm at a specific workspace index
+  void doStitch1D(API::MatrixWorkspace_sptr lhsWS,
+                  API::MatrixWorkspace_sptr rhsWS, const size_t wsIndex,
+                  const std::vector<double> &startOverlaps,
+                  const std::vector<double> &endOverlaps,
+                  const std::vector<double> &params, const bool scaleRhsWS,
+                  const bool useManualScaleFactor,
+                  const double manualScaleFactor,
+                  API::MatrixWorkspace_sptr &outWS, double &outScaleFactor);
+
+  /// Performs the Stitch1DMany algorithm at a specific period
+  void doStitch1DMany(std::vector<API::WorkspaceGroup_sptr> inputWSGroups,
+                      const size_t period, const bool storeInADS,
+                      const std::vector<double> &startOverlaps,
+                      const std::vector<double> &endOverlaps,
+                      const std::vector<double> &params, const bool scaleRhsWS,
+                      const bool useManualScaleFactor,
+                      const double manualScaleFactor, std::string &outName,
+                      std::vector<double> &outScaleFactors);
 
 private:
   /// Overwrites Algorithm method.
   void init() override;
   /// Overwrites Algorithm method.
   void exec() override;
+  /// Override to deal with (multiperiod) workspace groups
+  bool checkGroups() override;
+  bool processGroups() override;
 
   // Data
-  std::vector<Mantid::API::Workspace_sptr> m_inputWorkspaces;
+
+  // A 2D matrix holding workspaces obtained from each workspace list/group
+  // First index is the period number
+  // Second index is the index of the workspace to stitch
+  std::vector<std::vector<API::Workspace_sptr>> m_inputWSMatrix;
+
+  // List holding each workspace group
+  std::vector<API::WorkspaceGroup_sptr> m_inputWSGroups;
+
   std::vector<double> m_startOverlaps;
   std::vector<double> m_endOverlaps;
   std::vector<double> m_params;
   std::vector<double> m_scaleFactors;
-  Mantid::API::Workspace_sptr m_outputWorkspace;
+  API::Workspace_sptr m_outputWorkspace;
 
-  size_t m_numWorkspaces = 0;
+  size_t m_numWSPerPeriod = 0;
+  size_t m_numWSPerGroup = 0;
   double m_manualScaleFactor = 1.0;
   bool m_scaleRHSWorkspace = true;
   bool m_useManualScaleFactor = false;
+  size_t m_scaleFactorFromPeriod = 0;
 };
 
 } // namespace Algorithms
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/SumSpectra.h b/Framework/Algorithms/inc/MantidAlgorithms/SumSpectra.h
index c05ada0cf5a0aa76410efde2ef38c854458ffcc8..e7a400f89d8bf819c04a151bcff8fa69bd5a4f8d 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/SumSpectra.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/SumSpectra.h
@@ -34,7 +34,7 @@ namespace Algorithms {
     @author Nick Draper, Tessella Support Services plc
     @date 22/01/2009
 
-    Copyright &copy; 2007-2010 ISIS Rutherford Appleton Laboratory, NScD Oak
+    Copyright &copy; 2007-2016 ISIS Rutherford Appleton Laboratory, NScD Oak
    Ridge National Laboratory & European Spallation Source
 
     This file is part of Mantid.
@@ -80,8 +80,7 @@ private:
                         API::Progress &progress, size_t &numSpectra,
                         size_t &numMasked, size_t &numZeros);
   /// Handle logic for Workspace2D workspaces
-  void doWorkspace2D(API::MatrixWorkspace_const_sptr localworkspace,
-                     API::ISpectrum &outSpec, API::Progress &progress,
+  void doWorkspace2D(API::ISpectrum &outSpec, API::Progress &progress,
                      size_t &numSpectra, size_t &numMasked, size_t &numZeros);
 
   // Overridden Algorithm methods
@@ -91,6 +90,9 @@ private:
                  std::set<int> &indices);
   specnum_t getOutputSpecNo(API::MatrixWorkspace_const_sptr localworkspace);
 
+  API::MatrixWorkspace_sptr
+  replaceSpecialValues(API::MatrixWorkspace_sptr inputWs);
+
   /// The output spectrum number
   specnum_t m_outSpecNum;
   /// The spectrum to start the integration from
@@ -99,14 +101,16 @@ private:
   int m_maxWsInd;
   /// Set true to keep monitors
   bool m_keepMonitors;
+  /// Set true to remove special values before processing
+  bool m_replaceSpecialValues;
   /// numberOfSpectra in the input
   int m_numberOfSpectra;
   /// Blocksize of the input workspace
   int m_yLength;
-  /// Set of indicies to sum
+  /// Set of indices to sum
   std::set<int> m_indices;
 
-  // if calculateing additional workspace with specially weighted averages is
+  // if calculating additional workspace with specially weighted averages is
   // necessary
   bool m_calculateWeightedSum;
 };
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/TimeAtSampleStrategyElastic.h b/Framework/Algorithms/inc/MantidAlgorithms/TimeAtSampleStrategyElastic.h
index 73506e47e47e4b28243cbb9b01cacce77640f9f7..65e9d987a97499a7cb41c187c1eecd6f82b06f2f 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/TimeAtSampleStrategyElastic.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/TimeAtSampleStrategyElastic.h
@@ -2,6 +2,7 @@
 #define MANTID_ALGORITHMS_TIMEATSAMPLESTRATEGYELASTIC_H_
 
 #include "MantidKernel/System.h"
+#include "MantidKernel/V3D.h"
 #include "MantidAlgorithms/TimeAtSampleStrategy.h"
 #include <boost/shared_ptr.hpp>
 
@@ -9,6 +10,7 @@ namespace Mantid {
 
 namespace API {
 class MatrixWorkspace;
+class SpectrumInfo;
 }
 namespace Algorithms {
 
@@ -44,6 +46,8 @@ public:
 
 private:
   boost::shared_ptr<const Mantid::API::MatrixWorkspace> m_ws;
+  const API::SpectrumInfo &m_spectrumInfo;
+  const Kernel::V3D m_beamDir;
 };
 
 } // namespace Algorithms
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/TimeAtSampleStrategyIndirect.h b/Framework/Algorithms/inc/MantidAlgorithms/TimeAtSampleStrategyIndirect.h
index 7308106047720b945a49f614d1f38a5649e1ac18..ae593a0b01b3760bd4ed9391f2c1990c53f2dcc9 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/TimeAtSampleStrategyIndirect.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/TimeAtSampleStrategyIndirect.h
@@ -9,6 +9,7 @@ namespace Mantid {
 
 namespace API {
 class MatrixWorkspace;
+class SpectrumInfo;
 }
 
 namespace Algorithms {
@@ -46,6 +47,7 @@ public:
 private:
   /// Workspace to operate on
   boost::shared_ptr<const Mantid::API::MatrixWorkspace> m_ws;
+  const API::SpectrumInfo &m_spectrumInfo;
 };
 
 } // namespace Algorithms
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/UnwrapMonitor.h b/Framework/Algorithms/inc/MantidAlgorithms/UnwrapMonitor.h
index c28cdd07658cb4de0142cdfa7317d958b45a5821..cac0457fc2891d919ef2e0766ff8c4199a83bc7b 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/UnwrapMonitor.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/UnwrapMonitor.h
@@ -70,17 +70,17 @@ private:
   void init() override;
   void exec() override;
 
-  const std::vector<int> unwrapX(MantidVec &newX, const int &spectrum,
+  const std::vector<int> unwrapX(std::vector<double> &newX, const int &spectrum,
                                  const double &Ld);
   std::pair<int, int>
   handleFrameOverlapped(const Mantid::HistogramData::HistogramX &xdata,
                         const double &Ld, std::vector<double> &tempX);
   void unwrapYandE(const API::MatrixWorkspace_sptr &tempWS, const int &spectrum,
-                   const std::vector<int> &rangeBounds, MantidVec &newY,
-                   MantidVec &newE);
+                   const std::vector<int> &rangeBounds,
+                   std::vector<double> &newY, std::vector<double> &newE);
   API::MatrixWorkspace_sptr rebin(const API::MatrixWorkspace_sptr &workspace,
                                   const double &min, const double &max,
-                                  const int &numBins);
+                                  const size_t &numBins);
 
   double m_conversionConstant; ///< The constant used in the conversion from TOF
   /// to wavelength
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/UnwrapSNS.h b/Framework/Algorithms/inc/MantidAlgorithms/UnwrapSNS.h
index cbfc39c88c6770efed6d594be5ccec43d0366e40..5cb54f2160739fc7571f27c6d740417fb9b4b6cd 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/UnwrapSNS.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/UnwrapSNS.h
@@ -68,8 +68,8 @@ private:
   void execEvent();
   void runMaskDetectors();
 
-  int unwrapX(const Mantid::HistogramData::HistogramX &, MantidVec &,
-              const double &Ld);
+  int unwrapX(const Mantid::HistogramData::HistogramX &,
+              std::vector<double> &dataout, const double &Ld);
   void getTofRangeData(const bool);
   double m_conversionConstant; ///< The constant used in the conversion from TOF
   /// to wavelength
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/VesuvioL1ThetaResolution.h b/Framework/Algorithms/inc/MantidAlgorithms/VesuvioL1ThetaResolution.h
index b50d282e9e0f59cdb756ddea03c681fc71c58236..fe50065651b4391505ad172f52a783eb9a34785d 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/VesuvioL1ThetaResolution.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/VesuvioL1ThetaResolution.h
@@ -48,7 +48,7 @@ private:
   void exec() override;
   void loadInstrument();
 
-  void calculateDetector(Mantid::Geometry::IDetector_const_sptr detector,
+  void calculateDetector(const Mantid::Geometry::IDetector &detector,
                          std::vector<double> &l1Values,
                          std::vector<double> &thetaValues);
   Mantid::API::MatrixWorkspace_sptr
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/WorkspaceJoiners.h b/Framework/Algorithms/inc/MantidAlgorithms/WorkspaceJoiners.h
index ea0d84102069b6329aff45738403d656ed384541..f65acd8e6dd4f87ef9414a1d55b884237f37d966 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/WorkspaceJoiners.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/WorkspaceJoiners.h
@@ -50,20 +50,20 @@ public:
   }
 
 protected:
-  API::MatrixWorkspace_sptr execWS2D(API::MatrixWorkspace_const_sptr ws1,
-                                     API::MatrixWorkspace_const_sptr ws2);
+  API::MatrixWorkspace_sptr execWS2D(const API::MatrixWorkspace &ws1,
+                                     const API::MatrixWorkspace &ws2);
   API::MatrixWorkspace_sptr execEvent();
 
   using Mantid::API::Algorithm::validateInputs;
-  void validateInputs(API::MatrixWorkspace_const_sptr ws1,
-                      API::MatrixWorkspace_const_sptr ws2);
-  void getMinMax(API::MatrixWorkspace_const_sptr ws, specnum_t &min,
+  void validateInputs(const API::MatrixWorkspace &ws1,
+                      const API::MatrixWorkspace &ws2);
+  void getMinMax(const API::MatrixWorkspace &ws, specnum_t &min,
                  specnum_t &max);
 
   /// Abstract method to be implemented in concrete algorithm classes
-  virtual void fixSpectrumNumbers(API::MatrixWorkspace_const_sptr ws1,
-                                  API::MatrixWorkspace_const_sptr ws2,
-                                  API::MatrixWorkspace_sptr output) = 0;
+  virtual void fixSpectrumNumbers(const API::MatrixWorkspace &ws1,
+                                  const API::MatrixWorkspace &ws2,
+                                  API::MatrixWorkspace &output) = 0;
 
   API::Progress *m_progress; ///< Progress reporting object
   DataObjects::EventWorkspace_const_sptr
diff --git a/Framework/Algorithms/src/AbsorptionCorrection.cpp b/Framework/Algorithms/src/AbsorptionCorrection.cpp
index 66feb650b51dc9c54b35be411b6bd351e9754e21..c34f897cc0e7acf326e42eabb3cf6ccb3f920cac 100644
--- a/Framework/Algorithms/src/AbsorptionCorrection.cpp
+++ b/Framework/Algorithms/src/AbsorptionCorrection.cpp
@@ -7,6 +7,7 @@
 #include "MantidGeometry/IDetector.h"
 #include "MantidGeometry/Instrument.h"
 #include "MantidGeometry/Objects/ShapeFactory.h"
+#include "MantidGeometry/Objects/Track.h"
 #include "MantidHistogramData/Interpolate.h"
 #include "MantidKernel/BoundedValidator.h"
 #include "MantidKernel/CompositeValidator.h"
diff --git a/Framework/Algorithms/src/AddLogDerivative.cpp b/Framework/Algorithms/src/AddLogDerivative.cpp
index a7cb098cce813b79aa405ac0aa3039ac4a52f619..f4319c91c251e686895e2b50a6bf7d9efbce2d9f 100644
--- a/Framework/Algorithms/src/AddLogDerivative.cpp
+++ b/Framework/Algorithms/src/AddLogDerivative.cpp
@@ -1,4 +1,5 @@
 #include "MantidAlgorithms/AddLogDerivative.h"
+#include "MantidKernel/Strings.h"
 #include "MantidKernel/System.h"
 #include "MantidKernel/TimeSeriesProperty.h"
 #include "MantidAPI/MatrixWorkspace.h"
diff --git a/Framework/Algorithms/src/AddPeak.cpp b/Framework/Algorithms/src/AddPeak.cpp
index 5bfac64cc3ae6120632d295a6abdd7f4de35fb0d..39201982676402f3437ebc15ad550abd4be7f37a 100644
--- a/Framework/Algorithms/src/AddPeak.cpp
+++ b/Framework/Algorithms/src/AddPeak.cpp
@@ -5,6 +5,7 @@
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/Run.h"
 #include "MantidGeometry/Crystal/IPeak.h"
+#include "MantidGeometry/Instrument/Goniometer.h"
 #include "MantidKernel/Unit.h"
 #include "MantidKernel/System.h"
 
diff --git a/Framework/Algorithms/src/AddSampleLog.cpp b/Framework/Algorithms/src/AddSampleLog.cpp
index 3cd7993d327076fd7e2e07776a022e7d78ffb346..5e3ebedb3e7deae6efe907c3b8ba402521c990af 100644
--- a/Framework/Algorithms/src/AddSampleLog.cpp
+++ b/Framework/Algorithms/src/AddSampleLog.cpp
@@ -1,9 +1,7 @@
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidAlgorithms/AddSampleLog.h"
 #include "MantidAPI/ExperimentInfo.h"
 #include "MantidAPI/Run.h"
+#include "MantidAPI/Workspace.h"
 #include "MantidKernel/Exception.h"
 #include "MantidKernel/ListValidator.h"
 #include "MantidKernel/MandatoryValidator.h"
diff --git a/Framework/Algorithms/src/AnyShapeAbsorption.cpp b/Framework/Algorithms/src/AnyShapeAbsorption.cpp
index 11918abc5234e4b1c0ef266e90340fdfcff9b04b..337a58ad4b662a98f70f06053a613c0fc89cf1e4 100644
--- a/Framework/Algorithms/src/AnyShapeAbsorption.cpp
+++ b/Framework/Algorithms/src/AnyShapeAbsorption.cpp
@@ -1,7 +1,9 @@
 #include "MantidAlgorithms/AnyShapeAbsorption.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/Run.h"
+#include "MantidGeometry/Objects/Object.h"
 #include "MantidGeometry/Objects/ShapeFactory.h"
+#include "MantidGeometry/Objects/Track.h"
 #include "MantidKernel/BoundedValidator.h"
 
 namespace Mantid {
diff --git a/Framework/Algorithms/src/AppendSpectra.cpp b/Framework/Algorithms/src/AppendSpectra.cpp
index 1f67a73f282e9f37642c87b32cfc15f1b0572428..fd6986a3d3dded2ecd05fdca9ec3af80a6a4caaf 100644
--- a/Framework/Algorithms/src/AppendSpectra.cpp
+++ b/Framework/Algorithms/src/AppendSpectra.cpp
@@ -7,7 +7,10 @@
 #include "MantidDataObjects/EventWorkspace.h"
 #include "MantidKernel/BoundedValidator.h"
 #include "MantidKernel/SingletonHolder.h"
+#include "MantidIndexing/IndexInfo.h"
+#include "MantidIndexing/MakeRange.h"
 
+using namespace Mantid::Indexing;
 using namespace Mantid::Kernel;
 using namespace Mantid::API;
 using namespace Mantid::DataObjects;
@@ -75,7 +78,7 @@ void AppendSpectra::exec() {
   bool ValidateInputs = this->getProperty("ValidateInputs");
   if (ValidateInputs) {
     // Check that the input workspaces meet the requirements for this algorithm
-    this->validateInputs(ws1, ws2);
+    this->validateInputs(*ws1, *ws2);
   }
 
   const bool mergeLogs = getProperty("MergeLogs");
@@ -99,9 +102,9 @@ void AppendSpectra::exec() {
     throw std::runtime_error(
         "Workspace2D's must have the same number of bins.");
 
-  MatrixWorkspace_sptr output = execWS2D(ws1, ws2);
+  MatrixWorkspace_sptr output = execWS2D(*ws1, *ws2);
   for (int i = 1; i < number; i++)
-    output = execWS2D(output, ws2);
+    output = execWS2D(*output, *ws2);
   if (mergeLogs)
     combineLogs(ws1->run(), ws2->run(), output->mutableRun());
 
@@ -118,9 +121,9 @@ void AppendSpectra::exec() {
  * @param ws2 The second workspace supplied to the algorithm.
  * @param output The workspace that is going to be returned by the algorithm.
  */
-void AppendSpectra::fixSpectrumNumbers(API::MatrixWorkspace_const_sptr ws1,
-                                       API::MatrixWorkspace_const_sptr ws2,
-                                       API::MatrixWorkspace_sptr output) {
+void AppendSpectra::fixSpectrumNumbers(const MatrixWorkspace &ws1,
+                                       const MatrixWorkspace &ws2,
+                                       MatrixWorkspace &output) {
   specnum_t ws1min;
   specnum_t ws1max;
   getMinMax(ws1, ws1min, ws1max);
@@ -133,22 +136,27 @@ void AppendSpectra::fixSpectrumNumbers(API::MatrixWorkspace_const_sptr ws1,
   if (ws2min > ws1max)
     return;
 
+  auto indexInfo = output.indexInfo();
+  indexInfo.setSpectrumNumbers(
+      makeRange(0, static_cast<specnum_t>(output.getNumberHistograms() - 1)));
+  output.setIndexInfo(indexInfo);
+
   const int yAxisNum = 1;
-  const auto yAxisWS1 = ws1->getAxis(yAxisNum);
-  const auto yAxisWS2 = ws2->getAxis(yAxisNum);
-  auto outputYAxis = output->getAxis(yAxisNum);
-  const auto ws1len = ws1->getNumberHistograms();
+  const auto yAxisWS1 = ws1.getAxis(yAxisNum);
+  const auto yAxisWS2 = ws2.getAxis(yAxisNum);
+  auto outputYAxis = output.getAxis(yAxisNum);
+  const auto ws1len = ws1.getNumberHistograms();
 
   const bool isTextAxis = yAxisWS1->isText() && yAxisWS2->isText();
   const bool isNumericAxis = yAxisWS1->isNumeric() && yAxisWS2->isNumeric();
 
   auto outputTextAxis = dynamic_cast<TextAxis *>(outputYAxis);
-  for (size_t i = 0; i < output->getNumberHistograms(); ++i) {
+  for (size_t i = 0; i < output.getNumberHistograms(); ++i) {
     if (isTextAxis) {
       // check if we're outside the spectra of the first workspace
       const std::string inputLabel =
           i < ws1len ? yAxisWS1->label(i) : yAxisWS2->label(i - ws1len);
-      outputTextAxis->setLabel(i, (inputLabel.size() > 0) ? inputLabel : "");
+      outputTextAxis->setLabel(i, !inputLabel.empty() ? inputLabel : "");
 
     } else if (isNumericAxis) {
       // check if we're outside the spectra of the first workspace
@@ -156,9 +164,6 @@ void AppendSpectra::fixSpectrumNumbers(API::MatrixWorkspace_const_sptr ws1,
           i < ws1len ? yAxisWS1->getValue(i) : yAxisWS2->getValue(i - ws1len);
       outputYAxis->setValue(i, inputVal);
     }
-
-    // append the spectra
-    output->getSpectrum(i).setSpectrumNo(specnum_t(i));
   }
 }
 
diff --git a/Framework/Algorithms/src/AsymmetryCalc.cpp b/Framework/Algorithms/src/AsymmetryCalc.cpp
index 571cdaadb55694d7c299e4fc067451131889ea54..dad9b1ba8c56109d49df94c1ac761c4fe4638464 100644
--- a/Framework/Algorithms/src/AsymmetryCalc.cpp
+++ b/Framework/Algorithms/src/AsymmetryCalc.cpp
@@ -2,8 +2,8 @@
 // Includes
 //----------------------------------------------------------------------
 #include "MantidAlgorithms/AsymmetryCalc.h"
-#include "MantidAPI/MatrixWorkspace.h"
-#include "MantidAPI/WorkspaceFactory.h"
+#include "MantidAPI/HistoWorkspace.h"
+#include "MantidDataObjects/WorkspaceCreation.h"
 #include "MantidKernel/ArrayProperty.h"
 
 #include <cmath>
@@ -127,10 +127,8 @@ void AsymmetryCalc::exec() {
   assert(tmpWS->blocksize() == blocksize);
 
   // Create a point data workspace with only one spectra for forward
-  API::MatrixWorkspace_sptr outputWS = API::WorkspaceFactory::Instance().create(
-      inputWS, 1, blocksize, blocksize);
-
-  outputWS->setPoints(0, tmpWS->points(forward));
+  auto outputWS = DataObjects::create<API::HistoWorkspace>(
+      *inputWS, 1, tmpWS->points(forward));
 
   // Calculate asymmetry for each time bin
   // F-aB / F+aB
@@ -168,7 +166,7 @@ void AsymmetryCalc::exec() {
   // Update Y axis units
   outputWS->setYUnit("Asymmetry");
 
-  setProperty("OutputWorkspace", outputWS);
+  setProperty("OutputWorkspace", std::move(outputWS));
 }
 
 } // namespace Algorithm
diff --git a/Framework/Algorithms/src/BinaryOperation.cpp b/Framework/Algorithms/src/BinaryOperation.cpp
index 03bab20ddfdbfd7002d491ddeb45a1cd1c11ed3c..2fd86a39f76ea5a4d539ff47b4411920f32964ec 100644
--- a/Framework/Algorithms/src/BinaryOperation.cpp
+++ b/Framework/Algorithms/src/BinaryOperation.cpp
@@ -1,15 +1,16 @@
 #include "MantidAlgorithms/BinaryOperation.h"
 #include "MantidAPI/FrameworkManager.h"
 #include "MantidAPI/Axis.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidAPI/WorkspaceProperty.h"
 #include "MantidAPI/WorkspaceOpOverloads.h"
 #include "MantidDataObjects/EventWorkspace.h"
 #include "MantidDataObjects/EventList.h"
 #include "MantidDataObjects/WorkspaceSingleValue.h"
-#include "MantidGeometry/IDetector.h"
 #include "MantidGeometry/Instrument/ParameterMap.h"
 #include "MantidKernel/Timer.h"
+#include "MantidKernel/Unit.h"
 
 #include <boost/make_shared.hpp>
 
@@ -397,7 +398,7 @@ std::string BinaryOperation::checkSizeCompatibility(
     return "";
   // Past this point, we require the X arrays to match. Note this only checks
   // the first spectrum
-  if (!WorkspaceHelpers::matchingBins(lhs, rhs, true)) {
+  if (!WorkspaceHelpers::matchingBins(*lhs, *rhs, true)) {
     return "X arrays must match when performing this operation on a 2D "
            "workspaces.";
   }
@@ -432,31 +433,28 @@ std::string BinaryOperation::checkSizeCompatibility(
  * Checks if the spectra at the given index of either input workspace is masked.
  * If so then the output spectra has zeroed data
  * and is also masked.
- * @param lhs :: A pointer to the left-hand operand
- * @param rhs :: A pointer to the right-hand operand
+ * @param lhsSpectrumInfo :: The LHS spectrum info object
+ * @param rhsSpectrumInfo :: The RHS spectrum info object
  * @param index :: The workspace index to check
  * @param out :: A pointer to the output workspace
+ * @param outSpectrumInfo :: The spectrum info object of `out`
  * @returns True if further processing is not required on the spectra, false if
  * the binary operation should be performed.
  */
-bool BinaryOperation::propagateSpectraMask(
-    const API::MatrixWorkspace_const_sptr lhs,
-    const API::MatrixWorkspace_const_sptr rhs, const int64_t index,
-    API::MatrixWorkspace_sptr out) {
+bool BinaryOperation::propagateSpectraMask(const SpectrumInfo &lhsSpectrumInfo,
+                                           const SpectrumInfo &rhsSpectrumInfo,
+                                           const int64_t index,
+                                           MatrixWorkspace &out,
+                                           SpectrumInfo &outSpectrumInfo) {
   bool continueOp(true);
-  IDetector_const_sptr det_lhs, det_rhs;
-  try {
-    det_lhs = lhs->getDetector(index);
-    det_rhs = rhs->getDetector(index);
-  } catch (std::runtime_error &) {
-  } catch (std::domain_error &) {
-    // try statement will throw a domain_error when the axis is not a spectra
-    // axis.
-    return continueOp;
-  }
-  if ((det_lhs && det_lhs->isMasked()) || (det_rhs && det_rhs->isMasked())) {
+
+  if ((lhsSpectrumInfo.hasDetectors(index) &&
+       lhsSpectrumInfo.isMasked(index)) ||
+      (rhsSpectrumInfo.hasDetectors(index) &&
+       rhsSpectrumInfo.isMasked(index))) {
     continueOp = false;
-    out->maskWorkspaceIndex(index);
+    out.getSpectrum(index).clearData();
+    PARALLEL_CRITICAL(setMasked) { outSpectrumInfo.setMasked(index, true); }
   }
   return continueOp;
 }
@@ -522,6 +520,9 @@ void BinaryOperation::doSingleColumn() {
   // value from each m_rhs 'spectrum'
   // and then calling the virtual function
   const int64_t numHists = m_lhs->getNumberHistograms();
+  auto &outSpectrumInfo = m_out->mutableSpectrumInfo();
+  auto &lhsSpectrumInfo = m_lhs->spectrumInfo();
+  auto &rhsSpectrumInfo = m_rhs->spectrumInfo();
   if (m_eout) {
     // ---- The output is an EventWorkspace ------
     PARALLEL_FOR_IF(Kernel::threadSafe(*m_lhs, *m_rhs, *m_out))
@@ -531,7 +532,8 @@ void BinaryOperation::doSingleColumn() {
       const double rhsE = m_rhs->readE(i)[0];
 
       // m_out->setX(i, m_lhs->refX(i)); //unnecessary - that was copied before.
-      if (propagateSpectraMask(m_lhs, m_rhs, i, m_out)) {
+      if (propagateSpectraMask(lhsSpectrumInfo, rhsSpectrumInfo, i, *m_out,
+                               outSpectrumInfo)) {
         performEventBinaryOperation(m_eout->getSpectrum(i), rhsY, rhsE);
       }
       m_progress->report(this->name());
@@ -547,7 +549,8 @@ void BinaryOperation::doSingleColumn() {
       const double rhsE = m_rhs->readE(i)[0];
 
       m_out->setX(i, m_lhs->refX(i));
-      if (propagateSpectraMask(m_lhs, m_rhs, i, m_out)) {
+      if (propagateSpectraMask(lhsSpectrumInfo, rhsSpectrumInfo, i, *m_out,
+                               outSpectrumInfo)) {
         // Get reference to output vectors here to break any sharing outside the
         // function call below
         // where the order of argument evaluation is not guaranteed (if it's
@@ -671,6 +674,10 @@ void BinaryOperation::do2D(bool mismatchedSpectra) {
   // TODO: Check if this works for event workspaces...
   propagateBinMasks(m_rhs, m_out);
 
+  auto &outSpectrumInfo = m_out->mutableSpectrumInfo();
+  auto &lhsSpectrumInfo = m_lhs->spectrumInfo();
+  auto &rhsSpectrumInfo = m_rhs->spectrumInfo();
+
   if (m_eout) {
     // ----------- The output is an EventWorkspace -------------
 
@@ -690,7 +697,8 @@ void BinaryOperation::do2D(bool mismatchedSpectra) {
             continue;
         } else {
           // Check for masking except when mismatched sizes
-          if (!propagateSpectraMask(m_lhs, m_rhs, i, m_out))
+          if (!propagateSpectraMask(lhsSpectrumInfo, rhsSpectrumInfo, i, *m_out,
+                                    outSpectrumInfo))
             continue;
         }
         // Reach here? Do the division
@@ -722,7 +730,8 @@ void BinaryOperation::do2D(bool mismatchedSpectra) {
             continue;
         } else {
           // Check for masking except when mismatched sizes
-          if (!propagateSpectraMask(m_lhs, m_rhs, i, m_out))
+          if (!propagateSpectraMask(lhsSpectrumInfo, rhsSpectrumInfo, i, *m_out,
+                                    outSpectrumInfo))
             continue;
         }
 
@@ -760,7 +769,8 @@ void BinaryOperation::do2D(bool mismatchedSpectra) {
           continue;
       } else {
         // Check for masking except when mismatched sizes
-        if (!propagateSpectraMask(m_lhs, m_rhs, i, m_out))
+        if (!propagateSpectraMask(lhsSpectrumInfo, rhsSpectrumInfo, i, *m_out,
+                                  outSpectrumInfo))
           continue;
       }
       // Reach here? Do the division
diff --git a/Framework/Algorithms/src/CalMuonDeadTime.cpp b/Framework/Algorithms/src/CalMuonDeadTime.cpp
index 95a7162e9ac7a865ff69b99eea240db943a69e82..281cb8320f51dbb08252d1af0dcab11973f11b48 100644
--- a/Framework/Algorithms/src/CalMuonDeadTime.cpp
+++ b/Framework/Algorithms/src/CalMuonDeadTime.cpp
@@ -1,4 +1,5 @@
 #include "MantidAlgorithms/CalMuonDeadTime.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/IFunction.h"
 #include "MantidAPI/ITableWorkspace.h"
 #include "MantidAPI/MatrixWorkspace.h"
diff --git a/Framework/Algorithms/src/CalMuonDetectorPhases.cpp b/Framework/Algorithms/src/CalMuonDetectorPhases.cpp
index f2a24abf4a3097090af822669a35baf969d05eca..869e2d8b5a71d98ea6fbdc3408f3b0aabc168448 100644
--- a/Framework/Algorithms/src/CalMuonDetectorPhases.cpp
+++ b/Framework/Algorithms/src/CalMuonDetectorPhases.cpp
@@ -9,9 +9,11 @@
 #include "MantidAPI/MultiDomainFunction.h"
 #include "MantidAPI/Run.h"
 #include "MantidAPI/TableRow.h"
+#include "MantidIndexing/IndexInfo.h"
 #include "MantidKernel/ArrayProperty.h"
 #include "MantidKernel/PhysicalConstants.h"
 #include "MantidAPI/WorkspaceFactory.h"
+#include "MantidAPI/WorkspaceGroup.h"
 
 namespace Mantid {
 namespace Algorithms {
@@ -154,6 +156,8 @@ void CalMuonDetectorPhases::fitWorkspace(const API::MatrixWorkspace_sptr &ws,
   resTab->addColumn("double", "Asymmetry");
   resTab->addColumn("double", "Phase");
 
+  const auto &indexInfo = ws->indexInfo();
+
   // Loop through fitting all spectra individually
   const static std::string success = "success";
   for (int wsIndex = 0; wsIndex < nhist; wsIndex++) {
@@ -181,8 +185,7 @@ void CalMuonDetectorPhases::fitWorkspace(const API::MatrixWorkspace_sptr &ws,
     // Now we have our fitting results stored in tab
     // but we need to extract the relevant information, i.e.
     // the detector phases (parameter 'p') and asymmetries ('A')
-    const auto &spectrum = ws->getSpectrum(static_cast<size_t>(wsIndex));
-    extractDetectorInfo(tab, resTab, spectrum.getSpectrumNo());
+    extractDetectorInfo(tab, resTab, indexInfo.spectrumNumber(wsIndex));
   }
 }
 
diff --git a/Framework/Algorithms/src/CalculateCountRate.cpp b/Framework/Algorithms/src/CalculateCountRate.cpp
index 2f95a7a4bf5a83aeb14b184bf0e5c8eac3a74032..4aee86d8bef1906027c04d7710db7efa4794c817 100644
--- a/Framework/Algorithms/src/CalculateCountRate.cpp
+++ b/Framework/Algorithms/src/CalculateCountRate.cpp
@@ -4,6 +4,7 @@
 #include "MantidKernel/BoundedValidator.h"
 #include "MantidKernel/TimeSeriesProperty.h"
 #include "MantidKernel/ListValidator.h"
+#include "MantidKernel/Unit.h"
 #include "MantidKernel/UnitFactory.h"
 #include "MantidKernel/MandatoryValidator.h"
 #include "MantidKernel/make_unique.h"
@@ -150,7 +151,7 @@ void CalculateCountRate::exec() {
   DataObjects::EventWorkspace_sptr sourceWS = getProperty("Workspace");
   API::EventType et = sourceWS->getEventType();
   if (et == API::EventType::WEIGHTED_NOTIME) {
-    throw std::runtime_error("Event workspace " + sourceWS->name() +
+    throw std::runtime_error("Event workspace " + sourceWS->getName() +
                              " contains events without necessary frame "
                              "information. Can not process counting rate");
   }
@@ -509,7 +510,7 @@ void CalculateCountRate::setSourceWSandXRanges(
   API::MatrixWorkspace_sptr wst;
   if (unit->unitID() != RangeUnits) {
     auto conv = createChildAlgorithm("ConvertUnits", 0, 1);
-    std::string wsName = InputWorkspace->name();
+    std::string wsName = InputWorkspace->getName();
     if (wsName.empty()) {
       wsName = "_CountRate_UnitsConverted";
     } else {
diff --git a/Framework/Algorithms/src/CalculateDIFC.cpp b/Framework/Algorithms/src/CalculateDIFC.cpp
index 9ba0e4d740fbedb1fb121fb9e3dad455396fa9dc..9aeeaecce80eb65034bf7e45d5a57cf5e25912c3 100644
--- a/Framework/Algorithms/src/CalculateDIFC.cpp
+++ b/Framework/Algorithms/src/CalculateDIFC.cpp
@@ -70,21 +70,18 @@ void CalculateDIFC::exec() {
     outputWs->setTitle("DIFC workspace");
   }
 
-  Instrument_const_sptr instrument = inputWs->getInstrument();
-
   double l1;
   Kernel::V3D beamline, samplePos;
   double beamlineNorm;
 
-  instrument->getInstrumentParameters(l1, beamline, beamlineNorm, samplePos);
+  inputWs->getInstrument()->getInstrumentParameters(l1, beamline, beamlineNorm,
+                                                    samplePos);
 
-  // To get all the detector ID's
-  detid2det_map allDetectors;
-  instrument->getDetectors(allDetectors);
+  const auto &detectorInfo = inputWs->detectorInfo();
 
-  API::Progress progress(this, 0, 1, allDetectors.size());
+  API::Progress progress(this, 0, 1, detectorInfo.size());
   calculate(progress, outputWs, offsetsWs, l1, beamlineNorm, beamline,
-            samplePos, allDetectors);
+            samplePos, detectorInfo);
 
   setProperty("OutputWorkspace", outputWs);
 }
@@ -94,24 +91,24 @@ void CalculateDIFC::calculate(API::Progress &progress,
                               DataObjects::OffsetsWorkspace_sptr &offsetsWS,
                               double l1, double beamlineNorm,
                               Kernel::V3D &beamline, Kernel::V3D &samplePos,
-                              detid2det_map &allDetectors) {
+                              const API::DetectorInfo &detectorInfo) {
   SpecialWorkspace2D_sptr localWS =
       boost::dynamic_pointer_cast<SpecialWorkspace2D>(outputWs);
 
+  const auto &detectorIDs = detectorInfo.detectorIDs();
+
   // Now go through all
-  detid2det_map::const_iterator it = allDetectors.begin();
-  for (; it != allDetectors.end(); ++it) {
-    Geometry::IDetector_const_sptr det = it->second;
-    if ((!det->isMasked()) && (!det->isMonitor())) {
-      const detid_t detID = it->first;
+  for (size_t i = 0; i < detectorInfo.size(); ++i) {
+    if ((!detectorInfo.isMasked(i)) && (!detectorInfo.isMonitor(i))) {
       double offset = 0.;
       if (offsetsWS)
-        offset = offsetsWS->getValue(detID, 0.);
+        offset = offsetsWS->getValue(detectorIDs[i], 0.);
 
       double difc = Geometry::Instrument::calcConversion(
-          l1, beamline, beamlineNorm, samplePos, det, offset);
+          l1, beamline, beamlineNorm, samplePos, detectorInfo.position(i),
+          offset);
       difc = 1. / difc; // calcConversion gives 1/DIFC
-      localWS->setValue(detID, difc);
+      localWS->setValue(detectorIDs[i], difc);
     }
 
     progress.report("Calculate DIFC");
diff --git a/Framework/Algorithms/src/CalculateEfficiency.cpp b/Framework/Algorithms/src/CalculateEfficiency.cpp
index 65a086e197f0e222b282df61b3601b58b349da3c..315d8294f540d93c3eb61ae82794b560a67393ff 100644
--- a/Framework/Algorithms/src/CalculateEfficiency.cpp
+++ b/Framework/Algorithms/src/CalculateEfficiency.cpp
@@ -103,7 +103,7 @@ void CalculateEfficiency::exec() {
   rebinnedWS = childAlg->getProperty("OutputWorkspace");
 
   outputWS = WorkspaceFactory::Instance().create(rebinnedWS);
-  WorkspaceFactory::Instance().initializeFromParent(inputWS, outputWS, false);
+  WorkspaceFactory::Instance().initializeFromParent(*inputWS, *outputWS, false);
   for (int i = 0; i < static_cast<int>(rebinnedWS->getNumberHistograms());
        i++) {
     outputWS->setSharedX(i, rebinnedWS->sharedX(i));
@@ -311,8 +311,11 @@ void CalculateEfficiency::maskComponent(MatrixWorkspace &ws,
       }
     }
     auto indexList = ws.getIndicesFromDetectorIDs(detectorList);
-    for (const auto &idx : indexList)
-      ws.maskWorkspaceIndex(idx);
+    auto &spectrumInfo = ws.mutableSpectrumInfo();
+    for (const auto &idx : indexList) {
+      ws.getSpectrum(idx).clearData();
+      spectrumInfo.setMasked(idx, true);
+    }
   } catch (std::exception &) {
     g_log.warning("Expecting the component " + componentName +
                   " to be a CompAssembly, e.g., a bank. Component not masked!");
diff --git a/Framework/Algorithms/src/CalculateFlatBackground.cpp b/Framework/Algorithms/src/CalculateFlatBackground.cpp
index d71caca3341def0d2433efedee1d40853ac25aba..c93e30a349b793bd5272f51ab2b6fd7880dfed21 100644
--- a/Framework/Algorithms/src/CalculateFlatBackground.cpp
+++ b/Framework/Algorithms/src/CalculateFlatBackground.cpp
@@ -26,6 +26,7 @@ DECLARE_ALGORITHM(CalculateFlatBackground)
 using namespace Kernel;
 using namespace API;
 
+/// Enumeration for the different operating modes.
 enum class Modes { LINEAR_FIT, MEAN, MOVING_AVERAGE };
 
 void CalculateFlatBackground::init() {
@@ -97,16 +98,16 @@ void CalculateFlatBackground::exec() {
   API::MatrixWorkspace_const_sptr inputWS = getProperty("InputWorkspace");
 
   // Copy over all the data
-  const int numHists = static_cast<int>(inputWS->getNumberHistograms());
-  const int blocksize = static_cast<int>(inputWS->blocksize());
+  const size_t numHists = inputWS->getNumberHistograms();
+  const size_t blocksize = inputWS->blocksize();
 
   if (blocksize == 1)
     throw std::runtime_error("CalculateFlatBackground with only one bin is "
                              "not possible.");
 
-  m_skipMonitors = getProperty("SkipMonitors");
-  m_nullifyNegative = getProperty("NullifyNegativeValues");
-  std::string modeString = getProperty("Mode");
+  const bool skipMonitors = getProperty("SkipMonitors");
+  const bool nullifyNegative = getProperty("NullifyNegativeValues");
+  const std::string modeString = getProperty("Mode");
   Modes mode = Modes::LINEAR_FIT;
   if (modeString == "Mean") {
     mode = Modes::MEAN;
@@ -136,7 +137,7 @@ void CalculateFlatBackground::exec() {
     if (windowWidth <= 0) {
       throw std::runtime_error("AveragingWindowWidth zero or negative");
     }
-    if (blocksize < windowWidth) {
+    if (blocksize < static_cast<size_t>(windowWidth)) {
       throw std::runtime_error("AveragingWindowWidth is larger than the number "
                                "of bins in InputWorkspace");
     }
@@ -145,189 +146,142 @@ void CalculateFlatBackground::exec() {
 
   std::vector<int> wsInds = getProperty("WorkspaceIndexList");
   // check if the user passed an empty list, if so all of spec will be processed
-  getWsInds(wsInds, numHists);
+  if (wsInds.empty()) {
+    wsInds.resize(numHists);
+    std::iota(wsInds.begin(), wsInds.end(), 0);
+  }
 
   // Are we removing the background?
   const bool removeBackground =
       std::string(getProperty("outputMode")) == "Subtract Background";
 
   // Initialize the progress reporting object
-  m_progress = new Progress(this, 0.0, 0.2, numHists);
+  m_progress.reset(new Progress(this, 0.0, 0.2, numHists));
 
   MatrixWorkspace_sptr outputWS = getProperty("OutputWorkspace");
   // If input and output workspaces are not the same, create a new workspace for
   // the output
   if (outputWS != inputWS) {
     outputWS = WorkspaceFactory::Instance().create(inputWS);
-    PARALLEL_FOR_IF(Kernel::threadSafe(*inputWS, *outputWS))
-    for (int i = 0; i < numHists; ++i) {
-      PARALLEL_START_INTERUPT_REGION
-      outputWS->setHistogram(i, inputWS->histogram(i));
-      m_progress->report();
-      PARALLEL_END_INTERUPT_REGION
-    }
-    PARALLEL_CHECK_INTERUPT_REGION
   }
 
-  // Only convert histogram data to a distribution
-  convertToDistribution(outputWS);
-
-  // these are used to report information to the user, one progress update for
-  // each percent and a report on the size of the background found
-  double prg(0.2), backgroundTotal(0);
-  const double toFitsize(static_cast<double>(wsInds.size()));
-  const int progStep(static_cast<int>(ceil(toFitsize / 80.0)));
-
-  // Now loop over the required spectra
-  std::vector<int>::const_iterator specIt;
-  // local cache for global variable
-  bool skipMonitors(m_skipMonitors);
-  const auto &spectrumInfo = outputWS->spectrumInfo();
-  for (specIt = wsInds.begin(); specIt != wsInds.end(); ++specIt) {
-    const int currentSpec = *specIt;
-    try {
-      if (skipMonitors) {
-        if (!spectrumInfo.hasDetectors(currentSpec)) {
-          // Do nothing.
-          // not every spectra is the monitor or detector, some spectra have no
-          // instrument components attached.
-          g_log.information(" Can not find detector for spectra N: " +
-                            std::to_string(currentSpec) +
-                            " Processing background anyway\n");
-        } else {
-          if (spectrumInfo.isMonitor(currentSpec))
-            continue;
-        }
+  // For logging purposes.
+  double backgroundTotal = 0;
+  size_t calculationCount = 0;
+
+  PARALLEL_FOR_IF(Kernel::threadSafe(*inputWS, *outputWS))
+  for (int64_t i = 0; i < static_cast<int64_t>(numHists); ++i) {
+    PARALLEL_START_INTERUPT_REGION
+    // Extract a histogram from inputWS, work on it and, finally, put it to
+    // outputWS.
+    auto histogram = inputWS->histogram(i);
+    bool wasCounts = false;
+    if (histogram.yMode() == HistogramData::Histogram::YMode::Counts) {
+      wasCounts = true;
+      histogram.convertToFrequencies();
+    }
+    bool skipCalculation =
+        std::find(wsInds.cbegin(), wsInds.cend(), i) == wsInds.cend();
+    if (!skipCalculation && skipMonitors) {
+      const auto &spectrumInfo = inputWS->spectrumInfo();
+      if (!spectrumInfo.hasDetectors(i)) {
+        // Do nothing.
+        // not every spectra is the monitor or detector, some spectra have no
+        // instrument components attached.
+        g_log.information(" Can not find detector for spectra N: " +
+                          std::to_string(i) +
+                          " Processing background anyway\n");
+      } else if (spectrumInfo.isMonitor(i)) {
+        skipCalculation = true;
       }
-
+    }
+    double background = 0;
+    double variance = 0;
+    if (!skipCalculation) {
+      ++calculationCount;
       // Now call the function the user selected to calculate the background
-      double background = -1;
       switch (mode) {
       case Modes::LINEAR_FIT:
-        background = LinearFit(outputWS, currentSpec, startX, endX);
+        LinearFit(histogram, background, variance, startX, endX);
         break;
       case Modes::MEAN:
-        background = Mean(outputWS, currentSpec, startX, endX);
+        Mean(histogram, background, variance, startX, endX);
         break;
       case Modes::MOVING_AVERAGE:
-        background = MovingAverage(outputWS, currentSpec, windowWidth);
+        MovingAverage(histogram, background, variance, windowWidth);
         break;
       }
-      if (background < 0) {
-        g_log.warning() << "Problem with calculating the background number of "
-                           "counts spectrum with index " << currentSpec
-                        << ". The spectrum has been left unchanged.\n";
-        g_log.debug() << "The background for spectra index " << currentSpec
-                      << "was calculated to be " << background << '\n';
-        continue;
-      } else { // only used for the logging that gets done at the end
-        backgroundTotal += background;
+    }
+    if (background < 0) {
+      g_log.debug() << "The background for spectra index " << i
+                    << "was calculated to be " << background << '\n';
+      g_log.warning() << "Problem with calculating the background number of "
+                         "counts spectrum with index " << i << ".";
+      if (removeBackground) {
+        g_log.warning() << " The spectrum has been left unchanged.\n";
+      } else {
+        g_log.warning() << " The output background has been set to zero.\n";
       }
-
-      // Get references to the current spectrum
-      auto &Y = outputWS->mutableY(currentSpec);
-      auto &E = outputWS->mutableE(currentSpec);
-      // Now subtract the background from the data
-      for (int j = 0; j < blocksize; ++j) {
-        if (removeBackground) {
-          Y[j] -= background;
-        } else {
-          Y[j] = background;
+    } else {
+      backgroundTotal += background;
+    }
+    HistogramData::Histogram outHistogram(histogram);
+    auto &ys = outHistogram.mutableY();
+    auto &es = outHistogram.mutableE();
+    if (removeBackground) {
+      // When subtracting backgrounds, act only if background is positive.
+      if (background >= 0) {
+        for (size_t j = 0; j < ys.size(); ++j) {
+          double val = ys[j] - background;
+          double err = std::sqrt(es[j] * es[j] + variance);
+          if (nullifyNegative && (val < 0)) {
+            val = 0;
+            // The error estimate must go up in this nonideal situation and the
+            // value of background is a good estimate for it. However, don't
+            // reduce the error if it was already more than that
+            err = es[j] > background ? es[j] : background;
+          }
+          ys[j] = val;
+          es[j] = err;
         }
-        // remove negative values
-        if (m_nullifyNegative && Y[j] < 0.0) {
-          Y[j] = 0;
-          // The error estimate must go up in this nonideal situation and the
-          // value of background is a good estimate for it. However, don't
-          // reduce the error if it was already more than that
-          E[j] = E[j] > background ? E[j] : background;
+      }
+    } else {
+      for (size_t j = 0; j < ys.size(); ++j) {
+        const double originalVal = histogram.y()[j];
+        if (background < 0) {
+          ys[j] = 0;
+          es[j] = 0;
+        } else if (nullifyNegative && (background > originalVal)) {
+          ys[j] = originalVal;
+          es[j] = es[j] > background ? es[j] : background;
+        } else {
+          ys[j] = background;
+          es[j] = std::sqrt(variance);
         }
       }
-    } catch (std::exception &) {
-      g_log.error() << "Error processing the spectrum with index "
-                    << currentSpec << '\n';
-      throw;
     }
-
-    // make regular progress reports and check for canceling the algorithm
-    if (static_cast<int>(wsInds.end() - wsInds.begin()) % progStep == 0) {
-      interruption_point();
-      prg += (progStep * 0.7 / toFitsize);
-      progress(prg);
+    if (wasCounts) {
+      outHistogram.convertToCounts();
     }
-  } // Loop over spectra to be fitted
-
-  g_log.debug() << toFitsize << " spectra corrected\n";
-  if (!m_convertedFromRawCounts) {
-    g_log.information() << "The mean background over the spectra region was "
-                        << backgroundTotal / toFitsize << " per bin\n";
-  } else {
-    g_log.information()
-        << "Background corrected in uneven bin sized workspace\n";
+    outputWS->setHistogram(i, outHistogram);
+    m_progress->report();
+    PARALLEL_END_INTERUPT_REGION
   }
+  PARALLEL_CHECK_INTERUPT_REGION
 
-  restoreDistributionState(outputWS);
-
+  g_log.debug() << calculationCount << " spectra corrected\n";
+  g_log.information() << "The mean background was "
+                      << backgroundTotal / static_cast<double>(calculationCount)
+                      << ".\n";
   // Assign the output workspace to its property
   setProperty("OutputWorkspace", outputWS);
 }
-/** Converts only if the workspace requires it: workspaces that are
-* distributions or have constant width bins
-*  aren't affected. A flag is set if there was a change allowing the workspace
-* to be converted back
-*  @param workspace the workspace to check and possibly convert
-*/
-void CalculateFlatBackground::convertToDistribution(
-    API::MatrixWorkspace_sptr workspace) {
-  if (workspace->isDistribution()) {
-    return;
-  }
 
-  bool variationFound(false);
-  // the number of spectra we need to check to assess if the bin widths are all
-  // the same
-  const size_t total = WorkspaceHelpers::commonBoundaries(workspace)
-                           ? 1
-                           : workspace->getNumberHistograms();
-
-  MantidVec adjacents(workspace->x(0).size() - 1);
-  for (std::size_t i = 0; i < total; ++i) {
-    auto &X = workspace->x(i);
-    // Calculate bin widths
-    std::adjacent_difference(X.begin() + 1, X.end(), adjacents.begin());
-    // the first entry from adjacent difference is just a copy of the first
-    // entry in the input vector, ignore this.
-    if (X.size() > 1) {
-      MantidVec widths(adjacents.begin() + 1, adjacents.end());
-      if (!VectorHelper::isConstantValue(widths)) {
-        variationFound = true;
-        break;
-      }
-    }
-  }
-
-  if (variationFound) {
-    // after all the above checks the conclusion is we need the conversion
-    WorkspaceHelpers::makeDistribution(workspace, true);
-    m_convertedFromRawCounts = true;
-  }
-}
-/** Converts the workspace to a raw counts workspace if the flag
-* m_convertedFromRawCounts
-*  is set
-*  @param workspace the workspace to, possibly, convert
-*/
-void CalculateFlatBackground::restoreDistributionState(
-    API::MatrixWorkspace_sptr workspace) {
-  if (m_convertedFromRawCounts) {
-    WorkspaceHelpers::makeDistribution(workspace, false);
-    m_convertedFromRawCounts = false;
-  }
-}
-/** Checks that the range parameters have been set correctly
-*  @param startX :: The starting point
-*  @param endX ::   The ending point
-*  @throw std::invalid_argument If XMin or XMax are not set, or XMax is less
+/**
+* Checks that the range parameters have been set correctly.
+* @param startX the starting point
+* @param endX the ending point
+* @throw std::invalid_argument if XMin or XMax are not set, or XMax is less
 * than XMin
 */
 void CalculateFlatBackground::checkRange(double &startX, double &endX) {
@@ -342,46 +296,31 @@ void CalculateFlatBackground::checkRange(double &startX, double &endX) {
   }
 }
 
-/** checks if the array is empty and if so fills it with all the index numbers
-*  in the workspace. Non-empty arrays are left untouched
-*  @param output :: the array to be checked
-*  @param workspaceTotal :: required to be the total number of spectra in the
-* workspace
-*/
-void CalculateFlatBackground::getWsInds(std::vector<int> &output,
-                                        const int workspaceTotal) {
-  if (!output.empty()) {
-    return;
-  }
-
-  output.resize(workspaceTotal);
-  for (int i = 0; i < workspaceTotal; ++i) {
-    output[i] = i;
-  }
-}
-/** Gets the mean number of counts in each bin the background region and the
-* variance (error^2) of that number. Adjusts the y errors accordingly.
-*  @param WS :: points to the input workspace
-*  @param wsInd :: index of the spectrum to process
-*  @param startX :: a X-value in the first bin that will be considered, must not
+/**
+* Gets the mean number of counts in each bin the background region and the
+* variance (error^2) of that number.
+* @param histogram the histogram to operate on
+* @param background an output variable for the calculated background
+* @param variance an output variable for background's variance.
+* @param startX an X-value in the first bin that will be considered, must not
 * be greater endX
-*  @param endX :: a X-value in the last bin that will be considered, must not
+* @param endX an X-value in the last bin that will be considered, must not
 * less than startX
-*  @return the mean number of counts in each bin the background region
-*  @throw out_of_range if either startX or endX are out of the range of X-values
+* @throw out_of_range if either startX or endX are out of the range of X-values
 * in the specified spectrum
-*  @throw invalid_argument if endX has the value of first X-value one of the
+* @throw invalid_argument if endX has the value of first X-value one of the
 * spectra
 */
-double CalculateFlatBackground::Mean(const API::MatrixWorkspace_sptr WS,
-                                     const int wsInd, const double startX,
-                                     const double endX) const {
-  auto &XS = WS->x(wsInd);
-  auto &YS = WS->y(wsInd);
-  auto &ES = WS->mutableE(wsInd);
+void CalculateFlatBackground::Mean(const HistogramData::Histogram &histogram,
+                                   double &background, double &variance,
+                                   const double startX,
+                                   const double endX) const {
+  const auto &XS = histogram.x();
+  const auto &YS = histogram.y();
+  const auto &ES = histogram.e();
   // the function checkRange should already have checked that startX <= endX,
   // but we still need to check values weren't out side the ranges
-  if (endX > XS.back() || startX < XS.front()) {
+  if ((endX > XS.back()) || (startX < XS.front())) {
     throw std::out_of_range("Either the property startX or endX is outside the "
                             "range of X-values present in one of the specified "
                             "spectra");
@@ -412,39 +351,33 @@ double CalculateFlatBackground::Mean(const API::MatrixWorkspace_sptr WS,
   const double numBins = static_cast<double>(1 + endInd - startInd);
   // the +1 here is because the accumulate() stops one before the location of
   // the last iterator
-  double background =
+  background =
       std::accumulate(YS.begin() + startInd, YS.begin() + endInd + 1, 0.0) /
       numBins;
   // The error on the total number of background counts in the background region
   // is taken as the sqrt the total number counts. To get the the error on the
   // counts in each bin just divide this by the number of bins. The variance =
   // error^2 that is the total variance divide by the number of bins _squared_.
-  const double variance =
-      std::accumulate(ES.begin() + startInd, ES.begin() + endInd + 1, 0.0,
-                      VectorHelper::SumSquares<double>()) /
-      (numBins * numBins);
-  // adjust the errors using the variance (variance = error^2)
-  std::transform(ES.begin(), ES.end(), ES.begin(),
-                 std::bind2nd(VectorHelper::AddVariance<double>(), variance));
-  // return mean number of counts in each bin, the sum of the number of counts
-  // in all the bins divided by the number of bins used in that sum
-  return background;
+  variance = std::accumulate(ES.begin() + startInd, ES.begin() + endInd + 1,
+                             0.0, VectorHelper::SumSquares<double>()) /
+             (numBins * numBins);
 }
 
 /**
 * Uses linear algorithm to do the fitting.
-*
-* @param WS The workspace to fit
-* @param spectrum The spectrum number to fit, using the workspace numbering of
-*the spectra
-* @param startX An X value in the first bin to be included in the fit
-* @param endX An X value in the last bin to be included in the fit
-*
-* @return The value of the flat background
+* @param histogram the histogram to fit
+* @param background an output variable for the calculated background
+* @param variance an output variable for background's variance, currently always
+* zero.
+* @param startX an X value in the first bin to be included in the fit
+* @param endX an X value in the last bin to be included in the fit
 */
-double CalculateFlatBackground::LinearFit(API::MatrixWorkspace_sptr WS,
-                                          int spectrum, double startX,
-                                          double endX) {
+void CalculateFlatBackground::LinearFit(
+    const HistogramData::Histogram &histogram, double &background,
+    double &variance, const double startX, const double endX) {
+  MatrixWorkspace_sptr WS = WorkspaceFactory::Instance().create(
+      "Workspace2D", 1, histogram.x().size(), histogram.y().size());
+  WS->setHistogram(0, histogram);
   IAlgorithm_sptr childAlg = createChildAlgorithm("Fit");
 
   IFunction_sptr func =
@@ -453,7 +386,7 @@ double CalculateFlatBackground::LinearFit(API::MatrixWorkspace_sptr WS,
 
   childAlg->setProperty<MatrixWorkspace_sptr>("InputWorkspace", WS);
   childAlg->setProperty<bool>("CreateOutput", true);
-  childAlg->setProperty<int>("WorkspaceIndex", spectrum);
+  childAlg->setProperty<int>("WorkspaceIndex", 0);
   childAlg->setProperty<double>("StartX", startX);
   childAlg->setProperty<double>("EndX", endX);
   // Default minimizer doesn't work properly even on the easiest cases,
@@ -465,7 +398,8 @@ double CalculateFlatBackground::LinearFit(API::MatrixWorkspace_sptr WS,
   std::string outputStatus = childAlg->getProperty("OutputStatus");
   if (outputStatus != "success") {
     g_log.warning("Unable to successfully fit the data: " + outputStatus);
-    return -1.0;
+    background = -1;
+    return;
   }
 
   Mantid::API::ITableWorkspace_sptr output =
@@ -484,41 +418,48 @@ double CalculateFlatBackground::LinearFit(API::MatrixWorkspace_sptr WS,
 
   // Calculate the value of the flat background by taking the value at the
   // centre point of the fit
-  return slope * centre + intercept;
+  background = slope * centre + intercept;
+  // ATM we don't calculate the error here.
+  variance = 0;
 }
 
 /**
 * Utilizes cyclic boundary conditions when calculating the
 * average in the window.
-* @param WS The workspace to operate on
-* @param wsIndex The workspace index to operate on
-* @param windowWidth Width of the averaging window in bins
-* @return Minimum
+* @param histogram the histogram to operate on
+* @param background an output variable for the calculated background
+* @param variance an output variable for background's variance.
+* @param windowWidth the width of the averaging window in bins
 */
-double
-CalculateFlatBackground::MovingAverage(API::MatrixWorkspace_const_sptr WS,
-                                       int wsIndex, size_t windowWidth) const {
-  const auto &ys = WS->y(wsIndex);
+void CalculateFlatBackground::MovingAverage(
+    const HistogramData::Histogram &histogram, double &background,
+    double &variance, const size_t windowWidth) const {
+  const auto &ys = histogram.y();
+  const auto &es = histogram.e();
   double currentMin = std::numeric_limits<double>::max();
-
-  // Initialize sum.
-  double sum = 0;
-  for (size_t i = 0; i < windowWidth; ++i) {
-    sum += ys[i];
-  }
-  // When moving the window, we need to subtract the single point "falling off"
-  // while adding a new point. Saves us summing all the points in the window.
-  for (size_t i = 0; i < ys.size() - 1; ++i) {
-    currentMin = std::min(currentMin, sum / static_cast<double>(windowWidth));
-    size_t j = i + windowWidth;
-    // Cyclic boundary conditions.
-    if (j >= ys.size()) {
-      j -= ys.size();
+  double currentVariance = 0;
+
+  for (size_t i = 0; i < ys.size(); ++i) {
+    double sum = 0;
+    double varSqSum = 0;
+    for (size_t j = 0; j < windowWidth; ++j) {
+      size_t index = i + j;
+      if (index >= ys.size()) {
+        // Cyclic boundary conditions.
+        index -= ys.size();
+      }
+      sum += ys[index];
+      varSqSum += es[index] * es[index];
+    }
+    const double average = sum / static_cast<double>(windowWidth);
+    if (average < currentMin) {
+      currentMin = average;
+      currentVariance =
+          varSqSum / static_cast<double>(windowWidth * windowWidth);
     }
-    sum += ys[j] - ys[i];
   }
-  currentMin = std::min(currentMin, sum / static_cast<double>(windowWidth));
-  return currentMin;
+  background = currentMin;
+  variance = currentVariance;
 }
 
 } // namespace Algorithms
diff --git a/Framework/Algorithms/src/CalculateTransmission.cpp b/Framework/Algorithms/src/CalculateTransmission.cpp
index e8ef973aa69d324db2339a888a6fffea484f35e1..cdd86c426b1b401731378b7847f9ec92d47099ae 100644
--- a/Framework/Algorithms/src/CalculateTransmission.cpp
+++ b/Framework/Algorithms/src/CalculateTransmission.cpp
@@ -7,6 +7,7 @@
 #include "MantidAPI/FunctionFactory.h"
 #include "MantidAPI/HistogramValidator.h"
 #include "MantidAPI/IFunction.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidAPI/WorkspaceOpOverloads.h"
 #include "MantidAPI/WorkspaceUnitValidator.h"
 #include "MantidGeometry/Instrument.h"
@@ -137,7 +138,7 @@ void CalculateTransmission::exec() {
   if (!usingSameInstrument)
     throw std::invalid_argument(
         "The input workspaces do not come from the same instrument.");
-  if (!WorkspaceHelpers::matchingBins(sampleWS, directWS))
+  if (!WorkspaceHelpers::matchingBins(*sampleWS, *directWS))
     throw std::invalid_argument(
         "The input workspaces do not have matching bins.");
 
@@ -492,9 +493,9 @@ void CalculateTransmission::logIfNotMonitor(API::MatrixWorkspace_sptr sampleWS,
                                             size_t index) {
   const std::string message = "The detector at index " + std::to_string(index) +
                               " is not a monitor in the ";
-  if (!sampleWS->getDetector(index)->isMonitor())
+  if (!sampleWS->spectrumInfo().isMonitor(index))
     g_log.information(message + "sample workspace.");
-  if (!directWS->getDetector(index)->isMonitor())
+  if (!directWS->spectrumInfo().isMonitor(index))
     g_log.information(message + "direct workspace.");
 }
 
diff --git a/Framework/Algorithms/src/CalculateTransmissionBeamSpreader.cpp b/Framework/Algorithms/src/CalculateTransmissionBeamSpreader.cpp
index 51365805111c0e263bb96fc772994b84bde57f30..78f5f0feb6011e1ede4f479f595d22b9107ceef2 100644
--- a/Framework/Algorithms/src/CalculateTransmissionBeamSpreader.cpp
+++ b/Framework/Algorithms/src/CalculateTransmissionBeamSpreader.cpp
@@ -4,6 +4,7 @@
 #include "MantidAlgorithms/CalculateTransmissionBeamSpreader.h"
 #include "MantidAPI/CommonBinsValidator.h"
 #include "MantidAPI/HistogramValidator.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidAPI/WorkspaceOpOverloads.h"
 #include "MantidAPI/WorkspaceUnitValidator.h"
@@ -101,9 +102,9 @@ void CalculateTransmissionBeamSpreader::exec() {
         "The input workspaces do not come from the same instrument");
   }
   // Check that the two inputs have matching binning
-  if (!WorkspaceHelpers::matchingBins(sample_spreaderWS, direct_spreaderWS) ||
-      !WorkspaceHelpers::matchingBins(sample_spreaderWS, sample_scatterWS) ||
-      !WorkspaceHelpers::matchingBins(sample_spreaderWS, direct_scatterWS)) {
+  if (!WorkspaceHelpers::matchingBins(*sample_spreaderWS, *direct_spreaderWS) ||
+      !WorkspaceHelpers::matchingBins(*sample_spreaderWS, *sample_scatterWS) ||
+      !WorkspaceHelpers::matchingBins(*sample_spreaderWS, *direct_scatterWS)) {
     g_log.error("Input workspaces do not have matching binning");
     throw std::invalid_argument(
         "Input workspaces do not have matching binning");
@@ -244,7 +245,7 @@ API::MatrixWorkspace_sptr
 CalculateTransmissionBeamSpreader::extractSpectrum(API::MatrixWorkspace_sptr WS,
                                                    const size_t index) {
   // Check that given spectra are monitors
-  if (!WS->getDetector(index)->isMonitor()) {
+  if (!WS->spectrumInfo().isMonitor(index)) {
     g_log.information(
         "The Incident Beam Monitor UDET provided is not marked as a monitor");
   }
diff --git a/Framework/Algorithms/src/ChopData.cpp b/Framework/Algorithms/src/ChopData.cpp
index 3867c52997728d2e30379965465cbccc5e942216..0190ef65e842379730b9dbeaab8d25953372edbe 100644
--- a/Framework/Algorithms/src/ChopData.cpp
+++ b/Framework/Algorithms/src/ChopData.cpp
@@ -2,6 +2,7 @@
 #include "MantidAPI/HistogramValidator.h"
 #include "MantidAPI/SpectraAxisValidator.h"
 #include "MantidAPI/WorkspaceFactory.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidAPI/WorkspaceUnitValidator.h"
 #include "MantidKernel/CompositeValidator.h"
 #include "MantidKernel/MultiThreaded.h"
diff --git a/Framework/Algorithms/src/ClearMaskFlag.cpp b/Framework/Algorithms/src/ClearMaskFlag.cpp
index dfa7f3a53e68d50b6c096d9c49fbb7d33b5fdf46..4e9c7fcba0bc913cd5129834133e180db52fad51 100644
--- a/Framework/Algorithms/src/ClearMaskFlag.cpp
+++ b/Framework/Algorithms/src/ClearMaskFlag.cpp
@@ -1,9 +1,8 @@
 #include "MantidAlgorithms/ClearMaskFlag.h"
 
+#include "MantidAPI/DetectorInfo.h"
 #include "MantidAPI/MatrixWorkspace.h"
-#include "MantidGeometry/Instrument/ParameterMap.h"
-#include "MantidGeometry/Instrument/Detector.h"
-#include "MantidGeometry/Instrument/Component.h"
+#include "MantidGeometry/IDetector.h"
 #include "MantidGeometry/Instrument.h"
 
 namespace Mantid {
@@ -16,7 +15,6 @@ using Kernel::Direction;
 // Register the algorithm into the AlgorithmFactory
 DECLARE_ALGORITHM(ClearMaskFlag)
 
-//----------------------------------------------------------------------------------------------
 /// Algorithm's name for identification. @see Algorithm::name
 const std::string ClearMaskFlag::name() const { return "ClearMaskFlag"; }
 
@@ -28,7 +26,6 @@ const std::string ClearMaskFlag::category() const {
   return "Transforms\\Masking";
 }
 
-//----------------------------------------------------------------------------------------------
 /** Initialize the algorithm's properties.
  */
 void ClearMaskFlag::init() {
@@ -41,28 +38,22 @@ void ClearMaskFlag::init() {
                   "the whole instrument.");
 }
 
-//----------------------------------------------------------------------------------------------
 /** Execute the algorithm.
  */
 void ClearMaskFlag::exec() {
   MatrixWorkspace_sptr ws = getProperty("Workspace");
   std::string componentName = getPropertyValue("ComponentName");
-
-  // Clear the mask flags
-  Geometry::ParameterMap &pmap = ws->instrumentParameters();
+  auto &detectorInfo = ws->mutableDetectorInfo();
 
   if (!componentName.empty()) {
-    auto instrument = ws->getInstrument();
-    auto component = instrument->getComponentByName(componentName);
-    boost::shared_ptr<const Geometry::ICompAssembly> componentAssembly =
-        boost::dynamic_pointer_cast<const Geometry::ICompAssembly>(component);
-    std::vector<Geometry::IComponent_const_sptr> children;
-    componentAssembly->getChildren(children, true);
-    for (auto det : children) {
-      pmap.addBool(det.get(), "masked", false);
+    std::vector<IDetector_const_sptr> detectors;
+    ws->getInstrument()->getDetectorsInBank(detectors, componentName);
+    for (const auto &det : detectors) {
+      auto index = detectorInfo.indexOf(det->getID());
+      detectorInfo.setMasked(index, false);
     }
   } else {
-    pmap.clearParametersByName("masked");
+    detectorInfo.clearMaskFlags();
   }
 }
 
diff --git a/Framework/Algorithms/src/CompareWorkspaces.cpp b/Framework/Algorithms/src/CompareWorkspaces.cpp
index b3b18d6703b369c5901479d1638bc3ea70d63bbf..2ed328d8bd35a1db717db4cf304fb50a4fdc82a5 100644
--- a/Framework/Algorithms/src/CompareWorkspaces.cpp
+++ b/Framework/Algorithms/src/CompareWorkspaces.cpp
@@ -9,9 +9,11 @@
 #include "MantidAPI/Sample.h"
 #include "MantidAPI/TableRow.h"
 #include "MantidAPI/WorkspaceFactory.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidDataObjects/TableWorkspace.h"
 #include "MantidDataObjects/EventWorkspace.h"
 #include "MantidGeometry/Crystal/IPeak.h"
+#include "MantidKernel/Unit.h"
 
 namespace Mantid {
 namespace Algorithms {
@@ -128,8 +130,10 @@ void CompareWorkspaces::exec() {
     std::string message = m_Messages->cell<std::string>(0, 0);
     g_log.notice() << "The workspaces did not match: " << message << '\n';
   } else {
-    std::string ws1 = Workspace_const_sptr(getProperty("Workspace1"))->name();
-    std::string ws2 = Workspace_const_sptr(getProperty("Workspace2"))->name();
+    std::string ws1 =
+        Workspace_const_sptr(getProperty("Workspace1"))->getName();
+    std::string ws2 =
+        Workspace_const_sptr(getProperty("Workspace2"))->getName();
     g_log.notice() << "The workspaces \"" << ws1 << "\" and \"" << ws2
                    << "\" matched!\n";
   }
@@ -172,8 +176,8 @@ bool CompareWorkspaces::processGroups() {
   }
 
   if (m_Result && ws1 && ws2) {
-    g_log.notice() << "All workspaces in workspace groups \"" << ws1->name()
-                   << "\" and \"" << ws2->name() << "\" matched!\n";
+    g_log.notice() << "All workspaces in workspace groups \"" << ws1->getName()
+                   << "\" and \"" << ws2->getName() << "\" matched!\n";
   }
 
   setProperty("Result", m_Result);
@@ -1154,11 +1158,11 @@ void CompareWorkspaces::recordMismatch(std::string msg, std::string ws1,
   // Workspace names default to the workspaces currently being compared
   if (ws1.empty()) {
     Workspace_const_sptr w1 = getProperty("Workspace1");
-    ws1 = w1->name();
+    ws1 = w1->getName();
   }
   if (ws2.empty()) {
     Workspace_const_sptr w2 = getProperty("Workspace2");
-    ws2 = w2->name();
+    ws2 = w2->getName();
   }
 
   // Add new row and flag this comparison as a mismatch
diff --git a/Framework/Algorithms/src/ConjoinWorkspaces.cpp b/Framework/Algorithms/src/ConjoinWorkspaces.cpp
index 2e4bd855bec87a2d3a60d8afef49a9592dbcbc16..a750c432267993ea500a65e03ddb6009e8a9130e 100644
--- a/Framework/Algorithms/src/ConjoinWorkspaces.cpp
+++ b/Framework/Algorithms/src/ConjoinWorkspaces.cpp
@@ -1,9 +1,8 @@
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidAlgorithms/ConjoinWorkspaces.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/CommonBinsValidator.h"
 #include "MantidAPI/SpectraAxis.h"
+#include "MantidAPI/WorkspaceHistory.h"
 
 namespace Mantid {
 namespace Algorithms {
@@ -60,7 +59,7 @@ void ConjoinWorkspaces::exec() {
     // overlap
     // make sure we should bother checking
     if (this->getProperty("CheckOverlapping")) {
-      this->checkForOverlap(event_ws1, event_ws2, false);
+      this->checkForOverlap(*event_ws1, *event_ws2, false);
       m_overlapChecked = true;
     }
 
@@ -76,14 +75,14 @@ void ConjoinWorkspaces::exec() {
   }
 
   // Check that the input workspaces meet the requirements for this algorithm
-  this->validateInputs(ws1, ws2);
+  this->validateInputs(*ws1, *ws2);
 
   if (this->getProperty("CheckOverlapping")) {
-    this->checkForOverlap(ws1, ws2, true);
+    this->checkForOverlap(*ws1, *ws2, true);
     m_overlapChecked = true;
   }
 
-  MatrixWorkspace_sptr output = execWS2D(ws1, ws2);
+  MatrixWorkspace_sptr output = execWS2D(*ws1, *ws2);
   // Copy the history from the original workspace
   output->history().addHistory(ws1->getHistory());
 
@@ -102,16 +101,16 @@ void ConjoinWorkspaces::exec() {
  * (non-sensical for event workspaces)
  *  @throw std::invalid_argument If there is some overlap
  */
-void ConjoinWorkspaces::checkForOverlap(API::MatrixWorkspace_const_sptr ws1,
-                                        API::MatrixWorkspace_const_sptr ws2,
+void ConjoinWorkspaces::checkForOverlap(const MatrixWorkspace &ws1,
+                                        const MatrixWorkspace &ws2,
                                         bool checkSpectra) const {
   // Loop through the first workspace adding all the spectrum numbers & UDETS to
   // a set
   std::set<specnum_t> spectra;
   std::set<detid_t> detectors;
-  const size_t &nhist1 = ws1->getNumberHistograms();
+  const size_t &nhist1 = ws1.getNumberHistograms();
   for (size_t i = 0; i < nhist1; ++i) {
-    const auto &spec = ws1->getSpectrum(i);
+    const auto &spec = ws1.getSpectrum(i);
     const specnum_t spectrum = spec.getSpectrumNo();
     spectra.insert(spectrum);
     const auto &dets = spec.getDetectorIDs();
@@ -122,9 +121,9 @@ void ConjoinWorkspaces::checkForOverlap(API::MatrixWorkspace_const_sptr ws1,
 
   // Now go throught the spectrum numbers & UDETS in the 2nd workspace, making
   // sure that there's no overlap
-  const size_t &nhist2 = ws2->getNumberHistograms();
+  const size_t &nhist2 = ws2.getNumberHistograms();
   for (size_t j = 0; j < nhist2; ++j) {
-    const auto &spec = ws2->getSpectrum(j);
+    const auto &spec = ws2.getSpectrum(j);
     const specnum_t spectrum = spec.getSpectrumNo();
     if (checkSpectra) {
       if (spectrum > 0 && spectra.find(spectrum) != spectra.end()) {
@@ -155,9 +154,9 @@ void ConjoinWorkspaces::checkForOverlap(API::MatrixWorkspace_const_sptr ws1,
  * @param ws2 The second workspace supplied to the algorithm.
  * @param output The workspace that is going to be returned by the algorithm.
  */
-void ConjoinWorkspaces::fixSpectrumNumbers(API::MatrixWorkspace_const_sptr ws1,
-                                           API::MatrixWorkspace_const_sptr ws2,
-                                           API::MatrixWorkspace_sptr output) {
+void ConjoinWorkspaces::fixSpectrumNumbers(const MatrixWorkspace &ws1,
+                                           const MatrixWorkspace &ws2,
+                                           MatrixWorkspace &output) {
   bool needsFix(false);
 
   if (this->getProperty("CheckOverlapping")) {
@@ -178,7 +177,7 @@ void ConjoinWorkspaces::fixSpectrumNumbers(API::MatrixWorkspace_const_sptr ws1,
   specnum_t max;
   getMinMax(output, min, max);
   if (max - min >= static_cast<specnum_t>(
-                       output->getNumberHistograms())) // nothing to do then
+                       output.getNumberHistograms())) // nothing to do then
     return;
 
   // information for remapping the spectra numbers
@@ -188,11 +187,11 @@ void ConjoinWorkspaces::fixSpectrumNumbers(API::MatrixWorkspace_const_sptr ws1,
 
   // change the axis by adding the maximum existing spectrum number to the
   // current value
-  for (size_t i = ws1->getNumberHistograms(); i < output->getNumberHistograms();
+  for (size_t i = ws1.getNumberHistograms(); i < output.getNumberHistograms();
        i++) {
     specnum_t origid;
-    origid = output->getSpectrum(i).getSpectrumNo();
-    output->getSpectrum(i).setSpectrumNo(origid + ws1max);
+    origid = output.getSpectrum(i).getSpectrumNo();
+    output.getSpectrum(i).setSpectrumNo(origid + ws1max);
   }
 }
 
diff --git a/Framework/Algorithms/src/ConvertAxisByFormula.cpp b/Framework/Algorithms/src/ConvertAxisByFormula.cpp
index 5941af7807e84f817f720ee98027f19a5d52d29c..ada62fb7d4e67eb951a6db5656442b4f7a2f0481 100644
--- a/Framework/Algorithms/src/ConvertAxisByFormula.cpp
+++ b/Framework/Algorithms/src/ConvertAxisByFormula.cpp
@@ -178,7 +178,7 @@ void ConvertAxisByFormula::exec() {
     if ((isRaggedBins) || (isGeometryRequired)) {
       // ragged bins or geometry used - we have to calculate for every spectra
       size_t numberOfSpectra_i = outputWs->getNumberHistograms();
-      const auto &spectrumInfo = outputWs->spectrumInfo();
+      auto &spectrumInfo = outputWs->mutableSpectrumInfo();
 
       size_t failedDetectorCount = 0;
       Progress prog(this, 0.6, 1.0, numberOfSpectra_i);
@@ -192,7 +192,8 @@ void ConvertAxisByFormula::exec() {
         // both handled the same way
         {
           // could not find the geometry info for this spectra
-          outputWs->maskWorkspaceIndex(i);
+          outputWs->getSpectrum(i).clearData();
+          spectrumInfo.setMasked(i, true);
           failedDetectorCount++;
         }
         prog.report();
diff --git a/Framework/Algorithms/src/ConvertDiffCal.cpp b/Framework/Algorithms/src/ConvertDiffCal.cpp
index 90b46ea4f97906261070c5c72880ae2b4ae52b6a..6d95ac735057d0ab6595b1473b91479f4bef4c44 100644
--- a/Framework/Algorithms/src/ConvertDiffCal.cpp
+++ b/Framework/Algorithms/src/ConvertDiffCal.cpp
@@ -112,8 +112,8 @@ double calculateDIFC(OffsetsWorkspace_const_sptr offsetsWS,
 
   // the factor returned is what is needed to convert TOF->d-spacing
   // the table is supposed to be filled with DIFC which goes the other way
-  const double factor = Instrument::calcConversion(l1, beamline, beamline_norm,
-                                                   samplePos, detector, offset);
+  const double factor = Instrument::calcConversion(
+      l1, beamline, beamline_norm, samplePos, detector->getPos(), offset);
   return 1. / factor;
 }
 
diff --git a/Framework/Algorithms/src/ConvertEmptyToTof.cpp b/Framework/Algorithms/src/ConvertEmptyToTof.cpp
index 48351844286499e379e3284811149bbacbe93724..8480a2d3de549bbcba3cb0aee2084fad8ff307bf 100644
--- a/Framework/Algorithms/src/ConvertEmptyToTof.cpp
+++ b/Framework/Algorithms/src/ConvertEmptyToTof.cpp
@@ -333,9 +333,10 @@ bool ConvertEmptyToTof::doFitGaussianPeak(int workspaceindex, double &center,
   double centerrightend = center + sigma * 0.5;
   std::ostringstream os;
   os << centerleftend << " < PeakCentre < " << centerrightend;
-  auto *centerbound = API::ConstraintFactory::Instance().createInitialized(
-      gaussianpeak.get(), os.str(), false);
-  gaussianpeak->addConstraint(centerbound);
+  auto centerbound = std::unique_ptr<API::IConstraint>(
+      API::ConstraintFactory::Instance().createInitialized(gaussianpeak.get(),
+                                                           os.str(), false));
+  gaussianpeak->addConstraint(std::move(centerbound));
 
   g_log.debug("Calling createChildAlgorithm : Fit...");
   // 4. Fit
diff --git a/Framework/Algorithms/src/ConvertSpectrumAxis.cpp b/Framework/Algorithms/src/ConvertSpectrumAxis.cpp
index f566afe5adb0f4a5885d1a0a8937fb0bb6b7938e..8d7d1252590090f4fbce57f648fa8330a7cff05b 100644
--- a/Framework/Algorithms/src/ConvertSpectrumAxis.cpp
+++ b/Framework/Algorithms/src/ConvertSpectrumAxis.cpp
@@ -3,6 +3,7 @@
 #include "MantidAPI/NumericAxis.h"
 #include "MantidAPI/Run.h"
 #include "MantidAPI/SpectraAxisValidator.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidGeometry/Instrument.h"
 #include "MantidKernel/BoundedValidator.h"
@@ -95,15 +96,16 @@ void ConvertSpectrumAxis::exec() {
       emode = 2;
     const double delta = 0.0;
     double efixed;
+    auto &spectrumInfo = inputWS->spectrumInfo();
     for (size_t i = 0; i < nHist; i++) {
       std::vector<double> xval{inputWS->x(i).front(), inputWS->x(i).back()};
-      IDetector_const_sptr detector = inputWS->getDetector(i);
       double twoTheta, l1val, l2;
-      if (!detector->isMonitor()) {
-        twoTheta = inputWS->detectorTwoTheta(*detector);
-        l2 = detector->getDistance(*sample);
+      if (!spectrumInfo.isMonitor(i)) {
+        twoTheta = spectrumInfo.twoTheta(i);
+        l2 = spectrumInfo.l2(i);
         l1val = l1;
-        efixed = getEfixed(detector, inputWS, emode); // get efixed
+        efixed =
+            getEfixed(spectrumInfo.detector(i), inputWS, emode); // get efixed
       } else {
         twoTheta = 0.0;
         l2 = l1;
@@ -172,14 +174,15 @@ void ConvertSpectrumAxis::exec() {
   setProperty("OutputWorkspace", outputWS);
 }
 
-double ConvertSpectrumAxis::getEfixed(IDetector_const_sptr detector,
-                                      MatrixWorkspace_const_sptr inputWS,
-                                      int emode) const {
+double
+ConvertSpectrumAxis::getEfixed(const Mantid::Geometry::IDetector &detector,
+                               MatrixWorkspace_const_sptr inputWS,
+                               int emode) const {
   double efixed(0);
   double efixedProp = getProperty("Efixed");
   if (efixedProp != EMPTY_DBL()) {
     efixed = efixedProp;
-    g_log.debug() << "Detector: " << detector->getID() << " Efixed: " << efixed
+    g_log.debug() << "Detector: " << detector.getID() << " Efixed: " << efixed
                   << "\n";
   } else {
     if (emode == 1) {
@@ -192,29 +195,29 @@ double ConvertSpectrumAxis::getEfixed(IDetector_const_sptr detector,
         } else {
           efixed = 0.0;
           g_log.warning() << "Efixed could not be found for detector "
-                          << detector->getID() << ", set to 0.0\n";
+                          << detector.getID() << ", set to 0.0\n";
         }
       } else {
         efixed = 0.0;
         g_log.warning() << "Efixed could not be found for detector "
-                        << detector->getID() << ", set to 0.0\n";
+                        << detector.getID() << ", set to 0.0\n";
       }
     } else if (emode == 2) {
-      std::vector<double> efixedVec = detector->getNumberParameter("Efixed");
+      std::vector<double> efixedVec = detector.getNumberParameter("Efixed");
       if (efixedVec.empty()) {
-        int detid = detector->getID();
+        int detid = detector.getID();
         IDetector_const_sptr detectorSingle =
             inputWS->getInstrument()->getDetector(detid);
         efixedVec = detectorSingle->getNumberParameter("Efixed");
       }
       if (!efixedVec.empty()) {
         efixed = efixedVec.at(0);
-        g_log.debug() << "Detector: " << detector->getID()
+        g_log.debug() << "Detector: " << detector.getID()
                       << " EFixed: " << efixed << "\n";
       } else {
         efixed = 0.0;
         g_log.warning() << "Efixed could not be found for detector "
-                        << detector->getID() << ", set to 0.0\n";
+                        << detector.getID() << ", set to 0.0\n";
       }
     }
   }
diff --git a/Framework/Algorithms/src/ConvertSpectrumAxis2.cpp b/Framework/Algorithms/src/ConvertSpectrumAxis2.cpp
index 95c8c1d9b4b11ba605eac98c4cedba61f3158216..9013c790aee1cc466633ad81b74c7270334cc9e4 100644
--- a/Framework/Algorithms/src/ConvertSpectrumAxis2.cpp
+++ b/Framework/Algorithms/src/ConvertSpectrumAxis2.cpp
@@ -15,6 +15,8 @@
 
 #include <cfloat>
 
+constexpr double rad2deg = 180.0 / M_PI;
+
 namespace Mantid {
 namespace Algorithms {
 // Register the algorithm into the AlgorithmFactory
@@ -151,19 +153,20 @@ void ConvertSpectrumAxis2::createElasticQMap(API::Progress &progress,
   else if (emodeStr == "Indirect")
     emode = 2;
 
+  auto &spectrumInfo = inputWS->spectrumInfo();
   for (size_t i = 0; i < nHist; i++) {
-    IDetector_const_sptr detector = inputWS->getDetector(i);
-    double twoTheta(0.0), efixed(0.0);
-    if (!detector->isMonitor()) {
-      twoTheta = 0.5 * inputWS->detectorTwoTheta(*detector);
-      efixed = getEfixed(detector, inputWS, emode); // get efixed
+    double theta(0.0), efixed(0.0);
+    if (!spectrumInfo.isMonitor(i)) {
+      theta = 0.5 * spectrumInfo.twoTheta(i);
+      efixed =
+          getEfixed(spectrumInfo.detector(i), inputWS, emode); // get efixed
     } else {
-      twoTheta = 0.0;
+      theta = 0.0;
       efixed = DBL_MIN;
     }
 
     // Convert to MomentumTransfer
-    double elasticQInAngstroms = Kernel::UnitConversion::run(twoTheta, efixed);
+    double elasticQInAngstroms = Kernel::UnitConversion::run(theta, efixed);
 
     if (targetUnit == "ElasticQ") {
       m_indexMap.emplace(elasticQInAngstroms, i);
@@ -229,14 +232,15 @@ MatrixWorkspace_sptr ConvertSpectrumAxis2::createOutputWorkspace(
   return outputWorkspace;
 }
 
-double ConvertSpectrumAxis2::getEfixed(IDetector_const_sptr detector,
-                                       MatrixWorkspace_const_sptr inputWS,
-                                       int emode) const {
+double
+ConvertSpectrumAxis2::getEfixed(const Mantid::Geometry::IDetector &detector,
+                                MatrixWorkspace_const_sptr inputWS,
+                                int emode) const {
   double efixed(0);
   double efixedProp = getProperty("Efixed");
   if (efixedProp != EMPTY_DBL()) {
     efixed = efixedProp;
-    g_log.debug() << "Detector: " << detector->getID() << " Efixed: " << efixed
+    g_log.debug() << "Detector: " << detector.getID() << " Efixed: " << efixed
                   << "\n";
   } else {
     if (emode == 1) {
@@ -247,20 +251,20 @@ double ConvertSpectrumAxis2::getEfixed(IDetector_const_sptr detector,
                                     "workspace. Please provide a value.");
       }
     } else if (emode == 2) {
-      std::vector<double> efixedVec = detector->getNumberParameter("Efixed");
+      std::vector<double> efixedVec = detector.getNumberParameter("Efixed");
       if (efixedVec.empty()) {
-        int detid = detector->getID();
+        int detid = detector.getID();
         IDetector_const_sptr detectorSingle =
             inputWS->getInstrument()->getDetector(detid);
         efixedVec = detectorSingle->getNumberParameter("Efixed");
       }
       if (!efixedVec.empty()) {
         efixed = efixedVec.at(0);
-        g_log.debug() << "Detector: " << detector->getID()
+        g_log.debug() << "Detector: " << detector.getID()
                       << " EFixed: " << efixed << "\n";
       } else {
         g_log.warning() << "Efixed could not be found for detector "
-                        << detector->getID() << ", please provide a value\n";
+                        << detector.getID() << ", please provide a value\n";
         throw std::invalid_argument("Could not retrieve Efixed from the "
                                     "detector. Please provide a value.");
       }
diff --git a/Framework/Algorithms/src/ConvertToConstantL2.cpp b/Framework/Algorithms/src/ConvertToConstantL2.cpp
index 8a2d807fe4fb76cdcf1b8a2af890f30d2ab27418..6410f92040daef8b4bd19dfd5d84bb5cc385022c 100644
--- a/Framework/Algorithms/src/ConvertToConstantL2.cpp
+++ b/Framework/Algorithms/src/ConvertToConstantL2.cpp
@@ -9,6 +9,8 @@
 #include "MantidGeometry/Instrument/ComponentHelper.h"
 #include "MantidGeometry/Instrument/ParameterMap.h"
 #include "MantidKernel/CompositeValidator.h"
+#include "MantidKernel/PhysicalConstants.h"
+#include "MantidKernel/Strings.h"
 #include "MantidKernel/UnitFactory.h"
 
 #include <cmath>
diff --git a/Framework/Algorithms/src/ConvertToEventWorkspace.cpp b/Framework/Algorithms/src/ConvertToEventWorkspace.cpp
index 7aa9ba3508a64f4b71f453850f3697364995366d..50e9a43349c2e2e754b5bbffbc19c092c6767c6c 100644
--- a/Framework/Algorithms/src/ConvertToEventWorkspace.cpp
+++ b/Framework/Algorithms/src/ConvertToEventWorkspace.cpp
@@ -1,9 +1,9 @@
 #include "MantidAlgorithms/ConvertToEventWorkspace.h"
-#include "MantidAPI/WorkspaceFactory.h"
 #include "MantidKernel/System.h"
 #include "MantidDataObjects/Workspace2D.h"
 #include "MantidDataObjects/EventWorkspace.h"
 #include "MantidDataObjects/Events.h"
+#include "MantidDataObjects/WorkspaceCreation.h"
 #include <limits>
 
 using namespace Mantid::Kernel;
@@ -16,9 +16,6 @@ namespace Algorithms {
 // Register the algorithm into the AlgorithmFactory
 DECLARE_ALGORITHM(ConvertToEventWorkspace)
 
-//------------------------------------------MaxEventsPerBin----------------------------------------------------
-
-//----------------------------------------------------------------------------------------------
 /** Initialize the algorithm's properties.
  */
 void ConvertToEventWorkspace::init() {
@@ -42,7 +39,6 @@ void ConvertToEventWorkspace::init() {
                   "Name of the output EventWorkspace.");
 }
 
-//----------------------------------------------------------------------------------------------
 /** Execute the algorithm.
  */
 void ConvertToEventWorkspace::exec() {
@@ -52,14 +48,7 @@ void ConvertToEventWorkspace::exec() {
   bool GenerateZeros = getProperty("GenerateZeros");
   int MaxEventsPerBin = getProperty("MaxEventsPerBin");
 
-  // Create the event workspace
-  EventWorkspace_sptr outWS = boost::dynamic_pointer_cast<EventWorkspace>(
-      API::WorkspaceFactory::Instance().create(
-          "EventWorkspace", inWS->getNumberHistograms(), inWS->blocksize() + 1,
-          inWS->blocksize()));
-
-  // Copy geometry, etc. over.
-  API::WorkspaceFactory::Instance().initializeFromParent(inWS, outWS, false);
+  auto outWS = create<EventWorkspace>(*inWS);
 
   Progress prog(this, 0.0, 1.0, inWS->getNumberHistograms());
   PARALLEL_FOR_IF(Kernel::threadSafe(*inWS))
@@ -83,7 +72,7 @@ void ConvertToEventWorkspace::exec() {
   PARALLEL_CHECK_INTERUPT_REGION
 
   // Set the output
-  setProperty("OutputWorkspace", outWS);
+  setProperty("OutputWorkspace", std::move(outWS));
 }
 
 } // namespace Mantid
diff --git a/Framework/Algorithms/src/ConvertUnits.cpp b/Framework/Algorithms/src/ConvertUnits.cpp
index 47cac08c4a46ba48e122dfdd74e4389d87d4af8d..60f066fb630ebe8cc2ce1b8f558983bd6008f5e3 100644
--- a/Framework/Algorithms/src/ConvertUnits.cpp
+++ b/Framework/Algorithms/src/ConvertUnits.cpp
@@ -232,7 +232,7 @@ ConvertUnits::executeUnitConversion(const API::MatrixWorkspace_sptr inputWS) {
 
   // Rebin the data to common bins if requested, and if necessary
   bool alignBins = getProperty("AlignBins");
-  if (alignBins && !WorkspaceHelpers::commonBoundaries(outputWS))
+  if (alignBins && !WorkspaceHelpers::commonBoundaries(*outputWS))
     outputWS = this->alignBins(outputWS);
 
   // If appropriate, put back the bin width division into Y/E.
@@ -338,7 +338,7 @@ ConvertUnits::convertQuickly(API::MatrixWorkspace_const_sptr inputWS,
   CommonBinsValidator sameBins;
   bool commonBoundaries = false;
   if (sameBins.isValid(inputWS) == "") {
-    commonBoundaries = WorkspaceHelpers::commonBoundaries(inputWS);
+    commonBoundaries = WorkspaceHelpers::commonBoundaries(*inputWS);
     // Only do the full check if the quick one passes
     if (commonBoundaries) {
       // Calculate the new (common) X values
@@ -517,6 +517,9 @@ ConvertUnits::convertViaTOF(Kernel::Unit_const_sptr fromUnit,
       (!parameters.empty()) &&
       find(parameters.begin(), parameters.end(), "Always") != parameters.end();
 
+  auto localFromUnit = std::unique_ptr<Unit>(fromUnit->clone());
+  auto localOutputUnit = std::unique_ptr<Unit>(outputUnit->clone());
+
   // Perform Sanity Validation before creating workspace
   double checkefixed = efixedProp;
   double checkl2;
@@ -528,12 +531,10 @@ ConvertUnits::convertViaTOF(Kernel::Unit_const_sptr fromUnit,
     // copy the X values for the check
     auto checkXValues = inputWS->readX(checkIndex);
     // Convert the input unit to time-of-flight
-    auto checkFromUnit = std::unique_ptr<Unit>(fromUnit->clone());
-    auto checkOutputUnit = std::unique_ptr<Unit>(outputUnit->clone());
-    checkFromUnit->toTOF(checkXValues, emptyVec, l1, checkl2, checktwoTheta,
+    localFromUnit->toTOF(checkXValues, emptyVec, l1, checkl2, checktwoTheta,
                          emode, checkefixed, checkdelta);
     // Convert from time-of-flight to the desired unit
-    checkOutputUnit->fromTOF(checkXValues, emptyVec, l1, checkl2, checktwoTheta,
+    localOutputUnit->fromTOF(checkXValues, emptyVec, l1, checkl2, checktwoTheta,
                              emode, checkefixed, checkdelta);
   }
 
@@ -543,7 +544,7 @@ ConvertUnits::convertViaTOF(Kernel::Unit_const_sptr fromUnit,
       boost::dynamic_pointer_cast<EventWorkspace>(outputWS);
   assert(static_cast<bool>(eventWS) == m_inputEvents); // Sanity check
 
-  const auto &outSpectrumInfo = outputWS->spectrumInfo();
+  auto &outSpectrumInfo = outputWS->mutableSpectrumInfo();
   // Loop over the histograms (detector spectra)
   for (int64_t i = 0; i < numberOfSpectra_i; ++i) {
     double efixed = efixedProp;
@@ -554,11 +555,6 @@ ConvertUnits::convertViaTOF(Kernel::Unit_const_sptr fromUnit,
     if (getDetectorValues(outSpectrumInfo, *outputUnit, emode, *outputWS,
                           signedTheta, i, efixed, l2, twoTheta)) {
 
-      // Make local copies of the units. This allows running the loop in
-      // parallel
-      auto localFromUnit = std::unique_ptr<Unit>(fromUnit->clone());
-      auto localOutputUnit = std::unique_ptr<Unit>(outputUnit->clone());
-
       /// @todo Don't yet consider hold-off (delta)
       const double delta = 0.0;
 
@@ -581,7 +577,9 @@ ConvertUnits::convertViaTOF(Kernel::Unit_const_sptr fromUnit,
       // detectors, this call is
       // the same as just zeroing out the data (calling clearData on the
       // spectrum)
-      outputWS->maskWorkspaceIndex(i);
+      outputWS->getSpectrum(i).clearData();
+      if (outSpectrumInfo.hasDetectors(i))
+        outSpectrumInfo.setMasked(i, true);
     }
 
     prog.report("Convert to " + m_outputUnit->unitID());
@@ -657,7 +655,7 @@ void ConvertUnits::reverse(API::MatrixWorkspace_sptr WS) {
   EventWorkspace_sptr eventWS = boost::dynamic_pointer_cast<EventWorkspace>(WS);
   bool isInputEvents = static_cast<bool>(eventWS);
   size_t numberOfSpectra = WS->getNumberHistograms();
-  if (WorkspaceHelpers::commonBoundaries(WS) && !isInputEvents) {
+  if (WorkspaceHelpers::commonBoundaries(*WS) && !isInputEvents) {
     auto reverseX = make_cow<HistogramData::HistogramX>(WS->x(0).crbegin(),
                                                         WS->x(0).crend());
     for (size_t j = 0; j < numberOfSpectra; ++j) {
diff --git a/Framework/Algorithms/src/ConvertUnitsUsingDetectorTable.cpp b/Framework/Algorithms/src/ConvertUnitsUsingDetectorTable.cpp
index 9906fb3a512a4d65e02ca9485a32508cb45d996c..4eda0c21ddb3b1092072d94dbc2c9f265fe59cc8 100644
--- a/Framework/Algorithms/src/ConvertUnitsUsingDetectorTable.cpp
+++ b/Framework/Algorithms/src/ConvertUnitsUsingDetectorTable.cpp
@@ -4,6 +4,7 @@
 #include "MantidDataObjects/TableWorkspace.h"
 #include "MantidAPI/WorkspaceUnitValidator.h"
 #include "MantidAPI/HistogramValidator.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidGeometry/IDetector.h"
 #include "MantidKernel/CompositeValidator.h"
 #include "MantidKernel/ListValidator.h"
@@ -174,23 +175,20 @@ MatrixWorkspace_sptr ConvertUnitsUsingDetectorTable::convertViaTOF(
       boost::dynamic_pointer_cast<EventWorkspace>(outputWS);
   assert(static_cast<bool>(eventWS) == m_inputEvents); // Sanity check
 
-  // TODO: Check why this parallel stuff breaks
+  auto &spectrumInfo = outputWS->mutableSpectrumInfo();
+
   // Loop over the histograms (detector spectra)
-  // PARALLEL_FOR_IF(Kernel::threadSafe(*outputWS))
   for (int64_t i = 0; i < numberOfSpectra_i; ++i) {
 
     // Lets find what row this spectrum Number appears in our detector table.
 
-    // PARALLEL_START_INTERUPT_REGION
-
     std::size_t wsid = i;
 
-    try {
-
+    if (spectrumInfo.hasDetectors(i)) {
       double deg2rad = M_PI / 180.;
 
-      auto det = outputWS->getDetector(i);
-      int specNo = det->getID();
+      auto &det = spectrumInfo.detector(i);
+      int specNo = det.getID();
 
       // int spectraNumber = static_cast<int>(spectraColumn->toDouble(i));
       // wsid = outputWS->getIndexFromSpectrumNumber(spectraNumber);
@@ -248,23 +246,23 @@ MatrixWorkspace_sptr ConvertUnitsUsingDetectorTable::convertViaTOF(
       } else {
         // Not found
         failedDetectorCount++;
-        outputWS->maskWorkspaceIndex(wsid);
+        outputWS->getSpectrum(wsid).clearData();
+        if (spectrumInfo.hasDetectors(wsid))
+          spectrumInfo.setMasked(wsid, true);
       }
 
-    } catch (Exception::NotFoundError &) {
+    } else {
       // Get to here if exception thrown when calculating distance to detector
       failedDetectorCount++;
       // Since you usually (always?) get to here when there's no attached
       // detectors, this call is
       // the same as just zeroing out the data (calling clearData on the
       // spectrum)
-      outputWS->maskWorkspaceIndex(i);
+      outputWS->getSpectrum(i).clearData();
     }
 
     prog.report("Convert to " + m_outputUnit->unitID());
-    // PARALLEL_END_INTERUPT_REGION
   } // loop over spectra
-  // PARALLEL_CHECK_INTERUPT_REGION
 
   if (failedDetectorCount != 0) {
     g_log.information() << "Something went wrong for " << failedDetectorCount
diff --git a/Framework/Algorithms/src/CopyInstrumentParameters.cpp b/Framework/Algorithms/src/CopyInstrumentParameters.cpp
index 2f35738ae3b0e7208a749dec75292fe33be59aac..d17d1a9ca7485acde9481ee63e53d86ac433a6e8 100644
--- a/Framework/Algorithms/src/CopyInstrumentParameters.cpp
+++ b/Framework/Algorithms/src/CopyInstrumentParameters.cpp
@@ -1,10 +1,9 @@
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidAlgorithms/CopyInstrumentParameters.h"
+#include "MantidAPI/DetectorInfo.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidGeometry/Instrument/ParameterMap.h"
 
+#include <algorithm>
 #include <iostream>
 
 namespace Mantid {
@@ -97,9 +96,38 @@ void CopyInstrumentParameters::exec() {
     // changed parameters
     m_receivingWorkspace->swapInstrumentParameters(targMap);
 
+    // Deal with parameters that are stored in DetectorInfo. Note that this
+    // mimics what the above code is doing when copying the ParameterMap, even
+    // if it may not make sense. That is, we do a matching purely based on
+    // detector IDs, but completely ignore whether these belong to different
+    // instruments or different incompatible versions of the same instrument.
+    // This algorithm should probably enforce stricter compatiblity checks.
+    const auto &givingDetInfo = m_givingWorkspace->detectorInfo();
+    auto &receivingDetInfo = m_receivingWorkspace->mutableDetectorInfo();
+    try {
+      // If all detector IDs match a simple assignment should work.
+      receivingDetInfo = givingDetInfo;
+    } catch (std::runtime_error &) {
+      // Fallback for mismatch of detector IDs.
+      const auto &givingDetIDs = givingDetInfo.detectorIDs();
+      for (const auto detID : receivingDetInfo.detectorIDs()) {
+        // TODO Uncomment code and add handling for every field being added to
+        // Beamline::DetectorInfo.
+        // const auto receivingIndex = receivingDetInfo.indexOf(detID);
+        if (std::find(givingDetIDs.begin(), givingDetIDs.end(), detID) !=
+            givingDetIDs.end()) {
+          // const auto givingIndex = givingDetInfo.indexOf(detID);
+          // Copy values for all fields in DetectorInfo
+        } else {
+          // Set default values for all fields in DetectorInfo
+        }
+      }
+    }
   } else {
     // unchanged Copy parameters
     m_receivingWorkspace->replaceInstrumentParameters(givParams);
+    m_receivingWorkspace->mutableDetectorInfo() =
+        m_givingWorkspace->detectorInfo();
   }
 }
 
diff --git a/Framework/Algorithms/src/CorelliCrossCorrelate.cpp b/Framework/Algorithms/src/CorelliCrossCorrelate.cpp
index ff4a27633e09540e514db233157aa51ed61540c5..25b1e157925aa7a3dcd293ac05dc1b798d65d2aa 100644
--- a/Framework/Algorithms/src/CorelliCrossCorrelate.cpp
+++ b/Framework/Algorithms/src/CorelliCrossCorrelate.cpp
@@ -10,8 +10,12 @@
 #include "MantidGeometry/muParser_Silent.h"
 #include "MantidKernel/CompositeValidator.h"
 #include "MantidKernel/MandatoryValidator.h"
+#include "MantidKernel/PhysicalConstants.h"
 #include "MantidKernel/TimeSeriesProperty.h"
 
+#include <boost/algorithm/string/classification.hpp>
+#include <boost/algorithm/string/split.hpp>
+
 namespace Mantid {
 namespace Algorithms {
 
diff --git a/Framework/Algorithms/src/CorrectFlightPaths.cpp b/Framework/Algorithms/src/CorrectFlightPaths.cpp
deleted file mode 100644
index 0c0eead86d43782e487bbfa6839e44a2f3b84f32..0000000000000000000000000000000000000000
--- a/Framework/Algorithms/src/CorrectFlightPaths.cpp
+++ /dev/null
@@ -1,20 +0,0 @@
-#include "MantidAlgorithms/CorrectFlightPaths.h"
-#include "MantidAlgorithms/ConvertToConstantL2.h"
-
-namespace Mantid {
-namespace Algorithms {
-
-using namespace Kernel;
-using namespace API;
-using namespace Geometry;
-
-// Register the class into the algorithm factory
-DECLARE_ALGORITHM(CorrectFlightPaths)
-
-/// Constructor
-CorrectFlightPaths::CorrectFlightPaths() : ConvertToConstantL2() {
-  this->useAlgorithm("ConvertToConstantL2", 1);
-}
-
-} // namespace Algorithm
-} // namespace Mantid
diff --git a/Framework/Algorithms/src/CorrectKiKf.cpp b/Framework/Algorithms/src/CorrectKiKf.cpp
index 49611e20d851c8d88125234d0f79abaad8a2db74..bcfae45fb0f1bb6c9e6f49a2a7a8494b82778177 100644
--- a/Framework/Algorithms/src/CorrectKiKf.cpp
+++ b/Framework/Algorithms/src/CorrectKiKf.cpp
@@ -1,5 +1,6 @@
 #include "MantidAlgorithms/CorrectKiKf.h"
 #include "MantidAPI/Run.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidAPI/WorkspaceUnitValidator.h"
 #include "MantidDataObjects/EventWorkspace.h"
@@ -95,6 +96,7 @@ void CorrectKiKf::exec() {
 
   // Get the parameter map
   const ParameterMap &pmap = outputWS->constInstrumentParameters();
+  const auto &spectrumInfo = inputWS->spectrumInfo();
 
   PARALLEL_FOR_IF(Kernel::threadSafe(*inputWS, *outputWS))
   for (int64_t i = 0; i < int64_t(numberOfSpectra); ++i) {
@@ -105,27 +107,15 @@ void CorrectKiKf::exec() {
     if (emodeStr == "Indirect") {
       if (efixedProp != EMPTY_DBL())
         Efi = efixedProp;
-      else
-        try {
-          IDetector_const_sptr det = inputWS->getDetector(i);
-          if (!det->isMonitor()) {
-            try {
-              Parameter_sptr par = pmap.getRecursive(det.get(), "Efixed");
-              if (par) {
-                Efi = par->value<double>();
-                g_log.debug() << "Detector: " << det->getID()
-                              << " EFixed: " << Efi << "\n";
-              }
-            } catch (std::runtime_error &) { /* Throws if a DetectorGroup, use
-                                                single provided value */
-            }
-          }
-
-        } catch (std::runtime_error &) {
-          g_log.information() << "Workspace Index " << i
-                              << ": cannot find detector"
-                              << "\n";
-        }
+      // If a DetectorGroup is present should provide a value as a property
+      // instead
+      else if (spectrumInfo.hasUniqueDetector(i)) {
+        getEfixedFromParameterMap(Efi, i, spectrumInfo, pmap);
+      } else {
+        g_log.information() << "Workspace Index " << i
+                            << ": cannot find detector"
+                            << "\n";
+      }
     }
 
     auto &yOut = outputWS->mutableY(i);
@@ -221,6 +211,7 @@ void CorrectKiKf::execEvent() {
   const ParameterMap &pmap = outputWS->constInstrumentParameters();
 
   int64_t numHistograms = static_cast<int64_t>(inputWS->getNumberHistograms());
+  const auto &spectrumInfo = inputWS->spectrumInfo();
   API::Progress prog = API::Progress(this, 0.0, 1.0, numHistograms);
   PARALLEL_FOR_IF(Kernel::threadSafe(*outputWS))
   for (int64_t i = 0; i < numHistograms; ++i) {
@@ -230,29 +221,17 @@ void CorrectKiKf::execEvent() {
     // Now get the detector object for this histogram to check if monitor
     // or to get Ef for indirect geometry
     if (emodeStr == "Indirect") {
-      if (efixedProp != EMPTY_DBL())
+      if (efixedProp != EMPTY_DBL()) {
         Efi = efixedProp;
-      else
-        try {
-          IDetector_const_sptr det = inputWS->getDetector(i);
-          if (!det->isMonitor()) {
-            try {
-              Parameter_sptr par = pmap.getRecursive(det.get(), "Efixed");
-              if (par) {
-                Efi = par->value<double>();
-                g_log.debug() << "Detector: " << det->getID()
-                              << " EFixed: " << Efi << "\n";
-              }
-            } catch (std::runtime_error &) { /* Throws if a DetectorGroup, use
-                                                single provided value */
-            }
-          }
-
-        } catch (std::runtime_error &) {
-          g_log.information() << "Workspace Index " << i
-                              << ": cannot find detector"
-                              << "\n";
-        }
+        // If a DetectorGroup is present should provide a value as a property
+        // instead
+      } else if (spectrumInfo.hasUniqueDetector(i)) {
+        getEfixedFromParameterMap(Efi, i, spectrumInfo, pmap);
+      } else {
+        g_log.information() << "Workspace Index " << i
+                            << ": cannot find detector"
+                            << "\n";
+      }
     }
 
     if (emodeStr == "Indirect")
@@ -324,5 +303,21 @@ void CorrectKiKf::correctKiKfEventHelper(std::vector<T> &wevector,
   }
 }
 
+void CorrectKiKf::getEfixedFromParameterMap(double &Efi, int64_t i,
+                                            const SpectrumInfo &spectrumInfo,
+                                            const ParameterMap &pmap) {
+  Efi = 0;
+
+  if (spectrumInfo.isMonitor(i))
+    return;
+
+  const auto &det = spectrumInfo.detector(i);
+  Parameter_sptr par = pmap.getRecursive(&det, "Efixed");
+  if (par) {
+    Efi = par->value<double>();
+    g_log.debug() << "Detector: " << det.getID() << " EFixed: " << Efi << "\n";
+  }
+}
+
 } // namespace Algorithm
 } // namespace Mantid
diff --git a/Framework/Algorithms/src/CorrectTOFAxis.cpp b/Framework/Algorithms/src/CorrectTOFAxis.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1e324ac145f26a626bb002c77abb2cc2e9f269d4
--- /dev/null
+++ b/Framework/Algorithms/src/CorrectTOFAxis.cpp
@@ -0,0 +1,503 @@
+#include "MantidAlgorithms/CorrectTOFAxis.h"
+
+#include "MantidKernel/ArrayProperty.h"
+#include "MantidAPI/InstrumentValidator.h"
+#include "MantidAPI/ITableWorkspace.h"
+#include "MantidKernel/ListValidator.h"
+#include "MantidAPI/MatrixWorkspace.h"
+#include "MantidAPI/Run.h"
+#include "MantidAPI/SpectrumInfo.h"
+#include "MantidAPI/WorkspaceProperty.h"
+#include "MantidAPI/WorkspaceUnitValidator.h"
+#include "MantidKernel/BoundedValidator.h"
+#include "MantidKernel/CompositeValidator.h"
+#include "MantidKernel/MandatoryValidator.h"
+#include "MantidKernel/PhysicalConstants.h"
+#include "MantidKernel/UnitConversion.h"
+
+namespace Mantid {
+namespace Algorithms {
+
+using Mantid::Kernel::Direction;
+using Mantid::API::WorkspaceProperty;
+
+// Register the algorithm into the AlgorithmFactory
+DECLARE_ALGORITHM(CorrectTOFAxis)
+
+namespace {
+/** A private namespace holding some column names for FindEPP algorithm's output
+ *  table.
+ */
+namespace EPPTableLiterals {
+/// Title of the fit status column in EPP tables
+const static std::string FIT_STATUS_COLUMN("FitStatus");
+/// Title of the peak centre column in EPP tables
+const static std::string PEAK_CENTRE_COLUMN("PeakCentre");
+/// Tag for successfully fitted rows in EPP tables
+const static std::string FIT_STATUS_SUCCESS("success");
+} // namespace EPPTableLiterals
+
+/** A private namespace listing the different ways to index
+ *  spectra in Mantid.
+ */
+namespace IndexTypes {
+/// Tag for detector ids
+const static std::string DETECTOR_ID("Detector ID");
+/// Tag for spectrum numbers
+const static std::string SPECTRUM_NUMBER("Spectrum Number");
+/// Tag for workspace indices
+const static std::string WORKSPACE_INDEX("Workspace Index");
+} // namespace IndexTypes
+
+/** A private namespace listing the properties of CorrectTOFAxis.
+ */
+namespace PropertyNames {
+const static std::string ELASTIC_BIN_INDEX("ElasticBinIndex");
+const static std::string EPP_TABLE("EPPTable");
+const static std::string FIXED_ENERGY("EFixed");
+const static std::string INDEX_TYPE("IndexType");
+const static std::string INPUT_WORKSPACE("InputWorkspace");
+const static std::string OUTPUT_WORKSPACE("OutputWorkspace");
+const static std::string REFERENCE_SPECTRA("ReferenceSpectra");
+const static std::string REFERENCE_WORKSPACE("ReferenceWorkspace");
+} // namespace PropertyNames
+
+/** A private namespace listing some sample log entries.
+ */
+namespace SampleLog {
+const static std::string INCIDENT_ENERGY("Ei");
+const static std::string WAVELENGTH("wavelength");
+} // namespace SampleLog
+
+/** Maps given index according to indexMap.
+ *
+ *  @param index The index to be mapped
+ *  @param indexMap The index map
+ *
+ *  @return The mapped index.
+ *
+ *  @throw std::runtime_error if index is not in the map
+ */
+template <typename Map> size_t mapIndex(const int index, const Map &indexMap) {
+  try {
+    return indexMap.at(index);
+  } catch (std::out_of_range &) {
+    throw std::runtime_error(PropertyNames::REFERENCE_SPECTRA +
+                             " out of range.");
+  }
+}
+
+/** Converts given index from indexType to workspace index. If
+ *  indexType is already IndexType::WORKSPACE_INDEX, then index
+ *  is cast to size_t.
+ *
+ *  @param index Index to be converted
+ *  @param indexType Type of index.
+ *  @param ws Workspace to get index mappings from.
+ *
+ *  @return A workspace index corresponding to index.
+ */
+size_t toWorkspaceIndex(const int index, const std::string &indexType,
+                        API::MatrixWorkspace_const_sptr ws) {
+  if (indexType == IndexTypes::DETECTOR_ID) {
+    const auto indexMap = ws->getDetectorIDToWorkspaceIndexMap();
+    return mapIndex(index, indexMap);
+  } else if (indexType == IndexTypes::SPECTRUM_NUMBER) {
+    const auto indexMap = ws->getSpectrumToWorkspaceIndexMap();
+    return mapIndex(index, indexMap);
+  } else {
+    if (index < 0) {
+      throw std::runtime_error(PropertyNames::REFERENCE_SPECTRA +
+                               " out of range.");
+    }
+    return static_cast<size_t>(index);
+  }
+}
+
+/** Transforms indices according to given maps.
+ *  @param spectra A vector of indices to be transformed
+ *  @param indexMap A map to use in the transformation
+ *  @param workspaceIndices An output parameter for the transformed indices
+ */
+template <typename Map>
+void mapIndices(const std::vector<int> &spectra, const Map &indexMap,
+                std::vector<size_t> &workspaceIndices) {
+  auto back = std::back_inserter(workspaceIndices);
+  std::transform(spectra.cbegin(), spectra.cend(), back, [&indexMap](int i) {
+    try {
+      return indexMap.at(i);
+    } catch (std::out_of_range &) {
+      throw std::runtime_error(PropertyNames::REFERENCE_SPECTRA +
+                               " out of range.");
+    }
+  });
+}
+} // anonymous namespace
+
+//----------------------------------------------------------------------------------------------
+
+/// Algorithms name for identification. @see Algorithm::name
+const std::string CorrectTOFAxis::name() const { return "CorrectTOFAxis"; }
+
+/// Algorithm's version for identification. @see Algorithm::version
+int CorrectTOFAxis::version() const { return 1; }
+
+/// Algorithm's category for identification. @see Algorithm::category
+const std::string CorrectTOFAxis::category() const {
+  return "Inelastic\\Corrections";
+}
+
+/// Algorithm's summary for use in the GUI and help. @see Algorithm::summary
+const std::string CorrectTOFAxis::summary() const {
+  return "Corrects the time-of-flight axis with regards to the incident energy "
+         "and the L1+L2 distance or a reference workspace.";
+}
+
+//----------------------------------------------------------------------------------------------
+/** Initialize the algorithm's properties.
+ */
+void CorrectTOFAxis::init() {
+  auto tofWorkspace = boost::make_shared<Kernel::CompositeValidator>();
+  tofWorkspace->add<API::WorkspaceUnitValidator>("TOF");
+  tofWorkspace->add<API::InstrumentValidator>();
+  auto mustBePositiveDouble =
+      boost::make_shared<Kernel::BoundedValidator<double>>();
+  mustBePositiveDouble->setLower(0);
+  auto mustBePositiveInt = boost::make_shared<Kernel::BoundedValidator<int>>();
+  mustBePositiveInt->setLower(0);
+
+  declareProperty(
+      Kernel::make_unique<WorkspaceProperty<API::MatrixWorkspace>>(
+          PropertyNames::INPUT_WORKSPACE, "", Direction::Input, tofWorkspace),
+      "An input workspace.");
+  declareProperty(Kernel::make_unique<WorkspaceProperty<API::MatrixWorkspace>>(
+                      PropertyNames::OUTPUT_WORKSPACE, "", Direction::Output),
+                  "An output workspace.");
+  declareProperty(Kernel::make_unique<WorkspaceProperty<API::MatrixWorkspace>>(
+                      PropertyNames::REFERENCE_WORKSPACE, "", Direction::Input,
+                      API::PropertyMode::Optional, tofWorkspace),
+                  "A reference workspace from which to copy the TOF axis as "
+                  "well as the 'Ei' and 'wavelength' sample logs.");
+  declareProperty(Kernel::make_unique<WorkspaceProperty<API::ITableWorkspace>>(
+                      PropertyNames::EPP_TABLE.c_str(), "", Direction::Input,
+                      API::PropertyMode::Optional),
+                  "An input EPP table.");
+  const std::vector<std::string> indexTypes{IndexTypes::DETECTOR_ID,
+                                            IndexTypes::SPECTRUM_NUMBER,
+                                            IndexTypes::WORKSPACE_INDEX};
+  declareProperty(PropertyNames::INDEX_TYPE, IndexTypes::DETECTOR_ID,
+                  boost::make_shared<Kernel::StringListValidator>(indexTypes),
+                  "The type of indices used in " +
+                      PropertyNames::REFERENCE_SPECTRA + " or " +
+                      PropertyNames::ELASTIC_BIN_INDEX + " (default: '" +
+                      IndexTypes::DETECTOR_ID + "').");
+  declareProperty(Kernel::make_unique<Kernel::ArrayProperty<int>>(
+                      PropertyNames::REFERENCE_SPECTRA.c_str()),
+                  "A list of reference spectra.");
+  declareProperty(
+      PropertyNames::ELASTIC_BIN_INDEX, EMPTY_INT(), mustBePositiveInt,
+      "Bin index of the nominal elastic TOF channel.", Direction::Input);
+  declareProperty(
+      PropertyNames::FIXED_ENERGY, EMPTY_DBL(), mustBePositiveDouble,
+      "Incident energy if the 'EI' sample log is not present/incorrect.",
+      Direction::Input);
+}
+
+/** Validate the algorithm's input properties.
+ *  Also does some setup for the exec() method.
+ */
+std::map<std::string, std::string> CorrectTOFAxis::validateInputs() {
+  std::map<std::string, std::string> issues;
+  m_inputWs = getProperty(PropertyNames::INPUT_WORKSPACE);
+  m_referenceWs = getProperty(PropertyNames::REFERENCE_WORKSPACE);
+  if (m_referenceWs) {
+    m_referenceWs = getProperty(PropertyNames::REFERENCE_WORKSPACE);
+    if (m_inputWs->getNumberHistograms() !=
+        m_referenceWs->getNumberHistograms()) {
+      issues[PropertyNames::REFERENCE_WORKSPACE] =
+          "Number of histograms don't match with" +
+          PropertyNames::INPUT_WORKSPACE + ".";
+    }
+    for (size_t i = 0; i < m_inputWs->getNumberHistograms(); ++i) {
+      if (m_inputWs->x(i).size() != m_referenceWs->x(i).size()) {
+        issues[PropertyNames::REFERENCE_WORKSPACE] =
+            "X axis sizes don't match with " + PropertyNames::INPUT_WORKSPACE +
+            ".";
+        break;
+      }
+    }
+    if (!m_referenceWs->run().hasProperty(SampleLog::INCIDENT_ENERGY)) {
+      issues[PropertyNames::REFERENCE_WORKSPACE] =
+          "'Ei' is missing from the sample logs.";
+    }
+    if (!m_referenceWs->run().hasProperty(SampleLog::WAVELENGTH)) {
+      issues[PropertyNames::REFERENCE_WORKSPACE] =
+          "'wavelength' is missing from the sample logs.";
+    }
+    // If reference workspace is given, the rest of the properties are
+    // skipped.
+    return issues;
+  }
+  // If no reference workspace, we either use a predefined elastic channel
+  // or EPP tables to declare the elastic TOF.
+  const int elasticBinIndex = getProperty(PropertyNames::ELASTIC_BIN_INDEX);
+  if (elasticBinIndex != EMPTY_INT()) {
+    const std::string indexType = getProperty(PropertyNames::INDEX_TYPE);
+    m_elasticBinIndex = toWorkspaceIndex(elasticBinIndex, indexType, m_inputWs);
+  } else {
+    m_eppTable = getProperty(PropertyNames::EPP_TABLE);
+    if (!m_eppTable) {
+      issues[PropertyNames::EPP_TABLE] = "No EPP table specified nor " +
+                                         PropertyNames::ELASTIC_BIN_INDEX +
+                                         " specified.";
+      return issues;
+    }
+    const auto peakPositionColumn =
+        m_eppTable->getColumn(EPPTableLiterals::PEAK_CENTRE_COLUMN);
+    const auto fitStatusColumn =
+        m_eppTable->getColumn(EPPTableLiterals::FIT_STATUS_COLUMN);
+    if (!peakPositionColumn || !fitStatusColumn) {
+      issues[PropertyNames::EPP_TABLE] =
+          "EPP table doesn't contain the expected columns.";
+      return issues;
+    }
+  }
+  const std::vector<int> spectra =
+      getProperty(PropertyNames::REFERENCE_SPECTRA);
+  if (spectra.empty()) {
+    issues[PropertyNames::REFERENCE_SPECTRA] = "No spectra selected.";
+    return issues;
+  }
+  m_workspaceIndices = referenceWorkspaceIndices();
+  std::sort(m_workspaceIndices.begin(), m_workspaceIndices.end());
+  m_workspaceIndices.erase(
+      std::unique(m_workspaceIndices.begin(), m_workspaceIndices.end()),
+      m_workspaceIndices.end());
+  const auto &spectrumInfo = m_inputWs->spectrumInfo();
+  for (const auto i : m_workspaceIndices) {
+    if (spectrumInfo.isMonitor(i)) {
+      issues[PropertyNames::REFERENCE_SPECTRA] =
+          "Monitor found among the given spectra.";
+      break;
+    }
+    if (!spectrumInfo.hasDetectors(i)) {
+      issues[PropertyNames::REFERENCE_SPECTRA] =
+          "No detectors attached to workspace index " + std::to_string(i) + ".";
+      break;
+    }
+    if (m_eppTable) {
+      const auto peakPositionColumn =
+          m_eppTable->getColumn(EPPTableLiterals::PEAK_CENTRE_COLUMN);
+      if (i >= peakPositionColumn->size()) {
+        issues[PropertyNames::REFERENCE_SPECTRA] =
+            "Workspace index " + std::to_string(i) +
+            " not found in the EPP table.";
+      }
+    }
+  }
+
+  if (getPointerToProperty(PropertyNames::FIXED_ENERGY)->isDefault()) {
+    if (!m_inputWs->run().hasProperty(SampleLog::INCIDENT_ENERGY)) {
+      issues[PropertyNames::INPUT_WORKSPACE] =
+          "'Ei' is missing from the sample logs.";
+    }
+  }
+  return issues;
+}
+
+//----------------------------------------------------------------------------------------------
+/** Execute the algorithm.
+ */
+void CorrectTOFAxis::exec() {
+  m_inputWs = getProperty(PropertyNames::INPUT_WORKSPACE);
+  API::MatrixWorkspace_sptr outputWs =
+      getProperty(PropertyNames::OUTPUT_WORKSPACE);
+  if (outputWs != m_inputWs) {
+    outputWs = m_inputWs->clone();
+  }
+  if (m_referenceWs) {
+    useReferenceWorkspace(outputWs);
+  } else {
+    correctManually(outputWs);
+  }
+  setProperty(PropertyNames::OUTPUT_WORKSPACE, outputWs);
+}
+
+/** Correct with regards to a reference workspace.
+ *  Copies the X axis as well as the 'Ei' and 'wavelength' sample logs to the
+ *  corrected workspace.
+ *  @param outputWs The corrected workspace
+ */
+void CorrectTOFAxis::useReferenceWorkspace(API::MatrixWorkspace_sptr outputWs) {
+  const int64_t histogramCount =
+      static_cast<int64_t>(m_referenceWs->getNumberHistograms());
+  PARALLEL_FOR_IF(threadSafe(*m_referenceWs, *outputWs))
+  for (int64_t i = 0; i < histogramCount; ++i) {
+    PARALLEL_START_INTERUPT_REGION
+    std::copy(m_referenceWs->x(i).cbegin(), m_referenceWs->x(i).cend(),
+              outputWs->mutableX(i).begin());
+    PARALLEL_END_INTERUPT_REGION
+  }
+  PARALLEL_CHECK_INTERUPT_REGION
+  if (outputWs->run().hasProperty(SampleLog::INCIDENT_ENERGY)) {
+    outputWs->mutableRun()
+        .getProperty(SampleLog::INCIDENT_ENERGY)
+        ->setValueFromProperty(
+            *m_referenceWs->run().getProperty(SampleLog::INCIDENT_ENERGY));
+  }
+  if (outputWs->run().hasProperty(SampleLog::WAVELENGTH)) {
+    outputWs->mutableRun()
+        .getProperty(SampleLog::WAVELENGTH)
+        ->setValueFromProperty(
+            *m_referenceWs->run().getProperty(SampleLog::WAVELENGTH));
+  }
+}
+
+/** Do manual TOF axis correction.
+ *  Resolves the L1 and average L2 distances and calculates the time-of-flight
+ *  corresponding to the given incident energy. The X axis of the input
+ *  workspace is shifted correspondingly. If the incident energy is given
+ *  specifically, also adjusts the 'Ei' and 'wavelength' sample logs.
+ *  @param outputWs The corrected workspace
+ */
+void CorrectTOFAxis::correctManually(API::MatrixWorkspace_sptr outputWs) {
+  const auto &spectrumInfo = m_inputWs->spectrumInfo();
+  const double l1 = spectrumInfo.l1();
+  double l2 = 0;
+  double epp = 0;
+  g_log.information() << "EPP: " << epp << ".\n";
+  if (m_eppTable) {
+    averageL2AndEPP(spectrumInfo, l2, epp);
+  } else {
+    epp = m_inputWs->points(0)[m_elasticBinIndex];
+    l2 = averageL2(spectrumInfo);
+  }
+  double Ei = getProperty(PropertyNames::FIXED_ENERGY);
+  if (Ei == EMPTY_DBL()) {
+    Ei = m_inputWs->run().getPropertyAsSingleValue(SampleLog::INCIDENT_ENERGY);
+  } else {
+    // Save user-given Ei and wavelength to the output workspace.
+    outputWs->mutableRun().addProperty(SampleLog::INCIDENT_ENERGY, Ei, true);
+    const double wavelength = Kernel::UnitConversion::run(
+        "Energy", "Wavelength", Ei, l1, l2, 0, Kernel::DeltaEMode::Direct, 0);
+    outputWs->mutableRun().addProperty(SampleLog::WAVELENGTH, wavelength, true);
+  }
+  // In microseconds.
+  const double TOF = (l1 + l2) / std::sqrt(2 * Ei * PhysicalConstants::meV /
+                                           PhysicalConstants::NeutronMass) *
+                     1e6;
+  g_log.information() << "Calculated TOF for L1+L2 distance of " << l1 + l2
+                      << "m: " << TOF << '\n';
+  const double shift = TOF - epp;
+  g_log.debug() << "TOF shift: " << shift << '\n';
+  const int64_t histogramCount =
+      static_cast<int64_t>(m_inputWs->getNumberHistograms());
+  PARALLEL_FOR_IF(threadSafe(*m_inputWs, *outputWs))
+  for (int64_t i = 0; i < histogramCount; ++i) {
+    PARALLEL_START_INTERUPT_REGION
+    outputWs->mutableX(i) += shift;
+    PARALLEL_END_INTERUPT_REGION
+  }
+  PARALLEL_CHECK_INTERUPT_REGION
+}
+
+/** Calculates the average L2 distance between the sample and given
+ *  detectors.
+ *  @param spectrumInfo A spectrum info for the input workspace
+ *  @param l2 An output parameter for the average L2 distance
+ *  @param epp An output parameter for the average position
+ *         of the detectors' elastic peak
+ */
+void CorrectTOFAxis::averageL2AndEPP(const API::SpectrumInfo &spectrumInfo,
+                                     double &l2, double &epp) {
+  auto peakPositionColumn =
+      m_eppTable->getColumn(EPPTableLiterals::PEAK_CENTRE_COLUMN);
+  auto fitStatusColumn =
+      m_eppTable->getColumn(EPPTableLiterals::FIT_STATUS_COLUMN);
+  double l2Sum = 0;
+  double eppSum = 0;
+  size_t n = 0;
+  const int64_t indexCount = static_cast<int64_t>(m_workspaceIndices.size());
+  // cppcheck-suppress syntaxError
+  PRAGMA_OMP(parallel for if (m_eppTable->threadSafe())
+             reduction(+: n, l2Sum, eppSum))
+  for (int64_t i = 0; i < indexCount; ++i) {
+    PARALLEL_START_INTERUPT_REGION
+    const size_t index = m_workspaceIndices[i];
+    interruption_point();
+    if (fitStatusColumn->cell<std::string>(index) ==
+        EPPTableLiterals::FIT_STATUS_SUCCESS) {
+      if (!spectrumInfo.isMasked(index)) {
+        const double d = spectrumInfo.l2(index);
+        l2Sum += d;
+        const double epp = (*peakPositionColumn)[index];
+        eppSum += epp;
+        ++n;
+        g_log.debug() << "Including workspace index " << index
+                      << " - distance: " << d << " EPP: " << epp << ".\n";
+      } else {
+        g_log.debug() << "Excluding masked workspace index " << index << ".\n";
+      }
+    } else {
+      g_log.debug()
+          << "Excluding detector with unsuccessful fit at workspace index "
+          << index << ".\n";
+    }
+    PARALLEL_END_INTERUPT_REGION
+  }
+  PARALLEL_CHECK_INTERUPT_REGION
+  if (n == 0) {
+    throw std::runtime_error("No successful detector fits found in " +
+                             PropertyNames::EPP_TABLE);
+  }
+  l2 = l2Sum / static_cast<double>(n);
+  g_log.information() << "Average L2 distance: " << l2 << ".\n";
+  epp = eppSum / static_cast<double>(n);
+  g_log.information() << "Average EPP: " << epp << ".\n";
+}
+
+double CorrectTOFAxis::averageL2(const API::SpectrumInfo &spectrumInfo) {
+  double l2Sum = 0;
+  size_t n = 0;
+  const int64_t indexCount = static_cast<int64_t>(m_workspaceIndices.size());
+  PRAGMA_OMP(parallel for reduction(+: n, l2Sum))
+  for (int64_t i = 0; i < indexCount; ++i) {
+    PARALLEL_START_INTERUPT_REGION
+    const size_t index = m_workspaceIndices[i];
+    interruption_point();
+    if (!spectrumInfo.isMasked(index)) {
+      const double d = spectrumInfo.l2(index);
+      ++n;
+      l2Sum += d;
+    } else {
+      g_log.debug() << "Excluding masked workspace index " << index << ".\n";
+    }
+    PARALLEL_END_INTERUPT_REGION
+  }
+  PARALLEL_CHECK_INTERUPT_REGION
+  if (n == 0) {
+    throw std::runtime_error("No unmasked detectors found in " +
+                             PropertyNames::REFERENCE_SPECTRA);
+  }
+  const double l2 = l2Sum / static_cast<double>(indexCount);
+  g_log.information() << "Average L2 distance: " << l2 << ".\n";
+  return l2;
+}
+
+/** Transform spectrum numbers or detector IDs to workspace indices.
+ *  @return The transformed workspace indices.
+ */
+std::vector<size_t> CorrectTOFAxis::referenceWorkspaceIndices() const {
+  const std::vector<int> indices =
+      getProperty(PropertyNames::REFERENCE_SPECTRA);
+  const std::string indexType = getProperty(PropertyNames::INDEX_TYPE);
+  std::vector<size_t> workspaceIndices(indices.size());
+  std::transform(indices.cbegin(), indices.cend(), workspaceIndices.begin(),
+                 [&indexType, this](int index) {
+                   return toWorkspaceIndex(index, indexType, m_inputWs);
+                 });
+  return workspaceIndices;
+}
+
+} // namespace Algorithms
+} // namespace Mantid
diff --git a/Framework/Algorithms/src/CreateGroupingWorkspace.cpp b/Framework/Algorithms/src/CreateGroupingWorkspace.cpp
index f356ccd1f4d391bda04a02fe4cd370934d82cb50..3c2cbe2ab2f1b5808a45b8b8bfe04e43524ff0f3 100644
--- a/Framework/Algorithms/src/CreateGroupingWorkspace.cpp
+++ b/Framework/Algorithms/src/CreateGroupingWorkspace.cpp
@@ -6,6 +6,7 @@
 #include "MantidKernel/System.h"
 #include <boost/algorithm/string/detail/classification.hpp>
 #include <boost/algorithm/string/split.hpp>
+#include <boost/algorithm/string/trim.hpp>
 #include <queue>
 #include <fstream>
 #include "MantidAPI/FileProperty.h"
@@ -70,11 +71,13 @@ void CreateGroupingWorkspace::init() {
                   "Use / or , to separate multiple groups. "
                   "If empty, then an empty GroupingWorkspace will be created.");
 
-  std::vector<std::string> grouping{"", "All", "Group", "Column", "bank"};
+  std::vector<std::string> grouping{"", "All", "Group", "2_4Grouping", "Column",
+                                    "bank"};
   declareProperty(
       "GroupDetectorsBy", "", boost::make_shared<StringListValidator>(grouping),
       "Only used if GroupNames is empty: All detectors as one group, Groups "
-      "(East,West for SNAP), Columns for SNAP, detector banks");
+      "(Group or East,West for SNAP), 2_4Grouping (SNAP), Columns, detector "
+      "banks");
   declareProperty("MaxRecursionDepth", 5,
                   "Number of levels to search into the instrument (default=5)");
 
@@ -354,12 +357,23 @@ void CreateGroupingWorkspace::exec() {
     inst = tempWS->getInstrument();
   }
 
+  // Validation for 2_4Grouping input used only for SNAP
+  if (inst->getName().compare("SNAP") != 0 &&
+      grouping.compare("2_4Grouping") == 0) {
+    const std::string message("2_4Grouping only works for SNAP.");
+    g_log.error(message);
+    throw std::invalid_argument(message);
+  }
+
   if (GroupNames.empty() && OldCalFilename.empty()) {
     if (grouping.compare("All") == 0) {
       GroupNames = inst->getName();
     } else if (inst->getName().compare("SNAP") == 0 &&
                grouping.compare("Group") == 0) {
       GroupNames = "East,West";
+    } else if (inst->getName().compare("SNAP") == 0 &&
+               grouping.compare("2_4Grouping") == 0) {
+      GroupNames = "Column1,Column2,Column3,Column4,Column5,Column6,";
     } else {
       sortnames = true;
       GroupNames = "";
@@ -391,9 +405,20 @@ void CreateGroupingWorkspace::exec() {
 
   Progress prog(this, 0.2, 1.0, outWS->getNumberHistograms());
   // Make the grouping one of three ways:
-  if (!GroupNames.empty())
+  if (!GroupNames.empty()) {
     detIDtoGroup = makeGroupingByNames(GroupNames, inst, prog, sortnames);
-  else if (!OldCalFilename.empty())
+    if (grouping.compare("2_4Grouping") == 0) {
+      std::map<detid_t, int>::const_iterator it_end = detIDtoGroup.end();
+      std::map<detid_t, int>::const_iterator it;
+      for (it = detIDtoGroup.begin(); it != it_end; ++it) {
+        if (it->second < 5)
+          detIDtoGroup[it->first] = 1;
+        else
+          detIDtoGroup[it->first] = 2;
+      }
+    }
+
+  } else if (!OldCalFilename.empty())
     detIDtoGroup = readGroupingFile(OldCalFilename, prog);
   else if ((numGroups > 0) && !componentName.empty())
     detIDtoGroup =
diff --git a/Framework/Algorithms/src/CreateLogPropertyTable.cpp b/Framework/Algorithms/src/CreateLogPropertyTable.cpp
index a22bef79ccbabd6d61b932d7b14e321f04c71c57..4b6f41a8e91e5f3dfceaf8b857eea95aff01e005 100644
--- a/Framework/Algorithms/src/CreateLogPropertyTable.cpp
+++ b/Framework/Algorithms/src/CreateLogPropertyTable.cpp
@@ -1,6 +1,3 @@
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidAlgorithms/CreateLogPropertyTable.h"
 
 #include "MantidAPI/ITableWorkspace.h"
@@ -8,6 +5,7 @@
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/Run.h"
 #include "MantidAPI/WorkspaceFactory.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidKernel/ArrayProperty.h"
 #include "MantidKernel/ListValidator.h"
 #include "MantidKernel/MandatoryValidator.h"
diff --git a/Framework/Algorithms/src/CreateLogTimeCorrection.cpp b/Framework/Algorithms/src/CreateLogTimeCorrection.cpp
index 94a3f3b9663747446eede1a87d3d383784415d5f..0f949c3e9ba18f133067403b91a17ca8cf8dfe4b 100644
--- a/Framework/Algorithms/src/CreateLogTimeCorrection.cpp
+++ b/Framework/Algorithms/src/CreateLogTimeCorrection.cpp
@@ -49,7 +49,7 @@ void CreateLogTimeCorrection::exec() {
 
   //   Check whether the output workspace name is same as input
   string outwsname = getPropertyValue("OutputWorkspace");
-  if (outwsname.compare(m_dataWS->name()) == 0) {
+  if (outwsname.compare(m_dataWS->getName()) == 0) {
     stringstream errmsg;
     errmsg << "It is not allowed to use the same name by both input matrix "
               "workspace and output table workspace.";
@@ -69,7 +69,7 @@ void CreateLogTimeCorrection::exec() {
 
   string filename = getProperty("OutputFilename");
   g_log.information() << "Output file name is " << filename << ".\n";
-  if (filename.size() > 0) {
+  if (!filename.empty()) {
     writeCorrectionToFile(filename);
   }
 }
diff --git a/Framework/Algorithms/src/CreatePSDBleedMask.cpp b/Framework/Algorithms/src/CreatePSDBleedMask.cpp
index 3c096be5f472d65eaacaf2f4717970b1749f2556..56e19b29e6c385928ede57999e58581eced0f02d 100644
--- a/Framework/Algorithms/src/CreatePSDBleedMask.cpp
+++ b/Framework/Algorithms/src/CreatePSDBleedMask.cpp
@@ -1,5 +1,6 @@
 #include "MantidAlgorithms/CreatePSDBleedMask.h"
 #include "MantidAPI/Run.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidAPI/WorkspaceProperty.h"
 #include "MantidGeometry/Instrument/DetectorGroup.h"
 #include "MantidKernel/BoundedValidator.h"
@@ -98,6 +99,8 @@ void CreatePSDBleedMask::exec() {
 
   API::Progress progress(this, 0, 1, numSpectra);
 
+  const auto &spectrumInfo = inputWorkspace->spectrumInfo();
+
   // NOTE: This loop is intentionally left unparallelized as the majority of the
   // work requires a lock around it which actually slows down the loop.
   // Another benefit of keep it serial is losing the need for a call to 'sort'
@@ -106,24 +109,23 @@ void CreatePSDBleedMask::exec() {
   // correct
   // order
   for (int i = 0; i < numSpectra; ++i) {
-    IDetector_const_sptr det;
-    try {
-      det = inputWorkspace->getDetector(i);
-    } catch (Kernel::Exception::NotFoundError &) {
+    if (!spectrumInfo.hasDetectors(i))
       continue;
-    }
-    if (det->isMonitor())
+
+    if (spectrumInfo.isMonitor(i))
       continue;
 
-    boost::shared_ptr<const Geometry::DetectorGroup> group =
-        boost::dynamic_pointer_cast<const Geometry::DetectorGroup>(det);
+    auto &det = spectrumInfo.detector(i);
+    boost::shared_ptr<const Geometry::IComponent> parent;
 
-    if (group) {
-      det = group->getDetectors().front();
-      if (!det)
-        continue;
+    if (!spectrumInfo.hasUniqueDetector(i)) {
+      const Geometry::DetectorGroup &group =
+          dynamic_cast<const Geometry::DetectorGroup &>(det);
+      parent = group.getDetectors().front()->getParent();
+    } else {
+      parent = det.getParent();
     }
-    boost::shared_ptr<const Geometry::IComponent> parent = det->getParent();
+
     if (!parent)
       continue;
 
diff --git a/Framework/Algorithms/src/CreatePeaksWorkspace.cpp b/Framework/Algorithms/src/CreatePeaksWorkspace.cpp
index 3907b4f7e01c9f88e0b4146bc07dcb4fdcf20a7a..5798838d5e6609528a966970bdd2abd9bc75157b 100644
--- a/Framework/Algorithms/src/CreatePeaksWorkspace.cpp
+++ b/Framework/Algorithms/src/CreatePeaksWorkspace.cpp
@@ -1,6 +1,7 @@
 #include "MantidAlgorithms/CreatePeaksWorkspace.h"
 #include "MantidKernel/System.h"
 #include "MantidDataObjects/PeaksWorkspace.h"
+#include "MantidGeometry/Instrument/Goniometer.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/Run.h"
 
diff --git a/Framework/Algorithms/src/CreateSampleWorkspace.cpp b/Framework/Algorithms/src/CreateSampleWorkspace.cpp
index e24b9694d568f7a5baf587d5acd9af02fc51a460..8a8bf4524705b76a875d6f13e40385d2126ecea3 100644
--- a/Framework/Algorithms/src/CreateSampleWorkspace.cpp
+++ b/Framework/Algorithms/src/CreateSampleWorkspace.cpp
@@ -8,6 +8,7 @@
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidDataObjects/Workspace2D.h"
 #include "MantidDataObjects/EventWorkspace.h"
+#include "MantidDataObjects/WorkspaceCreation.h"
 #include "MantidGeometry/Objects/ShapeFactory.h"
 #include "MantidGeometry/Instrument/ReferenceFrame.h"
 #include "MantidGeometry/Instrument/RectangularDetector.h"
@@ -15,6 +16,8 @@
 #include "MantidKernel/ListValidator.h"
 #include "MantidKernel/UnitFactory.h"
 #include "MantidKernel/MersenneTwister.h"
+#include "MantidIndexing/IndexInfo.h"
+#include "MantidIndexing/MakeRange.h"
 
 #include <cmath>
 #include <ctime>
@@ -27,13 +30,10 @@ using namespace Kernel;
 using namespace API;
 using namespace Geometry;
 using namespace DataObjects;
+using namespace HistogramData;
+using namespace Indexing;
 using Mantid::MantidVec;
 using Mantid::MantidVecPtr;
-using HistogramData::BinEdges;
-using HistogramData::Counts;
-using HistogramData::CountVariances;
-using HistogramData::CountStandardDeviations;
-using HistogramData::LinearGenerator;
 
 // Register the algorithm into the AlgorithmFactory
 DECLARE_ALGORITHM(CreateSampleWorkspace)
@@ -303,21 +303,16 @@ MatrixWorkspace_sptr CreateSampleWorkspace::createHistogramWorkspace(
   Counts y(evalFunction(functionString, xValues, isRandom ? 1 : 0));
   CountStandardDeviations e(CountVariances(y.cbegin(), y.cend()));
 
-  auto retVal = createWorkspace<Workspace2D>(numPixels + numMonitors,
-                                             numBins + 1, numBins);
-  retVal->setInstrument(inst);
-
-  for (int wi = 0; wi < numMonitors + numPixels; wi++) {
-    detid_t detNumber = wi < numMonitors ? start_at_pixelID + numPixels + wi
-                                         : start_at_pixelID + wi - numMonitors;
-    retVal->setBinEdges(wi, x);
-    retVal->setCounts(wi, y);
-    retVal->setCountStandardDeviations(wi, e);
-    retVal->getSpectrum(wi).setDetectorID(detNumber);
-    retVal->getSpectrum(wi).setSpectrumNo(specnum_t(wi + 1));
-  }
+  std::vector<detid_t> detIDs;
+  for (int wi = 0; wi < numMonitors + numPixels; wi++)
+    detIDs.push_back(wi < numMonitors ? start_at_pixelID + numPixels + wi
+                                      : start_at_pixelID + wi - numMonitors);
+  Indexing::IndexInfo indexInfo(numPixels + numMonitors);
+  indexInfo.setDetectorIDs(std::move(detIDs));
 
-  return retVal;
+  auto retVal = create<Workspace2D>(indexInfo, Histogram(x, y, e));
+  retVal->setInstrument(inst);
+  return std::move(retVal);
 }
 
 /** Create event workspace
@@ -328,18 +323,20 @@ EventWorkspace_sptr CreateSampleWorkspace::createEventWorkspace(
     const std::string &functionString, bool isRandom) {
   DateAndTime run_start("2010-01-01T00:00:00");
 
+  std::vector<detid_t> detIDs;
+  for (int wi = 0; wi < numPixels + numMonitors; wi++)
+    detIDs.push_back(wi < numMonitors ? start_at_pixelID + numPixels + wi
+                                      : start_at_pixelID + wi - numMonitors);
+  Indexing::IndexInfo indexInfo(numPixels + numMonitors);
+  indexInfo.setDetectorIDs(std::move(detIDs));
+
   // add one to the number of bins as this is histogram
   int numXBins = numBins + 1;
+  BinEdges x(numXBins, LinearGenerator(x0, binDelta));
 
-  auto retVal = boost::make_shared<EventWorkspace>();
-  retVal->initialize(numPixels + numMonitors, 1, 1);
-
+  auto retVal = create<EventWorkspace>(indexInfo, x);
   retVal->setInstrument(inst);
 
-  // Set all the histograms at once.
-  BinEdges x(numXBins, LinearGenerator(x0, binDelta));
-  retVal->setAllX(x);
-
   std::vector<double> xValues(x.cbegin(), x.cend() - 1);
   std::vector<double> yValues =
       evalFunction(functionString, xValues, isRandom ? 1 : 0);
@@ -358,13 +355,6 @@ EventWorkspace_sptr CreateSampleWorkspace::createEventWorkspace(
   const double hourInSeconds = 60 * 60;
   for (int wi = 0; wi < numPixels + numMonitors; wi++) {
     EventList &el = retVal->getSpectrum(workspaceIndex);
-    el.setSpectrumNo(wi + 1);
-    detid_t detNumber = wi < numMonitors ? start_at_pixelID + numPixels + wi
-                                         : start_at_pixelID + wi - numMonitors;
-    el.setDetectorID(detNumber);
-
-    // for each bin
-
     for (int i = 0; i < numBins; ++i) {
       // create randomised events within the bin to match the number required -
       // calculated in yValues earlier
@@ -378,7 +368,7 @@ EventWorkspace_sptr CreateSampleWorkspace::createEventWorkspace(
     workspaceIndex++;
   }
 
-  return retVal;
+  return std::move(retVal);
 }
 //----------------------------------------------------------------------------------------------
 /**
diff --git a/Framework/Algorithms/src/CreateTransmissionWorkspace.cpp b/Framework/Algorithms/src/CreateTransmissionWorkspace.cpp
index 480a7750823e9452083b21e9df38f6183e48f35c..ea2bfebd41d0d8b2c43a20267c8abbdea0a4737b 100644
--- a/Framework/Algorithms/src/CreateTransmissionWorkspace.cpp
+++ b/Framework/Algorithms/src/CreateTransmissionWorkspace.cpp
@@ -1,6 +1,7 @@
 #include "MantidAlgorithms/CreateTransmissionWorkspace.h"
 #include "MantidAlgorithms/BoostOptionalToAlgorithmProperty.h"
 
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/WorkspaceUnitValidator.h"
 #include "MantidKernel/EnabledWhenProperty.h"
 
diff --git a/Framework/Algorithms/src/CropToComponent.cpp b/Framework/Algorithms/src/CropToComponent.cpp
index 8bfa3ad16e1d4c19382b30e11c7d0d65b2a18907..239cb9e95d8181babd577311dacbe786b7da90a9 100644
--- a/Framework/Algorithms/src/CropToComponent.cpp
+++ b/Framework/Algorithms/src/CropToComponent.cpp
@@ -17,15 +17,29 @@ void getDetectors(
   }
 }
 
-void getDetectorIDs(
+void getWorkspaceIndices(
+    Mantid::API::MatrixWorkspace_sptr workspace,
     std::vector<Mantid::Geometry::IDetector_const_sptr> &detectors,
-    std::vector<Mantid::detid_t> &detectorIDs) {
-  auto numberOfDetectors = static_cast<int>(detectors.size());
+    std::vector<size_t> &workspaceIndices) {
+  const auto numberOfDetectors = static_cast<int>(detectors.size());
+  std::vector<Mantid::detid_t> detectorIds(numberOfDetectors);
+
   PARALLEL_FOR_NO_WSP_CHECK()
   for (int index = 0; index < numberOfDetectors; ++index) {
     auto det = detectors[index];
-    detectorIDs[index] = det->getID();
+    detectorIds[index] = det->getID();
   }
+
+  // Get the corresponding workspace indices
+  auto detIdToWorkspaceIndexMap =
+      workspace->getDetectorIDToWorkspaceIndexMap(true);
+  PARALLEL_FOR_NO_WSP_CHECK()
+  for (int index = 0; index < numberOfDetectors; ++index) {
+    workspaceIndices[index] = detIdToWorkspaceIndexMap[detectorIds[index]];
+  }
+
+  // Sort the workspace indices
+  std::sort(workspaceIndices.begin(), workspaceIndices.end());
 }
 }
 
@@ -73,9 +87,6 @@ void CropToComponent::init() {
           "ComponentNames"),
       "List of component names which are used to crop the workspace."
       "to.");
-  declareProperty("OrderByDetId", false,
-                  "Whether to order the elements of "
-                  "the component by increasing detector ID.");
 }
 
 //----------------------------------------------------------------------------------------------
@@ -91,14 +102,9 @@ void CropToComponent::exec() {
   std::vector<Mantid::Geometry::IDetector_const_sptr> detectors;
   getDetectors(inputWorkspace, componentNames, detectors);
 
-  // Get the detector IDs from the Detectors
-  std::vector<detid_t> detectorIDs(detectors.size());
-  getDetectorIDs(detectors, detectorIDs);
-
-  const bool orderByDetID = getProperty("OrderByDetId");
-  if (orderByDetID) {
-    std::sort(detectorIDs.begin(), detectorIDs.end());
-  }
+  // Get the corresponding workspace indices from the detectors
+  std::vector<size_t> workspaceIndices(detectors.size());
+  getWorkspaceIndices(inputWorkspace, detectors, workspaceIndices);
 
   // Run ExtractSpectra in order to obtain the cropped workspace
   auto extract_alg = Mantid::API::AlgorithmManager::Instance().createUnmanaged(
@@ -107,7 +113,7 @@ void CropToComponent::exec() {
   extract_alg->initialize();
   extract_alg->setProperty("InputWorkspace", inputWorkspace);
   extract_alg->setProperty("OutputWorkspace", "dummy");
-  extract_alg->setProperty("DetectorList", detectorIDs);
+  extract_alg->setProperty("WorkspaceIndexList", workspaceIndices);
   extract_alg->execute();
   Mantid::API::MatrixWorkspace_sptr outputWorkspace =
       extract_alg->getProperty("OutputWorkspace");
diff --git a/Framework/Algorithms/src/CrossCorrelate.cpp b/Framework/Algorithms/src/CrossCorrelate.cpp
index 27a527d38c44776744bb2bd913dc589e443f7115..b3fafaa00981d130aa45831d12288a3b736f10ce 100644
--- a/Framework/Algorithms/src/CrossCorrelate.cpp
+++ b/Framework/Algorithms/src/CrossCorrelate.cpp
@@ -77,7 +77,7 @@ void CrossCorrelate::exec() {
   auto minIt = std::find_if(referenceX.cbegin(), referenceX.cend(),
                             std::bind2nd(std::greater<double>(), xmin));
   if (minIt == referenceX.cend())
-    throw std::runtime_error("No daWorkspaceIndexMaxta above XMin");
+    throw std::runtime_error("No data above XMin");
   auto maxIt = std::find_if(minIt, referenceX.cend(),
                             std::bind2nd(std::greater<double>(), xmax));
   if (minIt == maxIt)
@@ -135,6 +135,9 @@ void CrossCorrelate::exec() {
   // Create a 2DWorkspace that will hold the result
   const int nY = static_cast<int>(refY.size());
   const int npoints = 2 * nY - 3;
+  if (npoints < 1)
+    throw std::runtime_error("Range is not valid");
+
   MatrixWorkspace_sptr out =
       WorkspaceFactory::Instance().create(inputWS, nspecs, npoints, npoints);
 
diff --git a/Framework/Algorithms/src/CylinderAbsorption.cpp b/Framework/Algorithms/src/CylinderAbsorption.cpp
index e53f194cb50b1cee566ca1b87b98f380e64b14bd..c54af1c352c05dce23a9b745f06519f3d678dc70 100644
--- a/Framework/Algorithms/src/CylinderAbsorption.cpp
+++ b/Framework/Algorithms/src/CylinderAbsorption.cpp
@@ -1,9 +1,8 @@
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidAlgorithms/CylinderAbsorption.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidGeometry/Instrument.h"
+#include "MantidGeometry/Objects/Object.h"
+#include "MantidGeometry/Objects/Track.h"
 #include "MantidKernel/BoundedValidator.h"
 
 namespace Mantid {
diff --git a/Framework/Algorithms/src/DeleteWorkspace.cpp b/Framework/Algorithms/src/DeleteWorkspace.cpp
index 0bc10a13d6ee26c295a1b84f4c53d2549c2654fc..030dd4a64a8a0f80dddfeb057855b9b7e84f6adb 100644
--- a/Framework/Algorithms/src/DeleteWorkspace.cpp
+++ b/Framework/Algorithms/src/DeleteWorkspace.cpp
@@ -1,19 +1,12 @@
-//--------------------------------------------------------------------------
-// Includes
-//--------------------------------------------------------------------------
 #include "MantidAlgorithms/DeleteWorkspace.h"
+#include "MantidAPI/AnalysisDataService.h"
 
 namespace Mantid {
-
 namespace Algorithms {
 
 // Register the algorithm
 DECLARE_ALGORITHM(DeleteWorkspace)
 
-//--------------------------------------------------------------------------
-// Private member functions
-//--------------------------------------------------------------------------
-
 /// Initialize the algorithm properties
 void DeleteWorkspace::init() {
   declareProperty(Kernel::make_unique<API::WorkspaceProperty<API::Workspace>>(
diff --git a/Framework/Algorithms/src/DetectorDiagnostic.cpp b/Framework/Algorithms/src/DetectorDiagnostic.cpp
index dbb315c6bfb33b7ac14cbbbe97676f9e383caabb..7b1ea1099f6a9540a272c204363d5b64748246b5 100644
--- a/Framework/Algorithms/src/DetectorDiagnostic.cpp
+++ b/Framework/Algorithms/src/DetectorDiagnostic.cpp
@@ -1,10 +1,9 @@
-//--------------------------------------------------------------------------
-// Includes
-//--------------------------------------------------------------------------
 #include "MantidAlgorithms/DetectorDiagnostic.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidDataObjects/EventWorkspaceHelpers.h"
 #include "MantidDataObjects/MaskWorkspace.h"
+#include "MantidDataObjects/WorkspaceCreation.h"
 #include "MantidKernel/BoundedValidator.h"
 #include "MantidKernel/EnabledWhenProperty.h"
 #include "MantidKernel/Exception.h"
@@ -524,12 +523,11 @@ DataObjects::MaskWorkspace_sptr
 DetectorDiagnostic::generateEmptyMask(API::MatrixWorkspace_const_sptr inputWS) {
   // Create a new workspace for the results, copy from the input to ensure that
   // we copy over the instrument and current masking
-  auto maskWS = boost::make_shared<DataObjects::MaskWorkspace>();
-  maskWS->initialize(inputWS->getNumberHistograms(), 1, 1);
-  WorkspaceFactory::Instance().initializeFromParent(inputWS, maskWS, false);
+  auto maskWS =
+      create<DataObjects::MaskWorkspace>(*inputWS, HistogramData::Points(1));
   maskWS->setTitle(inputWS->getTitle());
 
-  return maskWS;
+  return std::move(maskWS);
 }
 
 std::vector<std::vector<size_t>>
@@ -608,29 +606,26 @@ std::vector<double> DetectorDiagnostic::calculateMedian(
   std::vector<double> medianvec;
   g_log.debug("Calculating the median count rate of the spectra");
 
+  bool checkForMask = false;
+  Geometry::Instrument_const_sptr instrument = input.getInstrument();
+  if (instrument != nullptr) {
+    checkForMask = ((instrument->getSource() != nullptr) &&
+                    (instrument->getSample() != nullptr));
+  }
+  const auto &spectrumInfo = input.spectrumInfo();
+
   for (const auto &hists : indexmap) {
     std::vector<double> medianInput;
     const int nhists = static_cast<int>(hists.size());
     // The maximum possible length is that of workspace length
     medianInput.reserve(nhists);
 
-    bool checkForMask = false;
-    Geometry::Instrument_const_sptr instrument = input.getInstrument();
-    if (instrument != nullptr) {
-      checkForMask = ((instrument->getSource() != nullptr) &&
-                      (instrument->getSample() != nullptr));
-    }
-
     PARALLEL_FOR_IF(Kernel::threadSafe(input))
     for (int i = 0; i < nhists; ++i) { // NOLINT
       PARALLEL_START_INTERUPT_REGION
 
-      if (checkForMask) {
-        const std::set<detid_t> &detids =
-            input.getSpectrum(hists[i]).getDetectorIDs();
-        if (instrument->isDetectorMasked(detids))
-          continue;
-        if (instrument->isMonitor(detids))
+      if (checkForMask && spectrumInfo.hasDetectors(hists[i])) {
+        if (spectrumInfo.isMasked(hists[i]) || spectrumInfo.isMonitor(hists[i]))
           continue;
       }
 
diff --git a/Framework/Algorithms/src/DetectorEfficiencyCor.cpp b/Framework/Algorithms/src/DetectorEfficiencyCor.cpp
index d1c4f78f5d14ea76bd104dffdca0e3fc27cd438c..46828fde5fa5aa85bc21ddbd505f5c5e0d21639f 100644
--- a/Framework/Algorithms/src/DetectorEfficiencyCor.cpp
+++ b/Framework/Algorithms/src/DetectorEfficiencyCor.cpp
@@ -3,10 +3,13 @@
 #include "MantidAPI/HistogramValidator.h"
 #include "MantidAPI/InstrumentValidator.h"
 #include "MantidAPI/Run.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidAPI/WorkspaceUnitValidator.h"
 #include "MantidGeometry/Instrument.h"
 #include "MantidGeometry/Instrument/ParameterMap.h"
+#include "MantidGeometry/Objects/Object.h"
+#include "MantidGeometry/Objects/Track.h"
 #include "MantidKernel/BoundedValidator.h"
 #include "MantidKernel/CompositeValidator.h"
 #include "MantidKernel/Exception.h"
@@ -120,6 +123,7 @@ void DetectorEfficiencyCor::exec() {
   int64_t numHists = m_inputWS->getNumberHistograms();
   double numHists_d = static_cast<double>(numHists);
   const int64_t progStep = static_cast<int64_t>(ceil(numHists_d / 100.0));
+  auto &spectrumInfo = m_inputWS->spectrumInfo();
 
   PARALLEL_FOR_IF(Kernel::threadSafe(*m_inputWS, *m_outputWS))
   for (int64_t i = 0; i < numHists; ++i) {
@@ -127,7 +131,7 @@ void DetectorEfficiencyCor::exec() {
 
     m_outputWS->setSharedX(i, m_inputWS->sharedX(i));
     try {
-      correctForEfficiency(i);
+      correctForEfficiency(i, spectrumInfo);
     } catch (Exception::NotFoundError &) {
       // zero the Y data that can't be corrected
       m_outputWS->mutableY(i) *= 0.0;
@@ -180,18 +184,23 @@ void DetectorEfficiencyCor::retrieveProperties() {
   }
 }
 
-/** Corrects a spectra for the detector efficiency calculated from detector
-information
-Gets the detector information and uses this to calculate its efficiency
-*  @param spectraIn :: index of the spectrum to get the efficiency for
-*  @throw invalid_argument if the shape of a detector is isn't a cylinder
-aligned along one axis
-*  @throw NotFoundError if the detector or its gas pressure or wall thickness
-were not found
-*/
-void DetectorEfficiencyCor::correctForEfficiency(int64_t spectraIn) {
-  IDetector_const_sptr det = m_inputWS->getDetector(spectraIn);
-  if (det->isMonitor() || det->isMasked()) {
+/**
+ * Corrects a spectra for the detector efficiency calculated from detector
+ * information
+ * Gets the detector information and uses this to calculate its efficiency
+ *  @param spectraIn :: index of the spectrum to get the efficiency for
+ *  @param spectrumInfo :: The SpectrumInfo object for the input workspace
+ *  @throw invalid_argument if the shape of a detector is not a cylinder aligned
+ * along one axis
+ *  @throw NotFoundError if the detector or its gas pressure or wall thickness
+ * were not found
+ */
+void DetectorEfficiencyCor::correctForEfficiency(
+    int64_t spectraIn, const SpectrumInfo &spectrumInfo) {
+  if (!spectrumInfo.hasDetectors(spectraIn))
+    throw Exception::NotFoundError("No detectors found", spectraIn);
+
+  if (spectrumInfo.isMonitor(spectraIn) || spectrumInfo.isMasked(spectraIn)) {
     return;
   }
 
@@ -209,9 +218,6 @@ void DetectorEfficiencyCor::correctForEfficiency(int64_t spectraIn) {
                                                         // average the
                                                         // correction computing
                                                         // it for the spectrum
-  if (ndets == 0) {
-    throw Exception::NotFoundError("No detectors found", spectraIn);
-  }
 
   // Storage for the reciprocal wave vectors that are calculated as the
   // correction proceeds
diff --git a/Framework/Algorithms/src/DetectorEfficiencyCorUser.cpp b/Framework/Algorithms/src/DetectorEfficiencyCorUser.cpp
index 66ec494094395d3a0564e14bdcf33b991cb0bb69..54475523b3552d23620654bb8315d6bf017366ff 100644
--- a/Framework/Algorithms/src/DetectorEfficiencyCorUser.cpp
+++ b/Framework/Algorithms/src/DetectorEfficiencyCorUser.cpp
@@ -8,6 +8,7 @@
 #include "MantidGeometry/muParser_Silent.h"
 #include "MantidKernel/BoundedValidator.h"
 #include "MantidKernel/CompositeValidator.h"
+#include "MantidKernel/Strings.h"
 
 using Mantid::HistogramData::Histogram;
 using Mantid::HistogramData::Points;
diff --git a/Framework/Algorithms/src/DiffractionEventCalibrateDetectors.cpp b/Framework/Algorithms/src/DiffractionEventCalibrateDetectors.cpp
index a57422657fab20266d7e1e1eec6699112eabe040..28fddc3280135c715b5b777309b397e6f532c012 100644
--- a/Framework/Algorithms/src/DiffractionEventCalibrateDetectors.cpp
+++ b/Framework/Algorithms/src/DiffractionEventCalibrateDetectors.cpp
@@ -1,8 +1,6 @@
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidAlgorithms/DiffractionEventCalibrateDetectors.h"
 #include "MantidAlgorithms/GSLFunctions.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/FileProperty.h"
 #include "MantidAPI/IFunction.h"
 #include "MantidAPI/InstrumentValidator.h"
@@ -410,7 +408,6 @@ void DiffractionEventCalibrateDetectors::exec() {
     std::cout << tim << " to CreateGroupingWorkspace\n";
 
     const gsl_multimin_fminimizer_type *T = gsl_multimin_fminimizer_nmsimplex;
-    gsl_multimin_fminimizer *s = nullptr;
     gsl_vector *ss, *x;
     gsl_multimin_function minex_func;
 
@@ -438,7 +435,7 @@ void DiffractionEventCalibrateDetectors::exec() {
     minex_func.f = &Mantid::Algorithms::gsl_costFunction;
     minex_func.params = &par;
 
-    s = gsl_multimin_fminimizer_alloc(T, nopt);
+    gsl_multimin_fminimizer *s = gsl_multimin_fminimizer_alloc(T, nopt);
     gsl_multimin_fminimizer_set(s, &minex_func, x, ss);
 
     do {
diff --git a/Framework/Algorithms/src/DiffractionFocussing.cpp b/Framework/Algorithms/src/DiffractionFocussing.cpp
index 458256d04f9c153ec1b80aeab4549ef62faea217..efd56eaa0add57f6f1fe95e5aede719d262ce227 100644
--- a/Framework/Algorithms/src/DiffractionFocussing.cpp
+++ b/Framework/Algorithms/src/DiffractionFocussing.cpp
@@ -1,12 +1,10 @@
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidAlgorithms/DiffractionFocussing.h"
 #include "MantidAPI/Axis.h"
 #include "MantidAPI/FileProperty.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidKernel/Unit.h"
+#include "MantidIndexing/IndexInfo.h"
 
 #include <fstream>
 #include <limits>
@@ -133,14 +131,17 @@ void DiffractionFocussing::exec() {
   API::MatrixWorkspace_sptr outputW = API::WorkspaceFactory::Instance().create(
       tmpW, resultIndeces.size(), newSize + 1, newSize);
 
+  std::vector<specnum_t> specNums;
+  const auto &tmpIndices = tmpW->indexInfo();
   for (int64_t hist = 0; hist < static_cast<int64_t>(resultIndeces.size());
        hist++) {
     int64_t i = resultIndeces[hist];
     outputW->setHistogram(hist, tmpW->histogram(i));
-    auto &inSpec = tmpW->getSpectrum(i);
-    outputW->getSpectrum(hist).setSpectrumNo(inSpec.getSpectrumNo());
-    inSpec.setSpectrumNo(-1);
+    specNums.push_back(tmpIndices.spectrumNumber(i));
   }
+  auto outputIndices = outputW->indexInfo();
+  outputIndices.setSpectrumNumbers(std::move(specNums));
+  outputW->setIndexInfo(outputIndices);
 
   progress(1.);
 
diff --git a/Framework/Algorithms/src/DiffractionFocussing2.cpp b/Framework/Algorithms/src/DiffractionFocussing2.cpp
index 16f90e20fd8d1121b648fd4f3f79d1d07d620366..9c53f1b3a87754e930bfd2cef0dbb6f73638afad 100644
--- a/Framework/Algorithms/src/DiffractionFocussing2.cpp
+++ b/Framework/Algorithms/src/DiffractionFocussing2.cpp
@@ -6,10 +6,14 @@
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/RawCountValidator.h"
 #include "MantidAPI/SpectraAxis.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidDataObjects/EventWorkspace.h"
 #include "MantidDataObjects/GroupingWorkspace.h"
+#include "MantidDataObjects/WorkspaceCreation.h"
 #include "MantidKernel/VectorHelper.h"
+#include "MantidIndexing/Group.h"
+#include "MantidIndexing/IndexInfo.h"
 
 #include <cfloat>
 #include <iterator>
@@ -190,10 +194,6 @@ void DiffractionFocussing2::exec() {
     // This is the output spectrum
     auto &outSpec = out->getSpectrum(outWorkspaceIndex);
 
-    // Also set the spectrum number to the group number
-    outSpec.setSpectrumNo(group);
-    outSpec.clearDetectorIDs();
-
     // Get the references to Y and E output and rebin
     // TODO can only be changed once rebin implemented in HistogramData
     auto &Yout = outSpec.dataY();
@@ -204,7 +204,7 @@ void DiffractionFocussing2::exec() {
     MantidVec groupWgt(nPoints, 0.0);
 
     // loop through the contributing histograms
-    std::vector<size_t> indices = m_wsIndices[group];
+    const std::vector<size_t> &indices = m_wsIndices[outWorkspaceIndex];
     const size_t groupSize = indices.size();
     for (size_t i = 0; i < groupSize; i++) {
       size_t inWorkspaceIndex = indices[i];
@@ -215,7 +215,6 @@ void DiffractionFocussing2::exec() {
       auto &Yin = inSpec.y();
       auto &Ein = inSpec.e();
 
-      outSpec.addDetectorIDs(inSpec.getDetectorIDs());
       try {
         // TODO This should be implemented in Histogram as rebin
         Mantid::Kernel::VectorHelper::rebinHistogram(
@@ -318,6 +317,10 @@ void DiffractionFocussing2::exec() {
   } // end of loop for groups
   PARALLEL_CHECK_INTERUPT_REGION
 
+  out->setIndexInfo(Indexing::group(m_matrixInputW->indexInfo(),
+                                    std::move(m_validGroups),
+                                    std::move(m_wsIndices)));
+
   delete prog;
 
   setProperty("OutputWorkspace", out);
@@ -334,13 +337,7 @@ void DiffractionFocussing2::exec() {
  */
 void DiffractionFocussing2::execEvent() {
   // Create a new outputworkspace with not much in it
-  DataObjects::EventWorkspace_sptr out;
-  out = boost::dynamic_pointer_cast<EventWorkspace>(
-      API::WorkspaceFactory::Instance().create("EventWorkspace",
-                                               m_validGroups.size(), 2, 1));
-  // Copy required stuff from it
-  API::WorkspaceFactory::Instance().initializeFromParent(m_matrixInputW, out,
-                                                         true);
+  auto out = create<EventWorkspace>(*m_matrixInputW, m_validGroups.size());
 
   MatrixWorkspace_const_sptr outputWS = getProperty("OutputWorkspace");
   bool inPlace = (m_matrixInputW == outputWS);
@@ -358,8 +355,7 @@ void DiffractionFocussing2::execEvent() {
   vector<size_t> size_required(this->m_validGroups.size(), 0);
   int totalHistProcess = 0;
   for (size_t iGroup = 0; iGroup < this->m_validGroups.size(); iGroup++) {
-    const int group = this->m_validGroups[iGroup];
-    const vector<size_t> &indices = this->m_wsIndices[group];
+    const vector<size_t> &indices = this->m_wsIndices[iGroup];
 
     totalHistProcess += static_cast<int>(indices.size());
     for (auto index : indices) {
@@ -391,8 +387,7 @@ void DiffractionFocussing2::execEvent() {
     g_log.information() << "Performing focussing on a single group\n";
     // Special case of a single group - parallelize differently
     EventList &groupEL = out->getSpectrum(0);
-    const int group = m_validGroups[0];
-    const std::vector<size_t> &indices = this->m_wsIndices[group];
+    const std::vector<size_t> &indices = this->m_wsIndices[0];
 
     int chunkSize = 200;
 
@@ -434,8 +429,7 @@ void DiffractionFocussing2::execEvent() {
     PARALLEL_FOR_IF(Kernel::threadSafe(*m_eventW))
     for (int iGroup = 0; iGroup < nValidGroups; iGroup++) {
       PARALLEL_START_INTERUPT_REGION
-      const int group = this->m_validGroups[iGroup];
-      const std::vector<size_t> &indices = this->m_wsIndices[group];
+      const std::vector<size_t> &indices = this->m_wsIndices[iGroup];
       for (auto wi : indices) {
         // In workspace index iGroup, put what was in the OLD workspace index wi
         out->getSpectrum(iGroup) += m_eventW->getSpectrum(wi);
@@ -487,8 +481,7 @@ void DiffractionFocussing2::execEvent() {
                          "groups. Histogram will be empty.\n";
   }
   out->clearMRU();
-  setProperty("OutputWorkspace",
-              boost::dynamic_pointer_cast<MatrixWorkspace>(out));
+  setProperty("OutputWorkspace", std::move(out));
   delete prog;
 }
 
@@ -559,6 +552,7 @@ void DiffractionFocussing2::determineRebinParameters() {
     checkForMask = ((instrument->getSource() != nullptr) &&
                     (instrument->getSample() != nullptr));
   }
+  const auto &spectrumInfo = m_matrixInputW->spectrumInfo();
 
   groupAtWorkspaceIndex.resize(nHist);
   for (int wi = 0; wi < nHist;
@@ -569,10 +563,8 @@ void DiffractionFocussing2::determineRebinParameters() {
     if (group == -1)
       continue;
 
-    // the spectrum is the real thing we want to work with
-    const auto &spec = m_matrixInputW->getSpectrum(wi);
     if (checkForMask) {
-      if (instrument->isDetectorMasked(spec.getDetectorIDs())) {
+      if (spectrumInfo.isMasked(wi)) {
         groupAtWorkspaceIndex[wi] = -1;
         continue;
       }
@@ -586,7 +578,7 @@ void DiffractionFocussing2::determineRebinParameters() {
     }
     const double min = (gpit->second).first;
     const double max = (gpit->second).second;
-    auto &X = spec.x();
+    auto &X = m_matrixInputW->x(wi);
     double temp = X.front();
     if (temp < (min)) // New Xmin found
       (gpit->second).first = temp;
@@ -672,6 +664,11 @@ size_t DiffractionFocussing2::setupGroupToWSIndices() {
     }
   }
 
+  m_wsIndices.erase(
+      std::remove_if(m_wsIndices.begin(), m_wsIndices.end(),
+                     [](const std::vector<size_t> &v) { return v.empty(); }),
+      m_wsIndices.end());
+
   return totalHistProcess;
 }
 
diff --git a/Framework/Algorithms/src/Divide.cpp b/Framework/Algorithms/src/Divide.cpp
index 6c1fdfabef9ae919ee0cda85435b68feaea2d5f7..bb2c5fd000a900d2bccd93248eb8c1acb4b17f92 100644
--- a/Framework/Algorithms/src/Divide.cpp
+++ b/Framework/Algorithms/src/Divide.cpp
@@ -88,7 +88,8 @@ void Divide::performBinaryOperation(const MantidVec &lhsX,
 void Divide::setOutputUnits(const API::MatrixWorkspace_const_sptr lhs,
                             const API::MatrixWorkspace_const_sptr rhs,
                             API::MatrixWorkspace_sptr out) {
-  if (rhs->YUnit().empty() || !WorkspaceHelpers::matchingBins(lhs, rhs, true)) {
+  if (rhs->YUnit().empty() ||
+      !WorkspaceHelpers::matchingBins(*lhs, *rhs, true)) {
     // Do nothing
   }
   // If the Y units match, then the output will be a distribution and will be
@@ -221,7 +222,7 @@ std::string Divide::checkSizeCompatibility(
   if (m_matchXSize) {
     // Past this point, for a 2D WS operation, we require the X arrays to match.
     // Note this only checks the first spectrum
-    if (!WorkspaceHelpers::matchingBins(lhs, rhs, true)) {
+    if (!WorkspaceHelpers::matchingBins(*lhs, *rhs, true)) {
       return "X arrays must match when dividing 2D workspaces.";
     }
   }
diff --git a/Framework/Algorithms/src/EditInstrumentGeometry.cpp b/Framework/Algorithms/src/EditInstrumentGeometry.cpp
index 730fc7abb507f3c99d0a0fb2aaebdbb63a183471..fb7b9a82722fa9b0f84e89c937166dbfe9eefa36 100644
--- a/Framework/Algorithms/src/EditInstrumentGeometry.cpp
+++ b/Framework/Algorithms/src/EditInstrumentGeometry.cpp
@@ -5,6 +5,7 @@
 #include "MantidGeometry/Instrument.h"
 #include "MantidKernel/ArrayProperty.h"
 #include "MantidKernel/MandatoryValidator.h"
+#include "MantidIndexing/IndexInfo.h"
 
 #include <sstream>
 
@@ -299,10 +300,9 @@ void EditInstrumentGeometry::exec() {
   instrument->markAsSource(source);
   source->setPos(0.0, 0.0, -1.0 * l1);
 
-  // Add the new instrument
-  workspace->setInstrument(instrument);
-
   // Add/copy detector information
+  auto indexInfo = workspace->indexInfo();
+  std::vector<detid_t> detIDs;
   for (size_t i = 0; i < workspace->getNumberHistograms(); i++) {
     // Create a new detector.
     //    (Instrument will take ownership of pointer so no need to delete.)
@@ -324,17 +324,21 @@ void EditInstrumentGeometry::exec() {
     detector->setPos(pos);
 
     // Add new detector to spectrum and instrument
-    auto &spectrum = workspace->getSpectrum(i);
     // Good and do some debug output
-    g_log.debug() << "Orignal spectrum " << spectrum.getSpectrumNo() << "has "
-                  << spectrum.getDetectorIDs().size() << " detectors. \n";
+    g_log.debug() << "Orignal spectrum " << indexInfo.spectrumNumber(i)
+                  << "has " << indexInfo.detectorIDs(i).size()
+                  << " detectors. \n";
 
-    spectrum.clearDetectorIDs();
-    spectrum.addDetectorID(newdetid);
+    detIDs.push_back(newdetid);
     instrument->add(detector);
     instrument->markAsDetector(detector);
 
   } // ENDFOR workspace index
+  indexInfo.setDetectorIDs(std::move(detIDs));
+  workspace->setIndexInfo(indexInfo);
+
+  // Add the new instrument
+  workspace->setInstrument(instrument);
 }
 
 } // namespace Mantid
diff --git a/Framework/Algorithms/src/EstimateResolutionDiffraction.cpp b/Framework/Algorithms/src/EstimateResolutionDiffraction.cpp
index 71e5c6c39ad82d62c25b1c1e940682705896113c..7d40bff984126d7260e021d31593bde062a41e5a 100644
--- a/Framework/Algorithms/src/EstimateResolutionDiffraction.cpp
+++ b/Framework/Algorithms/src/EstimateResolutionDiffraction.cpp
@@ -1,8 +1,8 @@
 #include "MantidAlgorithms/EstimateResolutionDiffraction.h"
+#include "MantidAPI/DetectorInfo.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/Run.h"
 #include "MantidAPI/SpectrumInfo.h"
-#include "MantidAPI/WorkspaceFactory.h"
 #include "MantidAPI/WorkspaceProperty.h"
 #include "MantidGeometry/IDetector.h"
 #include "MantidGeometry/Instrument/Detector.h"
@@ -10,6 +10,8 @@
 #include "MantidKernel/PhysicalConstants.h"
 #include "MantidKernel/TimeSeriesProperty.h"
 #include "MantidKernel/V3D.h"
+#include "MantidDataObjects/Workspace2D.h"
+#include "MantidDataObjects/WorkspaceCreation.h"
 
 #include <cmath>
 
@@ -87,7 +89,8 @@ void EstimateResolutionDiffraction::exec() {
 
   retrieveInstrumentParameters();
 
-  createOutputWorkspace();
+  m_outputWS = DataObjects::create<DataObjects::Workspace2D>(
+      *m_inputWS, HistogramData::Points(1));
 
   estimateDetectorResolution();
 
@@ -143,21 +146,11 @@ void EstimateResolutionDiffraction::retrieveInstrumentParameters() {
   g_log.notice() << "Centre neutron velocity = " << m_centreVelocity << "\n";
 }
 
-/**
-  */
-void EstimateResolutionDiffraction::createOutputWorkspace() {
-  size_t numspec = m_inputWS->getNumberHistograms();
-
-  m_outputWS = boost::dynamic_pointer_cast<MatrixWorkspace>(
-      WorkspaceFactory::Instance().create("Workspace2D", numspec, 1, 1));
-  // Copy geometry over.
-  API::WorkspaceFactory::Instance().initializeFromParent(m_inputWS, m_outputWS,
-                                                         false);
-}
 /**
   */
 void EstimateResolutionDiffraction::estimateDetectorResolution() {
   const auto &spectrumInfo = m_inputWS->spectrumInfo();
+  const auto &detectorInfo = m_inputWS->detectorInfo();
   const auto l1 = spectrumInfo.l1();
   g_log.notice() << "L1 = " << l1 << "\n";
   const V3D samplepos = spectrumInfo.samplePosition();
@@ -197,7 +190,12 @@ void EstimateResolutionDiffraction::estimateDetectorResolution() {
         spectrumInfo.isMonitor(i) ? 0.0 : spectrumInfo.twoTheta(i);
     double theta = 0.5 * twotheta;
 
-    double solidangle = det.solidAngle(samplepos);
+    double solidangle = 0.0;
+    for (const auto detID : m_inputWS->getSpectrum(i).getDetectorIDs()) {
+      const auto index = detectorInfo.indexOf(detID);
+      if (!detectorInfo.isMasked(index))
+        solidangle += detectorInfo.detector(index).solidAngle(samplepos);
+    }
     double deltatheta = sqrt(solidangle);
 
     // Resolution
diff --git a/Framework/Algorithms/src/ExportTimeSeriesLog.cpp b/Framework/Algorithms/src/ExportTimeSeriesLog.cpp
index 1c9d598fdcf5795192ccf8a03df5eeb2a253a08a..6090c20b461d5c1bc14943298e031e37d8af44b8 100644
--- a/Framework/Algorithms/src/ExportTimeSeriesLog.cpp
+++ b/Framework/Algorithms/src/ExportTimeSeriesLog.cpp
@@ -5,10 +5,10 @@
 #include "MantidAPI/Run.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidAPI/WorkspaceProperty.h"
-#include "MantidAPI/WorkspaceProperty.h"
 #include "MantidDataObjects/EventList.h"
 #include "MantidDataObjects/EventWorkspace.h"
 #include "MantidDataObjects/Events.h"
+#include "MantidDataObjects/WorkspaceCreation.h"
 #include "MantidGeometry/Instrument.h"
 #include "MantidKernel/ListValidator.h"
 #include "MantidKernel/System.h"
@@ -101,7 +101,6 @@ void ExportTimeSeriesLog::exec() {
   * @param outputeventws ::
  * true.
  */
-//----------------------------------------------------------------------------------------------
 /** Export part of designated log to an file in column format and a output file
  * @brief ExportTimeSeriesLog::exportLog
  * @param logname ::  name of log to export
@@ -123,7 +122,7 @@ void ExportTimeSeriesLog::exportLog(const std::string &logname,
   std::vector<Kernel::DateAndTime> times;
   std::vector<double> values;
 
-  if (logname.size() > 0) {
+  if (!logname.empty()) {
     // Log
     Kernel::TimeSeriesProperty<double> *tlog =
         dynamic_cast<Kernel::TimeSeriesProperty<double> *>(
@@ -256,7 +255,6 @@ void ExportTimeSeriesLog::setupWorkspace2D(
   xaxis->setUnit("Time");
 }
 
-//----------------------------------------------------------------------------------------------
 /** Set up an Event workspace
  * @brief ExportTimeSeriesLog::setupEventWorkspace
  * @param start_index
@@ -274,24 +272,14 @@ void ExportTimeSeriesLog::setupEventWorkspace(
 
   // Get some stuff from the input workspace
   const size_t numberOfSpectra = 1;
-  const int YLength = static_cast<int>(m_inputWS->blocksize());
   // determine output size
   size_t outsize = stop_index - start_index + 1;
   if (outsize > static_cast<size_t>(numentries))
     outsize = static_cast<size_t>(numentries);
 
-  // Make a brand new EventWorkspace
-  EventWorkspace_sptr outEventWS = boost::dynamic_pointer_cast<EventWorkspace>(
-      API::WorkspaceFactory::Instance().create(
-          "EventWorkspace", numberOfSpectra, YLength + 1, YLength));
-  // Copy geometry over.
-  API::WorkspaceFactory::Instance().initializeFromParent(m_inputWS, outEventWS,
-                                                         false);
-
-  m_outWS = boost::dynamic_pointer_cast<MatrixWorkspace>(outEventWS);
-  if (!m_outWS)
-    throw runtime_error(
-        "Output workspace cannot be casted to a MatrixWorkspace.");
+  boost::shared_ptr<EventWorkspace> outEventWS = create<EventWorkspace>(
+      *m_inputWS, numberOfSpectra, HistogramData::BinEdges(2));
+  m_outWS = outEventWS;
 
   // Create the output event list (empty)
   EventList &outEL = outEventWS->getSpectrum(0);
diff --git a/Framework/Algorithms/src/ExtractMask.cpp b/Framework/Algorithms/src/ExtractMask.cpp
index 4c735bd8db9d69a8b84378a4f35949a62ba7db90..bd2a694cd77f5ecfedc4e0db4381031a9769946d 100644
--- a/Framework/Algorithms/src/ExtractMask.cpp
+++ b/Framework/Algorithms/src/ExtractMask.cpp
@@ -80,10 +80,6 @@ void ExtractMask::exec() {
   }
   PARALLEL_CHECK_INTERUPT_REGION
 
-  // Clear all the "masked" bits on the output masked workspace
-  Geometry::ParameterMap &pmap = maskWS->instrumentParameters();
-  pmap.clearParametersByName("masked");
-
   g_log.information() << maskWS->getNumberMasked() << " spectra are masked\n";
   g_log.information() << detectorList.size() << " detectors are masked\n";
   setProperty("OutputWorkspace", maskWS);
diff --git a/Framework/Algorithms/src/ExtractMaskToTable.cpp b/Framework/Algorithms/src/ExtractMaskToTable.cpp
index 6b3d82165fc9a11218bfca054bf845d0c166ea06..878ed6bc63941bf414a21b2d43bc489146a2024d 100644
--- a/Framework/Algorithms/src/ExtractMaskToTable.cpp
+++ b/Framework/Algorithms/src/ExtractMaskToTable.cpp
@@ -1,4 +1,5 @@
 #include "MantidAlgorithms/ExtractMaskToTable.h"
+#include "MantidAPI/DetectorInfo.h"
 #include "MantidAPI/WorkspaceProperty.h"
 #include "MantidAPI/TableRow.h"
 #include "MantidDataObjects/MaskWorkspace.h"
@@ -55,7 +56,7 @@ void ExtractMaskToTable::exec() {
 
   bool m_inputIsMask = false;
   if (maskws) {
-    g_log.notice() << "InputWorkspace " << m_dataWS->name()
+    g_log.notice() << "InputWorkspace " << m_dataWS->getName()
                    << " is a MaskWorkspace.\n";
     m_inputIsMask = true;
   } else {
@@ -134,8 +135,8 @@ std::vector<detid_t> ExtractMaskToTable::parseMaskTable(
     chkcolumans[2] = "DetectorIDsList";
     for (int i = 0; i < 3; ++i) {
       if (colnames[i] != chkcolumans[i]) {
-        g_log.error() << "Mask table workspace " << masktablews->name() << "'s "
-                      << i << "-th column name is " << colnames[i]
+        g_log.error() << "Mask table workspace " << masktablews->getName()
+                      << "'s " << i << "-th column name is " << colnames[i]
                       << ", while it should be " << chkcolumans[i]
                       << ". MaskWorkspace is invalid"
                       << " and thus not used.\n";
@@ -202,22 +203,19 @@ std::vector<detid_t> ExtractMaskToTable::extractMaskFromMatrixWorkspace() {
   std::vector<detid_t> maskeddetids;
 
   // Get on hold of instrument
-  Instrument_const_sptr instrument = m_dataWS->getInstrument();
-  if (!instrument)
+  const auto &detectorInfo = m_dataWS->detectorInfo();
+  if (detectorInfo.size() == 0)
     throw runtime_error("There is no instrument in input workspace.");
 
   // Extract
-  size_t numdets = instrument->getNumberDetectors();
-  vector<detid_t> detids = instrument->getDetectorIDs();
+  const vector<detid_t> &detids = detectorInfo.detectorIDs();
 
-  for (size_t i = 0; i < numdets; ++i) {
-    detid_t tmpdetid = detids[i];
-    IDetector_const_sptr tmpdetector = instrument->getDetector(tmpdetid);
-    bool masked = tmpdetector->isMasked();
+  for (size_t i = 0; i < detectorInfo.size(); ++i) {
+    bool masked = detectorInfo.isMasked(i);
     if (masked) {
-      maskeddetids.push_back(tmpdetid);
+      maskeddetids.push_back(detids[i]);
     }
-    g_log.debug() << "[DB] Detector No. " << i << ":  ID = " << tmpdetid
+    g_log.debug() << "[DB] Detector No. " << i << ":  ID = " << detids[i]
                   << ", Masked = " << masked << ".\n";
   }
 
@@ -266,7 +264,7 @@ void ExtractMaskToTable::copyTableWorkspaceContent(
   vector<string> targetcolnames = targetWS->getColumnNames();
   if (sourcecolnames.size() != targetcolnames.size()) {
     stringstream errmsg;
-    errmsg << "Soruce table workspace " << sourceWS->name()
+    errmsg << "Soruce table workspace " << sourceWS->getName()
            << " has different number of columns (" << sourcecolnames.size()
            << ") than target table workspace's (" << targetcolnames.size()
            << ")";
diff --git a/Framework/Algorithms/src/ExtractSpectra.cpp b/Framework/Algorithms/src/ExtractSpectra.cpp
index c2871a39620fa2179458f8cc6313d17cd8aeabd7..bff8830bd560868d63d4548db0f865df761de895 100644
--- a/Framework/Algorithms/src/ExtractSpectra.cpp
+++ b/Framework/Algorithms/src/ExtractSpectra.cpp
@@ -1,11 +1,14 @@
 #include "MantidAlgorithms/ExtractSpectra.h"
 
+#include "MantidDataObjects/WorkspaceCreation.h"
 #include "MantidAPI/NumericAxis.h"
 #include "MantidAPI/TextAxis.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidKernel/ArrayProperty.h"
 #include "MantidKernel/BoundedValidator.h"
 #include "MantidKernel/VectorHelper.h"
+#include "MantidIndexing/Extract.h"
+#include "MantidIndexing/IndexInfo.h"
 
 #include <algorithm>
 
@@ -95,6 +98,9 @@ void ExtractSpectra::init() {
 void ExtractSpectra::exec() {
   // Get the input workspace
   m_inputWorkspace = getProperty("InputWorkspace");
+  m_histogram = m_inputWorkspace->isHistogramData();
+  // Check for common boundaries in input workspace
+  m_commonBoundaries = WorkspaceHelpers::commonBoundaries(*m_inputWorkspace);
 
   eventW = boost::dynamic_pointer_cast<EventWorkspace>(m_inputWorkspace);
   if (eventW != nullptr) {
@@ -108,10 +114,6 @@ void ExtractSpectra::exec() {
 
 /// Execute the algorithm in case of a histogrammed data.
 void ExtractSpectra::execHistogram() {
-  m_histogram = m_inputWorkspace->isHistogramData();
-  // Check for common boundaries in input workspace
-  m_commonBoundaries = WorkspaceHelpers::commonBoundaries(m_inputWorkspace);
-
   // Retrieve and validate the input properties
   this->checkProperties();
 
@@ -119,6 +121,8 @@ void ExtractSpectra::execHistogram() {
   MatrixWorkspace_sptr outputWorkspace = WorkspaceFactory::Instance().create(
       m_inputWorkspace, m_workspaceIndexList.size(), m_maxX - m_minX,
       m_maxX - m_minX - m_histogram);
+  outputWorkspace->setIndexInfo(
+      Indexing::extract(m_inputWorkspace->indexInfo(), m_workspaceIndexList));
 
   // If this is a Workspace2D, get the spectra axes for copying in the spectraNo
   // later
@@ -155,9 +159,9 @@ void ExtractSpectra::execHistogram() {
       if (hasDx) {
         auto &oldDx = m_inputWorkspace->dx(i);
         outputWorkspace->setSharedDx(
-            j,
-            make_cow<HistogramData::HistogramDx>(
-                oldDx.begin() + m_minX, oldDx.begin() + m_maxX - m_histogram));
+            j, make_cow<HistogramData::HistogramDx>(
+                   oldDx.begin() + m_minX,
+                   oldDx.begin() + (m_maxX - m_histogram)));
       }
     } else {
       // Safe to just copy whole vector 'cos can't be cropping in X if not
@@ -186,11 +190,8 @@ void ExtractSpectra::execHistogram() {
       } else if (outNumAxis) {
         outNumAxis->setValue(j, inAxis1->operator()(i));
       }
-      // spectra axis is handled by copyInfoFrom line
+      // spectra axis is implicit in workspace creation
     }
-    // Copy spectrum number & detectors
-    outputWorkspace->getSpectrum(j)
-        .copyInfoFrom(m_inputWorkspace->getSpectrum(i));
 
     if (!m_commonBoundaries)
       this->cropRagged(outputWorkspace, static_cast<int>(i), j);
@@ -241,7 +242,6 @@ void copyEventsHelper(const std::vector<T> &inputEvents,
  * input workspace
  */
 void ExtractSpectra::execEvent() {
-  m_histogram = m_inputWorkspace->isHistogramData();
   double minX_val = getProperty("XMin");
   double maxX_val = getProperty("XMax");
   if (isEmpty(minX_val))
@@ -249,27 +249,20 @@ void ExtractSpectra::execEvent() {
   if (isEmpty(maxX_val))
     maxX_val = eventW->getTofMax();
 
-  // Check for common boundaries in input workspace
-  m_commonBoundaries = WorkspaceHelpers::commonBoundaries(m_inputWorkspace);
-
   // Retrieve and validate the input properties
   this->checkProperties();
-  HistogramData::BinEdges XValues_new(0);
+  HistogramData::BinEdges XValues_new(2);
   if (m_commonBoundaries) {
     auto &oldX = m_inputWorkspace->x(m_workspaceIndexList.front());
     XValues_new =
         HistogramData::BinEdges(oldX.begin() + m_minX, oldX.begin() + m_maxX);
   }
-  size_t ntcnew = m_maxX - m_minX;
 
-  if (ntcnew < 2) {
+  if (m_maxX - m_minX < 2) {
     // create new output X axis
-    std::vector<double> rb_params;
-    rb_params.push_back(minX_val);
-    rb_params.push_back(maxX_val - minX_val);
-    rb_params.push_back(maxX_val);
-    ntcnew = VectorHelper::createAxisFromRebinParams(
-        rb_params, XValues_new.mutableRawData());
+    std::vector<double> rb_params{minX_val, maxX_val - minX_val, maxX_val};
+    static_cast<void>(VectorHelper::createAxisFromRebinParams(
+        rb_params, XValues_new.mutableRawData()));
   }
 
   // run inplace branch if appropriate
@@ -279,16 +272,12 @@ void ExtractSpectra::execEvent() {
     g_log.debug("Cropping EventWorkspace in-place.");
 
   // Create the output workspace
-  EventWorkspace_sptr outputWorkspace =
-      boost::dynamic_pointer_cast<EventWorkspace>(
-          API::WorkspaceFactory::Instance().create(
-              "EventWorkspace", m_workspaceIndexList.size(), ntcnew,
-              ntcnew - m_histogram));
   eventW->sortAll(TOF_SORT, nullptr);
+  auto outputWorkspace = create<EventWorkspace>(
+      *m_inputWorkspace,
+      Indexing::extract(m_inputWorkspace->indexInfo(), m_workspaceIndexList),
+      XValues_new);
   outputWorkspace->sortAll(TOF_SORT, nullptr);
-  // Copy required stuff from it
-  API::WorkspaceFactory::Instance().initializeFromParent(m_inputWorkspace,
-                                                         outputWorkspace, true);
 
   Progress prog(this, 0.0, 1.0, 2 * m_workspaceIndexList.size());
   eventW->sortAll(Mantid::DataObjects::TOF_SORT, &prog);
@@ -300,10 +289,6 @@ void ExtractSpectra::execEvent() {
     const EventList &el = eventW->getSpectrum(i);
     // The output event list
     EventList &outEL = outputWorkspace->getSpectrum(j);
-    //    // left side of the crop - will erase 0 -> endLeft
-    //    std::size_t endLeft;
-    //    // right side of the crop - will erase endRight->numEvents+1
-    //    std::size_t endRight;
 
     switch (el.getEventType()) {
     case TOF: {
@@ -331,9 +316,6 @@ void ExtractSpectra::execEvent() {
     }
     outEL.setSortOrder(el.getSortType());
 
-    // Copy spectrum number & detector IDs
-    outEL.copyInfoFrom(el);
-
     bool hasDx = eventW->hasDx(i);
 
     if (!m_commonBoundaries) {
@@ -342,12 +324,11 @@ void ExtractSpectra::execEvent() {
       outEL.setX(el.ptrX());
       outEL.setSharedDx(el.sharedDx());
     } else {
-      // Common bin boundaries get all set to the same value
-      outEL.setX(XValues_new.cowData());
+      // X is already set in workspace creation, just set Dx if necessary.
       if (hasDx) {
         auto &oldDx = m_inputWorkspace->dx(i);
-        outEL.setPointStandardDeviations(oldDx.begin() + m_minX,
-                                         oldDx.begin() + m_maxX - m_histogram);
+        outEL.setPointStandardDeviations(
+            oldDx.begin() + m_minX, oldDx.begin() + (m_maxX - m_histogram));
       }
     }
 
@@ -371,8 +352,7 @@ void ExtractSpectra::execEvent() {
   }
   PARALLEL_CHECK_INTERUPT_REGION
 
-  setProperty("OutputWorkspace",
-              boost::dynamic_pointer_cast<MatrixWorkspace>(outputWorkspace));
+  setProperty("OutputWorkspace", std::move(outputWorkspace));
 }
 
 /** Retrieves the optional input properties and checks that they have valid
diff --git a/Framework/Algorithms/src/FilterByLogValue.cpp b/Framework/Algorithms/src/FilterByLogValue.cpp
index 642a52a8d8400f3124d9b1658f238b6207d50df5..e1901303c6cb107487454d9166af5917a72aa752 100644
--- a/Framework/Algorithms/src/FilterByLogValue.cpp
+++ b/Framework/Algorithms/src/FilterByLogValue.cpp
@@ -1,6 +1,6 @@
 #include "MantidAlgorithms/FilterByLogValue.h"
+#include "MantidDataObjects/WorkspaceCreation.h"
 #include "MantidAPI/Run.h"
-#include "MantidAPI/WorkspaceFactory.h"
 #include "MantidKernel/BoundedValidator.h"
 #include "MantidKernel/ITimeSeriesProperty.h"
 #include "MantidKernel/ListValidator.h"
@@ -90,7 +90,7 @@ std::map<std::string, std::string> FilterByLogValue::validateInputs() {
   } catch (Exception::NotFoundError &) {
     errors["LogName"] = "The log '" + logname +
                         "' does not exist in the workspace '" +
-                        inputWS->name() + "'.";
+                        inputWS->getName() + "'.";
     return errors;
   }
 
@@ -206,14 +206,7 @@ void FilterByLogValue::exec() {
     this->setProperty("OutputWorkspace", inputWS);
   } else {
     // Make a brand new EventWorkspace for the output
-    // ------------------------------------------------------
-    outputWS = boost::dynamic_pointer_cast<EventWorkspace>(
-        API::WorkspaceFactory::Instance().create(
-            "EventWorkspace", inputWS->getNumberHistograms(), 2, 1));
-    // Copy geometry over.
-    API::WorkspaceFactory::Instance().initializeFromParent(inputWS, outputWS,
-                                                           false);
-    // But we don't copy the data.
+    outputWS = create<EventWorkspace>(*inputWS);
 
     // Loop over the histograms (detector spectra)
     PARALLEL_FOR_NO_WSP_CHECK()
diff --git a/Framework/Algorithms/src/FilterByTime.cpp b/Framework/Algorithms/src/FilterByTime.cpp
index 64038a4974feaec5ed26de8baa0d5e325d278c6b..dd08a9f46bd68884002419ff6e3d53e8ce330d44 100644
--- a/Framework/Algorithms/src/FilterByTime.cpp
+++ b/Framework/Algorithms/src/FilterByTime.cpp
@@ -1,7 +1,7 @@
 #include "MantidAlgorithms/FilterByTime.h"
 #include "MantidAPI/Run.h"
-#include "MantidAPI/WorkspaceFactory.h"
 #include "MantidDataObjects/EventWorkspace.h"
+#include "MantidDataObjects/WorkspaceCreation.h"
 #include "MantidKernel/BoundedValidator.h"
 #include "MantidKernel/DateAndTime.h"
 #include "MantidKernel/PhysicalConstants.h"
@@ -108,16 +108,7 @@ void FilterByTime::exec() {
     throw std::invalid_argument(
         "The stop time should be larger than the start time.");
 
-  // Make a brand new EventWorkspace
-  EventWorkspace_sptr outputWS = boost::dynamic_pointer_cast<EventWorkspace>(
-      API::WorkspaceFactory::Instance().create(
-          "EventWorkspace", inputWS->getNumberHistograms(), 2, 1));
-  // Copy geometry over.
-  API::WorkspaceFactory::Instance().initializeFromParent(inputWS, outputWS,
-                                                         false);
-  // But we don't copy the data.
-
-  setProperty("OutputWorkspace", outputWS);
+  auto outputWS = DataObjects::create<EventWorkspace>(*inputWS);
 
   size_t numberOfSpectra = inputWS->getNumberHistograms();
 
@@ -144,6 +135,7 @@ void FilterByTime::exec() {
 
   // Now filter out the run, using the DateAndTime type.
   outputWS->mutableRun().filterByTime(start, stop);
+  setProperty("OutputWorkspace", std::move(outputWS));
 }
 
 } // namespace Algorithms
diff --git a/Framework/Algorithms/src/FilterEvents.cpp b/Framework/Algorithms/src/FilterEvents.cpp
index e2302877fbb1cf2083e34e10c87fec8f1331f35b..5607b3e7eded4095d2d1858852aad7ca0f588a17 100644
--- a/Framework/Algorithms/src/FilterEvents.cpp
+++ b/Framework/Algorithms/src/FilterEvents.cpp
@@ -1,4 +1,5 @@
 #include "MantidAlgorithms/FilterEvents.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/FileProperty.h"
 #include "MantidAPI/TableRow.h"
 #include "MantidAPI/SpectrumInfo.h"
@@ -10,6 +11,7 @@
 #include "MantidAlgorithms/TimeAtSampleStrategyIndirect.h"
 #include "MantidDataObjects/SplittersWorkspace.h"
 #include "MantidDataObjects/TableWorkspace.h"
+#include "MantidDataObjects/WorkspaceCreation.h"
 #include "MantidKernel/ArrayProperty.h"
 #include "MantidKernel/BoundedValidator.h"
 #include "MantidKernel/ListValidator.h"
@@ -205,7 +207,7 @@ void FilterEvents::exec() {
   std::vector<std::string> outputwsnames;
   std::map<int, DataObjects::EventWorkspace_sptr>::iterator miter;
   for (miter = m_outputWS.begin(); miter != m_outputWS.end(); ++miter) {
-    outputwsnames.push_back(miter->second->name());
+    outputwsnames.push_back(miter->second->getName());
   }
   setProperty("OutputWorkspaceNames", outputwsnames);
 
@@ -304,7 +306,7 @@ void FilterEvents::processAlgorithmProperties() {
   if (m_isSplittersRelativeTime) {
     // Using relative time
     std::string start_time_str = getProperty("FilterStartTime");
-    if (start_time_str.size() > 0) {
+    if (!start_time_str.empty()) {
       // User specifies the filter starting time
       Kernel::DateAndTime temp_shift_time(start_time_str);
       m_filterStartTime = temp_shift_time;
@@ -500,15 +502,8 @@ void FilterEvents::createOutputWorkspaces() {
         add2output = false;
     }
 
-    // Generate one of the output workspaces & Copy geometry over. But we
-    // don't
-    // copy the data.
-    DataObjects::EventWorkspace_sptr optws =
-        boost::dynamic_pointer_cast<DataObjects::EventWorkspace>(
-            API::WorkspaceFactory::Instance().create(
-                "EventWorkspace", m_eventWS->getNumberHistograms(), 2, 1));
-    API::WorkspaceFactory::Instance().initializeFromParent(m_eventWS, optws,
-                                                           false);
+    boost::shared_ptr<EventWorkspace> optws =
+        create<DataObjects::EventWorkspace>(*m_eventWS);
     m_outputWS.emplace(wsgroup, optws);
 
     // Add information, including title and comment, to output workspace
@@ -711,13 +706,13 @@ void FilterEvents::setupCustomizedTOFCorrection() {
   if (toffactormap.size() > numhist) {
     g_log.warning() << "Input correction table workspace has more detectors ("
                     << toffactormap.size() << ") than input workspace "
-                    << m_eventWS->name() << "'s spectra number (" << numhist
+                    << m_eventWS->getName() << "'s spectra number (" << numhist
                     << ".\n";
   } else if (toffactormap.size() < numhist) {
     stringstream errss;
     errss << "Input correction table workspace has more detectors ("
           << toffactormap.size() << ") than input workspace "
-          << m_eventWS->name() << "'s spectra number (" << numhist << ".\n";
+          << m_eventWS->getName() << "'s spectra number (" << numhist << ".\n";
     throw runtime_error(errss.str());
   }
 
@@ -756,7 +751,7 @@ void FilterEvents::setupCustomizedTOFCorrection() {
         stringstream errss;
         errss << "Detector "
               << "w/ ID << " << detid << " of spectrum " << i
-              << " in Eventworkspace " << m_eventWS->name()
+              << " in Eventworkspace " << m_eventWS->getName()
               << " cannot be found in input TOF calibration workspace. ";
         throw runtime_error(errss.str());
       }
@@ -864,12 +859,12 @@ void FilterEvents::filterEventsBySplitters(double progressamount) {
     Kernel::TimeSplitterType splitters = generateSplitters(wsindex);
 
     g_log.debug() << "[FilterEvents D1215]: Output workspace Index " << wsindex
-                  << ": Name = " << opws->name()
+                  << ": Name = " << opws->getName()
                   << "; Number of splitters = " << splitters.size() << ".\n";
 
     // Skip output workspace has ZERO splitters
     if (splitters.empty()) {
-      g_log.warning() << "[FilterEvents] Workspace " << opws->name()
+      g_log.warning() << "[FilterEvents] Workspace " << opws->getName()
                       << " Indexed @ " << wsindex
                       << " won't have logs splitted due to zero splitter size. "
                       << ".\n";
@@ -987,7 +982,7 @@ void FilterEvents::splitLog(EventWorkspace_sptr eventws, std::string logname,
     throw std::runtime_error(errmsg.str());
   } else {
     for (const auto &split : splitters) {
-      g_log.debug() << "Workspace " << eventws->name() << ": "
+      g_log.debug() << "Workspace " << eventws->getName() << ": "
                     << "log name = " << logname
                     << ", duration = " << split.duration() << " from "
                     << split.start() << " to " << split.stop() << ".\n";
diff --git a/Framework/Algorithms/src/FindCenterOfMassPosition2.cpp b/Framework/Algorithms/src/FindCenterOfMassPosition2.cpp
index ad9325e5c775fb0dbe07cb46ccab262ddf2067b1..f39461ee37c9b0401d9e968087698abb011f73b7 100644
--- a/Framework/Algorithms/src/FindCenterOfMassPosition2.cpp
+++ b/Framework/Algorithms/src/FindCenterOfMassPosition2.cpp
@@ -106,7 +106,7 @@ void FindCenterOfMassPosition2::exec() {
     algo->execute();
 
     inputWS = algo->getProperty("OutputWorkspace");
-    WorkspaceFactory::Instance().initializeFromParent(inputWSWvl, inputWS,
+    WorkspaceFactory::Instance().initializeFromParent(*inputWSWvl, *inputWS,
                                                       false);
   } else {
     // Sum up all the wavelength bins
diff --git a/Framework/Algorithms/src/FindDeadDetectors.cpp b/Framework/Algorithms/src/FindDeadDetectors.cpp
index abf24380c1df8694c8ac618acabbc95d1697f85c..32a2d88eb5a214e8fa6068999ab4e4a5869992b6 100644
--- a/Framework/Algorithms/src/FindDeadDetectors.cpp
+++ b/Framework/Algorithms/src/FindDeadDetectors.cpp
@@ -3,6 +3,7 @@
 //----------------------------------------------------------------------
 #include "MantidAlgorithms/FindDeadDetectors.h"
 #include "MantidAPI/MatrixWorkspace.h"
+#include "MantidIndexing/IndexInfo.h"
 #include "MantidKernel/BoundedValidator.h"
 
 #include <fstream>
@@ -89,20 +90,20 @@ void FindDeadDetectors::exec() {
   int64_t iprogress_step = numSpec / 100;
   if (iprogress_step == 0)
     iprogress_step = 1;
+  const auto &indexInfo = integratedWorkspace->indexInfo();
   for (int64_t i = 0; i < int64_t(numSpec); ++i) {
     // Spectrum in the integratedWorkspace
-    auto &spec = integratedWorkspace->getSpectrum(i);
-    double &y = spec.mutableY()[0];
+    double &y = integratedWorkspace->mutableY(i)[0];
     if (y > deadThreshold) {
       y = liveValue;
     } else {
       ++countSpec;
       y = deadValue;
-      const specnum_t specNo = spec.getSpectrumNo();
+      const specnum_t specNo = indexInfo.spectrumNumber(i);
       // Write the spectrum number to file
       file << i << " " << specNo;
       // Get the list of detectors for this spectrum and iterate over
-      const auto &dets = spec.getDetectorIDs();
+      const auto &dets = indexInfo.detectorIDs(i);
       for (const auto &det : dets) {
         // Write the detector ID to file, log & the FoundDead output property
         file << " " << det;
diff --git a/Framework/Algorithms/src/FindPeakBackground.cpp b/Framework/Algorithms/src/FindPeakBackground.cpp
index baa9eae793baf5370c59f41431744880678de6f9..14dd2427f6a7afd067867021c84bc0bf9546f902 100644
--- a/Framework/Algorithms/src/FindPeakBackground.cpp
+++ b/Framework/Algorithms/src/FindPeakBackground.cpp
@@ -85,7 +85,7 @@ void FindPeakBackground::exec() {
   } else if (inpwsindex < 0 ||
              inpwsindex >= static_cast<int>(inpWS->getNumberHistograms())) {
     stringstream errss;
-    errss << "Input workspace " << inpWS->name() << " has "
+    errss << "Input workspace " << inpWS->getName() << " has "
           << inpWS->getNumberHistograms() << " spectra.  Input workspace index "
           << inpwsindex << " is out of boundary. ";
     throw runtime_error(errss.str());
diff --git a/Framework/Algorithms/src/FindPeaks.cpp b/Framework/Algorithms/src/FindPeaks.cpp
index e2e5d619df2a6118204f62bf8233b1e3fd92c932..1970805ca417c667bb99ec394bc53aafd6cc723d 100644
--- a/Framework/Algorithms/src/FindPeaks.cpp
+++ b/Framework/Algorithms/src/FindPeaks.cpp
@@ -983,7 +983,7 @@ void FindPeaks::fitSinglePeak(const API::MatrixWorkspace_sptr &input,
   std::string errmsg = estimatePeakParameters(
       vecX, vecY, i_min, i_max, vecbkgdparvalue, i_obscentre, est_height,
       est_fwhm, est_leftfwhm, est_rightfwhm);
-  if (errmsg.size() > 0) {
+  if (!errmsg.empty()) {
     // Unable to estimate peak
     i_obscentre = i_centre;
     est_fwhm = 1.;
diff --git a/Framework/Algorithms/src/FitPeak.cpp b/Framework/Algorithms/src/FitPeak.cpp
index f28a19783e16ea36e092fd53c7e50532bfc72472..cf3e596986d436d0cfe29dc55189f75c9a4d7ab6 100644
--- a/Framework/Algorithms/src/FitPeak.cpp
+++ b/Framework/Algorithms/src/FitPeak.cpp
@@ -264,7 +264,7 @@ bool FitOneSinglePeak::hasSetupToFitPeak(std::string &errmsg) {
   if (!m_dataWS)
     errmsg += "Data workspace ";
 
-  if (errmsg.size() > 0) {
+  if (!errmsg.empty()) {
     errmsg = "These parameters have not been set for fitting peak: " + errmsg;
     return false;
   }
@@ -835,7 +835,7 @@ double FitOneSinglePeak::fitCompositeFunction(
   // Check fit result
   goodness = checkFittedPeak(peakfunc, goodness, errorreason);
 
-  if (errorreason.size() > 0)
+  if (!errorreason.empty())
     m_sstream << "Error reason of fit peak+background composite: "
               << errorreason << "\n";
 
diff --git a/Framework/Algorithms/src/FlatPlateAbsorption.cpp b/Framework/Algorithms/src/FlatPlateAbsorption.cpp
index d3e84128f3ff86da4460d1ccab6044f1edb41d3e..65edf29229e768263534cdd451517944a8e0e474 100644
--- a/Framework/Algorithms/src/FlatPlateAbsorption.cpp
+++ b/Framework/Algorithms/src/FlatPlateAbsorption.cpp
@@ -1,9 +1,8 @@
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidAlgorithms/FlatPlateAbsorption.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidGeometry/Instrument.h"
+#include "MantidGeometry/Objects/Object.h"
+#include "MantidGeometry/Objects/Track.h"
 #include "MantidKernel/BoundedValidator.h"
 
 namespace Mantid {
diff --git a/Framework/Algorithms/src/GeneralisedSecondDifference.cpp b/Framework/Algorithms/src/GeneralisedSecondDifference.cpp
index e926d70e1d5b3289b2f7d2bc8ca24b6e2fe9d762..0162f0b9439159fb15f591a07352fd890ffe0ec1 100644
--- a/Framework/Algorithms/src/GeneralisedSecondDifference.cpp
+++ b/Framework/Algorithms/src/GeneralisedSecondDifference.cpp
@@ -1,12 +1,11 @@
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidAlgorithms/GeneralisedSecondDifference.h"
 
-#include "MantidAPI/MatrixWorkspace.h"
-#include "MantidAPI/WorkspaceFactory.h"
+#include "MantidDataObjects/WorkspaceCreation.h"
+#include "MantidAPI/HistoWorkspace.h"
 #include "MantidKernel/BoundedValidator.h"
 #include "MantidKernel/VectorHelper.h"
+#include "MantidIndexing/Extract.h"
+#include "MantidIndexing/IndexInfo.h"
 
 #include <numeric>
 #include <sstream>
@@ -83,14 +82,14 @@ void GeneralisedSecondDifference::exec() {
   // Calculate the Cij and Cij^2 coefficients
   computePrefactors();
 
-  const int n_specs = spec_max - spec_min + 1;
   const int n_points = static_cast<int>(inputWS->y(0).size()) - 2 * n_av;
   if (n_points < 1) {
     throw std::invalid_argument("Invalid (M,Z) values");
   }
   // Create OuputWorkspace
-  MatrixWorkspace_sptr out = WorkspaceFactory::Instance().create(
-      inputWS, n_specs, n_points + 1, n_points);
+  auto out = DataObjects::create<HistoWorkspace>(
+      *inputWS, Indexing::extract(inputWS->indexInfo(), spec_min, spec_max),
+      HistogramData::BinEdges(n_points + 1));
 
   const int nsteps = 2 * n_av + 1;
 
@@ -98,9 +97,6 @@ void GeneralisedSecondDifference::exec() {
       boost::make_shared<API::Progress>(this, 0.0, 1.0, (spec_max - spec_min));
   for (int i = spec_min; i <= spec_max; i++) {
     int out_index = i - spec_min;
-    out->getSpectrum(out_index)
-        .setSpectrumNo(inputWS->getSpectrum(i).getSpectrumNo());
-
     const auto &refX = inputWS->x(i);
     const auto &refY = inputWS->y(i);
     const auto &refE = inputWS->e(i);
@@ -124,7 +120,7 @@ void GeneralisedSecondDifference::exec() {
     }
     progress->report();
   }
-  setProperty("OutputWorkspace", out);
+  setProperty("OutputWorkspace", std::move(out));
 }
 /** Compute the Cij
  *
diff --git a/Framework/Algorithms/src/GenerateEventsFilter.cpp b/Framework/Algorithms/src/GenerateEventsFilter.cpp
index fa2ec6a0e2cf0c4df440ec7aebff5e3bc67a3902..34eb203fba83d0de4d893b626884d338575f304b 100644
--- a/Framework/Algorithms/src/GenerateEventsFilter.cpp
+++ b/Framework/Algorithms/src/GenerateEventsFilter.cpp
@@ -216,7 +216,7 @@ void GenerateEventsFilter::processInOutWorkspaces() {
 
   // Output splitter information workspace
   std::string title = getProperty("TitleOfSplitters");
-  if (title.size() == 0) {
+  if (title.empty()) {
     // Using default
     title = "Splitters";
   }
@@ -263,8 +263,8 @@ void GenerateEventsFilter::processInputTime() {
   std::string s_inptf = this->getProperty("StopTime");
 
   // Default
-  bool defaultstart = (s_inpt0.size() == 0);
-  bool defaultstop = (s_inptf.size() == 0);
+  bool defaultstart = s_inpt0.empty();
+  bool defaultstop = s_inptf.empty();
 
   // Determine format
   bool instringformat = true;
@@ -1674,7 +1674,7 @@ void GenerateEventsFilter::addNewTimeFilterSplitter(
   }
 
   // Information
-  if (info.size() > 0) {
+  if (!info.empty()) {
     API::TableRow row = m_filterInfoWS->appendRow();
     row << wsindex << info;
   }
diff --git a/Framework/Algorithms/src/GenerateIPythonNotebook.cpp b/Framework/Algorithms/src/GenerateIPythonNotebook.cpp
index ee5f18dc756624435606a9e84798cb5fbe815190..529b33549073a74d25262e8d5c7f7ee6288da4d6 100644
--- a/Framework/Algorithms/src/GenerateIPythonNotebook.cpp
+++ b/Framework/Algorithms/src/GenerateIPythonNotebook.cpp
@@ -5,6 +5,7 @@
 #include "MantidAPI/AlgorithmManager.h"
 #include "MantidAPI/AlgorithmHistory.h"
 #include "MantidAPI/NotebookBuilder.h"
+#include "MantidAPI/Workspace.h"
 
 #include <fstream>
 
@@ -21,9 +22,6 @@ namespace Algorithms {
 // Register the algorithm into the AlgorithmFactory
 DECLARE_ALGORITHM(GenerateIPythonNotebook)
 
-//----------------------------------------------------------------------------------------------
-
-//----------------------------------------------------------------------------------------------
 /** Initialize the algorithm's properties.
 */
 void GenerateIPythonNotebook::init() {
@@ -61,7 +59,6 @@ void GenerateIPythonNotebook::init() {
       "When to specify which algorithm version was used by Mantid.");
 }
 
-//----------------------------------------------------------------------------------------------
 /** Execute the algorithm.
 */
 void GenerateIPythonNotebook::exec() {
diff --git a/Framework/Algorithms/src/GeneratePeaks.cpp b/Framework/Algorithms/src/GeneratePeaks.cpp
index 7219781816ae7e087433a1a6036a311f16bd2352..b132b81487dd8f8c2a86a5193eff8bb832ad3935 100644
--- a/Framework/Algorithms/src/GeneratePeaks.cpp
+++ b/Framework/Algorithms/src/GeneratePeaks.cpp
@@ -1,7 +1,3 @@
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
-
 #include "MantidAlgorithms/GeneratePeaks.h"
 #include "MantidAPI/WorkspaceProperty.h"
 #include "MantidAPI/WorkspaceFactory.h"
@@ -14,6 +10,8 @@
 #include "MantidKernel/ArrayProperty.h"
 #include "MantidKernel/RebinParamsValidator.h"
 #include "MantidAPI/SpectraAxis.h"
+#include "MantidDataObjects/WorkspaceCreation.h"
+#include "MantidIndexing/IndexInfo.h"
 
 #include <boost/algorithm/string/split.hpp>
 #include <boost/algorithm/string/classification.hpp>
@@ -168,7 +166,7 @@ void GeneratePeaks::processAlgProperties(std::string &peakfunctype,
                                          std::string &bkgdfunctype) {
   // Function parameters
   std::string paramwsname = getPropertyValue("PeakParametersWorkspace");
-  if (paramwsname.size() > 0) {
+  if (!paramwsname.empty()) {
     // Using parameter table workspace has a higher priority
     m_useFuncParamWS = true;
     m_funcParamWS = getProperty("PeakParametersWorkspace");
@@ -761,31 +759,20 @@ GeneratePeaks::createDataWorkspace(std::vector<double> binparameters) {
     else
       xvalue += fabs(dx) * xvalue;
   }
-  size_t numxvalue = xarray.size();
-
-  BinEdges xArrayEdges(xarray);
 
-  // Create new workspace
-  MatrixWorkspace_sptr ws = API::WorkspaceFactory::Instance().create(
-      "Workspace2D", m_spectraSet.size(), numxvalue, numxvalue - 1);
-  for (size_t ip = 0; ip < m_spectraSet.size(); ip++) {
-    ws->setBinEdges(ip, xArrayEdges);
-  }
-  // Set spectrum numbers
-  std::map<specnum_t, specnum_t>::iterator spiter;
-  for (spiter = m_SpectrumMap.begin(); spiter != m_SpectrumMap.end();
-       ++spiter) {
-    specnum_t specid = spiter->first;
-    specnum_t wsindex = spiter->second;
-    g_log.debug() << "Build WorkspaceIndex-Spectrum  " << wsindex << " , "
-                  << specid << "\n";
-    ws->getSpectrum(wsindex).setSpectrumNo(specid);
+  std::vector<specnum_t> specNums;
+  for (const auto &item : m_SpectrumMap) {
+    specnum_t specid = item.first;
+    g_log.debug() << "Build WorkspaceIndex-Spectrum  " << specNums.size()
+                  << " , " << specid << "\n";
+    specNums.push_back(specid);
   }
 
-  return ws;
+  Indexing::IndexInfo indices(specNums.size());
+  indices.setSpectrumNumbers(std::move(specNums));
+  return create<Workspace2D>(indices, BinEdges(std::move(xarray)));
 }
 
-//----------------------------------------------------------------------------------------------
 /** Add function's parameter names after peak function name
   */
 std::vector<std::string>
diff --git a/Framework/Algorithms/src/GeneratePythonScript.cpp b/Framework/Algorithms/src/GeneratePythonScript.cpp
index a5624685f535d8c70740aa329e4ffa3d0497279e..5ee5894becf7f62babb485492b17bdbe834ab4b9 100644
--- a/Framework/Algorithms/src/GeneratePythonScript.cpp
+++ b/Framework/Algorithms/src/GeneratePythonScript.cpp
@@ -5,6 +5,7 @@
 #include "MantidAPI/AlgorithmManager.h"
 #include "MantidAPI/AlgorithmHistory.h"
 #include "MantidAPI/ScriptBuilder.h"
+#include "MantidAPI/Workspace.h"
 
 #include <fstream>
 
@@ -21,9 +22,6 @@ namespace Algorithms {
 // Register the algorithm into the AlgorithmFactory
 DECLARE_ALGORITHM(GeneratePythonScript)
 
-//----------------------------------------------------------------------------------------------
-
-//----------------------------------------------------------------------------------------------
 /** Initialize the algorithm's properties.
 */
 void GeneratePythonScript::init() {
@@ -60,7 +58,6 @@ void GeneratePythonScript::init() {
       "When to specify which algorithm version was used by Mantid.");
 }
 
-//----------------------------------------------------------------------------------------------
 /** Execute the algorithm.
 */
 void GeneratePythonScript::exec() {
diff --git a/Framework/Algorithms/src/GetAllEi.cpp b/Framework/Algorithms/src/GetAllEi.cpp
index d62149454ed65ad6603493424a2b6d1106bd28a8..ce1be24a33b0e93bf90759afeee000adac26da80 100644
--- a/Framework/Algorithms/src/GetAllEi.cpp
+++ b/Framework/Algorithms/src/GetAllEi.cpp
@@ -1,8 +1,11 @@
 #include "MantidAlgorithms/GetAllEi.h"
 #include "MantidAPI/Axis.h"
+#include "MantidAPI/HistoWorkspace.h"
 #include "MantidAPI/Run.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidDataObjects/TableWorkspace.h"
+#include "MantidDataObjects/WorkspaceCreation.h"
 #include "MantidGeometry/IComponent.h"
 #include "MantidGeometry/Instrument.h"
 #include "MantidKernel/BoundedValidator.h"
@@ -11,6 +14,8 @@
 #include "MantidKernel/UnitFactory.h"
 #include "MantidKernel/Unit.h"
 #include "MantidKernel/VectorHelper.h"
+#include "MantidIndexing/Extract.h"
+#include "MantidIndexing/IndexInfo.h"
 
 #include <boost/format.hpp>
 #include <boost/algorithm/string.hpp>
@@ -222,8 +227,8 @@ void GetAllEi::exec() {
   auto monitorWS = buildWorkspaceToFit(inputWS, det1WSIndex);
 
   // recalculate delay time from chopper position to monitor position
-  auto detector1 = inputWS->getDetector(det1WSIndex);
-  double mon1Distance = detector1->getDistance(*moderator);
+  const auto &detector1 = inputWS->spectrumInfo().detector(det1WSIndex);
+  double mon1Distance = detector1.getDistance(*moderator);
   double TOF0 = mon1Distance / velocity;
 
   //--->> below is reserved until full chopper's implementation is available;
@@ -881,24 +886,13 @@ GetAllEi::buildWorkspaceToFit(const API::MatrixWorkspace_sptr &inputWS,
   wsIndex0 = inputWS->getIndexFromSpectrumNumber(specNum1);
   specnum_t specNum2 = getProperty("Monitor2SpecID");
   size_t wsIndex1 = inputWS->getIndexFromSpectrumNumber(specNum2);
-  auto &pSpectr1 = inputWS->getSpectrum(wsIndex0);
-  auto &pSpectr2 = inputWS->getSpectrum(wsIndex1);
+
   // assuming equally binned ws.
-  // auto bins       = inputWS->dataX(wsIndex0);
-  auto bins = pSpectr1.ptrX();
-  size_t XLength = bins->size();
-  size_t YLength = inputWS->y(wsIndex0).size();
-  auto working_ws =
-      API::WorkspaceFactory::Instance().create(inputWS, 2, XLength, YLength);
-  // copy data --> very bad as implicitly assigns pointer
-  // to bins array and bins array have to exist out of this routine
-  // scope.
-  // This does not matter in this case as below we convert units
-  // which should decouple cow_pointer but very scary operation in
-  // general.
-
-  working_ws->setSharedX(0, bins);
-  working_ws->setSharedX(1, bins);
+  boost::shared_ptr<API::HistoWorkspace> working_ws =
+      DataObjects::create<API::HistoWorkspace>(
+          *inputWS, Indexing::extract(inputWS->indexInfo(),
+                                      std::vector<size_t>{wsIndex0, wsIndex1}),
+          inputWS->histogram(wsIndex0));
 
   // signal 1
   working_ws->setSharedY(0, inputWS->sharedY(wsIndex0));
@@ -909,17 +903,6 @@ GetAllEi::buildWorkspaceToFit(const API::MatrixWorkspace_sptr &inputWS,
   // error 2
   working_ws->setSharedE(1, inputWS->sharedE(wsIndex1));
 
-  // copy detector mapping
-  auto &spectrum1 = working_ws->getSpectrum(0);
-  spectrum1.setSpectrumNo(specNum1);
-  spectrum1.clearDetectorIDs();
-  spectrum1.addDetectorIDs(pSpectr1.getDetectorIDs());
-
-  auto &spectrum2 = working_ws->getSpectrum(1);
-  spectrum2.setSpectrumNo(specNum2);
-  spectrum2.clearDetectorIDs();
-  spectrum2.addDetectorIDs(pSpectr2.getDetectorIDs());
-
   if (inputWS->getAxis(0)->unit()->caption() != "Energy") {
     API::IAlgorithm_sptr conv = createChildAlgorithm("ConvertUnits");
     conv->initialize();
diff --git a/Framework/Algorithms/src/GetDetOffsetsMultiPeaks.cpp b/Framework/Algorithms/src/GetDetOffsetsMultiPeaks.cpp
index 9f4f0beb3356eaf24905c8d998f1e7bad3a5e277..d3e8835e03d7e4493079cfd027e8fc75d47bd2bb 100644
--- a/Framework/Algorithms/src/GetDetOffsetsMultiPeaks.cpp
+++ b/Framework/Algorithms/src/GetDetOffsetsMultiPeaks.cpp
@@ -7,6 +7,7 @@
 #include "MantidAPI/IPeakFunction.h"
 #include "MantidAPI/IBackgroundFunction.h"
 #include "MantidAPI/TableRow.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidAPI/WorkspaceUnitValidator.h"
 #include "MantidDataObjects/EventWorkspace.h"
@@ -303,7 +304,7 @@ void GetDetOffsetsMultiPeaks::processProperties() {
   // Fit windows
   std::string fitwinwsname = getPropertyValue("FitwindowTableWorkspace");
   g_log.notice() << "FitWindowTableWorkspace name: " << fitwinwsname << "\n";
-  if (fitwinwsname.size() > 0) {
+  if (!fitwinwsname.empty()) {
     // Use fit window workspace for each spectrum
     TableWorkspace_sptr fitwintablews = getProperty("FitwindowTableWorkspace");
     importFitWindowTableWorkspace(fitwintablews);
@@ -360,7 +361,7 @@ void GetDetOffsetsMultiPeaks::processProperties() {
 
   // Input resolution
   std::string reswsname = getPropertyValue("InputResolutionWorkspace");
-  if (reswsname.size() == 0)
+  if (reswsname.empty())
     m_hasInputResolution = false;
   else {
     m_inputResolutionWS = getProperty("InputResolutionWorkspace");
@@ -475,6 +476,7 @@ void GetDetOffsetsMultiPeaks::calculateDetectorsOffsets() {
   // Fit all the spectra with a gaussian
   Progress prog(this, 0, 1.0, nspec);
 
+  auto &spectrumInfo = m_maskWS->mutableSpectrumInfo();
   // cppcheck-suppress syntaxError
     PRAGMA_OMP(parallel for schedule(dynamic, 1) )
     for (int wi = 0; wi < nspec; ++wi) {
@@ -509,7 +511,8 @@ void GetDetOffsetsMultiPeaks::calculateDetectorsOffsets() {
           const size_t workspaceIndex = mapEntry->second;
           if (offsetresult.mask > 0.9) {
             // Being masked
-            m_maskWS->maskWorkspaceIndex(workspaceIndex);
+            m_maskWS->getSpectrum(workspaceIndex).clearData();
+            spectrumInfo.setMasked(workspaceIndex, true);
             m_maskWS->mutableY(workspaceIndex)[0] = offsetresult.mask;
           } else {
             // Using the detector
diff --git a/Framework/Algorithms/src/GetDetectorOffsets.cpp b/Framework/Algorithms/src/GetDetectorOffsets.cpp
index 5ce99a549b31ded3c5c9594601522212aa645330..e7cdc66de35303c94659427317c17ef8f6693543 100644
--- a/Framework/Algorithms/src/GetDetectorOffsets.cpp
+++ b/Framework/Algorithms/src/GetDetectorOffsets.cpp
@@ -3,6 +3,7 @@
 #include "MantidAPI/FileProperty.h"
 #include "MantidAPI/FunctionFactory.h"
 #include "MantidAPI/IPeakFunction.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidAPI/WorkspaceUnitValidator.h"
 #include "MantidDataObjects/MaskWorkspace.h"
 #include "MantidDataObjects/OffsetsWorkspace.h"
@@ -108,6 +109,7 @@ void GetDetectorOffsets::exec() {
 
   // Fit all the spectra with a gaussian
   Progress prog(this, 0, 1.0, nspec);
+  auto &spectrumInfo = maskWS->mutableSpectrumInfo();
   PARALLEL_FOR_IF(Kernel::threadSafe(*inputW))
   for (int wi = 0; wi < nspec; ++wi) {
     PARALLEL_START_INTERUPT_REGION
@@ -134,7 +136,8 @@ void GetDetectorOffsets::exec() {
         const size_t workspaceIndex = mapEntry->second;
         if (mask == 1.) {
           // Being masked
-          maskWS->maskWorkspaceIndex(workspaceIndex);
+          maskWS->getSpectrum(workspaceIndex).clearData();
+          spectrumInfo.setMasked(workspaceIndex, true);
           maskWS->mutableY(workspaceIndex)[0] = mask;
         } else {
           // Using the detector
diff --git a/Framework/Algorithms/src/GetEi2.cpp b/Framework/Algorithms/src/GetEi2.cpp
index e6d6c8fcb86a102df2c67b940bc0624e41498e23..0bf390f399dbfb56759c833997ee8d0b9b1be5ca 100644
--- a/Framework/Algorithms/src/GetEi2.cpp
+++ b/Framework/Algorithms/src/GetEi2.cpp
@@ -1,10 +1,11 @@
 #include "MantidAlgorithms/GetEi2.h"
 
-#include "MantidAPI/IEventWorkspace.h"
 #include "MantidAPI/HistogramValidator.h"
+#include "MantidAPI/IEventWorkspace.h"
 #include "MantidAPI/InstrumentValidator.h"
 #include "MantidAPI/Run.h"
 #include "MantidAPI/WorkspaceUnitValidator.h"
+#include "MantidGeometry/IDetector_fwd.h"
 #include "MantidGeometry/Instrument.h"
 #include "MantidGeometry/Instrument/DetectorGroup.h"
 #include "MantidGeometry/muParser_Silent.h"
@@ -13,9 +14,9 @@
 #include "MantidKernel/PhysicalConstants.h"
 #include "MantidKernel/VectorHelper.h"
 
+#include <algorithm>
 #include <boost/lexical_cast.hpp>
 #include <cmath>
-#include <algorithm>
 #include <sstream>
 
 using namespace Mantid::Kernel;
@@ -216,9 +217,10 @@ double GetEi2::calculateEi(const double initial_guess) {
   // Calculate actual peak postion for each monitor peak
   double peak_times[2] = {0.0, 0.0};
   double det_distances[2] = {0.0, 0.0};
+  auto &spectrumInfo = m_input_ws->spectrumInfo();
   for (unsigned int i = 0; i < 2; ++i) {
     size_t ws_index = mon_indices[i];
-    det_distances[i] = getDistanceFromSource(ws_index);
+    det_distances[i] = getDistanceFromSource(ws_index, spectrumInfo);
     const double peak_guess =
         det_distances[i] * std::sqrt(m_t_to_mev / initial_guess);
     const double t_min = (1.0 - m_tof_window) * peak_guess;
@@ -276,31 +278,33 @@ double GetEi2::calculateEi(const double initial_guess) {
   }
 }
 
-/** Gets the distance between the source and detectors whose workspace index is
+/**
+ * Gets the distance between the source and detectors whose workspace index is
  * passed
  *  @param ws_index :: The workspace index of the detector
+ *  @param spectrumInfo :: A spectrum info object for the input workspace
  *  @return The distance between the source and the given detector(or
  * DetectorGroup)
  *  @throw runtime_error if there is a problem
  */
-double GetEi2::getDistanceFromSource(size_t ws_index) const {
+double GetEi2::getDistanceFromSource(size_t ws_index,
+                                     const SpectrumInfo &spectrumInfo) const {
   g_log.debug() << "Computing distance between spectrum at index '" << ws_index
                 << "' and the source\n";
 
+  const auto &detector = spectrumInfo.detector(ws_index);
   const IComponent_const_sptr source = m_input_ws->getInstrument()->getSource();
-  // Retrieve a pointer detector
-  IDetector_const_sptr det = m_input_ws->getDetector(ws_index);
-  if (!det) {
+  if (!spectrumInfo.hasDetectors(ws_index)) {
     std::ostringstream msg;
     msg << "A detector for monitor at workspace index " << ws_index
         << " cannot be found. ";
     throw std::runtime_error(msg.str());
   }
   if (g_log.is(Logger::Priority::PRIO_DEBUG)) {
-    g_log.debug() << "Detector position = " << det->getPos()
+    g_log.debug() << "Detector position = " << spectrumInfo.position(ws_index)
                   << ", Source position = " << source->getPos() << "\n";
   }
-  const double dist = det->getDistance(*source);
+  const double dist = detector.getDistance(*source);
   g_log.debug() << "Distance = " << dist << " metres\n";
   return dist;
 }
@@ -646,6 +650,7 @@ API::MatrixWorkspace_sptr GetEi2::rebin(API::MatrixWorkspace_sptr monitor_ws,
   std::ostringstream binParams;
   binParams << first << "," << width << "," << end;
   childAlg->setPropertyValue("Params", binParams.str());
+  childAlg->setProperty("IgnoreBinErrors", true);
   childAlg->executeAsChildAlg();
   return childAlg->getProperty("OutputWorkspace");
 }
diff --git a/Framework/Algorithms/src/GetEiMonDet2.cpp b/Framework/Algorithms/src/GetEiMonDet2.cpp
index b047270bc69d9ee46b93ab5682a46ceb47ef8f04..2039e3ac57322a627238aeec2eea85bbd2a79d8c 100644
--- a/Framework/Algorithms/src/GetEiMonDet2.cpp
+++ b/Framework/Algorithms/src/GetEiMonDet2.cpp
@@ -3,6 +3,7 @@
 #include "MantidAPI/InstrumentValidator.h"
 #include "MantidAPI/ITableWorkspace.h"
 #include "MantidAPI/Run.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidAPI/WorkspaceUnitValidator.h"
 #include "MantidGeometry/Instrument.h"
 #include "MantidKernel/ArrayProperty.h"
@@ -21,6 +22,7 @@ using namespace Mantid::PhysicalConstants;
 namespace Mantid {
 namespace Algorithms {
 
+namespace {
 /** A private namespace to store string constants dealing with
  *  tables returned by the FindEPP algorithm.
  */
@@ -38,11 +40,11 @@ const static std::string FIT_STATUS_SUCCESS("success");
  */
 namespace IndexTypes {
 /// Tag for detector ids
-const static std::string DETECTOR_ID("DetectorID");
+const static std::string DETECTOR_ID("Detector ID");
 /// Tag for spectrum numbers
-const static std::string SPECTRUM_NUMBER("SpectrumNumber");
+const static std::string SPECTRUM_NUMBER("Spectrum Number");
 /// Tag for workspace indices
-const static std::string WORKSPACE_INDEX("WorkspaceIndex");
+const static std::string WORKSPACE_INDEX("Workspace Index");
 }
 
 /** A private namespace holding the property names of
@@ -71,6 +73,14 @@ const static std::string NOMINAL_ENERGY("NominalIncidentEnergy");
 const static std::string PULSE_INTERVAL("PulseInterval");
 }
 
+/** A private namespace holding names for sample log entries.
+ */
+namespace SampleLogs {
+/// Name of the pulse interval sample log
+const static std::string PULSE_INTERVAL("pulse_interval");
+}
+} // anonymous namespace
+
 // Register the algorithm into the algorithm factory.
 DECLARE_ALGORITHM(GetEiMonDet2)
 
@@ -123,7 +133,8 @@ void GetEiMonDet2::init() {
   declareProperty(PropertyNames::MONITOR, EMPTY_INT(), mandatoryIntProperty,
                   "Monitor's detector id/spectrum number/workspace index.");
   declareProperty(PropertyNames::PULSE_INTERVAL, EMPTY_DBL(),
-                  "Interval between neutron pulses, in microseconds.");
+                  "Interval between neutron pulses, in microseconds. Taken "
+                  "from the sample logs, if not specified.");
   declareProperty(
       PropertyNames::NOMINAL_ENERGY, EMPTY_DBL(), mustBePositive,
       "Incident energy guess. Taken from the sample logs, if not specified.");
@@ -198,6 +209,7 @@ void GetEiMonDet2::averageDetectorDistanceAndTOF(
   double distanceSum = 0;
   double eppSum = 0;
   size_t n = 0;
+  auto &spectrumInfo = m_detectorWs->spectrumInfo();
   // cppcheck-suppress syntaxError
   PRAGMA_OMP(parallel for if ( m_detectorEPPTable->threadSafe())
              reduction(+: n, distanceSum, eppSum))
@@ -210,17 +222,16 @@ void GetEiMonDet2::averageDetectorDistanceAndTOF(
     }
     if (fitStatusColumn->cell<std::string>(index) ==
         EPPTableLiterals::FIT_STATUS_SUCCESS) {
-      const auto detector = m_detectorWs->getDetector(index);
-      if (!detector) {
+      if (!spectrumInfo.hasDetectors(index)) {
         throw std::runtime_error("No detector specified by " +
                                  PropertyNames::DETECTORS + " found");
       }
-      if (detector->isMonitor()) {
+      if (spectrumInfo.isMonitor(index)) {
         g_log.warning() << "Workspace index " << index
                         << " should be detector, but is marked as monitor.\n";
       }
-      if (!detector->isMasked()) {
-        const double d = detector->getDistance(*sample);
+      if (!spectrumInfo.isMasked(index)) {
+        const double d = spectrumInfo.detector(index).getDistance(*sample);
         distanceSum += d;
         const double epp = (*peakPositionColumn)[index];
         eppSum += epp;
@@ -274,10 +285,17 @@ double GetEiMonDet2::computeTOF(const double distance, const double detectorEPP,
   g_log.information() << "Nominal time-of-flight: " << nominalTimeOfFlight
                       << ".\n";
   // Check if the obtained time-of-flight makes any sense.
-  const double energyTolerance = 20; // %'s of the nominal energy
+  const double energyTolerance = 0.2; // As a fraction of nominal energy.
   const double toleranceLimit =
       1 / std::sqrt(1 + energyTolerance) * nominalTimeOfFlight;
-  const double pulseInterval = getProperty(PropertyNames::PULSE_INTERVAL);
+  double pulseInterval = getProperty(PropertyNames::PULSE_INTERVAL);
+  if (pulseInterval == EMPTY_DBL()) {
+    if (m_detectorWs->run().hasProperty(SampleLogs::PULSE_INTERVAL)) {
+      pulseInterval = m_detectorWs->run().getPropertyAsSingleValue(
+          SampleLogs::PULSE_INTERVAL);
+      pulseInterval *= 1e6; // To microseconds.
+    }
+  }
   const double pulseIntervalLimit = nominalTimeOfFlight - pulseInterval / 2;
   const double lowerTimeLimit =
       toleranceLimit > pulseIntervalLimit ? toleranceLimit : pulseIntervalLimit;
@@ -297,8 +315,8 @@ double GetEiMonDet2::computeTOF(const double distance, const double detectorEPP,
     // Neutrons hit the detectors in a later frame.
     interruption_point();
     if (pulseInterval == EMPTY_DBL()) {
-      throw std::runtime_error("No " + PropertyNames::PULSE_INTERVAL +
-                               " specified");
+      throw std::runtime_error(PropertyNames::PULSE_INTERVAL +
+                               " not specified nor found in sample logs");
     }
     ++delayFrameCount;
     timeOfFlight = delayFrameCount * pulseInterval - monitorEPP + detectorEPP;
@@ -337,16 +355,17 @@ void GetEiMonDet2::monitorDistanceAndTOF(const size_t monitorIndex,
     throw std::runtime_error("No successful monitor fit found in " +
                              PropertyNames::MONITOR_EPP_TABLE);
   }
-  const auto monitor = m_monitorWs->getDetector(monitorIndex);
-  if (monitor->isMasked()) {
+  auto &spectrumInfo = m_monitorWs->spectrumInfo();
+  if (spectrumInfo.isMasked(monitorIndex)) {
     throw std::runtime_error("Monitor spectrum is masked");
   }
-  if (!monitor->isMonitor()) {
+  if (!spectrumInfo.isMonitor(monitorIndex)) {
     g_log.warning() << "The monitor spectrum is not actually marked "
                     << "as monitor.\n";
   }
   const auto sample = m_detectorWs->getInstrument()->getSample();
-  monitorToSampleDistance = monitor->getDistance(*sample);
+  monitorToSampleDistance =
+      spectrumInfo.position(monitorIndex).distance(sample->getPos());
   g_log.information() << "Monitor-to-sample distance: "
                       << monitorToSampleDistance << ".\n";
 
diff --git a/Framework/Algorithms/src/GetTimeSeriesLogInformation.cpp b/Framework/Algorithms/src/GetTimeSeriesLogInformation.cpp
index 504118a4a6b388ddc7dda0c025ca0e3e979d4cb8..c6a1ad414e5f5fd4edfbd51c8bba40d22e1a8708 100644
--- a/Framework/Algorithms/src/GetTimeSeriesLogInformation.cpp
+++ b/Framework/Algorithms/src/GetTimeSeriesLogInformation.cpp
@@ -84,7 +84,7 @@ void GetTimeSeriesLogInformation::exec() {
   }
 
   string logname = getProperty("LogName");
-  if (logname.size() == 0)
+  if (logname.empty())
     throw runtime_error("Input log value cannot be an empty string. ");
 
   Kernel::Property *log = m_dataWS->run().getProperty(logname);
@@ -302,7 +302,6 @@ void GetTimeSeriesLogInformation::exportErrorLog(MatrixWorkspace_sptr ws,
   std::ofstream ofs;
   ofs.open(ofilename.c_str(), std::ios::out);
 
-  size_t numbaddt = 0;
   Kernel::DateAndTime t0(ws->run().getProperty("run_start")->value());
 
   for (size_t i = 1; i < abstimevec.size(); i++) {
@@ -310,12 +309,8 @@ void GetTimeSeriesLogInformation::exportErrorLog(MatrixWorkspace_sptr ws,
                                          abstimevec[i - 1].totalNanoseconds()) *
                      1.0E-9;
     double dev = (tempdts - dts) / dts;
-    bool baddt = false;
-    if (fabs(dev) > 0.5)
-      baddt = true;
 
-    if (baddt) {
-      numbaddt++;
+    if (fabs(dev) > 0.5) {
       double deltapulsetimeSec1 =
           static_cast<double>(abstimevec[i - 1].totalNanoseconds() -
                               t0.totalNanoseconds()) *
diff --git a/Framework/Algorithms/src/GroupWorkspaces.cpp b/Framework/Algorithms/src/GroupWorkspaces.cpp
index a685d64a15d79c9981b1d063afe5ac1814651efa..d4e5b9eb9a01d3abe006cced6f94dc7ef0499cc5 100644
--- a/Framework/Algorithms/src/GroupWorkspaces.cpp
+++ b/Framework/Algorithms/src/GroupWorkspaces.cpp
@@ -1,8 +1,7 @@
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidAlgorithms/GroupWorkspaces.h"
 #include "MantidAPI/ADSValidator.h"
+#include "MantidAPI/AnalysisDataService.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidKernel/ArrayProperty.h"
 
 namespace Mantid {
@@ -65,7 +64,7 @@ void GroupWorkspaces::addToGroup(const API::Workspace_sptr &workspace) {
   if (localGroup) {
     addToGroup(localGroup->getNames());
     // Remove the group from the ADS
-    AnalysisDataService::Instance().remove(workspace->name());
+    AnalysisDataService::Instance().remove(workspace->getName());
   } else {
     m_group->addWorkspace(workspace);
   }
diff --git a/Framework/Algorithms/src/HRPDSlabCanAbsorption.cpp b/Framework/Algorithms/src/HRPDSlabCanAbsorption.cpp
index fb259f02f90c065cb1ced3118fccc087d23f9585..373a6c697e362952fcb950b8e494e0c7e6a2e532 100644
--- a/Framework/Algorithms/src/HRPDSlabCanAbsorption.cpp
+++ b/Framework/Algorithms/src/HRPDSlabCanAbsorption.cpp
@@ -1,8 +1,7 @@
 #include "MantidAlgorithms/HRPDSlabCanAbsorption.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/Sample.h"
-#include "MantidGeometry/IDetector.h"
-#include "MantidGeometry/IComponent.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidGeometry/Instrument/Component.h"
 #include "MantidKernel/BoundedValidator.h"
 #include "MantidKernel/Material.h"
@@ -95,28 +94,22 @@ void HRPDSlabCanAbsorption::exec() {
 
   const size_t numHists = workspace->getNumberHistograms();
   const size_t specSize = workspace->blocksize();
+
+  const auto &spectrumInfo = workspace->spectrumInfo();
   //
   Progress progress(this, 0.91, 1.0, numHists);
   for (size_t i = 0; i < numHists; ++i) {
     MantidVec &Y = workspace->dataY(i);
 
-    // Get detector position
-    IDetector_const_sptr det;
-    try {
-      det = workspace->getDetector(i);
-    } catch (Exception::NotFoundError &) {
-      // Catch when a spectrum doesn't have an attached detector and go to next
-      // one
+    if (!spectrumInfo.hasDetectors(i)) {
+      // If a spectrum doesn't have an attached detector go to next one instead
       continue;
     }
 
-    V3D detectorPos;
-    detectorPos.spherical(
-        det->getDistance(Component("dummy", V3D(0.0, 0.0, 0.0))),
-        det->getTwoTheta(V3D(0.0, 0.0, 0.0), V3D(0.0, 0.0, 1.0)) * 180.0 / M_PI,
-        det->getPhi() * 180.0 / M_PI);
+    // Get detector position
+    V3D detectorPos = spectrumInfo.position(i);
 
-    const int detID = det->getID();
+    const int detID = spectrumInfo.detector(i).getID();
     double angleFactor;
     // If the low angle or backscattering bank, want angle wrt beamline
     if (detID < 900000) {
diff --git a/Framework/Algorithms/src/He3TubeEfficiency.cpp b/Framework/Algorithms/src/He3TubeEfficiency.cpp
index 96dad74d98a5a1ab9e6c9f02c17248b27e66cbd3..7f7be044328501c2e4cfe4c1ced8ef907ff8c4b3 100644
--- a/Framework/Algorithms/src/He3TubeEfficiency.cpp
+++ b/Framework/Algorithms/src/He3TubeEfficiency.cpp
@@ -2,12 +2,15 @@
 #include "MantidAPI/Axis.h"
 #include "MantidAPI/HistogramValidator.h"
 #include "MantidAPI/InstrumentValidator.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidAPI/WorkspaceUnitValidator.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidDataObjects/EventWorkspace.h"
 #include "MantidDataObjects/Workspace2D.h"
 #include "MantidGeometry/Instrument.h"
 #include "MantidGeometry/Instrument/ParameterMap.h"
+#include "MantidGeometry/Objects/Object.h"
+#include "MantidGeometry/Objects/Track.h"
 #include "MantidKernel/ArrayBoundedValidator.h"
 #include "MantidKernel/ArrayProperty.h"
 #include "MantidKernel/CompositeValidator.h"
@@ -116,6 +119,7 @@ void He3TubeEfficiency::exec() {
 
   std::size_t numHists = this->inputWS->getNumberHistograms();
   this->progress = new API::Progress(this, 0.0, 1.0, numHists);
+  const auto &spectrumInfo = inputWS->spectrumInfo();
 
   PARALLEL_FOR_IF(Kernel::threadSafe(*inputWS, *outputWS))
   for (int i = 0; i < static_cast<int>(numHists); ++i) {
@@ -123,7 +127,7 @@ void He3TubeEfficiency::exec() {
 
     this->outputWS->setX(i, this->inputWS->refX(i));
     try {
-      this->correctForEfficiency(i);
+      this->correctForEfficiency(i, spectrumInfo);
     } catch (std::out_of_range &) {
       // if we don't have all the data there will be spectra we can't correct,
       // avoid leaving the workspace part corrected
@@ -155,17 +159,20 @@ void He3TubeEfficiency::exec() {
  * information. Gets the detector information and uses this to calculate its
  * efficiency
  *  @param spectraIndex :: index of the spectrum to get the efficiency for
+ *  @param spectrumInfo :: the SpectrumInfo object for the input workspace
  *  @throw invalid_argument if the shape of a detector is isn't a cylinder
  *  aligned along one axis
  *  @throw NotFoundError if the detector or its gas pressure or wall thickness
  *  were not found
  */
-void He3TubeEfficiency::correctForEfficiency(std::size_t spectraIndex) {
-  Geometry::IDetector_const_sptr det = this->inputWS->getDetector(spectraIndex);
-  if (det->isMonitor() || det->isMasked()) {
+void He3TubeEfficiency::correctForEfficiency(
+    std::size_t spectraIndex, const API::SpectrumInfo &spectrumInfo) {
+  if (spectrumInfo.isMonitor(spectraIndex) ||
+      spectrumInfo.isMasked(spectraIndex)) {
     return;
   }
 
+  const auto &det = spectrumInfo.detector(spectraIndex);
   const double exp_constant = this->calculateExponential(spectraIndex, det);
   const double scale = this->getProperty("ScaleFactor");
 
@@ -201,9 +208,9 @@ void He3TubeEfficiency::correctForEfficiency(std::size_t spectraIndex) {
  * @throw out_of_range if twice tube thickness is greater than tube diameter
  * @return the exponential contribution for the given detector
  */
-double He3TubeEfficiency::calculateExponential(
-    std::size_t spectraIndex,
-    boost::shared_ptr<const Geometry::IDetector> idet) {
+double
+He3TubeEfficiency::calculateExponential(std::size_t spectraIndex,
+                                        const Geometry::IDetector &idet) {
   // Get the parameters for the current associated tube
   double pressure =
       this->getParameter("TubePressure", spectraIndex, "tube_pressure", idet);
@@ -221,9 +228,9 @@ double He3TubeEfficiency::calculateExponential(
   // now get the sin of the angle, it's the magnitude of the cross product of
   // unit vector along the detector tube axis and a unit vector directed from
   // the sample to the detector center
-  Kernel::V3D vectorFromSample = idet->getPos() - this->samplePos;
+  Kernel::V3D vectorFromSample = idet.getPos() - this->samplePos;
   vectorFromSample.normalize();
-  Kernel::Quat rot = idet->getRotation();
+  Kernel::Quat rot = idet.getRotation();
   // rotate the original cylinder object axis to get the detector axis in the
   // actual instrument
   rot.rotate(detAxis);
@@ -248,14 +255,14 @@ double He3TubeEfficiency::calculateExponential(
  * @param detRadius :: An output parameter that contains the detector radius
  * @param detAxis :: An output parameter that contains the detector axis vector
  */
-void He3TubeEfficiency::getDetectorGeometry(
-    const boost::shared_ptr<const Geometry::IDetector> &det, double &detRadius,
-    Kernel::V3D &detAxis) {
-  boost::shared_ptr<const Geometry::Object> shape_sptr = det->shape();
+void He3TubeEfficiency::getDetectorGeometry(const Geometry::IDetector &det,
+                                            double &detRadius,
+                                            Kernel::V3D &detAxis) {
+  boost::shared_ptr<const Geometry::Object> shape_sptr = det.shape();
   if (!shape_sptr) {
     throw std::runtime_error(
         "Detector geometry error: detector with id: " +
-        std::to_string(det->getID()) +
+        std::to_string(det.getID()) +
         " does not have shape. Is this a detectors group?\n"
         "The algorithm works for instruments with one-to-one "
         "spectra-to-detector maps only!");
@@ -386,13 +393,14 @@ void He3TubeEfficiency::logErrors() const {
  * @param idet :: the current detector
  * @return the value of the detector property
  */
-double He3TubeEfficiency::getParameter(
-    std::string wsPropName, std::size_t currentIndex, std::string detPropName,
-    boost::shared_ptr<const Geometry::IDetector> idet) {
+double He3TubeEfficiency::getParameter(std::string wsPropName,
+                                       std::size_t currentIndex,
+                                       std::string detPropName,
+                                       const Geometry::IDetector &idet) {
   std::vector<double> wsProp = this->getProperty(wsPropName);
 
   if (wsProp.empty()) {
-    return idet->getNumberParameter(detPropName).at(0);
+    return idet.getNumberParameter(detPropName).at(0);
   } else {
     if (wsProp.size() == 1) {
       return wsProp.at(0);
@@ -421,13 +429,15 @@ void He3TubeEfficiency::execEvent() {
       boost::dynamic_pointer_cast<DataObjects::EventWorkspace>(matrixOutputWS);
 
   std::size_t numHistograms = outputWS->getNumberHistograms();
+  auto &spectrumInfo = outputWS->mutableSpectrumInfo();
   this->progress = new API::Progress(this, 0.0, 1.0, numHistograms);
+
   PARALLEL_FOR_IF(Kernel::threadSafe(*outputWS))
   for (int i = 0; i < static_cast<int>(numHistograms); ++i) {
     PARALLEL_START_INTERUPT_REGION
 
-    Geometry::IDetector_const_sptr det = outputWS->getDetector(i);
-    if (det->isMonitor() || det->isMasked()) {
+    const auto &det = spectrumInfo.detector(i);
+    if (spectrumInfo.isMonitor(i) || spectrumInfo.isMasked(i)) {
       continue;
     }
 
@@ -438,7 +448,8 @@ void He3TubeEfficiency::execEvent() {
       // Parameters are bad so skip correction
       PARALLEL_CRITICAL(deteff_invalid) {
         this->spectraSkipped.push_back(outputWS->getAxis(1)->spectraNo(i));
-        outputWS->maskWorkspaceIndex(i);
+        outputWS->getSpectrum(i).clearData();
+        spectrumInfo.setMasked(i, true);
       }
     }
 
diff --git a/Framework/Algorithms/src/Integration.cpp b/Framework/Algorithms/src/Integration.cpp
index 0e06abbe111e8abc9de45f75ff46614390176744..9e77fad4a0cbcdf33a31f47253b69a306fc2e929 100644
--- a/Framework/Algorithms/src/Integration.cpp
+++ b/Framework/Algorithms/src/Integration.cpp
@@ -347,7 +347,7 @@ MatrixWorkspace_sptr Integration::getOutputWorkspace(MatrixWorkspace_sptr inWS,
   if (inWS->id() == "RebinnedOutput") {
     MatrixWorkspace_sptr outWS = API::WorkspaceFactory::Instance().create(
         "Workspace2D", maxSpec - minSpec + 1, 2, 1);
-    API::WorkspaceFactory::Instance().initializeFromParent(inWS, outWS, true);
+    API::WorkspaceFactory::Instance().initializeFromParent(*inWS, *outWS, true);
     return outWS;
   } else {
     return API::WorkspaceFactory::Instance().create(inWS, maxSpec - minSpec + 1,
diff --git a/Framework/Algorithms/src/InterpolatingRebin.cpp b/Framework/Algorithms/src/InterpolatingRebin.cpp
index 43f9fffc6b970c80b64ac2aa5b60eb1e2811b5e0..3005fe25b506e33ee850ad6d7febe8a24ecac145 100644
--- a/Framework/Algorithms/src/InterpolatingRebin.cpp
+++ b/Framework/Algorithms/src/InterpolatingRebin.cpp
@@ -1,6 +1,3 @@
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidAlgorithms/InterpolatingRebin.h"
 #include "MantidAPI/Axis.h"
 #include "MantidAPI/MatrixWorkspace.h"
@@ -13,6 +10,8 @@
 #include <gsl/gsl_interp.h>
 #include <gsl/gsl_spline.h>
 
+#include <boost/lexical_cast.hpp>
+
 namespace Mantid {
 namespace Algorithms {
 
diff --git a/Framework/Algorithms/src/InterpolationOption.cpp b/Framework/Algorithms/src/InterpolationOption.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f9325dba7ed24f99bcb3a819a18c17f315ef720c
--- /dev/null
+++ b/Framework/Algorithms/src/InterpolationOption.cpp
@@ -0,0 +1,89 @@
+#include "MantidAlgorithms/InterpolationOption.h"
+#include "MantidHistogramData/Interpolate.h"
+#include "MantidKernel/ListValidator.h"
+#include "MantidKernel/make_unique.h"
+#include "MantidKernel/PropertyWithValue.h"
+
+#include <cassert>
+
+namespace {
+// The name of the interpolation property
+std::string PROP_NAME("Interpolation");
+std::string LINEAR_OPT("Linear");
+std::string CSPLINE_OPT("CSpline");
+std::vector<std::string> OPTIONS{LINEAR_OPT, CSPLINE_OPT};
+}
+
+namespace Mantid {
+using HistogramData::interpolateLinearInplace;
+using HistogramData::interpolateCSplineInplace;
+using Kernel::Property;
+
+namespace Algorithms {
+
+/**
+ * Constructs an object with the default interpolation method
+ */
+InterpolationOption::InterpolationOption() { set(Value::Linear); }
+
+/**
+ * Set the interpolation option
+ * @param kind Set the type of interpolation on the call to apply
+ */
+void InterpolationOption::set(InterpolationOption::Value kind) {
+  if (kind == Value::Linear) {
+    m_impl = interpolateLinearInplace;
+  } else {
+    m_impl = interpolateCSplineInplace;
+  }
+}
+
+/**
+ * Set the interpolation option
+ * @param kind Set the type of interpolation on the call to apply
+ */
+void InterpolationOption::set(const std::string &kind) {
+  if (kind == LINEAR_OPT) {
+    m_impl = interpolateLinearInplace;
+  } else if (kind == CSPLINE_OPT) {
+    m_impl = interpolateCSplineInplace;
+  } else {
+    throw std::invalid_argument(
+        "InterpolationOption::set() - Unknown interpolation method '" + kind +
+        "'");
+  }
+}
+
+/**
+ * Create a property suitable to attach to an algorithm to support interpolation
+ * @return A new Property containing the valid list of interpolation methods
+ */
+
+std::unique_ptr<Property> InterpolationOption::property() const {
+  using Kernel::StringListValidator;
+  using StringProperty = Kernel::PropertyWithValue<std::string>;
+
+  return Kernel::make_unique<StringProperty>(
+      PROP_NAME, LINEAR_OPT, boost::make_shared<StringListValidator>(OPTIONS));
+}
+
+/**
+ * @return The documentation string for the property
+ */
+std::string InterpolationOption::propertyDoc() const {
+  return "Method of interpolation used to compute unsimulated values.";
+}
+
+/**
+ * Apply the interpolation method to the given histogram
+ * @param inOut A reference to a histogram to interpolate
+ * @param stepSize The step size of calculated points
+ */
+void InterpolationOption::applyInplace(HistogramData::Histogram &inOut,
+                                       size_t stepSize) const {
+  assert(m_impl);
+  (*m_impl)(inOut, stepSize);
+}
+
+} // namespace Algorithms
+} // namespace Mantid
diff --git a/Framework/Algorithms/src/InvertMask.cpp b/Framework/Algorithms/src/InvertMask.cpp
index d767d4c6d77033595cc6366e357444990f880d85..52710f4feea7046c470c8d3f35c0a2d4648b8f78 100644
--- a/Framework/Algorithms/src/InvertMask.cpp
+++ b/Framework/Algorithms/src/InvertMask.cpp
@@ -34,7 +34,7 @@ void InvertMask::exec() {
   // 2. Do Invert by calling Child Algorithm
   API::IAlgorithm_sptr invert =
       createChildAlgorithm("BinaryOperateMasks", 0.0, 1.0, true);
-  invert->setPropertyValue("InputWorkspace1", inWS->name());
+  invert->setPropertyValue("InputWorkspace1", inWS->getName());
   invert->setProperty("OperationType", "NOT");
   invert->setProperty("OutputWorkspace", "tempws");
 
diff --git a/Framework/Algorithms/src/MaskBins.cpp b/Framework/Algorithms/src/MaskBins.cpp
index 454de81284b4f6471b86a1fc58f24190b39b3300..b5ddc35af20dd721782f9c0228ed64edfeb5583d 100644
--- a/Framework/Algorithms/src/MaskBins.cpp
+++ b/Framework/Algorithms/src/MaskBins.cpp
@@ -114,7 +114,7 @@ void MaskBins::exec() {
 
     // If the binning is the same throughout, we only need to find the index
     // limits once
-    const bool commonBins = WorkspaceHelpers::commonBoundaries(inputWS);
+    const bool commonBins = WorkspaceHelpers::commonBoundaries(*inputWS);
     if (commonBins) {
       auto X = inputWS->binEdges(0);
       this->findIndices(X, startBin, endBin);
diff --git a/Framework/Algorithms/src/MaskBinsFromTable.cpp b/Framework/Algorithms/src/MaskBinsFromTable.cpp
index 81b0850543db77fa84f0a805123c801970a47386..08d18b56d4f401f42e341211a5b8dd31ae177f4c 100644
--- a/Framework/Algorithms/src/MaskBinsFromTable.cpp
+++ b/Framework/Algorithms/src/MaskBinsFromTable.cpp
@@ -158,7 +158,7 @@ void MaskBinsFromTable::processMaskBinWorkspace(
     } else if (boost::algorithm::starts_with(colname, "detectorid")) {
       id_dets = i;
     } else {
-      g_log.warning() << "In TableWorkspace " << masktblws->name()
+      g_log.warning() << "In TableWorkspace " << masktblws->getName()
                       << ", column " << i << " with name " << colname
                       << " is not used by MaskBinsFromTable.";
     }
diff --git a/Framework/Algorithms/src/MaskDetectorsIf.cpp b/Framework/Algorithms/src/MaskDetectorsIf.cpp
index 2c390d55feb06819fce6d1afba2364521c06b280..8a0905510eae4f090765e908ba372413e43dd43e 100644
--- a/Framework/Algorithms/src/MaskDetectorsIf.cpp
+++ b/Framework/Algorithms/src/MaskDetectorsIf.cpp
@@ -1,12 +1,10 @@
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidAlgorithms/MaskDetectorsIf.h"
 #include "MantidAPI/FileProperty.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidKernel/ListValidator.h"
 
 #include <fstream>
+#include <iomanip>
 
 namespace Mantid {
 namespace Algorithms {
diff --git a/Framework/Algorithms/src/MedianDetectorTest.cpp b/Framework/Algorithms/src/MedianDetectorTest.cpp
index 8844f32e172146c517f6e2be5ffcba795eda476d..55dc0c82a9aca0f0dd86653ac5c4292ba7840d59 100644
--- a/Framework/Algorithms/src/MedianDetectorTest.cpp
+++ b/Framework/Algorithms/src/MedianDetectorTest.cpp
@@ -1,5 +1,6 @@
 #include "MantidAlgorithms/MedianDetectorTest.h"
 #include "MantidAPI/HistogramValidator.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidKernel/BoundedValidator.h"
 
 #include <cmath>
@@ -246,6 +247,7 @@ int MedianDetectorTest::maskOutliers(
     checkForMask = ((instrument->getSource() != nullptr) &&
                     (instrument->getSample() != nullptr));
   }
+  auto &spectrumInfo = countsWS->mutableSpectrumInfo();
 
   for (size_t i = 0; i < indexmap.size(); ++i) {
     std::vector<size_t> &hists = indexmap[i];
@@ -255,19 +257,23 @@ int MedianDetectorTest::maskOutliers(
     for (int j = 0; j < static_cast<int>(hists.size()); ++j) { // NOLINT
       const double value = countsWS->y(hists[j])[0];
       if ((value == 0.) && checkForMask) {
-        const auto &detids = countsWS->getSpectrum(hists[j]).getDetectorIDs();
-        if (instrument->isDetectorMasked(detids)) {
+        if (spectrumInfo.hasDetectors(hists[j]) &&
+            spectrumInfo.isMasked(hists[j])) {
           numFailed -= 1; // it was already masked
         }
       }
       if ((value < out_lo * median) && (value > 0.0)) {
-        countsWS->maskWorkspaceIndex(hists[j]);
-        PARALLEL_ATOMIC
-        ++numFailed;
+        countsWS->getSpectrum(hists[j]).clearData();
+        PARALLEL_CRITICAL(setMasked) {
+          spectrumInfo.setMasked(hists[j], true);
+          ++numFailed;
+        }
       } else if (value > out_hi * median) {
-        countsWS->maskWorkspaceIndex(hists[j]);
-        PARALLEL_ATOMIC
-        ++numFailed;
+        countsWS->getSpectrum(hists[j]).clearData();
+        PARALLEL_CRITICAL(setMasked) {
+          spectrumInfo.setMasked(hists[j], true);
+          ++numFailed;
+        }
       }
     }
     PARALLEL_CHECK_INTERUPT_REGION
@@ -313,6 +319,7 @@ int MedianDetectorTest::doDetectorTests(
     checkForMask = ((instrument->getSource() != nullptr) &&
                     (instrument->getSample() != nullptr));
   }
+  const auto &spectrumInfo = countsWS->spectrumInfo();
 
   PARALLEL_FOR_IF(Kernel::threadSafe(*countsWS, *maskWS))
   for (int j = 0; j < static_cast<int>(indexmap.size()); ++j) {
@@ -331,14 +338,12 @@ int MedianDetectorTest::doDetectorTests(
                                  numSpec));
       }
 
-      if (checkForMask) {
-        const auto &detids =
-            countsWS->getSpectrum(hists.at(i)).getDetectorIDs();
-        if (instrument->isDetectorMasked(detids)) {
+      if (checkForMask && spectrumInfo.hasDetectors(hists.at(i))) {
+        if (spectrumInfo.isMasked(hists.at(i))) {
           maskWS->mutableY(hists.at(i))[0] = deadValue;
           continue;
         }
-        if (instrument->isMonitor(detids)) {
+        if (spectrumInfo.isMonitor(hists.at(i))) {
           // Don't include in calculation but don't mask it
           continue;
         }
diff --git a/Framework/Algorithms/src/MergeRuns.cpp b/Framework/Algorithms/src/MergeRuns.cpp
index 52c6d8b880ba776443ad725fbd1d8eafea31932a..863df32806da78f8da44dc18e4ab8485e43d1d6a 100644
--- a/Framework/Algorithms/src/MergeRuns.cpp
+++ b/Framework/Algorithms/src/MergeRuns.cpp
@@ -5,13 +5,14 @@
 #include "MantidAPI/Axis.h"
 #include "MantidAPI/AlgorithmManager.h"
 #include "MantidAPI/Run.h"
-#include "MantidAPI/WorkspaceFactory.h"
 #include "MantidAPI/WorkspaceGroup.h"
 #include "MantidGeometry/Instrument.h"
 #include "MantidKernel/ArrayProperty.h"
+#include "MantidKernel/Unit.h"
 #include "MantidKernel/make_unique.h"
 #include "MantidAPI/ADSValidator.h"
 #include "MantidAlgorithms/MergeRuns/SampleLogsBehaviour.h"
+#include "MantidDataObjects/WorkspaceCreation.h"
 
 using Mantid::HistogramData::HistogramX;
 
@@ -139,7 +140,7 @@ void MergeRuns::exec() {
       MatrixWorkspace_sptr addee;
       // Only do a rebinning if the bins don't already match - otherwise can
       // just add (see the 'else')
-      if (!WorkspaceHelpers::matchingBins(outWS, *it, true)) {
+      if (!WorkspaceHelpers::matchingBins(*outWS, **it, true)) {
         std::vector<double> rebinParams;
         this->calculateRebinParams(outWS, *it, rebinParams);
 
@@ -158,7 +159,7 @@ void MergeRuns::exec() {
         sampleLogsBehaviour.setUpdatedSampleLogs(*outWS);
       } catch (std::invalid_argument &e) {
         g_log.error()
-            << "Could not merge run: " << it->get()->name() << ". Reason: \""
+            << "Could not merge run: " << it->get()->getName() << ". Reason: \""
             << e.what()
             << "\". MergeRuns will continue but this run will be skipped.";
         sampleLogsBehaviour.resetSampleLogs(*outWS);
@@ -310,9 +311,7 @@ void MergeRuns::execEvent() {
 
   // Create a new output event workspace, by copying the first WS in the list
   EventWorkspace_sptr inputWS = m_inEventWS[0];
-  auto outWS = createWorkspace<EventWorkspace>(
-      m_outputSize, inputWS->x(0).size(), inputWS->y(0).size());
-  WorkspaceFactory::Instance().initializeFromParent(inputWS, outWS, false);
+  auto outWS = create<EventWorkspace>(*inputWS, m_outputSize);
   const auto inputSize = inputWS->getNumberHistograms();
   for (size_t i = 0; i < inputSize; ++i)
     outWS->getSpectrum(i) = inputWS->getSpectrum(i);
@@ -346,8 +345,7 @@ void MergeRuns::execEvent() {
   }
 
   // Set the final workspace to the output property
-  setProperty("OutputWorkspace",
-              boost::dynamic_pointer_cast<MatrixWorkspace>(outWS));
+  setProperty("OutputWorkspace", std::move(outWS));
 }
 
 //------------------------------------------------------------------------------------------------
@@ -481,7 +479,7 @@ MergeRuns::validateInputs(const std::vector<std::string> &inputWorkspaces) {
       throw;
     }
     // Check that it has common binning
-    if (!WorkspaceHelpers::commonBoundaries(inWS.back())) {
+    if (!WorkspaceHelpers::commonBoundaries(*inWS.back())) {
       g_log.error("Input workspaces must have common binning for all spectra");
       throw std::invalid_argument(
           "Input workspaces must have common binning for all spectra");
diff --git a/Framework/Algorithms/src/MergeRuns/SampleLogsBehaviour.cpp b/Framework/Algorithms/src/MergeRuns/SampleLogsBehaviour.cpp
index 86c351bad639c95b665a08d563f24629a66ad635..a6d60412ff163d357791f65183865aafefb71cd8 100644
--- a/Framework/Algorithms/src/MergeRuns/SampleLogsBehaviour.cpp
+++ b/Framework/Algorithms/src/MergeRuns/SampleLogsBehaviour.cpp
@@ -1,6 +1,8 @@
 #include "MantidAlgorithms/MergeRuns/SampleLogsBehaviour.h"
 #include "MantidAPI/Run.h"
 #include "MantidGeometry/Instrument.h"
+#include "MantidKernel/Strings.h"
+#include "MantidKernel/StringTokenizer.h"
 #include "MantidKernel/TimeSeriesProperty.h"
 
 namespace Mantid {
@@ -442,7 +444,7 @@ void SampleLogsBehaviour::checkWarnProperty(const MatrixWorkspace &addeeWS,
   if (!isWithinTolerance(behaviour, addeeWSNumber, outWSNumber) &&
       !stringPropertiesMatch(behaviour, addeeWSProperty)) {
     m_logger.warning() << generateDifferenceMessage(
-        name, addeeWS.name(), addeeWSProperty->value(),
+        name, addeeWS.getName(), addeeWSProperty->value(),
         behaviour.property->value());
   }
 }
@@ -468,7 +470,7 @@ void SampleLogsBehaviour::checkErrorProperty(
   if (!isWithinTolerance(behaviour, addeeWSNumber, outWSNumber) &&
       !stringPropertiesMatch(behaviour, addeeWSProperty)) {
     throw std::invalid_argument(generateDifferenceMessage(
-        name, addeeWS.name(), addeeWSProperty->value(),
+        name, addeeWS.getName(), addeeWSProperty->value(),
         behaviour.property->value()));
   }
 }
diff --git a/Framework/Algorithms/src/ModeratorTzero.cpp b/Framework/Algorithms/src/ModeratorTzero.cpp
index 488e1099cf704aa023bf61b33ce14a385bcd5b73..72856b0e420f51d9404571df50eeb3405c8ee13b 100644
--- a/Framework/Algorithms/src/ModeratorTzero.cpp
+++ b/Framework/Algorithms/src/ModeratorTzero.cpp
@@ -1,6 +1,7 @@
 #include "MantidAlgorithms/ModeratorTzero.h"
 #include "MantidAPI/Axis.h"
 #include "MantidAPI/Run.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidAPI/WorkspaceUnitValidator.h"
 #include "MantidDataObjects/EventList.h"
@@ -66,7 +67,6 @@ void ModeratorTzero::exec() {
                                     // emission time, in microseconds
   m_niter = getProperty("Niter");   // number of iterations
   const MatrixWorkspace_sptr inputWS = getProperty("InputWorkspace");
-  m_instrument = inputWS->getInstrument(); // pointer to the instrument
   const std::string emode = getProperty("EMode");
 
   // Check if Ei stored in workspace
@@ -78,25 +78,12 @@ void ModeratorTzero::exec() {
   }
 
   // extract formula from instrument parameters
-  std::vector<std::string> t0_formula =
-      m_instrument->getStringParameter("t0_formula");
+  auto t0_formula = inputWS->getInstrument()->getStringParameter("t0_formula");
   if (t0_formula.empty()) {
     g_log.error("Unable to retrieve t0_formula among instrument parameters.");
     return;
   }
   m_formula = t0_formula[0];
-  // Are there source and sample?
-  IComponent_const_sptr source;
-  IComponent_const_sptr sample;
-  double Lss(0); // distance from source to sample
-  try {
-    source = m_instrument->getSource();
-    sample = m_instrument->getSample();
-    Lss = source->getDistance(*sample);
-  } catch (Exception::NotFoundError &) {
-    g_log.error("Unable to calculate source-sample distance.");
-    return;
-  }
 
   // Run execEvent if eventWorkSpace
   EventWorkspace_const_sptr eventWS =
@@ -125,6 +112,9 @@ void ModeratorTzero::exec() {
     t0_direct = parser.Eval();
   }
 
+  const auto &spectrumInfo = inputWS->spectrumInfo();
+  const double Lss = spectrumInfo.l1();
+
   const size_t numHists = static_cast<size_t>(inputWS->getNumberHistograms());
   Progress prog(this, 0.0, 1.0, numHists); // report progress of algorithm
   PARALLEL_FOR_IF(Kernel::threadSafe(*inputWS, *outputWS))
@@ -139,20 +129,17 @@ void ModeratorTzero::exec() {
     parser.DefineVar("incidentEnergy", &E1); // associate E1 to this parser
     parser.SetExpr(m_formula);
 
-    IDetector_const_sptr det;
     double L1(Lss); // distance from source to sample
     double L2(-1);  // distance from sample to detector
-    try {
-      det = inputWS->getDetector(i);
-      if (det->isMonitor()) {
+    if (spectrumInfo.hasDetectors(i)) {
+      if (spectrumInfo.isMonitor(i)) {
         // redefine the sample as the monitor
-        L1 = source->getDistance(*det);
+        L1 = Lss + spectrumInfo.l2(i); // L2 in SpectrumInfo defined negative
         L2 = 0;
       } else {
-        L2 = sample->getDistance(*det);
+        L2 = spectrumInfo.l2(i);
       }
-    } // end of try
-    catch (Exception::NotFoundError &) {
+    } else {
       g_log.error() << "Unable to calculate distances to/from detector" << i
                     << '\n';
     }
@@ -165,13 +152,14 @@ void ModeratorTzero::exec() {
 
       if (emode == "Indirect") {
         double t2(-1.0); // time from sample to detector. (-1) signals error
-        if (det->isMonitor()) {
+        if (spectrumInfo.isMonitor(i)) {
           t2 = 0.0;
         } else {
           static const double convFact =
               1.0e-6 *
               sqrt(2 * PhysicalConstants::meV / PhysicalConstants::NeutronMass);
-          std::vector<double> wsProp = det->getNumberParameter("Efixed");
+          std::vector<double> wsProp =
+              spectrumInfo.detector(i).getNumberParameter("Efixed");
           if (!wsProp.empty()) {
             double E2 = wsProp.at(0);        //[E2]=meV
             double v2 = convFact * sqrt(E2); //[v2]=meter/microsec
@@ -241,11 +229,6 @@ void ModeratorTzero::execEvent(const std::string &emode) {
   }
   auto outputWS = boost::dynamic_pointer_cast<EventWorkspace>(matrixOutputWS);
 
-  // Get pointers to sample and source
-  IComponent_const_sptr source = m_instrument->getSource();
-  IComponent_const_sptr sample = m_instrument->getSample();
-  double Lss = source->getDistance(*sample); // distance from source to sample
-
   // calculate tof shift once for all neutrons if emode==Direct
   double t0_direct(-1);
   if (emode == "Direct") {
@@ -257,6 +240,9 @@ void ModeratorTzero::execEvent(const std::string &emode) {
     t0_direct = parser.Eval();
   }
 
+  const auto &spectrumInfo = outputWS->spectrumInfo();
+  const double Lss = spectrumInfo.l1();
+
   // Loop over the spectra
   const size_t numHists = static_cast<size_t>(outputWS->getNumberHistograms());
   Progress prog(this, 0.0, 1.0, numHists); // report progress of algorithm
@@ -267,20 +253,18 @@ void ModeratorTzero::execEvent(const std::string &emode) {
     EventList &evlist = outputWS->getSpectrum(wsIndex);
     if (evlist.getNumberEvents() > 0) // don't bother with empty lists
     {
-      IDetector_const_sptr det;
       double L1(Lss); // distance from source to sample
       double L2(-1);  // distance from sample to detector
 
-      try {
-        det = outputWS->getDetector(i);
-        if (det->isMonitor()) {
+      if (spectrumInfo.hasDetectors(i)) {
+        if (spectrumInfo.isMonitor(i)) {
           // redefine the sample as the monitor
-          L1 = source->getDistance(*det);
+          L1 = Lss + spectrumInfo.l2(i); // L2 in SpectrumInfo defined negative
           L2 = 0;
         } else {
-          L2 = sample->getDistance(*det);
+          L2 = spectrumInfo.l2(i);
         }
-      } catch (Exception::NotFoundError &) {
+      } else {
         g_log.error() << "Unable to calculate distances to/from detector" << i
                       << '\n';
       }
@@ -299,13 +283,14 @@ void ModeratorTzero::execEvent(const std::string &emode) {
 
         if (emode == "Indirect") {
           double t2(-1.0); // time from sample to detector. (-1) signals error
-          if (det->isMonitor()) {
+          if (spectrumInfo.isMonitor(i)) {
             t2 = 0.0;
           } else {
             static const double convFact =
                 1.0e-6 * sqrt(2 * PhysicalConstants::meV /
                               PhysicalConstants::NeutronMass);
-            std::vector<double> wsProp = det->getNumberParameter("Efixed");
+            std::vector<double> wsProp =
+                spectrumInfo.detector(i).getNumberParameter("Efixed");
             if (!wsProp.empty()) {
               double E2 = wsProp.at(0);        //[E2]=meV
               double v2 = convFact * sqrt(E2); //[v2]=meter/microsec
diff --git a/Framework/Algorithms/src/ModeratorTzeroLinear.cpp b/Framework/Algorithms/src/ModeratorTzeroLinear.cpp
index d13fb6f89e68e43efca0fd6ae96c3f2ccdf0cf21..2f1622506cb5f735e792e07fd0f036efe7910f36 100644
--- a/Framework/Algorithms/src/ModeratorTzeroLinear.cpp
+++ b/Framework/Algorithms/src/ModeratorTzeroLinear.cpp
@@ -1,10 +1,12 @@
 #include "MantidAlgorithms/ModeratorTzeroLinear.h"
 #include "MantidAPI/Axis.h"
 #include "MantidAPI/Run.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidAPI/WorkspaceUnitValidator.h"
 #include "MantidDataObjects/EventWorkspace.h"
 #include "MantidDataObjects/Workspace2D.h"
+#include "MantidKernel/PhysicalConstants.h"
 #include "MantidKernel/UnitFactory.h"
 
 #include <boost/lexical_cast.hpp>
@@ -129,6 +131,7 @@ void ModeratorTzeroLinear::exec() {
   }
 
   // do the shift in X
+  const auto &spectrumInfo = inputWS->spectrumInfo();
   const size_t numHists = inputWS->getNumberHistograms();
   Progress prog(this, 0.0, 1.0, numHists); // report progress of algorithm
   PARALLEL_FOR_IF(Kernel::threadSafe(*inputWS, *outputWS))
@@ -136,7 +139,7 @@ void ModeratorTzeroLinear::exec() {
     PARALLEL_START_INTERUPT_REGION
     double t_f, L_i;
     size_t wsIndex = static_cast<size_t>(i);
-    calculateTfLi(inputWS, wsIndex, t_f, L_i);
+    calculateTfLi(spectrumInfo, wsIndex, t_f, L_i);
 
     outputWS->setHistogram(i, inputWS->histogram(i));
     // shift the time of flights
@@ -184,6 +187,7 @@ void ModeratorTzeroLinear::execEvent() {
   auto outputWS = boost::dynamic_pointer_cast<EventWorkspace>(matrixOutputWS);
 
   // Loop over the spectra
+  const auto &spectrumInfo = matrixOutputWS->spectrumInfo();
   const size_t numHists = outputWS->getNumberHistograms();
   Progress prog(this, 0.0, 1.0, numHists); // report progress of algorithm
   PARALLEL_FOR_IF(Kernel::threadSafe(*outputWS))
@@ -195,7 +199,7 @@ void ModeratorTzeroLinear::execEvent() {
     {
       // Calculate the time from sample to detector 'i'
       double t_f, L_i;
-      calculateTfLi(matrixOutputWS, wsIndex, t_f, L_i);
+      calculateTfLi(spectrumInfo, wsIndex, t_f, L_i);
       if (t_f >= 0) {
         const double scaling = L_i / (L_i + m_gradient);
         // Calculate new time of flight, TOF'=scaling*(TOF-t_f-intercept)+t_f =
@@ -211,57 +215,35 @@ void ModeratorTzeroLinear::execEvent() {
 } // end of void ModeratorTzeroLinear::execEvent()
 
 // calculate time from sample to detector
-void ModeratorTzeroLinear::calculateTfLi(MatrixWorkspace_const_sptr inputWS,
+void ModeratorTzeroLinear::calculateTfLi(const SpectrumInfo &spectrumInfo,
                                          size_t i, double &t_f, double &L_i) {
   static const double convFact = 1.0e-6 * sqrt(2 * PhysicalConstants::meV /
                                                PhysicalConstants::NeutronMass);
   static const double TfError = -1.0; // signal error when calculating final
                                       // time
-  // Get detector position
-  IDetector_const_sptr det;
-  try {
-    det = inputWS->getDetector(i);
-  } catch (Exception::NotFoundError &) {
+
+  if (!spectrumInfo.hasDetectors(i)) {
     t_f = TfError;
     return;
   }
 
-  if (det->isMonitor()) {
-    L_i = m_instrument->getSource()->getDistance(*det);
+  if (spectrumInfo.isMonitor(i)) {
+    L_i = spectrumInfo.sourcePosition().distance(spectrumInfo.position(i));
     t_f = 0.0; // t_f=0.0 since there is no sample to detector path
   } else {
-    IComponent_const_sptr sample = m_instrument->getSample();
-    try {
-      L_i = m_instrument->getSource()->getDistance(*sample);
-    } catch (Exception::NotFoundError &) {
-      g_log.error("Unable to calculate source-sample distance");
-      throw Exception::InstrumentDefinitionError(
-          "Unable to calculate source-sample distance", inputWS->getTitle());
-    }
+    L_i = spectrumInfo.l1();
     // Get final energy E_f, final velocity v_f
-    std::vector<double> wsProp = det->getNumberParameter("Efixed");
+    auto wsProp = spectrumInfo.detector(i).getNumberParameter("Efixed");
     if (!wsProp.empty()) {
       double E_f = wsProp.at(0);         //[E_f]=meV
       double v_f = convFact * sqrt(E_f); //[v_f]=meter/microsec
-
-      try {
-        // obtain L_f, calculate t_f
-        double L_f = det->getDistance(*sample);
-        t_f = L_f / v_f;
-        // g_log.debug() << "detector: " << i << " L_f=" << L_f << " t_f=" <<
-        // t_f << '\n';
-      } catch (Exception::NotFoundError &) {
-        g_log.error("Unable to calculate detector-sample distance");
-        throw Exception::InstrumentDefinitionError(
-            "Unable to calculate detector-sample distance",
-            inputWS->getTitle());
-      }
+      t_f = spectrumInfo.l2(i) / v_f;
     } else {
       g_log.debug() << "Efixed not found for detector " << i << '\n';
       t_f = TfError;
     }
   }
-} // end of CalculateTf(const MatrixWorkspace_sptr inputWS, size_t i)
+}
 
 } // namespace Algorithms
 } // namespace Mantid
diff --git a/Framework/Algorithms/src/MonitorEfficiencyCorUser.cpp b/Framework/Algorithms/src/MonitorEfficiencyCorUser.cpp
index bb91bd7c334fb828df65f1eb2db31b6694ec0ffc..69061e7f696d6b01d083ac219968cc5db68482e3 100644
--- a/Framework/Algorithms/src/MonitorEfficiencyCorUser.cpp
+++ b/Framework/Algorithms/src/MonitorEfficiencyCorUser.cpp
@@ -7,6 +7,7 @@
 #include "MantidGeometry/Instrument.h"
 #include "MantidGeometry/muParser_Silent.h"
 #include "MantidKernel/MultiThreaded.h"
+#include "MantidKernel/Strings.h"
 
 using Mantid::HistogramData::HistogramX;
 using Mantid::HistogramData::HistogramY;
diff --git a/Framework/Algorithms/src/MonteCarloAbsorption.cpp b/Framework/Algorithms/src/MonteCarloAbsorption.cpp
index adc508219c54c0e6b8459f16656062e0ebb4962b..31fc5327685cf26a3b09c35226c9a1618e693982 100644
--- a/Framework/Algorithms/src/MonteCarloAbsorption.cpp
+++ b/Framework/Algorithms/src/MonteCarloAbsorption.cpp
@@ -1,10 +1,9 @@
-//------------------------------------------------------------------------------
-// Includes
-//------------------------------------------------------------------------------
 #include "MantidAlgorithms/MonteCarloAbsorption.h"
+#include "MantidAlgorithms/InterpolationOption.h"
 #include "MantidAPI/ExperimentInfo.h"
 #include "MantidAPI/InstrumentValidator.h"
 #include "MantidAPI/Sample.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidAPI/WorkspaceProperty.h"
 #include "MantidAPI/WorkspaceUnitValidator.h"
@@ -53,11 +52,11 @@ struct EFixedProvider {
     }
   }
   inline DeltaEMode::Type emode() const { return m_emode; }
-  inline double value(const IDetector_const_sptr &det) const {
+  inline double value(const Mantid::detid_t detID) const {
     if (m_emode != DeltaEMode::Indirect)
       return m_value;
     else
-      return m_expt.getEFixed(det);
+      return m_expt.getEFixed(detID);
   }
 
 private:
@@ -103,6 +102,9 @@ void MonteCarloAbsorption::init() {
       "The number of \"neutron\" events to generate per simulated point");
   declareProperty("SeedValue", DEFAULT_SEED, positiveInt,
                   "Seed the random number generator with this value");
+
+  InterpolationOption interpolateOpt;
+  declareProperty(interpolateOpt.property(), interpolateOpt.propertyDoc());
 }
 
 /**
@@ -113,9 +115,11 @@ void MonteCarloAbsorption::exec() {
   const int nevents = getProperty("EventsPerPoint");
   const int nlambda = getProperty("NumberOfWavelengthPoints");
   const int seed = getProperty("SeedValue");
+  InterpolationOption interpolateOpt;
+  interpolateOpt.set(getPropertyValue("Interpolation"));
 
-  auto outputWS =
-      doSimulation(*inputWS, static_cast<size_t>(nevents), nlambda, seed);
+  auto outputWS = doSimulation(*inputWS, static_cast<size_t>(nevents), nlambda,
+                               seed, interpolateOpt);
 
   setProperty("OutputWorkspace", outputWS);
 }
@@ -127,11 +131,13 @@ void MonteCarloAbsorption::exec() {
  * @param nlambda Number of wavelength points to simulate. The remainder
  * are computed using interpolation
  * @param seed Seed value for the random number generator
+ * @param interpolateOpt Method of interpolation to compute unsimulated points
  * @return A new workspace containing the correction factors & errors
  */
 MatrixWorkspace_sptr
 MonteCarloAbsorption::doSimulation(const MatrixWorkspace &inputWS,
-                                   size_t nevents, int nlambda, int seed) {
+                                   size_t nevents, int nlambda, int seed,
+                                   const InterpolationOption &interpolateOpt) {
   auto outputWS = createOutputWorkspace(inputWS);
   // Cache information about the workspace that will be used repeatedly
   auto instrument = inputWS.getInstrument();
@@ -158,6 +164,8 @@ MonteCarloAbsorption::doSimulation(const MatrixWorkspace &inputWS,
   // Configure strategy
   MCAbsorptionStrategy strategy(*beamProfile, inputWS.sample(), nevents);
 
+  const auto &spectrumInfo = outputWS->spectrumInfo();
+
   PARALLEL_FOR_IF(Kernel::threadSafe(*outputWS))
   for (int64_t i = 0; i < nhists; ++i) {
     PARALLEL_START_INTERUPT_REGION
@@ -166,15 +174,13 @@ MonteCarloAbsorption::doSimulation(const MatrixWorkspace &inputWS,
     // The input was cloned so clear the errors out
     outE = 0.0;
     // Final detector position
-    IDetector_const_sptr detector;
-    try {
-      detector = outputWS->getDetector(i);
-    } catch (Kernel::Exception::NotFoundError &) {
+    if (!spectrumInfo.hasDetectors(i)) {
       continue;
     }
     // Per spectrum values
-    const auto &detPos = detector->getPos();
-    const double lambdaFixed = toWavelength(efixed.value(detector));
+    const auto &detPos = spectrumInfo.position(i);
+    const double lambdaFixed =
+        toWavelength(efixed.value(spectrumInfo.detector(i).getID()));
     MersenneTwister rng(seed);
 
     auto &outY = outputWS->mutableY(i);
@@ -203,7 +209,7 @@ MonteCarloAbsorption::doSimulation(const MatrixWorkspace &inputWS,
     // Interpolate through points not simulated
     if (lambdaStepSize > 1) {
       auto histnew = outputWS->histogram(i);
-      interpolateLinearInplace(histnew, lambdaStepSize);
+      interpolateOpt.applyInplace(histnew, lambdaStepSize);
       outputWS->setHistogram(i, histnew);
     }
 
diff --git a/Framework/Algorithms/src/Multiply.cpp b/Framework/Algorithms/src/Multiply.cpp
index f56dbf54dcd358f88ebd73545a1b8f479b5454fe..c3761ed2ea063168127b392cfe1f4686b40b2dde 100644
--- a/Framework/Algorithms/src/Multiply.cpp
+++ b/Framework/Algorithms/src/Multiply.cpp
@@ -187,7 +187,7 @@ std::string Multiply::checkSizeCompatibility(
     if (m_matchXSize) {
       // Past this point, for a 2D WS operation, we require the X arrays to
       // match. Note this only checks the first spectrum
-      if (!WorkspaceHelpers::matchingBins(lhs, rhs, true)) {
+      if (!WorkspaceHelpers::matchingBins(*lhs, *rhs, true)) {
         return "X arrays must match when multiplying 2D workspaces.";
       }
     }
diff --git a/Framework/Algorithms/src/NormaliseByCurrent.cpp b/Framework/Algorithms/src/NormaliseByCurrent.cpp
index 0265cc8de657d3a3cc5268b773717aa5e19ac9ec..628a78f0d648507faf4f82e8da4cb1815d3f673e 100644
--- a/Framework/Algorithms/src/NormaliseByCurrent.cpp
+++ b/Framework/Algorithms/src/NormaliseByCurrent.cpp
@@ -4,6 +4,8 @@
 #include "MantidKernel/ArrayProperty.h"
 #include "MantidKernel/LogFilter.h"
 
+#include <boost/lexical_cast.hpp>
+
 namespace Mantid {
 namespace Algorithms {
 
@@ -42,7 +44,7 @@ double NormaliseByCurrent::extractCharge(
   int nPeriods = 0;
   try {
     Property *nPeriodsProperty = run.getLogData("nperiods");
-    Kernel::toValue<int>(nPeriodsProperty->value(), nPeriods);
+    nPeriods = boost::lexical_cast<int>(nPeriodsProperty->value());
   } catch (Exception::NotFoundError &) {
     g_log.information() << "No nperiods property. If this is multi-period "
                            "data, then you will be normalising against the "
@@ -50,7 +52,6 @@ double NormaliseByCurrent::extractCharge(
   }
   // Handle multiperiod data.
   // The number of periods is set above by reference
-  // cppcheck-suppress knownConditionTrueFalse
   if (nPeriods > 1) {
     // Fetch the period property
     Property *currentPeriodNumberProperty = run.getLogData("current_period");
diff --git a/Framework/Algorithms/src/NormaliseToMonitor.cpp b/Framework/Algorithms/src/NormaliseToMonitor.cpp
index ae2de78e20288514ed56459af74630a9c5c192e2..9714ada76e5faf5b87b98e91ec27c0eb64096ff1 100644
--- a/Framework/Algorithms/src/NormaliseToMonitor.cpp
+++ b/Framework/Algorithms/src/NormaliseToMonitor.cpp
@@ -328,7 +328,7 @@ void NormaliseToMonitor::checkProperties(
   }
 
   // Do a check for common binning and store
-  m_commonBins = API::WorkspaceHelpers::commonBoundaries(inputWorkspace);
+  m_commonBins = API::WorkspaceHelpers::commonBoundaries(*inputWorkspace);
 
   int spec_num(-1);
   // Check the monitor spectrum or workspace and extract into new workspace
@@ -434,7 +434,7 @@ API::MatrixWorkspace_sptr NormaliseToMonitor::getMonitorWorkspace(
   // In this case we need to test whether the bins in the monitor workspace
   // match
   m_commonBins = (m_commonBins && API::WorkspaceHelpers::matchingBins(
-                                      inputWorkspace, monitorWS, true));
+                                      *inputWorkspace, *monitorWS, true));
 
   // If the workspace passes all these tests, make a local copy because it will
   // get changed
@@ -649,6 +649,8 @@ void NormaliseToMonitor::normaliseBinByBin(
   if (hasZeroDivision) {
     g_log.warning() << "Division by zero in some of the bins.\n";
   }
+  if (inputEvent)
+    outputEvent->clearMRU();
 }
 
 /** Calculates the overall normalization factor.
diff --git a/Framework/Algorithms/src/PDCalibration.cpp b/Framework/Algorithms/src/PDCalibration.cpp
index add9a37abc27229595f6933dcc463847bdd50b6a..22c16709e077d05d02039bc6c638d025c3af4a48 100644
--- a/Framework/Algorithms/src/PDCalibration.cpp
+++ b/Framework/Algorithms/src/PDCalibration.cpp
@@ -397,7 +397,7 @@ void PDCalibration::exec() {
       tof_vec.push_back(centre);
     }
 
-    if (d_vec.size() == 0) {
+    if (d_vec.empty()) {
       maskWS->setMaskedIndex(wkspIndex, true);
       continue;
     } else {
diff --git a/Framework/Algorithms/src/PDDetermineCharacterizations.cpp b/Framework/Algorithms/src/PDDetermineCharacterizations.cpp
index 136d8de60b2ff7ca8a29a53f7c00b185b88bdaf8..82864cfa1812978a46e56679c97d1d89d055729e 100644
--- a/Framework/Algorithms/src/PDDetermineCharacterizations.cpp
+++ b/Framework/Algorithms/src/PDDetermineCharacterizations.cpp
@@ -1,9 +1,10 @@
 #include "MantidAlgorithms/PDDetermineCharacterizations.h"
+#include "MantidAPI/ITableWorkspace.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/Run.h"
-#include "MantidKernel/PropertyManagerDataService.h"
-#include "MantidAPI/ITableWorkspace.h"
 #include "MantidKernel/ArrayProperty.h"
+#include "MantidKernel/PropertyManagerDataService.h"
+#include "MantidKernel/Strings.h"
 #include "MantidKernel/TimeSeriesProperty.h"
 
 namespace Mantid {
@@ -47,20 +48,25 @@ const std::string PDDetermineCharacterizations::summary() const {
 /**
  * These should match those in LoadPDCharacterizations
  * - "frequency" double
- * -  "wavelength" (double)
- * -  "bank" (integer)
- * -  "container" (string)
- * -  "vanadium" (string)
- * -  "empty" (string)
- * -  "d_min" (string)
- * -  "d_max" (string)
- * -  "tof_min" (double)
- * -  "tof_max" (double)
+ * - "wavelength" (double)
+ * - "bank" (integer)
+ * - "container" (string)
+ * - "vanadium" (string)
+ * - "vanadium_background" (string)
+ * - "empty" (string)
+ * - "d_min" (string)
+ * - "d_max" (string)
+ * - "tof_min" (double)
+ * - "tof_max" (double)
+ * - "wavelength_min" (double)
+ * - "wavelength_max" (double)
  * @return The list of expected column names
  */
 std::vector<std::string> getColumnNames() {
-  return {"frequency", "wavelength", "bank",  "container", "vanadium",
-          "empty",     "d_min",      "d_max", "tof_min",   "tof_max"};
+  return {"frequency", "wavelength", "bank", "container", "vanadium",
+          "vanadium_background", "empty_environment", "empty_instrument",
+          "d_min", "d_max", "tof_min", "tof_max", "wavelength_min",
+          "wavelength_max"};
 }
 
 /// More intesive input checking. @see Algorithm::validateInputs
@@ -120,6 +126,12 @@ void PDDetermineCharacterizations::init() {
   declareProperty(
       Kernel::make_unique<Kernel::ArrayProperty<int32_t>>("NormBackRun", "0"),
       "Normalization background" + defaultMsg);
+  declareProperty(
+      Kernel::make_unique<Kernel::ArrayProperty<int32_t>>("EmptyEnv", "0"),
+      "Empty sample environment" + defaultMsg);
+  declareProperty(
+      Kernel::make_unique<Kernel::ArrayProperty<int32_t>>("EmptyInstr", "0"),
+      "Empty instrument" + defaultMsg);
 
   std::vector<std::string> defaultFrequencyNames{"SpeedRequest1", "Speed1",
                                                  "frequency"};
@@ -152,7 +164,8 @@ bool closeEnough(const double left, const double right) {
 
 /// Fill in the property manager from the correct line in the table
 void PDDetermineCharacterizations::getInformationFromTable(
-    const double frequency, const double wavelength) {
+    const double frequency, const double wavelength,
+    const std::string &canName) {
   size_t numRows = m_characterizations->rowCount();
 
   for (size_t i = 0; i < numRows; ++i) {
@@ -163,33 +176,67 @@ void PDDetermineCharacterizations::getInformationFromTable(
 
     if (closeEnough(frequency, rowFrequency) &&
         closeEnough(wavelength, rowWavelength)) {
+
+      // declare how the row was chosen
       g_log.information() << "Using information from row " << i
                           << " with frequency = " << rowFrequency
                           << " and wavelength = " << rowWavelength << "\n";
-
       m_propertyManager->setProperty("frequency", frequency);
       m_propertyManager->setProperty("wavelength", wavelength);
 
+      // what bank number this should be called - only used at POWGEN
       m_propertyManager->setProperty(
           "bank", m_characterizations->getRef<int>("bank", i));
 
-      m_propertyManager->setProperty(
-          "vanadium", m_characterizations->getRef<std::string>("vanadium", i));
-      m_propertyManager->setProperty(
-          "container",
-          m_characterizations->getRef<std::string>("container", i));
-      m_propertyManager->setProperty(
-          "empty", m_characterizations->getRef<std::string>("empty", i));
-
+      // data ranges
       m_propertyManager->setPropertyValue(
           "d_min", m_characterizations->getRef<std::string>("d_min", i));
       m_propertyManager->setPropertyValue(
           "d_max", m_characterizations->getRef<std::string>("d_max", i));
-
       m_propertyManager->setProperty(
           "tof_min", m_characterizations->getRef<double>("tof_min", i));
       m_propertyManager->setProperty(
           "tof_max", m_characterizations->getRef<double>("tof_max", i));
+      m_propertyManager->setProperty(
+          "wavelength_min",
+          m_characterizations->getRef<double>("wavelength_min", i));
+      m_propertyManager->setProperty(
+          "wavelength_max",
+          m_characterizations->getRef<double>("wavelength_max", i));
+
+      // characterization run numbers
+      m_propertyManager->setProperty(
+          "vanadium", m_characterizations->getRef<std::string>("vanadium", i));
+      m_propertyManager->setProperty(
+          "vanadium_background",
+          m_characterizations->getRef<std::string>("vanadium_background", i));
+      m_propertyManager->setProperty(
+          "container",
+          m_characterizations->getRef<std::string>("container", i));
+      m_propertyManager->setProperty(
+          "empty_environment",
+          m_characterizations->getRef<std::string>("empty_environment", i));
+      m_propertyManager->setProperty(
+          "empty_instrument",
+          m_characterizations->getRef<std::string>("empty_instrument", i));
+
+      // something special if the container was specified
+      if (!canName.empty()) {
+        const auto columnNames = m_characterizations->getColumnNames();
+        if (std::find(columnNames.begin(), columnNames.end(), canName) ==
+            columnNames.end()) {
+          g_log.warning() << "Failed to find container name \"" << canName
+                          << "\" in characterizations table \""
+                          << m_characterizations->getName() << "\"\n";
+        } else {
+          const auto canRuns =
+              m_characterizations->getRef<std::string>(canName, i);
+          g_log.information() << "Updating container identifier to \""
+                              << canRuns << "\"\n";
+          m_propertyManager->setProperty("container", canRuns);
+        }
+      }
+
       return;
     }
   }
@@ -257,22 +304,12 @@ void PDDetermineCharacterizations::setDefaultsInPropManager() {
     m_propertyManager->declareProperty(
         Kernel::make_unique<PropertyWithValue<double>>("wavelength", 0.));
   }
+
   if (!m_propertyManager->existsProperty("bank")) {
     m_propertyManager->declareProperty(
         Kernel::make_unique<PropertyWithValue<int>>("bank", 1));
   }
-  if (!m_propertyManager->existsProperty("vanadium")) {
-    m_propertyManager->declareProperty(
-        Kernel::make_unique<ArrayProperty<int32_t>>("vanadium", "0"));
-  }
-  if (!m_propertyManager->existsProperty("container")) {
-    m_propertyManager->declareProperty(
-        Kernel::make_unique<ArrayProperty<int32_t>>("container", "0"));
-  }
-  if (!m_propertyManager->existsProperty("empty")) {
-    m_propertyManager->declareProperty(
-        Kernel::make_unique<ArrayProperty<int32_t>>("empty", "0"));
-  }
+
   if (!m_propertyManager->existsProperty("d_min")) {
     m_propertyManager->declareProperty(
         Kernel::make_unique<ArrayProperty<double>>("d_min"));
@@ -289,6 +326,36 @@ void PDDetermineCharacterizations::setDefaultsInPropManager() {
     m_propertyManager->declareProperty(
         Kernel::make_unique<PropertyWithValue<double>>("tof_max", 0.));
   }
+  if (!m_propertyManager->existsProperty("wavelength_min")) {
+    m_propertyManager->declareProperty(
+        Kernel::make_unique<PropertyWithValue<double>>("wavelength_min", 0.));
+  }
+  if (!m_propertyManager->existsProperty("wavelength_max")) {
+    m_propertyManager->declareProperty(
+        Kernel::make_unique<PropertyWithValue<double>>("wavelength_max", 0.));
+  }
+
+  if (!m_propertyManager->existsProperty("vanadium")) {
+    m_propertyManager->declareProperty(
+        Kernel::make_unique<ArrayProperty<int32_t>>("vanadium", "0"));
+  }
+  if (!m_propertyManager->existsProperty("vanadium_background")) {
+    m_propertyManager->declareProperty(
+        Kernel::make_unique<ArrayProperty<int32_t>>("vanadium_background",
+                                                    "0"));
+  }
+  if (!m_propertyManager->existsProperty("container")) {
+    m_propertyManager->declareProperty(
+        Kernel::make_unique<ArrayProperty<int32_t>>("container", "0"));
+  }
+  if (!m_propertyManager->existsProperty("empty_environment")) {
+    m_propertyManager->declareProperty(
+        Kernel::make_unique<ArrayProperty<int32_t>>("empty_environment", "0"));
+  }
+  if (!m_propertyManager->existsProperty("empty_instrument")) {
+    m_propertyManager->declareProperty(
+        Kernel::make_unique<ArrayProperty<int32_t>>("empty_instrument", "0"));
+  }
 }
 
 /**
@@ -335,12 +402,34 @@ void PDDetermineCharacterizations::exec() {
 
     double wavelength = getLogValue(run, WL_PROP_NAME);
 
-    getInformationFromTable(frequency, wavelength);
+    // determine the container name
+    std::string container;
+    if (run.hasProperty("SampleContainer")) {
+      const auto containerProp = run.getLogData("SampleContainer");
+
+      // the property is normally a TimeSeriesProperty
+      const auto containerPropSeries =
+          dynamic_cast<TimeSeriesProperty<std::string> *>(containerProp);
+      if (containerPropSeries) {
+        // assume that only the first value matters
+        container = containerPropSeries->valuesAsVector().front();
+      } else {
+        // try as a normal Property
+        container = containerProp->value();
+      }
+
+      // remove whitespace from the value
+      container = Kernel::Strings::replaceAll(container, " ", "");
+    }
+
+    getInformationFromTable(frequency, wavelength, container);
   }
 
   overrideRunNumProperty("BackRun", "container");
   overrideRunNumProperty("NormRun", "vanadium");
-  overrideRunNumProperty("NormBackRun", "empty");
+  overrideRunNumProperty("NormBackRun", "vanadium_background");
+  overrideRunNumProperty("EmptyEnv", "empty_environment");
+  overrideRunNumProperty("EmptyInstr", "empty_instrument");
 
   std::vector<std::string> expectedNames = getColumnNames();
   for (auto &expectedName : expectedNames) {
diff --git a/Framework/Algorithms/src/Pause.cpp b/Framework/Algorithms/src/Pause.cpp
index 0ce83c15cc6c594ef49c56cc2f442e9e81b5ff67..9eed799b21f036851e216ea5e2f04666f0cb9ec4 100644
--- a/Framework/Algorithms/src/Pause.cpp
+++ b/Framework/Algorithms/src/Pause.cpp
@@ -1,5 +1,6 @@
 #include "MantidAlgorithms/Pause.h"
 #include "MantidAPI/Algorithm.h"
+#include "MantidKernel/DateAndTime.h"
 
 #include <Poco/Thread.h>
 
@@ -12,7 +13,6 @@ namespace Algorithms {
 // Register the algorithm into the AlgorithmFactory
 DECLARE_ALGORITHM(Pause)
 
-//----------------------------------------------------------------------------------------------
 /// Algorithm's name for identification. @see Algorithm::name
 const std::string Pause::name() const { return "Pause"; }
 
@@ -22,9 +22,6 @@ int Pause::version() const { return 1; }
 /// Algorithm's category for identification. @see Algorithm::category
 const std::string Pause::category() const { return "Utility\\Development"; }
 
-//----------------------------------------------------------------------------------------------
-
-//----------------------------------------------------------------------------------------------
 /** Initialize the algorithm's properties.
  */
 void Pause::init() {
@@ -33,7 +30,6 @@ void Pause::init() {
                   "Enter a negative number to pause forever until cancelled.");
 }
 
-//----------------------------------------------------------------------------------------------
 /** Execute the algorithm.
  */
 void Pause::exec() {
diff --git a/Framework/Algorithms/src/PlotAsymmetryByLogValue.cpp b/Framework/Algorithms/src/PlotAsymmetryByLogValue.cpp
index ae77d31cf88053bb4d0c2a9ef4849f7e0948c7f0..e7a106c02f1fefa737fd50f98ddf405247b0b377 100644
--- a/Framework/Algorithms/src/PlotAsymmetryByLogValue.cpp
+++ b/Framework/Algorithms/src/PlotAsymmetryByLogValue.cpp
@@ -18,6 +18,7 @@
 #include "MantidKernel/TimeSeriesProperty.h"
 #include "Poco/File.h"
 #include <MantidAPI/FileFinder.h>
+#include "MantidAPI/WorkspaceGroup.h"
 
 namespace // anonymous
     {
diff --git a/Framework/Algorithms/src/PointByPointVCorrection.cpp b/Framework/Algorithms/src/PointByPointVCorrection.cpp
index 1d6a66d359755229cf7591997dbefecb35ccd3c1..f82b31f612af611391da1d080e3517cf4eb9ce54 100644
--- a/Framework/Algorithms/src/PointByPointVCorrection.cpp
+++ b/Framework/Algorithms/src/PointByPointVCorrection.cpp
@@ -159,7 +159,7 @@ void PointByPointVCorrection::check_validity(
     throw std::runtime_error("The input workspaces are not the same size");
   }
   // Now check that the bins match
-  if (!WorkspaceHelpers::matchingBins(w1, w2)) {
+  if (!WorkspaceHelpers::matchingBins(*w1, *w2)) {
     g_log.error("The input workspaces have different binning");
     throw std::runtime_error("The input workspaces have different binning");
   }
diff --git a/Framework/Algorithms/src/PolarizationCorrection.cpp b/Framework/Algorithms/src/PolarizationCorrection.cpp
index c7a88b8320e57aea23a6ea3f4bb28d032f9ad478..d3f4983a28dda537a8e7659fc3320d01f9db9164 100644
--- a/Framework/Algorithms/src/PolarizationCorrection.cpp
+++ b/Framework/Algorithms/src/PolarizationCorrection.cpp
@@ -2,6 +2,7 @@
 #include "MantidAPI/Axis.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidAPI/WorkspaceGroup.h"
+#include "MantidAPI/WorkspaceHistory.h"
 #include "MantidDataObjects/WorkspaceSingleValue.h"
 #include "MantidKernel/ArrayProperty.h"
 #include "MantidKernel/ListValidator.h"
diff --git a/Framework/Algorithms/src/Q1D2.cpp b/Framework/Algorithms/src/Q1D2.cpp
index 7433e9993bfcd2e53a5b526f2810ab42a639d5c7..1181c1779028dfc9f23241205be853377be9ec72 100644
--- a/Framework/Algorithms/src/Q1D2.cpp
+++ b/Framework/Algorithms/src/Q1D2.cpp
@@ -3,6 +3,7 @@
 #include "MantidAlgorithms/Qhelper.h"
 #include "MantidAPI/Axis.h"
 #include "MantidAPI/CommonBinsValidator.h"
+#include "MantidAPI/DetectorInfo.h"
 #include "MantidAPI/HistogramValidator.h"
 #include "MantidAPI/InstrumentValidator.h"
 #include "MantidAPI/ISpectrum.h"
@@ -161,8 +162,9 @@ void Q1D2::exec() {
     // get the bins that are included inside the RadiusCut/WaveCutcut off, those
     // to calculate for
     // const size_t wavStart = waveLengthCutOff(i);
-    const size_t wavStart = helper.waveLengthCutOff(
-        m_dataWS, getProperty("RadiusCut"), getProperty("WaveCut"), i);
+    const size_t wavStart = helper.waveLengthCutOff(m_dataWS, spectrumInfo,
+                                                    getProperty("RadiusCut"),
+                                                    getProperty("WaveCut"), i);
     if (wavStart >= m_dataWS->y(i).size()) {
       // all the spectra in this detector are out of range
       continue;
@@ -382,11 +384,17 @@ void Q1D2::calculateNormalization(
 void Q1D2::pixelWeight(API::MatrixWorkspace_const_sptr pixelAdj,
                        const size_t wsIndex, double &weight,
                        double &error) const {
-  const V3D samplePos = m_dataWS->getInstrument()->getSample()->getPos();
-
-  if (m_doSolidAngle)
-    weight = m_dataWS->getDetector(wsIndex)->solidAngle(samplePos);
-  else
+  const auto &detectorInfo = m_dataWS->detectorInfo();
+  const V3D samplePos = detectorInfo.samplePosition();
+
+  if (m_doSolidAngle) {
+    weight = 0.0;
+    for (const auto detID : m_dataWS->getSpectrum(wsIndex).getDetectorIDs()) {
+      const auto index = detectorInfo.indexOf(detID);
+      if (!detectorInfo.isMasked(index))
+        weight += detectorInfo.detector(index).solidAngle(samplePos);
+    }
+  } else
     weight = 1.0;
 
   if (weight < 1e-200) {
diff --git a/Framework/Algorithms/src/Q1DWeighted.cpp b/Framework/Algorithms/src/Q1DWeighted.cpp
index aeb3ac3fdc18b2477d696af6ef6d1dc15877bf79..36fc5177d2c2f4530407f4927210575af9e9b409 100644
--- a/Framework/Algorithms/src/Q1DWeighted.cpp
+++ b/Framework/Algorithms/src/Q1DWeighted.cpp
@@ -5,6 +5,7 @@
 #include "MantidAPI/Run.h"
 #include "MantidAPI/SpectrumInfo.h"
 #include "MantidAPI/WorkspaceFactory.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidAPI/WorkspaceUnitValidator.h"
 #include "MantidDataObjects/Histogram1D.h"
 #include "MantidGeometry/Instrument.h"
@@ -16,6 +17,8 @@
 #include "MantidKernel/UnitFactory.h"
 #include "MantidKernel/VectorHelper.h"
 
+constexpr double deg2rad = M_PI / 180.0;
+
 namespace Mantid {
 namespace Algorithms {
 
@@ -332,7 +335,7 @@ void Q1DWeighted::exec() {
   }
   // set the output property
   std::string outputWSGroupName = getPropertyValue("WedgeWorkspace");
-  if (outputWSGroupName.size() == 0) {
+  if (outputWSGroupName.empty()) {
     std::string outputWSName = getPropertyValue("OutputWorkspace");
     outputWSGroupName = outputWSName + "_wedges";
     setPropertyValue("WedgeWorkspace", outputWSGroupName);
diff --git a/Framework/Algorithms/src/Qhelper.cpp b/Framework/Algorithms/src/Qhelper.cpp
index ad35cb9231470d2727518528fa354ae6aa767152..4cd98900e3e0c3fac9e3528285d73acc54fefeff 100644
--- a/Framework/Algorithms/src/Qhelper.cpp
+++ b/Framework/Algorithms/src/Qhelper.cpp
@@ -139,6 +139,7 @@ void Qhelper::examineInput(API::MatrixWorkspace_const_sptr dataWS,
 * included based on the
 *  the calculation: W = Wcut (Rcut-R)/Rcut
 *  @param dataWS data workspace
+ * @param spectrumInfo the spectrumInfo associated with the data workspace
 *  @param RCut the radius cut off, should be value of the property RadiusCut
 * (unit is mm)
 *  @param WCut this wavelength cut off, should be equal to the value WaveCut
@@ -146,6 +147,7 @@ void Qhelper::examineInput(API::MatrixWorkspace_const_sptr dataWS,
 *  @return index number of the first bin to include in the calculation
 */
 size_t Qhelper::waveLengthCutOff(API::MatrixWorkspace_const_sptr dataWS,
+                                 const SpectrumInfo &spectrumInfo,
                                  const double RCut, const double WCut,
                                  const size_t wsInd) const {
   double l_WCutOver = 0.0;
@@ -161,7 +163,7 @@ size_t Qhelper::waveLengthCutOff(API::MatrixWorkspace_const_sptr dataWS,
   }
   // get the distance of between this detector and the origin, which should be
   // the along the beam center
-  const V3D posOnBank = dataWS->getDetector(wsInd)->getPos();
+  const V3D posOnBank = spectrumInfo.position(wsInd);
   double R = (posOnBank.X() * posOnBank.X()) + (posOnBank.Y() * posOnBank.Y());
   R = std::sqrt(R);
 
diff --git a/Framework/Algorithms/src/Qxy.cpp b/Framework/Algorithms/src/Qxy.cpp
index 42d8cc3181becfd31991e61c044d7c0fbd8caa71..741e8294bf35b01e746678faee6529119f981ea9 100644
--- a/Framework/Algorithms/src/Qxy.cpp
+++ b/Framework/Algorithms/src/Qxy.cpp
@@ -1,5 +1,6 @@
 #include "MantidAlgorithms/Qxy.h"
 #include "MantidAPI/BinEdgeAxis.h"
+#include "MantidAPI/DetectorInfo.h"
 #include "MantidAPI/HistogramValidator.h"
 #include "MantidAPI/InstrumentValidator.h"
 #include "MantidAPI/SpectrumInfo.h"
@@ -121,6 +122,7 @@ void Qxy::exec() {
   Progress prog(this, 0.05, 1.0, numSpec);
 
   const auto &spectrumInfo = inputWorkspace->spectrumInfo();
+  const auto &detectorInfo = inputWorkspace->detectorInfo();
 
   // the samplePos is often not (0, 0, 0) because the instruments components are
   // moved to account for the beam centre
@@ -140,7 +142,8 @@ void Qxy::exec() {
     // get the bins that are included inside the RadiusCut/WaveCutcut off, those
     // to calculate for
     const size_t wavStart = helper.waveLengthCutOff(
-        inputWorkspace, getProperty("RadiusCut"), getProperty("WaveCut"), i);
+        inputWorkspace, spectrumInfo, getProperty("RadiusCut"),
+        getProperty("WaveCut"), i);
     if (wavStart >= inputWorkspace->y(i).size()) {
       // all the spectra in this detector are out of range
       continue;
@@ -164,7 +167,12 @@ void Qxy::exec() {
 
     // the solid angle of the detector as seen by the sample is used for
     // normalisation later on
-    double angle = spectrumInfo.detector(i).solidAngle(samplePos);
+    double angle = 0.0;
+    for (const auto detID : inputWorkspace->getSpectrum(i).getDetectorIDs()) {
+      const auto index = detectorInfo.indexOf(detID);
+      if (!detectorInfo.isMasked(index))
+        angle += detectorInfo.detector(index).solidAngle(samplePos);
+    }
 
     // some bins are masked completely or partially, the following vector will
     // contain the fractions
@@ -362,10 +370,8 @@ Qxy::setUpOutputWorkspace(API::MatrixWorkspace_const_sptr inputWorkspace) {
   MatrixWorkspace_sptr outputWorkspace = WorkspaceFactory::Instance().create(
       inputWorkspace, bins - 1, bins, bins - 1);
   // ... but clear the masking from the parameter map as we don't want to carry
-  // that over since this is essentially
-  // a 2D rebin
-  ParameterMap &pmap = outputWorkspace->instrumentParameters();
-  pmap.clearParametersByName("masked");
+  // that over since this is essentially a 2D rebin
+  outputWorkspace->mutableDetectorInfo().clearMaskFlags();
 
   // Create a numeric axis to replace the vertical one
   Axis *verticalAxis = new BinEdgeAxis(bins);
diff --git a/Framework/Algorithms/src/RRFMuon.cpp b/Framework/Algorithms/src/RRFMuon.cpp
index b206495e068f516c40777813331376370eb2614c..35eb7b6dcf36ef7fee7bbdbcd23c91ca2f3aada7 100644
--- a/Framework/Algorithms/src/RRFMuon.cpp
+++ b/Framework/Algorithms/src/RRFMuon.cpp
@@ -89,11 +89,9 @@ void RRFMuon::exec() {
 
   // Put results into output workspace
   // Real RRF polarization
-  outputWs->getSpectrum(0).setSpectrumNo(1);
   outputWs->setSharedX(0, inputWs->sharedX(0));
   outputWs->mutableY(0) = rrfRe;
   // Imaginary RRF polarization
-  outputWs->getSpectrum(1).setSpectrumNo(2);
   outputWs->setSharedX(1, inputWs->sharedX(1));
   outputWs->mutableY(1) = rrfIm;
 
diff --git a/Framework/Algorithms/src/RadiusSum.cpp b/Framework/Algorithms/src/RadiusSum.cpp
index 8bdd59379ecce72d43b1e929cbbcd61d968c046f..35423da6be78c9e364db29813167feca5f88d288 100644
--- a/Framework/Algorithms/src/RadiusSum.cpp
+++ b/Framework/Algorithms/src/RadiusSum.cpp
@@ -5,6 +5,7 @@
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidGeometry/IDetector.h"
 #include "MantidGeometry/IObjComponent.h"
+#include "MantidGeometry/Objects/BoundingBox.h"
 #include "MantidKernel/ArrayLengthValidator.h"
 #include "MantidKernel/ArrayProperty.h"
 #include "MantidKernel/BoundedValidator.h"
@@ -16,6 +17,7 @@
 
 #include <boost/foreach.hpp>
 
+#include <array>
 #include <cmath>
 #include <limits>
 #include <numeric>
@@ -515,30 +517,16 @@ double RadiusSum::getMinBinSizeForInstrument(API::MatrixWorkspace_sptr inWS) {
   // minimum
   // reasonalbe size for the bin is the width of one detector.
 
-  double width;
-  size_t i = 0;
-  while (true) {
-    i++;
-
-    // this should never happen because it was done in
-    // getBoundariesOfInstrument,
-    // but it is here to avoid risk of infiniti loop
-    if (i >= inWS->getNumberHistograms())
-      throw std::invalid_argument(
-          "Did not find any non monitor detector position");
-
-    auto det = inWS->getDetector(i);
-    if (det->isMonitor())
+  const auto &spectrumInfo = inWS->spectrumInfo();
+  for (size_t i = 0; i < inWS->getNumberHistograms(); ++i) {
+    if (spectrumInfo.isMonitor(i))
       continue;
-
     Geometry::BoundingBox bbox;
-    det->getBoundingBox(bbox);
-
-    width = bbox.width().norm();
-    break;
+    spectrumInfo.detector(i).getBoundingBox(bbox);
+    return bbox.width().norm();
   }
-
-  return width;
+  // this should never happen because it was done in getBoundariesOfInstrument,
+  throw std::invalid_argument("Did not find any non monitor detector position");
 }
 
 double RadiusSum::getMinBinSizeForNumericImage(API::MatrixWorkspace_sptr inWS) {
diff --git a/Framework/Algorithms/src/ReadGroupsFromFile.cpp b/Framework/Algorithms/src/ReadGroupsFromFile.cpp
index 07880d99ef21d9275996322dbd90c1313005a054..d28782fcd1c1b8ff90921c59f22562fc0f9fbffc 100644
--- a/Framework/Algorithms/src/ReadGroupsFromFile.cpp
+++ b/Framework/Algorithms/src/ReadGroupsFromFile.cpp
@@ -1,6 +1,3 @@
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidAlgorithms/ReadGroupsFromFile.h"
 #include "MantidAPI/FileProperty.h"
 #include "MantidAPI/InstrumentDataService.h"
@@ -10,6 +7,7 @@
 #include "MantidAPI/WorkspaceProperty.h"
 #include "MantidDataObjects/Workspace2D.h"
 #include "MantidKernel/ListValidator.h"
+#include "MantidKernel/StringTokenizer.h"
 
 // Poco XML Headers for Grouping File
 #include <Poco/DOM/DOMParser.h>
diff --git a/Framework/Algorithms/src/Rebin.cpp b/Framework/Algorithms/src/Rebin.cpp
index b7729e557e175382029736f6cf3648e65c2e97db..62a87396a4b8aa1d3a73c66eb32bad11af3705d2 100644
--- a/Framework/Algorithms/src/Rebin.cpp
+++ b/Framework/Algorithms/src/Rebin.cpp
@@ -1,12 +1,13 @@
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidAlgorithms/Rebin.h"
+#include "MantidHistogramData/Exception.h"
+#include "MantidHistogramData/Rebin.h"
 
 #include "MantidAPI/Axis.h"
-#include "MantidAPI/WorkspaceFactory.h"
-#include "MantidDataObjects/EventWorkspace.h"
+#include "MantidAPI/HistoWorkspace.h"
+#include "MantidDataObjects/Workspace2D.h"
 #include "MantidDataObjects/EventList.h"
+#include "MantidDataObjects/EventWorkspace.h"
+#include "MantidDataObjects/WorkspaceCreation.h"
 #include "MantidKernel/ArrayProperty.h"
 #include "MantidKernel/RebinParamsValidator.h"
 #include "MantidKernel/VectorHelper.h"
@@ -19,6 +20,11 @@ DECLARE_ALGORITHM(Rebin)
 
 using namespace Kernel;
 using namespace API;
+using HistogramData::Histogram;
+using HistogramData::BinEdges;
+using HistogramData::Frequencies;
+using HistogramData::FrequencyStandardDeviations;
+using HistogramData::Exception::InvalidBinEdgesError;
 using DataObjects::EventList;
 using DataObjects::EventWorkspace;
 using DataObjects::EventWorkspace_sptr;
@@ -107,6 +113,12 @@ void Rebin::init() {
   declareProperty(
       "FullBinsOnly", false,
       "Omit the final bin if it's width is smaller than the step size");
+
+  declareProperty("IgnoreBinErrors", false,
+                  "Ignore errors related to "
+                  "zero/negative bin widths in "
+                  "input/output workspaces. When ignored, the signal and "
+                  "errors are set to zero");
 }
 
 /** Executes the rebin algorithm
@@ -134,16 +146,13 @@ void Rebin::exec() {
   // workspace independent determination of length
   const int histnumber = static_cast<int>(inputWS->getNumberHistograms());
 
-  //-------------------------------------------------------
-
   bool fullBinsOnly = getProperty("FullBinsOnly");
 
   HistogramData::BinEdges XValues_new(0);
   // create new output X axis
-  const int ntcnew = VectorHelper::createAxisFromRebinParams(
-      rbParams, XValues_new.mutableRawData(), true, fullBinsOnly);
+  static_cast<void>(VectorHelper::createAxisFromRebinParams(
+      rbParams, XValues_new.mutableRawData(), true, fullBinsOnly));
 
-  //---------------------------------------------------------------------------------
   // Now, determine if the input workspace is actually an EventWorkspace
   EventWorkspace_const_sptr eventInputWS =
       boost::dynamic_pointer_cast<const EventWorkspace>(inputWS);
@@ -162,18 +171,10 @@ void Rebin::exec() {
       eventOutputWS->setAllX(XValues_new);
     } else {
       //--------- Different output, OR you're inplace but not preserving Events
-      //--- create a Workspace2D -------
       g_log.information() << "Creating a Workspace2D from the EventWorkspace "
                           << eventInputWS->getName() << ".\n";
-
-      // Create a Workspace2D
-      // This creates a new Workspace2D through a torturous route using the
-      // WorkspaceFactory.
-      // The Workspace2D is created with an EMPTY CONSTRUCTOR
-      outputWS = WorkspaceFactory::Instance().create("Workspace2D", histnumber,
-                                                     ntcnew, ntcnew - 1);
-      WorkspaceFactory::Instance().initializeFromParent(inputWS, outputWS,
-                                                        true);
+      outputWS = DataObjects::create<DataObjects::Workspace2D>(
+          *inputWS, histnumber, XValues_new);
 
       // Initialize progress reporting.
       Progress prog(this, 0.0, 1.0, histnumber);
@@ -182,10 +183,6 @@ void Rebin::exec() {
       PARALLEL_FOR_IF(Kernel::threadSafe(*inputWS, *outputWS))
       for (int i = 0; i < histnumber; ++i) {
         PARALLEL_START_INTERUPT_REGION
-
-        // Set the X axis for each output histogram
-        outputWS->setBinEdges(i, XValues_new);
-
         // Get a const event list reference. eventInputWS->dataY() doesn't work.
         const EventList &el = eventInputWS->getSpectrum(i);
         MantidVec y_data, e_data;
@@ -193,8 +190,8 @@ void Rebin::exec() {
         el.generateHistogram(XValues_new.rawData(), y_data, e_data);
 
         // Copy the data over.
-        outputWS->dataY(i).assign(y_data.begin(), y_data.end());
-        outputWS->dataE(i).assign(e_data.begin(), e_data.end());
+        outputWS->mutableY(i) = std::move(y_data);
+        outputWS->mutableE(i) = std::move(e_data);
 
         // Report progress
         prog.report(name());
@@ -239,38 +236,28 @@ void Rebin::exec() {
 
     // make output Workspace the same type is the input, but with new length of
     // signal array
-    outputWS = API::WorkspaceFactory::Instance().create(inputWS, histnumber,
-                                                        ntcnew, ntcnew - 1);
+    outputWS = DataObjects::create<API::HistoWorkspace>(*inputWS, histnumber,
+                                                        XValues_new);
 
     // Copy over the 'vertical' axis
     if (inputWS->axes() > 1)
       outputWS->replaceAxis(1, inputWS->getAxis(1)->clone(outputWS.get()));
+    bool ignoreBinErrors = getProperty("IgnoreBinErrors");
 
     Progress prog(this, 0.0, 1.0, histnumber);
     PARALLEL_FOR_IF(Kernel::threadSafe(*inputWS, *outputWS))
     for (int hist = 0; hist < histnumber; ++hist) {
       PARALLEL_START_INTERUPT_REGION
-      // get const references to input Workspace arrays (no copying)
-      const MantidVec &XValues = inputWS->readX(hist);
-      const MantidVec &YValues = inputWS->readY(hist);
-      const MantidVec &YErrors = inputWS->readE(hist);
-
-      // get references to output workspace data (no copying)
-      MantidVec &YValues_new = outputWS->dataY(hist);
-      MantidVec &YErrors_new = outputWS->dataE(hist);
 
-      // output data arrays are implicitly filled by function
       try {
-        VectorHelper::rebin(XValues, YValues, YErrors, XValues_new.rawData(),
-                            YValues_new, YErrors_new, dist);
-      } catch (std::exception &ex) {
-        g_log.error() << "Error in rebin function: " << ex.what() << '\n';
-        throw;
+        outputWS->setHistogram(
+            hist, HistogramData::rebin(inputWS->histogram(hist), XValues_new));
+      } catch (InvalidBinEdgesError &) {
+        if (ignoreBinErrors)
+          outputWS->setBinEdges(hist, XValues_new);
+        else
+          throw;
       }
-
-      // Populate the output workspace X values
-      outputWS->setBinEdges(hist, XValues_new);
-
       prog.report(name());
       PARALLEL_END_INTERUPT_REGION
     }
@@ -307,14 +294,6 @@ void Rebin::exec() {
 
   } // END ---- Workspace2D
 }
-//
-//    /** Continue execution for EventWorkspace scenario */
-//    void Rebin::execEvent()
-//    {
-//      // retrieve the properties
-//      std::vector<double> rb_params=getProperty("Params");
-//
-//    }
 
 /** Takes the masks in the input workspace and apportions the weights into the
 *new bins that overlap
@@ -336,7 +315,7 @@ void Rebin::propagateMasks(API::MatrixWorkspace_const_sptr inputWS,
   const MatrixWorkspace::MaskList &mask = inputWS->maskedBins(hist);
   // Now iterate over the list, building up a vector of the masked bins
   auto it = mask.cbegin();
-  const MantidVec &XValues = inputWS->readX(hist);
+  auto &XValues = inputWS->x(hist);
   masked_bins.push_back(XValues[(*it).first]);
   weights.push_back((*it).second);
   masked_bins.push_back(XValues[(*it).first + 1]);
@@ -352,20 +331,27 @@ void Rebin::propagateMasks(API::MatrixWorkspace_const_sptr inputWS,
     masked_bins.push_back(XValues[(*it).first + 1]);
   }
 
-  // Create a zero vector for the errors because we don't care about them here
-  const MantidVec zeroes(weights.size(), 0.0);
-  // Create a vector to hold the redistributed weights
-  const MantidVec &XValues_new = outputWS->readX(hist);
-  MantidVec newWeights(XValues_new.size() - 1), zeroes2(XValues_new.size() - 1);
+  //// Create a zero vector for the errors because we don't care about them here
+  auto errSize = weights.size();
+  Histogram oldHist(BinEdges(std::move(masked_bins)),
+                    Frequencies(std::move(weights)),
+                    FrequencyStandardDeviations(errSize, 0));
   // Use rebin function to redistribute the weights. Note that distribution flag
   // is set
-  VectorHelper::rebin(masked_bins, weights, zeroes, XValues_new, newWeights,
-                      zeroes2, true);
+  bool ignoreErrors = getProperty("IgnoreBinErrors");
+
+  try {
+    auto newHist = HistogramData::rebin(oldHist, outputWS->binEdges(hist));
+    auto &newWeights = newHist.y();
 
-  // Now process the output vector and fill the new masking list
-  for (size_t index = 0; index < newWeights.size(); ++index) {
-    if (newWeights[index] > 0.0)
-      outputWS->flagMasked(hist, index, newWeights[index]);
+    // Now process the output vector and fill the new masking list
+    for (size_t index = 0; index < newWeights.size(); ++index) {
+      if (newWeights[index] > 0.0)
+        outputWS->flagMasked(hist, index, newWeights[index]);
+    }
+  } catch (InvalidBinEdgesError &) {
+    if (!ignoreErrors)
+      throw;
   }
 }
 
diff --git a/Framework/Algorithms/src/Rebin2D.cpp b/Framework/Algorithms/src/Rebin2D.cpp
index ef9247399c74e18b86d4314f75b1746665b2d7c5..6a426c9c5dcb68a501795e85c9218dd6dc0706a2 100644
--- a/Framework/Algorithms/src/Rebin2D.cpp
+++ b/Framework/Algorithms/src/Rebin2D.cpp
@@ -1,12 +1,9 @@
-//------------------------------------------------------------------------------
-// Includes
-//------------------------------------------------------------------------------
 #include "MantidAlgorithms/Rebin2D.h"
 #include "MantidAPI/BinEdgeAxis.h"
-#include "MantidAPI/WorkspaceFactory.h"
 #include "MantidAPI/WorkspaceProperty.h"
 #include "MantidDataObjects/FractionalRebinning.h"
 #include "MantidDataObjects/RebinnedOutput.h"
+#include "MantidDataObjects/WorkspaceCreation.h"
 #include "MantidGeometry/Math/ConvexPolygon.h"
 #include "MantidGeometry/Math/PolygonIntersection.h"
 #include "MantidGeometry/Math/Quadrilateral.h"
@@ -184,19 +181,17 @@ Rebin2D::createOutputWorkspace(MatrixWorkspace_const_sptr parent,
 
   auto &newY = newYBins.mutableRawData();
   // First create the two sets of bin boundaries
-  const int newXSize = createAxisFromRebinParams(getProperty("Axis1Binning"),
-                                                 newXBins.mutableRawData());
+  static_cast<void>(createAxisFromRebinParams(getProperty("Axis1Binning"),
+                                              newXBins.mutableRawData()));
   const int newYSize =
       createAxisFromRebinParams(getProperty("Axis2Binning"), newY);
   // and now the workspace
+  HistogramData::BinEdges binEdges(newXBins);
   MatrixWorkspace_sptr outputWS;
   if (!useFractionalArea) {
-    outputWS = WorkspaceFactory::Instance().create(parent, newYSize - 1,
-                                                   newXSize, newXSize - 1);
+    outputWS = create<MatrixWorkspace>(*parent, newYSize - 1, binEdges);
   } else {
-    outputWS = WorkspaceFactory::Instance().create(
-        "RebinnedOutput", newYSize - 1, newXSize, newXSize - 1);
-    WorkspaceFactory::Instance().initializeFromParent(parent, outputWS, true);
+    outputWS = create<RebinnedOutput>(*parent, newYSize - 1, binEdges);
   }
   Axis *const verticalAxis = new BinEdgeAxis(newY);
   // Meta data
@@ -204,11 +199,6 @@ Rebin2D::createOutputWorkspace(MatrixWorkspace_const_sptr parent,
   verticalAxis->title() = parent->getAxis(1)->title();
   outputWS->replaceAxis(1, verticalAxis);
 
-  // Now set the axis values
-  for (size_t i = 0; i < static_cast<size_t>(newYSize - 1); ++i) {
-    outputWS->setBinEdges(i, newXBins);
-  }
-
   return outputWS;
 }
 
diff --git a/Framework/Algorithms/src/RebinByPulseTimes.cpp b/Framework/Algorithms/src/RebinByPulseTimes.cpp
index 6067ef19a528fb77dabb56e6f105d6caa690d780..0d4dacf38b66c4a22fb9293628ef5193539e6fe7 100644
--- a/Framework/Algorithms/src/RebinByPulseTimes.cpp
+++ b/Framework/Algorithms/src/RebinByPulseTimes.cpp
@@ -60,11 +60,11 @@ void RebinByPulseTimes::doHistogramming(IEventWorkspace_sptr inWS,
     el.generateHistogramPulseTime(*XValues_new, y_data, e_data);
 
     // Set the X axis for each output histogram
-    outputWS->setX(i, x);
+    outputWS->setSharedX(i, x);
 
     // Copy the data over.
-    outputWS->dataY(i).assign(y_data.begin(), y_data.end());
-    outputWS->dataE(i).assign(e_data.begin(), e_data.end());
+    outputWS->mutableY(i) = std::move(y_data);
+    outputWS->mutableE(i) = std::move(e_data);
 
     // Report progress
     prog.report(name());
diff --git a/Framework/Algorithms/src/RebinByTimeAtSample.cpp b/Framework/Algorithms/src/RebinByTimeAtSample.cpp
index cb0445ff59620e2e657256eccbde3956477c3e50..f9902d418a0608d9ad92c5d50583e3ce1b27cba9 100644
--- a/Framework/Algorithms/src/RebinByTimeAtSample.cpp
+++ b/Framework/Algorithms/src/RebinByTimeAtSample.cpp
@@ -1,9 +1,9 @@
 #include "MantidAlgorithms/RebinByTimeAtSample.h"
 #include "MantidAlgorithms/TimeAtSampleStrategyElastic.h"
 #include "MantidDataObjects/EventWorkspace.h"
-#include "MantidKernel/VectorHelper.h"
 #include "MantidKernel/Unit.h"
 #include "MantidKernel/V3D.h"
+#include "MantidKernel/VectorHelper.h"
 
 #include <boost/make_shared.hpp>
 
@@ -11,6 +11,8 @@
 #include <cmath>
 
 namespace Mantid {
+using namespace HistogramData;
+
 namespace Algorithms {
 using namespace Mantid::Kernel;
 using namespace Mantid::API;
@@ -76,11 +78,11 @@ void RebinByTimeAtSample::doHistogramming(IEventWorkspace_sptr inWS,
                                      tofOffset);
 
     // Set the X axis for each output histogram
-    outputWS->setX(i, x);
+    outputWS->setSharedX(i, x);
 
     // Copy the data over.
-    outputWS->dataY(i).assign(y_data.begin(), y_data.end());
-    outputWS->dataE(i).assign(e_data.begin(), e_data.end());
+    outputWS->mutableY(i) = std::move(y_data);
+    outputWS->mutableE(i) = std::move(e_data);
 
     // Report progress
     prog.report(name());
diff --git a/Framework/Algorithms/src/RebinByTimeBase.cpp b/Framework/Algorithms/src/RebinByTimeBase.cpp
index 5e9334ac2fd691f5bd06a812b67bce53bf9a0172..0b2a577a6e281b8d64ed06b2315a2851870ccea8 100644
--- a/Framework/Algorithms/src/RebinByTimeBase.cpp
+++ b/Framework/Algorithms/src/RebinByTimeBase.cpp
@@ -1,8 +1,9 @@
 #include "MantidAlgorithms/RebinByTimeBase.h"
 #include "MantidAPI/Axis.h"
 #include "MantidAPI/Run.h"
-#include "MantidAPI/WorkspaceFactory.h"
 #include "MantidDataObjects/EventWorkspace.h"
+#include "MantidDataObjects/Workspace2D.h"
+#include "MantidDataObjects/WorkspaceCreation.h"
 #include "MantidKernel/ArrayProperty.h"
 #include "MantidKernel/RebinParamsValidator.h"
 #include "MantidKernel/VectorHelper.h"
@@ -112,8 +113,8 @@ void RebinByTimeBase::exec() {
 
   MantidVecPtr XValues_new;
   // create new X axis, with absolute times in seconds.
-  const int ntcnew = VectorHelper::createAxisFromRebinParams(
-      rebinningParams, XValues_new.access());
+  static_cast<void>(VectorHelper::createAxisFromRebinParams(
+      rebinningParams, XValues_new.access()));
 
   ConvertToRelativeTime transformToRelativeT(runStartTime);
 
@@ -122,9 +123,8 @@ void RebinByTimeBase::exec() {
   std::transform(XValues_new->begin(), XValues_new->end(),
                  OutXValues_scaled.begin(), transformToRelativeT);
 
-  outputWS = WorkspaceFactory::Instance().create("Workspace2D", histnumber,
-                                                 ntcnew, ntcnew - 1);
-  WorkspaceFactory::Instance().initializeFromParent(inWS, outputWS, true);
+  outputWS = DataObjects::create<DataObjects::Workspace2D>(
+      *inWS, histnumber, HistogramData::BinEdges(*XValues_new));
 
   // Copy all the axes
   for (int i = 1; i < inWS->axes(); i++) {
diff --git a/Framework/Algorithms/src/RebinToWorkspace.cpp b/Framework/Algorithms/src/RebinToWorkspace.cpp
index 1d8925963838b8510a11af7e41690ca111a807a5..83251e66f74d16a1c90359e26c88b2cf9f099e85 100644
--- a/Framework/Algorithms/src/RebinToWorkspace.cpp
+++ b/Framework/Algorithms/src/RebinToWorkspace.cpp
@@ -2,8 +2,8 @@
 // Includes
 //------------------------------
 #include "MantidAlgorithms/RebinToWorkspace.h"
-#include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/HistogramValidator.h"
+#include "MantidAPI/MatrixWorkspace.h"
 
 using namespace Mantid::API;
 using namespace Mantid::Algorithms;
@@ -62,6 +62,7 @@ void RebinToWorkspace::exec() {
   runRebin->setPropertyValue("OutputWorkspace", "rebin_out");
   runRebin->setProperty("params", rb_params);
   runRebin->setProperty("PreserveEvents", PreserveEvents);
+  runRebin->setProperty("IgnoreBinErrors", true);
   runRebin->executeAsChildAlg();
   progress(1);
   MatrixWorkspace_sptr ws = runRebin->getProperty("OutputWorkspace");
@@ -78,7 +79,7 @@ std::vector<double> RebinToWorkspace::createRebinParameters(
     Mantid::API::MatrixWorkspace_sptr toMatch) {
   using namespace Mantid::API;
 
-  const MantidVec &matchXdata = toMatch->readX(0);
+  auto &matchXdata = toMatch->x(0);
   // params vector should have the form [x_1, delta_1,x_2, ...
   // ,x_n-1,delta_n-1,x_n), see Rebin.cpp
   std::vector<double> rb_params;
diff --git a/Framework/Algorithms/src/Rebunch.cpp b/Framework/Algorithms/src/Rebunch.cpp
index a7fb024357b83ea2fd0caa1d28b7c8aff511a834..76e43512c6df3a2428206eb08a4dfdf1ce96dd75 100644
--- a/Framework/Algorithms/src/Rebunch.cpp
+++ b/Framework/Algorithms/src/Rebunch.cpp
@@ -4,8 +4,8 @@
 #include "MantidAlgorithms/Rebunch.h"
 #include "MantidAPI/Axis.h"
 #include "MantidAPI/MatrixWorkspace.h"
-#include "MantidAPI/Workspace_fwd.h"
 #include "MantidAPI/WorkspaceFactory.h"
+#include "MantidAPI/Workspace_fwd.h"
 #include "MantidKernel/BoundedValidator.h"
 
 #include <cmath>
@@ -13,6 +13,7 @@
 #include <sstream>
 
 namespace Mantid {
+using namespace HistogramData;
 namespace Algorithms {
 
 // Register the class into the algorithm factory
@@ -56,8 +57,8 @@ void Rebunch::exec() {
   // workspace independent determination of length
   int histnumber = static_cast<int>(inputW->size() / inputW->blocksize());
 
-  int size_x = static_cast<int>(inputW->readX(0).size());
-  int size_y = static_cast<int>(inputW->readY(0).size());
+  int size_x = static_cast<int>(inputW->x(0).size());
+  int size_y = static_cast<int>(inputW->y(0).size());
 
   // signal is the same length for histogram and point data
   int ny = (size_y / n_bunch);
@@ -82,24 +83,20 @@ void Rebunch::exec() {
   PARALLEL_FOR_IF(Kernel::threadSafe(*inputW, *outputW))
   for (int hist = 0; hist < histnumber; hist++) {
     PARALLEL_START_INTERUPT_REGION
-
-    // get const references to input Workspace arrays (no copying)
-    const MantidVec &XValues = inputW->readX(hist);
-    const MantidVec &YValues = inputW->readY(hist);
-    const MantidVec &YErrors = inputW->readE(hist);
-
-    // get references to output workspace data (no copying)
-    MantidVec &XValues_new = outputW->dataX(hist);
-    MantidVec &YValues_new = outputW->dataY(hist);
-    MantidVec &YErrors_new = outputW->dataE(hist);
-
     // output data arrays are implicitly filled by function
     if (point) {
-      rebunch_point(XValues, YValues, YErrors, XValues_new, YValues_new,
-                    YErrors_new, n_bunch);
+      rebunch_point(inputW->x(hist), inputW->y(hist), inputW->e(hist),
+                    outputW->mutableX(hist), outputW->mutableY(hist),
+                    outputW->mutableE(hist), n_bunch);
+    } else if (dist) {
+      rebunch_hist_frequencies(inputW->x(hist), inputW->y(hist),
+                               inputW->e(hist), outputW->mutableX(hist),
+                               outputW->mutableY(hist), outputW->mutableE(hist),
+                               n_bunch);
     } else {
-      rebunch_hist(XValues, YValues, YErrors, XValues_new, YValues_new,
-                   YErrors_new, n_bunch, dist);
+      rebunch_hist_counts(inputW->x(hist), inputW->y(hist), inputW->e(hist),
+                          outputW->mutableX(hist), outputW->mutableY(hist),
+                          outputW->mutableE(hist), n_bunch);
     }
 
     if (hist % progress_step == 0) {
@@ -127,48 +124,104 @@ void Rebunch::exec() {
 
 /** Rebunches histogram data data according to n_bunch input
  *
- * @param xold :: old x array of data
- * @param xnew :: new x array of data
- * @param yold :: old y array of data
- * @param ynew :: new y array of data
- * @param eold :: old error array of data
- * @param enew :: new error array of data
+ * @param xold :: old x data
+ * @param yold :: old y data
+ * @param eold :: old e data
+ * @param xnew :: new x data
+ * @param ynew :: new y data
+ * @param enew :: new e data
  * @param n_bunch :: number of data points to bunch together for each new point
- * @param distribution :: flag defining if distribution data (1) or not (0)
  * @throw runtime_error Thrown if algorithm cannot execute
  * @throw invalid_argument Thrown if input to function is incorrect
  **/
-void Rebunch::rebunch_hist(const std::vector<double> &xold,
-                           const std::vector<double> &yold,
-                           const std::vector<double> &eold,
-                           std::vector<double> &xnew, std::vector<double> &ynew,
-                           std::vector<double> &enew, const size_t n_bunch,
-                           const bool distribution) {
+void Rebunch::rebunch_hist_counts(const HistogramX &xold,
+                                  const HistogramY &yold,
+                                  const HistogramE &eold, HistogramX &xnew,
+                                  HistogramY &ynew, HistogramE &enew,
+                                  const size_t n_bunch) {
+  size_t size_x = xold.size();
+  size_t size_y = yold.size();
+
+  double ysum, esum;
+  size_t hi_index = size_x - 1;
+  size_t wbins = size_y / n_bunch;
+  size_t rem = size_y % n_bunch;
+
   size_t i, j;
+  int i_in = 0;
+  j = 0;
+  while (j < wbins) {
+    ysum = 0.0;
+    esum = 0.0;
+    for (i = 1; i <= n_bunch; i++) {
+      ysum += yold[i_in];
+      esum += eold[i_in] * eold[i_in];
+      i_in++;
+    }
+    // average contributing x values
+    ynew[j] = ysum;
+    enew[j] = sqrt(esum);
+    j++;
+  }
+  if (rem != 0) {
+    ysum = 0.0;
+    esum = 0.0;
+    for (i = 1; i <= rem; i++) {
+      ysum += yold[i_in];
+      esum += eold[i_in] * eold[i_in];
+      i_in++;
+    }
+    ynew[j] = ysum;
+    enew[j] = sqrt(esum);
+  }
+
+  j = 0;
+  xnew[j] = xold[0];
+  j++;
+  for (i = n_bunch; i < hi_index; i += n_bunch) {
+    xnew[j] = xold[i];
+    j++;
+  }
+  xnew[j] = xold[hi_index];
+}
+
+/** Rebunches histogram data data according to n_bunch input
+*
+* @param xold :: old x data
+* @param yold :: old y data
+* @param eold :: old e data
+* @param xnew :: new x data
+* @param ynew :: new y data
+* @param enew :: new e data
+* @param n_bunch :: number of data points to bunch together for each new point
+* @throw runtime_error Thrown if algorithm cannot execute
+* @throw invalid_argument Thrown if input to function is incorrect
+**/
+void Rebunch::rebunch_hist_frequencies(const HistogramX &xold,
+                                       const HistogramY &yold,
+                                       const HistogramE &eold, HistogramX &xnew,
+                                       HistogramY &ynew, HistogramE &enew,
+                                       const size_t n_bunch) {
   double width;
   size_t size_x = xold.size();
   size_t size_y = yold.size();
+
   double ysum, esum;
   size_t hi_index = size_x - 1;
   size_t wbins = size_y / n_bunch;
   size_t rem = size_y % n_bunch;
 
+  size_t i, j;
   int i_in = 0;
   j = 0;
   while (j < wbins) {
     ysum = 0.0;
     esum = 0.0;
     for (i = 1; i <= n_bunch; i++) {
-      if (distribution) {
-        width = xold[i_in + 1] - xold[i_in];
-        ysum += yold[i_in] * width;
-        esum += eold[i_in] * eold[i_in] * width * width;
-        i_in++;
-      } else {
-        ysum += yold[i_in];
-        esum += eold[i_in] * eold[i_in];
-        i_in++;
-      }
+      width = xold[i_in + 1] - xold[i_in];
+      ysum += yold[i_in] * width;
+      esum += eold[i_in] * eold[i_in] * width * width;
+      i_in++;
     }
     // average contributing x values
     ynew[j] = ysum;
@@ -179,16 +232,10 @@ void Rebunch::rebunch_hist(const std::vector<double> &xold,
     ysum = 0.0;
     esum = 0.0;
     for (i = 1; i <= rem; i++) {
-      if (distribution) {
-        width = xold[i_in + 1] - xold[i_in];
-        ysum += yold[i_in] * width;
-        esum += eold[i_in] * eold[i_in] * width * width;
-        i_in++;
-      } else {
-        ysum += yold[i_in];
-        esum += eold[i_in] * eold[i_in];
-        i_in++;
-      }
+      width = xold[i_in + 1] - xold[i_in];
+      ysum += yold[i_in] * width;
+      esum += eold[i_in] * eold[i_in] * width * width;
+      i_in++;
     }
     ynew[j] = ysum;
     enew[j] = sqrt(esum);
@@ -203,39 +250,36 @@ void Rebunch::rebunch_hist(const std::vector<double> &xold,
   }
   xnew[j] = xold[hi_index];
 
-  if (distribution)
-    for (i = 0; i < ynew.size(); i++) {
-      width = xnew[i + 1] - xnew[i];
-      ynew[i] = ynew[i] / width;
-      enew[i] = enew[i] / width;
-    }
+  for (i = 0; i < ynew.size(); i++) {
+    width = xnew[i + 1] - xnew[i];
+    ynew[i] = ynew[i] / width;
+    enew[i] = enew[i] / width;
+  }
 }
 
 /** Rebunches point data data according to n_bunch input
  *
- * @param xold :: old x array of data
- * @param xnew :: new x array of data
- * @param yold :: old y array of data
- * @param ynew :: new y array of data
- * @param eold :: old error array of data
- * @param enew :: new error array of data
+ * @param xold :: old x data
+ * @param yold :: old y data
+ * @param eold :: old e data
+ * @param xnew :: new x data
+ * @param ynew :: new y data
+ * @param enew :: new e data
  * @param n_bunch :: number of data points to bunch together for each new point
  * @throw runtime_error Thrown if algorithm cannot execute
  * @throw invalid_argument Thrown if input to function is incorrect
  **/
+void Rebunch::rebunch_point(const HistogramX &xold, const HistogramY &yold,
+                            const HistogramE &eold, HistogramX &xnew,
+                            HistogramY &ynew, HistogramE &enew,
+                            const size_t n_bunch) {
 
-void Rebunch::rebunch_point(const std::vector<double> &xold,
-                            const std::vector<double> &yold,
-                            const std::vector<double> &eold,
-                            std::vector<double> &xnew,
-                            std::vector<double> &ynew,
-                            std::vector<double> &enew, const int n_bunch) {
-  int i, j;
-  int size_y = static_cast<int>(yold.size());
+  size_t size_y = yold.size();
   double xsum, ysum, esum;
-  int wbins = size_y / n_bunch;
-  int rem = size_y % n_bunch;
+  size_t wbins = size_y / n_bunch;
+  size_t rem = size_y % n_bunch;
 
+  size_t i, j;
   int i_in = 0;
   j = 0;
   while (j < wbins) {
diff --git a/Framework/Algorithms/src/ReflectometryReductionOne.cpp b/Framework/Algorithms/src/ReflectometryReductionOne.cpp
index b63524e8dedc9d12b073e0cdff37594c64e5b54a..0e08c3036f88412e0d4ed3c779403c062d847b44 100644
--- a/Framework/Algorithms/src/ReflectometryReductionOne.cpp
+++ b/Framework/Algorithms/src/ReflectometryReductionOne.cpp
@@ -8,6 +8,7 @@
 #include "MantidKernel/ListValidator.h"
 #include "MantidKernel/ArrayProperty.h"
 #include "MantidKernel/EnabledWhenProperty.h"
+#include "MantidKernel/Tolerance.h"
 #include "MantidKernel/Unit.h"
 #include <boost/make_shared.hpp>
 
@@ -627,9 +628,9 @@ void ReflectometryReductionOne::exec() {
   double momentumTransferMaximum = getProperty("MomentumTransferMaximum");
   MantidVec QParams;
   if (isDefault("MomentumTransferMinimum"))
-    momentumTransferMinimum = calculateQ(IvsLam->readX(0).back(), theta.get());
+    momentumTransferMinimum = calculateQ(IvsLam->x(0).back(), theta.get());
   if (isDefault("MomentumTransferMaximum"))
-    momentumTransferMaximum = calculateQ(IvsLam->readX(0).front(), theta.get());
+    momentumTransferMaximum = calculateQ(IvsLam->x(0).front(), theta.get());
   if (isDefault("MomentumTransferStep")) {
     // if the DQQ is not given for this run.
     // we will use CalculateResoltion to produce this value
diff --git a/Framework/Algorithms/src/ReflectometryReductionOneAuto.cpp b/Framework/Algorithms/src/ReflectometryReductionOneAuto.cpp
index 060c169b191450288e25ac7e19f5816d8933b957..ca95d270a211bff87c2741a947bbe2d0697d463e 100644
--- a/Framework/Algorithms/src/ReflectometryReductionOneAuto.cpp
+++ b/Framework/Algorithms/src/ReflectometryReductionOneAuto.cpp
@@ -1,5 +1,6 @@
 #include "MantidAlgorithms/BoostOptionalToAlgorithmProperty.h"
 #include "MantidAlgorithms/ReflectometryReductionOneAuto.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidAPI/WorkspaceUnitValidator.h"
 #include "MantidKernel/ArrayProperty.h"
 #include "MantidKernel/BoundedValidator.h"
@@ -750,12 +751,13 @@ bool ReflectometryReductionOneAuto::processGroups() {
     // Otherwise, if polarization correction is off, we process them
     // using one transmission group member at a time.
     if (firstTransG && !isPolarizationCorrectionOn) // polarization off
-      alg->setProperty("FirstTransmissionRun", firstTransG->getItem(i)->name());
+      alg->setProperty("FirstTransmissionRun",
+                       firstTransG->getItem(i)->getName());
     if (secondTransG && !isPolarizationCorrectionOn) // polarization off
       alg->setProperty("SecondTransmissionRun",
-                       secondTransG->getItem(i)->name());
+                       secondTransG->getItem(i)->getName());
 
-    alg->setProperty("InputWorkspace", group->getItem(i)->name());
+    alg->setProperty("InputWorkspace", group->getItem(i)->getName());
     alg->setProperty("OutputWorkspace", IvsQName);
     alg->setProperty("OutputWorkspaceWavelength", IvsLamName);
     alg->execute();
diff --git a/Framework/Algorithms/src/ReflectometryWorkflowBase.cpp b/Framework/Algorithms/src/ReflectometryWorkflowBase.cpp
index 428e8d3c0e9e1c56de031585715b0a91037b948b..1b56adf11718ff476f2fae2701401f47295764c6 100644
--- a/Framework/Algorithms/src/ReflectometryWorkflowBase.cpp
+++ b/Framework/Algorithms/src/ReflectometryWorkflowBase.cpp
@@ -9,6 +9,7 @@
 #include "MantidKernel/RebinParamsValidator.h"
 
 using namespace Mantid::API;
+using namespace Mantid::HistogramData;
 using namespace Mantid::Kernel;
 
 namespace Mantid {
@@ -439,10 +440,10 @@ ReflectometryWorkflowBase::toLamDetector(const std::string &processingCommands,
 }
 
 MatrixWorkspace_sptr
-ReflectometryWorkflowBase::makeUnityWorkspace(const std::vector<double> &x) {
+ReflectometryWorkflowBase::makeUnityWorkspace(const HistogramX &x) {
   auto createWorkspaceAlg = this->createChildAlgorithm("CreateWorkspace");
   createWorkspaceAlg->initialize();
-  createWorkspaceAlg->setProperty("DataX", x);
+  createWorkspaceAlg->setProperty("DataX", x.rawData());
   createWorkspaceAlg->setProperty("DataY",
                                   std::vector<double>(x.size() - 1, 1.0));
   createWorkspaceAlg->setProperty("NSpec", 1);
@@ -482,7 +483,7 @@ ReflectometryWorkflowBase::toLam(MatrixWorkspace_sptr toConvert,
     monitorWS = toLamMonitor(toConvert, monitorIndex, backgroundMinMax);
   } else {
     // We don't have a monitor index, so we divide through by unity.
-    monitorWS = makeUnityWorkspace(detectorWS->readX(0));
+    monitorWS = makeUnityWorkspace(detectorWS->x(0));
   }
 
   // Rebin the Monitor Workspace to match the Detector Workspace.
diff --git a/Framework/Algorithms/src/Regroup.cpp b/Framework/Algorithms/src/Regroup.cpp
index 509de164674ee242050508c699554c8515ffb5d4..8f89fa60d6664b57df7cec3d84ebd2d21ca1958a 100644
--- a/Framework/Algorithms/src/Regroup.cpp
+++ b/Framework/Algorithms/src/Regroup.cpp
@@ -16,6 +16,9 @@
 #include <numeric>
 
 namespace Mantid {
+using HistogramData::HistogramX;
+using HistogramData::HistogramY;
+using HistogramData::HistogramE;
 namespace Algorithms {
 
 // Register the class into the algorithm factory
@@ -57,7 +60,7 @@ void Regroup::exec() {
   MatrixWorkspace_const_sptr inputW = getProperty("InputWorkspace");
 
   // can work only if all histograms have the same boundaries
-  if (!API::WorkspaceHelpers::commonBoundaries(inputW)) {
+  if (!API::WorkspaceHelpers::commonBoundaries(*inputW)) {
     g_log.error("Histograms with different boundaries");
     throw std::runtime_error("Histograms with different boundaries");
   }
@@ -66,11 +69,11 @@ void Regroup::exec() {
 
   int histnumber = static_cast<int>(inputW->getNumberHistograms());
   HistogramData::BinEdges XValues_new(0);
-  const MantidVec &XValues_old = inputW->readX(0);
+  auto &XValues_old = inputW->x(0);
   std::vector<int> xoldIndex; // indeces of new x in XValues_old
   // create new output X axis
-  int ntcnew =
-      newAxis(rb_params, XValues_old, XValues_new.mutableRawData(), xoldIndex);
+  int ntcnew = newAxis(rb_params, XValues_old.rawData(),
+                       XValues_new.mutableRawData(), xoldIndex);
 
   // make output Workspace the same type is the input, but with new length of
   // signal array
@@ -82,13 +85,13 @@ void Regroup::exec() {
     progress_step = 1;
   for (int hist = 0; hist < histnumber; hist++) {
     // get const references to input Workspace arrays (no copying)
-    const MantidVec &XValues = inputW->readX(hist);
-    const MantidVec &YValues = inputW->readY(hist);
-    const MantidVec &YErrors = inputW->readE(hist);
+    auto &XValues = inputW->x(hist);
+    auto &YValues = inputW->y(hist);
+    auto &YErrors = inputW->e(hist);
 
     // get references to output workspace data (no copying)
-    MantidVec &YValues_new = outputW->dataY(hist);
-    MantidVec &YErrors_new = outputW->dataE(hist);
+    auto &YValues_new = outputW->mutableY(hist);
+    auto &YErrors_new = outputW->mutableE(hist);
 
     // output data arrays are implicitly filled by function
     rebin(XValues, YValues, YErrors, xoldIndex, YValues_new, YErrors_new, dist);
@@ -120,21 +123,18 @@ void Regroup::exec() {
 /** Regroup the data according to new output X array
  *
  * @param xold :: old x array of data
- * @param xoldIndex :: indeces of new x in XValues_old
  * @param yold :: old y array of data
- * @param ynew :: new y array of data
  * @param eold :: old error array of data
+ * @param xoldIndex :: indeces of new x in XValues_old
+ * @param ynew :: new y array of data
  * @param enew :: new error array of data
  * @param distribution :: flag defining if distribution data (1) or not (0)
  * @throw runtime_error Thrown if algorithm cannot execute
  * @throw invalid_argument Thrown if input to function is incorrect
  **/
-void Regroup::rebin(const std::vector<double> &xold,
-                    const std::vector<double> &yold,
-                    const std::vector<double> &eold,
-                    const std::vector<int> &xoldIndex,
-                    std::vector<double> &ynew, std::vector<double> &enew,
-                    bool distribution) {
+void Regroup::rebin(const HistogramX &xold, const HistogramY &yold,
+                    const HistogramE &eold, std::vector<int> &xoldIndex,
+                    HistogramY &ynew, HistogramE &enew, bool distribution) {
 
   for (int i = 0; i < int(xoldIndex.size() - 1); i++) {
 
diff --git a/Framework/Algorithms/src/RemoveBackground.cpp b/Framework/Algorithms/src/RemoveBackground.cpp
index ffc385ad655973ebfbd0d832acd1b1a07b1fbb0b..d442aa4656cd2056af3ccfcd4067f834fd75d208 100644
--- a/Framework/Algorithms/src/RemoveBackground.cpp
+++ b/Framework/Algorithms/src/RemoveBackground.cpp
@@ -13,10 +13,15 @@
 #include "MantidKernel/CompositeValidator.h"
 #include "MantidKernel/ListValidator.h"
 #include "MantidKernel/RebinParamsValidator.h"
+#include "MantidKernel/Unit.h"
 #include "MantidKernel/VectorHelper.h"
 #include "MantidKernel/VisibleWhenProperty.h"
 #include "MantidKernel/make_unique.h"
 
+using Mantid::HistogramData::HistogramX;
+using Mantid::HistogramData::HistogramY;
+using Mantid::HistogramData::HistogramE;
+
 namespace Mantid {
 namespace Algorithms {
 
@@ -120,11 +125,11 @@ void RemoveBackground::exec() {
   for (int hist = 0; hist < histnumber; ++hist) {
     PARALLEL_START_INTERUPT_REGION
     // get references to output Workspace X-arrays.
-    MantidVec &XValues = outputWS->dataX(hist);
+    auto &XValues = outputWS->mutableX(hist);
     // get references to output workspace data and error. If it is new
     // workspace, data will be copied there, if old, modified in-place
-    MantidVec &YValues = outputWS->dataY(hist);
-    MantidVec &YErrors = outputWS->dataE(hist);
+    auto &YValues = outputWS->mutableY(hist);
+    auto &YErrors = outputWS->mutableE(hist);
 
     // output data arrays are implicitly filled by function
     int id = PARALLEL_THREAD_NUMBER;
@@ -213,9 +218,9 @@ void BackgroundHelper::initialize(const API::MatrixWorkspace_const_sptr &bkgWS,
   if (bkgWS->getNumberHistograms() <= 1)
     m_singleValueBackground = true;
 
-  const MantidVec &dataX = bkgWS->readX(0);
-  const MantidVec &dataY = bkgWS->readY(0);
-  const MantidVec &dataE = bkgWS->readE(0);
+  auto &dataX = bkgWS->x(0);
+  auto &dataY = bkgWS->y(0);
+  auto &dataE = bkgWS->e(0);
   m_NBg = dataY[0];
   m_dtBg = dataX[1] - dataX[0];
   m_ErrSq = dataE[0] * dataE[0]; // needs further clarification
@@ -239,8 +244,8 @@ void BackgroundHelper::initialize(const API::MatrixWorkspace_const_sptr &bkgWS,
 * single thread, in multithreading -- result of
 *                      omp_get_thread_num() )
 */
-void BackgroundHelper::removeBackground(int nHist, MantidVec &x_data,
-                                        MantidVec &y_data, MantidVec &e_data,
+void BackgroundHelper::removeBackground(int nHist, HistogramX &x_data,
+                                        HistogramY &y_data, HistogramE &e_data,
                                         int threadNum) const {
 
   double dtBg, IBg, ErrBgSq;
@@ -249,9 +254,9 @@ void BackgroundHelper::removeBackground(int nHist, MantidVec &x_data,
     ErrBgSq = m_ErrSq;
     IBg = m_NBg;
   } else {
-    const MantidVec &dataX = m_bgWs->readX(nHist);
-    const MantidVec &dataY = m_bgWs->readY(nHist);
-    const MantidVec &dataE = m_bgWs->readE(nHist);
+    auto &dataX = m_bgWs->x(nHist);
+    auto &dataY = m_bgWs->y(nHist);
+    auto &dataE = m_bgWs->e(nHist);
     dtBg = (dataX[1] - dataX[0]);
     IBg = dataY[0];
     ErrBgSq = dataE[0] * dataE[0]; // Needs further clarification
@@ -263,9 +268,9 @@ void BackgroundHelper::removeBackground(int nHist, MantidVec &x_data,
     double L2 = m_spectrumInfo->l2(nHist);
     double delta(std::numeric_limits<double>::quiet_NaN());
     // get access to source workspace in case if target is different from source
-    const MantidVec &XValues = m_wkWS->readX(nHist);
-    const MantidVec &YValues = m_wkWS->readY(nHist);
-    const MantidVec &YErrors = m_wkWS->readE(nHist);
+    auto &XValues = m_wkWS->x(nHist);
+    auto &YValues = m_wkWS->y(nHist);
+    auto &YErrors = m_wkWS->e(nHist);
 
     // use thread-specific unit conversion class to avoid multithreading issues
     Kernel::Unit *unitConv = m_WSUnit[threadNum];
diff --git a/Framework/Algorithms/src/RemoveBins.cpp b/Framework/Algorithms/src/RemoveBins.cpp
index 4a5467e32c94249dbeabdcf014df10780c7a1b4b..91455f52c29634c4443870708eb98ee05cde3da1 100644
--- a/Framework/Algorithms/src/RemoveBins.cpp
+++ b/Framework/Algorithms/src/RemoveBins.cpp
@@ -14,6 +14,10 @@
 #include "MantidKernel/Unit.h"
 #include "MantidKernel/UnitFactory.h"
 
+using Mantid::HistogramData::HistogramX;
+using Mantid::HistogramData::HistogramY;
+using Mantid::HistogramData::HistogramE;
+
 namespace Mantid {
 namespace Algorithms {
 
@@ -84,7 +88,7 @@ void RemoveBins::exec() {
   const bool unitChange = (rangeUnit != "AsInput" && rangeUnit != "inputUnit");
   if (unitChange)
     m_rangeUnit = UnitFactory::Instance().create(rangeUnit);
-  const bool commonBins = WorkspaceHelpers::commonBoundaries(m_inputWorkspace);
+  const bool commonBins = WorkspaceHelpers::commonBoundaries(*m_inputWorkspace);
   const int index = getProperty("WorkspaceIndex");
   const bool singleSpectrum = !isEmpty(index);
   const bool recalcRange = (unitChange || !commonBins);
@@ -92,7 +96,7 @@ void RemoveBins::exec() {
   // If the above evaluates to false, and the range given is at the edge of the
   // workspace, then we can just call
   // CropWorkspace as a ChildAlgorithm and we're done.
-  const MantidVec &X0 = m_inputWorkspace->readX(0);
+  auto &X0 = m_inputWorkspace->x(0);
   if (!singleSpectrum && !recalcRange &&
       (m_startX <= X0.front() || m_endX >= X0.back())) {
     double start, end;
@@ -123,21 +127,12 @@ void RemoveBins::exec() {
 
   // Loop over the spectra
   int start = 0, end = 0;
-  const int blockSize = static_cast<int>(m_inputWorkspace->readX(0).size());
+  const int blockSize = static_cast<int>(m_inputWorkspace->x(0).size());
   const int numHists =
       static_cast<int>(m_inputWorkspace->getNumberHistograms());
   Progress prog(this, 0.0, 1.0, numHists);
   for (int i = 0; i < numHists; ++i) {
-    // Copy over the data
-    const MantidVec &X = m_inputWorkspace->readX(i);
-    MantidVec &myX = outputWS->dataX(i);
-    myX = X;
-    const MantidVec &Y = m_inputWorkspace->readY(i);
-    MantidVec &myY = outputWS->dataY(i);
-    myY = Y;
-    const MantidVec &E = m_inputWorkspace->readE(i);
-    MantidVec &myE = outputWS->dataE(i);
-    myE = E;
+    outputWS->setHistogram(i, m_inputWorkspace->histogram(i));
 
     // If just operating on a single spectrum and this isn't it, go to next
     // iteration
@@ -150,6 +145,9 @@ void RemoveBins::exec() {
       this->transformRangeUnit(i, startX, endX);
     }
 
+    auto &X = m_inputWorkspace->x(i);
+    auto &outY = outputWS->mutableY(i);
+    auto &outE = outputWS->mutableE(i);
     // Calculate the bin indices corresponding to the X range, if necessary
     if (recalcRange || singleSpectrum || !i) {
       start = this->findIndex(startX, X);
@@ -158,12 +156,12 @@ void RemoveBins::exec() {
 
     if (start == 0 || end == blockSize) {
       // Remove bins from either end
-      this->RemoveFromEnds(start, end, myY, myE);
+      this->RemoveFromEnds(start, end, outY, outE);
     } else {
       // Remove bins from middle
       const double startFrac = (X[start] - startX) / (X[start] - X[start - 1]);
       const double endFrac = (endX - X[end - 1]) / (X[end] - X[end - 1]);
-      this->RemoveFromMiddle(start - 1, end, startFrac, endFrac, myY, myE);
+      this->RemoveFromMiddle(start - 1, end, startFrac, endFrac, outY, outE);
     }
     prog.report();
   } // Loop over spectra
@@ -285,7 +283,7 @@ void RemoveBins::calculateDetectorPosition(const int index, double &l1,
  *  @return The index (will give vec.size()+1 if the value is past the end of
  * the vector)
  */
-int RemoveBins::findIndex(const double &value, const MantidVec &vec) {
+int RemoveBins::findIndex(const double &value, const HistogramX &vec) {
   auto pos = std::lower_bound(vec.cbegin(), vec.cend(), value);
   return static_cast<int>(std::distance(vec.cbegin(), pos));
 }
@@ -296,8 +294,8 @@ int RemoveBins::findIndex(const double &value, const MantidVec &vec) {
  *  @param Y ::     The data vector
  *  @param E ::     The error vector
  */
-void RemoveBins::RemoveFromEnds(int start, int end, MantidVec &Y,
-                                MantidVec &E) {
+void RemoveBins::RemoveFromEnds(int start, int end, HistogramY &Y,
+                                HistogramE &E) {
   if (start)
     --start;
   int size = static_cast<int>(Y.size());
@@ -325,8 +323,8 @@ void RemoveBins::RemoveFromEnds(int start, int end, MantidVec &Y,
  */
 void RemoveBins::RemoveFromMiddle(const int &start, const int &end,
                                   const double &startFrac,
-                                  const double &endFrac, MantidVec &Y,
-                                  MantidVec &E) {
+                                  const double &endFrac, HistogramY &Y,
+                                  HistogramE &E) {
   // Remove bins from middle
   double valPrev = 0;
   double valNext = 0;
diff --git a/Framework/Algorithms/src/RemoveLowResTOF.cpp b/Framework/Algorithms/src/RemoveLowResTOF.cpp
index 711fea813694721da46c6037d22a2ba004d3ee72..38766a9291431b3b2da65a61afde21efdaacff03 100644
--- a/Framework/Algorithms/src/RemoveLowResTOF.cpp
+++ b/Framework/Algorithms/src/RemoveLowResTOF.cpp
@@ -9,6 +9,7 @@
 #include "MantidKernel/BoundedValidator.h"
 #include "MantidKernel/CompositeValidator.h"
 #include "MantidKernel/EnabledWhenProperty.h"
+#include "MantidKernel/Unit.h"
 #include "MantidKernel/UnitFactory.h"
 #include <cmath>
 #include <limits>
@@ -115,7 +116,7 @@ void RemoveLowResTOF::exec() {
   m_numberOfSpectra = m_inputWS->getNumberHistograms();
 
   std::string lowreswsname = getPropertyValue("LowResTOFWorkspace");
-  if (lowreswsname.size() > 0)
+  if (!lowreswsname.empty())
     m_outputLowResTOF = true;
   else
     m_outputLowResTOF = false;
diff --git a/Framework/Algorithms/src/RemoveWorkspaceHistory.cpp b/Framework/Algorithms/src/RemoveWorkspaceHistory.cpp
index 269cd5a3f2893b130deebfe4b2adb8d8c7b00579..acd3339fbe716b586cd144e42c962a86b8d43f34 100644
--- a/Framework/Algorithms/src/RemoveWorkspaceHistory.cpp
+++ b/Framework/Algorithms/src/RemoveWorkspaceHistory.cpp
@@ -1,3 +1,4 @@
+#include "MantidAPI/Workspace.h"
 #include "MantidAPI/WorkspaceHistory.h"
 #include "MantidAlgorithms/RemoveWorkspaceHistory.h"
 
@@ -10,7 +11,6 @@ namespace Algorithms {
 // Register the algorithm into the AlgorithmFactory
 DECLARE_ALGORITHM(RemoveWorkspaceHistory)
 
-//----------------------------------------------------------------------------------------------
 /// Algorithm's name for identification. @see Algorithm::name
 const std::string RemoveWorkspaceHistory::name() const {
   return "RemoveWorkspaceHistory";
@@ -29,7 +29,6 @@ const std::string RemoveWorkspaceHistory::summary() const {
   return "Removes all algorithm history records from a given workspace.";
 }
 
-//----------------------------------------------------------------------------------------------
 /** Initialize the algorithm's properties.
  */
 void RemoveWorkspaceHistory::init() {
@@ -38,7 +37,6 @@ void RemoveWorkspaceHistory::init() {
                   "Workspace to remove the algorithm history from.");
 }
 
-//----------------------------------------------------------------------------------------------
 /** Execute the algorithm.
  */
 void RemoveWorkspaceHistory::exec() {
@@ -47,4 +45,4 @@ void RemoveWorkspaceHistory::exec() {
 }
 
 } // namespace Algorithms
-} // namespace Mantid
\ No newline at end of file
+} // namespace Mantid
diff --git a/Framework/Algorithms/src/RenameWorkspace.cpp b/Framework/Algorithms/src/RenameWorkspace.cpp
index e20e72a4815c9ea53372e3b646d38b270d57b4b8..07c0df28de1da37a70cb53947c1b3b9efe9a80f3 100644
--- a/Framework/Algorithms/src/RenameWorkspace.cpp
+++ b/Framework/Algorithms/src/RenameWorkspace.cpp
@@ -1,11 +1,9 @@
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidAlgorithms/RenameWorkspace.h"
 #include "MantidAPI/FrameworkManager.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidKernel/Exception.h"
 #include "MantidAPI/AnalysisDataService.h"
+#include "MantidAPI/WorkspaceGroup.h"
 
 namespace Mantid {
 namespace Algorithms {
@@ -114,7 +112,7 @@ void RenameWorkspace::exec() {
   if (monWS) {
     std::string monWSName = monWS->getName();
     // rename the monitor workspace accordingly
-    if (monWSName.size() == 0) {
+    if (monWSName.empty()) {
       // workspace will always have name after added to ADS, so apparently not
       // the case
       AnalysisDataService::Instance().add(outputwsName + "_monitors", monWS);
@@ -134,7 +132,7 @@ void RenameWorkspace::exec() {
 bool RenameWorkspace::processGroups() {
   // Get the input & output workspace names
   Workspace_sptr inputWS = getProperty("InputWorkspace");
-  const std::string inputwsName = inputWS->name();
+  const std::string inputwsName = inputWS->getName();
   std::string outputwsName = getPropertyValue("OutputWorkspace");
 
   if (inputwsName == outputwsName) {
diff --git a/Framework/Algorithms/src/ReplaceSpecialValues.cpp b/Framework/Algorithms/src/ReplaceSpecialValues.cpp
index bd36b77a27722277e67f7c6e138b4c331f844a54..57b4d8b5b266e0766f63296384da8b126c01c71a 100644
--- a/Framework/Algorithms/src/ReplaceSpecialValues.cpp
+++ b/Framework/Algorithms/src/ReplaceSpecialValues.cpp
@@ -22,26 +22,38 @@ ReplaceSpecialValues::ReplaceSpecialValues()
       m_performBigCheck(false) {}
 
 void ReplaceSpecialValues::defineProperties() {
+  // NaN properties
   declareProperty("NaNValue", Mantid::EMPTY_DBL(),
-                  "The value used to replace occurrances of NaN "
+                  "The value used to replace occurrences of NaN "
                   "(default: do not check).");
   declareProperty("NaNError", 0.0,
                   "The error value used when replacing a value of NaN ");
+  // Infinity properties
   declareProperty(
       "InfinityValue", Mantid::EMPTY_DBL(),
-      "The value used to replace occurrances of positive or negative infinity "
+      "The value used to replace occurrences of positive or negative infinity "
       "(default: do not check).");
   declareProperty("InfinityError", 0.0,
                   "The error value used when replacing a value of infinity ");
+  // Big number properties
   declareProperty("BigNumberThreshold", Mantid::EMPTY_DBL(),
                   "The threshold above which a number (positive or negative) "
                   "should be replaced. "
                   "(default: do not check)");
   declareProperty(
       "BigNumberValue", 0.0,
-      "The value with which to replace occurrances of 'big' numbers.");
+      "The value with which to replace occurrences of 'big' numbers.");
   declareProperty("BigNumberError", 0.0,
                   "The error value used when replacing a 'big' number");
+  // Small number properties
+  declareProperty("SmallNumberThreshold", Mantid::EMPTY_DBL(),
+                  "The threshold below which a number (positive or negative) "
+                  "should be replaced. (default: do not check)");
+  declareProperty(
+      "SmallNumberValue", 0.0,
+      "The value with which to replace occurrences of 'small' numbers.");
+  declareProperty("SmallNumberError", 0.0,
+                  "The error value used when replacing a 'small' number");
 }
 
 void ReplaceSpecialValues::retrieveProperties() {
@@ -52,13 +64,21 @@ void ReplaceSpecialValues::retrieveProperties() {
   m_bigThreshold = getProperty("BigNumberThreshold");
   m_bigValue = getProperty("BigNumberValue");
   m_bigError = getProperty("BigNumberError");
+  m_smallThreshold = getProperty("SmallNumberThreshold");
+  m_smallValue = getProperty("SmallNumberValue");
+  m_smallError = getProperty("SmallNumberError");
 
   m_performNaNCheck = !checkifPropertyEmpty(m_NaNValue);
   m_performInfiniteCheck = !checkifPropertyEmpty(m_InfiniteValue);
   m_performBigCheck = !checkifPropertyEmpty(m_bigThreshold);
-  if (!(m_performNaNCheck || m_performInfiniteCheck || m_performBigCheck)) {
-    throw std::invalid_argument(
-        "No value was defined for NaN, infinity or BigValueThreshold");
+  m_performSmallCheck = !checkifPropertyEmpty(m_smallThreshold);
+
+  const bool replacement_set = m_performNaNCheck || m_performInfiniteCheck ||
+                               m_performBigCheck || m_performSmallCheck;
+
+  if (!replacement_set) {
+    throw std::invalid_argument("No value was defined for NaN, infinity, "
+                                "BigValueThreshold or SmallValueThreshold");
   }
 }
 
@@ -79,22 +99,29 @@ void ReplaceSpecialValues::performUnaryOperation(const double XIn,
   } else if (m_performBigCheck && checkIfBig(YIn)) {
     YOut = m_bigValue;
     EOut = m_bigError;
+  } else if (m_performSmallCheck && checkIfSmall(YIn)) {
+    YOut = m_smallValue;
+    EOut = m_smallError;
   }
 }
 
-bool ReplaceSpecialValues::checkIfNan(const double &value) const {
+bool ReplaceSpecialValues::checkIfNan(const double value) const {
   return (std::isnan(value));
 }
 
-bool ReplaceSpecialValues::checkIfInfinite(const double &value) const {
+bool ReplaceSpecialValues::checkIfInfinite(const double value) const {
   return (std::isinf(value));
 }
 
-bool ReplaceSpecialValues::checkIfBig(const double &value) const {
+bool ReplaceSpecialValues::checkIfBig(const double value) const {
   return (std::abs(value) > m_bigThreshold);
 }
 
-bool ReplaceSpecialValues::checkifPropertyEmpty(const double &value) const {
+bool ReplaceSpecialValues::checkIfSmall(const double value) const {
+  return (std::abs(value) < m_smallThreshold);
+}
+
+bool ReplaceSpecialValues::checkifPropertyEmpty(const double value) const {
   return (std::abs(value - Mantid::EMPTY_DBL()) < 1e-08);
 }
 
diff --git a/Framework/Algorithms/src/ResampleX.cpp b/Framework/Algorithms/src/ResampleX.cpp
index 9e13cdf4d6e483f9aa187ee89ab03b8a6540e016..fac60b299c800e7722254ef0ff2bad982f2dc67c 100644
--- a/Framework/Algorithms/src/ResampleX.cpp
+++ b/Framework/Algorithms/src/ResampleX.cpp
@@ -2,6 +2,8 @@
 #include "MantidAPI/Axis.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidDataObjects/EventWorkspace.h"
+#include "MantidDataObjects/Workspace2D.h"
+#include "MantidDataObjects/WorkspaceCreation.h"
 #include "MantidKernel/ArrayProperty.h"
 #include "MantidKernel/BoundedValidator.h"
 #include "MantidKernel/VectorHelper.h"
@@ -359,18 +361,11 @@ void ResampleX::exec() {
     else // event workspace -> matrix workspace
     {
       //--------- Different output, OR you're inplace but not preserving Events
-      //--- create a Workspace2D -------
       g_log.information() << "Creating a Workspace2D from the EventWorkspace "
                           << inputEventWS->getName() << ".\n";
+      outputWS = create<DataObjects::Workspace2D>(
+          *inputWS, numSpectra, HistogramData::BinEdges(m_numBins));
 
-      // Create a Workspace2D
-      // This creates a new Workspace2D through a torturous route using the
-      // WorkspaceFactory.
-      // The Workspace2D is created with an EMPTY CONSTRUCTOR
-      outputWS = WorkspaceFactory::Instance().create("Workspace2D", numSpectra,
-                                                     m_numBins, m_numBins - 1);
-      WorkspaceFactory::Instance().initializeFromParent(inputWS, outputWS,
-                                                        true);
       // Initialize progress reporting.
       Progress prog(this, 0.0, 1.0, numSpectra);
 
diff --git a/Framework/Algorithms/src/SANSDirectBeamScaling.cpp b/Framework/Algorithms/src/SANSDirectBeamScaling.cpp
deleted file mode 100644
index f485e744347519bcd696783ae8fce1e7edfc93d6..0000000000000000000000000000000000000000
--- a/Framework/Algorithms/src/SANSDirectBeamScaling.cpp
+++ /dev/null
@@ -1,172 +0,0 @@
-#include "MantidAlgorithms/SANSDirectBeamScaling.h"
-#include "MantidAPI/HistogramValidator.h"
-#include "MantidAPI/SpectrumInfo.h"
-#include "MantidAPI/WorkspaceUnitValidator.h"
-#include "MantidDataObjects/Histogram1D.h"
-#include "MantidGeometry/Instrument.h"
-#include "MantidKernel/ArrayProperty.h"
-#include "MantidKernel/BoundedValidator.h"
-#include "MantidKernel/CompositeValidator.h"
-#include "MantidKernel/RebinParamsValidator.h"
-#include "MantidKernel/PhysicalConstants.h"
-#include "MantidKernel/UnitFactory.h"
-#include "MantidKernel/VectorHelper.h"
-
-namespace Mantid {
-namespace Algorithms {
-
-// Register the algorithm into the AlgorithmFactory
-DECLARE_ALGORITHM(SANSDirectBeamScaling)
-
-using namespace Kernel;
-using namespace API;
-using namespace Geometry;
-using namespace DataObjects;
-
-void SANSDirectBeamScaling::init() {
-  auto wsValidator = boost::make_shared<CompositeValidator>();
-  wsValidator->add<WorkspaceUnitValidator>("Wavelength");
-  wsValidator->add<HistogramValidator>();
-  declareProperty(make_unique<WorkspaceProperty<>>(
-      "InputWorkspace", "", Direction::Input, wsValidator));
-
-  auto mustBePositive = boost::make_shared<BoundedValidator<double>>();
-  mustBePositive->setLower(0.0);
-  declareProperty("AttenuatorTransmission", 1.0, mustBePositive,
-                  "Attenuator transmission for empty direct beam.");
-  declareProperty("AttenuatorTransmissionError", 0.0, mustBePositive,
-                  "Uncertainty in attenuator transmission.");
-  declareProperty("BeamRadius", 0.03, mustBePositive,
-                  "Radius of the beam stop [m].");
-
-  // Source aperture radius in meters
-  declareProperty("SourceApertureRadius", 0.04, mustBePositive,
-                  "Source aperture to be used if it is not found in the "
-                  "instrument parameters [m].");
-
-  // Sample aperture radius in meters
-  declareProperty("SampleApertureRadius", 0.008, mustBePositive,
-                  "Sample aperture to be used if it is not found in the "
-                  "instrument parameters [m].");
-
-  // Detector ID of the monitor
-  auto zeroOrMore = boost::make_shared<BoundedValidator<int>>();
-  zeroOrMore->setLower(0);
-  declareProperty("BeamMonitor", 1, zeroOrMore,
-                  "The UDET of the incident beam monitor.");
-
-  declareProperty(make_unique<ArrayProperty<double>>(
-                      "ScaleFactor", boost::make_shared<NullValidator>(),
-                      Direction::Output),
-                  "Scale factor value and uncertainty [n/(monitor "
-                  "count)/(cm^2)/steradian].");
-}
-
-void SANSDirectBeamScaling::exec() {
-  MatrixWorkspace_const_sptr inputWS = getProperty("InputWorkspace");
-  const double beamRadius = getProperty("BeamRadius");
-  const double attTrans = getProperty("AttenuatorTransmission");
-  const double attTransErr = getProperty("AttenuatorTransmissionError");
-
-  // Extract the required spectra into separate workspaces
-  std::vector<detid_t> udet;
-  udet.push_back(getProperty("BeamMonitor"));
-  // Convert UDETs to workspace indices
-  auto index = inputWS->getIndicesFromDetectorIDs(udet);
-  if (index.empty()) {
-    g_log.debug() << "inputWS->getIndicesFromDetectorIDs() returned empty\n";
-    throw std::invalid_argument(
-        "Could not find the incident beam monitor spectra\n");
-  }
-
-  const int64_t numHists = inputWS->getNumberHistograms();
-  Progress progress(this, 0.0, 1.0, numHists);
-
-  // Number of X bins
-  const int64_t xLength = inputWS->y(0).size();
-
-  // Monitor counts
-  double monitor = 0.0;
-  const auto &MonIn = inputWS->y(index[0]);
-  for (int64_t j = 0; j < xLength; j++)
-    monitor += MonIn[j];
-
-  const V3D sourcePos = inputWS->getInstrument()->getSource()->getPos();
-  double counts = 0.0;
-  double error = 0.0;
-  int nPixels = 0;
-
-  // Sample-detector distance for the contributing pixels
-  double sdd = 0.0;
-
-  const auto &spectrumInfo = inputWS->spectrumInfo();
-  for (int64_t i = 0; i < int64_t(numHists); ++i) {
-    if (!spectrumInfo.hasDetectors(i)) {
-      g_log.warning() << "Workspace index " << i
-                      << " has no detector assigned to it - discarding\n";
-      continue;
-    }
-
-    // Skip if we have a monitor or if the detector is masked.
-    if (spectrumInfo.isMonitor(i) || spectrumInfo.isMasked(i))
-      continue;
-
-    const auto &YIn = inputWS->y(i);
-    const auto &EIn = inputWS->e(i);
-
-    // Sum up all the counts
-    V3D pos = spectrumInfo.position(i) - V3D(sourcePos.X(), sourcePos.Y(), 0.0);
-    const double pixelDistance = pos.Z();
-    pos.setZ(0.0);
-    if (pos.norm() <= beamRadius) {
-      // Correct data for all X bins
-      for (int64_t j = 0; j < xLength; j++) {
-        counts += YIn[j];
-        error += EIn[j] * EIn[j];
-      }
-      nPixels += 1;
-      sdd += pixelDistance;
-    }
-    progress.report("Absolute Scaling");
-  }
-  if (0 == nPixels)
-    throw std::runtime_error(
-        "The number of pixels found is 0 which seems to "
-        "indicate that something went wrong. Does the "
-        "input workspace have any histogram, and valid pixels for them?");
-
-  // Get the average SDD for the counted pixels, and transform to mm.
-  sdd = sdd / nPixels * 1000.0;
-  error = std::sqrt(error);
-
-  // Transform from m to mm
-  double sourceAperture = getProperty("SourceApertureRadius");
-  sourceAperture *= 1000.0;
-  // Transform from m to mm
-  double sampleAperture = getProperty("SampleApertureRadius");
-  sampleAperture *= 1000.0;
-  // TODO: replace this by some meaningful value
-  const double KCG2FluxPerMon_SUGAR = 1.0;
-
-  // Solid angle correction scale in 1/(cm^2)/steradian
-  double solidAngleCorrScale = sdd / (M_PI * sourceAperture * sampleAperture);
-  solidAngleCorrScale = solidAngleCorrScale * solidAngleCorrScale * 100.0;
-
-  // Scaling factor in n/(monitor count)/(cm^2)/steradian
-  double scale = counts / monitor * solidAngleCorrScale / KCG2FluxPerMon_SUGAR;
-  double scaleErr =
-      std::abs(error / monitor) * solidAngleCorrScale / KCG2FluxPerMon_SUGAR;
-
-  scaleErr = std::abs(scale / attTrans) *
-             sqrt((scaleErr / scale) * (scaleErr / scale) +
-                  (attTransErr / attTrans) * (attTransErr / attTrans));
-  scale /= attTrans;
-
-  std::vector<double> output;
-  output.push_back(scale);
-  output.push_back(scaleErr);
-  setProperty("ScaleFactor", output);
-}
-
-} // namespace Algorithms
-} // namespace Mantid
diff --git a/Framework/Algorithms/src/SampleCorrections/MCAbsorptionStrategy.cpp b/Framework/Algorithms/src/SampleCorrections/MCAbsorptionStrategy.cpp
index 2bac0f324cfc9055ac3db231f76bd1df9e44ff17..f4a73febff75595e268cc3eaf37e0d3bd7368279 100644
--- a/Framework/Algorithms/src/SampleCorrections/MCAbsorptionStrategy.cpp
+++ b/Framework/Algorithms/src/SampleCorrections/MCAbsorptionStrategy.cpp
@@ -25,7 +25,9 @@ namespace Algorithms {
 MCAbsorptionStrategy::MCAbsorptionStrategy(const IBeamProfile &beamProfile,
                                            const API::Sample &sample,
                                            size_t nevents)
-    : m_beamProfile(beamProfile), m_scatterVol(MCInteractionVolume(sample)),
+    : m_beamProfile(beamProfile),
+      m_scatterVol(
+          MCInteractionVolume(sample, beamProfile.defineActiveRegion(sample))),
       m_nevents(nevents), m_error(1.0 / std::sqrt(m_nevents)) {}
 
 /**
@@ -42,19 +44,15 @@ std::tuple<double, double>
 MCAbsorptionStrategy::calculate(Kernel::PseudoRandomNumberGenerator &rng,
                                 const Kernel::V3D &finalPos,
                                 double lambdaBefore, double lambdaAfter) const {
-  // The simulation consists of sampling the beam profile and then computing the
-  // absorption within the interacting volume defined by the sample (and
-  // environment. The final correction factor is computed as the simple average
-  // of m_nevents of this process.
   const auto scatterBounds = m_scatterVol.getBoundingBox();
   double factor(0.0);
   for (size_t i = 0; i < m_nevents; ++i) {
     size_t attempts(0);
     do {
       const auto neutron = m_beamProfile.generatePoint(rng, scatterBounds);
+
       const double wgt = m_scatterVol.calculateAbsorption(
-          rng, neutron.startPos, neutron.unitDir, finalPos, lambdaBefore,
-          lambdaAfter);
+          rng, neutron.startPos, finalPos, lambdaBefore, lambdaAfter);
       if (wgt < 0.0) {
         ++attempts;
       } else {
diff --git a/Framework/Algorithms/src/SampleCorrections/MCInteractionVolume.cpp b/Framework/Algorithms/src/SampleCorrections/MCInteractionVolume.cpp
index 8045cc5c99ce939964480012eef83ad9b5547e1b..3d96995f6d11a9bc4dc6658ba936372f9207f064 100644
--- a/Framework/Algorithms/src/SampleCorrections/MCInteractionVolume.cpp
+++ b/Framework/Algorithms/src/SampleCorrections/MCInteractionVolume.cpp
@@ -13,6 +13,10 @@ using Kernel::V3D;
 namespace Algorithms {
 
 namespace {
+
+// Maximum number of attempts to generate a scatter point
+constexpr size_t MAX_SCATTER_ATTEMPTS = 500;
+
 /**
  * Compute the attenuation factor for the given coefficients
  * @param rho Number density of the sample in \f$\\A^{-3}\f$
@@ -27,12 +31,17 @@ double attenuation(double rho, double sigma, double length) {
 }
 
 /**
- * Construct the volume with only a sample object
+ * Construct the volume encompassing the sample + any environment kit. The
+ * beam profile defines a bounding region for the sampling of the scattering
+ * position.
  * @param sample A reference to a sample object that defines a valid shape
  * & material
+ * @param activeRegion Restrict scattering point sampling to this region
  */
-MCInteractionVolume::MCInteractionVolume(const API::Sample &sample)
-    : m_sample(sample.getShape()), m_env(nullptr) {
+MCInteractionVolume::MCInteractionVolume(
+    const API::Sample &sample, const Geometry::BoundingBox &activeRegion)
+    : m_sample(sample.getShape()), m_env(nullptr),
+      m_activeRegion(activeRegion) {
   if (!m_sample.hasValidShape()) {
     throw std::invalid_argument(
         "MCInteractionVolume() - Sample shape does not have a valid shape.");
@@ -57,11 +66,11 @@ const Geometry::BoundingBox &MCInteractionVolume::getBoundingBox() const {
 }
 
 /**
- * Calculate the attenuation correction factor for given track through the
- * volume
- * @param rng A reference to a PseudoRandomNumberGenerator
+ * Calculate the attenuation correction factor the volume given a start and
+ * end point.
+ * @param rng A reference to a PseudoRandomNumberGenerator producing
+ * random number between [0,1]
  * @param startPos Origin of the initial track
- * @param direc Direction of travel of the neutron
  * @param endPos Final position of neutron after scattering (assumed to be
  * outside of the "volume")
  * @param lambdaBefore Wavelength, in \f$\\A^-1\f$, before scattering
@@ -71,68 +80,59 @@ const Geometry::BoundingBox &MCInteractionVolume::getBoundingBox() const {
  */
 double MCInteractionVolume::calculateAbsorption(
     Kernel::PseudoRandomNumberGenerator &rng, const Kernel::V3D &startPos,
-    const Kernel::V3D &direc, const Kernel::V3D &endPos, double lambdaBefore,
-    double lambdaAfter) const {
-  // Create track with start position and direction and "fire" it through
-  // the sample to produce a number of intersections. Choose a random
-  // intersection and within this section pick a random "depth". This point
-  // is the scatter point.
-  // Form a second track originating at the scatter point and ending at endPos
-  // to give a second set of intersections.
-  // The total attenuation factor is the product of the attenuation factor
-  // for each intersection
-
-  // Generate scatter point
-  Track path1(startPos, direc);
-  int nsegments = m_sample.interceptSurface(path1);
+    const Kernel::V3D &endPos, double lambdaBefore, double lambdaAfter) const {
+  // Generate scatter point. If there is an environment present then
+  // first select whether the scattering occurs on the sample or the
+  // environment. The attenuation for the path leading to the scatter point
+  // is calculated in reverse, i.e. defining the track from the scatter pt
+  // backwards for simplicity with how the Track object works. This avoids
+  // having to understand exactly which object the scattering occurred in.
+  V3D scatterPos;
+  if (m_env && (rng.nextValue() > 0.5)) {
+    scatterPos =
+        m_env->generatePoint(rng, m_activeRegion, MAX_SCATTER_ATTEMPTS);
+  } else {
+    scatterPos = m_sample.generatePointInObject(rng, m_activeRegion,
+                                                MAX_SCATTER_ATTEMPTS);
+  }
+  auto toStart = startPos - scatterPos;
+  toStart.normalize();
+  Track beforeScatter(scatterPos, toStart);
+  int nlinks = m_sample.interceptSurface(beforeScatter);
   if (m_env) {
-    nsegments += m_env->interceptSurfaces(path1);
+    nlinks += m_env->interceptSurfaces(beforeScatter);
   }
-  if (nsegments == 0) {
+  // This should not happen but numerical precision means that it can
+  // occasionally occur with tracks that are very close to the surface
+  if (nlinks == 0) {
     return -1.0;
   }
-  int scatterSegmentNo(1);
-  if (nsegments != 1) {
-    scatterSegmentNo = rng.nextInt(1, nsegments);
-  }
 
-  double atten(1.0);
-  V3D scatterPos;
-  auto segItr(path1.cbegin());
-  for (int i = 0; i < scatterSegmentNo; ++i, ++segItr) {
-    double length = segItr->distInsideObject;
-    if (i == scatterSegmentNo - 1) {
-      length *= rng.nextValue();
-      scatterPos = segItr->entryPoint + direc * length;
+  // Function to calculate total attenuation for a track
+  auto calculateAttenuation = [](const Track &path, double lambda) {
+    double factor(1.0);
+    for (const auto &segment : path) {
+      const double length = segment.distInsideObject;
+      const auto &segObj = *(segment.object);
+      const auto &segMat = segObj.material();
+      factor *= attenuation(segMat.numberDensity(),
+                            segMat.totalScatterXSection(lambda) +
+                                segMat.absorbXSection(lambda),
+                            length);
     }
-    const auto &segObj = *(segItr->object);
-    const auto &segMat = segObj.material();
-    atten *= attenuation(segMat.numberDensity(),
-                         segMat.totalScatterXSection(lambdaBefore) +
-                             segMat.absorbXSection(lambdaBefore),
-                         length);
-  }
+    return factor;
+  };
 
   // Now track to final destination
   V3D scatteredDirec = endPos - scatterPos;
   scatteredDirec.normalize();
-  Track path2(scatterPos, scatteredDirec);
-  m_sample.interceptSurface(path2);
+  Track afterScatter(scatterPos, scatteredDirec);
+  m_sample.interceptSurface(afterScatter);
   if (m_env) {
-    m_env->interceptSurfaces(path2);
+    m_env->interceptSurfaces(afterScatter);
   }
-
-  for (const auto &segment : path2) {
-    double length = segment.distInsideObject;
-    const auto &segObj = *(segment.object);
-    const auto &segMat = segObj.material();
-    atten *= attenuation(segMat.numberDensity(),
-                         segMat.totalScatterXSection(lambdaAfter) +
-                             segMat.absorbXSection(lambdaAfter),
-                         length);
-  }
-
-  return atten;
+  return calculateAttenuation(beforeScatter, lambdaBefore) *
+         calculateAttenuation(afterScatter, lambdaAfter);
 }
 
 } // namespace Algorithms
diff --git a/Framework/Algorithms/src/SampleCorrections/MayersSampleCorrection.cpp b/Framework/Algorithms/src/SampleCorrections/MayersSampleCorrection.cpp
index f4e353e0230cc2d8ad3768ee8939f93842c285c1..83c6b287d13414431f168da69bdf7166b7228b03 100644
--- a/Framework/Algorithms/src/SampleCorrections/MayersSampleCorrection.cpp
+++ b/Framework/Algorithms/src/SampleCorrections/MayersSampleCorrection.cpp
@@ -3,6 +3,7 @@
 #include "MantidAPI/InstrumentValidator.h"
 #include "MantidAPI/Sample.h"
 #include "MantidAPI/SampleValidator.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidGeometry/IDetector.h"
 #include "MantidGeometry/Instrument.h"
@@ -10,6 +11,8 @@
 #include "MantidKernel/CompositeValidator.h"
 #include "MantidKernel/Material.h"
 
+#include <cmath>
+
 namespace Mantid {
 namespace Algorithms {
 
@@ -62,6 +65,16 @@ void MayersSampleCorrection::init() {
       "If True then also correct for the effects of multiple scattering."
       "Please note that the MS correction assumes the scattering is elastic.",
       Direction::Input);
+  declareProperty("MSEvents", 10000, "Controls the number of second-scatter "
+                                     "events generated. Only applicable where "
+                                     "MultipleScattering=True.",
+                  Direction::Input);
+  declareProperty("MSRuns", 10,
+                  "Controls the number of simulations, each containing "
+                  "MSEvents, performed. The final MS correction is "
+                  "computed as the average over the runs. Only applicable"
+                  "where MultipleScattering=True.",
+                  Direction::Input);
   // Outputs
   declareProperty(Kernel::make_unique<WorkspaceProperty<>>(
                       "OutputWorkspace", "", Direction::Output),
@@ -73,17 +86,16 @@ void MayersSampleCorrection::init() {
 void MayersSampleCorrection::exec() {
   using API::Progress;
   using API::WorkspaceFactory;
+
   MatrixWorkspace_sptr inputWS = getProperty("InputWorkspace");
-  bool mscatOn = getProperty("MultipleScattering");
-  MatrixWorkspace_sptr outputWS = WorkspaceFactory::Instance().create(inputWS);
+  const bool mscatOn = getProperty("MultipleScattering");
+  const int msEvents = getProperty("MSEvents");
+  const int msRuns = getProperty("MSRuns");
 
+  MatrixWorkspace_sptr outputWS = WorkspaceFactory::Instance().create(inputWS);
   // Instrument constants
   auto instrument = inputWS->getInstrument();
-  const auto source = instrument->getSource();
-  const auto sample = instrument->getSample();
-  const auto beamLine = sample->getPos() - source->getPos();
   const auto frame = instrument->getReferenceFrame();
-  const double l1 = sample->getDistance(*source);
 
   // Sample
   const auto &sampleShape = inputWS->sample().getShape();
@@ -101,30 +113,37 @@ void MayersSampleCorrection::exec() {
   Progress prog(this, 0., 1., nhist);
   prog.setNotifyStep(0.01);
 
+  const auto &spectrumInfo = inputWS->spectrumInfo();
+
   PARALLEL_FOR_IF(Kernel::threadSafe(*inputWS, *outputWS))
   for (int64_t i = 0; i < static_cast<int64_t>(nhist); ++i) {
     PARALLEL_START_INTERUPT_REGION
 
-    IDetector_const_sptr det;
-    try {
-      det = inputWS->getDetector(i);
-    } catch (Exception::NotFoundError &) {
+    if (!spectrumInfo.hasDetectors(i) || spectrumInfo.isMonitor(i) ||
+        spectrumInfo.isMasked(i)) {
       continue;
     }
-    if (det->isMonitor() || det->isMasked())
-      continue;
 
     MayersSampleCorrectionStrategy::Parameters params;
     params.mscat = mscatOn;
-    params.l1 = l1;
-    params.l2 = det->getDistance(*sample);
-    params.twoTheta = det->getTwoTheta(sample->getPos(), beamLine);
-    params.phi = det->getPhi();
+    params.l1 = spectrumInfo.l1();
+    params.l2 = spectrumInfo.l2(i);
+    params.twoTheta = spectrumInfo.twoTheta(i);
+    // Code requires angle above/below scattering plane not our definition of
+    // phi
+    const auto pos = spectrumInfo.position(i);
+    // Theta here is the angle between beam and neutron path not necessarily
+    // twoTheta if sample not at origin
+    double _(0.0), theta(0.0), phi(0.0);
+    pos.getSpherical(_, theta, phi);
+    params.azimuth = asin(sin(theta) * sin(phi));
     params.rho = sampleMaterial.numberDensity();
     params.sigmaAbs = sampleMaterial.absorbXSection();
     params.sigmaSc = sampleMaterial.totalScatterXSection();
     params.cylRadius = radius;
     params.cylHeight = height;
+    params.msNEvents = static_cast<size_t>(msEvents);
+    params.msNRuns = static_cast<size_t>(msRuns);
 
     MayersSampleCorrectionStrategy correction(params, inputWS->histogram(i));
     outputWS->setHistogram(i, correction.getCorrectedHisto());
diff --git a/Framework/Algorithms/src/SampleCorrections/MayersSampleCorrectionStrategy.cpp b/Framework/Algorithms/src/SampleCorrections/MayersSampleCorrectionStrategy.cpp
index b04e7147902a9bf3f9639951c8787643fbd63bbc..f9cce68e36b9857c75fc927a12b06c66814bcf2b 100644
--- a/Framework/Algorithms/src/SampleCorrections/MayersSampleCorrectionStrategy.cpp
+++ b/Framework/Algorithms/src/SampleCorrections/MayersSampleCorrectionStrategy.cpp
@@ -25,8 +25,6 @@ size_t N_MUR_PTS = 21;
 size_t N_RAD = 29;
 /// Number of theta points for cylindrical integration
 size_t N_THETA = 29;
-/// Number of second order event points
-size_t N_SECOND = 10000;
 /// Order of polynomial used to fit generated points
 size_t N_POLY_ORDER = 4;
 /// 2pi
@@ -189,6 +187,7 @@ MayersSampleCorrectionStrategy::calculateSelfAttenuation(const double muR) {
   const double dyr = muR / to<double>(N_RAD - 1);
   const double dyth = TWOPI / to<double>(N_THETA - 1);
   const double muRSq = muR * muR;
+  const double cosaz = cos(m_pars.azimuth);
 
   // Store values at each point
   std::vector<double> yr(N_RAD), yth(N_THETA);
@@ -208,7 +207,7 @@ MayersSampleCorrectionStrategy::calculateSelfAttenuation(const double muR) {
       if (fact2 < 0.0)
         fact2 = 0.0;
       const double mul2 =
-          (sqrt(fact2) - r0 * cos(m_pars.twoTheta - theta)) / cos(m_pars.phi);
+          (sqrt(fact2) - r0 * cos(m_pars.twoTheta - theta)) / cosaz;
       yth[j] = exp(-mul1 - mul2);
     }
 
@@ -231,15 +230,15 @@ MayersSampleCorrectionStrategy::calculateMS(const size_t irp, const double muR,
   // Radial coordinate raised to power 1/3 to ensure uniform density of points
   // across circle following discussion with W.G.Marshall (ISIS)
   const double radDistPower = 1. / 3.;
-  double muH = muR * (m_pars.cylHeight / m_pars.cylRadius);
+  const double muH = muR * (m_pars.cylHeight / m_pars.cylRadius);
+  const double cosaz = cos(m_pars.azimuth);
   seedRNG(irp);
 
   // Take an average over a number of sets of second scatters
-  const size_t nsets(10);
-  std::vector<double> deltas(nsets, 0.0);
-  for (size_t j = 0; j < nsets; ++j) {
+  std::vector<double> deltas(m_pars.msNRuns, 0.0);
+  for (size_t j = 0; j < m_pars.msNRuns; ++j) {
     double sum = 0.0;
-    for (size_t i = 0; i < N_SECOND; ++i) {
+    for (size_t i = 0; i < m_pars.msNEvents; ++i) {
       // Random (r,theta,z)
       const double r1 = pow(m_rng->nextValue(), radDistPower) * muR;
       const double r2 = pow(m_rng->nextValue(), radDistPower) * muR;
@@ -257,7 +256,7 @@ MayersSampleCorrectionStrategy::calculateMS(const size_t irp, const double muR,
         fact2 = 0.0;
       // Path out from final point
       const double mul2 =
-          (sqrt(fact2) - r2 * cos(m_pars.twoTheta - th2)) / cos(m_pars.phi);
+          (sqrt(fact2) - r2 * cos(m_pars.twoTheta - th2)) / cosaz;
       // Path between point 1 & 2
       const double mul12 =
           sqrt(pow(r1 * cos(th1) - r2 * cos(th2), 2) +
@@ -267,7 +266,7 @@ MayersSampleCorrectionStrategy::calculateMS(const size_t irp, const double muR,
       sum += exp(-(mul1 + mul2 + mul12)) / pow(mul12, 2);
     }
     const double beta =
-        pow(M_PI * muR * muR * muH, 2) * sum / to<double>(N_SECOND);
+        pow(M_PI * muR * muR * muH, 2) * sum / to<double>(m_pars.msNEvents);
     const double delta = 0.25 * beta / (M_PI * abs * muH);
     deltas[j] = delta;
   }
diff --git a/Framework/Algorithms/src/SampleCorrections/RectangularBeamProfile.cpp b/Framework/Algorithms/src/SampleCorrections/RectangularBeamProfile.cpp
index 5fe679a20237a1a1956b8b3c511cbcc38ce5da9c..b3aa0b2168d826c9b6c507eb66a2176a538befa2 100644
--- a/Framework/Algorithms/src/SampleCorrections/RectangularBeamProfile.cpp
+++ b/Framework/Algorithms/src/SampleCorrections/RectangularBeamProfile.cpp
@@ -1,5 +1,7 @@
 #include "MantidAlgorithms/SampleCorrections/RectangularBeamProfile.h"
+#include "MantidAPI/Sample.h"
 #include "MantidGeometry/Instrument/ReferenceFrame.h"
+#include "MantidGeometry/Instrument/SampleEnvironment.h"
 #include "MantidGeometry/Objects/BoundingBox.h"
 #include "MantidKernel/PseudoRandomNumberGenerator.h"
 #include "MantidKernel/V3D.h"
@@ -70,5 +72,34 @@ IBeamProfile::Ray RectangularBeamProfile::generatePoint(
   return rngRay;
 }
 
+/**
+ * Compute a region that defines how the beam illuminates the given sample/can
+ * @param sample A reference to a sample object holding its shape
+ * @return A BoundingBox defining the active region
+ */
+Geometry::BoundingBox
+RectangularBeamProfile::defineActiveRegion(const API::Sample &sample) const {
+  auto sampleBox = sample.getShape().getBoundingBox();
+  try {
+    const auto &envBox = sample.getEnvironment().boundingBox();
+    sampleBox.grow(envBox);
+  } catch (std::runtime_error &) {
+  }
+  // In the beam direction use the maximum sample extent other wise restrict
+  // the active region to the width/height of beam
+  const auto &sampleMin(sampleBox.minPoint());
+  const auto &sampleMax(sampleBox.maxPoint());
+  V3D minPoint, maxPoint;
+  minPoint[m_horIdx] = m_min[m_horIdx];
+  maxPoint[m_horIdx] = m_min[m_horIdx] + m_width;
+  minPoint[m_upIdx] = m_min[m_upIdx];
+  maxPoint[m_upIdx] = m_min[m_upIdx] + m_height;
+  minPoint[m_beamIdx] = sampleMin[m_beamIdx];
+  maxPoint[m_beamIdx] = sampleMax[m_beamIdx];
+
+  return Geometry::BoundingBox(maxPoint.X(), maxPoint.Y(), maxPoint.Z(),
+                               minPoint.X(), minPoint.Y(), minPoint.Z());
+}
+
 } // namespace Algorithms
 } // namespace Mantid
diff --git a/Framework/Algorithms/src/SmoothNeighbours.cpp b/Framework/Algorithms/src/SmoothNeighbours.cpp
index d6e4fd4f366357ead20ebd99b0d944d3b8c37b9f..7cb6006d0abf01f2c91ab4bb00022de668edb42d 100644
--- a/Framework/Algorithms/src/SmoothNeighbours.cpp
+++ b/Framework/Algorithms/src/SmoothNeighbours.cpp
@@ -1,6 +1,8 @@
 #include "MantidAlgorithms/SmoothNeighbours.h"
+#include "MantidAPI/DetectorInfo.h"
 #include "MantidAPI/InstrumentValidator.h"
 #include "MantidAPI/NearestNeighbourInfo.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidDataObjects/EventList.h"
 #include "MantidDataObjects/EventWorkspace.h"
@@ -332,7 +334,6 @@ void SmoothNeighbours::findNeighboursUbiqutious() {
   // Cull by radius
   RadiusFilter radiusFilter(Radius);
 
-  IDetector_const_sptr det;
   // Go through every input workspace pixel
   outWI = 0;
   int sum = getProperty("SumNumberOfNeighbours");
@@ -343,6 +344,7 @@ void SmoothNeighbours::findNeighboursUbiqutious() {
     for (size_t wi = 0; wi < inWS->getNumberHistograms(); wi++)
       used[wi] = false;
   }
+  const auto &detectorInfo = inWS->detectorInfo();
   for (size_t wi = 0; wi < inWS->getNumberHistograms(); wi++) {
     if (sum > 1)
       if (used[wi])
@@ -351,10 +353,10 @@ void SmoothNeighbours::findNeighboursUbiqutious() {
     try {
       // Get the list of detectors in this pixel
       const auto &dets = inWS->getSpectrum(wi).getDetectorIDs();
-      det = inst->getDetector(*dets.begin());
-      if (det->isMonitor())
+      const auto index = detectorInfo.indexOf(*dets.begin());
+      if (detectorInfo.isMonitor(index))
         continue; // skip monitor
-      if (det->isMasked()) {
+      if (detectorInfo.isMasked(index)) {
         // Calibration masks many detectors, but there should be 0s after
         // smoothing
         if (sum == 1)
@@ -362,7 +364,8 @@ void SmoothNeighbours::findNeighboursUbiqutious() {
         continue; // skip masked detectors
       }
       if (sum > 1) {
-        parent = det->getParent();
+        const auto &det = detectorInfo.detector(index);
+        parent = det.getParent();
         if (parent)
           grandparent = parent->getParent();
       }
@@ -404,8 +407,8 @@ void SmoothNeighbours::findNeighboursUbiqutious() {
             // Get the list of detectors in this pixel
             const std::set<detid_t> &dets =
                 inWS->getSpectrum(neighWI).getDetectorIDs();
-            det = inst->getDetector(*dets.begin());
-            neighbParent = det->getParent();
+            const auto &det = detectorInfo.detector(*dets.begin());
+            neighbParent = det.getParent();
             neighbGParent = neighbParent->getParent();
             if (noNeigh >= sum ||
                 neighbParent->getName().compare(parent->getName()) != 0 ||
@@ -510,10 +513,10 @@ double SmoothNeighbours::translateToMeters(const std::string radiusUnits,
     Instrument_const_sptr instrument = fetchInstrument();
 
     // Get the first idetector from the workspace index 0.
-    IDetector_const_sptr firstDet = inWS->getDetector(0);
+    const auto &firstDet = inWS->spectrumInfo().detector(0);
     // Find the bounding box of that detector
     BoundingBox bbox;
-    firstDet->getBoundingBox(bbox);
+    firstDet.getBoundingBox(bbox);
     // Multiply (meters/pixels) by number of pixels, note that enteredRadius
     // takes on meaning of the number of pixels.
     translatedRadius = bbox.width().norm() * enteredRadius;
@@ -679,7 +682,7 @@ void SmoothNeighbours::execWorkspace2D() {
   */
 void SmoothNeighbours::setupNewInstrument(MatrixWorkspace_sptr outws) {
   // Copy geometry over.
-  API::WorkspaceFactory::Instance().initializeFromParent(inWS, outws, false);
+  API::WorkspaceFactory::Instance().initializeFromParent(*inWS, *outws, false);
 
   // Go through all the output workspace
   size_t numberOfSpectra = outws->getNumberHistograms();
@@ -720,7 +723,7 @@ void SmoothNeighbours::spreadPixels(MatrixWorkspace_sptr outws) {
   }
 
   // Copy geometry over.
-  API::WorkspaceFactory::Instance().initializeFromParent(inWS, outws2, false);
+  API::WorkspaceFactory::Instance().initializeFromParent(*inWS, *outws2, false);
   // Go through all the input workspace
   for (int outWIi = 0; outWIi < int(numberOfSpectra); outWIi++) {
     const auto &inSpec = inWS->getSpectrum(outWIi);
@@ -759,7 +762,7 @@ void SmoothNeighbours::execEvent(Mantid::DataObjects::EventWorkspace_sptr ws) {
       API::WorkspaceFactory::Instance().create(
           "EventWorkspace", numberOfSpectra, YLength + 1, YLength));
   // Copy geometry over.
-  API::WorkspaceFactory::Instance().initializeFromParent(ws, outWS, false);
+  API::WorkspaceFactory::Instance().initializeFromParent(*ws, *outWS, false);
   // Ensure thread-safety
   outWS->sortAll(TOF_SORT, nullptr);
 
diff --git a/Framework/Algorithms/src/SofQWCentre.cpp b/Framework/Algorithms/src/SofQWCentre.cpp
index 23f122bcfa1c558c8be288edbc61f895ddf92e74..d89214e7f522a2b90f7b22e8daab01fbf6df58c0 100644
--- a/Framework/Algorithms/src/SofQWCentre.cpp
+++ b/Framework/Algorithms/src/SofQWCentre.cpp
@@ -2,10 +2,12 @@
 #include "MantidDataObjects/Histogram1D.h"
 #include "MantidAPI/BinEdgeAxis.h"
 #include "MantidAPI/CommonBinsValidator.h"
+#include "MantidAPI/DetectorInfo.h"
 #include "MantidAPI/HistogramValidator.h"
 #include "MantidAPI/InstrumentValidator.h"
 #include "MantidAPI/SpectraAxisValidator.h"
 #include "MantidAPI/SpectrumDetectorMapping.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidAPI/WorkspaceUnitValidator.h"
 #include "MantidGeometry/Instrument.h"
@@ -92,7 +94,7 @@ void SofQWCentre::exec() {
   MatrixWorkspace_const_sptr inputWorkspace = getProperty("InputWorkspace");
 
   // Do the full check for common binning
-  if (!WorkspaceHelpers::commonBoundaries(inputWorkspace)) {
+  if (!WorkspaceHelpers::commonBoundaries(*inputWorkspace)) {
     g_log.error(
         "The input workspace must have common binning across all spectra");
     throw std::invalid_argument(
@@ -111,24 +113,12 @@ void SofQWCentre::exec() {
   m_EmodeProperties.initCachedValues(*inputWorkspace, this);
   int emode = m_EmodeProperties.m_emode;
 
-  // Get a pointer to the instrument contained in the workspace
-  Instrument_const_sptr instrument = inputWorkspace->getInstrument();
-
-  // Get the distance between the source and the sample (assume in metres)
-  IComponent_const_sptr source = instrument->getSource();
-  IComponent_const_sptr sample = instrument->getSample();
-  V3D beamDir = sample->getPos() - source->getPos();
+  const auto &detectorInfo = inputWorkspace->detectorInfo();
+  const auto &spectrumInfo = inputWorkspace->spectrumInfo();
+  V3D beamDir = detectorInfo.samplePosition() - detectorInfo.sourcePosition();
   beamDir.normalize();
-
-  try {
-    double l1 = source->getDistance(*sample);
-    g_log.debug() << "Source-sample distance: " << l1 << '\n';
-  } catch (Exception::NotFoundError &) {
-    g_log.error("Unable to calculate source-sample distance");
-    throw Exception::InstrumentDefinitionError(
-        "Unable to calculate source-sample distance",
-        inputWorkspace->getTitle());
-  }
+  double l1 = detectorInfo.l1();
+  g_log.debug() << "Source-sample distance: " << l1 << '\n';
 
   // Conversion constant for E->k. k(A^-1) = sqrt(energyToK*E(meV))
   const double energyToK = 8.0 * M_PI * M_PI * PhysicalConstants::NeutronMass *
@@ -141,40 +131,31 @@ void SofQWCentre::exec() {
   const size_t numBins = inputWorkspace->blocksize();
   Progress prog(this, 0.0, 1.0, numHists);
   for (int64_t i = 0; i < int64_t(numHists); ++i) {
-    try {
-      // Now get the detector object for this histogram
-      IDetector_const_sptr spectrumDet = inputWorkspace->getDetector(i);
-      if (spectrumDet->isMonitor())
-        continue;
-
-      const double efixed = m_EmodeProperties.getEFixed(*spectrumDet);
-
-      // For inelastic scattering the simple relationship q=4*pi*sinTheta/lambda
-      // does not hold. In order to
-      // be completely general we must calculate the momentum transfer by
-      // calculating the incident and final
-      // wave vectors and then use |q| = sqrt[(ki - kf)*(ki - kf)]
-      DetectorGroup_const_sptr detGroup =
-          boost::dynamic_pointer_cast<const DetectorGroup>(spectrumDet);
-      std::vector<IDetector_const_sptr> detectors;
-      if (detGroup) {
-        detectors = detGroup->getDetectors();
-      } else {
-        detectors.push_back(spectrumDet);
-      }
-
-      const size_t numDets = detectors.size();
-      // cache to reduce number of static casts
-      const double numDets_d = static_cast<double>(numDets);
-      const auto &Y = inputWorkspace->y(i);
-      const auto &E = inputWorkspace->e(i);
-      const auto &X = inputWorkspace->x(i);
+    if (!spectrumInfo.hasDetectors(i) || spectrumInfo.isMonitor(i))
+      continue;
 
-      // Loop over the detectors and for each bin calculate Q
-      for (size_t idet = 0; idet < numDets; ++idet) {
-        IDetector_const_sptr det = detectors[idet];
+    const auto &spectrumDet = spectrumInfo.detector(i);
+    const double efixed = m_EmodeProperties.getEFixed(spectrumDet);
+
+    // For inelastic scattering the simple relationship q=4*pi*sinTheta/lambda
+    // does not hold. In order to
+    // be completely general we must calculate the momentum transfer by
+    // calculating the incident and final
+    // wave vectors and then use |q| = sqrt[(ki - kf)*(ki - kf)]
+
+    const auto &detIDs = inputWorkspace->getSpectrum(i).getDetectorIDs();
+    double numDets_d = static_cast<double>(detIDs.size());
+    const auto &Y = inputWorkspace->y(i);
+    const auto &E = inputWorkspace->e(i);
+    const auto &X = inputWorkspace->x(i);
+
+    // Loop over the detectors and for each bin calculate Q
+    for (const auto detID : detIDs) {
+      try {
+        size_t idet = detectorInfo.indexOf(detID);
         // Calculate kf vector direction and then Q for each energy bin
-        V3D scatterDir = (det->getPos() - sample->getPos());
+        V3D scatterDir =
+            (detectorInfo.position(idet) - detectorInfo.samplePosition());
         scatterDir.normalize();
         for (size_t j = 0; j < numBins; ++j) {
           const double deltaE = 0.5 * (X[j] + X[j + 1]);
@@ -227,7 +208,7 @@ void SofQWCentre::exec() {
           // Add this spectra-detector pair to the mapping
           specNumberMapping.push_back(
               outputWorkspace->getSpectrum(qIndex).getSpectrumNo());
-          detIDMapping.push_back(det->getID());
+          detIDMapping.push_back(detID);
 
           // And add the data and it's error to that bin, taking into account
           // the number of detectors contributing to this bin
@@ -237,13 +218,11 @@ void SofQWCentre::exec() {
               sqrt((pow(outputWorkspace->e(qIndex)[j], 2) + pow(E[j], 2)) /
                    numDets_d);
         }
+      } catch (std::out_of_range &) {
+        // Skip invalid detector IDs
+        numDets_d -= 1.0;
+        continue;
       }
-
-    } catch (Exception::NotFoundError &) {
-      // Get to here if exception thrown when calculating distance to detector
-      // Presumably, if we get to here the spectrum will be all zeroes anyway
-      // (from conversion to E)
-      continue;
     }
     prog.report();
   }
diff --git a/Framework/Algorithms/src/SofQWNormalisedPolygon.cpp b/Framework/Algorithms/src/SofQWNormalisedPolygon.cpp
index c3873ef09adceebf2d1214555028dc424c7ca503..f48ec4225a508478c76fe69fc72e4bf787e1bd91 100644
--- a/Framework/Algorithms/src/SofQWNormalisedPolygon.cpp
+++ b/Framework/Algorithms/src/SofQWNormalisedPolygon.cpp
@@ -3,11 +3,16 @@
 #include "MantidAPI/BinEdgeAxis.h"
 #include "MantidAPI/NearestNeighbourInfo.h"
 #include "MantidAPI/SpectrumDetectorMapping.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidDataObjects/FractionalRebinning.h"
+#include "MantidDataObjects/WorkspaceCreation.h"
 #include "MantidGeometry/Instrument.h"
 #include "MantidGeometry/Instrument/DetectorGroup.h"
 #include "MantidGeometry/Instrument/ReferenceFrame.h"
+#include "MantidGeometry/Objects/BoundingBox.h"
+#include "MantidGeometry/Objects/Object.h"
+#include "MantidIndexing/IndexInfo.h"
 #include "MantidKernel/UnitFactory.h"
 #include "MantidKernel/VectorHelper.h"
 
@@ -61,21 +66,21 @@ void SofQWNormalisedPolygon::init() {
 void SofQWNormalisedPolygon::exec() {
   MatrixWorkspace_sptr inputWS = getProperty("InputWorkspace");
   // Do the full check for common binning
-  if (!WorkspaceHelpers::commonBoundaries(inputWS)) {
+  if (!WorkspaceHelpers::commonBoundaries(*inputWS)) {
     throw std::invalid_argument(
         "The input workspace must have common binning across all spectra");
   }
 
   RebinnedOutput_sptr outputWS =
-      this->setUpOutputWorkspace(inputWS, getProperty("QAxisBinning"), m_Qout);
+      this->setUpOutputWorkspace(*inputWS, getProperty("QAxisBinning"), m_Qout);
   g_log.debug() << "Workspace type: " << outputWS->id() << '\n';
   setProperty("OutputWorkspace", outputWS);
   const size_t nEnergyBins = inputWS->blocksize();
   const size_t nHistos = inputWS->getNumberHistograms();
 
   // Holds the spectrum-detector mapping
-  std::vector<specnum_t> specNumberMapping;
-  std::vector<detid_t> detIDMapping;
+  std::vector<std::vector<detid_t>> detIDMapping(
+      outputWS->getNumberHistograms());
 
   // Progress reports & cancellation
   const size_t nreports(nHistos * nEnergyBins);
@@ -99,14 +104,16 @@ void SofQWNormalisedPolygon::exec() {
   const auto &X = inputWS->x(0);
   int emode = m_EmodeProperties.m_emode;
 
+  const auto &inputIndices = inputWS->indexInfo();
+  const auto &spectrumInfo = inputWS->spectrumInfo();
+
   PARALLEL_FOR_IF(Kernel::threadSafe(*inputWS, *outputWS))
   for (int64_t i = 0; i < static_cast<int64_t>(nHistos);
        ++i) // signed for openmp
   {
     PARALLEL_START_INTERUPT_REGION
 
-    DetConstPtr detector = inputWS->getDetector(i);
-    if (detector->isMasked() || detector->isMonitor()) {
+    if (spectrumInfo.isMasked(i) || spectrumInfo.isMonitor(i)) {
       continue;
     }
 
@@ -125,8 +132,8 @@ void SofQWNormalisedPolygon::exec() {
     const double phiLower = phi - phiHalfWidth;
     const double phiUpper = phi + phiHalfWidth;
 
-    const double efixed = m_EmodeProperties.getEFixed(*detector);
-    const specnum_t specNo = inputWS->getSpectrum(i).getSpectrumNo();
+    const double efixed = m_EmodeProperties.getEFixed(spectrumInfo.detector(i));
+    const specnum_t specNo = inputIndices.spectrumNumber(i);
     std::stringstream logStream;
     for (size_t j = 0; j < nEnergyBins; ++j) {
       m_progress->report("Computing polygon intersections");
@@ -163,9 +170,7 @@ void SofQWNormalisedPolygon::exec() {
       if (qIndex != 0 && qIndex < static_cast<int>(m_Qout.size())) {
         // Add this spectra-detector pair to the mapping
         PARALLEL_CRITICAL(SofQWNormalisedPolygon_spectramap) {
-          specNumberMapping.push_back(
-              outputWS->getSpectrum(qIndex - 1).getSpectrumNo());
-          detIDMapping.push_back(detector->getID());
+          detIDMapping[qIndex - 1].push_back(spectrumInfo.detector(i).getID());
         }
       }
     }
@@ -181,8 +186,9 @@ void SofQWNormalisedPolygon::exec() {
   FractionalRebinning::normaliseOutput(outputWS, inputWS, m_progress);
 
   // Set the output spectrum-detector mapping
-  SpectrumDetectorMapping outputDetectorMap(specNumberMapping, detIDMapping);
-  outputWS->updateSpectraUsing(outputDetectorMap);
+  auto outputIndices = outputWS->indexInfo();
+  outputIndices.setDetectorIDs(std::move(detIDMapping));
+  outputWS->setIndexInfo(outputIndices);
 
   // Replace any NaNs in outputWorkspace with zeroes
   if (this->getProperty("ReplaceNaNs")) {
@@ -246,32 +252,29 @@ void SofQWNormalisedPolygon::initAngularCachesNonPSD(
   auto inst = workspace->getInstrument();
   const PointingAlong upDir = inst->getReferenceFrame()->pointingUp();
 
+  const auto &spectrumInfo = workspace->spectrumInfo();
+
   for (size_t i = 0; i < nhist; ++i) // signed for OpenMP
   {
     m_progress->report("Calculating detector angles");
-    IDetector_const_sptr det;
-    try {
-      det = workspace->getDetector(i);
-      // Check to see if there is an EFixed, if not skip it
-      try {
-        m_EmodeProperties.getEFixed(*det);
-      } catch (std::runtime_error &) {
-        det.reset();
-      }
-    } catch (Kernel::Exception::NotFoundError &) {
-      // Catch if no detector. Next line tests whether this happened - test
-      // placed
-      // outside here because Mac Intel compiler doesn't like 'continue' in a
-      // catch
-      // in an openmp block.
-    }
+
+    this->m_theta[i] = -1.0; // Indicates a detector to skip
+    this->m_thetaWidths[i] = -1.0;
+
     // If no detector found, skip onto the next spectrum
-    if (!det || det->isMonitor()) {
-      this->m_theta[i] = -1.0; // Indicates a detector to skip
-      this->m_thetaWidths[i] = -1.0;
+    if (!spectrumInfo.hasDetectors(i) || spectrumInfo.isMonitor(i)) {
+      continue;
+    }
+
+    const auto &det = spectrumInfo.detector(i);
+    // Check to see if there is an EFixed, if not skip it
+    try {
+      m_EmodeProperties.getEFixed(det);
+    } catch (std::runtime_error &) {
       continue;
     }
-    this->m_theta[i] = workspace->detectorTwoTheta(*det);
+
+    this->m_theta[i] = spectrumInfo.twoTheta(i);
 
     /**
      * Determine width from shape geometry. A group is assumed to contain
@@ -279,18 +282,26 @@ void SofQWNormalisedPolygon::initAngularCachesNonPSD(
      * The shape is retrieved and rotated to match the rotation of the detector.
      * The angular width is computed using the l2 distance from the sample
      */
-    if (auto group = boost::dynamic_pointer_cast<const DetectorGroup>(det)) {
+    Kernel::V3D pos;
+    boost::shared_ptr<const Object>
+        shape; // Defined in its own reference frame with centre at 0,0,0
+    Kernel::Quat rot;
+
+    if (spectrumInfo.hasUniqueDetector(i)) {
+      pos = det.getPos();
+      shape = det.shape();
+      rot = det.getRotation();
+    } else {
       // assume they all have same shape and same r,theta
-      auto dets = group->getDetectors();
-      det = dets[0];
+      const auto &group = dynamic_cast<const Geometry::DetectorGroup &>(det);
+      const auto &firstDet = group.getDetectors();
+      pos = firstDet[0]->getPos();
+      shape = firstDet[0]->shape();
+      rot = firstDet[0]->getRotation();
     }
-    const auto pos = det->getPos();
+
     double l2(0.0), t(0.0), p(0.0);
     pos.getSpherical(l2, t, p);
-    // Get the shape
-    auto shape =
-        det->shape(); // Defined in its own reference frame with centre at 0,0,0
-    auto rot = det->getRotation();
     BoundingBox bbox = shape->getBoundingBox();
     auto maxPoint(bbox.maxPoint());
     rot.rotate(maxPoint);
@@ -326,9 +337,11 @@ void SofQWNormalisedPolygon::initAngularCachesPSD(
   this->m_phi = std::vector<double>(nHistos);
   this->m_phiWidths = std::vector<double>(nHistos);
 
+  const auto &spectrumInfo = workspace->spectrumInfo();
+
   for (size_t i = 0; i < nHistos; ++i) {
     m_progress->report("Calculating detector angular widths");
-    DetConstPtr detector = workspace->getDetector(i);
+    const auto &detector = spectrumInfo.detector(i);
     g_log.debug() << "Current histogram: " << i << '\n';
     specnum_t inSpec = workspace->getSpectrum(i).getSpectrumNo();
     SpectraDistanceMap neighbours = neighbourInfo.getNeighboursExact(inSpec);
@@ -339,8 +352,8 @@ void SofQWNormalisedPolygon::initAngularCachesPSD(
     double phiWidth = -DBL_MAX;
 
     // Find theta and phi widths
-    double theta = workspace->detectorTwoTheta(*detector);
-    double phi = detector->getPhi();
+    double theta = spectrumInfo.twoTheta(i);
+    double phi = detector.getPhi();
 
     specnum_t deltaPlus1 = inSpec + 1;
     specnum_t deltaMinus1 = inSpec - 1;
@@ -352,9 +365,9 @@ void SofQWNormalisedPolygon::initAngularCachesPSD(
       g_log.debug() << "Neighbor ID: " << spec << '\n';
       if (spec == deltaPlus1 || spec == deltaMinus1 || spec == deltaPlusT ||
           spec == deltaMinusT) {
-        DetConstPtr detector_n = workspace->getDetector(spec - 1);
-        double theta_n = workspace->detectorTwoTheta(*detector_n) * 0.5;
-        double phi_n = detector_n->getPhi();
+        const auto &detector_n = spectrumInfo.detector(spec - 1);
+        double theta_n = spectrumInfo.twoTheta(spec - 1) * 0.5;
+        double phi_n = detector_n.getPhi();
 
         double dTheta = std::fabs(theta - theta_n);
         double dPhi = std::fabs(phi - phi_n);
@@ -386,33 +399,20 @@ void SofQWNormalisedPolygon::initAngularCachesPSD(
  *  @return A pointer to the newly-created workspace
  */
 RebinnedOutput_sptr SofQWNormalisedPolygon::setUpOutputWorkspace(
-    API::MatrixWorkspace_const_sptr inputWorkspace,
+    const API::MatrixWorkspace &inputWorkspace,
     const std::vector<double> &binParams, std::vector<double> &newAxis) {
-  // Create vector to hold the new X axis values
-  HistogramData::BinEdges xAxis(inputWorkspace->sharedX(0));
-  const int xLength = static_cast<int>(xAxis.size());
   // Create a vector to temporarily hold the vertical ('y') axis and populate
   // that
   const int yLength = static_cast<int>(
       VectorHelper::createAxisFromRebinParams(binParams, newAxis));
 
-  // Create the output workspace
-  MatrixWorkspace_sptr temp = WorkspaceFactory::Instance().create(
-      "RebinnedOutput", yLength - 1, xLength, xLength - 1);
-  RebinnedOutput_sptr outputWorkspace =
-      boost::static_pointer_cast<RebinnedOutput>(temp);
-  WorkspaceFactory::Instance().initializeFromParent(inputWorkspace,
-                                                    outputWorkspace, true);
+  // Create output workspace, bin edges are same as in inputWorkspace index 0
+  auto outputWorkspace = create<RebinnedOutput>(inputWorkspace, yLength - 1);
 
   // Create a binned numeric axis to replace the default vertical one
   Axis *const verticalAxis = new BinEdgeAxis(newAxis);
   outputWorkspace->replaceAxis(1, verticalAxis);
 
-  // Now set the axis values
-  for (int i = 0; i < yLength - 1; ++i) {
-    outputWorkspace->setBinEdges(i, xAxis);
-  }
-
   // Set the axis units
   verticalAxis->unit() = UnitFactory::Instance().create("MomentumTransfer");
   verticalAxis->title() = "|Q|";
@@ -423,7 +423,7 @@ RebinnedOutput_sptr SofQWNormalisedPolygon::setUpOutputWorkspace(
   outputWorkspace->setYUnit("");
   outputWorkspace->setYUnitLabel("Intensity");
 
-  return outputWorkspace;
+  return std::move(outputWorkspace);
 }
 
 } // namespace Mantid
diff --git a/Framework/Algorithms/src/SofQWPolygon.cpp b/Framework/Algorithms/src/SofQWPolygon.cpp
index cceb6adc60c0551f484b3fe66705e59d2dd0ed47..1c54a016ae52138405b572699a66254a0ef5bc72 100644
--- a/Framework/Algorithms/src/SofQWPolygon.cpp
+++ b/Framework/Algorithms/src/SofQWPolygon.cpp
@@ -1,11 +1,9 @@
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidAlgorithms/SofQWPolygon.h"
 #include "MantidAlgorithms/SofQW.h"
 #include "MantidAlgorithms/ReplaceSpecialValues.h"
 #include "MantidAPI/SpectraAxis.h"
 #include "MantidAPI/SpectrumDetectorMapping.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidGeometry/Math/PolygonIntersection.h"
 #include "MantidGeometry/Math/Quadrilateral.h"
 #include "MantidGeometry/Instrument/DetectorGroup.h"
@@ -25,8 +23,6 @@ using namespace Mantid::Geometry;
 SofQWPolygon::SofQWPolygon()
     : Rebin2D(), m_Qout(), m_thetaPts(), m_thetaWidth(0.0) {}
 
-//----------------------------------------------------------------------------------------------
-
 /**
  * Initialize the algorithm
  */
@@ -38,7 +34,7 @@ void SofQWPolygon::init() { SofQW::createCommonInputProperties(*this); }
 void SofQWPolygon::exec() {
   MatrixWorkspace_const_sptr inputWS = getProperty("InputWorkspace");
   // Do the full check for common binning
-  if (!WorkspaceHelpers::commonBoundaries(inputWS)) {
+  if (!WorkspaceHelpers::commonBoundaries(*inputWS)) {
     throw std::invalid_argument(
         "The input workspace must have common binning across all spectra");
   }
@@ -213,36 +209,23 @@ void SofQWPolygon::initThetaCache(const API::MatrixWorkspace &workspace) {
   size_t ndets(0);
   double minTheta(DBL_MAX), maxTheta(-DBL_MAX);
 
-  for (int64_t i = 0; i < static_cast<int64_t>(nhist); ++i) // signed for OpenMP
-  {
-
+  const auto &spectrumInfo = workspace.spectrumInfo();
+  for (int64_t i = 0; i < static_cast<int64_t>(nhist); ++i) {
     m_progress->report("Calculating detector angles");
-    IDetector_const_sptr det;
+    m_thetaPts[i] = -1.0; // Indicates a detector to skip
+    if (!spectrumInfo.hasDetectors(i) || spectrumInfo.isMonitor(i))
+      continue;
+    // Check to see if there is an EFixed, if not skip it
     try {
-      det = workspace.getDetector(i);
-      // Check to see if there is an EFixed, if not skip it
-      try {
-        m_EmodeProperties.getEFixed(*det);
-      } catch (std::runtime_error &) {
-        det.reset();
-      }
-    } catch (Kernel::Exception::NotFoundError &) {
-      // Catch if no detector. Next line tests whether this happened - test
-      // placed
-      // outside here because Mac Intel compiler doesn't like 'continue' in a
-      // catch
-      // in an openmp block.
-    }
-    // If no detector found, skip onto the next spectrum
-    if (!det || det->isMonitor()) {
-      m_thetaPts[i] = -1.0; // Indicates a detector to skip
-    } else {
-      ++ndets;
-      const double theta = workspace.detectorTwoTheta(*det);
-      m_thetaPts[i] = theta;
-      minTheta = std::min(minTheta, theta);
-      maxTheta = std::max(maxTheta, theta);
+      m_EmodeProperties.getEFixed(spectrumInfo.detector(i));
+    } catch (std::runtime_error &) {
+      continue;
     }
+    ++ndets;
+    const double theta = spectrumInfo.twoTheta(i);
+    m_thetaPts[i] = theta;
+    minTheta = std::min(minTheta, theta);
+    maxTheta = std::max(maxTheta, theta);
   }
 
   if (0 == ndets)
diff --git a/Framework/Algorithms/src/SolidAngle.cpp b/Framework/Algorithms/src/SolidAngle.cpp
index 3ac5ef22f01db98cb35735fa0cb0f937de1d6553..934f92ec7042392c11c6a67a053323b42d3eaf99 100644
--- a/Framework/Algorithms/src/SolidAngle.cpp
+++ b/Framework/Algorithms/src/SolidAngle.cpp
@@ -1,4 +1,5 @@
 #include "MantidAlgorithms/SolidAngle.h"
+#include "MantidAPI/DetectorInfo.h"
 #include "MantidAPI/InstrumentValidator.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/SpectrumInfo.h"
@@ -81,10 +82,11 @@ void SolidAngle::exec() {
   setProperty("OutputWorkspace", outputWS);
 
   const auto &spectrumInfo = inputWS->spectrumInfo();
+  const auto &detectorInfo = inputWS->detectorInfo();
   const Kernel::V3D samplePos = spectrumInfo.samplePosition();
   g_log.debug() << "Sample position is " << samplePos << '\n';
 
-  int loopIterations = m_MaxSpec - m_MinSpec;
+  const int loopIterations = m_MaxSpec - m_MinSpec;
   int failCount = 0;
   Progress prog(this, 0.0, 1.0, numberOfSpectra);
 
@@ -92,14 +94,16 @@ void SolidAngle::exec() {
   PARALLEL_FOR_IF(Kernel::threadSafe(*outputWS, *inputWS))
   for (int j = 0; j <= loopIterations; ++j) {
     PARALLEL_START_INTERUPT_REGION
-    int i = j + m_MinSpec;
+    const int i = j + m_MinSpec;
     if (spectrumInfo.hasDetectors(i)) {
       // Copy over the spectrum number & detector IDs
       outputWS->getSpectrum(j).copyInfoFrom(inputWS->getSpectrum(i));
-      // Solid angle should be zero if detector is masked ('dead')
-      double solidAngle = spectrumInfo.isMasked(i)
-                              ? 0.0
-                              : spectrumInfo.detector(i).solidAngle(samplePos);
+      double solidAngle = 0.0;
+      for (const auto detID : inputWS->getSpectrum(j).getDetectorIDs()) {
+        const auto index = detectorInfo.indexOf(detID);
+        if (!detectorInfo.isMasked(index))
+          solidAngle += detectorInfo.detector(index).solidAngle(samplePos);
+      }
 
       outputWS->mutableX(j)[0] = inputWS->x(i).front();
       outputWS->mutableX(j)[1] = inputWS->x(i).back();
@@ -119,7 +123,7 @@ void SolidAngle::exec() {
 
   if (failCount != 0) {
     g_log.information() << "Unable to calculate solid angle for " << failCount
-                        << " spectra. Zeroing spectrum.\n";
+                        << " spectra. Zeroing these spectra.\n";
   }
 }
 
diff --git a/Framework/Algorithms/src/SpatialGrouping.cpp b/Framework/Algorithms/src/SpatialGrouping.cpp
index 1be8baeb0852f5c6dd9e10d24149f399f656f940..d41ff40179f70db563b0822b38d3b78853d6f23c 100644
--- a/Framework/Algorithms/src/SpatialGrouping.cpp
+++ b/Framework/Algorithms/src/SpatialGrouping.cpp
@@ -5,6 +5,7 @@
 
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/FileProperty.h"
+#include "MantidAPI/SpectrumInfo.h"
 
 #include <map>
 
@@ -68,34 +69,32 @@ void SpatialGrouping::exec() {
   int gridSize = getProperty("GridSize");
   size_t nNeighbours = (gridSize * gridSize) - 1;
 
-  // Make a map key = spectrum number, value = detector at that spectrum
-  m_detectors.clear();
-  for (size_t i = 0; i < inputWorkspace->getNumberHistograms(); i++) {
+  m_positions.clear();
+  const auto &spectrumInfo = inputWorkspace->spectrumInfo();
+  for (size_t i = 0; i < inputWorkspace->getNumberHistograms(); ++i) {
     const auto &spec = inputWorkspace->getSpectrum(i);
-    m_detectors[spec.getSpectrumNo()] = inputWorkspace->getDetector(i);
+    m_positions[spec.getSpectrumNo()] = spectrumInfo.position(i);
   }
 
   // TODO: There is a confusion in this algorithm between detector IDs and
   // spectrum numbers!
 
-  Mantid::API::Progress prog(this, 0.0, 1.0, m_detectors.size());
+  Mantid::API::Progress prog(this, 0.0, 1.0, m_positions.size());
 
   bool ignoreMaskedDetectors = false;
   m_neighbourInfo = Kernel::make_unique<API::NearestNeighbourInfo>(
       *inputWorkspace, ignoreMaskedDetectors);
 
-  for (auto &detector : m_detectors) {
+  for (size_t i = 0; i < inputWorkspace->getNumberHistograms(); ++i) {
     prog.report();
 
-    // The detector
-    Mantid::Geometry::IDetector_const_sptr &det = detector.second;
-    // The spectrum number of the detector
-    specnum_t specNo = detector.first;
+    const auto &spec = inputWorkspace->getSpectrum(i);
+    specnum_t specNo = spec.getSpectrumNo();
 
     // We are not interested in Monitors and we don't want them to be included
     // in
     // any of the other lists
-    if (det->isMonitor()) {
+    if (spectrumInfo.isMonitor(i)) {
       m_included.insert(specNo);
       continue;
     }
@@ -112,7 +111,7 @@ void SpatialGrouping::exec() {
     Mantid::Geometry::BoundingBox bbox(empty, empty, empty, empty, empty,
                                        empty);
 
-    createBox(det, bbox, searchDist);
+    createBox(spectrumInfo.detector(i), bbox, searchDist);
 
     bool extend = true;
     while ((nNeighbours > nearest.size()) && extend) {
@@ -206,17 +205,15 @@ bool SpatialGrouping::expandNet(
     const size_t noNeighbours, const Mantid::Geometry::BoundingBox &bbox) {
   const size_t incoming = nearest.size();
 
-  Mantid::Geometry::IDetector_const_sptr det = m_detectors[spec];
-
   std::map<specnum_t, Mantid::Kernel::V3D> potentials;
 
   // Special case for first run for this detector
   if (incoming == 0) {
-    potentials = m_neighbourInfo->getNeighbours(det.get());
+    potentials = m_neighbourInfo->getNeighbours(spec, 0.0);
   } else {
     for (auto &nrsIt : nearest) {
       std::map<specnum_t, Mantid::Kernel::V3D> results;
-      results = m_neighbourInfo->getNeighbours(m_detectors[nrsIt.first].get());
+      results = m_neighbourInfo->getNeighbours(nrsIt.first, 0.0);
       for (auto &result : results) {
         potentials[result.first] = result.second;
       }
@@ -246,7 +243,7 @@ bool SpatialGrouping::expandNet(
 
     // If we get this far, we need to determine if the detector is of a suitable
     // distance
-    Mantid::Kernel::V3D pos = m_detectors[potential.first]->getPos();
+    Mantid::Kernel::V3D pos = m_positions[potential.first];
     if (!bbox.isPointInside(pos)) {
       continue;
     }
@@ -303,9 +300,9 @@ void SpatialGrouping::sortByDistance(
 * @param searchDist :: search distance in pixels, number of pixels to search
 * through for finding group
 */
-void SpatialGrouping::createBox(
-    boost::shared_ptr<const Geometry::IDetector> det,
-    Geometry::BoundingBox &bndbox, double searchDist) {
+void SpatialGrouping::createBox(const Geometry::IDetector &det,
+                                Geometry::BoundingBox &bndbox,
+                                double searchDist) {
 
   // We may have DetectorGroups here
   // Unfortunately, IDetector doesn't contain the
@@ -313,7 +310,7 @@ void SpatialGrouping::createBox(
   // boost::dynamic_pointer_cast<Mantid::Geometry::Detector>(det);
 
   Mantid::Geometry::BoundingBox bbox;
-  det->getBoundingBox(bbox);
+  det.getBoundingBox(bbox);
 
   double xmax = bbox.xMax();
   double ymax = bbox.yMax();
diff --git a/Framework/Algorithms/src/SpecularReflectionAlgorithm.cpp b/Framework/Algorithms/src/SpecularReflectionAlgorithm.cpp
index 214cceaf4509e48470a43529e542b4f112f90d79..a313930aea53b9cf7637f9bb173d7db77c723321 100644
--- a/Framework/Algorithms/src/SpecularReflectionAlgorithm.cpp
+++ b/Framework/Algorithms/src/SpecularReflectionAlgorithm.cpp
@@ -1,6 +1,7 @@
 #include "MantidAlgorithms/SpecularReflectionAlgorithm.h"
 
 #include "MantidAPI/MatrixWorkspace.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidKernel/ArrayBoundedValidator.h"
 #include "MantidKernel/ArrayProperty.h"
 #include "MantidKernel/EnabledWhenProperty.h"
@@ -154,7 +155,7 @@ SpecularReflectionAlgorithm::getDetectorComponent(
     checkSpectrumNumbers(spectrumNumbers, strictSpectrumChecking, g_log);
     auto specToWorkspaceIndex = workspace->getSpectrumToWorkspaceIndexMap();
     DetectorGroup_sptr allDetectors = boost::make_shared<DetectorGroup>();
-    bool warnIfMasked = true;
+    const auto &spectrumInfo = workspace->spectrumInfo();
     for (auto index : spectrumNumbers) {
       const size_t spectrumNumber{static_cast<size_t>(index)};
       auto it = specToWorkspaceIndex.find(index);
@@ -166,7 +167,10 @@ SpecularReflectionAlgorithm::getDetectorComponent(
       }
       const size_t workspaceIndex = it->second;
       auto detector = workspace->getDetector(workspaceIndex);
-      allDetectors->addDetector(detector, warnIfMasked);
+      if (spectrumInfo.isMasked(workspaceIndex))
+        g_log.warning() << "Adding a detector (ID:" << detector->getID()
+                        << ") that is flagged as masked.\n";
+      allDetectors->addDetector(detector);
     }
     searchResult = allDetectors;
   } else {
diff --git a/Framework/Algorithms/src/Stitch1D.cpp b/Framework/Algorithms/src/Stitch1D.cpp
index 05d0eef3bc2cfa36da72ef8eca1b937247762a4f..3931ec759e96a9a6beb58c96671db36417ad609d 100644
--- a/Framework/Algorithms/src/Stitch1D.cpp
+++ b/Framework/Algorithms/src/Stitch1D.cpp
@@ -143,9 +143,10 @@ void Stitch1D::init() {
                   "Rebinning Parameters. See Rebin for format. If only a "
                   "single value is provided, start and end are taken from "
                   "input workspaces.");
-  declareProperty(make_unique<PropertyWithValue<bool>>("ScaleRHSWorkspace",
-                                                       true, Direction::Input),
-                  "Scaling either with respect to workspace 1 or workspace 2");
+  declareProperty(
+      make_unique<PropertyWithValue<bool>>("ScaleRHSWorkspace", true,
+                                           Direction::Input),
+      "Scaling either with respect to LHS workspace or RHS workspace");
   declareProperty(make_unique<PropertyWithValue<bool>>("UseManualScaleFactor",
                                                        false, Direction::Input),
                   "True to use a provided value for the scale factor.");
@@ -280,7 +281,7 @@ std::vector<double> Stitch1D::getRebinParams(MatrixWorkspace_sptr &lhsWS,
   return result;
 }
 
-/**Runs the Rebin Algorithm as a child
+/**Runs the Rebin Algorithm as a child and replaces special values
  @param input :: The input workspace
  @param params :: a vector<double> containing rebinning parameters
  @return A shared pointer to the resulting MatrixWorkspace
@@ -360,52 +361,6 @@ MatrixWorkspace_sptr Stitch1D::integration(MatrixWorkspace_sptr &input,
   return outWS;
 }
 
-/**Runs the MultiplyRange Algorithm as a child defining an end bin
- @param input :: The input workspace
- @param startBin :: The first bin int eh range to multiply
- @param endBin :: The last bin in the range to multiply
- @param factor :: The multiplication factor
- @return A shared pointer to the resulting MatrixWorkspace
- */
-MatrixWorkspace_sptr Stitch1D::multiplyRange(MatrixWorkspace_sptr &input,
-                                             const int &startBin,
-                                             const int &endBin,
-                                             const double &factor) {
-  auto multiplyRange = this->createChildAlgorithm("MultiplyRange");
-  multiplyRange->setProperty("InputWorkspace", input);
-  multiplyRange->setProperty("StartBin", startBin);
-  multiplyRange->setProperty("EndBin", endBin);
-  multiplyRange->setProperty("Factor", factor);
-  g_log.information("MultiplyRange StartBin: " + std::to_string(startBin));
-  g_log.information("MultiplyRange EndBin: " + std::to_string(endBin));
-  g_log.information("MultiplyRange Factor: " +
-                    boost::lexical_cast<std::string>(factor));
-  multiplyRange->execute();
-  MatrixWorkspace_sptr outWS = multiplyRange->getProperty("OutputWorkspace");
-  return outWS;
-}
-
-/**Runs the MultiplyRange Algorithm as a child
- @param input :: The input workspace
- @param startBin :: The first bin int eh range to multiply
- @param factor :: The multiplication factor
- @return A shared pointer to the resulting MatrixWorkspace
- */
-MatrixWorkspace_sptr Stitch1D::multiplyRange(MatrixWorkspace_sptr &input,
-                                             const int &startBin,
-                                             const double &factor) {
-  auto multiplyRange = this->createChildAlgorithm("MultiplyRange");
-  multiplyRange->setProperty("InputWorkspace", input);
-  multiplyRange->setProperty("StartBin", startBin);
-  multiplyRange->setProperty("Factor", factor);
-  g_log.information("MultiplyRange StartBin: " + std::to_string(startBin));
-  g_log.information("MultiplyRange Factor: " +
-                    boost::lexical_cast<std::string>(factor));
-  multiplyRange->execute();
-  MatrixWorkspace_sptr outWS = multiplyRange->getProperty("OutputWorkspace");
-  return outWS;
-}
-
 /**Runs the WeightedMean Algorithm as a child
  @param inOne :: The first input workspace
  @param inTwo :: The second input workspace
diff --git a/Framework/Algorithms/src/Stitch1DMany.cpp b/Framework/Algorithms/src/Stitch1DMany.cpp
index ac33223869f903a578eea16a2a5916575528a5c7..69098fd9e122b5a244783e50b291dba64ef8030e 100644
--- a/Framework/Algorithms/src/Stitch1DMany.cpp
+++ b/Framework/Algorithms/src/Stitch1DMany.cpp
@@ -1,5 +1,6 @@
 #include "MantidAlgorithms/Stitch1DMany.h"
 #include "MantidAPI/MatrixWorkspace.h"
+#include "MantidAPI/WorkspaceHistory.h"
 #include "MantidAPI/WorkspaceProperty.h"
 #include "MantidKernel/ArrayProperty.h"
 #include "MantidKernel/BoundedValidator.h"
@@ -60,6 +61,14 @@ void Stitch1DMany::init() {
   declareProperty(
       make_unique<ArrayProperty<double>>("OutScaleFactors", Direction::Output),
       "The actual used values for the scaling factors at each stitch step.");
+
+  auto scaleFactorFromPeriodValidator =
+      boost::make_shared<BoundedValidator<int>>();
+  scaleFactorFromPeriodValidator->setLower(1);
+  declareProperty(make_unique<PropertyWithValue<int>>(
+                      "ScaleFactorFromPeriod", 1,
+                      scaleFactorFromPeriodValidator, Direction::Input),
+                  "Provided index of period to obtain scale factor from.");
 }
 
 /** Load and validate the algorithm's properties.
@@ -67,44 +76,104 @@ void Stitch1DMany::init() {
 std::map<std::string, std::string> Stitch1DMany::validateInputs() {
   std::map<std::string, std::string> errors;
 
-  m_inputWorkspaces.clear();
-
   const std::vector<std::string> inputWorkspacesStr =
       this->getProperty("InputWorkspaces");
-  if (inputWorkspacesStr.size() < 2)
-    errors["InputWorkspaces"] = "At least 2 input workspaces required.";
 
+  // Check all workspaces exist
+  std::vector<Workspace_sptr> inputWorkspaces;
   for (const auto &ws : inputWorkspacesStr) {
     if (AnalysisDataService::Instance().doesExist(ws)) {
-      m_inputWorkspaces.push_back(
+      inputWorkspaces.push_back(
           AnalysisDataService::Instance().retrieveWS<Workspace>(ws));
     } else {
       errors["InputWorkspaces"] = ws + " is not a valid workspace.";
       break;
     }
   }
+  m_inputWSMatrix.push_back(inputWorkspaces);
 
-  // Check that all the workspaces are of the same type
-  if (!m_inputWorkspaces.empty()) {
-    const std::string id = m_inputWorkspaces[0]->id();
-    for (auto &inputWorkspace : m_inputWorkspaces) {
-      if (inputWorkspace->id() != id) {
-        errors["InputWorkspaces"] = "All workspaces must be the same type.";
-        break;
+  // Add common errors
+  auto commonErrors = validateCommonInputs();
+  errors.insert(commonErrors.begin(), commonErrors.end());
+
+  return errors;
+}
+
+/** Load and validate the algorithm's properties for workspace groups.
+ */
+void Stitch1DMany::validateGroupWorkspacesInputs() {
+  std::string error;
+
+  const std::vector<std::string> inputWorkspacesStr =
+      this->getProperty("InputWorkspaces");
+
+  // Check all workspace groups and their constituent workspaces exist
+  for (const auto &groupWSName : inputWorkspacesStr) {
+    if (AnalysisDataService::Instance().doesExist(groupWSName)) {
+
+      std::vector<Workspace_sptr> inputWorkspaces;
+      auto groupWS = AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>(
+          groupWSName);
+
+      for (size_t i = 0; i < groupWS->size(); i++) {
+        const std::string &wsName = groupWS->getItem(i)->getName();
+        if (AnalysisDataService::Instance().doesExist(wsName)) {
+          inputWorkspaces.push_back(
+              AnalysisDataService::Instance().retrieveWS<Workspace>(wsName));
+        } else {
+          throw std::invalid_argument(groupWSName +
+                                      " is not a valid workspace.");
+        }
       }
+
+      m_inputWSMatrix.push_back(inputWorkspaces);
+      m_inputWSGroups.push_back(groupWS);
+    } else {
+      throw std::invalid_argument(groupWSName +
+                                  " is not a valid workspace group.");
     }
+  }
+
+  size_t numWSInGroup = m_inputWSMatrix[0].size();
 
-    // If our inputs are all group workspaces, check they're the same size
-    WorkspaceGroup_sptr firstGroup =
-        boost::dynamic_pointer_cast<WorkspaceGroup>(m_inputWorkspaces[0]);
-    if (firstGroup) {
-      size_t groupSize = firstGroup->size();
-      for (auto &inputWorkspace : m_inputWorkspaces) {
-        WorkspaceGroup_sptr group =
-            boost::dynamic_pointer_cast<WorkspaceGroup>(inputWorkspace);
-        if (group->size() != groupSize) {
-          errors["InputWorkspaces"] =
-              "All group workspaces must be the same size.";
+  // Check all workspace groups are the same size
+  for (auto &inputWsGroup : m_inputWSGroups) {
+    if (inputWsGroup->size() != numWSInGroup) {
+      throw std::runtime_error("All workspace groups must be the same size.");
+    }
+  }
+
+  int scaleFactorFromPeriod = this->getProperty("ScaleFactorFromPeriod");
+  m_scaleFactorFromPeriod = (size_t)scaleFactorFromPeriod;
+  m_scaleFactorFromPeriod--; // To account for period being indexed from 1
+  if (m_scaleFactorFromPeriod >= m_inputWSGroups.size())
+    throw std::runtime_error("Period index out of range");
+
+  // Throw if a common error is found
+  auto commonErrors = validateCommonInputs();
+  if (commonErrors.size() > 0) {
+    auto error = commonErrors.begin();
+    throw std::runtime_error(error->second);
+  }
+}
+
+/** Load and validate properties common to both group and non-group workspaces.
+*/
+std::map<std::string, std::string> Stitch1DMany::validateCommonInputs() {
+  std::map<std::string, std::string> errors;
+
+  const std::vector<std::string> inputWorkspacesStr =
+      this->getProperty("InputWorkspaces");
+  if (inputWorkspacesStr.size() < 2)
+    errors["InputWorkspaces"] = "At least 2 input workspaces required.";
+
+  // Check that all the workspaces are of the same type
+  if (!m_inputWSMatrix.empty() && !m_inputWSMatrix[0].empty()) {
+    const std::string id = m_inputWSMatrix[0][0]->id();
+    for (auto &period : m_inputWSMatrix) {
+      for (auto &inputWS : period) {
+        if (inputWS->id() != id) {
+          errors["InputWorkspaces"] = "All workspaces must be the same type.";
           break;
         }
       }
@@ -113,12 +182,18 @@ std::map<std::string, std::string> Stitch1DMany::validateInputs() {
     errors["InputWorkspaces"] = "Input workspaces must be given";
   }
 
-  m_numWorkspaces = m_inputWorkspaces.size();
-
   m_startOverlaps = this->getProperty("StartOverlaps");
   m_endOverlaps = this->getProperty("EndOverlaps");
+  m_scaleRHSWorkspace = this->getProperty("ScaleRHSWorkspace");
+  m_params = this->getProperty("Params");
 
-  if (!m_startOverlaps.empty() && m_startOverlaps.size() != m_numWorkspaces - 1)
+  m_numWSPerGroup = m_inputWSMatrix[0].size();
+  m_numWSPerPeriod = m_inputWSMatrix.size();
+
+  size_t numStitchableWS =
+      (m_numWSPerPeriod > 1) ? m_numWSPerPeriod : m_numWSPerGroup;
+
+  if (!m_startOverlaps.empty() && m_startOverlaps.size() != numStitchableWS - 1)
     errors["StartOverlaps"] = "If given, StartOverlaps must have one fewer "
                               "entries than the number of input workspaces.";
 
@@ -126,23 +201,11 @@ std::map<std::string, std::string> Stitch1DMany::validateInputs() {
     errors["EndOverlaps"] =
         "EndOverlaps must have the same number of entries as StartOverlaps.";
 
-  m_scaleRHSWorkspace = this->getProperty("ScaleRHSWorkspace");
-  m_useManualScaleFactor = this->getProperty("UseManualScaleFactor");
-  m_manualScaleFactor = this->getProperty("ManualScaleFactor");
-  m_params = this->getProperty("Params");
-
   if (m_params.empty())
     errors["Params"] = "At least one parameter must be given.";
 
-  if (!m_scaleRHSWorkspace) {
-    // Flip these around for processing
-    std::reverse(m_inputWorkspaces.begin(), m_inputWorkspaces.end());
-    std::reverse(m_startOverlaps.begin(), m_startOverlaps.end());
-    std::reverse(m_endOverlaps.begin(), m_endOverlaps.end());
-  }
-
-  m_scaleFactors.clear();
-  m_outputWorkspace.reset();
+  m_useManualScaleFactor = this->getProperty("UseManualScaleFactor");
+  m_manualScaleFactor = this->getProperty("ManualScaleFactor");
 
   return errors;
 }
@@ -150,114 +213,207 @@ std::map<std::string, std::string> Stitch1DMany::validateInputs() {
 /** Execute the algorithm.
  */
 void Stitch1DMany::exec() {
-  // Check we're not dealing with group workspaces
-  if (!boost::dynamic_pointer_cast<WorkspaceGroup>(m_inputWorkspaces[0])) {
-    MatrixWorkspace_sptr lhsWS =
-        boost::dynamic_pointer_cast<MatrixWorkspace>(m_inputWorkspaces[0]);
-
-    for (size_t i = 1; i < m_numWorkspaces; ++i) {
-      MatrixWorkspace_sptr rhsWS =
-          boost::dynamic_pointer_cast<MatrixWorkspace>(m_inputWorkspaces[i]);
-
-      IAlgorithm_sptr stitchAlg = createChildAlgorithm("Stitch1D");
-      stitchAlg->initialize();
-
-      stitchAlg->setProperty("LHSWorkspace", lhsWS);
-      stitchAlg->setProperty("RHSWorkspace", rhsWS);
-      if (m_startOverlaps.size() > i - 1) {
-        stitchAlg->setProperty("StartOverlap", m_startOverlaps[i - 1]);
-        stitchAlg->setProperty("EndOverlap", m_endOverlaps[i - 1]);
-      }
-      stitchAlg->setProperty("Params", m_params);
-      stitchAlg->setProperty("ScaleRHSWorkspace", m_scaleRHSWorkspace);
-      stitchAlg->setProperty("UseManualScaleFactor", m_useManualScaleFactor);
-      if (m_useManualScaleFactor)
-        stitchAlg->setProperty("ManualScaleFactor", m_manualScaleFactor);
+  MatrixWorkspace_sptr lhsWS =
+      boost::dynamic_pointer_cast<MatrixWorkspace>(m_inputWSMatrix[0][0]);
 
-      stitchAlg->execute();
+  for (size_t i = 1; i < m_numWSPerGroup; i++) {
+    MatrixWorkspace_sptr rhsWS =
+        boost::dynamic_pointer_cast<MatrixWorkspace>(m_inputWSMatrix[0][i]);
+    double outScaleFactor;
 
-      lhsWS = stitchAlg->getProperty("OutputWorkspace");
-      m_scaleFactors.push_back(stitchAlg->getProperty("OutScaleFactor"));
-    }
+    doStitch1D(lhsWS, rhsWS, i, m_startOverlaps, m_endOverlaps, m_params,
+               m_scaleRHSWorkspace, m_useManualScaleFactor, m_manualScaleFactor,
+               lhsWS, outScaleFactor);
 
-    if (!isChild()) {
-      // Copy each input workspace's history into our output workspace's history
-      for (auto &inputWorkspace : m_inputWorkspaces)
-        lhsWS->history().addHistory(inputWorkspace->getHistory());
-    }
-    // We're a child algorithm, but we're recording history anyway
-    else if (isRecordingHistoryForChild() && m_parentHistory) {
-      m_parentHistory->addChildHistory(m_history);
+    m_scaleFactors.push_back(outScaleFactor);
+  }
+  m_outputWorkspace = lhsWS;
+
+  // Save output
+  this->setProperty("OutputWorkspace", m_outputWorkspace);
+  this->setProperty("OutScaleFactors", m_scaleFactors);
+}
+
+/** Performs the Stitch1D algorithm at a specific workspace index.
+ * @param lhsWS :: The left-hand workspace to be stitched
+ * @param rhsWS :: The right-hand workspace to be stitched
+ * @param wsIndex :: The index of the rhs workspace being stitched
+ * @param startOverlaps :: Start overlaps for stitched workspaces
+ * @param endOverlaps :: End overlaps for stitched workspaces
+ * @param params :: Rebinning parameters
+ * @param scaleRhsWS :: Scaling either with respect to left or right workspaces
+ * @param useManualScaleFactor :: True to use a provided value for scale factor
+ * @param manualScaleFactor :: Provided value for scaling factor
+ * @param outWS :: Output stitched workspace
+ * @param outScaleFactor :: Actual value used for scale factor
+ */
+void Stitch1DMany::doStitch1D(
+    MatrixWorkspace_sptr lhsWS, MatrixWorkspace_sptr rhsWS,
+    const size_t wsIndex, const std::vector<double> &startOverlaps,
+    const std::vector<double> &endOverlaps, const std::vector<double> &params,
+    const bool scaleRhsWS, const bool useManualScaleFactor,
+    const double manualScaleFactor, MatrixWorkspace_sptr &outWS,
+    double &outScaleFactor) {
+
+  IAlgorithm_sptr alg = createChildAlgorithm("Stitch1D");
+  alg->initialize();
+  alg->setProperty("LHSWorkspace", lhsWS);
+  alg->setProperty("RHSWorkspace", rhsWS);
+  if (startOverlaps.size() > wsIndex - 1) {
+    alg->setProperty("StartOverlap", startOverlaps[wsIndex - 1]);
+    alg->setProperty("EndOverlap", endOverlaps[wsIndex - 1]);
+  }
+  alg->setProperty("Params", params);
+  alg->setProperty("ScaleRHSWorkspace", scaleRhsWS);
+  alg->setProperty("UseManualScaleFactor", useManualScaleFactor);
+  if (useManualScaleFactor)
+    alg->setProperty("ManualScaleFactor", manualScaleFactor);
+  alg->execute();
+
+  outWS = alg->getProperty("OutputWorkspace");
+  outScaleFactor = alg->getProperty("OutScaleFactor");
+
+  if (!isChild()) {
+    // Copy each input workspace's history into our output workspace's history
+    for (auto &inputWS : m_inputWSMatrix[0]) {
+      outWS->history().addHistory(inputWS->getHistory());
     }
+  }
+}
 
-    m_outputWorkspace = lhsWS;
+/** Performs the Stitch1DMany algorithm at a specific period
+ * @param inputWSGroups :: The set of workspace groups to be stitched
+ * @param period :: The period index we are stitching at
+ * @param storeInADS :: True to store in the AnalysisDataService
+ * @param startOverlaps :: Start overlaps for stitched workspaces
+ * @param endOverlaps :: End overlaps for stitched workspaces
+ * @param params :: Rebinning parameters
+ * @param scaleRhsWS :: Scaling either with respect to left or right workspaces
+ * @param useManualScaleFactor :: True to use a provided value for scale factor
+ * @param manualScaleFactor :: Provided value for scaling factor
+ * @param outName :: Output stitched workspace name
+ * @param outScaleFactors :: Actual values used for scale factors
+ */
+void Stitch1DMany::doStitch1DMany(
+    std::vector<WorkspaceGroup_sptr> inputWSGroups, const size_t period,
+    const bool storeInADS, const std::vector<double> &startOverlaps,
+    const std::vector<double> &endOverlaps, const std::vector<double> &params,
+    const bool scaleRhsWS, const bool useManualScaleFactor,
+    const double manualScaleFactor, std::string &outName,
+    std::vector<double> &outScaleFactors) {
+
+  // List of workspaces to stitch
+  std::vector<std::string> toProcess;
+
+  for (auto &groupWs : inputWSGroups) {
+    const std::string &wsName = groupWs->getItem(period)->getName();
+    toProcess.push_back(wsName);
+    outName += "_" + wsName;
   }
-  // We're dealing with group workspaces
-  else {
-    std::vector<WorkspaceGroup_sptr> groupWorkspaces;
-    groupWorkspaces.reserve(m_inputWorkspaces.size());
-    for (auto &inputWorkspace : m_inputWorkspaces)
-      groupWorkspaces.push_back(
-          boost::dynamic_pointer_cast<WorkspaceGroup>(inputWorkspace));
-
-    // List of workspaces to be grouped
-    std::vector<std::string> toGroup;
-
-    const std::string groupName = this->getProperty("OutputWorkspace");
-
-    size_t numWSPerGroup = groupWorkspaces[0]->size();
-
-    for (size_t i = 0; i < numWSPerGroup; ++i) {
-      // List of workspaces to stitch
-      std::vector<std::string> toProcess;
-      // The name of the resulting workspace
-      std::string outName = groupName;
-
-      for (auto &groupWorkspace : groupWorkspaces) {
-        const std::string wsName = groupWorkspace->getItem(i)->name();
-        toProcess.push_back(wsName);
-        outName += "_" + wsName;
-      }
 
-      IAlgorithm_sptr stitchAlg = createChildAlgorithm("Stitch1DMany");
-      stitchAlg->initialize();
-      stitchAlg->setAlwaysStoreInADS(true);
-      stitchAlg->setProperty("InputWorkspaces", toProcess);
-      stitchAlg->setProperty("OutputWorkspace", outName);
-      stitchAlg->setProperty("StartOverlaps", m_startOverlaps);
-      stitchAlg->setProperty("EndOverlaps", m_endOverlaps);
-      stitchAlg->setProperty("Params", m_params);
-      stitchAlg->setProperty("ScaleRHSWorkspace", m_scaleRHSWorkspace);
-      stitchAlg->setProperty("UseManualScaleFactor", m_useManualScaleFactor);
-      if (m_useManualScaleFactor)
-        stitchAlg->setProperty("ManualScaleFactor", m_manualScaleFactor);
-      stitchAlg->execute();
+  IAlgorithm_sptr alg = createChildAlgorithm("Stitch1DMany");
+  alg->initialize();
+  alg->setChild(false);
+  alg->setAlwaysStoreInADS(storeInADS);
+  alg->setProperty("InputWorkspaces", toProcess);
+  alg->setProperty("OutputWorkspace", outName);
+  alg->setProperty("StartOverlaps", startOverlaps);
+  alg->setProperty("EndOverlaps", endOverlaps);
+  alg->setProperty("Params", params);
+  alg->setProperty("ScaleRHSWorkspace", scaleRhsWS);
+  alg->setProperty("UseManualScaleFactor", useManualScaleFactor);
+  if (useManualScaleFactor)
+    alg->setProperty("ManualScaleFactor", manualScaleFactor);
+  alg->execute();
+
+  outScaleFactors = alg->getProperty("OutScaleFactors");
+}
+
+bool Stitch1DMany::checkGroups() {
+  std::vector<std::string> wsNames = getProperty("InputWorkspaces");
+
+  try {
+    if (AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>(wsNames[0]))
+      return true;
+  } catch (...) {
+  }
+  return false;
+}
+
+bool Stitch1DMany::processGroups() {
+  validateGroupWorkspacesInputs();
+
+  std::vector<std::string> toGroup; // List of workspaces to be grouped
+  std::string groupName = this->getProperty("OutputWorkspace");
+  std::string outName;
+
+  // Determine whether or not we are using a global scale factor
+  Property *manualSF = this->getProperty("ManualScaleFactor");
+  bool usingScaleFromPeriod = m_useManualScaleFactor && manualSF->isDefault();
+
+  if (!usingScaleFromPeriod) {
+    for (size_t i = 0; i < m_numWSPerGroup; ++i) {
+      outName = groupName;
+      std::vector<double> scaleFactors;
+      doStitch1DMany(m_inputWSGroups, i, true, m_startOverlaps, m_endOverlaps,
+                     m_params, m_scaleRHSWorkspace, m_useManualScaleFactor,
+                     m_manualScaleFactor, outName, scaleFactors);
 
       // Add the resulting workspace to the list to be grouped together
       toGroup.push_back(outName);
 
       // Add the scalefactors to the list so far
-      const std::vector<double> scaleFactors =
-          stitchAlg->getProperty("OutScaleFactors");
       m_scaleFactors.insert(m_scaleFactors.end(), scaleFactors.begin(),
                             scaleFactors.end());
     }
+  } else {
+    // Obtain scale factors for the specified period
+    outName = groupName;
+    std::vector<double> periodScaleFactors;
+    doStitch1DMany(m_inputWSGroups, m_scaleFactorFromPeriod, false,
+                   m_startOverlaps, m_endOverlaps, m_params,
+                   m_scaleRHSWorkspace, false, m_manualScaleFactor, outName,
+                   periodScaleFactors);
+
+    // Iterate over each period
+    for (size_t i = 0; i < m_numWSPerGroup; i++) {
+      auto lhsWS =
+          boost::dynamic_pointer_cast<MatrixWorkspace>(m_inputWSMatrix[0][i]);
+      outName = groupName + "_" + lhsWS->getName();
+
+      // Perform stiching on the workspace for each group of that period
+      for (size_t j = 1; j < m_numWSPerPeriod; j++) {
+        auto rhsWS =
+            boost::dynamic_pointer_cast<MatrixWorkspace>(m_inputWSMatrix[j][i]);
+        outName += "_" + rhsWS->getName(); // add name
+        double outScaleFactor;
+
+        doStitch1D(lhsWS, rhsWS, j, m_startOverlaps, m_endOverlaps, m_params,
+                   m_scaleRHSWorkspace, m_useManualScaleFactor,
+                   periodScaleFactors[j - 1], lhsWS, outScaleFactor);
+
+        m_scaleFactors.push_back(outScaleFactor);
+      }
 
-    IAlgorithm_sptr groupAlg = createChildAlgorithm("GroupWorkspaces");
-    groupAlg->initialize();
-    groupAlg->setAlwaysStoreInADS(true);
-    groupAlg->setProperty("InputWorkspaces", toGroup);
-    groupAlg->setProperty("OutputWorkspace", groupName);
-    groupAlg->execute();
-
-    m_outputWorkspace =
-        AnalysisDataService::Instance().retrieveWS<Workspace>(groupName);
+      // Add name of stitched workspaces to group list and ADS
+      toGroup.push_back(outName);
+      AnalysisDataService::Instance().addOrReplace(outName, lhsWS);
+    }
   }
 
-  // Save output
+  IAlgorithm_sptr groupAlg = createChildAlgorithm("GroupWorkspaces");
+  groupAlg->initialize();
+  groupAlg->setAlwaysStoreInADS(true);
+  groupAlg->setProperty("InputWorkspaces", toGroup);
+  groupAlg->setProperty("OutputWorkspace", groupName);
+  groupAlg->execute();
+
+  m_outputWorkspace =
+      AnalysisDataService::Instance().retrieveWS<Workspace>(groupName);
+
   this->setProperty("OutputWorkspace", m_outputWorkspace);
   this->setProperty("OutScaleFactors", m_scaleFactors);
+  return true;
 }
-
 } // namespace Algorithms
 } // namespace Mantid
diff --git a/Framework/Algorithms/src/StripVanadiumPeaks.cpp b/Framework/Algorithms/src/StripVanadiumPeaks.cpp
index f1a6c737dc7852b46e240494c3e09676859cacaa..3dc076cec44ac139de469c088c62e1ed69dc87c7 100644
--- a/Framework/Algorithms/src/StripVanadiumPeaks.cpp
+++ b/Framework/Algorithms/src/StripVanadiumPeaks.cpp
@@ -5,6 +5,7 @@
 #include "MantidDataObjects/EventWorkspace.h"
 #include "MantidKernel/BoundedValidator.h"
 #include "MantidKernel/PhysicalConstants.h"
+#include "MantidKernel/Unit.h"
 #include "MantidKernel/VectorHelper.h"
 
 namespace Mantid {
diff --git a/Framework/Algorithms/src/SumEventsByLogValue.cpp b/Framework/Algorithms/src/SumEventsByLogValue.cpp
index e344885039b609ef9e7d3c2f168ade6299099383..fe6886489006bcc658317ad0848328d1345c36b0 100644
--- a/Framework/Algorithms/src/SumEventsByLogValue.cpp
+++ b/Framework/Algorithms/src/SumEventsByLogValue.cpp
@@ -4,6 +4,7 @@
 #include "MantidAPI/Column.h"
 #include "MantidAPI/ITableWorkspace.h"
 #include "MantidAPI/Run.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidGeometry/IDetector.h"
 #include "MantidKernel/ArrayProperty.h"
@@ -82,7 +83,7 @@ std::map<std::string, std::string> SumEventsByLogValue::validateInputs() {
   } catch (Exception::NotFoundError &) {
     errors["LogName"] = "The log '" + m_logName +
                         "' does not exist in the workspace '" +
-                        m_inputWorkspace->name() + "'.";
+                        m_inputWorkspace->getName() + "'.";
     return errors;
   }
 
@@ -305,14 +306,15 @@ void SumEventsByLogValue::addMonitorCounts(ITableWorkspace_sptr outputWorkspace,
   if (!monitorWorkspace)
     return;
 
+  const auto &spectrumInfo = monitorWorkspace->spectrumInfo();
+
   const int xLength = maxVal - minVal + 1;
   // Loop over the spectra - there will be one per monitor
   for (std::size_t spec = 0; spec < monitorWorkspace->getNumberHistograms();
        ++spec) {
     try {
       // Create a column for this monitor
-      const std::string monitorName =
-          monitorWorkspace->getDetector(spec)->getName();
+      const std::string monitorName = spectrumInfo.detector(spec).getName();
       auto monitorCounts = outputWorkspace->addColumn("int", monitorName);
       const IEventList &eventList = monitorWorkspace->getSpectrum(spec);
       // Accumulate things in a local vector before transferring to the table
diff --git a/Framework/Algorithms/src/SumNeighbours.cpp b/Framework/Algorithms/src/SumNeighbours.cpp
index 67282904d1e67c27c1547716ecaad1047861f7d5..ded1a31e9c42de10ee3610bcbb8bc57dc73fccde 100644
--- a/Framework/Algorithms/src/SumNeighbours.cpp
+++ b/Framework/Algorithms/src/SumNeighbours.cpp
@@ -3,6 +3,7 @@
 //----------------------------------------------------------------------
 #include "MantidAlgorithms/SumNeighbours.h"
 #include "MantidAPI/InstrumentValidator.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidDataObjects/EventWorkspace.h"
 #include "MantidDataObjects/EventList.h"
 #include "MantidGeometry/IComponent.h"
@@ -62,9 +63,10 @@ void SumNeighbours::exec() {
 
   // Get the input workspace
   Mantid::API::MatrixWorkspace_sptr inWS = getProperty("InputWorkspace");
-  Mantid::Geometry::IDetector_const_sptr det = inWS->getDetector(0);
+  const auto &spectrumInfo = inWS->spectrumInfo();
+  const auto &det = spectrumInfo.detector(0);
   // Check if grandparent is rectangular detector
-  boost::shared_ptr<const Geometry::IComponent> parent = det->getParent();
+  boost::shared_ptr<const Geometry::IComponent> parent = det.getParent();
   boost::shared_ptr<const RectangularDetector> rect;
 
   if (parent) {
diff --git a/Framework/Algorithms/src/SumSpectra.cpp b/Framework/Algorithms/src/SumSpectra.cpp
index 95c16d6ba4c91dd4cde6d92a6bac836651be185f..353fd38503e8dd302f37c114fa94073c0aa011a4 100644
--- a/Framework/Algorithms/src/SumSpectra.cpp
+++ b/Framework/Algorithms/src/SumSpectra.cpp
@@ -4,6 +4,7 @@
 #include "MantidAPI/SpectrumInfo.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidDataObjects/RebinnedOutput.h"
+#include "MantidDataObjects/WorkspaceCreation.h"
 #include "MantidGeometry/IDetector.h"
 #include "MantidKernel/ArrayProperty.h"
 #include "MantidKernel/BoundedValidator.h"
@@ -20,7 +21,8 @@ using namespace DataObjects;
 
 SumSpectra::SumSpectra()
     : API::Algorithm(), m_outSpecNum(0), m_minWsInd(0), m_maxWsInd(0),
-      m_keepMonitors(false), m_numberOfSpectra(0), m_yLength(0), m_indices(),
+      m_keepMonitors(false), m_replaceSpecialValues(false),
+      m_numberOfSpectra(0), m_yLength(0), m_indices(),
       m_calculateWeightedSum(false) {}
 
 /** Initialisation method.
@@ -68,6 +70,10 @@ void SumSpectra::init() {
                   "values with zero error are dropped from the summation. To "
                   "estimate the number of dropped values see the "
                   "description. ");
+
+  declareProperty("RemoveSpecialValues", false,
+                  "If enabled floating point special values such as NaN or Inf"
+                  " are removed before the spectra are summed.");
 }
 
 /** Executes the algorithm
@@ -80,6 +86,7 @@ void SumSpectra::exec() {
   const std::vector<int> indices_list = getProperty("ListOfWorkspaceIndices");
 
   m_keepMonitors = getProperty("IncludeMonitors");
+  m_replaceSpecialValues = getProperty("RemoveSpecialValues");
 
   // Get the input workspace
   MatrixWorkspace_const_sptr localworkspace = getProperty("InputWorkspace");
@@ -140,7 +147,7 @@ void SumSpectra::exec() {
     size_t numMasked(0);  // total number of the masked and skipped spectra
     size_t numZeros(0);   // number of spectra which have 0 value in the first
     // column (used in special cases of evaluating how good
-    // Puasonian statistics is)
+    // Poissonian statistics is)
 
     Progress progress(this, 0, 1, this->m_indices.size());
 
@@ -158,8 +165,7 @@ void SumSpectra::exec() {
       this->doRebinnedOutput(outputWorkspace, progress, numSpectra, numMasked,
                              numZeros);
     } else {
-      this->doWorkspace2D(localworkspace, outSpec, progress, numSpectra,
-                          numMasked, numZeros);
+      this->doWorkspace2D(outSpec, progress, numSpectra, numMasked, numZeros);
     }
 
     // Pointer to sqrt function
@@ -211,9 +217,33 @@ SumSpectra::getOutputSpecNo(MatrixWorkspace_const_sptr localworkspace) {
   return specId;
 }
 
+/**
+  * Calls an algorithm to replace special values within the workspace
+  * such as NaN or Inf to 0.
+  * @param inputWs The workspace to process
+  * @return The workspace with special floating point values set to 0
+  */
+API::MatrixWorkspace_sptr
+SumSpectra::replaceSpecialValues(API::MatrixWorkspace_sptr inputWs) {
+  if (!m_replaceSpecialValues) {
+    // Skip any additional processing
+    return inputWs;
+  }
+
+  IAlgorithm_sptr alg = this->createChildAlgorithm("ReplaceSpecialValues");
+  alg->setProperty<MatrixWorkspace_sptr>("InputWorkspace", inputWs);
+  std::string outName = "_" + inputWs->getName() + "_clean";
+  alg->setProperty("OutputWorkspace", outName);
+  alg->setProperty("NaNValue", 0.0);
+  alg->setProperty("NaNError", 0.0);
+  alg->setProperty("InfinityValue", 0.0);
+  alg->setProperty("InfinityError", 0.0);
+  alg->executeAsChildAlg();
+  return alg->getProperty("OutputWorkspace");
+}
+
 /**
  * This function deals with the logic necessary for summing a Workspace2D.
- * @param localworkspace The input workspace for summing.
  * @param outSpec The spectrum for the summed output.
  * @param progress The progress indicator.
  * @param numSpectra The number of spectra contributed to the sum.
@@ -222,69 +252,74 @@ SumSpectra::getOutputSpecNo(MatrixWorkspace_const_sptr localworkspace) {
  * @param numZeros The number of zero bins in histogram workspace or empty
  * spectra for event workspace.
  */
-void SumSpectra::doWorkspace2D(MatrixWorkspace_const_sptr localworkspace,
-                               ISpectrum &outSpec, Progress &progress,
+void SumSpectra::doWorkspace2D(ISpectrum &outSpec, Progress &progress,
                                size_t &numSpectra, size_t &numMasked,
                                size_t &numZeros) {
   // Get references to the output workspaces's data vectors
-  auto &YSum = outSpec.mutableY();
-  auto &YError = outSpec.mutableE();
+  auto &OutputYSum = outSpec.mutableY();
+  auto &OutputYError = outSpec.mutableE();
 
   std::vector<double> Weight;
   std::vector<size_t> nZeros;
   if (m_calculateWeightedSum) {
-    Weight.assign(YSum.size(), 0);
-    nZeros.assign(YSum.size(), 0);
+    Weight.assign(OutputYSum.size(), 0);
+    nZeros.assign(OutputYSum.size(), 0);
   }
   numSpectra = 0;
   numMasked = 0;
   numZeros = 0;
 
+  MatrixWorkspace_sptr in_ws = getProperty("InputWorkspace");
+  // Clean workspace of any NANs or Inf values
+  auto localworkspace = replaceSpecialValues(in_ws);
   const auto &spectrumInfo = localworkspace->spectrumInfo();
   // Loop over spectra
-  for (const auto i : this->m_indices) {
+  for (const auto wsIndex : this->m_indices) {
     // Don't go outside the range.
-    if ((i >= this->m_numberOfSpectra) || (i < 0)) {
-      g_log.error() << "Invalid index " << i
+    if ((wsIndex >= this->m_numberOfSpectra) || (wsIndex < 0)) {
+      g_log.error() << "Invalid index " << wsIndex
                     << " was specified. Sum was aborted.\n";
       break;
     }
 
-    if (spectrumInfo.hasDetectors(i)) {
+    if (spectrumInfo.hasDetectors(wsIndex)) {
       // Skip monitors, if the property is set to do so
-      if (!m_keepMonitors && spectrumInfo.isMonitor(i))
+      if (!m_keepMonitors && spectrumInfo.isMonitor(wsIndex))
         continue;
       // Skip masked detectors
-      if (spectrumInfo.isMasked(i)) {
+      if (spectrumInfo.isMasked(wsIndex)) {
         numMasked++;
         continue;
       }
     }
     numSpectra++;
 
-    // Retrieve the spectrum into a vector
-    const auto &YValues = localworkspace->y(i);
-    const auto &YErrors = localworkspace->e(i);
+    const auto &YValues = localworkspace->y(wsIndex);
+    const auto &YErrors = localworkspace->e(wsIndex);
     if (m_calculateWeightedSum) {
-      for (int k = 0; k < this->m_yLength; ++k) {
-        if (YErrors[k] != 0) {
-          double errsq = YErrors[k] * YErrors[k];
-          YError[k] += errsq;
-          Weight[k] += 1. / errsq;
-          YSum[k] += YValues[k] / errsq;
+      // Retrieve the spectrum into a vector
+      for (int i = 0; i < m_yLength; ++i) {
+        if (std::isnormal(YErrors[i])) {
+          const double yErrorsVal = YErrors[i];
+          const double errsq = yErrorsVal * yErrorsVal;
+          OutputYError[i] += errsq;
+          Weight[i] += 1. / errsq;
+          OutputYSum[i] += YValues[i] / errsq;
         } else {
-          nZeros[k]++;
+          nZeros[i]++;
         }
       }
     } else {
-      for (int k = 0; k < this->m_yLength; ++k) {
-        YSum[k] += YValues[k];
-        YError[k] += YErrors[k] * YErrors[k];
+      OutputYSum += YValues;
+      for (int i = 0; i < m_yLength; ++i) {
+        const auto yErrorsVal = YErrors[i];
+        OutputYError[i] += yErrorsVal * yErrorsVal;
       }
     }
 
     // Map all the detectors onto the spectrum of the output
-    outSpec.addDetectorIDs(localworkspace->getSpectrum(i).getDetectorIDs());
+    outSpec.addDetectorIDs(
+        localworkspace->getSpectrum(wsIndex).getDetectorIDs());
 
     progress.report();
   }
@@ -293,7 +328,7 @@ void SumSpectra::doWorkspace2D(MatrixWorkspace_const_sptr localworkspace,
     numZeros = 0;
     for (size_t i = 0; i < Weight.size(); i++) {
       if (numSpectra > nZeros[i])
-        YSum[i] *= double(numSpectra - nZeros[i]) / Weight[i];
+        OutputYSum[i] *= double(numSpectra - nZeros[i]) / Weight[i];
       if (nZeros[i] != 0)
         numZeros += nZeros[i];
     }
@@ -312,21 +347,12 @@ void SumSpectra::doRebinnedOutput(MatrixWorkspace_sptr outputWorkspace,
                                   Progress &progress, size_t &numSpectra,
                                   size_t &numMasked, size_t &numZeros) {
   // Get a copy of the input workspace
-  MatrixWorkspace_sptr temp = getProperty("InputWorkspace");
+  MatrixWorkspace_sptr in_ws = getProperty("InputWorkspace");
 
   // First, we need to clean the input workspace for nan's and inf's in order
   // to treat the data correctly later. This will create a new private
   // workspace that will be retrieved as mutable.
-  IAlgorithm_sptr alg = this->createChildAlgorithm("ReplaceSpecialValues");
-  alg->setProperty<MatrixWorkspace_sptr>("InputWorkspace", temp);
-  std::string outName = "_" + temp->getName() + "_clean";
-  alg->setProperty("OutputWorkspace", outName);
-  alg->setProperty("NaNValue", 0.0);
-  alg->setProperty("NaNError", 0.0);
-  alg->setProperty("InfinityValue", 0.0);
-  alg->setProperty("InfinityError", 0.0);
-  alg->executeAsChildAlg();
-  MatrixWorkspace_sptr localworkspace = alg->getProperty("OutputWorkspace");
+  auto localworkspace = replaceSpecialValues(in_ws);
 
   // Transform to real workspace types
   RebinnedOutput_sptr inWS =
@@ -423,13 +449,7 @@ void SumSpectra::doRebinnedOutput(MatrixWorkspace_sptr outputWorkspace,
  */
 void SumSpectra::execEvent(EventWorkspace_const_sptr localworkspace,
                            std::set<int> &indices) {
-  // Make a brand new EventWorkspace
-  EventWorkspace_sptr outputWorkspace =
-      boost::dynamic_pointer_cast<EventWorkspace>(
-          API::WorkspaceFactory::Instance().create("EventWorkspace", 1, 2, 1));
-  // Copy geometry over.
-  API::WorkspaceFactory::Instance().initializeFromParent(localworkspace,
-                                                         outputWorkspace, true);
+  auto outputWorkspace = create<EventWorkspace>(*localworkspace, 1);
 
   Progress progress(this, 0, 1, indices.size());
 
@@ -473,9 +493,6 @@ void SumSpectra::execEvent(EventWorkspace_const_sptr localworkspace,
     progress.report();
   }
 
-  // Set all X bins on the output
-  outputWorkspace->setAllX(localworkspace->binEdges(0));
-
   outputWorkspace->mutableRun().addProperty("NumAllSpectra", int(numSpectra),
                                             "", true);
   outputWorkspace->mutableRun().addProperty("NumMaskSpectra", int(numMasked),
@@ -484,8 +501,7 @@ void SumSpectra::execEvent(EventWorkspace_const_sptr localworkspace,
                                             true);
 
   // Assign it to the output workspace property
-  setProperty("OutputWorkspace",
-              boost::dynamic_pointer_cast<MatrixWorkspace>(outputWorkspace));
+  setProperty("OutputWorkspace", std::move(outputWorkspace));
 }
 
 } // namespace Algorithms
diff --git a/Framework/Algorithms/src/TimeAtSampleStrategyElastic.cpp b/Framework/Algorithms/src/TimeAtSampleStrategyElastic.cpp
index 8ffec11d65dc38d184b2fd85a3308510266b7924..c86129f728998283f439d340039ffe627303eb2c 100644
--- a/Framework/Algorithms/src/TimeAtSampleStrategyElastic.cpp
+++ b/Framework/Algorithms/src/TimeAtSampleStrategyElastic.cpp
@@ -1,54 +1,24 @@
 #include "MantidAlgorithms/TimeAtSampleStrategyElastic.h"
-#include "MantidGeometry/IDetector.h"
 #include "MantidGeometry/IComponent.h"
 #include "MantidGeometry/Instrument.h"
 #include "MantidGeometry/Instrument/ReferenceFrame.h"
-#include "MantidKernel/V3D.h"
 #include "MantidAPI/MatrixWorkspace.h"
+#include "MantidAPI/SpectrumInfo.h"
 
 using namespace Mantid::Kernel;
 using namespace Mantid::Geometry;
 using namespace Mantid::API;
 
-namespace {
-/**
- * For detectors (not monitor detectors). neutrons interact with the sample
- *first. so the ratio we want to
- * calculate is L1 / (L1 + L2) in order to calculate a TatSample for a neturon
- *based on it's recorded TOF at the detector.
- *
- * For monitors. The L2 scattering distance is of no consequence. The ratio we
- *want to calculate is L1m / L1s where L1m
- * is the L1 for the monitor, and L1s is the L1 for the sample.
- *
- *
- * @param detector : Detector
- * @param source : Source
- * @param L1s : L1 distance Source - Sample
- * @return Calculated ratio
- */
-double calculateTOFRatio(const IDetector &detector, const IComponent &source,
-                         const IComponent &sample, const double &L1s,
-                         const V3D &beamDir) {
-  if (detector.isMonitor()) {
-    double L1m = beamDir.scalar_prod(source.getPos() - detector.getPos());
-    return std::abs(L1s / L1m);
-  } else {
-    const double L2 = sample.getPos().distance(detector.getPos());
-    return L1s / (L1s + L2);
-  }
-}
-}
-
 namespace Mantid {
 namespace Algorithms {
 
-//----------------------------------------------------------------------------------------------
 /** Constructor
  */
 TimeAtSampleStrategyElastic::TimeAtSampleStrategyElastic(
     Mantid::API::MatrixWorkspace_const_sptr ws)
-    : m_ws(ws) {}
+    : m_ws(ws), m_spectrumInfo(m_ws->spectrumInfo()),
+      m_beamDir(
+          m_ws->getInstrument()->getReferenceFrame()->vecPointingAlongBeam()) {}
 
 /**
  * @brief Calculate correction
@@ -57,17 +27,19 @@ TimeAtSampleStrategyElastic::TimeAtSampleStrategyElastic(
  */
 Correction
 TimeAtSampleStrategyElastic::calculate(const size_t &workspace_index) const {
-  auto instrument = m_ws->getInstrument();
-  auto source = instrument->getSource();
-  auto sample = instrument->getSample();
-  const double L1s = source->getDistance(*sample);
-  auto refFrame = instrument->getReferenceFrame();
-  const V3D &beamDir = refFrame->vecPointingAlongBeam();
-  const double factor = calculateTOFRatio(*m_ws->getDetector(workspace_index),
-                                          *source, *sample, L1s, beamDir);
-
   Correction retvalue(0, 0);
-  retvalue.factor = factor;
+
+  // Calculate TOF ratio
+  const double L1s = m_spectrumInfo.l1();
+  if (m_spectrumInfo.isMonitor(workspace_index)) {
+    double L1m =
+        m_beamDir.scalar_prod(m_spectrumInfo.sourcePosition() -
+                              m_spectrumInfo.position(workspace_index));
+    retvalue.factor = std::abs(L1s / L1m);
+  } else {
+    retvalue.factor = L1s / (L1s + m_spectrumInfo.l2(workspace_index));
+  }
+
   retvalue.offset = 0;
 
   return retvalue;
diff --git a/Framework/Algorithms/src/TimeAtSampleStrategyIndirect.cpp b/Framework/Algorithms/src/TimeAtSampleStrategyIndirect.cpp
index 86ce80783e8a957143d36efcc463f8fa96a23d4b..b6e957ecf76ba5f20cf73129fba9ea6a3b71214c 100644
--- a/Framework/Algorithms/src/TimeAtSampleStrategyIndirect.cpp
+++ b/Framework/Algorithms/src/TimeAtSampleStrategyIndirect.cpp
@@ -8,6 +8,7 @@
 #include "MantidKernel/PhysicalConstants.h"
 #include "MantidKernel/V3D.h"
 #include "MantidAPI/MatrixWorkspace.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include <cmath>
 #include <boost/shared_ptr.hpp>
 #include <sstream>
@@ -17,19 +18,13 @@ using namespace Mantid::Geometry;
 using namespace Mantid::API;
 
 namespace Mantid {
-
-namespace API {
-class MatrixWorkspace;
-}
-
 namespace Algorithms {
 
-//----------------------------------------------------------------------------------------------
 /** Constructor
  */
 TimeAtSampleStrategyIndirect::TimeAtSampleStrategyIndirect(
     MatrixWorkspace_const_sptr ws)
-    : m_ws(ws) {}
+    : m_ws(ws), m_spectrumInfo(m_ws->spectrumInfo()) {}
 
 Correction
 TimeAtSampleStrategyIndirect::calculate(const size_t &workspace_index) const {
@@ -37,18 +32,17 @@ TimeAtSampleStrategyIndirect::calculate(const size_t &workspace_index) const {
   // A constant among all spectra
   double twomev_d_mass =
       2. * PhysicalConstants::meV / PhysicalConstants::NeutronMass;
-  V3D samplepos = m_ws->getInstrument()->getSample()->getPos();
 
   // Get the parameter map
   const ParameterMap &pmap = m_ws->constInstrumentParameters();
 
   double shift;
-  IDetector_const_sptr det = m_ws->getDetector(workspace_index);
-  if (!det->isMonitor()) {
+  const IDetector *det = &m_spectrumInfo.detector(workspace_index);
+  if (!m_spectrumInfo.isMonitor(workspace_index)) {
     // Get E_fix
     double efix = 0.;
     try {
-      Parameter_sptr par = pmap.getRecursive(det.get(), "Efixed");
+      Parameter_sptr par = pmap.getRecursive(det, "Efixed");
       if (par) {
         efix = par->value<double>();
       }
@@ -60,10 +54,7 @@ TimeAtSampleStrategyIndirect::calculate(const size_t &workspace_index) const {
       throw std::runtime_error(errmsg.str());
     }
 
-    // Get L2
-    double l2 = det->getPos().distance(samplepos);
-
-    // Calculate shift
+    double l2 = m_spectrumInfo.l2(workspace_index);
     shift = -1. * l2 / sqrt(efix * twomev_d_mass);
 
   } else {
diff --git a/Framework/Algorithms/src/UnGroupWorkspace.cpp b/Framework/Algorithms/src/UnGroupWorkspace.cpp
index 87f1dfcff5a90a6fa43ab1e69555097eabd348c1..816b067e552520f39a14b1fd04e7695cf228203d 100644
--- a/Framework/Algorithms/src/UnGroupWorkspace.cpp
+++ b/Framework/Algorithms/src/UnGroupWorkspace.cpp
@@ -1,5 +1,7 @@
 #include "MantidAlgorithms/UnGroupWorkspace.h"
 #include "MantidKernel/ListValidator.h"
+#include "MantidAPI/AnalysisDataService.h"
+#include "MantidAPI/WorkspaceGroup.h"
 
 namespace Mantid {
 namespace Algorithms {
diff --git a/Framework/Algorithms/src/UnwrapMonitor.cpp b/Framework/Algorithms/src/UnwrapMonitor.cpp
index 7d42b638d6878d561e92425ea46197fbc916e8ad..6d6519460ff56a3a994f4191772ef6742fe8bd96 100644
--- a/Framework/Algorithms/src/UnwrapMonitor.cpp
+++ b/Framework/Algorithms/src/UnwrapMonitor.cpp
@@ -97,7 +97,7 @@ void UnwrapMonitor::exec() {
 
   // This will be used later to store the maximum number of bin BOUNDARIES for
   // the rebinning
-  int max_bins = 0;
+  size_t max_bins = 0;
 
   const auto &spectrumInfo = m_inputWS->spectrumInfo();
   const double L1 = spectrumInfo.l1();
@@ -124,12 +124,12 @@ void UnwrapMonitor::exec() {
 
     // Unwrap the x data. Returns the bin ranges that end up being used
     const double Ld = L1 + spectrumInfo.l2(i);
-    MantidVec newX;
+    std::vector<double> newX;
     const std::vector<int> rangeBounds = this->unwrapX(newX, i, Ld);
 
     // Unwrap the y & e data according to the ranges found above
-    MantidVec newY;
-    MantidVec newE;
+    std::vector<double> newY;
+    std::vector<double> newE;
     this->unwrapYandE(tempWS, i, rangeBounds, newY, newE);
 
     // Now set the new X, Y and E values on the Histogram
@@ -142,7 +142,7 @@ void UnwrapMonitor::exec() {
     // Get the maximum number of bins (excluding monitors) for the rebinning
     // below
     if (!spectrumInfo.isMonitor(i)) {
-      const int XLen = static_cast<int>(tempWS->x(i).size());
+      const size_t XLen = tempWS->x(i).size();
       if (XLen > max_bins)
         max_bins = XLen;
     }
@@ -176,8 +176,9 @@ void UnwrapMonitor::exec() {
  *  @return A 3-element vector containing the bins at which the upper and lower
  * ranges start & end
  */
-const std::vector<int>
-UnwrapMonitor::unwrapX(MantidVec &newX, const int &spectrum, const double &Ld) {
+const std::vector<int> UnwrapMonitor::unwrapX(std::vector<double> &newX,
+                                              const int &spectrum,
+                                              const double &Ld) {
   // Create and initalise the vector that will store the bin ranges, and will be
   // returned
   // Elements are: 0 - Lower range start, 1 - Lower range end, 2 - Upper range
@@ -302,10 +303,11 @@ std::pair<int, int> UnwrapMonitor::handleFrameOverlapped(
 void UnwrapMonitor::unwrapYandE(const API::MatrixWorkspace_sptr &tempWS,
                                 const int &spectrum,
                                 const std::vector<int> &rangeBounds,
-                                MantidVec &newY, MantidVec &newE) {
+                                std::vector<double> &newY,
+                                std::vector<double> &newE) {
   // Copy over the relevant ranges of Y & E data
-  MantidVec &Y = newY;
-  MantidVec &E = newE;
+  std::vector<double> &Y = newY;
+  std::vector<double> &E = newE;
   // Get references to the input data
   const auto &YIn = m_inputWS->y(spectrum);
   const auto &EIn = m_inputWS->e(spectrum);
@@ -360,9 +362,10 @@ void UnwrapMonitor::unwrapYandE(const API::MatrixWorkspace_sptr &tempWS,
  */
 API::MatrixWorkspace_sptr
 UnwrapMonitor::rebin(const API::MatrixWorkspace_sptr &workspace,
-                     const double &min, const double &max, const int &numBins) {
+                     const double &min, const double &max,
+                     const size_t &numBins) {
   // Calculate the width of a bin
-  const double step = (max - min) / numBins;
+  const double step = (max - min) / static_cast<double>(numBins);
 
   // Create a Rebin child algorithm
   IAlgorithm_sptr childAlg = createChildAlgorithm("Rebin");
diff --git a/Framework/Algorithms/src/UnwrapMonitorsInTOF.cpp b/Framework/Algorithms/src/UnwrapMonitorsInTOF.cpp
index 48a4406c7a1e35eceafc24bcb6c47d910df1277f..3a4e2f7854eac6b11f106d90476d09165c6ea456 100644
--- a/Framework/Algorithms/src/UnwrapMonitorsInTOF.cpp
+++ b/Framework/Algorithms/src/UnwrapMonitorsInTOF.cpp
@@ -2,6 +2,7 @@
 #include "MantidAPI/WorkspaceProperty.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/ISpectrum.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidGeometry/Instrument.h"
 #include "MantidKernel/PhysicalConstants.h"
@@ -62,18 +63,19 @@ MinAndMaxTof getMinAndMaxTofForDistanceFromSoure(double distanceFromSource,
   return MinAndMaxTof(minTof, maxTof);
 }
 
-double
-getDistanceFromSourceForWorkspaceIndex(Mantid::API::MatrixWorkspace *workspace,
-                                       size_t workspaceIndex) {
-  const auto detector = workspace->getDetector(workspaceIndex);
-  return detector->getDistance(*(workspace->getInstrument()->getSource()));
+double getDistanceFromSourceForWorkspaceIndex(
+    Mantid::API::MatrixWorkspace *workspace,
+    const Mantid::API::SpectrumInfo &spectrumInfo, size_t workspaceIndex) {
+  const auto &detector = spectrumInfo.detector(workspaceIndex);
+  return detector.getDistance(*(workspace->getInstrument()->getSource()));
 }
 
 MinAndMaxTof getMinAndMaxTof(Mantid::API::MatrixWorkspace *workspace,
+                             const Mantid::API::SpectrumInfo &spectrumInfo,
                              size_t workspaceIndex, double lowerWavelengthLimit,
                              double upperWavelengthLimit) {
-  const auto distanceFromSource =
-      getDistanceFromSourceForWorkspaceIndex(workspace, workspaceIndex);
+  const auto distanceFromSource = getDistanceFromSourceForWorkspaceIndex(
+      workspace, spectrumInfo, workspaceIndex);
   return getMinAndMaxTofForDistanceFromSoure(
       distanceFromSource, lowerWavelengthLimit, upperWavelengthLimit);
 }
@@ -242,10 +244,10 @@ getWorkspaceIndicesForMonitors(Mantid::API::MatrixWorkspace *workspace) {
     }
   } else {
     auto numberOfHistograms = workspace->getNumberHistograms();
+    const auto &spectrumInfo = workspace->spectrumInfo();
     for (size_t workspaceIndex = 0; workspaceIndex < numberOfHistograms;
          ++workspaceIndex) {
-      auto detector = workspace->getDetector(workspaceIndex);
-      if (detector->isMonitor()) {
+      if (spectrumInfo.isMonitor(workspaceIndex)) {
         workspaceIndices.push_back(workspaceIndex);
       }
     }
@@ -331,15 +333,28 @@ void UnwrapMonitorsInTOF::exec() {
   const auto workspaceIndices =
       getWorkspaceIndicesForMonitors(outputWorkspace.get());
 
+  const auto &spectrumInfo = outputWorkspace->spectrumInfo();
+
   for (const auto &workspaceIndex : workspaceIndices) {
     const auto minMaxTof =
-        getMinAndMaxTof(outputWorkspace.get(), workspaceIndex,
+        getMinAndMaxTof(outputWorkspace.get(), spectrumInfo, workspaceIndex,
                         lowerWavelengthLimit, upperWavelengthLimit);
     auto points = getPoints(outputWorkspace.get(), workspaceIndex);
     auto counts =
         getCounts(outputWorkspace.get(), workspaceIndex, minMaxTof, points);
-    Mantid::HistogramData::Histogram histogram(points, counts);
-    outputWorkspace->setHistogram(workspaceIndex, histogram);
+    // Get the input histogram
+    auto inputHistogram = inputWorkspace->histogram(workspaceIndex);
+    auto spectrumIsHistogramData =
+        inputHistogram.xMode() ==
+        Mantid::HistogramData::Histogram::XMode::BinEdges;
+    if (spectrumIsHistogramData) {
+      Mantid::HistogramData::BinEdges binEdges(points);
+      Mantid::HistogramData::Histogram histogram(binEdges, counts);
+      outputWorkspace->setHistogram(workspaceIndex, histogram);
+    } else {
+      Mantid::HistogramData::Histogram histogram(points, counts);
+      outputWorkspace->setHistogram(workspaceIndex, histogram);
+    }
   }
   setProperty("OutputWorkspace", outputWorkspace);
 }
diff --git a/Framework/Algorithms/src/UnwrapSNS.cpp b/Framework/Algorithms/src/UnwrapSNS.cpp
index bb222f377302d1bc01bebbade2aa7dfa4eb54c6f..ab2a39198048fe388ac4dafa5bdc790b0143552b 100644
--- a/Framework/Algorithms/src/UnwrapSNS.cpp
+++ b/Framework/Algorithms/src/UnwrapSNS.cpp
@@ -150,7 +150,7 @@ void UnwrapSNS::exec() {
     } else {
       const double Ld = L1 + spectrumInfo.l2(workspaceIndex);
       // fix the x-axis
-      MantidVec timeBins;
+      std::vector<double> timeBins;
       size_t pivot = this->unwrapX(m_inputWS->x(workspaceIndex), timeBins, Ld);
       outputWS->setBinEdges(workspaceIndex, std::move(timeBins));
 
@@ -212,7 +212,7 @@ void UnwrapSNS::execEvent() {
     if (spectrumInfo.hasDetectors(workspaceIndex))
       Ld = L1 + spectrumInfo.l2(workspaceIndex);
 
-    MantidVec time_bins;
+    std::vector<double> time_bins;
     if (outW->x(0).size() > 2) {
       this->unwrapX(m_inputWS->x(workspaceIndex), time_bins, Ld);
       outW->setBinEdges(workspaceIndex, std::move(time_bins));
@@ -220,7 +220,7 @@ void UnwrapSNS::execEvent() {
       outW->setSharedX(workspaceIndex, m_inputWS->sharedX(workspaceIndex));
     }
     if (numEvents > 0) {
-      MantidVec times(numEvents);
+      std::vector<double> times(numEvents);
       outW->getSpectrum(workspaceIndex).getTofs(times);
       double filterVal = m_Tmin * Ld / m_LRef;
       for (size_t j = 0; j < numEvents; j++) {
@@ -239,11 +239,11 @@ void UnwrapSNS::execEvent() {
 }
 
 int UnwrapSNS::unwrapX(const Mantid::HistogramData::HistogramX &datain,
-                       MantidVec &dataout, const double &Ld) {
-  MantidVec tempX_L; // lower half - to be frame wrapped
+                       std::vector<double> &dataout, const double &Ld) {
+  std::vector<double> tempX_L; // lower half - to be frame wrapped
   tempX_L.reserve(m_XSize);
   tempX_L.clear();
-  MantidVec tempX_U; // upper half - to not be frame wrapped
+  std::vector<double> tempX_U; // upper half - to not be frame wrapped
   tempX_U.reserve(m_XSize);
   tempX_U.clear();
 
diff --git a/Framework/Algorithms/src/VesuvioL1ThetaResolution.cpp b/Framework/Algorithms/src/VesuvioL1ThetaResolution.cpp
index dfcb105e054d8bb8b140f1f83623055df87fe92b..8e1f7bc734975d6336e6eda1e16ce4242976f0bd 100644
--- a/Framework/Algorithms/src/VesuvioL1ThetaResolution.cpp
+++ b/Framework/Algorithms/src/VesuvioL1ThetaResolution.cpp
@@ -4,8 +4,10 @@
 #include "MantidAPI/FileProperty.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/TextAxis.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidGeometry/Instrument.h"
+#include "MantidGeometry/Objects/Object.h"
 #include "MantidKernel/BoundedValidator.h"
 #include "MantidKernel/Statistics.h"
 #include "MantidKernel/Unit.h"
@@ -37,8 +39,6 @@ public:
 // Register the algorithm into the AlgorithmFactory
 DECLARE_ALGORITHM(VesuvioL1ThetaResolution)
 
-//----------------------------------------------------------------------------------------------
-
 /// Algorithms name for identification. @see Algorithm::name
 const std::string VesuvioL1ThetaResolution::name() const {
   return "VesuvioL1ThetaResolution";
@@ -174,17 +174,19 @@ void VesuvioL1ThetaResolution::exec() {
   // Set up progress reporting
   Progress prog(this, 0.0, 1.0, numHist);
 
+  const auto &spectrumInfo = m_instWorkspace->spectrumInfo();
+
   // Loop for all detectors
   for (size_t i = 0; i < numHist; i++) {
     std::vector<double> l1;
     std::vector<double> theta;
-    IDetector_const_sptr det = m_instWorkspace->getDetector(i);
+    const auto &det = spectrumInfo.detector(i);
 
     // Report progress
     std::stringstream report;
-    report << "Detector " << det->getID();
+    report << "Detector " << det.getID();
     prog.report(report.str());
-    g_log.information() << "Detector ID " << det->getID() << '\n';
+    g_log.information() << "Detector ID " << det.getID() << '\n';
 
     // Do simulation
     calculateDetector(det, l1, theta);
@@ -213,31 +215,29 @@ void VesuvioL1ThetaResolution::exec() {
     // Process data for L1 distribution
     if (m_l1DistributionWs) {
       auto &x = m_l1DistributionWs->mutableX(i);
-      std::vector<double> y(numEvents, 1.0);
 
       std::sort(l1.begin(), l1.end());
       std::copy(l1.begin(), l1.end(), x.begin());
 
-      m_l1DistributionWs->mutableY(i) = y;
+      m_l1DistributionWs->mutableY(i) = 1.0;
 
       auto &spec = m_l1DistributionWs->getSpectrum(i);
       spec.setSpectrumNo(specNo);
-      spec.addDetectorID(det->getID());
+      spec.addDetectorID(det.getID());
     }
 
     // Process data for theta distribution
     if (m_thetaDistributionWs) {
       auto &x = m_thetaDistributionWs->mutableX(i);
-      std::vector<double> y(numEvents, 1.0);
 
       std::sort(theta.begin(), theta.end());
       std::copy(theta.begin(), theta.end(), x.begin());
 
-      m_thetaDistributionWs->mutableY(i) = y;
+      m_thetaDistributionWs->mutableY(i) = 1.0;
 
       auto &spec = m_thetaDistributionWs->getSpectrum(i);
       spec.setSpectrumNo(specNo);
-      spec.addDetectorID(det->getID());
+      spec.addDetectorID(det.getID());
     }
   }
 
@@ -350,7 +350,7 @@ void VesuvioL1ThetaResolution::loadInstrument() {
 /** Loads the instrument into a workspace.
  */
 void VesuvioL1ThetaResolution::calculateDetector(
-    IDetector_const_sptr detector, std::vector<double> &l1Values,
+    const IDetector &detector, std::vector<double> &l1Values,
     std::vector<double> &thetaValues) {
   const int numEvents = getProperty("NumEvents");
   l1Values.reserve(numEvents);
@@ -362,7 +362,7 @@ void VesuvioL1ThetaResolution::calculateDetector(
     sampleWidth = 4.0;
 
   // Get detector dimensions
-  Geometry::Object_const_sptr pixelShape = detector->shape();
+  Geometry::Object_const_sptr pixelShape = detector.shape();
   if (!pixelShape || !pixelShape->hasValidShape()) {
     throw std::invalid_argument("Detector pixel has no defined shape!");
   }
@@ -375,12 +375,12 @@ void VesuvioL1ThetaResolution::calculateDetector(
                 << '\n';
 
   // Scattering angle in rad
-  const double theta = m_instWorkspace->detectorTwoTheta(*detector);
+  const double theta = m_instWorkspace->detectorTwoTheta(detector);
   if (theta == 0.0)
     return;
 
   // Final flight path in cm
-  const double l1av = detector->getDistance(*m_sample) * 100.0;
+  const double l1av = detector.getDistance(*m_sample) * 100.0;
 
   const double x0 = l1av * sin(theta);
   const double y0 = l1av * cos(theta);
diff --git a/Framework/Algorithms/src/WienerSmooth.cpp b/Framework/Algorithms/src/WienerSmooth.cpp
index a8f8d361dddf9bf06d40028e2290b4b18c811ebc..0d1683b2624ea21a1f0678b89055f88180486bea 100644
--- a/Framework/Algorithms/src/WienerSmooth.cpp
+++ b/Framework/Algorithms/src/WienerSmooth.cpp
@@ -371,9 +371,10 @@ WienerSmooth::smoothSingleSpectrum(API::MatrixWorkspace_sptr inputWS,
     auto histogram = out->histogram(0);
     histogram.setSharedX(inputWS->sharedX(wsIndex));
     histogram.setSharedE(inputWS->sharedE(wsIndex));
-    auto newSize = histogram.y().size() - 1;
 
+    auto newSize = histogram.y().size() - 1;
     histogram.resize(newSize);
+
     out->setHistogram(0, histogram);
   } else {
     out->setSharedX(0, inputWS->sharedX(wsIndex));
@@ -386,9 +387,8 @@ WienerSmooth::smoothSingleSpectrum(API::MatrixWorkspace_sptr inputWS,
 /**
  * Get the start and end of the x-interval.
  * @param X :: The x-vector of a spectrum.
- * @param isHistogram :: Is the x-vector comming form a histogram? If it's true
- * the bin
- *   centres are used.
+ * @param isHistogram :: Is the x-vector coming form a histogram? If it's true
+ * the bin centers are used.
  * @return :: A pair of start x and end x.
  */
 std::pair<double, double>
diff --git a/Framework/Algorithms/src/WorkflowAlgorithmRunner.cpp b/Framework/Algorithms/src/WorkflowAlgorithmRunner.cpp
index c41b7b2f6cf0db115c3073f9d21b2d8dc0cbc12a..c0969dddf839feb9f60d955a635465d412d0e670 100644
--- a/Framework/Algorithms/src/WorkflowAlgorithmRunner.cpp
+++ b/Framework/Algorithms/src/WorkflowAlgorithmRunner.cpp
@@ -3,6 +3,7 @@
 #include "MantidAPI/ITableWorkspace.h"
 #include "MantidKernel/MandatoryValidator.h"
 
+#include <deque>
 #include <unordered_map>
 
 using namespace Mantid::API;
diff --git a/Framework/Algorithms/src/WorkspaceJoiners.cpp b/Framework/Algorithms/src/WorkspaceJoiners.cpp
index 9f63c08f5cb7496e0827d7c2f80cb66583a0db07..2703228332aaca364febf218dbea5fbcfd528948 100644
--- a/Framework/Algorithms/src/WorkspaceJoiners.cpp
+++ b/Framework/Algorithms/src/WorkspaceJoiners.cpp
@@ -5,6 +5,8 @@
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidGeometry/IDetector.h"
 #include "MantidGeometry/Instrument.h"
+#include "MantidDataObjects/WorkspaceCreation.h"
+#include "MantidKernel/Unit.h"
 
 namespace Mantid {
 namespace Algorithms {
@@ -29,40 +31,39 @@ const std::string WorkspaceJoiners::category() const {
 /** Executes the algorithm for histogram workspace inputs
  *  @returns The result workspace
  */
-MatrixWorkspace_sptr
-WorkspaceJoiners::execWS2D(API::MatrixWorkspace_const_sptr ws1,
-                           API::MatrixWorkspace_const_sptr ws2) {
+MatrixWorkspace_sptr WorkspaceJoiners::execWS2D(const MatrixWorkspace &ws1,
+                                                const MatrixWorkspace &ws2) {
   // Create the output workspace
   const size_t totalHists =
-      ws1->getNumberHistograms() + ws2->getNumberHistograms();
+      ws1.getNumberHistograms() + ws2.getNumberHistograms();
   MatrixWorkspace_sptr output = WorkspaceFactory::Instance().create(
-      "Workspace2D", totalHists, ws1->x(0).size(), ws1->y(0).size());
+      "Workspace2D", totalHists, ws1.x(0).size(), ws1.y(0).size());
   // Copy over stuff from first input workspace. This will include the spectrum
   // masking
-  WorkspaceFactory::Instance().initializeFromParent(ws1, output, true);
+  WorkspaceFactory::Instance().initializeFromParent(ws1, *output, true);
 
   // Create the X values inside a cow pointer - they will be shared in the
   // output workspace
-  auto XValues = ws1->refX(0);
+  auto XValues = ws1.refX(0);
 
   // Initialize the progress reporting object
   m_progress = new API::Progress(this, 0.0, 1.0, totalHists);
 
   // Loop over the input workspaces in turn copying the data into the output one
-  const int64_t &nhist1 = ws1->getNumberHistograms();
-  PARALLEL_FOR_IF(Kernel::threadSafe(*ws1, *output))
+  const int64_t &nhist1 = ws1.getNumberHistograms();
+  PARALLEL_FOR_IF(Kernel::threadSafe(ws1, *output))
   for (int64_t i = 0; i < nhist1; ++i) {
     PARALLEL_START_INTERUPT_REGION
     auto &outSpec = output->getSpectrum(i);
-    const auto &inSpec = ws1->getSpectrum(i);
+    const auto &inSpec = ws1.getSpectrum(i);
 
     outSpec.setHistogram(inSpec.histogram());
     // Copy the spectrum number/detector IDs
     outSpec.copyInfoFrom(inSpec);
 
     // Propagate binmasking, if needed
-    if (ws1->hasMaskedBins(i)) {
-      for (const auto &inputMask : ws1->maskedBins(i)) {
+    if (ws1.hasMaskedBins(i)) {
+      for (const auto &inputMask : ws1.maskedBins(i)) {
         output->flagMasked(i, inputMask.first, inputMask.second);
       }
     }
@@ -73,36 +74,41 @@ WorkspaceJoiners::execWS2D(API::MatrixWorkspace_const_sptr ws1,
   PARALLEL_CHECK_INTERUPT_REGION
 
   // For second loop we use the offset from the first
-  const int64_t &nhist2 = ws2->getNumberHistograms();
-  const auto &spectrumInfo = ws2->spectrumInfo();
-  PARALLEL_FOR_IF(Kernel::threadSafe(*ws2, *output))
+  const int64_t &nhist2 = ws2.getNumberHistograms();
+  const auto &spectrumInfo = ws2.spectrumInfo();
+  auto &outSpectrumInfo = output->mutableSpectrumInfo();
+  PARALLEL_FOR_IF(Kernel::threadSafe(ws2, *output))
   for (int64_t j = 0; j < nhist2; ++j) {
     PARALLEL_START_INTERUPT_REGION
     // The spectrum in the output workspace
     auto &outSpec = output->getSpectrum(nhist1 + j);
     // Spectrum in the second workspace
-    const auto &inSpec = ws2->getSpectrum(j);
+    const auto &inSpec = ws2.getSpectrum(j);
 
     outSpec.setHistogram(inSpec.histogram());
     // Copy the spectrum number/detector IDs
     outSpec.copyInfoFrom(inSpec);
 
     // Propagate masking, if needed
-    if (ws2->hasMaskedBins(j)) {
-      for (const auto &inputMask : ws2->maskedBins(j)) {
+    if (ws2.hasMaskedBins(j)) {
+      for (const auto &inputMask : ws2.maskedBins(j)) {
         output->flagMasked(nhist1 + j, inputMask.first, inputMask.second);
       }
     }
     // Propagate spectrum masking
-    if (spectrumInfo.hasDetectors(j) && spectrumInfo.isMasked(j))
-      output->maskWorkspaceIndex(nhist1 + j);
+    if (spectrumInfo.hasDetectors(j) && spectrumInfo.isMasked(j)) {
+      output->getSpectrum(nhist1 + j).clearData();
+      PARALLEL_CRITICAL(setMasked) {
+        outSpectrumInfo.setMasked(nhist1 + j, true);
+      }
+    }
 
     m_progress->report();
     PARALLEL_END_INTERUPT_REGION
   }
   PARALLEL_CHECK_INTERUPT_REGION
 
-  fixSpectrumNumbers(ws1, ws2, output);
+  fixSpectrumNumbers(ws1, ws2, *output);
 
   return output;
 }
@@ -116,13 +122,7 @@ MatrixWorkspace_sptr WorkspaceJoiners::execEvent() {
   // Create the output workspace
   const size_t totalHists =
       event_ws1->getNumberHistograms() + event_ws2->getNumberHistograms();
-  // Have the minimum # of histograms in the output.
-  EventWorkspace_sptr output = boost::dynamic_pointer_cast<EventWorkspace>(
-      WorkspaceFactory::Instance().create("EventWorkspace", totalHists,
-                                          event_ws1->x(0).size(),
-                                          event_ws1->y(0).size()));
-  // Copy over geometry (but not data) from first input workspace
-  WorkspaceFactory::Instance().initializeFromParent(event_ws1, output, true);
+  auto output = create<EventWorkspace>(*event_ws1, totalHists);
 
   // Initialize the progress reporting object
   m_progress = new API::Progress(this, 0.0, 1.0, totalHists);
@@ -136,6 +136,7 @@ MatrixWorkspace_sptr WorkspaceJoiners::execEvent() {
   // For second loop we use the offset from the first
   const int64_t &nhist2 = event_ws2->getNumberHistograms();
   const auto &spectrumInfo = event_ws2->spectrumInfo();
+  auto &outSpectrumInfo = output->mutableSpectrumInfo();
   for (int64_t j = 0; j < nhist2; ++j) {
     // This is the workspace index at which we assign in the output
     int64_t output_wi = j + nhist1;
@@ -143,8 +144,12 @@ MatrixWorkspace_sptr WorkspaceJoiners::execEvent() {
 
     // Propagate spectrum masking. First workspace will have been done by the
     // factory
-    if (spectrumInfo.hasDetectors(j) && spectrumInfo.isMasked(j))
-      output->maskWorkspaceIndex(output_wi);
+    if (spectrumInfo.hasDetectors(j) && spectrumInfo.isMasked(j)) {
+      output->getSpectrum(output_wi).clearData();
+      PARALLEL_CRITICAL(setMaskedEvent) {
+        outSpectrumInfo.setMasked(output_wi, true);
+      }
+    }
 
     m_progress->report();
   }
@@ -152,9 +157,9 @@ MatrixWorkspace_sptr WorkspaceJoiners::execEvent() {
   // Set the same bins for all output pixels
   output->setAllX(event_ws1->binEdges(0));
 
-  fixSpectrumNumbers(event_ws1, event_ws2, output);
+  fixSpectrumNumbers(*event_ws1, *event_ws2, *output);
 
-  return output;
+  return std::move(output);
 }
 
 /** Checks that the two input workspace have common binning & size, the same
@@ -164,8 +169,8 @@ MatrixWorkspace_sptr WorkspaceJoiners::execEvent() {
  *  @param ws2 :: The second input workspace
  *  @throw std::invalid_argument If the workspaces are not compatible
  */
-void WorkspaceJoiners::validateInputs(API::MatrixWorkspace_const_sptr ws1,
-                                      API::MatrixWorkspace_const_sptr ws2) {
+void WorkspaceJoiners::validateInputs(const MatrixWorkspace &ws1,
+                                      const MatrixWorkspace &ws2) {
   // This is the full check for common binning
   if (!WorkspaceHelpers::commonBoundaries(ws1) ||
       !WorkspaceHelpers::commonBoundaries(ws2)) {
@@ -175,15 +180,15 @@ void WorkspaceJoiners::validateInputs(API::MatrixWorkspace_const_sptr ws1,
         "Both input workspaces must have common binning for all their spectra");
   }
 
-  if (ws1->getInstrument()->getName() != ws2->getInstrument()->getName()) {
+  if (ws1.getInstrument()->getName() != ws2.getInstrument()->getName()) {
     const std::string message("The input workspaces are not compatible because "
                               "they come from different instruments");
     g_log.error(message);
     throw std::invalid_argument(message);
   }
 
-  Unit_const_sptr ws1_unit = ws1->getAxis(0)->unit();
-  Unit_const_sptr ws2_unit = ws2->getAxis(0)->unit();
+  Unit_const_sptr ws1_unit = ws1.getAxis(0)->unit();
+  Unit_const_sptr ws2_unit = ws2.getAxis(0)->unit();
   const std::string ws1_unitID = (ws1_unit ? ws1_unit->unitID() : "");
   const std::string ws2_unitID = (ws2_unit ? ws2_unit->unitID() : "");
 
@@ -194,7 +199,7 @@ void WorkspaceJoiners::validateInputs(API::MatrixWorkspace_const_sptr ws1,
     throw std::invalid_argument(message);
   }
 
-  if (ws1->isDistribution() != ws2->isDistribution()) {
+  if (ws1.isDistribution() != ws2.isDistribution()) {
     const std::string message(
         "The input workspaces have inconsistent distribution flags");
     g_log.error(message);
@@ -216,14 +221,14 @@ void WorkspaceJoiners::validateInputs(API::MatrixWorkspace_const_sptr ws1,
  * @param min The minimum id (output).
  * @param max The maximum id (output).
  */
-void WorkspaceJoiners::getMinMax(MatrixWorkspace_const_sptr ws, specnum_t &min,
+void WorkspaceJoiners::getMinMax(const MatrixWorkspace &ws, specnum_t &min,
                                  specnum_t &max) {
   specnum_t temp;
-  size_t length = ws->getNumberHistograms();
+  size_t length = ws.getNumberHistograms();
   // initial values
-  min = max = ws->getSpectrum(0).getSpectrumNo();
+  min = max = ws.getSpectrum(0).getSpectrumNo();
   for (size_t i = 0; i < length; i++) {
-    temp = ws->getSpectrum(i).getSpectrumNo();
+    temp = ws.getSpectrum(i).getSpectrumNo();
     // Adjust min/max
     if (temp < min)
       min = temp;
diff --git a/Framework/Algorithms/src/XDataConverter.cpp b/Framework/Algorithms/src/XDataConverter.cpp
index 290cc76352d54e4296c88947d73205f3727f8309..774f67cd843dc4e30670c2438a91e977d7aeebe1 100644
--- a/Framework/Algorithms/src/XDataConverter.cpp
+++ b/Framework/Algorithms/src/XDataConverter.cpp
@@ -51,7 +51,7 @@ void XDataConverter::exec() {
   const int numSpectra = static_cast<int>(inputWS->getNumberHistograms());
   const size_t numYValues = inputWS->blocksize();
   const size_t numXValues = getNewXSize(inputWS);
-  m_sharedX = API::WorkspaceHelpers::sharedXData(inputWS);
+  m_sharedX = API::WorkspaceHelpers::sharedXData(*inputWS);
   // Create the new workspace
   MatrixWorkspace_sptr outputWS = WorkspaceFactory::Instance().create(
       inputWS, numSpectra, numXValues, numYValues);
diff --git a/Framework/Algorithms/test/AddLogDerivativeTest.h b/Framework/Algorithms/test/AddLogDerivativeTest.h
index 4d83e735cc5a6c71f92b432f70c620b418e92612..756cb8cf04a4186297275c2de4dbf495feee6365 100644
--- a/Framework/Algorithms/test/AddLogDerivativeTest.h
+++ b/Framework/Algorithms/test/AddLogDerivativeTest.h
@@ -34,7 +34,7 @@ public:
   /** Perform test, return result */
   TimeSeriesProperty<double> *do_test(int Derivative, bool willFail = false,
                                       bool addRepeatedTimes = false) {
-    Workspace2D_sptr ws = WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+    Workspace2D_sptr ws = WorkspaceCreationHelper::create2DWorkspace(10, 10);
     AnalysisDataService::Instance().addOrReplace("Dummy", ws);
 
     TimeSeriesProperty<double> *p =
diff --git a/Framework/Algorithms/test/AddNoteTest.h b/Framework/Algorithms/test/AddNoteTest.h
index 8397e4aa49ab1395e39960b546f78189ccd91163..f35be8902d98d76ac1a0554cb3270e06bad6b571 100644
--- a/Framework/Algorithms/test/AddNoteTest.h
+++ b/Framework/Algorithms/test/AddNoteTest.h
@@ -18,7 +18,7 @@ public:
   static void destroySuite(AddNoteTest *suite) { delete suite; }
 
   void test_delete_existing_removes_complete_log_first() {
-    auto ws = WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+    auto ws = WorkspaceCreationHelper::create2DWorkspace(10, 10);
     TS_ASSERT_THROWS_NOTHING(executeAlgorithm(
         ws, "Test Name", "2010-09-14T04:20:12", "First Test String"));
     checkLogWithEntryExists<std::string>(ws, "Test Name", "2010-09-14T04:20:12",
@@ -30,7 +30,7 @@ public:
   }
 
   void test_empty_time_property_produces_current_time_in_log_output() {
-    auto ws = WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+    auto ws = WorkspaceCreationHelper::create2DWorkspace(10, 10);
 
     // Get Current Date Time
     namespace pt = boost::posix_time;
@@ -66,7 +66,7 @@ public:
   }
 
   void test_algorithm_fails_if_log_exists_but_is_not_a_time_series() {
-    auto ws = WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+    auto ws = WorkspaceCreationHelper::create2DWorkspace(10, 10);
     auto &run = ws->mutableRun();
     run.addProperty<std::string>("Test Name", "Test");
     TS_ASSERT_THROWS(
@@ -140,4 +140,4 @@ private:
   }
 };
 
-#endif /* MANTID_ALGORITHMS_ADDNOTETEST_H_ */
\ No newline at end of file
+#endif /* MANTID_ALGORITHMS_ADDNOTETEST_H_ */
diff --git a/Framework/Algorithms/test/AddSampleLogTest.h b/Framework/Algorithms/test/AddSampleLogTest.h
index 5941f875d468c03717f9290b498714a7f0b1fdee..c2cb9ec6c7e91f98aecd9595fcc046322936960e 100644
--- a/Framework/Algorithms/test/AddSampleLogTest.h
+++ b/Framework/Algorithms/test/AddSampleLogTest.h
@@ -18,26 +18,26 @@ class AddSampleLogTest : public CxxTest::TestSuite {
 public:
   void test_Workspace2D() {
     MatrixWorkspace_sptr ws =
-        WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+        WorkspaceCreationHelper::create2DWorkspace(10, 10);
     ExecuteAlgorithm(ws, "My Name", "String", "My Value", 0.0);
   }
 
   void test_EventWorkspace() {
     MatrixWorkspace_sptr ws =
-        WorkspaceCreationHelper::CreateEventWorkspace(10, 10);
+        WorkspaceCreationHelper::createEventWorkspace(10, 10);
     ExecuteAlgorithm(ws, "My Name", "String", "My Value", 0.0);
   }
 
   void test_CanOverwrite() {
     MatrixWorkspace_sptr ws =
-        WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+        WorkspaceCreationHelper::create2DWorkspace(10, 10);
     ExecuteAlgorithm(ws, "My Name", "String", "My Value", 0.0);
     ExecuteAlgorithm(ws, "My Name", "String", "My New Value", 0.0);
   }
 
   void test_Number() {
     MatrixWorkspace_sptr ws =
-        WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+        WorkspaceCreationHelper::create2DWorkspace(10, 10);
     ExecuteAlgorithm(ws, "My Name", "Number", "1.234", 1.234);
     ExecuteAlgorithm(ws, "My Name", "Number", "2.456", 2.456);
 
@@ -47,19 +47,19 @@ public:
 
   void test_BadNumber() {
     MatrixWorkspace_sptr ws =
-        WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+        WorkspaceCreationHelper::create2DWorkspace(10, 10);
     ExecuteAlgorithm(ws, "My Name", "Number", "OneTwoThreeFour", 0.0, true);
   }
 
   void test_BadNumberSeries() {
     MatrixWorkspace_sptr ws =
-        WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+        WorkspaceCreationHelper::create2DWorkspace(10, 10);
     ExecuteAlgorithm(ws, "My Name", "Number Series", "FiveSixSeven", 0.0, true);
   }
 
   void test_NumberSeries() {
     MatrixWorkspace_sptr ws =
-        WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+        WorkspaceCreationHelper::create2DWorkspace(10, 10);
     ws->mutableRun().setStartAndEndTime(DateAndTime("2013-12-18T13:40:00"),
                                         DateAndTime("2013-12-18T13:42:00"));
     ExecuteAlgorithm(ws, "My Name", "Number Series", "1.234", 1.234);
@@ -73,7 +73,7 @@ public:
 
   void test_Units() {
     MatrixWorkspace_sptr ws =
-        WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+        WorkspaceCreationHelper::create2DWorkspace(10, 10);
     ws->mutableRun().setStartAndEndTime(DateAndTime("2013-12-18T13:40:00"),
                                         DateAndTime("2013-12-18T13:42:00"));
     ExecuteAlgorithm(ws, "My Name", "Number Series", "1.234", 1.234, false,
@@ -86,7 +86,7 @@ public:
 
   void test_number_type() {
     MatrixWorkspace_sptr ws =
-        WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+        WorkspaceCreationHelper::create2DWorkspace(10, 10);
     ws->mutableRun().setStartAndEndTime(DateAndTime("2013-12-18T13:40:00"),
                                         DateAndTime("2013-12-18T13:42:00"));
     ExecuteAlgorithm(ws, "My Name", "Number Series", "1.234", 1.234, false,
diff --git a/Framework/Algorithms/test/AddTimeSeriesLogTest.h b/Framework/Algorithms/test/AddTimeSeriesLogTest.h
index 59b106f78f7235964cb04b426860256dc5f0d2de..682fe50fb867080daad80c1c6921d0dc9f0f806b 100644
--- a/Framework/Algorithms/test/AddTimeSeriesLogTest.h
+++ b/Framework/Algorithms/test/AddTimeSeriesLogTest.h
@@ -20,7 +20,7 @@ public:
   static void destroySuite(AddTimeSeriesLogTest *suite) { delete suite; }
 
   void test_defaults_create_a_double_type_series() {
-    auto ws = WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+    auto ws = WorkspaceCreationHelper::create2DWorkspace(10, 10);
     TS_ASSERT_THROWS_NOTHING(
         executeAlgorithm(ws, "Test Name", "2010-09-14T04:20:12", 20.0));
     checkLogWithEntryExists<double>(ws, "Test Name", "2010-09-14T04:20:12",
@@ -32,7 +32,7 @@ public:
   }
 
   void test_forcing_to_int_creates_int_from_double() {
-    auto ws = WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+    auto ws = WorkspaceCreationHelper::create2DWorkspace(10, 10);
     TS_ASSERT_THROWS_NOTHING(executeAlgorithm(
         ws, "Test Name", "2010-09-14T04:20:12", 20.5, Integer));
 
@@ -57,7 +57,7 @@ public:
   }
 
   void test_delete_existing_removes_complete_log_first() {
-    auto ws = WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+    auto ws = WorkspaceCreationHelper::create2DWorkspace(10, 10);
     TS_ASSERT_THROWS_NOTHING(
         executeAlgorithm(ws, "Test Name", "2010-09-14T04:20:12", 20.0));
     checkLogWithEntryExists<double>(ws, "Test Name", "2010-09-14T04:20:12",
@@ -105,7 +105,7 @@ public:
   }
 
   void test_algorithm_fails_if_log_exists_but_is_not_a_time_series() {
-    auto ws = WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+    auto ws = WorkspaceCreationHelper::create2DWorkspace(10, 10);
     auto &run = ws->mutableRun();
     run.addProperty<double>("Test Name", 1.0);
     TS_ASSERT_THROWS(
@@ -114,7 +114,7 @@ public:
   }
 
   void test_algorithm_fails_if_time_series_exists_but_it_is_incorrect_type() {
-    auto ws = WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+    auto ws = WorkspaceCreationHelper::create2DWorkspace(10, 10);
     auto &run = ws->mutableRun();
     const std::string logName = "DoubleSeries";
     auto *timeSeries = new Mantid::Kernel::TimeSeriesProperty<double>(logName);
diff --git a/Framework/Algorithms/test/AlignDetectorsTest.h b/Framework/Algorithms/test/AlignDetectorsTest.h
index e59810f9d8dbb0742533ce8b6647c73e4e3ae4ef..5cb368392ac0256c4dcde34aaba788b1af43f211 100644
--- a/Framework/Algorithms/test/AlignDetectorsTest.h
+++ b/Framework/Algorithms/test/AlignDetectorsTest.h
@@ -6,9 +6,9 @@
 
 #include "MantidAPI/Axis.h"
 #include "MantidAlgorithms/AlignDetectors.h"
-#include "MantidDataHandling/LoadEventPreNexus.h"
 #include "MantidDataHandling/LoadNexus.h"
 #include "MantidDataObjects/EventWorkspace.h"
+#include "MantidKernel/Unit.h"
 
 using namespace Mantid::Algorithms;
 using namespace Mantid::DataHandling;
diff --git a/Framework/Algorithms/test/AnnularRingAbsorptionTest.h b/Framework/Algorithms/test/AnnularRingAbsorptionTest.h
index ac1d57638cffd3a60457e02d1dabac05e5a42737..c3131a7605dfc62b27e0a04b6682aa016d4bf9a6 100644
--- a/Framework/Algorithms/test/AnnularRingAbsorptionTest.h
+++ b/Framework/Algorithms/test/AnnularRingAbsorptionTest.h
@@ -45,9 +45,9 @@ public:
 
     const double delta(1e-08);
     const size_t middle_index = 4;
-    TS_ASSERT_DELTA(0.97773712, outWS->readY(0).front(), delta);
-    TS_ASSERT_DELTA(0.83720057, outWS->readY(0)[middle_index], delta);
-    TS_ASSERT_DELTA(0.72020602, outWS->readY(0).back(), delta);
+    TS_ASSERT_DELTA(0.96859812, outWS->readY(0).front(), delta);
+    TS_ASSERT_DELTA(0.79254304, outWS->readY(0)[middle_index], delta);
+    TS_ASSERT_DELTA(0.67064972, outWS->readY(0).back(), delta);
   }
 
   //-------------------- Failure cases --------------------------------
@@ -57,7 +57,7 @@ public:
 
     auto alg = createAlgorithm();
     // Create a simple test workspace that has no instrument
-    auto testWS = WorkspaceCreationHelper::Create2DWorkspace(10, 5);
+    auto testWS = WorkspaceCreationHelper::create2DWorkspace(10, 5);
 
     TS_ASSERT_THROWS(
         alg->setProperty<MatrixWorkspace_sptr>("InputWorkspace", testWS),
diff --git a/Framework/Algorithms/test/AppendSpectraTest.h b/Framework/Algorithms/test/AppendSpectraTest.h
index 97369dc7ad525bbe481975e12c9378e7ba549b9d..50e462cd810566124065940690350decaa5634c0 100644
--- a/Framework/Algorithms/test/AppendSpectraTest.h
+++ b/Framework/Algorithms/test/AppendSpectraTest.h
@@ -4,6 +4,7 @@
 #include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Axis.h"
 #include "MantidAPI/FrameworkManager.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidAlgorithms/AppendSpectra.h"
 #include "MantidDataHandling/LoadRaw3.h"
 #include "MantidKernel/TimeSeriesProperty.h"
@@ -66,8 +67,10 @@ public:
 
     // Mask a spectrum and check it is carried over
     const size_t maskTop(5), maskBottom(10);
-    in1->maskWorkspaceIndex(maskTop);
-    in2->maskWorkspaceIndex(maskBottom);
+    in1->getSpectrum(maskTop).clearData();
+    in2->getSpectrum(maskBottom).clearData();
+    in1->mutableSpectrumInfo().setMasked(maskTop, true);
+    in2->mutableSpectrumInfo().setMasked(maskBottom, true);
 
     // Now it should succeed
     TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("InputWorkspace1", "top"));
@@ -94,8 +97,8 @@ public:
                      in2->getAxis(1)->spectraNo(2));
 
     // Check masking
-    TS_ASSERT_EQUALS(output->getDetector(maskTop)->isMasked(), true);
-    TS_ASSERT_EQUALS(output->getDetector(10 + maskBottom)->isMasked(), true);
+    TS_ASSERT_EQUALS(output->spectrumInfo().isMasked(maskTop), true);
+    TS_ASSERT_EQUALS(output->spectrumInfo().isMasked(10 + maskBottom), true);
   }
 
   //----------------------------------------------------------------------------------------------
@@ -145,14 +148,14 @@ public:
   //----------------------------------------------------------------------------------------------
   void testExecMismatchedWorkspaces() {
     MatrixWorkspace_sptr ews =
-        WorkspaceCreationHelper::CreateEventWorkspace(10, 10);
+        WorkspaceCreationHelper::createEventWorkspace(10, 10);
 
     // Check it fails if mixing event workspaces and workspace 2Ds
     AppendSpectra alg;
     alg.initialize();
     TS_ASSERT_THROWS_NOTHING(alg.setProperty("InputWorkspace1", ews));
     TS_ASSERT_THROWS_NOTHING(alg.setProperty(
-        "InputWorkspace2", WorkspaceCreationHelper::Create2DWorkspace(10, 10)));
+        "InputWorkspace2", WorkspaceCreationHelper::create2DWorkspace(10, 10)));
     TS_ASSERT_THROWS_NOTHING(
         alg.setPropertyValue("OutputWorkspace", "outevent"));
     alg.execute();
@@ -165,12 +168,12 @@ public:
     int numBins = 20;
 
     if (event) {
-      ws1 = WorkspaceCreationHelper::CreateEventWorkspace2(
+      ws1 = WorkspaceCreationHelper::createEventWorkspace2(
           10, numBins); // 2 events per bin
-      ws2 = WorkspaceCreationHelper::CreateEventWorkspace2(5, numBins);
+      ws2 = WorkspaceCreationHelper::createEventWorkspace2(5, numBins);
     } else {
-      ws1 = WorkspaceCreationHelper::Create2DWorkspace(10, numBins);
-      ws2 = WorkspaceCreationHelper::Create2DWorkspace(5, numBins);
+      ws1 = WorkspaceCreationHelper::create2DWorkspace(10, numBins);
+      ws2 = WorkspaceCreationHelper::create2DWorkspace(5, numBins);
     }
 
     auto ws1Log = new TimeSeriesProperty<std::string>("aLog");
diff --git a/Framework/Algorithms/test/ApplyCalibrationTest.h b/Framework/Algorithms/test/ApplyCalibrationTest.h
index 32e53c0fe79b397ca0ef9785eefd0a38fec1f807..c06ee20a333e7a7849c7d8bc87be2aa4878d4069 100644
--- a/Framework/Algorithms/test/ApplyCalibrationTest.h
+++ b/Framework/Algorithms/test/ApplyCalibrationTest.h
@@ -12,6 +12,7 @@
 #include "WorkspaceCreationHelperTest.h"
 #include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/ITableWorkspace.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidAPI/TableRow.h"
 #include "MantidKernel/V3D.h"
 #include "MantidGeometry/Instrument.h"
@@ -63,17 +64,17 @@ public:
 
     TS_ASSERT(appCalib.isExecuted());
 
-    IDetector_const_sptr det = ws->getDetector(0);
-    int id = det->getID();
-    V3D newPos = det->getPos();
+    const auto &spectrumInfo = ws->spectrumInfo();
+
+    int id = spectrumInfo.detector(0).getID();
+    V3D newPos = spectrumInfo.position(0);
     TS_ASSERT_EQUALS(id, 1);
     TS_ASSERT_DELTA(newPos.X(), 1.0, 0.0001);
     TS_ASSERT_DELTA(newPos.Y(), 0.0, 0.0001);
     TS_ASSERT_DELTA(newPos.Z(), 2.0, 0.0001);
 
-    det = ws->getDetector(ndets - 1);
-    id = det->getID();
-    newPos = det->getPos();
+    id = spectrumInfo.detector(ndets - 1).getID();
+    newPos = spectrumInfo.position(ndets - 1);
     TS_ASSERT_EQUALS(id, ndets);
     TS_ASSERT_DELTA(newPos.X(), 1.0, 0.0001);
     TS_ASSERT_DELTA(newPos.Y(), 0.01 * (ndets - 1), 0.0001);
diff --git a/Framework/Algorithms/test/ApplyDeadTimeCorrTest.h b/Framework/Algorithms/test/ApplyDeadTimeCorrTest.h
index 131b19f6c1f9527054c5bcf7e80c8338efc74476..18b2d5c4a25a18b8d720a5afb06f1b096e4bb63b 100644
--- a/Framework/Algorithms/test/ApplyDeadTimeCorrTest.h
+++ b/Framework/Algorithms/test/ApplyDeadTimeCorrTest.h
@@ -171,7 +171,7 @@ public:
   /// Test algorithm rejects an input workspace with uneven bin widths
   void testUnevenBinWidths() {
     constexpr size_t numSpectra(2);
-    auto workspace = WorkspaceCreationHelper::Create2DWorkspace(
+    auto workspace = WorkspaceCreationHelper::create2DWorkspace(
         static_cast<int>(numSpectra), 10);
 
     // Rebin the workspace to make bin widths uneven
diff --git a/Framework/Algorithms/test/ApplyDetailedBalanceTest.h b/Framework/Algorithms/test/ApplyDetailedBalanceTest.h
index 3753d1a4ca6a9a8aecf67355fea75753587787c0..a522d25c087a781ca5d6a00839ae649ea34729e6 100644
--- a/Framework/Algorithms/test/ApplyDetailedBalanceTest.h
+++ b/Framework/Algorithms/test/ApplyDetailedBalanceTest.h
@@ -92,7 +92,7 @@ public:
   }
 
   void test_event() {
-    EventWorkspace_sptr evin = WorkspaceCreationHelper::CreateEventWorkspace(
+    EventWorkspace_sptr evin = WorkspaceCreationHelper::createEventWorkspace(
                             1, 5, 10, 0, 1, 3),
                         evout;
     evin->getAxis(0)->unit() = UnitFactory::Instance().create("DeltaE");
@@ -160,7 +160,6 @@ private:
       ws2D->setX(i, cow_xv);
       ws2D->dataY(i) = {1, 2, 3, 4, 5};
       ws2D->dataE(i) = {sqrt(1), sqrt(2), sqrt(3), sqrt(4), sqrt(5)};
-      ws2D->getSpectrum(i).setSpectrumNo(i);
     }
 
     AnalysisDataService::Instance().add(inputWSname, ws2D);
diff --git a/Framework/Algorithms/test/ApplyTransmissionCorrectionTest.h b/Framework/Algorithms/test/ApplyTransmissionCorrectionTest.h
index 2f28b6442e34ea003f6798c478bf1d50cc1964e8..cde5ba6e7c2a5c1e34ee464c1a6c02f9038852fd 100644
--- a/Framework/Algorithms/test/ApplyTransmissionCorrectionTest.h
+++ b/Framework/Algorithms/test/ApplyTransmissionCorrectionTest.h
@@ -48,7 +48,7 @@ public:
 
     const std::string transWS("trans");
     Workspace2D_sptr trans_ws =
-        WorkspaceCreationHelper::Create2DWorkspace154(1, 1, 1);
+        WorkspaceCreationHelper::create2DWorkspace154(1, 1, 1);
     trans_ws->getAxis(0)->unit() = UnitFactory::Instance().create("Wavelength");
     trans_ws->mutableY(0)[0] = 0.6;
     trans_ws->mutableE(0)[0] = 0.02;
diff --git a/Framework/Algorithms/test/AsymmetryCalcTest.h b/Framework/Algorithms/test/AsymmetryCalcTest.h
index 8deb314373051ceae9d4a02181540ed27c7f4ccb..19e8c2d8d9dc0374d25b913192e9b74f338e8e2d 100644
--- a/Framework/Algorithms/test/AsymmetryCalcTest.h
+++ b/Framework/Algorithms/test/AsymmetryCalcTest.h
@@ -7,6 +7,7 @@
 #include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/IAlgorithm.h"
 #include "MantidAPI/Workspace.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidAlgorithms/AsymmetryCalc.h"
 #include "MantidDataHandling/GroupDetectors.h"
 #include "MantidDataHandling/LoadInstrument.h"
@@ -81,7 +82,7 @@ public:
   }
 
   void test_single_spectra() {
-    auto ws = WorkspaceCreationHelper::Create2DWorkspace(3, 10);
+    auto ws = WorkspaceCreationHelper::create2DWorkspace(3, 10);
     for (size_t i = 0; i < ws->getNumberHistograms(); ++i) {
       auto &y = ws->mutableY(i);
       std::fill(y.begin(), y.end(), static_cast<double>(i + 1));
@@ -104,7 +105,7 @@ public:
   }
 
   void test_yUnitLabel() {
-    auto ws = WorkspaceCreationHelper::Create2DWorkspace(2, 1);
+    auto ws = WorkspaceCreationHelper::create2DWorkspace(2, 1);
 
     AsymmetryCalc alg;
     alg.initialize();
@@ -123,7 +124,7 @@ public:
   }
 
   void test_validateInputs() {
-    auto ws = WorkspaceCreationHelper::Create2DWorkspace(2, 1);
+    auto ws = WorkspaceCreationHelper::create2DWorkspace(2, 1);
     AsymmetryCalc asymCalc;
     asymCalc.initialize();
     asymCalc.setChild(true);
@@ -146,9 +147,9 @@ public:
  */
   void testValidateInputsWithWSGroup() {
     auto ws1 = boost::static_pointer_cast<Workspace>(
-        WorkspaceCreationHelper::Create2DWorkspace(2, 1));
+        WorkspaceCreationHelper::create2DWorkspace(2, 1));
     auto ws2 = boost::static_pointer_cast<Workspace>(
-        WorkspaceCreationHelper::Create2DWorkspace(2, 1));
+        WorkspaceCreationHelper::create2DWorkspace(2, 1));
     AnalysisDataService::Instance().add("workspace1", ws1);
     AnalysisDataService::Instance().add("workspace2", ws2);
     auto group = boost::make_shared<WorkspaceGroup>();
diff --git a/Framework/Algorithms/test/AverageLogDataTest.h b/Framework/Algorithms/test/AverageLogDataTest.h
index 0323e175ef1220af6a8ff1acab91942ed18b461c..9fd415828bab13f33c3284cebef7e28d7c767651 100644
--- a/Framework/Algorithms/test/AverageLogDataTest.h
+++ b/Framework/Algorithms/test/AverageLogDataTest.h
@@ -113,7 +113,7 @@ private:
   void makeWS(double shift) {
     inputWS = "AverageLogDataTestWS";
     Mantid::DataObjects::Workspace2D_sptr w =
-        WorkspaceCreationHelper::Create2DWorkspace(1, 1);
+        WorkspaceCreationHelper::create2DWorkspace(1, 1);
     Mantid::Kernel::DateAndTime run_start("2010-01-01T00:00:00");
     Mantid::Kernel::TimeSeriesProperty<double> *pc, *p1;
     pc = new Mantid::Kernel::TimeSeriesProperty<double>("proton_charge");
diff --git a/Framework/Algorithms/test/BinaryOperationTest.h b/Framework/Algorithms/test/BinaryOperationTest.h
index ade17cfb671c262f7b33c68d8995db852bf0fa58..826d443dc14f0f9b6a5e2fab9d00a50db977665e 100644
--- a/Framework/Algorithms/test/BinaryOperationTest.h
+++ b/Framework/Algorithms/test/BinaryOperationTest.h
@@ -7,6 +7,7 @@
 #include "MantidTestHelpers/WorkspaceCreationHelper.h"
 #include "MantidAlgorithms/BinaryOperation.h"
 #include "MantidAPI/AnalysisDataService.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidDataObjects/EventWorkspace.h"
 #include "MantidDataObjects/Workspace2D.h"
@@ -68,17 +69,17 @@ public:
   void testcheckSizeCompatibility1D1D() {
     // Register the workspace in the data service
     Workspace2D_sptr work_in1 =
-        WorkspaceCreationHelper::Create1DWorkspaceFib(10);
+        WorkspaceCreationHelper::create1DWorkspaceFib(10);
     Workspace2D_sptr work_in2 =
-        WorkspaceCreationHelper::Create1DWorkspaceFib(20);
+        WorkspaceCreationHelper::create1DWorkspaceFib(20);
     Workspace2D_sptr work_in3 =
-        WorkspaceCreationHelper::Create1DWorkspaceFib(10);
+        WorkspaceCreationHelper::create1DWorkspaceFib(10);
     Workspace2D_sptr work_in4 =
-        WorkspaceCreationHelper::Create1DWorkspaceFib(5);
+        WorkspaceCreationHelper::create1DWorkspaceFib(5);
     Workspace2D_sptr work_in5 =
-        WorkspaceCreationHelper::Create1DWorkspaceFib(3);
+        WorkspaceCreationHelper::create1DWorkspaceFib(3);
     Workspace2D_sptr work_in6 =
-        WorkspaceCreationHelper::Create1DWorkspaceFib(1);
+        WorkspaceCreationHelper::create1DWorkspaceFib(1);
     BinaryOpHelper helper;
     TS_ASSERT(!helper.checkSizeCompatibility(work_in1, work_in2).empty());
     TS_ASSERT(helper.checkSizeCompatibility(work_in1, work_in3).empty());
@@ -90,22 +91,22 @@ public:
   void testcheckSizeCompatibility2D1D() {
     // Register the workspace in the data service
     Workspace2D_sptr work_in1 =
-        WorkspaceCreationHelper::Create2DWorkspace123(10, 10);
+        WorkspaceCreationHelper::create2DWorkspace123(10, 10);
     Workspace2D_sptr work_in2 =
-        WorkspaceCreationHelper::Create1DWorkspaceFib(20);
+        WorkspaceCreationHelper::create1DWorkspaceFib(20);
     Workspace2D_sptr work_in3 =
-        WorkspaceCreationHelper::Create1DWorkspaceFib(10);
+        WorkspaceCreationHelper::create1DWorkspaceFib(10);
     Workspace2D_sptr work_in4 =
-        WorkspaceCreationHelper::Create1DWorkspaceFib(5);
+        WorkspaceCreationHelper::create1DWorkspaceFib(5);
     Workspace2D_sptr work_in5 =
-        WorkspaceCreationHelper::Create1DWorkspaceFib(3);
+        WorkspaceCreationHelper::create1DWorkspaceFib(3);
     Workspace2D_sptr work_in6 =
-        WorkspaceCreationHelper::Create1DWorkspaceFib(1);
+        WorkspaceCreationHelper::create1DWorkspaceFib(1);
     MatrixWorkspace_sptr work_inEvent1 =
-        WorkspaceCreationHelper::CreateEventWorkspace(10, 1);
+        WorkspaceCreationHelper::createEventWorkspace(10, 1);
     // will not pass x array does not match
     MatrixWorkspace_sptr work_inEvent2 =
-        WorkspaceCreationHelper::CreateEventWorkspace(1, 10);
+        WorkspaceCreationHelper::createEventWorkspace(1, 10);
     BinaryOpHelper helper;
     TS_ASSERT(!helper.checkSizeCompatibility(work_in1, work_in2).empty());
     TS_ASSERT(helper.checkSizeCompatibility(work_in1, work_in3).empty());
@@ -120,21 +121,21 @@ public:
 
     // Register the workspace in the data service
     Workspace2D_sptr work_in1 =
-        WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+        WorkspaceCreationHelper::create2DWorkspace(10, 10);
     Workspace2D_sptr work_in2 =
-        WorkspaceCreationHelper::Create2DWorkspace(10, 20);
+        WorkspaceCreationHelper::create2DWorkspace(10, 20);
     Workspace2D_sptr work_in3 =
-        WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+        WorkspaceCreationHelper::create2DWorkspace(10, 10);
     Workspace2D_sptr work_in4 =
-        WorkspaceCreationHelper::Create2DWorkspace(5, 5);
+        WorkspaceCreationHelper::create2DWorkspace(5, 5);
     Workspace2D_sptr work_in5 =
-        WorkspaceCreationHelper::Create2DWorkspace(3, 3);
+        WorkspaceCreationHelper::create2DWorkspace(3, 3);
     Workspace2D_sptr work_in6 =
-        WorkspaceCreationHelper::Create2DWorkspace(100, 1);
+        WorkspaceCreationHelper::create2DWorkspace(100, 1);
     MatrixWorkspace_sptr work_inEvent1 =
-        WorkspaceCreationHelper::CreateEventWorkspace(5, 5);
+        WorkspaceCreationHelper::createEventWorkspace(5, 5);
     MatrixWorkspace_sptr work_inEvent2 =
-        WorkspaceCreationHelper::CreateEventWorkspace(10, 10);
+        WorkspaceCreationHelper::createEventWorkspace(10, 10);
     BinaryOpHelper helper;
     TS_ASSERT(!helper.checkSizeCompatibility(work_in1, work_in2).empty());
     TS_ASSERT(helper.checkSizeCompatibility(work_in1, work_in3).empty());
@@ -153,9 +154,9 @@ public:
     masking.insert(4);
 
     MatrixWorkspace_sptr work_in1 =
-        WorkspaceCreationHelper::Create2DWorkspace123(nHist, nBins, 0, masking);
+        WorkspaceCreationHelper::create2DWorkspace123(nHist, nBins, 0, masking);
     MatrixWorkspace_sptr work_in2 =
-        WorkspaceCreationHelper::Create2DWorkspace154(nHist, nBins);
+        WorkspaceCreationHelper::create2DWorkspace154(nHist, nBins);
 
     BinaryOpHelper helper;
     helper.initialize();
@@ -174,18 +175,14 @@ public:
     TS_ASSERT(output);
 
     for (int i = 0; i < nHist; ++i) {
-      IDetector_const_sptr det;
-      try {
-        det = output->getDetector(i);
-      } catch (Mantid::Kernel::Exception::NotFoundError &) {
-      }
+      auto &spectrumInfo = output->spectrumInfo();
 
-      TSM_ASSERT("Detector was found", det);
-      if (det) {
+      TSM_ASSERT("Detector was not found", spectrumInfo.hasDetectors(i));
+      if (spectrumInfo.hasDetectors(i)) {
         if (masking.count(i) == 0) {
-          TS_ASSERT_EQUALS(det->isMasked(), false);
+          TS_ASSERT_EQUALS(spectrumInfo.isMasked(i), false);
         } else {
-          TS_ASSERT_EQUALS(det->isMasked(), true);
+          TS_ASSERT_EQUALS(spectrumInfo.isMasked(i), true);
         }
       }
     }
@@ -196,9 +193,9 @@ public:
                                     std::vector<std::vector<int>> rhs,
                                     bool expect_throw = false) {
     EventWorkspace_sptr lhsWS =
-        WorkspaceCreationHelper::CreateGroupedEventWorkspace(lhs, 50, 1.0);
+        WorkspaceCreationHelper::createGroupedEventWorkspace(lhs, 50, 1.0);
     EventWorkspace_sptr rhsWS =
-        WorkspaceCreationHelper::CreateGroupedEventWorkspace(rhs, 50, 1.0);
+        WorkspaceCreationHelper::createGroupedEventWorkspace(rhs, 50, 1.0);
     BinaryOperation::BinaryOperationTable_sptr table;
     Mantid::Kernel::Timer timer1;
     if (expect_throw) {
diff --git a/Framework/Algorithms/test/CMakeLists.txt b/Framework/Algorithms/test/CMakeLists.txt
index 4a56a1753372d6c03dd9c2284a25d340b1e884e5..8db5f42908ece10c2eeb9b8e5d34d852db6d3bf5 100644
--- a/Framework/Algorithms/test/CMakeLists.txt
+++ b/Framework/Algorithms/test/CMakeLists.txt
@@ -46,6 +46,7 @@ if ( CXXTEST_FOUND )
             DataObjects
             Geometry
             HistogramData
+            Indexing
             Kernel
             Nexus
             ${Boost_LIBRARIES}
diff --git a/Framework/Algorithms/test/CalMuonDetectorPhasesTest.h b/Framework/Algorithms/test/CalMuonDetectorPhasesTest.h
index 6f05454434fc3b749bbc497d3123833e5f03c4cc..90a8ee919699685c0cd922d7ac20eb005aa54df7 100644
--- a/Framework/Algorithms/test/CalMuonDetectorPhasesTest.h
+++ b/Framework/Algorithms/test/CalMuonDetectorPhasesTest.h
@@ -11,6 +11,7 @@
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/Run.h"
 #include "MantidAPI/Workspace.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidGeometry/Instrument.h"
 #include "MantidKernel/cow_ptr.h"
 #include "MantidKernel/PhysicalConstants.h"
diff --git a/Framework/Algorithms/test/CalculateDIFCTest.h b/Framework/Algorithms/test/CalculateDIFCTest.h
index eb3c64acafa62a1f34d6173bb51c9e2c7baa710a..d682a124cdfbb1f2c73904cabb73ba2acc4912da 100644
--- a/Framework/Algorithms/test/CalculateDIFCTest.h
+++ b/Framework/Algorithms/test/CalculateDIFCTest.h
@@ -4,6 +4,7 @@
 #include <cxxtest/TestSuite.h>
 
 #include "MantidAlgorithms/CalculateDIFC.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidTestHelpers/WorkspaceCreationHelper.h"
 
 using Mantid::Algorithms::CalculateDIFC;
@@ -81,9 +82,10 @@ public:
 
     auto offsetsWS =
         OffsetsWorkspace_sptr(new OffsetsWorkspace(inputWS->getInstrument()));
+    const auto &spectrumInfo = offsetsWS->spectrumInfo();
     for (int i = 0; i < NUM_SPEC; ++i) {
-      IDetector_const_sptr det = inputWS->getDetector(i);
-      offsetsWS->setValue(det->getID(), OFFSET);
+      const auto &det = spectrumInfo.detector(i);
+      offsetsWS->setValue(det.getID(), OFFSET);
     }
 
     runTest(inputWS, offsetsWS, outWSName);
diff --git a/Framework/Algorithms/test/CalculateEfficiencyTest.h b/Framework/Algorithms/test/CalculateEfficiencyTest.h
index f6767c9025900ee05aba770971dfd401ffa96855..7e9be018df3e451807d5c2dedb5f1da77d890501 100644
--- a/Framework/Algorithms/test/CalculateEfficiencyTest.h
+++ b/Framework/Algorithms/test/CalculateEfficiencyTest.h
@@ -1,7 +1,9 @@
 #ifndef CALCULATEEFFICIENCYTEST_H_
 #define CALCULATEEFFICIENCYTEST_H_
 
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Axis.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidAlgorithms/CalculateEfficiency.h"
 #include "MantidDataHandling/LoadSpice2D.h"
 #include "MantidDataHandling/MoveInstrumentComponent.h"
@@ -99,12 +101,9 @@ public:
                     0.4502, tolerance);
 
     // Check that pixels that were out of range were masked
-    TS_ASSERT(
-        !ws2d_out->getDetector(5 + SANSInstrumentCreationHelper::nMonitors)
-             ->isMasked())
-    TS_ASSERT(
-        !ws2d_out->getDetector(1 + SANSInstrumentCreationHelper::nMonitors)
-             ->isMasked())
+    const auto &oSpecInfo = ws2d_out->spectrumInfo();
+    TS_ASSERT(!oSpecInfo.isMasked(5 + SANSInstrumentCreationHelper::nMonitors));
+    TS_ASSERT(!oSpecInfo.isMasked(1 + SANSInstrumentCreationHelper::nMonitors));
 
     // Repeat the calculation by excluding high/low pixels
 
@@ -144,11 +143,10 @@ public:
                     0.5002, tolerance);
 
     // Check that pixels that were out of range were masked
-    TS_ASSERT(ws2d_out->getDetector(5 + SANSInstrumentCreationHelper::nMonitors)
-                  ->isMasked())
+    const auto &oSpecInfo2 = ws2d_out->spectrumInfo();
+    TS_ASSERT(oSpecInfo2.isMasked(5 + SANSInstrumentCreationHelper::nMonitors));
     TS_ASSERT(
-        !ws2d_out->getDetector(1 + SANSInstrumentCreationHelper::nMonitors)
-             ->isMasked())
+        !oSpecInfo2.isMasked(1 + SANSInstrumentCreationHelper::nMonitors));
 
     Mantid::API::AnalysisDataService::Instance().remove(inputWS);
     Mantid::API::AnalysisDataService::Instance().remove(outputWS);
@@ -231,9 +229,10 @@ public:
     TS_ASSERT_DELTA(ws2d_out->e(6 + nmon)[0], 0.105261, tolerance);
 
     // Check that pixels that were out of range were masked
-    TS_ASSERT(ws2d_out->getDetector(1826)->isMasked())
-    TS_ASSERT(ws2d_out->getDetector(2014)->isMasked())
-    TS_ASSERT(ws2d_out->getDetector(2015)->isMasked())
+    const auto &oSpecInfo = ws2d_out->spectrumInfo();
+    TS_ASSERT(oSpecInfo.isMasked(1826));
+    TS_ASSERT(oSpecInfo.isMasked(2014));
+    TS_ASSERT(oSpecInfo.isMasked(2015));
 
     Mantid::API::AnalysisDataService::Instance().remove(inputWS);
     Mantid::API::AnalysisDataService::Instance().remove(outputWS);
diff --git a/Framework/Algorithms/test/CalculateFlatBackgroundTest.h b/Framework/Algorithms/test/CalculateFlatBackgroundTest.h
index 58f2131d77ebbc1ab8c4d9d3e6fbda4be30b24dd..8c7ea949d6c22f8cc015381dae83d6b073a191f6 100644
--- a/Framework/Algorithms/test/CalculateFlatBackgroundTest.h
+++ b/Framework/Algorithms/test/CalculateFlatBackgroundTest.h
@@ -1,14 +1,17 @@
 #ifndef FLATBACKGROUNDTEST_H_
 #define FLATBACKGROUNDTEST_H_
 
+#include "MantidAlgorithms/CalculateFlatBackground.h"
+#include "MantidAlgorithms/CompareWorkspaces.h"
+#include "MantidAlgorithms/Minus.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Axis.h"
 #include "MantidAPI/FrameworkManager.h"
-#include "MantidAlgorithms/CalculateFlatBackground.h"
-#include "MantidTestHelpers/WorkspaceCreationHelper.h"
 #include "MantidDataObjects/Workspace2D.h"
 #include "MantidGeometry/Instrument/RectangularDetector.h"
 #include "MantidKernel/MersenneTwister.h"
 #include "MantidTestHelpers/ComponentCreationHelper.h"
+#include "MantidTestHelpers/WorkspaceCreationHelper.h"
 #include <boost/lexical_cast.hpp>
 #include <cmath>
 #include <cxxtest/TestSuite.h>
@@ -40,6 +43,7 @@ private:
 
     // common beginning
     Mantid::Algorithms::CalculateFlatBackground flatBG;
+    flatBG.setRethrows(true);
     TS_ASSERT_THROWS_NOTHING(flatBG.initialize())
     TS_ASSERT(flatBG.isInitialized())
 
@@ -308,10 +312,17 @@ public:
       background /= 15.0;
       backError = std::sqrt(backError) / 15.0;
       for (int i = 0; i < NUMBINS; ++i) {
-        TS_ASSERT_DELTA(YOut[i], background, 1e-6)
-        TS_ASSERT_DELTA(EOut[i],
-                        std::sqrt((EIn[i] * EIn[i]) + (backError * backError)),
-                        1e-6)
+        if (background <= YIn[i]) {
+          TS_ASSERT_DELTA(YOut[i], background, 1e-6)
+          TS_ASSERT_DELTA(EOut[i], backError, 1e-6)
+        } else {
+          TS_ASSERT_DELTA(YOut[i], YIn[i], 1e-6)
+          if (background < EIn[i]) {
+            TS_ASSERT_DELTA(EOut[i], EIn[i], 1e-6)
+          } else {
+            TS_ASSERT_DELTA(EOut[i], background, 1e-6)
+          }
+        }
       }
     }
   }
@@ -345,15 +356,19 @@ public:
       background /= numSummed;
       backError = std::sqrt(backError) / numSummed;
       for (int i = 0; i < NUMBINS; ++i) {
-        double correct = (YIn[i] - background) > 0 ? YIn[i] - background : 0;
-        TS_ASSERT_DELTA(YOut[i], correct, 1e-6)
-
-        if (YIn[i] - background < 0 && EIn[i] < background) {
-          TS_ASSERT_DELTA(EOut[i], background, 1e-6)
-        } else {
+        double correct = YIn[i] > background ? YIn[i] - background : 0;
+        if (YIn[i] > background) {
+          TS_ASSERT_DELTA(YOut[i], correct, 1e-6)
           TS_ASSERT_DELTA(
               EOut[i], std::sqrt((EIn[i] * EIn[i]) + (backError * backError)),
               1e-6)
+        } else {
+          TS_ASSERT_DELTA(YOut[i], 0, 1e-6)
+          if (EIn[i] < background) {
+            TS_ASSERT_DELTA(EOut[i], background, 1e-6)
+          } else {
+            TS_ASSERT_DELTA(EOut[i], EIn[i], 1e-6)
+          }
         }
       }
     }
@@ -443,7 +458,7 @@ public:
     TS_ASSERT_DELTA(EOut[20], 37.2677, 0.001)
   }
 
-  void test_skipMonitors() {
+  void testSkipMonitors() {
 
     Mantid::Algorithms::CalculateFlatBackground flatBG;
     TS_ASSERT_THROWS_NOTHING(flatBG.initialize())
@@ -487,7 +502,7 @@ public:
     AnalysisDataService::Instance().remove("Removed1");
   }
 
-  void test_movingAverageThrowsOnlyWithInvalidWindowWidth() {
+  void testMovingAverageThrowsOnlyWithInvalidWindowWidth() {
     size_t binCount = 5;
     movingAverageWindowWidthTest(0, binCount, true);
     movingAverageWindowWidthTest(1, binCount, false);
@@ -496,24 +511,158 @@ public:
     movingAverageWindowWidthTest(binCount + 1, binCount, true);
   }
 
-  void test_movingAverageModeWhenWindowWidthIsOne() {
+  void testMovingAverageModeWhenWindowWidthIsOne() {
     const size_t spectraCount = 3;
     const size_t binCount = 4;
     movingAverageTest(1, spectraCount, binCount);
   }
 
-  void test_movingAverageModeWhenWindowWidthIsTwo() {
+  void testMovingAverageModeWhenWindowWidthIsTwo() {
     const size_t spectraCount = 2;
     const size_t binCount = 7;
     movingAverageTest(2, spectraCount, binCount);
   }
 
-  void test_movingAverageModeWithMaximalWindowWidth() {
+  void testMovingAverageModeWithMaximalWindowWidth() {
     const size_t spectraCount = 4;
     const size_t binCount = 9;
     movingAverageTest(binCount, spectraCount, binCount);
   }
 
+  void testSpectraLeftUnchangedIfUnableToCalculate() {
+    const double y1 = -23;
+    const double y2 = -42;
+    const std::string outWsName("Removed1");
+    const std::vector<std::string> modes{"Linear Fit", "Mean",
+                                         "Moving Average"};
+    const std::array<bool, 2> nullifyOptions{{true, false}};
+    for (const auto nullifyNegatives : nullifyOptions) {
+      for (const auto &mode : modes) {
+        executeWithTwoBinInputWorkspace(y1, y2, 1, outWsName, mode, "",
+                                        "Subtract Background",
+                                        nullifyNegatives);
+        MatrixWorkspace_sptr outputWS =
+            AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(
+                outWsName);
+        TS_ASSERT_DELTA(outputWS->y(0)[0], y1, 1e-12)
+        TS_ASSERT_DELTA(outputWS->y(0)[1], y2, 1e-12)
+        AnalysisDataService::Instance().remove(outWsName);
+      }
+      for (const auto &mode : modes) {
+        executeWithTwoBinInputWorkspace(y1, y2, 1, outWsName, mode, "",
+                                        "Return Background", nullifyNegatives);
+        MatrixWorkspace_sptr outputWS =
+            AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(
+                outWsName);
+        TS_ASSERT_DELTA(outputWS->y(0)[0], 0, 1e-12)
+        TS_ASSERT_DELTA(outputWS->y(0)[1], 0, 1e-12)
+        AnalysisDataService::Instance().remove(outWsName);
+      }
+    }
+  }
+
+  void testSubtractBackgroundWhenNotAllSpectraSelected() {
+    const double y1 = 23;
+    const double y2 = 42;
+    const std::string outWsName("Removed1");
+    // Subtract background only from spectrum index 1.
+    // The spectrum at index 0 should be left unchanged.
+    executeWithTwoBinInputWorkspace(y1, y2, 2, outWsName, "Mean", "1",
+                                    "Subtract Background", false);
+    MatrixWorkspace_sptr outputWS =
+        AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(outWsName);
+    TS_ASSERT_DELTA(outputWS->y(0)[0], y1, 1e-12)
+    TS_ASSERT_DELTA(outputWS->y(0)[1], y2, 1e-12)
+    TS_ASSERT_DELTA(outputWS->y(1)[0], y1 - (y1 + y2) / 2, 1e-12)
+    TS_ASSERT_DELTA(outputWS->y(1)[1], y2 - (y1 + y2) / 2, 1e-12)
+    AnalysisDataService::Instance().remove(outWsName);
+  }
+
+  void testReturnBackgroundWhenNotAllSpectraSelected() {
+    const double y1 = 23;
+    const double y2 = 42;
+    const std::string outWsName("Removed1");
+    const bool nullifyNegatives = false;
+    // Return background only for spectrum index 1.
+    // The output at spectrum index 0 should be zero.
+    executeWithTwoBinInputWorkspace(y1, y2, 2, outWsName, "Mean", "1",
+                                    "Return Background", nullifyNegatives);
+    MatrixWorkspace_sptr outputWS =
+        AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(outWsName);
+    TS_ASSERT_DELTA(outputWS->y(0)[0], 0, 1e-12)
+    TS_ASSERT_DELTA(outputWS->y(0)[1], 0, 1e-12)
+    TS_ASSERT_DELTA(outputWS->y(1)[0], (y1 + y2) / 2, 1e-12)
+    TS_ASSERT_DELTA(outputWS->y(1)[1], (y1 + y2) / 2, 1e-12)
+    AnalysisDataService::Instance().remove(outWsName);
+  }
+
+  void testMeanSubtractBackgroundAndReturnBackgroundEquivalent() {
+    const double y1 = 31;
+    const double y2 = 39;
+    const std::string outBackgroundWSName("background");
+    const std::string outSubtractedWSName("subtracted");
+    const bool nullifyNegatives = false;
+    executeWithTwoBinInputWorkspace(y1, y2, 1, outBackgroundWSName, "Mean", "",
+                                    "Return Background", nullifyNegatives);
+    MatrixWorkspace_sptr inputWS = executeWithTwoBinInputWorkspace(
+        y1, y2, 1, outSubtractedWSName, "Mean", "", "Subtract Background",
+        nullifyNegatives);
+    compareSubtractedAndBackgroundWorkspaces(inputWS, outSubtractedWSName,
+                                             outBackgroundWSName);
+    AnalysisDataService::Instance().remove(outBackgroundWSName);
+    AnalysisDataService::Instance().remove(outSubtractedWSName);
+  }
+
+  void testLinearFitSubtractBackgroundAndReturnBackgroundEquivalent() {
+    const double y1 = 31;
+    const double y2 = 39;
+    const std::string outBackgroundWSName("background");
+    const std::string outSubtractedWSName("subtracted");
+    const bool nullifyNegatives = false;
+    executeWithTwoBinInputWorkspace(y1, y2, 1, outBackgroundWSName,
+                                    "Linear Fit", "", "Return Background",
+                                    nullifyNegatives);
+    MatrixWorkspace_sptr inputWS = executeWithTwoBinInputWorkspace(
+        y1, y2, 1, outSubtractedWSName, "Linear Fit", "", "Subtract Background",
+        nullifyNegatives);
+    compareSubtractedAndBackgroundWorkspaces(inputWS, outSubtractedWSName,
+                                             outBackgroundWSName);
+    AnalysisDataService::Instance().remove(outBackgroundWSName);
+    AnalysisDataService::Instance().remove(outSubtractedWSName);
+  }
+
+  void testMovingAverageSubtractBackgroundAndReturnBackgroundEquivalent() {
+    const double y1 = 31;
+    const double y2 = 39;
+    const std::string outBackgroundWSName("background");
+    const std::string outSubtractedWSName("subtracted");
+    const bool nullifyNegatives = false;
+    executeWithTwoBinInputWorkspace(y1, y2, 1, outBackgroundWSName,
+                                    "Moving Average", "", "Return Background",
+                                    nullifyNegatives);
+    MatrixWorkspace_sptr inputWS = executeWithTwoBinInputWorkspace(
+        y1, y2, 1, outSubtractedWSName, "Moving Average", "",
+        "Subtract Background", nullifyNegatives);
+    compareSubtractedAndBackgroundWorkspaces(inputWS, outSubtractedWSName,
+                                             outBackgroundWSName);
+    AnalysisDataService::Instance().remove(outBackgroundWSName);
+    AnalysisDataService::Instance().remove(outSubtractedWSName);
+  }
+
+  void testReturnBackgroundReturnsOriginalValuesIfNullifyNegativeValuesIsSet() {
+    const double y1 = 23;
+    const double y2 = 42;
+    const std::string outWsName("Removed1");
+    const bool nullifyNegatives = true;
+    executeWithTwoBinInputWorkspace(y1, y2, 1, outWsName, "Mean", "",
+                                    "Return Background", nullifyNegatives);
+    MatrixWorkspace_sptr outputWS =
+        AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(outWsName);
+    TS_ASSERT_DELTA(outputWS->y(0)[0], y1, 1e-12)
+    TS_ASSERT_DELTA(outputWS->y(0)[1], (y1 + y2) / 2, 1e-12)
+    AnalysisDataService::Instance().remove(outWsName);
+  }
+
 private:
   double bg;
 
@@ -531,7 +680,6 @@ private:
         new Geometry::Instrument("testInst"));
     // testInst->setReferenceFrame(boost::shared_ptr<Geometry::ReferenceFrame>(new
     // Geometry::ReferenceFrame(Geometry::PointingAlong::Y,Geometry::X,Geometry::Left,"")));
-    WS->setInstrument(testInst);
 
     const double pixelRadius(0.05);
     Geometry::Object_sptr pixelShape =
@@ -551,6 +699,7 @@ private:
       testInst->markAsMonitor(physicalPixel);
       WS->getSpectrum(i).addDetectorID(physicalPixel->getID());
     }
+    WS->setInstrument(testInst);
   }
 
   /// Creates a  workspace with a single special value in each spectrum.
@@ -602,8 +751,9 @@ private:
       flatBG.setProperty("InputWorkspace", WS);
       flatBG.setPropertyValue("OutputWorkspace", "Removed1");
       flatBG.setPropertyValue("Mode", "Moving Average");
-      flatBG.setProperty("AveragingWindowWidth", static_cast<int>(windowWidth));
       flatBG.setPropertyValue("OutputMode", "Return Background");
+      flatBG.setProperty("NullifyNegativeValues", false);
+      flatBG.setProperty("AveragingWindowWidth", static_cast<int>(windowWidth));
       TS_ASSERT_THROWS_NOTHING(flatBG.execute())
       TS_ASSERT(flatBG.isExecuted())
       MatrixWorkspace_sptr outputWS =
@@ -615,6 +765,10 @@ private:
                                      movingAverageStandardY(j)) /
                                 static_cast<double>(windowWidth);
         TS_ASSERT_DELTA(outputWS->y(j)[0], expected, 1e-12)
+        const double expectedError = std::sqrt(
+            static_cast<double>(windowWidth) * movingAverageStandardY(j) /
+            static_cast<double>(windowWidth * windowWidth));
+        TS_ASSERT_DELTA(outputWS->e(j)[0], expectedError, 1e-12)
       }
       AnalysisDataService::Instance().remove("Removed1");
     }
@@ -642,6 +796,75 @@ private:
     }
     AnalysisDataService::Instance().remove("Removed1");
   }
+
+  MatrixWorkspace_sptr executeWithTwoBinInputWorkspace(
+      const double y1, const double y2, const size_t histogramCount,
+      const std::string &outWsName, const std::string &mode,
+      const std::string &wsIndexList, const std::string &outputMode,
+      bool nullifyNegatives) {
+    const size_t binCount = 2;
+    Mantid::DataObjects::Workspace2D_sptr WS(
+        new Mantid::DataObjects::Workspace2D);
+    WS->initialize(histogramCount, binCount + 1, binCount);
+    const double xBegin = -0.2;
+    const double xEnd = 0.6;
+    for (size_t i = 0; i < histogramCount; ++i) {
+      WS->mutableX(i)[0] = xBegin;
+      WS->mutableX(i)[1] = xBegin + (xEnd - xBegin) / 2.0;
+      WS->mutableX(i)[2] = xEnd;
+      WS->mutableY(i)[0] = y1;
+      WS->mutableY(i)[1] = y2;
+      WS->mutableE(i)[0] = std::sqrt(std::abs(y1));
+      WS->mutableE(i)[1] = std::sqrt(std::abs(y2));
+    }
+    Mantid::Algorithms::CalculateFlatBackground flatBG;
+    TS_ASSERT_THROWS_NOTHING(flatBG.initialize());
+    TS_ASSERT(flatBG.isInitialized())
+    flatBG.setRethrows(true);
+    flatBG.setProperty("InputWorkspace", WS);
+    flatBG.setPropertyValue("OutputWorkspace", outWsName);
+    flatBG.setProperty("StartX", xBegin);
+    flatBG.setProperty("EndX", xEnd);
+    flatBG.setPropertyValue("WorkspaceIndexList", wsIndexList);
+    flatBG.setPropertyValue("Mode", mode);
+    flatBG.setPropertyValue("OutputMode", outputMode);
+    flatBG.setProperty("NullifyNegativeValues", nullifyNegatives);
+    flatBG.setProperty("AveragingWindowWidth", 1);
+    TS_ASSERT_THROWS_NOTHING(flatBG.execute())
+    TS_ASSERT(flatBG.isExecuted())
+    return WS;
+  }
+
+  void compareSubtractedAndBackgroundWorkspaces(
+      MatrixWorkspace_sptr originalWS, const std::string &subtractedWSName,
+      const std::string &backgroundWSName) {
+    const std::string minusWSName("minused");
+    MatrixWorkspace_sptr backgroundWS =
+        AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(
+            backgroundWSName);
+    MatrixWorkspace_sptr subtractedWS =
+        AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(
+            subtractedWSName);
+    Algorithms::Minus minus;
+    minus.initialize();
+    minus.setProperty("LHSWorkspace", originalWS);
+    minus.setProperty("RHSWorkspace", backgroundWS);
+    minus.setPropertyValue("OutputWorkspace", minusWSName);
+    minus.execute();
+    MatrixWorkspace_sptr minusWS =
+        AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(
+            minusWSName);
+    Algorithms::CompareWorkspaces comparison;
+    comparison.initialize();
+    comparison.setProperty("Workspace1", subtractedWS);
+    comparison.setProperty("Workspace2", minusWSName);
+    comparison.setProperty("Tolerance", 1e-6);
+    comparison.setProperty("ToleranceRelErr", true);
+    comparison.execute();
+    bool result = comparison.getProperty("Result");
+    TS_ASSERT(result)
+    AnalysisDataService::Instance().remove(minusWSName);
+  }
 };
 
 #endif /*FlatBackgroundTest_H_*/
diff --git a/Framework/Algorithms/test/CalculateResolutionTest.h b/Framework/Algorithms/test/CalculateResolutionTest.h
index edfda09c925f9de8d31b69f69e1eea91f0c51728..19ed6d382072a7be8504d38a8583a7a4e363f238 100644
--- a/Framework/Algorithms/test/CalculateResolutionTest.h
+++ b/Framework/Algorithms/test/CalculateResolutionTest.h
@@ -5,6 +5,7 @@
 
 #include "MantidAlgorithms/CalculateResolution.h"
 #include "MantidDataObjects/Workspace2D.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidGeometry/Instrument.h"
 #include "MantidGeometry/Instrument/Detector.h"
 #include "MantidKernel/V3D.h"
@@ -23,7 +24,7 @@ public:
 
     CalculateResolution alg;
     alg.initialize();
-    alg.setPropertyValue("Workspace", ws->name());
+    alg.setPropertyValue("Workspace", ws->getName());
     alg.setProperty("TwoTheta", 1.0);
     TS_ASSERT_THROWS_NOTHING(alg.execute());
     TS_ASSERT(alg.isExecuted());
@@ -38,7 +39,7 @@ public:
 
     CalculateResolution alg;
     alg.initialize();
-    alg.setPropertyValue("Workspace", ws->name());
+    alg.setPropertyValue("Workspace", ws->getName());
     alg.setProperty("TwoTheta", 1.0);
     TS_ASSERT_THROWS_NOTHING(alg.execute());
     TS_ASSERT(alg.isExecuted());
diff --git a/Framework/Algorithms/test/CalculateSlitsTest.h b/Framework/Algorithms/test/CalculateSlitsTest.h
new file mode 100644
index 0000000000000000000000000000000000000000..d094923db0917381b87943e934d36d525541c566
--- /dev/null
+++ b/Framework/Algorithms/test/CalculateSlitsTest.h
@@ -0,0 +1,115 @@
+#ifndef CALCULATESLITSTEST_H_
+#define CALCULATESLITSTEST_H_
+
+#include <cxxtest/TestSuite.h>
+
+#include "MantidAlgorithms/CalculateSlits.h"
+
+using namespace Mantid::Algorithms;
+
+namespace {
+double roundFour(double i) { return floor(i * 10000 + 0.5) / 10000; }
+}
+
+class CalculateSlitsTest : public CxxTest::TestSuite {
+public:
+  void testSensibleArgs() {
+    CalculateSlits alg;
+    alg.initialize();
+    alg.setProperty("Slit1Slit2", 1940.5);
+    alg.setProperty("Slit2SA", 364.);
+    alg.setProperty("Angle", 0.7);
+    alg.setProperty("Footprint", 50.);
+    alg.setProperty("Resolution", 0.03);
+
+    TS_ASSERT_THROWS_NOTHING(alg.execute());
+    TS_ASSERT(alg.isExecuted());
+
+    // truncate the output values to 4 decimal places to eliminate
+    // insignificant error
+    const double slit1 = roundFour(alg.getProperty("Slit1"));
+    TS_ASSERT_EQUALS(slit1, 1.0784);
+
+    const double slit2 = roundFour(alg.getProperty("Slit2"));
+    TS_ASSERT_EQUALS(slit2, 0.3440);
+  }
+
+  void testWithNegativeAngle() {
+    CalculateSlits alg;
+    alg.initialize();
+    alg.setProperty("Slit1Slit2", 1940.5);
+    alg.setProperty("Slit2SA", 364.);
+    alg.setProperty("Angle", -0.7);
+    alg.setProperty("Footprint", 50.);
+    alg.setProperty("Resolution", 0.03);
+
+    TS_ASSERT_THROWS_NOTHING(alg.execute());
+    TS_ASSERT(alg.isExecuted());
+
+    // truncate the output values to 4 decimal places to eliminate
+    // insignificant error
+    const double slit1 = roundFour(alg.getProperty("Slit1"));
+    TS_ASSERT_EQUALS(slit1, -1.0784);
+
+    const double slit2 = roundFour(alg.getProperty("Slit2"));
+    TS_ASSERT_EQUALS(slit2, -0.3440);
+  }
+
+  void testWithZeroAngle() {
+    CalculateSlits alg;
+    alg.initialize();
+    alg.setProperty("Slit1Slit2", 1940.5);
+    alg.setProperty("Slit2SA", 364.);
+    alg.setProperty("Angle", 0.);
+    alg.setProperty("Footprint", 50.);
+    alg.setProperty("Resolution", 0.03);
+
+    TS_ASSERT_THROWS_NOTHING(alg.execute());
+    TS_ASSERT(alg.isExecuted());
+
+    const double slit1 = alg.getProperty("Slit1");
+    TS_ASSERT_EQUALS(slit1, 0.0);
+
+    const double slit2 = alg.getProperty("Slit2");
+    TS_ASSERT_EQUALS(slit2, 0.0);
+  }
+
+  void testWithNanAndInf() {
+    const double nan = std::numeric_limits<double>::quiet_NaN();
+    const double inf = std::numeric_limits<double>::infinity();
+    const double ninf = -inf;
+
+    CalculateSlits alg;
+    alg.initialize();
+    alg.setProperty("Slit1Slit2", nan);
+    alg.setProperty("Slit2SA", nan);
+    alg.setProperty("Angle", inf);
+    alg.setProperty("Footprint", inf);
+    alg.setProperty("Resolution", ninf);
+
+    TS_ASSERT_THROWS_NOTHING(alg.execute());
+    TS_ASSERT(alg.isExecuted());
+
+    const double slit1 = alg.getProperty("Slit1");
+    TS_ASSERT(std::isnan(slit1));
+
+    const double slit2 = alg.getProperty("Slit2");
+    TS_ASSERT(std::isnan(slit2));
+  }
+
+  void testWithNoArgs() {
+    CalculateSlits alg;
+    alg.initialize();
+
+    TS_ASSERT_THROWS_NOTHING(alg.execute());
+    TS_ASSERT(alg.isExecuted());
+
+    const double slit1 = alg.getProperty("Slit1");
+    TS_ASSERT(std::isnan(slit1));
+
+    const double slit2 = alg.getProperty("Slit2");
+    TS_ASSERT(std::isnan(slit2));
+  }
+};
+
+#endif /*CALCULATESLITSTEST_H_*/
diff --git a/Framework/Algorithms/test/CalculateTransmissionBeamSpreaderTest.h b/Framework/Algorithms/test/CalculateTransmissionBeamSpreaderTest.h
index 611b767c97228eeb71f76297cc6a1847c4d258b0..e19b0356af2d9baf7b1324c371fe6ab8c3f2ee3d 100644
--- a/Framework/Algorithms/test/CalculateTransmissionBeamSpreaderTest.h
+++ b/Framework/Algorithms/test/CalculateTransmissionBeamSpreaderTest.h
@@ -8,6 +8,7 @@
 #include "MantidAlgorithms/CropWorkspace.h"
 #include "MantidDataHandling/LoadInstrument.h"
 #include "MantidDataHandling/LoadRaw3.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidTestHelpers/SANSInstrumentCreationHelper.h"
 
 using namespace Mantid::API;
diff --git a/Framework/Algorithms/test/CalculateZscoreTest.h b/Framework/Algorithms/test/CalculateZscoreTest.h
index 4fe2ffb7b8f7e3104be32b545623dfcc6cfd88d6..c2915b77b9e9719bdbe6dfdafe3d5ff0561b312f 100644
--- a/Framework/Algorithms/test/CalculateZscoreTest.h
+++ b/Framework/Algorithms/test/CalculateZscoreTest.h
@@ -3,6 +3,7 @@
 
 #include <cxxtest/TestSuite.h>
 
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidAlgorithms/CalculateZscore.h"
diff --git a/Framework/Algorithms/test/ChainedOperatorTest.h b/Framework/Algorithms/test/ChainedOperatorTest.h
index 9a603d282b2e71a63e62b140dabdcc0da4a9a38e..a9c9142cbf1ee6dd8ec34c05095f17de89c62301 100644
--- a/Framework/Algorithms/test/ChainedOperatorTest.h
+++ b/Framework/Algorithms/test/ChainedOperatorTest.h
@@ -48,9 +48,9 @@ public:
     int nHist = 10, nBins = 20;
     // Register the workspace in the data service
     MatrixWorkspace_sptr work_in1 =
-        WorkspaceCreationHelper::Create2DWorkspace123(nHist, nBins);
+        WorkspaceCreationHelper::create2DWorkspace123(nHist, nBins);
     MatrixWorkspace_sptr work_in2 =
-        WorkspaceCreationHelper::Create2DWorkspace154(nHist, nBins);
+        WorkspaceCreationHelper::create2DWorkspace154(nHist, nBins);
 
     performTest(work_in1, work_in2);
   }
@@ -59,9 +59,9 @@ public:
     int nHist = 10, nBins = 20;
     // Register the workspace in the data service
     MatrixWorkspace_sptr work_in1 =
-        WorkspaceCreationHelper::CreateEventWorkspace(nHist, nBins);
+        WorkspaceCreationHelper::createEventWorkspace(nHist, nBins);
     MatrixWorkspace_sptr work_in2 =
-        WorkspaceCreationHelper::CreateEventWorkspace(nHist, nBins);
+        WorkspaceCreationHelper::createEventWorkspace(nHist, nBins);
 
     performTest(work_in1, work_in2);
   }
diff --git a/Framework/Algorithms/test/ChangeBinOffsetTest.h b/Framework/Algorithms/test/ChangeBinOffsetTest.h
index fd043ebe9fb13ac8c4885d4e16cc0ec9d6530974..ee5b37e64ae319f875d2aa0f204cfd1aa0e21794 100644
--- a/Framework/Algorithms/test/ChangeBinOffsetTest.h
+++ b/Framework/Algorithms/test/ChangeBinOffsetTest.h
@@ -10,7 +10,7 @@
 
 #include "MantidDataObjects/Workspace2D.h"
 #include "MantidDataObjects/EventWorkspace.h"
-#include "MantidDataHandling/LoadEventPreNexus.h"
+#include "MantidDataHandling/LoadEventPreNexus2.h"
 #include "MantidAPI/IAlgorithm.h"
 #include "MantidAlgorithms/ChangeBinOffset.h"
 
@@ -98,7 +98,7 @@ public:
 
   void setup_Event() {
     this->inputSpace = "eventWS";
-    Mantid::DataHandling::LoadEventPreNexus loader;
+    Mantid::DataHandling::LoadEventPreNexus2 loader;
     loader.initialize();
     std::string eventfile("CNCS_7860_neutron_event.dat");
     std::string pulsefile("CNCS_7860_pulseid.dat");
@@ -179,9 +179,9 @@ public:
   }
 
   ChangeBinOffsetTestPerformance() {
-    input = WorkspaceCreationHelper::Create2DWorkspaceBinned(10000, 1000);
+    input = WorkspaceCreationHelper::create2DWorkspaceBinned(10000, 1000);
     inputEvent =
-        WorkspaceCreationHelper::CreateEventWorkspace(10000, 1000, 5000);
+        WorkspaceCreationHelper::createEventWorkspace(10000, 1000, 5000);
   }
 
   void testExec2D() {
diff --git a/Framework/Algorithms/test/ChangeLogTimeTest.h b/Framework/Algorithms/test/ChangeLogTimeTest.h
index f34bfe66876c7d9b08bf139e4348119c0c0ee5f4..77451ab8b5e1a67a1c70945118b7237275f7f44f 100644
--- a/Framework/Algorithms/test/ChangeLogTimeTest.h
+++ b/Framework/Algorithms/test/ChangeLogTimeTest.h
@@ -5,6 +5,7 @@
 #include "MantidAlgorithms/ChangeLogTime.h"
 #include "MantidDataObjects/Workspace2D.h"
 #include "MantidKernel/TimeSeriesProperty.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Run.h"
 
 using std::string;
diff --git a/Framework/Algorithms/test/ChangePulsetimeTest.h b/Framework/Algorithms/test/ChangePulsetimeTest.h
index a3892cc950cf7b2c49658ea7cf175934e4a48c1c..a28318b755f86edf7ad9f51ca08d072b940d2061 100644
--- a/Framework/Algorithms/test/ChangePulsetimeTest.h
+++ b/Framework/Algorithms/test/ChangePulsetimeTest.h
@@ -53,7 +53,7 @@ public:
     TS_ASSERT(alg.isInitialized())
 
     EventWorkspace_sptr in_ws, out_ws;
-    in_ws = WorkspaceCreationHelper::CreateEventWorkspace2(100, 100);
+    in_ws = WorkspaceCreationHelper::createEventWorkspace2(100, 100);
     AnalysisDataService::Instance().addOrReplace(in_ws_name, in_ws);
 
     alg.setPropertyValue("InputWorkspace", in_ws_name);
@@ -136,7 +136,7 @@ private:
 public:
   void setUp() override {
     EventWorkspace_sptr in_ws =
-        WorkspaceCreationHelper::CreateEventWorkspace2(30000, 30000);
+        WorkspaceCreationHelper::createEventWorkspace2(30000, 30000);
     m_workspace = in_ws;
   }
 
diff --git a/Framework/Algorithms/test/ChangeTimeZeroTest.h b/Framework/Algorithms/test/ChangeTimeZeroTest.h
index cff58f6fa4f61e1050c53eabe8d8228133944824..c5d103f8cf39e3c2406e103a6d8b9f6640e2c9d7 100644
--- a/Framework/Algorithms/test/ChangeTimeZeroTest.h
+++ b/Framework/Algorithms/test/ChangeTimeZeroTest.h
@@ -12,6 +12,7 @@
 #include "MantidDataObjects/EventWorkspace.h"
 #include "MantidDataObjects/EventList.h"
 #include "MantidAPI/MatrixWorkspace.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidKernel/DateTimeValidator.h"
 
 using namespace Mantid::Kernel;
@@ -111,7 +112,7 @@ Mantid::API::MatrixWorkspace_sptr provideWorkspace2D(LogType logType,
 Mantid::API::MatrixWorkspace_sptr
 provideWorkspaceSingleValue(LogType logType, DateAndTime startTime,
                             int length) {
-  auto ws = WorkspaceCreationHelper::CreateWorkspaceSingleValue(10);
+  auto ws = WorkspaceCreationHelper::createWorkspaceSingleValue(10);
   // Add the logs
   provideLogs(logType, ws, startTime, length);
   return ws;
@@ -121,7 +122,7 @@ provideWorkspaceSingleValue(LogType logType, DateAndTime startTime,
 Mantid::API::MatrixWorkspace_sptr
 provideEventWorkspaceCustom(LogType logType, DateAndTime startTime, int length,
                             int pixels, int bins, int events) {
-  auto ws = WorkspaceCreationHelper::CreateEventWorkspaceWithStartTime(
+  auto ws = WorkspaceCreationHelper::createEventWorkspaceWithStartTime(
       pixels, bins, events, 0.0, 1.0, 2, 0, startTime);
   // Add the logs
   provideLogs(logType, ws, startTime, length);
diff --git a/Framework/Algorithms/test/CheckWorkspacesMatchTest.h b/Framework/Algorithms/test/CheckWorkspacesMatchTest.h
index fe6f7fb6dbcfdc8f378feb7f7c4d1f281315806e..13c1715feb4192e1cdf1fca04bf88aa73f798ce8 100644
--- a/Framework/Algorithms/test/CheckWorkspacesMatchTest.h
+++ b/Framework/Algorithms/test/CheckWorkspacesMatchTest.h
@@ -7,6 +7,7 @@
 #include "MantidAPI/FrameworkManager.h"
 #include "MantidAPI/NumericAxis.h"
 #include "MantidAPI/Sample.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidKernel/UnitFactory.h"
 #include "MantidDataObjects/EventWorkspace.h"
 #include "MantidDataObjects/PeaksWorkspace.h"
@@ -35,7 +36,7 @@ public:
   static void destroySuite(CheckWorkspacesMatchTest *suite) { delete suite; }
 
   CheckWorkspacesMatchTest()
-      : ws1(WorkspaceCreationHelper::Create2DWorkspace123(2, 2)) {
+      : ws1(WorkspaceCreationHelper::create2DWorkspace123(2, 2)) {
     FrameworkManager::Instance();
   }
 
@@ -53,7 +54,7 @@ public:
       checker.initialize();
 
     MatrixWorkspace_sptr ws =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(10, 100);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(10, 100);
     // A workspace had better match itself!
     TS_ASSERT_THROWS_NOTHING(checker.setProperty("Workspace1", ws));
     TS_ASSERT_THROWS_NOTHING(checker.setProperty("Workspace2", ws));
@@ -172,9 +173,9 @@ public:
       checker.initialize();
 
     EventWorkspace_sptr ews1 =
-        WorkspaceCreationHelper::CreateEventWorkspace(10, 20, 30);
+        WorkspaceCreationHelper::createEventWorkspace(10, 20, 30);
     EventWorkspace_sptr ews2 =
-        WorkspaceCreationHelper::CreateEventWorkspace(10, 20, 30);
+        WorkspaceCreationHelper::createEventWorkspace(10, 20, 30);
     TS_ASSERT_THROWS_NOTHING(checker.setProperty(
         "Workspace1", boost::dynamic_pointer_cast<MatrixWorkspace>(ews1)));
     TS_ASSERT_THROWS_NOTHING(checker.setProperty(
@@ -192,7 +193,7 @@ public:
       checker.initialize();
 
     EventWorkspace_sptr ews2 =
-        WorkspaceCreationHelper::CreateEventWorkspace(10, 20, 30);
+        WorkspaceCreationHelper::createEventWorkspace(10, 20, 30);
     TS_ASSERT_THROWS_NOTHING(checker.setProperty("Workspace1", ws1));
     TS_ASSERT_THROWS_NOTHING(checker.setProperty(
         "Workspace2", boost::dynamic_pointer_cast<MatrixWorkspace>(ews2)));
@@ -209,9 +210,9 @@ public:
       checker.initialize();
 
     EventWorkspace_sptr ews1 =
-        WorkspaceCreationHelper::CreateEventWorkspace(10, 20, 30);
+        WorkspaceCreationHelper::createEventWorkspace(10, 20, 30);
     EventWorkspace_sptr ews2 =
-        WorkspaceCreationHelper::CreateEventWorkspace(15, 20, 30);
+        WorkspaceCreationHelper::createEventWorkspace(15, 20, 30);
     TS_ASSERT_THROWS_NOTHING(checker.setProperty(
         "Workspace1", boost::dynamic_pointer_cast<MatrixWorkspace>(ews1)));
     TS_ASSERT_THROWS_NOTHING(checker.setProperty(
@@ -227,9 +228,9 @@ public:
     if (!checker.isInitialized())
       checker.initialize();
     EventWorkspace_sptr ews1 =
-        WorkspaceCreationHelper::CreateEventWorkspace(10, 20, 30);
+        WorkspaceCreationHelper::createEventWorkspace(10, 20, 30);
     EventWorkspace_sptr ews2 =
-        WorkspaceCreationHelper::CreateEventWorkspace(10, 20, 30, 0.0, 1.0, 2);
+        WorkspaceCreationHelper::createEventWorkspace(10, 20, 30, 0.0, 1.0, 2);
     TS_ASSERT_THROWS_NOTHING(checker.setProperty(
         "Workspace1", boost::dynamic_pointer_cast<MatrixWorkspace>(ews1)));
     TS_ASSERT_THROWS_NOTHING(checker.setProperty(
@@ -245,9 +246,9 @@ public:
     if (!checker.isInitialized())
       checker.initialize();
     EventWorkspace_sptr ews1 =
-        WorkspaceCreationHelper::CreateEventWorkspace(10, 20, 30, 15.0, 10.0);
+        WorkspaceCreationHelper::createEventWorkspace(10, 20, 30, 15.0, 10.0);
     EventWorkspace_sptr ews2 =
-        WorkspaceCreationHelper::CreateEventWorkspace(10, 20, 30, 5.0, 10.0);
+        WorkspaceCreationHelper::createEventWorkspace(10, 20, 30, 5.0, 10.0);
     TS_ASSERT_THROWS_NOTHING(checker.setProperty(
         "Workspace1", boost::dynamic_pointer_cast<MatrixWorkspace>(ews1)));
     TS_ASSERT_THROWS_NOTHING(checker.setProperty(
@@ -542,7 +543,7 @@ public:
       checker.initialize();
 
     Mantid::API::MatrixWorkspace_sptr ws2 =
-        WorkspaceCreationHelper::Create1DWorkspaceFib(2);
+        WorkspaceCreationHelper::create1DWorkspaceFib(2);
 
     TS_ASSERT_THROWS_NOTHING(checker.setProperty("Workspace1", ws1));
     TS_ASSERT_THROWS_NOTHING(checker.setProperty("Workspace2", ws2));
@@ -559,7 +560,7 @@ public:
       checker.initialize();
 
     Mantid::API::MatrixWorkspace_sptr ws2 =
-        WorkspaceCreationHelper::Create2DWorkspace123(2, 2, true);
+        WorkspaceCreationHelper::create2DWorkspace123(2, 2, true);
 
     TS_ASSERT_THROWS_NOTHING(checker.setProperty("Workspace1", ws1));
     TS_ASSERT_THROWS_NOTHING(checker.setProperty("Workspace2", ws2));
@@ -577,7 +578,7 @@ public:
       checker.initialize();
 
     Mantid::API::MatrixWorkspace_sptr ws2 =
-        WorkspaceCreationHelper::Create2DWorkspace123(2, 2);
+        WorkspaceCreationHelper::create2DWorkspace123(2, 2);
     ws2->setDistribution(true);
 
     TS_ASSERT_THROWS_NOTHING(checker.setProperty("Workspace1", ws1));
@@ -596,7 +597,7 @@ public:
       checker.initialize();
 
     Mantid::API::MatrixWorkspace_sptr ws2 =
-        WorkspaceCreationHelper::Create2DWorkspace123(2, 2);
+        WorkspaceCreationHelper::create2DWorkspace123(2, 2);
     Mantid::API::Axis *const newAxis = new Mantid::API::NumericAxis(2);
     ws2->replaceAxis(1, newAxis);
 
@@ -616,7 +617,7 @@ public:
       checker.initialize();
 
     Mantid::API::MatrixWorkspace_sptr ws2 =
-        WorkspaceCreationHelper::Create2DWorkspace123(2, 2);
+        WorkspaceCreationHelper::create2DWorkspace123(2, 2);
     ws2->getAxis(0)->title() = "blah";
 
     TS_ASSERT_THROWS_NOTHING(checker.setProperty("Workspace1", ws1));
@@ -635,7 +636,7 @@ public:
       checker.initialize();
 
     Mantid::API::MatrixWorkspace_sptr ws2 =
-        WorkspaceCreationHelper::Create2DWorkspace123(2, 2);
+        WorkspaceCreationHelper::create2DWorkspace123(2, 2);
     ws2->getAxis(0)->unit() =
         Mantid::Kernel::UnitFactory::Instance().create("Wavelength");
 
@@ -654,9 +655,9 @@ public:
       checker.initialize();
 
     Mantid::API::MatrixWorkspace_sptr ws1local =
-        WorkspaceCreationHelper::Create2DWorkspace123(2, 2);
+        WorkspaceCreationHelper::create2DWorkspace123(2, 2);
     Mantid::API::MatrixWorkspace_sptr ws2 =
-        WorkspaceCreationHelper::Create2DWorkspace123(2, 2);
+        WorkspaceCreationHelper::create2DWorkspace123(2, 2);
     // Put numeric axes on these workspaces as checkAxes won't test values on
     // spectra axes
     Axis *newAxisWS1 = new NumericAxis(ws1local->getAxis(1)->length());
@@ -689,7 +690,7 @@ public:
       checker.initialize();
 
     Mantid::API::MatrixWorkspace_sptr ws2 =
-        WorkspaceCreationHelper::Create2DWorkspace123(2, 2);
+        WorkspaceCreationHelper::create2DWorkspace123(2, 2);
     ws2->setYUnit("blah");
 
     TS_ASSERT_THROWS_NOTHING(checker.setProperty("Workspace1", ws1));
@@ -706,7 +707,7 @@ public:
       checker.initialize();
 
     Mantid::API::MatrixWorkspace_sptr ws2 =
-        WorkspaceCreationHelper::Create2DWorkspace123(2, 2);
+        WorkspaceCreationHelper::create2DWorkspace123(2, 2);
     ws2->getSpectrum(0).setSpectrumNo(1234);
     TS_ASSERT_THROWS_NOTHING(checker.setProperty("Workspace1", ws1));
     TS_ASSERT_THROWS_NOTHING(checker.setProperty("Workspace2", ws2));
@@ -714,7 +715,7 @@ public:
     TS_ASSERT_EQUALS(checker.getPropertyValue("Result"),
                      "Spectrum number mismatch");
 
-    ws2 = WorkspaceCreationHelper::Create2DWorkspace123(2, 2);
+    ws2 = WorkspaceCreationHelper::create2DWorkspace123(2, 2);
     ws2->getSpectrum(0).setDetectorID(99);
     ws2->getSpectrum(1).setDetectorID(98);
     TS_ASSERT_THROWS_NOTHING(checker.setProperty("Workspace1", ws1));
@@ -732,7 +733,7 @@ public:
       checker.initialize();
 
     Mantid::API::MatrixWorkspace_sptr ws2 =
-        WorkspaceCreationHelper::Create2DWorkspace123(2, 2);
+        WorkspaceCreationHelper::create2DWorkspace123(2, 2);
     Mantid::Geometry::Instrument_sptr instrument(
         new Mantid::Geometry::Instrument("different"));
     ws2->setInstrument(instrument);
@@ -752,7 +753,7 @@ public:
       checker.initialize();
 
     Mantid::API::MatrixWorkspace_sptr ws2 =
-        WorkspaceCreationHelper::Create2DWorkspace123(2, 2);
+        WorkspaceCreationHelper::create2DWorkspace123(2, 2);
     ws2->instrumentParameters().addBool(new Mantid::Geometry::Component,
                                         "myParam", true);
 
@@ -772,7 +773,7 @@ public:
       checker.initialize();
 
     Mantid::API::MatrixWorkspace_sptr ws2 =
-        WorkspaceCreationHelper::Create2DWorkspace123(2, 2);
+        WorkspaceCreationHelper::create2DWorkspace123(2, 2);
     ws2->maskBin(0, 0);
     ws2->dataY(0)[0] = 2;
     ws2->dataE(0)[0] = 3;
@@ -784,7 +785,7 @@ public:
     TS_ASSERT_EQUALS(checker.getPropertyValue("Result"), "Masking mismatch");
 
     Mantid::API::MatrixWorkspace_sptr ws3 =
-        WorkspaceCreationHelper::Create2DWorkspace123(2, 2);
+        WorkspaceCreationHelper::create2DWorkspace123(2, 2);
     ws3->maskBin(0, 1);
     ws3->dataY(0)[1] = 2;
     ws3->dataE(0)[1] = 3;
@@ -804,7 +805,7 @@ public:
     checker.setProperty("CheckSample", true);
 
     Mantid::API::MatrixWorkspace_sptr ws2 =
-        WorkspaceCreationHelper::Create2DWorkspace123(2, 2);
+        WorkspaceCreationHelper::create2DWorkspace123(2, 2);
     ws2->mutableSample().setName("different");
 
     TS_ASSERT_THROWS_NOTHING(checker.setProperty("Workspace1", ws1));
@@ -821,7 +822,7 @@ public:
     checker.setProperty("CheckSample", true);
 
     Mantid::API::MatrixWorkspace_sptr ws2 =
-        WorkspaceCreationHelper::Create2DWorkspace123(2, 2);
+        WorkspaceCreationHelper::create2DWorkspace123(2, 2);
     ws2->mutableRun().setProtonCharge(99.99);
 
     TS_ASSERT_THROWS_NOTHING(checker.setProperty("Workspace1", ws1));
@@ -838,7 +839,7 @@ public:
     checker.setProperty("CheckSample", true);
 
     Mantid::API::MatrixWorkspace_sptr ws2 =
-        WorkspaceCreationHelper::Create2DWorkspace123(2, 2);
+        WorkspaceCreationHelper::create2DWorkspace123(2, 2);
     ws2->mutableRun().addLogData(
         new Mantid::Kernel::PropertyWithValue<int>("Prop1", 99));
 
@@ -850,7 +851,7 @@ public:
                      "Different numbers of logs");
 
     Mantid::API::MatrixWorkspace_sptr ws3 =
-        WorkspaceCreationHelper::Create2DWorkspace123(2, 2);
+        WorkspaceCreationHelper::create2DWorkspace123(2, 2);
     ws3->mutableRun().addLogData(
         new Mantid::Kernel::PropertyWithValue<int>("Prop2", 99));
 
@@ -861,7 +862,7 @@ public:
     TS_ASSERT_EQUALS(checker.getPropertyValue("Result"), "Log mismatch");
 
     Mantid::API::MatrixWorkspace_sptr ws4 =
-        WorkspaceCreationHelper::Create2DWorkspace123(2, 2);
+        WorkspaceCreationHelper::create2DWorkspace123(2, 2);
     ws4->mutableRun().addLogData(
         new Mantid::Kernel::PropertyWithValue<int>("Prop1", 100));
 
@@ -876,7 +877,7 @@ public:
     // Create a group
     const std::string groupName("TestGroup");
     WorkspaceGroup_sptr group =
-        WorkspaceCreationHelper::CreateWorkspaceGroup(2, 2, 2, groupName);
+        WorkspaceCreationHelper::createWorkspaceGroup(2, 2, 2, groupName);
 
     doGroupTest(groupName, groupName,
                 Mantid::Algorithms::CheckWorkspacesMatch::successString());
@@ -888,10 +889,10 @@ public:
     // Create a group
     const std::string groupOneName("TestGroupOne");
     WorkspaceGroup_sptr groupOne =
-        WorkspaceCreationHelper::CreateWorkspaceGroup(2, 2, 2, groupOneName);
+        WorkspaceCreationHelper::createWorkspaceGroup(2, 2, 2, groupOneName);
     const std::string groupTwoName("TestGroupTwo");
     WorkspaceGroup_sptr groupTwo =
-        WorkspaceCreationHelper::CreateWorkspaceGroup(3, 2, 2, groupTwoName);
+        WorkspaceCreationHelper::createWorkspaceGroup(3, 2, 2, groupTwoName);
 
     doGroupTest(groupOneName, groupTwoName, "GroupWorkspaces size mismatch.",
                 std::map<std::string, std::string>(), true);
@@ -903,9 +904,9 @@ public:
   void test_Input_With_A_Group_And_A_Single_Workspace_Gives_Type_Mismatch() {
     const std::string groupName("CheckWorkspacesMatch_TestGroup");
     WorkspaceGroup_sptr group =
-        WorkspaceCreationHelper::CreateWorkspaceGroup(2, 2, 2, groupName);
+        WorkspaceCreationHelper::createWorkspaceGroup(2, 2, 2, groupName);
     Mantid::API::MatrixWorkspace_sptr ws2 =
-        WorkspaceCreationHelper::Create2DWorkspace123(2, 2);
+        WorkspaceCreationHelper::create2DWorkspace123(2, 2);
     const std::string wsName("CheckWorkspacesMatch_TestWS");
     Mantid::API::AnalysisDataService::Instance().add(wsName, ws2);
 
@@ -922,10 +923,10 @@ public:
     // Create a group
     const std::string groupOneName("TestGroupOne");
     WorkspaceGroup_sptr groupOne =
-        WorkspaceCreationHelper::CreateWorkspaceGroup(2, 2, 2, groupOneName);
+        WorkspaceCreationHelper::createWorkspaceGroup(2, 2, 2, groupOneName);
     const std::string groupTwoName("TestGroupTwo");
     WorkspaceGroup_sptr groupTwo =
-        WorkspaceCreationHelper::CreateWorkspaceGroup(2, 2, 2, groupTwoName);
+        WorkspaceCreationHelper::createWorkspaceGroup(2, 2, 2, groupTwoName);
     Mantid::API::AnalysisDataServiceImpl &dataStore =
         Mantid::API::AnalysisDataService::Instance();
     // Extract the zeroth element of groupTwo and add a spurious log
diff --git a/Framework/Algorithms/test/ChopDataTest.h b/Framework/Algorithms/test/ChopDataTest.h
index 0cf6b1fff3bc6d38d02257b0e36a6c5bffb9d774..879d67a5c15c972c5fa381564b434ee3f3cee221 100644
--- a/Framework/Algorithms/test/ChopDataTest.h
+++ b/Framework/Algorithms/test/ChopDataTest.h
@@ -5,6 +5,7 @@
 
 #include "MantidAlgorithms/ChopData.h"
 #include "MantidAPI/Axis.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidTestHelpers/WorkspaceCreationHelper.h"
 
 using namespace Mantid::API;
@@ -28,7 +29,7 @@ public:
 
   void testExec() {
     Mantid::DataObjects::Workspace2D_sptr inputWS =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(149, 24974, 5, 4);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(149, 24974, 5, 4);
 
     for (int i = 0; i < 4995; i++) {
       inputWS->mutableX(140)[i + 19980] = 0.2;
diff --git a/Framework/Algorithms/test/ClearInstrumentParametersTest.h b/Framework/Algorithms/test/ClearInstrumentParametersTest.h
index a07280e353ade6587cf07c9a9ce73b2e455cbdd4..ab4803c926981034acab8d84498a5fe6dac9b708 100644
--- a/Framework/Algorithms/test/ClearInstrumentParametersTest.h
+++ b/Framework/Algorithms/test/ClearInstrumentParametersTest.h
@@ -61,7 +61,7 @@ public:
   void clearParameters() {
     ClearInstrumentParameters clearer;
     TS_ASSERT_THROWS_NOTHING(clearer.initialize());
-    clearer.setPropertyValue("Workspace", m_ws->name());
+    clearer.setPropertyValue("Workspace", m_ws->getName());
     TS_ASSERT_THROWS_NOTHING(clearer.execute());
     TS_ASSERT(clearer.isExecuted());
   }
diff --git a/Framework/Algorithms/test/ClearMaskFlagTest.h b/Framework/Algorithms/test/ClearMaskFlagTest.h
index dc75fa6ff4239f0f03f7262b8ce8a345a99cc34f..91afa209f332d6a04ee56463401054745eb4d617 100644
--- a/Framework/Algorithms/test/ClearMaskFlagTest.h
+++ b/Framework/Algorithms/test/ClearMaskFlagTest.h
@@ -4,6 +4,8 @@
 #include <cxxtest/TestSuite.h>
 #include "MantidHistogramData/LinearGenerator.h"
 #include "MantidAlgorithms/ClearMaskFlag.h"
+#include "MantidAPI/AnalysisDataService.h"
+#include "MantidAPI/DetectorInfo.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidDataObjects/Workspace2D.h"
 #include "MantidGeometry/Instrument.h"
@@ -57,9 +59,9 @@ public:
     space2D->setInstrument(instr);
 
     // set the mask on a bunch of spectra
-    Mantid::Geometry::ParameterMap &pmap = space2D->instrumentParameters();
+    auto &detectorInfo = space2D->mutableDetectorInfo();
     for (int j = 0; j < nummask; ++j) {
-      pmap.addBool(instr->getDetector(j)->getComponentID(), "masked", true);
+      detectorInfo.setMasked(j, true);
     }
 
     // register the workspace in the data service
@@ -84,9 +86,9 @@ public:
       return;
 
     // check the results
-    Instrument_const_sptr out_instr = ws->getInstrument();
+    const auto &resultDetInfo = ws->detectorInfo();
     for (int j = 0; j < numspec; ++j) {
-      TS_ASSERT(!out_instr->isDetectorMasked(j));
+      TS_ASSERT(!resultDetInfo.isMasked(j));
     }
 
     // remove workspace from the data service.
diff --git a/Framework/Algorithms/test/CloneWorkspaceTest.h b/Framework/Algorithms/test/CloneWorkspaceTest.h
index c35f470f9f48995bc3f8b51d3997f4e332f5334d..fba9e16d1537a2598ad885b50052894a6ac929d6 100644
--- a/Framework/Algorithms/test/CloneWorkspaceTest.h
+++ b/Framework/Algorithms/test/CloneWorkspaceTest.h
@@ -10,6 +10,7 @@
 #include "MantidTestHelpers/WorkspaceCreationHelper.h"
 #include "MantidTestHelpers/ComponentCreationHelper.h"
 #include "MantidAPI/AnalysisDataService.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidDataObjects/MDEventFactory.h"
 #include "MantidTestHelpers/MDEventsTestHelper.h"
 #include "MantidGeometry/Instrument.h"
@@ -84,7 +85,7 @@ public:
   void testExecEvent() {
     // First make the algorithm
     EventWorkspace_sptr ew =
-        WorkspaceCreationHelper::CreateEventWorkspace(100, 60, 50);
+        WorkspaceCreationHelper::createEventWorkspace(100, 60, 50);
     AnalysisDataService::Instance().addOrReplace("in_event", ew);
 
     Mantid::Algorithms::CloneWorkspace alg;
@@ -147,7 +148,7 @@ public:
 
   void test_group() {
     WorkspaceGroup_const_sptr ingroup =
-        WorkspaceCreationHelper::CreateWorkspaceGroup(3, 1, 1, "grouptoclone");
+        WorkspaceCreationHelper::createWorkspaceGroup(3, 1, 1, "grouptoclone");
     Mantid::Algorithms::CloneWorkspace alg;
     alg.initialize();
     alg.setPropertyValue("InputWorkspace", "grouptoclone");
@@ -165,19 +166,19 @@ public:
     // Try to get the first member
     TS_ASSERT_THROWS_NOTHING(out1 = outgroup->getItem(0))
     // Check its name
-    TS_ASSERT_EQUALS(out1->name(), "clonedgroup_1")
+    TS_ASSERT_EQUALS(out1->getName(), "clonedgroup_1")
     // Check it is indeed a different workspace
     TS_ASSERT_DIFFERS(out1, ingroup->getItem(0))
     // Try to get the second member
     TS_ASSERT_THROWS_NOTHING(out2 = outgroup->getItem(1))
     // Check its name
-    TS_ASSERT_EQUALS(out2->name(), "clonedgroup_2")
+    TS_ASSERT_EQUALS(out2->getName(), "clonedgroup_2")
     // Check it is indeed a different workspace
     TS_ASSERT_DIFFERS(out2, ingroup->getItem(1))
     // Try to get the third member
     TS_ASSERT_THROWS_NOTHING(out3 = outgroup->getItem(2))
     // Check its name
-    TS_ASSERT_EQUALS(out3->name(), "clonedgroup_3")
+    TS_ASSERT_EQUALS(out3->getName(), "clonedgroup_3")
     // Check it is indeed a different workspace
     TS_ASSERT_DIFFERS(out3, ingroup->getItem(2))
 
diff --git a/Framework/Algorithms/test/CommentTest.h b/Framework/Algorithms/test/CommentTest.h
index 22c846ada84473c034352a8cbd2d5fd71d21f00b..d05d80021f7b19e88515c420fd1cdb099f562a5e 100644
--- a/Framework/Algorithms/test/CommentTest.h
+++ b/Framework/Algorithms/test/CommentTest.h
@@ -5,6 +5,7 @@
 
 #include "MantidAlgorithms/Comment.h"
 #include "MantidAPI/Workspace.h"
+#include "MantidAPI/WorkspaceHistory.h"
 #include "MantidTestHelpers/WorkspaceCreationHelper.h"
 
 using namespace Mantid::API;
@@ -25,10 +26,10 @@ public:
   void test_exec() {
     std::string wsName = "CommentTest_Exec_workspace";
     // Create test input
-    auto ws = WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+    auto ws = WorkspaceCreationHelper::create2DWorkspace(10, 10);
     AnalysisDataService::Instance().add(wsName, ws);
     // and an identical ws for comparison later
-    auto ws2 = WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+    auto ws2 = WorkspaceCreationHelper::create2DWorkspace(10, 10);
 
     Mantid::Algorithms::Comment alg;
     TS_ASSERT_THROWS_NOTHING(alg.initialize())
@@ -61,4 +62,4 @@ public:
   }
 };
 
-#endif /* MANTID_ALGORITHMS_COMMENTTEST_H_ */
\ No newline at end of file
+#endif /* MANTID_ALGORITHMS_COMMENTTEST_H_ */
diff --git a/Framework/Algorithms/test/CommutativeBinaryOperationTest.h b/Framework/Algorithms/test/CommutativeBinaryOperationTest.h
index 7392a6af03789fe5cc97c7a65bf337580e1de596..d0321893aa53fc1f45493f4c8d5de064763deeb2 100644
--- a/Framework/Algorithms/test/CommutativeBinaryOperationTest.h
+++ b/Framework/Algorithms/test/CommutativeBinaryOperationTest.h
@@ -72,17 +72,17 @@ public:
   void testcheckSizeCompatibility1D1D() {
     // Register the workspace in the data service
     MatrixWorkspace_sptr work_in1 =
-        WorkspaceCreationHelper::Create1DWorkspaceFib(10);
+        WorkspaceCreationHelper::create1DWorkspaceFib(10);
     MatrixWorkspace_sptr work_in2 =
-        WorkspaceCreationHelper::Create1DWorkspaceFib(20);
+        WorkspaceCreationHelper::create1DWorkspaceFib(20);
     MatrixWorkspace_sptr work_in3 =
-        WorkspaceCreationHelper::Create1DWorkspaceFib(10);
+        WorkspaceCreationHelper::create1DWorkspaceFib(10);
     MatrixWorkspace_sptr work_in4 =
-        WorkspaceCreationHelper::Create1DWorkspaceFib(5);
+        WorkspaceCreationHelper::create1DWorkspaceFib(5);
     MatrixWorkspace_sptr work_in5 =
-        WorkspaceCreationHelper::Create1DWorkspaceFib(3);
+        WorkspaceCreationHelper::create1DWorkspaceFib(3);
     MatrixWorkspace_sptr work_in6 =
-        WorkspaceCreationHelper::Create1DWorkspaceFib(1);
+        WorkspaceCreationHelper::create1DWorkspaceFib(1);
     CommutativeBinaryOpHelper helper;
     TS_ASSERT(!helper.checkSizeCompatibility(work_in1, work_in2).empty());
     TS_ASSERT(helper.checkSizeCompatibility(work_in1, work_in3).empty());
@@ -94,21 +94,21 @@ public:
   void testcheckSizeCompatibility2D1D() {
     // Register the workspace in the data service
     MatrixWorkspace_sptr work_in1 =
-        WorkspaceCreationHelper::Create2DWorkspace123(10, 10);
+        WorkspaceCreationHelper::create2DWorkspace123(10, 10);
     MatrixWorkspace_sptr work_in2 =
-        WorkspaceCreationHelper::Create1DWorkspaceFib(20);
+        WorkspaceCreationHelper::create1DWorkspaceFib(20);
     MatrixWorkspace_sptr work_in3 =
-        WorkspaceCreationHelper::Create1DWorkspaceFib(10);
+        WorkspaceCreationHelper::create1DWorkspaceFib(10);
     MatrixWorkspace_sptr work_in4 =
-        WorkspaceCreationHelper::Create1DWorkspaceFib(5);
+        WorkspaceCreationHelper::create1DWorkspaceFib(5);
     MatrixWorkspace_sptr work_in5 =
-        WorkspaceCreationHelper::Create1DWorkspaceFib(3);
+        WorkspaceCreationHelper::create1DWorkspaceFib(3);
     MatrixWorkspace_sptr work_in6 =
-        WorkspaceCreationHelper::Create1DWorkspaceFib(1);
+        WorkspaceCreationHelper::create1DWorkspaceFib(1);
     MatrixWorkspace_sptr work_event1 =
-        WorkspaceCreationHelper::CreateEventWorkspace(10, 1);
+        WorkspaceCreationHelper::createEventWorkspace(10, 1);
     MatrixWorkspace_sptr work_event2 =
-        WorkspaceCreationHelper::CreateEventWorkspace(1, 10);
+        WorkspaceCreationHelper::createEventWorkspace(1, 10);
     CommutativeBinaryOpHelper helper;
     TS_ASSERT(!helper.checkSizeCompatibility(work_in1, work_in2).empty());
     TS_ASSERT(helper.checkSizeCompatibility(work_in1, work_in3).empty());
@@ -123,23 +123,23 @@ public:
   void testcheckSizeCompatibility2D2D() {
     // Register the workspace in the data service
     MatrixWorkspace_sptr work_in1 =
-        WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+        WorkspaceCreationHelper::create2DWorkspace(10, 10);
     MatrixWorkspace_sptr work_in2 =
-        WorkspaceCreationHelper::Create2DWorkspace(10, 20);
+        WorkspaceCreationHelper::create2DWorkspace(10, 20);
     MatrixWorkspace_sptr work_in3 =
-        WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+        WorkspaceCreationHelper::create2DWorkspace(10, 10);
     MatrixWorkspace_sptr work_in4 =
-        WorkspaceCreationHelper::Create2DWorkspace(5, 5);
+        WorkspaceCreationHelper::create2DWorkspace(5, 5);
     MatrixWorkspace_sptr work_in5 =
-        WorkspaceCreationHelper::Create2DWorkspace(3, 3);
+        WorkspaceCreationHelper::create2DWorkspace(3, 3);
     MatrixWorkspace_sptr work_in6 =
-        WorkspaceCreationHelper::Create2DWorkspace(100, 1);
+        WorkspaceCreationHelper::create2DWorkspace(100, 1);
     MatrixWorkspace_sptr work_in7 =
-        WorkspaceCreationHelper::CreateWorkspaceSingleValue(10.0);
+        WorkspaceCreationHelper::createWorkspaceSingleValue(10.0);
     MatrixWorkspace_sptr work_event1 =
-        WorkspaceCreationHelper::CreateEventWorkspace(10, 1);
+        WorkspaceCreationHelper::createEventWorkspace(10, 1);
     MatrixWorkspace_sptr work_event2 =
-        WorkspaceCreationHelper::CreateEventWorkspace(10, 10);
+        WorkspaceCreationHelper::createEventWorkspace(10, 10);
     CommutativeBinaryOpHelper helper;
     TS_ASSERT(!helper.checkSizeCompatibility(work_in1, work_in2).empty());
     TS_ASSERT(helper.checkSizeCompatibility(work_in1, work_in3).empty());
diff --git a/Framework/Algorithms/test/CompareWorkspacesTest.h b/Framework/Algorithms/test/CompareWorkspacesTest.h
index 3f04aae3798099f3eee2763416b767f4e0657f22..9ef855e597fa2e0033fd191ad691bdc003c24cfb 100644
--- a/Framework/Algorithms/test/CompareWorkspacesTest.h
+++ b/Framework/Algorithms/test/CompareWorkspacesTest.h
@@ -9,6 +9,7 @@
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/NumericAxis.h"
 #include "MantidAPI/Sample.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidDataObjects/EventWorkspace.h"
 #include "MantidDataObjects/MDBoxBase.h"
 #include "MantidDataObjects/MDHistoWorkspace.h"
@@ -35,7 +36,7 @@ public:
   static void destroySuite(CompareWorkspacesTest *suite) { delete suite; }
 
   CompareWorkspacesTest()
-      : ws1(WorkspaceCreationHelper::Create2DWorkspace123(2, 2)),
+      : ws1(WorkspaceCreationHelper::create2DWorkspace123(2, 2)),
         PROPERTY_VALUE_TRUE("1") {
     FrameworkManager::Instance();
   }
@@ -54,7 +55,7 @@ public:
       checker.initialize();
 
     Workspace2D_sptr ws =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(10, 100);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(10, 100);
     // A workspace had better match itself!
     TS_ASSERT_THROWS_NOTHING(checker.setProperty("Workspace1", ws));
     TS_ASSERT_THROWS_NOTHING(checker.setProperty("Workspace2", ws));
@@ -170,9 +171,9 @@ public:
       checker.initialize();
 
     EventWorkspace_sptr ews1 =
-        WorkspaceCreationHelper::CreateEventWorkspace(10, 20, 30);
+        WorkspaceCreationHelper::createEventWorkspace(10, 20, 30);
     EventWorkspace_sptr ews2 =
-        WorkspaceCreationHelper::CreateEventWorkspace(10, 20, 30);
+        WorkspaceCreationHelper::createEventWorkspace(10, 20, 30);
     TS_ASSERT_THROWS_NOTHING(checker.setProperty(
         "Workspace1", boost::dynamic_pointer_cast<MatrixWorkspace>(ews1)));
     TS_ASSERT_THROWS_NOTHING(checker.setProperty(
@@ -189,7 +190,7 @@ public:
       checker.initialize();
 
     EventWorkspace_sptr ews2 =
-        WorkspaceCreationHelper::CreateEventWorkspace(10, 20, 30);
+        WorkspaceCreationHelper::createEventWorkspace(10, 20, 30);
     TS_ASSERT_THROWS_NOTHING(checker.setProperty("Workspace1", ws1));
     TS_ASSERT_THROWS_NOTHING(checker.setProperty(
         "Workspace2", boost::dynamic_pointer_cast<MatrixWorkspace>(ews2)));
@@ -205,9 +206,9 @@ public:
       checker.initialize();
 
     EventWorkspace_sptr ews1 =
-        WorkspaceCreationHelper::CreateEventWorkspace(10, 20, 30);
+        WorkspaceCreationHelper::createEventWorkspace(10, 20, 30);
     EventWorkspace_sptr ews2 =
-        WorkspaceCreationHelper::CreateEventWorkspace(15, 20, 30);
+        WorkspaceCreationHelper::createEventWorkspace(15, 20, 30);
     TS_ASSERT_THROWS_NOTHING(checker.setProperty(
         "Workspace1", boost::dynamic_pointer_cast<MatrixWorkspace>(ews1)));
     TS_ASSERT_THROWS_NOTHING(checker.setProperty(
@@ -222,9 +223,9 @@ public:
     if (!checker.isInitialized())
       checker.initialize();
     EventWorkspace_sptr ews1 =
-        WorkspaceCreationHelper::CreateEventWorkspace(10, 20, 30);
+        WorkspaceCreationHelper::createEventWorkspace(10, 20, 30);
     EventWorkspace_sptr ews2 =
-        WorkspaceCreationHelper::CreateEventWorkspace(10, 20, 30, 0.0, 1.0, 2);
+        WorkspaceCreationHelper::createEventWorkspace(10, 20, 30, 0.0, 1.0, 2);
     TS_ASSERT_THROWS_NOTHING(checker.setProperty(
         "Workspace1", boost::dynamic_pointer_cast<MatrixWorkspace>(ews1)));
     TS_ASSERT_THROWS_NOTHING(checker.setProperty(
@@ -239,9 +240,9 @@ public:
     if (!checker.isInitialized())
       checker.initialize();
     EventWorkspace_sptr ews1 =
-        WorkspaceCreationHelper::CreateEventWorkspace(10, 20, 30, 15.0, 10.0);
+        WorkspaceCreationHelper::createEventWorkspace(10, 20, 30, 15.0, 10.0);
     EventWorkspace_sptr ews2 =
-        WorkspaceCreationHelper::CreateEventWorkspace(10, 20, 30, 5.0, 10.0);
+        WorkspaceCreationHelper::createEventWorkspace(10, 20, 30, 5.0, 10.0);
     TS_ASSERT_THROWS_NOTHING(checker.setProperty(
         "Workspace1", boost::dynamic_pointer_cast<MatrixWorkspace>(ews1)));
     TS_ASSERT_THROWS_NOTHING(checker.setProperty(
@@ -520,7 +521,7 @@ public:
       checker.initialize();
 
     Mantid::API::MatrixWorkspace_sptr ws2 =
-        WorkspaceCreationHelper::Create1DWorkspaceFib(2);
+        WorkspaceCreationHelper::create1DWorkspaceFib(2);
 
     TS_ASSERT_THROWS_NOTHING(checker.setProperty("Workspace1", ws1));
     TS_ASSERT_THROWS_NOTHING(checker.setProperty("Workspace2", ws2));
@@ -542,7 +543,7 @@ public:
       checker.initialize();
 
     Mantid::API::MatrixWorkspace_sptr ws2 =
-        WorkspaceCreationHelper::Create2DWorkspace123(2, 2, true);
+        WorkspaceCreationHelper::create2DWorkspace123(2, 2, true);
 
     TS_ASSERT_THROWS_NOTHING(checker.setProperty("Workspace1", ws1));
     TS_ASSERT_THROWS_NOTHING(checker.setProperty("Workspace2", ws2));
@@ -565,7 +566,7 @@ public:
       checker.initialize();
 
     Mantid::API::MatrixWorkspace_sptr ws2 =
-        WorkspaceCreationHelper::Create2DWorkspace123(2, 2);
+        WorkspaceCreationHelper::create2DWorkspace123(2, 2);
     ws2->setDistribution(true);
 
     TS_ASSERT_THROWS_NOTHING(checker.setProperty("Workspace1", ws1));
@@ -589,7 +590,7 @@ public:
       checker.initialize();
 
     Mantid::API::MatrixWorkspace_sptr ws2 =
-        WorkspaceCreationHelper::Create2DWorkspace123(2, 2);
+        WorkspaceCreationHelper::create2DWorkspace123(2, 2);
     Mantid::API::Axis *const newAxis = new Mantid::API::NumericAxis(2);
     ws2->replaceAxis(1, newAxis);
 
@@ -613,7 +614,7 @@ public:
       checker.initialize();
 
     Mantid::API::MatrixWorkspace_sptr ws2 =
-        WorkspaceCreationHelper::Create2DWorkspace123(2, 2);
+        WorkspaceCreationHelper::create2DWorkspace123(2, 2);
     ws2->getAxis(0)->title() = "blah";
 
     TS_ASSERT_THROWS_NOTHING(checker.setProperty("Workspace1", ws1));
@@ -636,7 +637,7 @@ public:
       checker.initialize();
 
     Mantid::API::MatrixWorkspace_sptr ws2 =
-        WorkspaceCreationHelper::Create2DWorkspace123(2, 2);
+        WorkspaceCreationHelper::create2DWorkspace123(2, 2);
     ws2->getAxis(0)->unit() =
         Mantid::Kernel::UnitFactory::Instance().create("Wavelength");
 
@@ -660,9 +661,9 @@ public:
       checker.initialize();
 
     Mantid::API::MatrixWorkspace_sptr ws1local =
-        WorkspaceCreationHelper::Create2DWorkspace123(2, 2);
+        WorkspaceCreationHelper::create2DWorkspace123(2, 2);
     Mantid::API::MatrixWorkspace_sptr ws2 =
-        WorkspaceCreationHelper::Create2DWorkspace123(2, 2);
+        WorkspaceCreationHelper::create2DWorkspace123(2, 2);
     // Put numeric axes on these workspaces as checkAxes won't test values on
     // spectra axes
     Axis *newAxisWS1 = new NumericAxis(ws1local->getAxis(1)->length());
@@ -700,7 +701,7 @@ public:
       checker.initialize();
 
     Mantid::API::MatrixWorkspace_sptr ws2 =
-        WorkspaceCreationHelper::Create2DWorkspace123(2, 2);
+        WorkspaceCreationHelper::create2DWorkspace123(2, 2);
     ws2->setYUnit("blah");
 
     TS_ASSERT_THROWS_NOTHING(checker.setProperty("Workspace1", ws1));
@@ -723,7 +724,7 @@ public:
       checker.initialize();
 
     Mantid::API::MatrixWorkspace_sptr ws2 =
-        WorkspaceCreationHelper::Create2DWorkspace123(2, 2);
+        WorkspaceCreationHelper::create2DWorkspace123(2, 2);
     ws2->getSpectrum(0).setSpectrumNo(1234);
     TS_ASSERT_THROWS_NOTHING(checker.setProperty("Workspace1", ws1));
     TS_ASSERT_THROWS_NOTHING(checker.setProperty("Workspace2", ws2));
@@ -737,7 +738,7 @@ public:
     TS_ASSERT_EQUALS(table->cell<std::string>(0, 0),
                      "Spectrum number mismatch");
 
-    ws2 = WorkspaceCreationHelper::Create2DWorkspace123(2, 2);
+    ws2 = WorkspaceCreationHelper::create2DWorkspace123(2, 2);
     ws2->getSpectrum(0).setDetectorID(99);
     ws2->getSpectrum(1).setDetectorID(98);
     TS_ASSERT_THROWS_NOTHING(checker.setProperty("Workspace1", ws1));
@@ -759,7 +760,7 @@ public:
       checker.initialize();
 
     Mantid::API::MatrixWorkspace_sptr ws2 =
-        WorkspaceCreationHelper::Create2DWorkspace123(2, 2);
+        WorkspaceCreationHelper::create2DWorkspace123(2, 2);
     Mantid::Geometry::Instrument_sptr instrument(
         new Mantid::Geometry::Instrument("different"));
     ws2->setInstrument(instrument);
@@ -785,7 +786,7 @@ public:
       checker.initialize();
 
     Mantid::API::MatrixWorkspace_sptr ws2 =
-        WorkspaceCreationHelper::Create2DWorkspace123(2, 2);
+        WorkspaceCreationHelper::create2DWorkspace123(2, 2);
     ws2->instrumentParameters().addBool(new Mantid::Geometry::Component,
                                         "myParam", true);
 
@@ -811,7 +812,7 @@ public:
       checker.initialize();
 
     Mantid::API::MatrixWorkspace_sptr ws2 =
-        WorkspaceCreationHelper::Create2DWorkspace123(2, 2);
+        WorkspaceCreationHelper::create2DWorkspace123(2, 2);
     ws2->maskBin(0, 0);
     ws2->dataY(0)[0] = 2;
     ws2->dataE(0)[0] = 3;
@@ -828,7 +829,7 @@ public:
     TS_ASSERT_EQUALS(table->cell<std::string>(0, 0), "Masking mismatch");
 
     Mantid::API::MatrixWorkspace_sptr ws3 =
-        WorkspaceCreationHelper::Create2DWorkspace123(2, 2);
+        WorkspaceCreationHelper::create2DWorkspace123(2, 2);
     ws3->maskBin(0, 1);
     ws3->dataY(0)[1] = 2;
     ws3->dataE(0)[1] = 3;
@@ -853,7 +854,7 @@ public:
     checker.setProperty("CheckSample", true);
 
     Mantid::API::MatrixWorkspace_sptr ws2 =
-        WorkspaceCreationHelper::Create2DWorkspace123(2, 2);
+        WorkspaceCreationHelper::create2DWorkspace123(2, 2);
     ws2->mutableSample().setName("different");
 
     TS_ASSERT_THROWS_NOTHING(checker.setProperty("Workspace1", ws1));
@@ -874,7 +875,7 @@ public:
     checker.setProperty("CheckSample", true);
 
     Mantid::API::MatrixWorkspace_sptr ws2 =
-        WorkspaceCreationHelper::Create2DWorkspace123(2, 2);
+        WorkspaceCreationHelper::create2DWorkspace123(2, 2);
     ws2->mutableRun().setProtonCharge(99.99);
 
     TS_ASSERT_THROWS_NOTHING(checker.setProperty("Workspace1", ws1));
@@ -895,7 +896,7 @@ public:
     checker.setProperty("CheckSample", true);
 
     Mantid::API::MatrixWorkspace_sptr ws2 =
-        WorkspaceCreationHelper::Create2DWorkspace123(2, 2);
+        WorkspaceCreationHelper::create2DWorkspace123(2, 2);
     ws2->mutableRun().addLogData(
         new Mantid::Kernel::PropertyWithValue<int>("Prop1", 99));
 
@@ -912,7 +913,7 @@ public:
                      "Different numbers of logs");
 
     Mantid::API::MatrixWorkspace_sptr ws3 =
-        WorkspaceCreationHelper::Create2DWorkspace123(2, 2);
+        WorkspaceCreationHelper::create2DWorkspace123(2, 2);
     ws3->mutableRun().addLogData(
         new Mantid::Kernel::PropertyWithValue<int>("Prop2", 99));
 
@@ -927,7 +928,7 @@ public:
     TS_ASSERT_EQUALS(table->cell<std::string>(0, 0), "Log mismatch");
 
     Mantid::API::MatrixWorkspace_sptr ws4 =
-        WorkspaceCreationHelper::Create2DWorkspace123(2, 2);
+        WorkspaceCreationHelper::create2DWorkspace123(2, 2);
     ws4->mutableRun().addLogData(
         new Mantid::Kernel::PropertyWithValue<int>("Prop1", 100));
 
@@ -946,7 +947,7 @@ public:
     // Create a group
     const std::string groupName("TestGroup");
     WorkspaceGroup_sptr group =
-        WorkspaceCreationHelper::CreateWorkspaceGroup(2, 2, 2, groupName);
+        WorkspaceCreationHelper::createWorkspaceGroup(2, 2, 2, groupName);
 
     doGroupTest(groupName, groupName, PROPERTY_VALUE_TRUE);
 
@@ -957,10 +958,10 @@ public:
     // Create a group
     const std::string groupOneName("TestGroupOne");
     WorkspaceGroup_sptr groupOne =
-        WorkspaceCreationHelper::CreateWorkspaceGroup(2, 2, 2, groupOneName);
+        WorkspaceCreationHelper::createWorkspaceGroup(2, 2, 2, groupOneName);
     const std::string groupTwoName("TestGroupTwo");
     WorkspaceGroup_sptr groupTwo =
-        WorkspaceCreationHelper::CreateWorkspaceGroup(3, 2, 2, groupTwoName);
+        WorkspaceCreationHelper::createWorkspaceGroup(3, 2, 2, groupTwoName);
 
     doGroupTest(groupOneName, groupTwoName, "GroupWorkspaces size mismatch.",
                 std::map<std::string, std::string>(), true);
@@ -972,9 +973,9 @@ public:
   void test_Input_With_A_Group_And_A_Single_Workspace_Gives_Type_Mismatch() {
     const std::string groupName("CheckWorkspacesMatch_TestGroup");
     WorkspaceGroup_sptr group =
-        WorkspaceCreationHelper::CreateWorkspaceGroup(2, 2, 2, groupName);
+        WorkspaceCreationHelper::createWorkspaceGroup(2, 2, 2, groupName);
     Mantid::API::MatrixWorkspace_sptr ws2 =
-        WorkspaceCreationHelper::Create2DWorkspace123(2, 2);
+        WorkspaceCreationHelper::create2DWorkspace123(2, 2);
     const std::string wsName("CheckWorkspacesMatch_TestWS");
     Mantid::API::AnalysisDataService::Instance().add(wsName, ws2);
 
@@ -991,10 +992,10 @@ public:
     // Create a group
     const std::string groupOneName("TestGroupOne");
     WorkspaceGroup_sptr groupOne =
-        WorkspaceCreationHelper::CreateWorkspaceGroup(2, 2, 2, groupOneName);
+        WorkspaceCreationHelper::createWorkspaceGroup(2, 2, 2, groupOneName);
     const std::string groupTwoName("TestGroupTwo");
     WorkspaceGroup_sptr groupTwo =
-        WorkspaceCreationHelper::CreateWorkspaceGroup(2, 2, 2, groupTwoName);
+        WorkspaceCreationHelper::createWorkspaceGroup(2, 2, 2, groupTwoName);
     Mantid::API::AnalysisDataServiceImpl &dataStore =
         Mantid::API::AnalysisDataService::Instance();
     // Extract the zeroth element of groupTwo and add a spurious log
diff --git a/Framework/Algorithms/test/ConjoinWorkspacesTest.h b/Framework/Algorithms/test/ConjoinWorkspacesTest.h
index b4ad9f165c2c39bbb6cd30d3cd41531a44aa8b3b..d4f4a140aeaa1786d561259c60644151b7ae9609 100644
--- a/Framework/Algorithms/test/ConjoinWorkspacesTest.h
+++ b/Framework/Algorithms/test/ConjoinWorkspacesTest.h
@@ -5,6 +5,8 @@
 
 #include "MantidAlgorithms/ConjoinWorkspaces.h"
 #include "MantidAPI/Axis.h"
+#include "MantidAPI/SpectrumInfo.h"
+#include "MantidAPI/WorkspaceHistory.h"
 #include "MantidDataHandling/LoadRaw3.h"
 #include "MantidTestHelpers/WorkspaceCreationHelper.h"
 
@@ -73,8 +75,10 @@ public:
 
     // Mask a spectrum and check it is carried over
     const size_t maskTop(5), maskBottom(10);
-    in1->maskWorkspaceIndex(maskTop);
-    in2->maskWorkspaceIndex(maskBottom);
+    in1->getSpectrum(maskTop).clearData();
+    in2->getSpectrum(maskBottom).clearData();
+    in1->mutableSpectrumInfo().setMasked(maskTop, true);
+    in2->mutableSpectrumInfo().setMasked(maskBottom, true);
 
     // Check it fails if properties haven't been set
     TS_ASSERT_THROWS(conj.execute(), std::runtime_error);
@@ -111,8 +115,9 @@ public:
                      in2->getAxis(1)->spectraNo(2));
 
     // Check masking
-    TS_ASSERT_EQUALS(output->getDetector(maskTop)->isMasked(), true);
-    TS_ASSERT_EQUALS(output->getDetector(10 + maskBottom)->isMasked(), true);
+    const auto &spectrumInfo = output->spectrumInfo();
+    TS_ASSERT_EQUALS(spectrumInfo.isMasked(maskTop), true);
+    TS_ASSERT_EQUALS(spectrumInfo.isMasked(10 + maskBottom), true);
 
     // Check that 2nd input workspace no longer exists
     TS_ASSERT_THROWS(AnalysisDataService::Instance().retrieve("bottom"),
@@ -125,7 +130,7 @@ public:
   //----------------------------------------------------------------------------------------------
   void testExecMismatchedWorkspaces() {
     MatrixWorkspace_sptr ews =
-        WorkspaceCreationHelper::CreateEventWorkspace(10, 10);
+        WorkspaceCreationHelper::createEventWorkspace(10, 10);
 
     // Check it fails if input overlap
     ConjoinWorkspaces conj;
@@ -138,7 +143,7 @@ public:
     // Check it fails if mixing event workspaces and workspace 2Ds
     TS_ASSERT_THROWS_NOTHING(conj.setProperty("InputWorkspace1", ews));
     TS_ASSERT_THROWS_NOTHING(conj.setProperty(
-        "InputWorkspace2", WorkspaceCreationHelper::Create2DWorkspace(10, 10)));
+        "InputWorkspace2", WorkspaceCreationHelper::create2DWorkspace(10, 10)));
     conj.execute();
     TS_ASSERT(!conj.isExecuted());
   }
@@ -147,10 +152,10 @@ public:
     MatrixWorkspace_sptr ws1, ws2;
     int numPixels = 10;
     int numBins = 20;
-    ws1 = WorkspaceCreationHelper::CreateEventWorkspace(numPixels, numBins);
+    ws1 = WorkspaceCreationHelper::createEventWorkspace(numPixels, numBins);
     const std::string ws1_name = "ConjoinWorkspaces_testDoCheckForOverlap";
     AnalysisDataService::Instance().add(ws1_name, ws1);
-    ws2 = WorkspaceCreationHelper::CreateEventWorkspace(5, numBins);
+    ws2 = WorkspaceCreationHelper::createEventWorkspace(5, numBins);
 
     ConjoinWorkspaces conj;
     conj.initialize();
@@ -196,12 +201,12 @@ public:
     int numBins = 20;
 
     if (event) {
-      ws1 = WorkspaceCreationHelper::CreateEventWorkspace2(
+      ws1 = WorkspaceCreationHelper::createEventWorkspace2(
           10, numBins); // 2 events per bin
-      ws2 = WorkspaceCreationHelper::CreateEventWorkspace2(5, numBins);
+      ws2 = WorkspaceCreationHelper::createEventWorkspace2(5, numBins);
     } else {
-      ws1 = WorkspaceCreationHelper::Create2DWorkspace(10, numBins);
-      ws2 = WorkspaceCreationHelper::Create2DWorkspace(5, numBins);
+      ws1 = WorkspaceCreationHelper::create2DWorkspace(10, numBins);
+      ws2 = WorkspaceCreationHelper::create2DWorkspace(5, numBins);
     }
     AnalysisDataService::Instance().addOrReplace(ws1Name, ws1);
     AnalysisDataService::Instance().addOrReplace(ws2Name, ws2);
diff --git a/Framework/Algorithms/test/ConvertAxesToRealSpaceTest.h b/Framework/Algorithms/test/ConvertAxesToRealSpaceTest.h
index e33d5dbefd8e20299b2ffeb3c2b9c19f2b833e46..fa589f57c06a75e76b776d5db96aebede3a82009 100644
--- a/Framework/Algorithms/test/ConvertAxesToRealSpaceTest.h
+++ b/Framework/Algorithms/test/ConvertAxesToRealSpaceTest.h
@@ -7,6 +7,7 @@
 
 #include "MantidAlgorithms/ConvertAxesToRealSpace.h"
 #include "MantidAPI/Axis.h"
+#include "MantidKernel/Unit.h"
 
 using Mantid::Algorithms::ConvertAxesToRealSpace;
 using namespace Mantid::API;
@@ -103,4 +104,4 @@ public:
   }
 };
 
-#endif /* MANTID_ALGORITHMS_CONVERTAXESTOREALSPACETEST_H_ */
\ No newline at end of file
+#endif /* MANTID_ALGORITHMS_CONVERTAXESTOREALSPACETEST_H_ */
diff --git a/Framework/Algorithms/test/ConvertAxisByFormulaTest.h b/Framework/Algorithms/test/ConvertAxisByFormulaTest.h
index 479c8f6a49815d56ec6e2b9715a183d4aaf761d4..a25f5de619c632aa136b6393200037618f8d0a34 100644
--- a/Framework/Algorithms/test/ConvertAxisByFormulaTest.h
+++ b/Framework/Algorithms/test/ConvertAxisByFormulaTest.h
@@ -32,7 +32,7 @@ public:
     std::string resultWs = alg.name() + "_testPlusRefAxis_Result";
 
     AnalysisDataService::Instance().add(
-        inputWs, WorkspaceCreationHelper::Create2DWorkspace123(10, 10));
+        inputWs, WorkspaceCreationHelper::create2DWorkspace123(10, 10));
     TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("InputWorkspace", inputWs));
     TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("OutputWorkspace", resultWs));
     TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("Formula", "x+3"));
@@ -89,7 +89,7 @@ public:
     std::string resultWs = alg.name() + "_testSquareXNumeric_Result";
 
     AnalysisDataService::Instance().add(
-        inputWs, WorkspaceCreationHelper::Create2DWorkspace123(10, 10));
+        inputWs, WorkspaceCreationHelper::create2DWorkspace123(10, 10));
     TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("InputWorkspace", inputWs));
     TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("OutputWorkspace", resultWs));
     TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("Formula", "(X+2)*(x+2)"));
diff --git a/Framework/Algorithms/test/ConvertDiffCalTest.h b/Framework/Algorithms/test/ConvertDiffCalTest.h
index 9216fb96d27f36c37834573e152172ccf27e503b..1f90cf1c58bde101acc622429b58d85a19464481 100644
--- a/Framework/Algorithms/test/ConvertDiffCalTest.h
+++ b/Framework/Algorithms/test/ConvertDiffCalTest.h
@@ -3,6 +3,7 @@
 
 #include <cxxtest/TestSuite.h>
 
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/ITableWorkspace.h"
 #include "MantidAlgorithms/ConvertDiffCal.h"
 #include "MantidDataObjects/OffsetsWorkspace.h"
diff --git a/Framework/Algorithms/test/ConvertFromDistributionTest.h b/Framework/Algorithms/test/ConvertFromDistributionTest.h
index a9073b090f020ae4cff92a7938850e38c75d761a..2ac426811e2ecab03c43de36981d061a55a1cbfe 100644
--- a/Framework/Algorithms/test/ConvertFromDistributionTest.h
+++ b/Framework/Algorithms/test/ConvertFromDistributionTest.h
@@ -19,7 +19,7 @@ public:
 
   ConvertFromDistributionTest() : dist("dist") {
     MatrixWorkspace_sptr WS =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(1, 10, 0, 0.5);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(1, 10, 0, 0.5);
     WS->setDistribution(true);
     AnalysisDataService::Instance().add(dist, WS);
   }
diff --git a/Framework/Algorithms/test/ConvertSpectrumAxis2Test.h b/Framework/Algorithms/test/ConvertSpectrumAxis2Test.h
index 6c039474a51e4224b766f6db5d34329bba8ee07c..b928b67c8e18ffa0477d9e3e29705c27282feda9 100644
--- a/Framework/Algorithms/test/ConvertSpectrumAxis2Test.h
+++ b/Framework/Algorithms/test/ConvertSpectrumAxis2Test.h
@@ -8,6 +8,7 @@
 #include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Axis.h"
 #include "MantidDataHandling/LoadRaw3.h"
+#include "MantidKernel/Unit.h"
 #include "MantidKernel/UnitFactory.h"
 
 using namespace Mantid::API;
@@ -391,4 +392,33 @@ public:
   }
 };
 
+class ConvertSpectrumAxis2TestPerformance : public CxxTest::TestSuite {
+public:
+  static ConvertSpectrumAxis2TestPerformance *createSuite() {
+    return new ConvertSpectrumAxis2TestPerformance();
+  }
+  static void destroySuite(ConvertSpectrumAxis2TestPerformance *suite) {
+    delete suite;
+  }
+
+  ConvertSpectrumAxis2TestPerformance() {
+    m_testWS = WorkspaceCreationHelper::create2DWorkspaceWithFullInstrument(
+        20000, 20000);
+  }
+
+  void test_conversion_to_signed_theta_with_many_entries() {
+    Mantid::Algorithms::ConvertSpectrumAxis2 conv;
+    conv.initialize();
+    conv.setChild(true);
+    conv.setProperty("InputWorkspace", m_testWS);
+    conv.setPropertyValue("OutputWorkspace", "outputWS");
+    conv.setPropertyValue("Target", "SignedTheta");
+    conv.setPropertyValue("EFixed", "10.0");
+    conv.execute();
+  }
+
+private:
+  MatrixWorkspace_sptr m_testWS;
+};
+
 #endif /*CONVERTSPECTRUMAXIS2TEST_H_*/
diff --git a/Framework/Algorithms/test/ConvertSpectrumAxisTest.h b/Framework/Algorithms/test/ConvertSpectrumAxisTest.h
index fe5040c56b4bf012b15be59f85f3c6cd18574156..d117c0394f8a7c00c0c5a65c305dc9c381a269f5 100644
--- a/Framework/Algorithms/test/ConvertSpectrumAxisTest.h
+++ b/Framework/Algorithms/test/ConvertSpectrumAxisTest.h
@@ -5,6 +5,7 @@
 #include "MantidAPI/Axis.h"
 #include "MantidAlgorithms/ConvertSpectrumAxis.h"
 #include "MantidDataHandling/LoadRaw3.h"
+#include "MantidKernel/Unit.h"
 #include "MantidTestHelpers/WorkspaceCreationHelper.h"
 #include "MantidTestHelpers/HistogramDataTestHelper.h"
 #include <cxxtest/TestSuite.h>
diff --git a/Framework/Algorithms/test/ConvertTableToMatrixWorkspaceTest.h b/Framework/Algorithms/test/ConvertTableToMatrixWorkspaceTest.h
index 439af30c7ded2f70affc42c0756ce470d77a2768..788bf97cdf846ccfd28c3ff392a0bc2c73037aba 100644
--- a/Framework/Algorithms/test/ConvertTableToMatrixWorkspaceTest.h
+++ b/Framework/Algorithms/test/ConvertTableToMatrixWorkspaceTest.h
@@ -4,6 +4,7 @@
 #include <cxxtest/TestSuite.h>
 
 #include "MantidAlgorithms/ConvertTableToMatrixWorkspace.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Axis.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/ITableWorkspace.h"
diff --git a/Framework/Algorithms/test/ConvertToDistributionTest.h b/Framework/Algorithms/test/ConvertToDistributionTest.h
index 73aed2000b1c094bc46e2036c5f4e01c2600adcd..ee31b3754e632d643012bbaf91b82cc202053ed1 100644
--- a/Framework/Algorithms/test/ConvertToDistributionTest.h
+++ b/Framework/Algorithms/test/ConvertToDistributionTest.h
@@ -6,6 +6,7 @@
 
 #include "MantidAlgorithms/ConvertToDistribution.h"
 #include "MantidAPI/AnalysisDataService.h"
+#include "MantidAPI/WorkspaceGroup.h"
 
 using namespace Mantid::API;
 using Mantid::Algorithms::ConvertToDistribution;
@@ -84,7 +85,7 @@ public:
 
 private:
   Workspace_sptr createTestWorkspace() {
-    return WorkspaceCreationHelper::Create2DWorkspaceBinned(1, 10, 0, 0.5);
+    return WorkspaceCreationHelper::create2DWorkspaceBinned(1, 10, 0, 0.5);
   }
 };
 
diff --git a/Framework/Algorithms/test/ConvertToEventWorkspaceTest.h b/Framework/Algorithms/test/ConvertToEventWorkspaceTest.h
index 09c369422870f29c44c7a028593d2088b333ea86..b66c94b146a8ba565897713536e930efcc2f5846 100644
--- a/Framework/Algorithms/test/ConvertToEventWorkspaceTest.h
+++ b/Framework/Algorithms/test/ConvertToEventWorkspaceTest.h
@@ -160,7 +160,7 @@ public:
   /// Workspace with infinity or NAN = don't create events there.
   void test_with_nan_and_inf() {
     // Create the input
-    Workspace2D_sptr inWS = WorkspaceCreationHelper::Create2DWorkspace(1, 10);
+    Workspace2D_sptr inWS = WorkspaceCreationHelper::create2DWorkspace(1, 10);
 
     double nan = std::numeric_limits<double>::quiet_NaN();
     double inf = std::numeric_limits<double>::infinity();
@@ -211,7 +211,7 @@ public:
   /// Create events for zero-weight bins
   void test_GenerateZeros() {
     // Create the input
-    Workspace2D_sptr inWS = WorkspaceCreationHelper::Create2DWorkspace(1, 10);
+    Workspace2D_sptr inWS = WorkspaceCreationHelper::create2DWorkspace(1, 10);
 
     // Clear the vector
     inWS->dataY(0).assign(10, 0.0);
diff --git a/Framework/Algorithms/test/ConvertToHistogramTest.h b/Framework/Algorithms/test/ConvertToHistogramTest.h
index 8ad63562c082a91799abccc09f546a4be8237485..0af9416c715ef295b7019e352fe57a6c4103b763 100644
--- a/Framework/Algorithms/test/ConvertToHistogramTest.h
+++ b/Framework/Algorithms/test/ConvertToHistogramTest.h
@@ -29,7 +29,7 @@ public:
   test_That_Output_Is_The_Same_As_Input_If_Input_Contains_Histogram_Data() {
     // True indicates a non histogram workspace
     Workspace2D_sptr testWS =
-        WorkspaceCreationHelper::Create2DWorkspace123(5, 10, true);
+        WorkspaceCreationHelper::create2DWorkspace123(5, 10, true);
 
     MatrixWorkspace_sptr outputWS = runAlgorithm(testWS);
     TS_ASSERT(outputWS);
@@ -45,7 +45,7 @@ public:
     // Creates a workspace with 10 points
     const int numYPoints(10);
     const int numSpectra(2);
-    Workspace2D_sptr testWS = WorkspaceCreationHelper::Create2DWorkspace123(
+    Workspace2D_sptr testWS = WorkspaceCreationHelper::create2DWorkspace123(
         numSpectra, numYPoints, false);
     // Reset the X data to something reasonable
     Points x(numYPoints, LinearGenerator(0.0, 1.0));
@@ -137,7 +137,7 @@ public:
 
   void setUp() override {
     inputWS =
-        WorkspaceCreationHelper::Create2DWorkspace123(20000, 10000, false);
+        WorkspaceCreationHelper::create2DWorkspace123(20000, 10000, false);
   }
 
   void tearDown() override {
diff --git a/Framework/Algorithms/test/ConvertToMatrixWorkspaceTest.h b/Framework/Algorithms/test/ConvertToMatrixWorkspaceTest.h
index d1f53b5ca7c0e1590f28b9f514bcee87bf900c10..4f260a314ee203b3c7e68023fffeab00616aa912 100644
--- a/Framework/Algorithms/test/ConvertToMatrixWorkspaceTest.h
+++ b/Framework/Algorithms/test/ConvertToMatrixWorkspaceTest.h
@@ -39,7 +39,7 @@ public:
     cloner.initialize();
     // create 2D input workspace
     Mantid::API::MatrixWorkspace_sptr in =
-        WorkspaceCreationHelper::Create2DWorkspace(5, 10);
+        WorkspaceCreationHelper::create2DWorkspace(5, 10);
     // add instance to variable 'in'
 
     Mantid::API::MatrixWorkspace_sptr out;
diff --git a/Framework/Algorithms/test/ConvertToPointDataTest.h b/Framework/Algorithms/test/ConvertToPointDataTest.h
index 574e30b846e9c14524beb68e35b8e6241c913c6d..287621e1ecb944169405ce0425df9be9f515d458 100644
--- a/Framework/Algorithms/test/ConvertToPointDataTest.h
+++ b/Framework/Algorithms/test/ConvertToPointDataTest.h
@@ -6,6 +6,7 @@
 
 #include "MantidTestHelpers/WorkspaceCreationHelper.h"
 #include "MantidAPI/NumericAxis.h"
+#include "MantidKernel/Unit.h"
 #include "MantidKernel/UnitFactory.h"
 using Mantid::Algorithms::ConvertToPointData;
 using Mantid::API::IAlgorithm_sptr;
@@ -25,7 +26,7 @@ public:
   void test_That_Output_Is_The_Same_As_Input_If_Input_Contains_Point_Data() {
     // False indicates a non histogram workspace
     Workspace2D_sptr testWS =
-        WorkspaceCreationHelper::Create2DWorkspace123(5, 10, false);
+        WorkspaceCreationHelper::create2DWorkspace123(5, 10, false);
 
     MatrixWorkspace_sptr outputWS = runAlgorithm(testWS);
     TS_ASSERT(outputWS);
@@ -44,7 +45,7 @@ public:
     const int numBins(10);
     const int numSpectra(2);
     Workspace2D_sptr testWS =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(numSpectra, numBins);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(numSpectra, numBins);
     TS_ASSERT_EQUALS(testWS->isHistogramData(), true);
     // add a new vertical axis
     Mantid::API::Axis *const verticalAxis =
@@ -102,7 +103,7 @@ public:
     double xBoundaries[11] = {0.0,  1.0,  3.0,  5.0,  6.0, 7.0,
                               10.0, 13.0, 16.0, 17.0, 17.5};
     const int numSpectra(2);
-    Workspace2D_sptr testWS = WorkspaceCreationHelper::Create2DWorkspaceBinned(
+    Workspace2D_sptr testWS = WorkspaceCreationHelper::create2DWorkspaceBinned(
         numSpectra, 11, xBoundaries);
     const size_t numBins = testWS->blocksize();
     TS_ASSERT_EQUALS(testWS->isHistogramData(), true);
@@ -172,7 +173,7 @@ public:
   }
 
   void setUp() override {
-    inputWS = WorkspaceCreationHelper::Create2DWorkspaceBinned(20000, 10000);
+    inputWS = WorkspaceCreationHelper::create2DWorkspaceBinned(20000, 10000);
   }
 
   void tearDown() override {
diff --git a/Framework/Algorithms/test/ConvertUnitsTest.h b/Framework/Algorithms/test/ConvertUnitsTest.h
index 4deba8f33b5b3deef9a73a4f86458d4fa2ec2df0..ccf1b3244657ac8bbc8d5df06d48708aad6822ec 100644
--- a/Framework/Algorithms/test/ConvertUnitsTest.h
+++ b/Framework/Algorithms/test/ConvertUnitsTest.h
@@ -11,11 +11,11 @@
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidAlgorithms/ConvertToDistribution.h"
 #include "MantidAlgorithms/ConvertUnits.h"
-#include "MantidDataHandling/LoadEventPreNexus.h"
 #include "MantidDataHandling/LoadInstrument.h"
 #include "MantidDataObjects/EventWorkspace.h"
 #include "MantidDataObjects/Workspace2D.h"
 #include "MantidGeometry/Instrument.h"
+#include "MantidGeometry/Objects/Object.h"
 #include "MantidKernel/UnitFactory.h"
 
 using namespace Mantid::Kernel;
@@ -411,7 +411,7 @@ public:
 
   void testConvertQuicklyCommonBins() {
     Workspace2D_sptr input =
-        WorkspaceCreationHelper::Create2DWorkspace123(3, 10, 1);
+        WorkspaceCreationHelper::create2DWorkspace123(3, 10, 1);
     input->getAxis(0)->unit() =
         UnitFactory::Instance().create("MomentumTransfer");
     AnalysisDataService::Instance().add("quickIn", input);
@@ -455,7 +455,7 @@ public:
     // the scaling of Y and E for the distribution case is not testable.
     double deltax = 0.123;
     Workspace2D_sptr input =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(2, 10, x0, deltax);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(2, 10, x0, deltax);
     input->getAxis(0)->unit() =
         UnitFactory::Instance().create("MomentumTransfer");
     // Y must have units, otherwise ConvertUnits does not treat data as
@@ -527,11 +527,10 @@ public:
 
   void testDeltaE() {
     MatrixWorkspace_sptr ws =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(1, 2663, 5, 7.5);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(1, 2663, 5, 7.5);
     ws->getAxis(0)->unit() = UnitFactory::Instance().create("TOF");
 
     Instrument_sptr testInst(new Instrument);
-    ws->setInstrument(testInst);
     // Make it look like MARI (though not bin boundaries are different to the
     // real MARI file used before)
     // Define a source and sample position
@@ -551,6 +550,7 @@ public:
     physicalPixel->setPos(-0.34732, -3.28797, -2.29022);
     testInst->add(physicalPixel);
     testInst->markAsDetector(physicalPixel);
+    ws->setInstrument(testInst);
     ws->getSpectrum(0).addDetectorID(physicalPixel->getID());
 
     ConvertUnits conv;
diff --git a/Framework/Algorithms/test/CopyDetectorMappingTest.h b/Framework/Algorithms/test/CopyDetectorMappingTest.h
index 20885801e0533a956f77900edefd7e21e1f5bc24..82c3f73f6cdd911730698616440ddd67c485e766 100644
--- a/Framework/Algorithms/test/CopyDetectorMappingTest.h
+++ b/Framework/Algorithms/test/CopyDetectorMappingTest.h
@@ -22,7 +22,7 @@ public:
     Mantid::Algorithms::CopyDetectorMapping copyMapping;
     TS_ASSERT_THROWS_NOTHING(copyMapping.initialize())
 
-    auto toMatch = WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+    auto toMatch = WorkspaceCreationHelper::create2DWorkspace(10, 10);
 
     // Set the detector map for a spectra in the to match workspace
     std::set<detid_t> detIDs;
@@ -35,7 +35,7 @@ public:
     // Add workspaces to ADS
     AnalysisDataService::Instance().add("to_match", toMatch);
     AnalysisDataService::Instance().add(
-        "to_remap", WorkspaceCreationHelper::Create2DWorkspace(10, 10));
+        "to_remap", WorkspaceCreationHelper::create2DWorkspace(10, 10));
 
     // Run algorithm
     TS_ASSERT_THROWS_NOTHING(
@@ -66,9 +66,9 @@ public:
 
     // Add workspaces to ADS
     AnalysisDataService::Instance().add(
-        "to_match", WorkspaceCreationHelper::Create2DWorkspace(10, 10));
+        "to_match", WorkspaceCreationHelper::create2DWorkspace(10, 10));
     AnalysisDataService::Instance().add(
-        "to_remap", WorkspaceCreationHelper::Create2DWorkspace(20, 10));
+        "to_remap", WorkspaceCreationHelper::create2DWorkspace(20, 10));
 
     // Run algorithm
     TS_ASSERT_THROWS_NOTHING(
diff --git a/Framework/Algorithms/test/CopyInstrumentParametersTest.h b/Framework/Algorithms/test/CopyInstrumentParametersTest.h
index 3f6c6b2909893c27708153f5a463d51219bdc6cf..924d7ec4171a8cdb4deaa934499336a8c4ce5d69 100644
--- a/Framework/Algorithms/test/CopyInstrumentParametersTest.h
+++ b/Framework/Algorithms/test/CopyInstrumentParametersTest.h
@@ -8,7 +8,9 @@
 #include "MantidAlgorithms/CopyInstrumentParameters.h"
 #include "MantidAPI/Workspace.h"
 #include "MantidDataObjects/Workspace2D.h"
+#include "MantidAPI/DetectorInfo.h"
 #include "MantidAPI/MatrixWorkspace.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "WorkspaceCreationHelperTest.h"
 #include "MantidAPI/AnalysisDataService.h"
@@ -64,21 +66,19 @@ public:
     // Get instrument of input workspace and move some detectors
     Geometry::ParameterMap *pmap;
     pmap = &(ws1->instrumentParameters());
+    auto &detectorInfoWs1 = ws1->mutableDetectorInfo();
     Geometry::Instrument_const_sptr instrument = ws1->getInstrument();
-    IComponent_const_sptr det1 = instrument->getDetector(1);
-    Geometry::ComponentHelper::moveComponent(*det1, *pmap, V3D(6.0, 0.0, 0.7),
-                                             Absolute);
-    IComponent_const_sptr det2 = instrument->getDetector(2);
-    Geometry::ComponentHelper::moveComponent(*det2, *pmap, V3D(6.0, 0.1, 0.7),
-                                             Absolute);
+    detectorInfoWs1.setPosition(0, V3D(6.0, 0.0, 0.7));
+    detectorInfoWs1.setPosition(1, V3D(6.0, 0.1, 0.7));
+
     // add auxiliary instrument parameters
     pmap->addDouble(instrument.get(), "Ei", 100);
     pmap->addString(instrument.get(), "some_param", "some_value");
 
     // Verify that a detector moved in the input workspace has not yet been
     // moved in the output workspace
-    IDetector_const_sptr deto = ws2->getDetector(0);
-    V3D newPos = deto->getPos();
+    const auto &spectrumInfoWs2 = ws2->spectrumInfo();
+    V3D newPos = spectrumInfoWs2.position(0);
     TS_ASSERT_DELTA(newPos.Z(), 5.0, 0.0001);
 
     // Execute Algorithm
@@ -88,16 +88,15 @@ public:
 
     // Verify that the detectors in the output workspace have been moved as in
     // the input workspace before execution
-    IDetector_const_sptr deto1 = ws2->getDetector(0);
-    int id1 = deto1->getID();
-    V3D newPos1 = deto1->getPos();
+    const auto &spectrumInfoWs2New = ws2->spectrumInfo();
+    int id1 = spectrumInfoWs2New.detector(0).getID();
+    V3D newPos1 = spectrumInfoWs2New.position(0);
     TS_ASSERT_EQUALS(id1, 1);
     TS_ASSERT_DELTA(newPos1.X(), 6.0, 0.0001);
     TS_ASSERT_DELTA(newPos1.Y(), 0.0, 0.0001);
     TS_ASSERT_DELTA(newPos1.Z(), 0.7, 0.0001);
-    IDetector_const_sptr deto2 = ws2->getDetector(1);
-    int id2 = deto2->getID();
-    V3D newPos2 = deto2->getPos();
+    int id2 = spectrumInfoWs2New.detector(1).getID();
+    V3D newPos2 = spectrumInfoWs2New.position(1);
     TS_ASSERT_EQUALS(id2, 2);
     TS_ASSERT_DELTA(newPos2.X(), 6.0, 0.0001);
     TS_ASSERT_DELTA(newPos2.Y(), 0.1, 0.0001);
@@ -128,12 +127,9 @@ public:
     // add auxiliary instrument parameters
     pmap->addDouble(instrument.get(), "Ei", 100);
     pmap->addString(instrument.get(), "some_param", "some_value");
-    IComponent_const_sptr det1 = instrument->getDetector(1);
-    Geometry::ComponentHelper::moveComponent(*det1, *pmap, V3D(6.0, 0.0, 0.7),
-                                             Absolute);
-    IComponent_const_sptr det4 = instrument->getDetector(4);
-    Geometry::ComponentHelper::moveComponent(*det4, *pmap, V3D(6.0, 0.1, 0.7),
-                                             Absolute);
+    auto &detectorInfoWs1 = ws1->mutableDetectorInfo();
+    detectorInfoWs1.setPosition(0, V3D(6.0, 0.0, 0.7));
+    detectorInfoWs1.setPosition(3, V3D(6.0, 0.1, 0.7));
 
     // Create output workspace with another parameterized instrument and put
     // into data store
@@ -144,12 +140,11 @@ public:
     dataStore.add(wsName2, ws2);
 
     pmap = &(ws2->instrumentParameters());
+    auto &detectorInfoWs2 = ws2->mutableDetectorInfo();
     instrument = ws2->getInstrument();
     pmap->addDouble(instrument.get(), "T", 10);
     pmap->addString(instrument.get(), "some_param", "other_value");
-    IComponent_const_sptr det2 = instrument->getDetector(2);
-    Geometry::ComponentHelper::moveComponent(*det2, *pmap, V3D(6.0, 0.2, 0.7),
-                                             Absolute);
+    detectorInfoWs2.setPosition(1, V3D(6.0, 0.2, 0.7));
 
     // Set properties
     TS_ASSERT_THROWS_NOTHING(
@@ -173,19 +168,21 @@ public:
     TS_ASSERT_EQUALS(100, (instr2->getNumberParameter("Ei"))[0]);
     // TS_ASSERT_EQUALS(10,(instr2->getNumberParameter("T"))[0]);
 
+    const auto &spectrumInfoWs2New = ws2->spectrumInfo();
+
     // new detector allocation applied
-    IDetector_const_sptr deto1 = ws2->getDetector(0);
-    int id1 = deto1->getID();
-    V3D newPos1 = deto1->getPos();
+    const auto &deto1 = spectrumInfoWs2New.detector(0);
+    int id1 = deto1.getID();
+    V3D newPos1 = deto1.getPos();
     TS_ASSERT_EQUALS(id1, 1);
     TS_ASSERT_DELTA(newPos1.X(), 6.0, 0.0001);
     TS_ASSERT_DELTA(newPos1.Y(), 0.0, 0.0001);
     TS_ASSERT_DELTA(newPos1.Z(), 0.7, 0.0001);
 
     // previous detector placement rejected
-    IDetector_const_sptr deto2 = ws2->getDetector(1);
-    int id2 = deto2->getID();
-    V3D newPos2 = deto2->getPos();
+    const auto &deto2 = spectrumInfoWs2New.detector(1);
+    int id2 = deto2.getID();
+    V3D newPos2 = deto2.getPos();
     TS_ASSERT_EQUALS(id2, 2);
     TS_ASSERT_DELTA(newPos2.X(), 0.0, 0.0001);
     TS_ASSERT_DELTA(newPos2.Y(), 0.0, 0.0001);
@@ -233,12 +230,11 @@ public:
                       static_cast<double>(i * 10));
     }
     // calibrate detectors;
+    auto &detectorInfo = ws1->mutableDetectorInfo();
     for (size_t i = 0; i < n_detectors; i++) {
-      IComponent_const_sptr det =
-          instrument->getDetector(static_cast<Mantid::detid_t>(i + 1));
-      Geometry::ComponentHelper::moveComponent(
-          *det, *pmap,
-          V3D(sin(M_PI * double(i)), cos(M_PI * double(i / 500)), 7), Absolute);
+      auto detIndex = detectorInfo.indexOf(static_cast<Mantid::detid_t>(i + 1));
+      detectorInfo.setPosition(
+          detIndex, V3D(sin(M_PI * double(i)), cos(M_PI * double(i / 500)), 7));
     }
 
     // Create output workspace with another parameterized instrument and put
@@ -289,10 +285,10 @@ public:
 
     // new detector allocation applied
     size_t nDetectors = ws2->getNumberHistograms();
+    const auto &spectrumInfo = ws2->spectrumInfo();
     for (size_t i = 0; i < nDetectors; i++) {
-      IDetector_const_sptr deto1 = ws2->getDetector(i);
-      int id = deto1->getID();
-      V3D newPos1 = deto1->getPos();
+      int id = spectrumInfo.detector(i).getID();
+      V3D newPos1 = spectrumInfo.position(i);
       TS_ASSERT_EQUALS(id, i + 1);
       TS_ASSERT_DELTA(newPos1.X(), sin(M_PI * double(i)), 0.0001);
       TS_ASSERT_DELTA(newPos1.Y(), cos(M_PI * double(i / 500)), 0.0001);
diff --git a/Framework/Algorithms/test/CopyLogsTest.h b/Framework/Algorithms/test/CopyLogsTest.h
index 609448ba99406e44336da1e1d00698752049fd68..a182ab0a032de87d0c722c7546d9b9e05c4227ca 100644
--- a/Framework/Algorithms/test/CopyLogsTest.h
+++ b/Framework/Algorithms/test/CopyLogsTest.h
@@ -26,9 +26,9 @@ public:
 
   void test_exec() {
     MatrixWorkspace_sptr inputWs =
-        WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+        WorkspaceCreationHelper::create2DWorkspace(10, 10);
     MatrixWorkspace_sptr outputWs =
-        WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+        WorkspaceCreationHelper::create2DWorkspace(10, 10);
 
     WorkspaceCreationHelper::storeWS("alpha", outputWs);
 
@@ -37,14 +37,14 @@ public:
 
     runAlg(inputWs, outputWs, mode);
 
-    WorkspaceCreationHelper::removeWS(outputWs->name());
+    WorkspaceCreationHelper::removeWS(outputWs->getName());
   }
 
   void test_mergeReplaceExisting() {
     MatrixWorkspace_sptr inputWs =
-        WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+        WorkspaceCreationHelper::create2DWorkspace(10, 10);
     MatrixWorkspace_sptr outputWs =
-        WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+        WorkspaceCreationHelper::create2DWorkspace(10, 10);
 
     WorkspaceCreationHelper::storeWS("alpha", outputWs);
 
@@ -67,14 +67,14 @@ public:
     TS_ASSERT_EQUALS(run.getLogData("B")->value(), "World");
     TS_ASSERT_EQUALS(run.getLogData("C")->value(), "1");
 
-    WorkspaceCreationHelper::removeWS(outputWs->name());
+    WorkspaceCreationHelper::removeWS(outputWs->getName());
   }
 
   void test_mergeKeepExisting() {
     MatrixWorkspace_sptr inputWs =
-        WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+        WorkspaceCreationHelper::create2DWorkspace(10, 10);
     MatrixWorkspace_sptr outputWs =
-        WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+        WorkspaceCreationHelper::create2DWorkspace(10, 10);
 
     WorkspaceCreationHelper::storeWS("alpha", outputWs);
 
@@ -97,14 +97,14 @@ public:
     TS_ASSERT_EQUALS(run.getLogData("B")->value(), "Universe");
     TS_ASSERT_EQUALS(run.getLogData("C")->value(), "1");
 
-    WorkspaceCreationHelper::removeWS(outputWs->name());
+    WorkspaceCreationHelper::removeWS(outputWs->getName());
   }
 
   void test_wipeExisting() {
     MatrixWorkspace_sptr inputWs =
-        WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+        WorkspaceCreationHelper::create2DWorkspace(10, 10);
     MatrixWorkspace_sptr outputWs =
-        WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+        WorkspaceCreationHelper::create2DWorkspace(10, 10);
 
     WorkspaceCreationHelper::storeWS("alpha", outputWs);
 
@@ -127,7 +127,7 @@ public:
     TS_ASSERT_EQUALS(run.getLogData("B")->value(), "World");
     TS_ASSERT_THROWS_ANYTHING(run.getLogData("C"));
 
-    WorkspaceCreationHelper::removeWS(outputWs->name());
+    WorkspaceCreationHelper::removeWS(outputWs->getName());
   }
 
   // Run the Copy Logs algorithm
diff --git a/Framework/Algorithms/test/CopySampleTest.h b/Framework/Algorithms/test/CopySampleTest.h
index 52bd203a20433efcb6a48d1323a812ad536d841e..ed4aad9bd5cd43e0323e0c3c3bde69fa2e0cfc6d 100644
--- a/Framework/Algorithms/test/CopySampleTest.h
+++ b/Framework/Algorithms/test/CopySampleTest.h
@@ -7,6 +7,7 @@
 #include "MantidDataObjects/WorkspaceSingleValue.h"
 #include "MantidKernel/Material.h"
 #include "MantidKernel/NeutronAtom.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Sample.h"
 #include "MantidGeometry/Crystal/OrientedLattice.h"
 #include "MantidGeometry/Objects/ShapeFactory.h"
diff --git a/Framework/Algorithms/test/CorelliCrossCorrelateTest.h b/Framework/Algorithms/test/CorelliCrossCorrelateTest.h
index 99c1705d69bb69bc787dfce95b76465d35983dc0..db417481bdfcddaf7fbf11a03dee6f66f577518d 100644
--- a/Framework/Algorithms/test/CorelliCrossCorrelateTest.h
+++ b/Framework/Algorithms/test/CorelliCrossCorrelateTest.h
@@ -4,6 +4,7 @@
 #include <cxxtest/TestSuite.h>
 
 #include "MantidAlgorithms/CorelliCrossCorrelate.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Axis.h"
 #include "MantidAPI/Run.h"
 #include "MantidKernel/DateAndTime.h"
diff --git a/Framework/Algorithms/test/CorrectKiKfTest.h b/Framework/Algorithms/test/CorrectKiKfTest.h
index d0c27f7c821a9c682a63e274647e42bdf24551fe..672376272f87c1d09bcebe66a4952840dce411e1 100644
--- a/Framework/Algorithms/test/CorrectKiKfTest.h
+++ b/Framework/Algorithms/test/CorrectKiKfTest.h
@@ -273,7 +273,6 @@ private:
       ws2D->setSharedX(i, cow_xv);
       ws2D->mutableY(i) = {1, 2, 3, 4, 5};
       ws2D->mutableE(i) = {sqrt(1), sqrt(2), sqrt(3), sqrt(4), sqrt(5)};
-      ws2D->getSpectrum(i).setSpectrumNo(i);
     }
 
     AnalysisDataService::Instance().add(inputWSname, ws2D);
@@ -281,7 +280,7 @@ private:
 
   void createEventWorkspace() {
     EventWorkspace_sptr event =
-        WorkspaceCreationHelper::CreateEventWorkspace(1, 5, 5, 0, 0.9, 2, 0);
+        WorkspaceCreationHelper::createEventWorkspace(1, 5, 5, 0, 0.9, 2, 0);
     event->getAxis(0)->unit() = UnitFactory::Instance().create("DeltaE");
     AnalysisDataService::Instance().add(inputEvWSname, event);
   }
diff --git a/Framework/Algorithms/test/CorrectTOFAxisTest.h b/Framework/Algorithms/test/CorrectTOFAxisTest.h
new file mode 100644
index 0000000000000000000000000000000000000000..1988711ac22238d6a4bd030a6405aef70bea124e
--- /dev/null
+++ b/Framework/Algorithms/test/CorrectTOFAxisTest.h
@@ -0,0 +1,402 @@
+#ifndef MANTID_ALGORITHMS_CORRECTTOFAXISTEST_H_
+#define MANTID_ALGORITHMS_CORRECTTOFAXISTEST_H_
+
+#include <cxxtest/TestSuite.h>
+
+#include "MantidAlgorithms/CorrectTOFAxis.h"
+#include "MantidAPI/Axis.h"
+#include "MantidAPI/MatrixWorkspace.h"
+#include "MantidAPI/SpectrumInfo.h"
+#include "MantidDataHandling/LoadEmptyInstrument.h"
+#include "MantidKernel/PhysicalConstants.h"
+#include "MantidKernel/UnitFactory.h"
+#include "MantidTestHelpers/WorkspaceCreationHelper.h"
+
+using Mantid::Algorithms::CorrectTOFAxis;
+using namespace Mantid::API;
+using namespace WorkspaceCreationHelper;
+
+class CorrectTOFAxisTest : public CxxTest::TestSuite {
+public:
+  // This pair of boilerplate methods prevent the suite being created statically
+  // This means the constructor isn't called when running other tests
+  static CorrectTOFAxisTest *createSuite() { return new CorrectTOFAxisTest(); }
+  static void destroySuite(CorrectTOFAxisTest *suite) { delete suite; }
+
+  void test_CorrectionUsingReferenceWorkspace() {
+    const size_t blocksize = 16;
+    const double x0 = 23.66;
+    const double dx = 0.05;
+    const double TOF = x0 + dx * 3 * blocksize / 4;
+    auto inputWs = createInputWorkspace(blocksize, x0, dx, TOF);
+    const double referenceTOF = 1.06 * TOF;
+    const double length = flightLengthIN4(inputWs);
+    const double referenceEi = incidentEnergy(referenceTOF, length);
+    const double referenceWavelength = wavelength(referenceEi, length);
+    auto referenceWs = createInputWorkspace(blocksize, x0, dx, referenceTOF);
+    auto alg = createCorrectTOFAxisAlgorithm();
+    TS_ASSERT_THROWS_NOTHING(alg->setProperty("InputWorkspace", inputWs))
+    TS_ASSERT_THROWS_NOTHING(
+        alg->setPropertyValue("OutputWorkspace", "_unused_for_child"))
+    TS_ASSERT_THROWS_NOTHING(
+        alg->setProperty("ReferenceWorkspace", referenceWs));
+    TS_ASSERT_THROWS_NOTHING(alg->execute());
+    TS_ASSERT(alg->isExecuted());
+
+    MatrixWorkspace_sptr outputWs = alg->getProperty("OutputWorkspace");
+    TS_ASSERT(outputWs);
+    TS_ASSERT_EQUALS(outputWs->run().getPropertyAsSingleValue("EI"),
+                     referenceEi)
+    TS_ASSERT_EQUALS(outputWs->run().getPropertyAsSingleValue("wavelength"),
+                     referenceWavelength)
+    for (size_t i = 0; i < inputWs->getNumberHistograms(); ++i) {
+      for (size_t j = 0; j < blocksize; ++j) {
+        TS_ASSERT_DELTA(outputWs->x(i)[j], referenceWs->x(i)[j], 1e-6)
+        TS_ASSERT_EQUALS(outputWs->y(i)[j], inputWs->y(i)[j])
+        TS_ASSERT_EQUALS(outputWs->e(i)[j], inputWs->e(i)[j])
+      }
+      TS_ASSERT_DELTA(outputWs->x(i).back(), referenceWs->x(i).back(), 1e-6)
+    }
+  }
+
+  void test_CorrectionUsingEPPTable() {
+    const size_t blocksize = 512;
+    const double x0 = 1402;
+    const double dx = 0.23;
+    const size_t eppIndex = blocksize / 3;
+    const double eppTOF = x0 + static_cast<double>(eppIndex) * dx + dx / 2;
+    auto inputWs = createInputWorkspace(blocksize, x0, dx, eppTOF);
+    std::vector<EPPTableRow> eppRows(inputWs->getNumberHistograms());
+    for (auto &row : eppRows) {
+      row.peakCentre = eppTOF;
+    }
+    const double length = flightLengthIN4(inputWs);
+    const double nominalEi = incidentEnergy(eppTOF, length);
+    inputWs->mutableRun().addProperty("EI", nominalEi, true);
+    const double nominalWavelength = wavelength(nominalEi, length);
+    inputWs->mutableRun().addProperty("wavelength", nominalWavelength, true);
+    const double actualEi = 1.05 * nominalEi;
+    const double actualElasticTOF = tof(actualEi, length);
+    const double actualWavelength = wavelength(actualEi, length);
+    const double TOFShift = actualElasticTOF - eppTOF;
+    ITableWorkspace_sptr eppTable = createEPPTableWorkspace(eppRows);
+    auto alg = createCorrectTOFAxisAlgorithm();
+    TS_ASSERT_THROWS_NOTHING(alg->setProperty("InputWorkspace", inputWs))
+    TS_ASSERT_THROWS_NOTHING(
+        alg->setPropertyValue("OutputWorkspace", "_unused_for_child"))
+    TS_ASSERT_THROWS_NOTHING(alg->setProperty("EPPTable", eppTable));
+    TS_ASSERT_THROWS_NOTHING(
+        alg->setPropertyValue("IndexType", "Workspace Index"))
+    TS_ASSERT_THROWS_NOTHING(alg->setPropertyValue("ReferenceSpectra", "1-300"))
+    TS_ASSERT_THROWS_NOTHING(alg->setProperty("EFixed", actualEi))
+    TS_ASSERT_THROWS_NOTHING(alg->execute());
+    TS_ASSERT(alg->isExecuted());
+
+    MatrixWorkspace_sptr outputWs = alg->getProperty("OutputWorkspace");
+    assertTOFShift(outputWs, inputWs, actualEi, actualWavelength, TOFShift);
+  }
+
+  void test_CorrectionUsingElasticBinIndex() {
+    const size_t blocksize = 512;
+    const double x0 = 1402;
+    const double dx = 0.23;
+    const size_t eppIndex = blocksize / 3;
+    const double eppTOF = x0 + static_cast<double>(eppIndex) * dx + dx / 2;
+    auto inputWs = createInputWorkspace(blocksize, x0, dx, eppTOF);
+    const double length = flightLengthIN4(inputWs);
+    const double nominalEi = incidentEnergy(eppTOF, length);
+    inputWs->mutableRun().addProperty("EI", nominalEi, true);
+    const double nominalWavelength = wavelength(nominalEi, length);
+    inputWs->mutableRun().addProperty("wavelength", nominalWavelength, true);
+    const double actualEi = 1.05 * nominalEi;
+    const double actualElasticTOF = tof(actualEi, length);
+    const double actualWavelength = wavelength(actualEi, length);
+    const double TOFShift = actualElasticTOF - eppTOF;
+    auto alg = createCorrectTOFAxisAlgorithm();
+    TS_ASSERT_THROWS_NOTHING(alg->setProperty("InputWorkspace", inputWs))
+    TS_ASSERT_THROWS_NOTHING(
+        alg->setPropertyValue("OutputWorkspace", "_unused_for_child"))
+    TS_ASSERT_THROWS_NOTHING(
+        alg->setPropertyValue("IndexType", "Workspace Index"))
+    TS_ASSERT_THROWS_NOTHING(alg->setPropertyValue("ReferenceSpectra", "1-300"))
+    TS_ASSERT_THROWS_NOTHING(
+        alg->setProperty("ElasticBinIndex", static_cast<int>(eppIndex)))
+    TS_ASSERT_THROWS_NOTHING(alg->setProperty("EFixed", actualEi))
+    TS_ASSERT_THROWS_NOTHING(alg->execute());
+    TS_ASSERT(alg->isExecuted());
+
+    MatrixWorkspace_sptr outputWs = alg->getProperty("OutputWorkspace");
+    assertTOFShift(outputWs, inputWs, actualEi, actualWavelength, TOFShift);
+  }
+
+  void test_FailureIfNoInputPropertiesSet() {
+    auto alg = createCorrectTOFAxisAlgorithm();
+    TS_ASSERT_THROWS_ANYTHING(alg->execute());
+    TS_ASSERT(!alg->isExecuted());
+  }
+
+  void test_FailureIfOnlyInputAndOutputWorkspacesSet() {
+    const size_t blocksize = 128;
+    const double x0 = 1431;
+    const double dx = 0.33;
+    const double eppTOF = x0 + blocksize / 4 * dx + dx / 2;
+    auto inputWs = createInputWorkspace(blocksize, x0, dx, eppTOF);
+    auto alg = createCorrectTOFAxisAlgorithm();
+    TS_ASSERT_THROWS_NOTHING(alg->setProperty("InputWorkspace", inputWs))
+    TS_ASSERT_THROWS_NOTHING(
+        alg->setPropertyValue("OutputWorkspace", "_unused_for_child"))
+    TS_ASSERT_THROWS_ANYTHING(alg->execute());
+    TS_ASSERT(!alg->isExecuted());
+  }
+
+  void test_FailureIfReferenceWorkspaceIncompatible() {
+    const size_t blocksize = 16;
+    const double x0 = 23.66;
+    const double dx = 0.05;
+    const double TOF = x0 + blocksize * dx / 2;
+    auto inputWs = createInputWorkspace(blocksize, x0, dx, TOF);
+    auto referenceWs = createInputWorkspace(blocksize - 1, x0, dx, TOF);
+    auto alg = createCorrectTOFAxisAlgorithm();
+    TS_ASSERT_THROWS_NOTHING(alg->setProperty("InputWorkspace", inputWs))
+    TS_ASSERT_THROWS_NOTHING(
+        alg->setPropertyValue("OutputWorkspace", "_unused_for_child"))
+    TS_ASSERT_THROWS_NOTHING(
+        alg->setProperty("ReferenceWorkspace", referenceWs));
+    TS_ASSERT_THROWS_ANYTHING(alg->execute());
+    TS_ASSERT(!alg->isExecuted());
+  }
+
+  void test_FailureNoEiGivenAtAllWithElasticBinIndex() {
+    const size_t blocksize = 512;
+    const double x0 = 1390.1;
+    const double dx = 0.24;
+    const size_t elasticBin = blocksize / 3;
+    const double eppTOF = x0 + static_cast<double>(elasticBin) * dx + dx / 2;
+    auto inputWs = createInputWorkspace(blocksize, x0, dx, eppTOF);
+    inputWs->mutableRun().removeProperty("EI");
+    auto alg = createCorrectTOFAxisAlgorithm();
+    TS_ASSERT_THROWS_NOTHING(alg->setProperty("InputWorkspace", inputWs))
+    TS_ASSERT_THROWS_NOTHING(
+        alg->setPropertyValue("OutputWorkspace", "_unused_for_child"))
+    TS_ASSERT_THROWS_NOTHING(
+        alg->setPropertyValue("IndexType", "Workspace Index"))
+    TS_ASSERT_THROWS_NOTHING(alg->setPropertyValue("ReferenceSpectra", "1-300"))
+    TS_ASSERT_THROWS_NOTHING(
+        alg->setProperty("ElasticBinIndex", static_cast<int>(elasticBin)))
+    TS_ASSERT_THROWS_ANYTHING(alg->execute());
+    TS_ASSERT(!alg->isExecuted());
+  }
+
+  void test_FailureNoEiGivenAtAllWithEPPTable() {
+    const size_t blocksize = 512;
+    const double x0 = 1390.1;
+    const double dx = 0.24;
+    const double eppTOF = x0 + blocksize / 3 * dx + dx / 2;
+    auto inputWs = createInputWorkspace(blocksize, x0, dx, eppTOF);
+    inputWs->mutableRun().removeProperty("EI");
+    std::vector<EPPTableRow> eppRows(inputWs->getNumberHistograms());
+    for (auto &row : eppRows) {
+      row.peakCentre = eppTOF;
+    }
+    ITableWorkspace_sptr eppTable = createEPPTableWorkspace(eppRows);
+    auto alg = createCorrectTOFAxisAlgorithm();
+    TS_ASSERT_THROWS_NOTHING(alg->setProperty("InputWorkspace", inputWs))
+    TS_ASSERT_THROWS_NOTHING(
+        alg->setPropertyValue("OutputWorkspace", "_unused_for_child"))
+    TS_ASSERT_THROWS_NOTHING(alg->setProperty("EPPTable", eppTable));
+    TS_ASSERT_THROWS_NOTHING(
+        alg->setPropertyValue("IndexType", "Workspace Index"))
+    TS_ASSERT_THROWS_NOTHING(alg->setPropertyValue("ReferenceSpectra", "1-300"))
+    TS_ASSERT_THROWS_ANYTHING(alg->execute());
+    TS_ASSERT(!alg->isExecuted());
+  }
+
+  void test_Init() {
+    CorrectTOFAxis alg;
+    alg.setRethrows(true);
+    TS_ASSERT_THROWS_NOTHING(alg.initialize())
+    TS_ASSERT(alg.isInitialized())
+  }
+
+  void test_SampleLogsMissingInReferenceWorkspace() {
+    const size_t blocksize = 16;
+    const double x0 = 23.66;
+    const double dx = 0.05;
+    const double TOF = x0 + dx * 3 * blocksize / 4;
+    auto inputWs =
+        createInputWorkspaceWithoutSampleLogs(blocksize, x0, dx, TOF);
+    const double referenceTOF = 1.06 * TOF;
+    auto referenceWs = createInputWorkspace(blocksize, x0, dx, referenceTOF);
+    auto alg = createCorrectTOFAxisAlgorithm();
+    TS_ASSERT_THROWS_NOTHING(alg->setProperty("InputWorkspace", inputWs))
+    TS_ASSERT_THROWS_NOTHING(
+        alg->setPropertyValue("OutputWorkspace", "_unused_for_child"))
+    TS_ASSERT_THROWS_NOTHING(
+        alg->setProperty("ReferenceWorkspace", referenceWs));
+    TS_ASSERT_THROWS_NOTHING(alg->execute());
+    TS_ASSERT(alg->isExecuted());
+
+    MatrixWorkspace_sptr outputWs = alg->getProperty("OutputWorkspace");
+    TS_ASSERT(outputWs);
+    TS_ASSERT(!outputWs->run().hasProperty("Ei"))
+    TS_ASSERT(!outputWs->run().hasProperty("wavelength"))
+    for (size_t i = 0; i < inputWs->getNumberHistograms(); ++i) {
+      for (size_t j = 0; j < blocksize; ++j) {
+        TS_ASSERT_DELTA(outputWs->x(i)[j], referenceWs->x(i)[j], 1e-6)
+        TS_ASSERT_EQUALS(outputWs->y(i)[j], inputWs->y(i)[j])
+        TS_ASSERT_EQUALS(outputWs->e(i)[j], inputWs->e(i)[j])
+      }
+      TS_ASSERT_DELTA(outputWs->x(i).back(), referenceWs->x(i).back(), 1e-6)
+    }
+  }
+
+  void test_UseEiFromSampleLogs() {
+    const size_t blocksize = 512;
+    const double x0 = 1390.1;
+    const double dx = 0.24;
+    const double eppTOF = x0 + blocksize / 3 * dx + dx / 2;
+    auto inputWs = createInputWorkspace(blocksize, x0, dx, eppTOF);
+    const double length = flightLengthIN4(inputWs);
+    const double nominalEi = incidentEnergy(eppTOF, length);
+    const double actualEi = 0.93 * nominalEi;
+    inputWs->mutableRun().addProperty("EI", actualEi, true);
+    const double actualElasticTOF = tof(actualEi, length);
+    const double TOFShift = actualElasticTOF - eppTOF;
+    // In this case the algorithm doesn't update the wavelength in
+    // the samplelogs since also Ei will not be updated.
+    const double originalWavelength = wavelength(nominalEi, length);
+    std::vector<EPPTableRow> eppRows(inputWs->getNumberHistograms());
+    for (auto &row : eppRows) {
+      row.peakCentre = eppTOF;
+    }
+    ITableWorkspace_sptr eppTable = createEPPTableWorkspace(eppRows);
+    auto alg = createCorrectTOFAxisAlgorithm();
+    TS_ASSERT_THROWS_NOTHING(alg->setProperty("InputWorkspace", inputWs))
+    TS_ASSERT_THROWS_NOTHING(
+        alg->setPropertyValue("OutputWorkspace", "_unused_for_child"))
+    TS_ASSERT_THROWS_NOTHING(alg->setProperty("EPPTable", eppTable));
+    TS_ASSERT_THROWS_NOTHING(
+        alg->setPropertyValue("IndexType", "Workspace Index"))
+    TS_ASSERT_THROWS_NOTHING(alg->setPropertyValue("ReferenceSpectra", "1-300"))
+    TS_ASSERT_THROWS_NOTHING(alg->execute());
+    TS_ASSERT(alg->isExecuted());
+
+    MatrixWorkspace_sptr outputWs = alg->getProperty("OutputWorkspace");
+    assertTOFShift(outputWs, inputWs, actualEi, originalWavelength, TOFShift);
+  }
+
+private:
+  static void addSampleLogs(MatrixWorkspace_sptr ws, const double TOF) {
+    const double length = flightLengthIN4(ws);
+    const double Ei = incidentEnergy(TOF, length);
+    ws->mutableRun().addProperty("EI", Ei);
+    const double lambda = wavelength(Ei, length);
+    ws->mutableRun().addProperty("wavelength", lambda);
+  }
+
+  static void assertTOFShift(MatrixWorkspace_sptr shiftedWs,
+                             MatrixWorkspace_sptr ws, const double ei,
+                             const double wavelength, const double shift) {
+    TS_ASSERT(shiftedWs);
+    TS_ASSERT_EQUALS(shiftedWs->run().getPropertyAsSingleValue("EI"), ei);
+    TS_ASSERT_DELTA(shiftedWs->run().getPropertyAsSingleValue("wavelength"),
+                    wavelength, 1e-8)
+    for (size_t i = 0; i < ws->getNumberHistograms(); ++i) {
+      for (size_t j = 0; j < ws->blocksize(); ++j) {
+        TS_ASSERT_DELTA(shiftedWs->x(i)[j], ws->x(i)[j] + shift, 1e-6)
+        TS_ASSERT_EQUALS(shiftedWs->y(i)[j], ws->y(i)[j])
+        TS_ASSERT_EQUALS(shiftedWs->e(i)[j], ws->e(i)[j])
+      }
+      TS_ASSERT_DELTA(shiftedWs->x(i).back(), ws->x(i).back() + shift, 1e-6)
+    }
+  }
+
+  static std::unique_ptr<CorrectTOFAxis> createCorrectTOFAxisAlgorithm() {
+    std::unique_ptr<CorrectTOFAxis> alg(new CorrectTOFAxis);
+    alg->setChild(true);
+    alg->setRethrows(true);
+    TS_ASSERT_THROWS_NOTHING(alg->initialize())
+    TS_ASSERT(alg->isInitialized())
+    return alg;
+  }
+
+  static MatrixWorkspace_sptr
+  createEmptyIN4Workspace(const std::string &wsName) {
+    Mantid::DataHandling::LoadEmptyInstrument loadInstrument;
+    loadInstrument.setChild(true);
+    loadInstrument.initialize();
+    loadInstrument.setProperty("InstrumentName", "IN4");
+    loadInstrument.setProperty("OutputWorkspace", wsName);
+    loadInstrument.execute();
+    MatrixWorkspace_sptr ws = loadInstrument.getProperty("OutputWorkspace");
+    auto xAxis = ws->getAxis(0);
+    xAxis->unit() = Mantid::Kernel::UnitFactory::Instance().create("TOF");
+    return ws;
+  }
+
+  static MatrixWorkspace_sptr createInputWorkspace(const size_t blocksize,
+                                                   const double x0,
+                                                   const double dx,
+                                                   const double TOF) {
+    auto inputWs =
+        createInputWorkspaceWithoutSampleLogs(blocksize, x0, dx, TOF);
+    addSampleLogs(inputWs, TOF);
+    return inputWs;
+  }
+
+  static MatrixWorkspace_sptr
+  createInputWorkspaceWithoutSampleLogs(const size_t blocksize, const double x0,
+                                        const double dx, const double TOF) {
+    auto inputWs = createEmptyIN4Workspace("_input_ws");
+    const double sigma = 3 * dx;
+    auto gaussianPeak = [TOF, sigma](const double x) {
+      const double a = -(x - TOF) / sigma;
+      return std::exp(-a * a / 2);
+    };
+    fillWorkspace(inputWs, blocksize, x0, dx, gaussianPeak);
+    return inputWs;
+  }
+
+  template <typename Function>
+  static void fillWorkspace(MatrixWorkspace_sptr &ws, const size_t nBins,
+                            const double x0, const double dx, Function yFromX) {
+    ws = WorkspaceFactory::Instance().create(ws, ws->getNumberHistograms(),
+                                             nBins + 1, nBins);
+    for (size_t i = 0; i < ws->getNumberHistograms(); ++i) {
+      for (size_t j = 0; j < nBins; ++j) {
+        const double x = x0 + static_cast<double>(j) * dx;
+        ws->mutableX(i)[j] = x;
+        const double y = yFromX(x + dx / 2);
+        ws->mutableY(i)[j] = y;
+        ws->mutableE(i)[j] = std::sqrt(y);
+      }
+      ws->mutableX(i).back() = x0 + static_cast<double>(nBins) * dx;
+    }
+  }
+
+  static double flightLengthIN4(MatrixWorkspace_const_sptr ws) {
+    const double l1 = ws->spectrumInfo().l1();
+    const double l2 = ws->spectrumInfo().l2(1);
+    return l1 + l2;
+  }
+
+  static double incidentEnergy(const double TOF, const double flightLenght) {
+    const double velocity = flightLenght / (TOF * 1e-6);
+    return Mantid::PhysicalConstants::NeutronMass * velocity * velocity / 2 /
+           Mantid::PhysicalConstants::meV;
+  }
+
+  static double tof(const double Ei, const double flightLength) {
+    return flightLength / std::sqrt(2 * Ei * Mantid::PhysicalConstants::meV /
+                                    Mantid::PhysicalConstants::NeutronMass) /
+           1e-6;
+  }
+
+  static double wavelength(const double Ei, const double flightLength) {
+    const double velocity = flightLength / tof(Ei, flightLength);
+    return Mantid::PhysicalConstants::h / velocity /
+           Mantid::PhysicalConstants::NeutronMass * 1e4;
+  }
+};
+
+#endif /* MANTID_ALGORITHMS_CORRECTTOFAXISTEST_H_ */
diff --git a/Framework/Algorithms/test/CorrectToFileTest.h b/Framework/Algorithms/test/CorrectToFileTest.h
index 817a1d0ed49d45b16df1d2b9603023220e8226ce..c6e4d350de31e7932460bcb26fd3806a05bf56b1 100644
--- a/Framework/Algorithms/test/CorrectToFileTest.h
+++ b/Framework/Algorithms/test/CorrectToFileTest.h
@@ -36,7 +36,7 @@ public:
   void testExec2D() {
     // Need a workspace to correct
     MatrixWorkspace_sptr testInput =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(10, 102, 1.5);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(10, 102, 1.5);
     testInput->getAxis(0)->unit() =
         Mantid::Kernel::UnitFactory::Instance().create("Wavelength");
 
@@ -63,7 +63,7 @@ public:
   void testExecEvent() {
     // Need a workspace to correct
     MatrixWorkspace_sptr testInput =
-        WorkspaceCreationHelper::CreateEventWorkspace(10, 102, 100, 1.5);
+        WorkspaceCreationHelper::createEventWorkspace(10, 102, 100, 1.5);
     testInput->getAxis(0)->unit() =
         Mantid::Kernel::UnitFactory::Instance().create("Wavelength");
 
@@ -89,7 +89,7 @@ public:
 
   void testSpectraDivide() { // Need a workspace to correct
     MatrixWorkspace_sptr testInput =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(102, 32, 1.5);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(102, 32, 1.5);
 
     MatrixWorkspace_sptr data =
         executeAlgorithm(testInput, "SpectrumNumber", "Divide");
@@ -114,7 +114,7 @@ public:
 
   void testSpectraMultip() { // Need a workspace to correct
     MatrixWorkspace_sptr testInput =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(102, 32, 1.5);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(102, 32, 1.5);
 
     MatrixWorkspace_sptr data =
         executeAlgorithm(testInput, "SpectrumNumber", "Multiply", false);
diff --git a/Framework/Algorithms/test/CreateFlatEventWorkspaceTest.h b/Framework/Algorithms/test/CreateFlatEventWorkspaceTest.h
index 565a98e2761a5a45a0e5fe6fd4589b5139fe0406..985a3ab9317ca39d4830dfa087570ad101ad8183 100644
--- a/Framework/Algorithms/test/CreateFlatEventWorkspaceTest.h
+++ b/Framework/Algorithms/test/CreateFlatEventWorkspaceTest.h
@@ -4,8 +4,8 @@
 #include <cxxtest/TestSuite.h>
 
 #include "MantidAlgorithms/CreateFlatEventWorkspace.h"
-
 #include "MantidDataObjects/EventWorkspace.h"
+#include "MantidAPI/AnalysisDataService.h"
 
 using Mantid::Algorithms::CreateFlatEventWorkspace;
 
diff --git a/Framework/Algorithms/test/CreateGroupingWorkspaceTest.h b/Framework/Algorithms/test/CreateGroupingWorkspaceTest.h
index 4072e06dd8372e78b490fc451dc2da4e83e1207a..542ab62bb7a6763e2a99cd47025a8f93a44359de 100644
--- a/Framework/Algorithms/test/CreateGroupingWorkspaceTest.h
+++ b/Framework/Algorithms/test/CreateGroupingWorkspaceTest.h
@@ -5,6 +5,7 @@
 #include "MantidDataObjects/GroupingWorkspace.h"
 #include "MantidKernel/System.h"
 #include "MantidKernel/Timer.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/FrameworkManager.h"
 #include <cxxtest/TestSuite.h>
 
diff --git a/Framework/Algorithms/test/CreateLogPropertyTableTest.h b/Framework/Algorithms/test/CreateLogPropertyTableTest.h
index 64ffbef2e182ebf4216a8d705e1f92dd8ee886d2..2a631f790ac568e2b1b57d57b642b0421fb54718 100644
--- a/Framework/Algorithms/test/CreateLogPropertyTableTest.h
+++ b/Framework/Algorithms/test/CreateLogPropertyTableTest.h
@@ -109,7 +109,7 @@ private:
     using namespace WorkspaceCreationHelper;
 
     MatrixWorkspace_sptr eventws =
-        WorkspaceCreationHelper::Create2DWorkspace(1, 1);
+        WorkspaceCreationHelper::create2DWorkspace(1, 1);
 
     int64_t runstoptime_ns = runStart + 1000000;
     int64_t pulsetime_ns(100000);
diff --git a/Framework/Algorithms/test/CreateLogTimeCorrectionTest.h b/Framework/Algorithms/test/CreateLogTimeCorrectionTest.h
index af260e4fd845d407b70d510a8f008e67e6af947d..3ac2ac3ce28d3c37e2294452d40b7311ce3a830e 100644
--- a/Framework/Algorithms/test/CreateLogTimeCorrectionTest.h
+++ b/Framework/Algorithms/test/CreateLogTimeCorrectionTest.h
@@ -4,6 +4,7 @@
 #include <cxxtest/TestSuite.h>
 
 #include "MantidAlgorithms/CreateLogTimeCorrection.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/TableRow.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidDataHandling/LoadInstrument.h"
diff --git a/Framework/Algorithms/test/CreatePSDBleedMaskTest.h b/Framework/Algorithms/test/CreatePSDBleedMaskTest.h
index 3dee02ac06177765b52550d425eec49088594bf1..96ba1ee3f63fac40e77e7b1162691964737060a5 100644
--- a/Framework/Algorithms/test/CreatePSDBleedMaskTest.h
+++ b/Framework/Algorithms/test/CreatePSDBleedMaskTest.h
@@ -97,7 +97,7 @@ private:
     // YLength = nTubes * nPixelsPerTube
     const int nSpectra(nTubes * nPixelsPerTube);
     Workspace2D_sptr testWS =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(nSpectra, nBins);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(nSpectra, nBins);
     testWS->setInstrument(createTestInstrument(nTubes, nPixelsPerTube));
     // Set a spectra to have high count such that the fail the test
     const int failedTube(1);
diff --git a/Framework/Algorithms/test/CreateSampleWorkspaceTest.h b/Framework/Algorithms/test/CreateSampleWorkspaceTest.h
index ba9751051bd35c00d5064bdd8f37ea77ce2e31da..ea15dc7a27829e9e863f4fac7fbad5ecd97a3267 100644
--- a/Framework/Algorithms/test/CreateSampleWorkspaceTest.h
+++ b/Framework/Algorithms/test/CreateSampleWorkspaceTest.h
@@ -3,6 +3,7 @@
 
 #include <cxxtest/TestSuite.h>
 
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/FrameworkManager.h"
 #include "MantidGeometry/Instrument.h"
 #include "MantidGeometry/IComponent.h"
@@ -10,8 +11,10 @@
 #include "MantidGeometry/Instrument/RectangularDetector.h"
 #include "MantidAlgorithms/CreateSampleWorkspace.h"
 #include "MantidAPI/Axis.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidDataObjects/Workspace2D.h"
 #include "MantidDataObjects/EventWorkspace.h"
+#include "MantidKernel/Unit.h"
 
 using Mantid::Algorithms::CreateSampleWorkspace;
 using namespace Mantid::Kernel;
@@ -463,15 +466,15 @@ public:
     TS_ASSERT_THROWS_NOTHING(alg.execute());
     MatrixWorkspace_sptr outWS = alg.getProperty("OutputWorkspace");
 
-    TS_ASSERT(outWS->getDetector(0)->isMonitor());
+    TS_ASSERT(outWS->spectrumInfo().isMonitor(0));
     TS_ASSERT_DELTA(outWS->readY(0)[40], 0.3, 0.0001);
     TS_ASSERT_DELTA(outWS->readY(0)[50], 10.3, 0.0001);
 
-    TS_ASSERT(outWS->getDetector(1)->isMonitor());
+    TS_ASSERT(outWS->spectrumInfo().isMonitor(1));
     TS_ASSERT_DELTA(outWS->readY(1)[40], 0.3, 0.0001);
     TS_ASSERT_DELTA(outWS->readY(1)[50], 10.3, 0.0001);
 
-    TS_ASSERT(!outWS->getDetector(2)->isMonitor());
+    TS_ASSERT(!outWS->spectrumInfo().isMonitor(2));
     TS_ASSERT_DELTA(outWS->readY(2)[40], 0.3, 0.0001);
     TS_ASSERT_DELTA(outWS->readY(2)[50], 10.3, 0.0001);
 
@@ -494,15 +497,15 @@ public:
 
     TS_ASSERT_EQUALS(ews->getNumberEvents(), 191900);
 
-    TS_ASSERT(ews->getDetector(0)->isMonitor());
+    TS_ASSERT(ews->spectrumInfo().isMonitor(0));
     TS_ASSERT_DELTA(ews->readY(0)[50], 257, 0.0001);
     TS_ASSERT_DELTA(ews->readY(0)[60], 7, 0.0001);
 
-    TS_ASSERT(ews->getDetector(1)->isMonitor());
+    TS_ASSERT(ews->spectrumInfo().isMonitor(1));
     TS_ASSERT_DELTA(ews->readY(1)[50], 257, 0.0001);
     TS_ASSERT_DELTA(ews->readY(1)[60], 7, 0.0001);
 
-    TS_ASSERT(!ews->getDetector(2)->isMonitor());
+    TS_ASSERT(!ews->spectrumInfo().isMonitor(2));
     TS_ASSERT_DELTA(ews->readY(2)[50], 257, 0.0001);
     TS_ASSERT_DELTA(ews->readY(2)[60], 7, 0.0001);
 
diff --git a/Framework/Algorithms/test/CreateTransmissionWorkspaceAutoTest.h b/Framework/Algorithms/test/CreateTransmissionWorkspaceAutoTest.h
index 733ae98fc67d2aed9aca874a4f92d78961b441c8..b4dd34ca8db59bfdb48eaba635c39e9aee502f4e 100644
--- a/Framework/Algorithms/test/CreateTransmissionWorkspaceAutoTest.h
+++ b/Framework/Algorithms/test/CreateTransmissionWorkspaceAutoTest.h
@@ -2,10 +2,15 @@
 #define MANTID_ALGORITHMS_CREATETRANSMISSIONWORKSPACEAUTOTEST_H_
 
 #include <cxxtest/TestSuite.h>
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAlgorithms/CreateTransmissionWorkspaceAuto.h"
 #include "MantidAPI/FrameworkManager.h"
 #include "MantidAPI/AlgorithmManager.h"
+#include "MantidAPI/WorkspaceHistory.h"
+
+#include <boost/algorithm/string/classification.hpp>
+#include <boost/algorithm/string/split.hpp>
 #include <boost/lexical_cast.hpp>
 
 using Mantid::Algorithms::CreateTransmissionWorkspaceAuto;
diff --git a/Framework/Algorithms/test/CreateTransmissionWorkspaceTest.h b/Framework/Algorithms/test/CreateTransmissionWorkspaceTest.h
index 9f76c3eddf8537b61a7100f8b8c636c630a48588..6b1f814bc643e6b4f8f924c0db3d5e816a0f8a74 100644
--- a/Framework/Algorithms/test/CreateTransmissionWorkspaceTest.h
+++ b/Framework/Algorithms/test/CreateTransmissionWorkspaceTest.h
@@ -17,6 +17,7 @@
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidTestHelpers/WorkspaceCreationHelper.h"
 #include "MantidGeometry/Instrument/ReferenceFrame.h"
+#include "MantidKernel/Unit.h"
 
 using namespace Mantid;
 using namespace Mantid::Kernel;
diff --git a/Framework/Algorithms/test/CreateUserDefinedBackgroundTest.h b/Framework/Algorithms/test/CreateUserDefinedBackgroundTest.h
index 61cb415db20b6eff761b6c4641b9dd768640a9ca..1dfed0fb9df03a3e55463df7bc0c889c5460a61a 100644
--- a/Framework/Algorithms/test/CreateUserDefinedBackgroundTest.h
+++ b/Framework/Algorithms/test/CreateUserDefinedBackgroundTest.h
@@ -271,7 +271,7 @@ public:
 private:
   /// Create workspace containing test data
   MatrixWorkspace_sptr createTestData(bool isHisto) {
-    return WorkspaceCreationHelper::Create2DWorkspaceFromFunction(
+    return WorkspaceCreationHelper::create2DWorkspaceFromFunction(
         dataFunction, 1, 0.0, 10.0, 0.1, isHisto);
   }
 
@@ -374,4 +374,4 @@ private:
   const std::string m_key;
 };
 
-#endif /* MANTID_ALGORITHMS_CREATEUSERDEFINEDBACKGROUNDTEST_H_ */
\ No newline at end of file
+#endif /* MANTID_ALGORITHMS_CREATEUSERDEFINEDBACKGROUNDTEST_H_ */
diff --git a/Framework/Algorithms/test/CreateWorkspaceTest.h b/Framework/Algorithms/test/CreateWorkspaceTest.h
index cac8183e92f8b65b0b133ece9651ed861b1f4994..8a46393d9f5df348d61065acade6e8de42a8e1e0 100644
--- a/Framework/Algorithms/test/CreateWorkspaceTest.h
+++ b/Framework/Algorithms/test/CreateWorkspaceTest.h
@@ -126,8 +126,8 @@ public:
 
   void testParenting() {
     MatrixWorkspace_sptr parent =
-        WorkspaceCreationHelper::CreateEventWorkspace(1, 1, 1);
-    WorkspaceCreationHelper::AddTSPEntry(parent->mutableRun(), "ALogEntry",
+        WorkspaceCreationHelper::createEventWorkspace(1, 1, 1);
+    WorkspaceCreationHelper::addTSPEntry(parent->mutableRun(), "ALogEntry",
                                          99.0);
 
     Mantid::Algorithms::CreateWorkspace alg;
diff --git a/Framework/Algorithms/test/CropToComponentTest.h b/Framework/Algorithms/test/CropToComponentTest.h
index 79d93830b8be190705fc17d0b1097be1683c3c3f..12ef6a95fdb882160c61ba9aef6fddbe931c5596 100644
--- a/Framework/Algorithms/test/CropToComponentTest.h
+++ b/Framework/Algorithms/test/CropToComponentTest.h
@@ -131,7 +131,7 @@ public:
                       std::runtime_error)
   }
 
-  void test_that_det_ids_can_be_ordered() {
+  void test_that_det_ids_are_ordered() {
     // Arrange
     Mantid::DataHandling::LoadRaw3 loader;
     loader.initialize();
@@ -148,36 +148,24 @@ public:
     Mantid::Algorithms::CropToComponent crop;
     crop.setChild(true);
     crop.initialize();
-    crop.setProperty("InputWorkspace", workspace);
-    crop.setProperty("OutputWorkspace", "unordered");
-    crop.setProperty("ComponentNames", componentNames);
-    crop.setProperty("OrderByDetId", false);
-    crop.execute();
-    TS_ASSERT(crop.isExecuted())
-    Mantid::API::MatrixWorkspace_sptr unOrderedWorkspace =
-        crop.getProperty("OutputWorkspace");
-
+    crop.setRethrows(true);
     crop.setProperty("InputWorkspace", workspace);
     crop.setProperty("OutputWorkspace", "ordered");
     crop.setProperty("ComponentNames", componentNames);
-    crop.setProperty("OrderByDetId", true);
     crop.execute();
     TS_ASSERT(crop.isExecuted())
     Mantid::API::MatrixWorkspace_sptr orderedWorkspace =
         crop.getProperty("OutputWorkspace");
 
     // Assert
-    // Test the first theree spectrum numbers.
-    // The unordered workspace should show: 3, 131 259
+    // Test the first three spectrum numbers.
     // The ordered workspace should show: 3, 4, 5
+    // Without the implemneted ordering we would get 3, 131, 259
     std::array<size_t, 3> indices{{0, 1, 2}};
-    std::array<size_t, 3> expectedUnordered{{3, 131, 259}};
     std::array<size_t, 3> expectedOrdered{{3, 4, 5}};
 
     for (auto index : indices) {
-      const auto &specUnordered = unOrderedWorkspace->getSpectrum(index);
       const auto &specOrdered = orderedWorkspace->getSpectrum(index);
-      TS_ASSERT_EQUALS(specUnordered.getSpectrumNo(), expectedUnordered[index]);
       TS_ASSERT_EQUALS(specOrdered.getSpectrumNo(), expectedOrdered[index]);
     }
 
diff --git a/Framework/Algorithms/test/CropWorkspaceTest.h b/Framework/Algorithms/test/CropWorkspaceTest.h
index 83a43b361fecb9be6a78172d38d61d1eac654e1e..bc679ee1aafd583242cb700041d0a6fa8146b701 100644
--- a/Framework/Algorithms/test/CropWorkspaceTest.h
+++ b/Framework/Algorithms/test/CropWorkspaceTest.h
@@ -96,7 +96,7 @@ public:
   void makeFakeEventWorkspace(std::string wsName) {
     // Make an event workspace with 2 events in each bin.
     EventWorkspace_sptr test_in =
-        WorkspaceCreationHelper::CreateEventWorkspace(36, 50, 50, 0.0, 2., 2);
+        WorkspaceCreationHelper::createEventWorkspace(36, 50, 50, 0.0, 2., 2);
     // Fake a unit in the data.
     test_in->getAxis(0)->unit() = UnitFactory::Instance().create("TOF");
     test_in->setInstrument(
@@ -230,7 +230,7 @@ public:
 
   void testWithPointData() {
     AnalysisDataService::Instance().add(
-        "point", WorkspaceCreationHelper::Create2DWorkspace123(5, 5));
+        "point", WorkspaceCreationHelper::create2DWorkspace123(5, 5));
     CropWorkspace crop3;
     TS_ASSERT_THROWS_NOTHING(crop3.initialize());
     TS_ASSERT_THROWS_NOTHING(crop3.setPropertyValue("InputWorkspace", "point"));
@@ -310,7 +310,7 @@ public:
   void testRagged_events() {
     // Event workspace with 10 bins from 0 to 10
     EventWorkspace_sptr input =
-        WorkspaceCreationHelper::CreateEventWorkspace(5, 10, 10, 0.0, 1.0);
+        WorkspaceCreationHelper::createEventWorkspace(5, 10, 10, 0.0, 1.0);
     // Change the first X vector to 3, 4, 5 ..
     for (int k = 0; k <= 10; ++k) {
       input->dataX(0)[k] = k + 3;
@@ -348,7 +348,7 @@ public:
   void testNegativeBinBoundaries() {
     const std::string wsName("neg");
     AnalysisDataService::Instance().add(
-        wsName, WorkspaceCreationHelper::Create2DWorkspaceBinned(1, 5, -6));
+        wsName, WorkspaceCreationHelper::create2DWorkspaceBinned(1, 5, -6));
     CropWorkspace crop4;
     TS_ASSERT_THROWS_NOTHING(crop4.initialize());
     TS_ASSERT_THROWS_NOTHING(crop4.setPropertyValue("InputWorkspace", wsName));
@@ -380,7 +380,7 @@ public:
   // Public so it can be used within ExtractSingleSpectrum test
   static void doTestWithTextAxis(Algorithm *alg) {
     Workspace2D_sptr inputWS =
-        WorkspaceCreationHelper::Create2DWorkspace(3, 10);
+        WorkspaceCreationHelper::create2DWorkspace(3, 10);
     // Change the data so we know we've cropped the correct one
     const size_t croppedIndex(1);
     const double flagged(100.0);
@@ -437,7 +437,7 @@ public:
 
   void setUp() override {
     AnalysisDataService::Instance().add(
-        "ToCrop", WorkspaceCreationHelper::CreateEventWorkspace(
+        "ToCrop", WorkspaceCreationHelper::createEventWorkspace(
                       5000, 10000, 8000, 0.0, 1.0, 3));
   }
 
diff --git a/Framework/Algorithms/test/CrossCorrelateTest.h b/Framework/Algorithms/test/CrossCorrelateTest.h
new file mode 100644
index 0000000000000000000000000000000000000000..6f1ecee40acbb34374fbc730aecc1e3f9266541e
--- /dev/null
+++ b/Framework/Algorithms/test/CrossCorrelateTest.h
@@ -0,0 +1,179 @@
+#ifndef CROSSCORRELATETEST_H_
+#define CROSSCORRELATETEST_H_
+
+#include <cxxtest/TestSuite.h>
+
+#include "MantidHistogramData/LinearGenerator.h"
+#include "MantidAlgorithms/CrossCorrelate.h"
+#include "MantidTestHelpers/WorkspaceCreationHelper.h"
+
+using namespace Mantid;
+using namespace Mantid::Algorithms;
+using namespace Mantid::API;
+using namespace Mantid::DataObjects;
+using Mantid::HistogramData::BinEdges;
+using Mantid::HistogramData::CountStandardDeviations;
+
+class CrossCorrelateTest : public CxxTest::TestSuite {
+public:
+  // This pair of boilerplate methods prevent the suite being
+  // created statically This means the constructor isn't called when
+  // running other tests
+  static CrossCorrelateTest *createSuite() { return new CrossCorrelateTest(); }
+  static void destroySuite(CrossCorrelateTest *suite) { delete suite; }
+
+  void testValidInput() {
+    // setup and run the algorithm (includes basic checks)
+    CrossCorrelate alg;
+    const MatrixWorkspace_const_sptr inWS = setupAlgorithm(alg, 2.0, 4.0);
+    const MatrixWorkspace_const_sptr outWS = runAlgorithm(alg, inWS);
+
+    // specific checks
+    const MantidVec &outX = outWS->readX(0);
+    TS_ASSERT_EQUALS(outX.size(), 3);
+    TS_ASSERT_DELTA(outX[0], -1.0, 1e-6);
+    TS_ASSERT_DELTA(outX[1], 0.0, 1e-6);
+    TS_ASSERT_DELTA(outX[2], 1.0, 1e-6);
+
+    const MantidVec &outY0 = outWS->readY(0);
+    TS_ASSERT_EQUALS(outY0.size(), 3);
+    TS_ASSERT_DELTA(outY0[0], -0.018902, 1e-6);
+    TS_ASSERT_DELTA(outY0[1], 1.0, 1e-6);
+    TS_ASSERT_DELTA(outY0[2], -0.018902, 1e-6);
+
+    const MantidVec &outY1 = outWS->readY(1);
+    TS_ASSERT_EQUALS(outY1.size(), 3);
+    TS_ASSERT_DELTA(outY1[0], -0.681363, 1e-6);
+    TS_ASSERT_DELTA(outY1[1], 0.168384, 1e-6);
+    TS_ASSERT_DELTA(outY1[2], 0.456851, 1e-6);
+  }
+
+  // This tests an input X length of 3, which is the minimum the algorithm can
+  // handle
+  void testMinimumInputXLength() {
+    // setup and run the algorithm (includes basic checks)
+    CrossCorrelate alg;
+    const MatrixWorkspace_const_sptr inWS = setupAlgorithm(alg, 2.0, 3.5);
+    const MatrixWorkspace_const_sptr outWS = runAlgorithm(alg, inWS);
+
+    // specific checks
+    const MantidVec &outX = outWS->readX(0);
+    TS_ASSERT_EQUALS(outX.size(), 1);
+    TS_ASSERT_DELTA(outX[0], 0.0, 1e-6);
+
+    const MantidVec &outY0 = outWS->readY(0);
+    TS_ASSERT_EQUALS(outY0.size(), 1);
+    TS_ASSERT_DELTA(outY0[0], 1.0, 1e-6);
+
+    const MantidVec &outY1 = outWS->readY(1);
+    TS_ASSERT_EQUALS(outY1.size(), 1);
+    TS_ASSERT_DELTA(outY1[0], -1.0, 1e-6);
+  }
+
+  void testInputXLength2() {
+    // this throws because at least 3 X values are required
+    CrossCorrelate alg;
+    setupAlgorithm(alg, 2.0, 3.0);
+    runAlgorithmThrows(alg);
+  }
+
+  void testInputXLength1() {
+    // this throws because at least 3 X values are required
+    CrossCorrelate alg;
+    setupAlgorithm(alg, 2.0, 2.4);
+    runAlgorithmThrows(alg);
+  }
+
+  void testXMinEqualsXMax() {
+    // this throws because XMin should be > XMax
+    CrossCorrelate alg;
+    setupAlgorithm(alg, 2.0, 2.0);
+    runAlgorithmThrows(alg);
+  }
+
+  void testXMinGreaterThanXMax() {
+    // this throws because XMin should be < XMax
+    CrossCorrelate alg;
+    setupAlgorithm(alg, 3.0, 2.0);
+    runAlgorithmThrows(alg);
+  }
+
+private:
+  const MatrixWorkspace_sptr makeFakeWorkspace() {
+    // create the x and e values
+    const int nBins = 10;
+    BinEdges xValues(nBins + 1, HistogramData::LinearGenerator(0.0, 0.5));
+    CountStandardDeviations e1(nBins, sqrt(3.0));
+
+    // for y use a gaussian peak centred at 2.5 with height=10
+    const double sigmaSq = 0.7 * 0.7;
+    std::vector<double> yValues(nBins);
+    for (size_t j = 0; j < nBins; ++j) {
+      yValues[j] =
+          0.3 + 10.0 * exp(-0.5 * pow(xValues[j] - 2.5, 2.0) / sigmaSq);
+    }
+
+    // create the workspace
+    const int nHist = 2;
+    const MatrixWorkspace_sptr ws =
+        createWorkspace<Workspace2D>(nHist, nBins + 1, nBins);
+    ws->getAxis(0)->setUnit("dSpacing");
+
+    for (size_t i = 0; i < nHist; ++i) {
+      ws->setBinEdges(i, xValues);
+      ws->mutableY(i) = yValues;
+      ws->setCountStandardDeviations(i, e1);
+
+      // offset the x values for the next spectrum
+      xValues += 0.5;
+    }
+
+    return ws;
+  }
+
+  // Initialise the algorithm and set the properties. Creates a fake workspace
+  // for the input and returns it.
+  MatrixWorkspace_const_sptr
+  setupAlgorithm(CrossCorrelate &alg, const double xmin, const double xmax) {
+
+    // create the workspace
+    const MatrixWorkspace_sptr inWS = makeFakeWorkspace();
+
+    // set up the algorithm
+    if (!alg.isInitialized())
+      alg.initialize();
+    alg.setChild(true);
+    alg.setProperty("InputWorkspace", inWS);
+    alg.setProperty("OutputWorkspace", "outWS");
+    alg.setProperty("ReferenceSpectra", 0);
+    alg.setProperty("WorkspaceIndexMin", 0);
+    alg.setProperty("WorkspaceIndexMax", 1);
+    alg.setProperty("XMin", xmin);
+    alg.setProperty("XMax", xmax);
+
+    return inWS;
+  }
+
+  // Run the algorithm and do some basic checks. Returns the output workspace.
+  MatrixWorkspace_const_sptr
+  runAlgorithm(CrossCorrelate &alg, const MatrixWorkspace_const_sptr inWS) {
+    // run the algorithm
+    TS_ASSERT_THROWS_NOTHING(alg.execute());
+    TS_ASSERT(alg.isExecuted());
+
+    // verify the output workspace
+    const MatrixWorkspace_const_sptr outWS = alg.getProperty("OutputWorkspace");
+    TS_ASSERT_EQUALS(inWS->getNumberHistograms(),
+                     outWS->getNumberHistograms()); // shouldn't drop histograms
+
+    return outWS;
+  }
+
+  // Run the algorithm with invalid input and check that it throws a runtime
+  // error
+  void runAlgorithmThrows(CrossCorrelate &alg) {
+    TS_ASSERT_THROWS(alg.execute(), std::runtime_error);
+  }
+};
+
+#endif /*CROSSCORRELATETEST_H_*/
diff --git a/Framework/Algorithms/test/CuboidGaugeVolumeAbsorptionTest.h b/Framework/Algorithms/test/CuboidGaugeVolumeAbsorptionTest.h
index 776a7e23b8e058b054e1f973443915d3de055166..c49e3b2ea8540adb3fd9e3d62aef412566ed2a06 100644
--- a/Framework/Algorithms/test/CuboidGaugeVolumeAbsorptionTest.h
+++ b/Framework/Algorithms/test/CuboidGaugeVolumeAbsorptionTest.h
@@ -28,7 +28,7 @@ public:
 
   void testFailsIfNoInstrument() {
     // Create a simple test workspace that has no instrument
-    Workspace2D_sptr testWS = WorkspaceCreationHelper::Create2DWorkspace(10, 5);
+    Workspace2D_sptr testWS = WorkspaceCreationHelper::create2DWorkspace(10, 5);
     // Needs to have units of wavelength
     testWS->getAxis(0)->unit() =
         Mantid::Kernel::UnitFactory::Instance().create("Wavelength");
diff --git a/Framework/Algorithms/test/DeleteLogTest.h b/Framework/Algorithms/test/DeleteLogTest.h
index 09d86ac23b453d497d25899063799842f5947ec5..8bd866cb162a53e7bb38264be418c4dc5794179e 100644
--- a/Framework/Algorithms/test/DeleteLogTest.h
+++ b/Framework/Algorithms/test/DeleteLogTest.h
@@ -28,7 +28,7 @@ public:
     alg.setChild(true); // no ADS storage
     alg.setRethrows(true);
     TS_ASSERT_THROWS_NOTHING(alg.setProperty("Name", "NotALog"));
-    auto ws = WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+    auto ws = WorkspaceCreationHelper::create2DWorkspace(10, 10);
     alg.setProperty("Workspace", ws);
     TS_ASSERT_THROWS_NOTHING(alg.execute());
   }
@@ -38,7 +38,7 @@ public:
     alg.initialize();
     alg.setChild(true); // no ADS storage
     alg.setRethrows(true);
-    auto ws = WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+    auto ws = WorkspaceCreationHelper::create2DWorkspace(10, 10);
     std::string logName("SingleValue");
     ws->mutableRun().addProperty<double>(logName, 1.0);
     alg.setProperty("Workspace", ws);
@@ -54,7 +54,7 @@ public:
     alg.initialize();
     alg.setChild(true); // no ADS storage
     alg.setRethrows(true);
-    auto ws = WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+    auto ws = WorkspaceCreationHelper::create2DWorkspace(10, 10);
     std::string logName("TimeSeries");
 
     auto *tsp = new Mantid::Kernel::TimeSeriesProperty<double>(logName);
diff --git a/Framework/Algorithms/test/DeleteWorkspaceTest.h b/Framework/Algorithms/test/DeleteWorkspaceTest.h
index f22fae8a61ce15956de8e164dfabfc494e93a296..3ae2eb059826db4f2092ff59ed7b1ff4395e8c3a 100644
--- a/Framework/Algorithms/test/DeleteWorkspaceTest.h
+++ b/Framework/Algorithms/test/DeleteWorkspaceTest.h
@@ -17,10 +17,10 @@ public:
     // Need a test workspace registered within the ADS
     const int yLength1 = 10;
     Workspace2D_sptr testWS1 =
-        WorkspaceCreationHelper::Create2DWorkspace(yLength1, 10);
+        WorkspaceCreationHelper::create2DWorkspace(yLength1, 10);
     const int yLength2 = 20;
     Workspace2D_sptr testWS2 =
-        WorkspaceCreationHelper::Create2DWorkspace(yLength2, 10);
+        WorkspaceCreationHelper::create2DWorkspace(yLength2, 10);
     AnalysisDataServiceImpl &dataStore = AnalysisDataService::Instance();
     const size_t storeSizeAtStart(dataStore.size());
     const std::string testName1 = "DeleteWorkspace_testWS1";
@@ -56,10 +56,10 @@ public:
     // Need a test workspace registered within the ADS
     const int yLength1 = 10;
     Workspace2D_sptr testWS1 =
-        WorkspaceCreationHelper::Create2DWorkspace(yLength1, 10);
+        WorkspaceCreationHelper::create2DWorkspace(yLength1, 10);
     const int yLength2 = 20;
     Workspace2D_sptr testWS2 =
-        WorkspaceCreationHelper::Create2DWorkspace(yLength2, 10);
+        WorkspaceCreationHelper::create2DWorkspace(yLength2, 10);
     AnalysisDataServiceImpl &dataStore = AnalysisDataService::Instance();
     dataStore.clear();
 
diff --git a/Framework/Algorithms/test/DetectorEfficiencyCorTest.h b/Framework/Algorithms/test/DetectorEfficiencyCorTest.h
index b50ab80cdc17266f27a67b16a2520e9a919620a6..a367e53279ad2cd63d54f2435d37f5a234762737 100644
--- a/Framework/Algorithms/test/DetectorEfficiencyCorTest.h
+++ b/Framework/Algorithms/test/DetectorEfficiencyCorTest.h
@@ -137,20 +137,23 @@ private:
         ShapeFactory().createShape(xmlShape, addTypeTag);
 
     boost::shared_ptr<Instrument> instrument = boost::make_shared<Instrument>();
+    const int ndets(2);
+    std::vector<Detector *> detectors;
+    for (int i = 0; i < ndets; ++i) {
+      Detector *detector = new Detector("det", i + 1, shape, NULL);
+      detector->setPos(i * 0.2, i * 0.2, 5);
+      instrument->markAsDetector(detector);
+      detectors.push_back(detector);
+    }
     space2D->setInstrument(instrument);
     ObjComponent *sample = new ObjComponent("sample", shape, NULL);
     sample->setPos(0, 0, 0);
     instrument->markAsSamplePos(sample);
 
     ParameterMap &pmap = space2D->instrumentParameters();
-    // Detector info
-    const int ndets(2);
-    for (int i = 0; i < ndets; ++i) {
-      Detector *detector = new Detector("det", i + 1, shape, NULL);
-      detector->setPos(i * 0.2, i * 0.2, 5);
+    for (const auto detector : detectors) {
       pmap.add("double", detector, "TubePressure", 10.0);
       pmap.add("double", detector, "TubeThickness", 0.0008);
-      instrument->markAsDetector(detector);
     }
     return space2D;
   }
diff --git a/Framework/Algorithms/test/DetectorEfficiencyVariationTest.h b/Framework/Algorithms/test/DetectorEfficiencyVariationTest.h
index fb0e579396b2cd2832d4514cc2cdf79e2851e3b8..c8fcc8c15a04901c608858a99565740c2730d3b2 100644
--- a/Framework/Algorithms/test/DetectorEfficiencyVariationTest.h
+++ b/Framework/Algorithms/test/DetectorEfficiencyVariationTest.h
@@ -146,10 +146,6 @@ public:
       inputB->setCounts(j, std::move(forInputB));
       inputA->setCountStandardDeviations(j, errors);
       inputB->setCountStandardDeviations(j, errors);
-      // Just set the spectrum number to match the index, spectra numbers and
-      // detector maps must be indentical for both
-      inputA->getSpectrum(j).setSpectrumNo(j + 1);
-      inputB->getSpectrum(j).setSpectrumNo(j + 1);
     }
 
     // Register the input workspaces to the ADS where they can be accessed by
diff --git a/Framework/Algorithms/test/DiffractionFocussing2Test.h b/Framework/Algorithms/test/DiffractionFocussing2Test.h
index 5e6db504b0d41b1c0bde093678951939135aebcb..7f8cb32fdfe1e9cc5d015dfa147344e835e498f9 100644
--- a/Framework/Algorithms/test/DiffractionFocussing2Test.h
+++ b/Framework/Algorithms/test/DiffractionFocussing2Test.h
@@ -7,7 +7,6 @@
 #include "MantidAlgorithms/MaskBins.h"
 #include "MantidAlgorithms/Rebin.h"
 #include "MantidAPI/SpectraAxis.h"
-#include "MantidDataHandling/LoadEventPreNexus.h"
 #include "MantidDataHandling/LoadNexus.h"
 #include "MantidDataHandling/LoadRaw3.h"
 #include "MantidDataObjects/EventWorkspace.h"
diff --git a/Framework/Algorithms/test/DiffractionFocussingTest.h b/Framework/Algorithms/test/DiffractionFocussingTest.h
index 2b1ebb342b197366bacada0bdecdcb65019e7a42..eae24368d3d19662adf497ff05c4dede6584bc7d 100644
--- a/Framework/Algorithms/test/DiffractionFocussingTest.h
+++ b/Framework/Algorithms/test/DiffractionFocussingTest.h
@@ -4,6 +4,7 @@
 #include <cxxtest/TestSuite.h>
 
 #include "MantidAlgorithms/DiffractionFocussing.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidDataHandling/LoadNexus.h"
 
diff --git a/Framework/Algorithms/test/ElasticWindowTest.h b/Framework/Algorithms/test/ElasticWindowTest.h
index 1b18b2e167e3742a45dad43fd8b69789569b9104..fc5a591aa36dd1364de9261eb38d93a49d6efbff 100644
--- a/Framework/Algorithms/test/ElasticWindowTest.h
+++ b/Framework/Algorithms/test/ElasticWindowTest.h
@@ -9,6 +9,7 @@
 #include "MantidAlgorithms/ElasticWindow.h"
 #include "MantidAlgorithms/Rebin.h"
 #include "MantidAlgorithms/SetInstrumentParameter.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Axis.h"
 #include "MantidAPI/FrameworkManager.h"
 #include "MantidKernel/System.h"
diff --git a/Framework/Algorithms/test/EstimateResolutionDiffractionTest.h b/Framework/Algorithms/test/EstimateResolutionDiffractionTest.h
index 6ae958d9bf905ee01a782143965c09fe161f5b9c..90ae83b702172df851add8ad68bcabc0133cf85b 100644
--- a/Framework/Algorithms/test/EstimateResolutionDiffractionTest.h
+++ b/Framework/Algorithms/test/EstimateResolutionDiffractionTest.h
@@ -3,6 +3,7 @@
 
 #include <cxxtest/TestSuite.h>
 
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/Run.h"
 #include "MantidAlgorithms/EstimateResolutionDiffraction.h"
@@ -48,7 +49,7 @@ public:
     alg.initialize();
 
     TS_ASSERT_THROWS_NOTHING(
-        alg.setPropertyValue("InputWorkspace", ws->name()));
+        alg.setPropertyValue("InputWorkspace", ws->getName()));
     TS_ASSERT_THROWS_NOTHING(
         alg.setPropertyValue("OutputWorkspace", "PG3_Resolution"));
     TS_ASSERT_THROWS_NOTHING(alg.setProperty("DeltaTOF", 40.0));
diff --git a/Framework/Algorithms/test/ExponentialCorrectionTest.h b/Framework/Algorithms/test/ExponentialCorrectionTest.h
index 8e331f08db243ea9ccfa22b1d9e01794fb241cff..bb98354e2019411550c8916d0048644bc03b8acb 100644
--- a/Framework/Algorithms/test/ExponentialCorrectionTest.h
+++ b/Framework/Algorithms/test/ExponentialCorrectionTest.h
@@ -50,7 +50,7 @@ public:
 
   void testDivide() {
     MatrixWorkspace_sptr inputWS =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(2, 3, 0.5);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(2, 3, 0.5);
     AnalysisDataService::Instance().add("InputWS", inputWS);
 
     Mantid::Algorithms::ExponentialCorrection expon3;
@@ -88,7 +88,7 @@ public:
 
   void testMultiply() {
     MatrixWorkspace_sptr inputWS =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(2, 3, 0.5);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(2, 3, 0.5);
     AnalysisDataService::Instance().add("InputWS", inputWS);
 
     Mantid::Algorithms::ExponentialCorrection expon3;
@@ -126,7 +126,7 @@ public:
   }
 
   void testEvents() {
-    EventWorkspace_sptr evin = WorkspaceCreationHelper::CreateEventWorkspace(
+    EventWorkspace_sptr evin = WorkspaceCreationHelper::createEventWorkspace(
                             1, 5, 10, 0, 1, 3),
                         evout;
     AnalysisDataService::Instance().add("test_ev_ec", evin);
diff --git a/Framework/Algorithms/test/ExponentialTest.h b/Framework/Algorithms/test/ExponentialTest.h
index e9d3e88406d32fbf1e459642f7b854bb05849c5b..5acc38d4a239ee1a02683f9367c06acf9f76cfa4 100644
--- a/Framework/Algorithms/test/ExponentialTest.h
+++ b/Framework/Algorithms/test/ExponentialTest.h
@@ -30,7 +30,7 @@ public:
     int sizex = 10;
     // Register the workspace in the data service
     MatrixWorkspace_sptr work_in1 =
-        WorkspaceCreationHelper::Create1DWorkspaceFib(sizex);
+        WorkspaceCreationHelper::create1DWorkspaceFib(sizex);
 
     AnalysisDataService::Instance().add("test_in11", work_in1);
     setError(work_in1);
@@ -56,7 +56,7 @@ public:
 
   void testEvents() {
     // evin has 0 events per bin in pixel0, 1 in pixel 1, 2 in pixel2, ...
-    EventWorkspace_sptr evin = WorkspaceCreationHelper::CreateEventWorkspace(
+    EventWorkspace_sptr evin = WorkspaceCreationHelper::createEventWorkspace(
                             5, 3, 1000, 0, 1, 4),
                         evout;
     AnalysisDataService::Instance().add("test_ev_exp", evin);
diff --git a/Framework/Algorithms/test/ExtractFFTSpectrumTest.h b/Framework/Algorithms/test/ExtractFFTSpectrumTest.h
index 3e3a52b7cafda622c2e0f75342ecd32b16e44f44..b9a5f848529fac8ea85e6aaafe5b34125392cb96 100644
--- a/Framework/Algorithms/test/ExtractFFTSpectrumTest.h
+++ b/Framework/Algorithms/test/ExtractFFTSpectrumTest.h
@@ -8,6 +8,7 @@
 #include "MantidAPI/Axis.h"
 #include "MantidDataHandling/LoadNexus.h"
 #include "MantidAlgorithms/Rebin.h"
+#include "MantidKernel/Unit.h"
 
 using namespace Mantid::Kernel;
 using namespace Mantid::API;
diff --git a/Framework/Algorithms/test/ExtractMaskTest.h b/Framework/Algorithms/test/ExtractMaskTest.h
index 54a782c8aacde56fb97e436e9a614f7909411cfd..d7fbb44bc96ba8272af511b34436a450d48d502b 100644
--- a/Framework/Algorithms/test/ExtractMaskTest.h
+++ b/Framework/Algorithms/test/ExtractMaskTest.h
@@ -1,10 +1,8 @@
 #ifndef EXTRACTMASKINGTEST_H_
 #define EXTRACTMASKINGTEST_H_
 
-//------------------------------------------------------------------------------
-// Includes
-//------------------------------------------------------------------------------
 #include <cxxtest/TestSuite.h>
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidAlgorithms/ExtractMask.h"
 #include "MantidDataObjects/MaskWorkspace.h"
 #include "MantidTestHelpers/WorkspaceCreationHelper.h"
@@ -36,7 +34,7 @@ public:
     // Create a simple test workspace
     const int nvectors(50), nbins(10);
     Workspace2D_sptr inputWS =
-        WorkspaceCreationHelper::Create2DWorkspace(nvectors, nbins);
+        WorkspaceCreationHelper::create2DWorkspace(nvectors, nbins);
     // Mask every 10th spectra
     std::set<int64_t> maskedIndices;
     for (int i = 0; i < 50; i += 10) {
@@ -89,6 +87,8 @@ private:
     TS_ASSERT_EQUALS(outputWS->blocksize(), 1);
     size_t nOutputHists(outputWS->getNumberHistograms());
     TS_ASSERT_EQUALS(nOutputHists, inputWS->getNumberHistograms());
+    const auto &iSpecInfo = inputWS->spectrumInfo();
+    const auto &oSpecInfo = outputWS->spectrumInfo();
     for (size_t i = 0; i < nOutputHists; ++i) {
       // Sizes
       TS_ASSERT_EQUALS(outputWS->readX(i).size(), 1);
@@ -97,17 +97,11 @@ private:
       // Data
       double expectedValue(-1.0);
       bool outputMasked(false);
-      IDetector_const_sptr inputDet, outputDet;
-      try {
-        inputDet = inputWS->getDetector(i);
-        outputDet = outputWS->getDetector(i);
-      } catch (Mantid::Kernel::Exception::NotFoundError &) {
+      if (!iSpecInfo.hasDetectors(i) || !oSpecInfo.hasDetectors(i)) {
         expectedValue = 1.0;
-        inputDet = IDetector_sptr();
-        outputDet = IDetector_sptr();
       }
 
-      if (inputDet && inputDet->isMasked()) {
+      if (iSpecInfo.hasDetectors(i) && iSpecInfo.isMasked(i)) {
         expectedValue = 1.0;
         outputMasked = true;
       } else {
@@ -118,8 +112,8 @@ private:
       TS_ASSERT_EQUALS(outputWS->dataY(i)[0], expectedValue);
       TS_ASSERT_EQUALS(outputWS->dataE(i)[0], expectedValue);
       TS_ASSERT_EQUALS(outputWS->dataX(i)[0], 0.0);
-      if (inputDet) {
-        TS_ASSERT_EQUALS(outputDet->isMasked(), outputMasked);
+      if (iSpecInfo.hasDetectors(i)) {
+        TS_ASSERT_EQUALS(oSpecInfo.isMasked(i), outputMasked);
       }
     }
   }
diff --git a/Framework/Algorithms/test/ExtractMaskToTableTest.h b/Framework/Algorithms/test/ExtractMaskToTableTest.h
index 78b338148bc4bcebb09b6bdef335d1b83d0f1f11..56f25ea6e7a1e1677e9a7261da5d06b2328a3a45 100644
--- a/Framework/Algorithms/test/ExtractMaskToTableTest.h
+++ b/Framework/Algorithms/test/ExtractMaskToTableTest.h
@@ -7,6 +7,7 @@
 #include "MantidAlgorithms/ExtractMask.h"
 #include "MantidAlgorithms/SumNeighbours.h"
 #include "MantidAlgorithms/MaskDetectorsIf.h"
+#include "MantidAPI/DetectorInfo.h"
 #include "MantidAPI/TableRow.h"
 #include "MantidTestHelpers/WorkspaceCreationHelper.h"
 #include "MantidDataObjects/Workspace2D.h"
@@ -104,7 +105,7 @@ public:
     // Create a workspace with some detectors masked
     const int nvectors(50), nbins(10);
     Workspace2D_sptr inputws =
-        WorkspaceCreationHelper::Create2DWorkspace(nvectors, nbins);
+        WorkspaceCreationHelper::create2DWorkspace(nvectors, nbins);
 
     //   Mask every 10th spectra
     std::set<int64_t> maskedIndices;
@@ -167,7 +168,7 @@ public:
     // Create a workspace with some detectors masked
     const int nvectors(50), nbins(10);
     Workspace2D_sptr inputws =
-        WorkspaceCreationHelper::Create2DWorkspace(nvectors, nbins);
+        WorkspaceCreationHelper::create2DWorkspace(nvectors, nbins);
 
     //   Mask every 10th spectra
     std::set<int64_t> maskedIndices;
@@ -268,7 +269,7 @@ public:
     // Create a workspace with some detectors masked
     const int nvectors(50), nbins(10);
     Workspace2D_sptr inputws =
-        WorkspaceCreationHelper::Create2DWorkspace(nvectors, nbins);
+        WorkspaceCreationHelper::create2DWorkspace(nvectors, nbins);
 
     //   Mask every 10th spectra
     std::set<int64_t> maskedIndices;
@@ -375,12 +376,11 @@ public:
       cout << "Workspace masked."
            << "\n";
 
-    Instrument_const_sptr instrument = inputws->getInstrument();
-    for (size_t i = 0; i < instrument->getDetectorIDs().size(); ++i) {
-      if (instrument->getDetector(instrument->getDetectorIDs()[i])->isMasked())
-        cout << "Detector : " << instrument->getDetectorIDs()[i]
-             << " is masked."
-             << "\n";
+    const auto &detectorInfo = inputws->detectorInfo();
+    for (size_t i = 0; i < detectorInfo.size(); ++i) {
+      if (detectorInfo.isMasked(i))
+        cout << "Detector : " << detectorInfo.detectorIDs()[i]
+             << " is masked.\n";
     }
 
     /*
diff --git a/Framework/Algorithms/test/ExtractSingleSpectrumTest.h b/Framework/Algorithms/test/ExtractSingleSpectrumTest.h
index 704ffca52c6e01c1f17c5d3c726bad0f6a773a27..1073b97166fe75703902b0bce21de2a8e94b707b 100644
--- a/Framework/Algorithms/test/ExtractSingleSpectrumTest.h
+++ b/Framework/Algorithms/test/ExtractSingleSpectrumTest.h
@@ -66,7 +66,7 @@ public:
     // Create and input event workspace
     const int eventsPerPixel(25);
     const int numPixels(10);
-    EventWorkspace_sptr eventWS = WorkspaceCreationHelper::CreateEventWorkspace(
+    EventWorkspace_sptr eventWS = WorkspaceCreationHelper::createEventWorkspace(
         numPixels, 50, eventsPerPixel, 0.0, 1.0, 1 /*EventPattern=1*/);
     TS_ASSERT(eventWS);
     const int wsIndex(4);
diff --git a/Framework/Algorithms/test/ExtractSpectraTest.h b/Framework/Algorithms/test/ExtractSpectraTest.h
index 1e16115d6a22914f8e35351d9fd1ba2edcc70465..b76a91d627a6da72bf7ccac2e89df73f308f63ff 100644
--- a/Framework/Algorithms/test/ExtractSpectraTest.h
+++ b/Framework/Algorithms/test/ExtractSpectraTest.h
@@ -454,7 +454,7 @@ private:
   }
 
   MatrixWorkspace_sptr createInputWorkspaceEvent() const {
-    EventWorkspace_sptr ws = WorkspaceCreationHelper::CreateEventWorkspace(
+    EventWorkspace_sptr ws = WorkspaceCreationHelper::createEventWorkspace(
         int(nSpec), int(nBins), 50, 0.0, 1., 2);
     ws->getAxis(0)->unit() = UnitFactory::Instance().create("TOF");
     ws->setInstrument(
@@ -716,9 +716,9 @@ public:
   }
 
   ExtractSpectraTestPerformance() {
-    input = WorkspaceCreationHelper::Create2DWorkspaceBinned(40000, 10000);
+    input = WorkspaceCreationHelper::create2DWorkspaceBinned(40000, 10000);
     inputEvent =
-        WorkspaceCreationHelper::CreateEventWorkspace(40000, 10000, 2000);
+        WorkspaceCreationHelper::createEventWorkspace(40000, 10000, 2000);
   }
 
   void testExec2D() {
diff --git a/Framework/Algorithms/test/FFTSmooth2Test.h b/Framework/Algorithms/test/FFTSmooth2Test.h
index c97eb18174bcab81d5d340a5f88323f7a34b24ea..cd93b1d12a455db3307c799aacd707a68af6cb8e 100644
--- a/Framework/Algorithms/test/FFTSmooth2Test.h
+++ b/Framework/Algorithms/test/FFTSmooth2Test.h
@@ -172,10 +172,10 @@ public:
 
     // Make workspaces where Y value == workspace index
     if (event)
-      ws1 = WorkspaceCreationHelper::CreateEventWorkspace(10, numBins, numBins,
+      ws1 = WorkspaceCreationHelper::createEventWorkspace(10, numBins, numBins,
                                                           0, 1.0, 4);
     else
-      ws1 = WorkspaceCreationHelper::Create2DWorkspaceWhereYIsWorkspaceIndex(
+      ws1 = WorkspaceCreationHelper::create2DWorkspaceWhereYIsWorkspaceIndex(
           numPixels, numBins);
 
     std::string outName = "SmoothedWS";
diff --git a/Framework/Algorithms/test/FFTTest.h b/Framework/Algorithms/test/FFTTest.h
index f00fb4d764367972510b649f5c1f585c9a76ecad..01100624c558052aa4a25c04f953ec6891ff5724 100644
--- a/Framework/Algorithms/test/FFTTest.h
+++ b/Framework/Algorithms/test/FFTTest.h
@@ -9,6 +9,7 @@
 #include "MantidAPI/FrameworkManager.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/WorkspaceFactory.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidAlgorithms/FFT.h"
 #include "MantidDataObjects/Workspace2D.h"
 #include "MantidKernel/UnitFactory.h"
diff --git a/Framework/Algorithms/test/FilterByLogValueTest.h b/Framework/Algorithms/test/FilterByLogValueTest.h
index 4b38f70af64bb97f8668b3a58a9389fe0b396b2d..1d9ea52bc630560525cfafb57b404ec2c0556906 100644
--- a/Framework/Algorithms/test/FilterByLogValueTest.h
+++ b/Framework/Algorithms/test/FilterByLogValueTest.h
@@ -33,10 +33,10 @@ public:
     // InputWorkspace has to be an EventWorkspace
     TS_ASSERT_THROWS(
         alg.setProperty("InputWorkspace",
-                        WorkspaceCreationHelper::Create2DWorkspace(1, 1)),
+                        WorkspaceCreationHelper::create2DWorkspace(1, 1)),
         std::invalid_argument);
     TS_ASSERT_THROWS_NOTHING(alg.setProperty(
-        "InputWorkspace", WorkspaceCreationHelper::CreateEventWorkspace()));
+        "InputWorkspace", WorkspaceCreationHelper::createEventWorkspace()));
 
     // LogName must not be empty
     TS_ASSERT_THROWS(alg.setProperty("LogName", ""), std::invalid_argument);
@@ -57,7 +57,7 @@ public:
 
   void test_validateInputs() {
     // Create and event workspace. We don't care what data is in it.
-    EventWorkspace_sptr ws = WorkspaceCreationHelper::CreateEventWorkspace();
+    EventWorkspace_sptr ws = WorkspaceCreationHelper::createEventWorkspace();
     // Add a single-number log
     ws->mutableRun().addProperty("SingleValue", 5);
     // Add a time-series property
@@ -106,7 +106,7 @@ public:
    */
   EventWorkspace_sptr createInputWS(bool add_proton_charge = true) {
     // Default Event Workspace with times from 0-99
-    EventWorkspace_sptr ew = WorkspaceCreationHelper::CreateEventWorkspace2();
+    EventWorkspace_sptr ew = WorkspaceCreationHelper::createEventWorkspace2();
 
     DateAndTime run_start("2010-01-01T00:00:00"); // NOTE This run_start is
                                                   // hard-coded in
@@ -151,7 +151,7 @@ public:
     ew->mutableRun().addProperty(single);
 
     // Finalize the needed stuff
-    WorkspaceCreationHelper::EventWorkspace_Finalize(ew);
+    WorkspaceCreationHelper::eventWorkspace_Finalize(ew);
 
     return ew;
   }
diff --git a/Framework/Algorithms/test/FilterByTime2Test.h b/Framework/Algorithms/test/FilterByTime2Test.h
index 8408c283b5deb8b628d5bbf54bcf42b4d0a04ae0..8280809e9c468e4f52d8f178889991a1cff37455 100644
--- a/Framework/Algorithms/test/FilterByTime2Test.h
+++ b/Framework/Algorithms/test/FilterByTime2Test.h
@@ -11,7 +11,7 @@
 #include <cxxtest/TestSuite.h>
 
 #include "MantidAlgorithms/FilterByTime2.h"
-#include "MantidDataHandling/LoadEventPreNexus.h"
+#include "MantidDataHandling/LoadEventPreNexus2.h"
 #include "MantidKernel/DateAndTime.h"
 #include "MantidDataObjects/EventWorkspace.h"
 #include "MantidTestHelpers/WorkspaceCreationHelper.h"
@@ -28,7 +28,7 @@ public:
   /** Setup for loading raw data */
   void setUp_Event() {
     inputWS = "eventWS";
-    LoadEventPreNexus loader;
+    LoadEventPreNexus2 loader;
     loader.initialize();
     std::string eventfile("CNCS_7860_neutron_event.dat");
     std::string pulsefile("CNCS_7860_pulseid.dat");
@@ -44,7 +44,7 @@ public:
    */
   void NtestTooManyParams() {
     EventWorkspace_sptr ws =
-        WorkspaceCreationHelper::CreateEventWorkspace(1, 1);
+        WorkspaceCreationHelper::createEventWorkspace(1, 1);
     AnalysisDataService::Instance().addOrReplace("eventWS", ws);
 
     // Do the filtering now.
diff --git a/Framework/Algorithms/test/FilterByTimeTest.h b/Framework/Algorithms/test/FilterByTimeTest.h
index 3f7105857061e5b5ccf3445cf90fdd170e43c247..a304c4dcda3c1b177a50f59027a7edca33a32a19 100644
--- a/Framework/Algorithms/test/FilterByTimeTest.h
+++ b/Framework/Algorithms/test/FilterByTimeTest.h
@@ -33,7 +33,7 @@ public:
   FilterByTimeTest() {
     inWS = "filterbytime_input";
     EventWorkspace_sptr ws =
-        WorkspaceCreationHelper::CreateEventWorkspace(4, 1);
+        WorkspaceCreationHelper::createEventWorkspace(4, 1);
     // Add proton charge
     TimeSeriesProperty<double> *pc =
         new TimeSeriesProperty<double>("proton_charge");
@@ -53,7 +53,7 @@ public:
 
   void testTooManyParams() {
     EventWorkspace_sptr ws =
-        WorkspaceCreationHelper::CreateEventWorkspace(1, 1);
+        WorkspaceCreationHelper::createEventWorkspace(1, 1);
     AnalysisDataService::Instance().addOrReplace("eventWS", ws);
 
     // Do the filtering now.
diff --git a/Framework/Algorithms/test/FilterByXValueTest.h b/Framework/Algorithms/test/FilterByXValueTest.h
index 1b01bb2cdd82982d678b1a6a758f0d637db59105..9db6417cb3ef4adf929fca54ca17392f1aad20fd 100644
--- a/Framework/Algorithms/test/FilterByXValueTest.h
+++ b/Framework/Algorithms/test/FilterByXValueTest.h
@@ -23,10 +23,10 @@ public:
     // InputWorkspace has to be an EventWorkspace
     TS_ASSERT_THROWS(
         alg.setProperty("InputWorkspace",
-                        WorkspaceCreationHelper::Create2DWorkspace(1, 1)),
+                        WorkspaceCreationHelper::create2DWorkspace(1, 1)),
         std::invalid_argument);
     TS_ASSERT_THROWS_NOTHING(alg.setProperty(
-        "InputWorkspace", WorkspaceCreationHelper::CreateEventWorkspace()));
+        "InputWorkspace", WorkspaceCreationHelper::createEventWorkspace()));
 
     // At least one of XMin & XMax must be specified
     auto errorMap = alg.validateInputs();
@@ -48,7 +48,7 @@ public:
   void test_exec() {
     using Mantid::DataObjects::EventWorkspace_sptr;
     EventWorkspace_sptr inputWS =
-        WorkspaceCreationHelper::CreateEventWorkspace2(5, 1);
+        WorkspaceCreationHelper::createEventWorkspace2(5, 1);
     // Add the workspace to the ADS so that it gets a name (stops validation
     // complaints)
     Mantid::API::AnalysisDataService::Instance().add("inWS", inputWS);
@@ -80,7 +80,7 @@ public:
 
   void setUp() override {
     Mantid::API::AnalysisDataService::Instance().add(
-        "ToFilter", WorkspaceCreationHelper::CreateEventWorkspace(
+        "ToFilter", WorkspaceCreationHelper::createEventWorkspace(
                         5000, 1000, 8000, 0.0, 1.0, 3));
   }
 
diff --git a/Framework/Algorithms/test/FilterEventsTest.h b/Framework/Algorithms/test/FilterEventsTest.h
index ccf0402a3e8d7177e331f37fb99df393d3309878..a27169c7a7b92f76332d973b1da5f002cebd2c64 100644
--- a/Framework/Algorithms/test/FilterEventsTest.h
+++ b/Framework/Algorithms/test/FilterEventsTest.h
@@ -13,6 +13,7 @@
 #include "MantidDataObjects/SplittersWorkspace.h"
 #include "MantidDataObjects/TableWorkspace.h"
 #include "MantidGeometry/Instrument.h"
+#include "MantidKernel/PhysicalConstants.h"
 #include "MantidKernel/TimeSeriesProperty.h"
 #include "MantidKernel/TimeSplitter.h"
 #include "MantidTestHelpers/WorkspaceCreationHelper.h"
@@ -428,7 +429,7 @@ public:
     FilterEvents filter;
     filter.initialize();
 
-    filter.setProperty("InputWorkspace", ws->name());
+    filter.setProperty("InputWorkspace", ws->getName());
     filter.setProperty("OutputWorkspaceBaseName", "SplittedDataDG");
     filter.setProperty("CorrectionToSample", "Direct");
     filter.setProperty("SplitterWorkspace", "SplitterTableX");
diff --git a/Framework/Algorithms/test/FindCenterOfMassPosition2Test.h b/Framework/Algorithms/test/FindCenterOfMassPosition2Test.h
index 83aa975dcdaa184cffabb955d9147f3a538639a6..af79181947bac5e41f463222bc675eca677c6b74 100644
--- a/Framework/Algorithms/test/FindCenterOfMassPosition2Test.h
+++ b/Framework/Algorithms/test/FindCenterOfMassPosition2Test.h
@@ -7,6 +7,7 @@
 #include "MantidDataObjects/Workspace2D.h"
 #include "MantidKernel/UnitFactory.h"
 #include "MantidKernel/ConfigService.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/TableRow.h"
 #include "MantidDataObjects/TableWorkspace.h"
 
@@ -50,7 +51,6 @@ public:
         double dy = (center_y - (double)iy);
         Y[0] = exp(-(dx * dx + dy * dy));
         E[0] = 1;
-        ws->getSpectrum(i).setSpectrumNo(i);
       }
     }
   }
diff --git a/Framework/Algorithms/test/FindCenterOfMassPositionTest.h b/Framework/Algorithms/test/FindCenterOfMassPositionTest.h
index 7f0a52eae36ed6be76081b3dff5d0570b6b9b56d..1f19170fa9291d6f02d524697183241e711d2ea2 100644
--- a/Framework/Algorithms/test/FindCenterOfMassPositionTest.h
+++ b/Framework/Algorithms/test/FindCenterOfMassPositionTest.h
@@ -7,6 +7,7 @@
 #include "MantidDataObjects/Workspace2D.h"
 #include "MantidKernel/UnitFactory.h"
 #include "MantidKernel/ConfigService.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/TableRow.h"
 #include "MantidDataObjects/TableWorkspace.h"
 
@@ -49,7 +50,6 @@ public:
         double dy = (center_y - (double)iy);
         Y[0] = exp(-(dx * dx + dy * dy));
         E[0] = 1;
-        ws->getSpectrum(i).setSpectrumNo(i);
       }
     }
   }
diff --git a/Framework/Algorithms/test/FindDeadDetectorsTest.h b/Framework/Algorithms/test/FindDeadDetectorsTest.h
index 81c7108785a77535f3478b4acbfdff263079a7f0..ff7805e6efe49a519707d8f8c9dac9f19e8b0cd5 100644
--- a/Framework/Algorithms/test/FindDeadDetectorsTest.h
+++ b/Framework/Algorithms/test/FindDeadDetectorsTest.h
@@ -38,10 +38,9 @@ public:
     // data
     Workspace2D_sptr work_in =
         // the x values look like this -1, 2, 5, 8, 11, 14, 17, 20, 23, 26
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(sizey, sizex, -1, 3.0);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(sizey, sizex, -1, 3.0);
 
     Instrument_sptr instr(new Instrument);
-    work_in->setInstrument(instr);
 
     // yVeryDead is a detector that never responds and produces no counts
     Counts yVeryDead(sizex, 0);
@@ -78,6 +77,7 @@ public:
       instr->markAsDetector(det);
       work_in->getSpectrum(i).setDetectorID(i);
     }
+    work_in->setInstrument(instr);
 
     FindDeadDetectors alg;
 
diff --git a/Framework/Algorithms/test/FindDetectorsOutsideLimitsTest.h b/Framework/Algorithms/test/FindDetectorsOutsideLimitsTest.h
index a3b03243c337c4bfb50364f208a62a4f444adb14..9c6b0ea835879a855d34c172dc36a74fe294385c 100644
--- a/Framework/Algorithms/test/FindDetectorsOutsideLimitsTest.h
+++ b/Framework/Algorithms/test/FindDetectorsOutsideLimitsTest.h
@@ -38,10 +38,9 @@ public:
     // data
     Workspace2D_sptr work_in =
         // the x values look like this -1, 2, 5, 8, 11, 14, 17, 20, 23, 26
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(sizey, sizex, -1, 3.0);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(sizey, sizex, -1, 3.0);
 
     Instrument_sptr instr(new Instrument);
-    work_in->setInstrument(instr);
 
     // yVeryDead is a detector with low counts
     Counts yVeryDead(sizex, 0.1);
@@ -78,6 +77,7 @@ public:
       instr->markAsDetector(det);
       work_in->getSpectrum(i).setDetectorID(i);
     }
+    work_in->setInstrument(instr);
 
     FindDetectorsOutsideLimits alg;
 
@@ -153,7 +153,7 @@ public:
 
   void testExec_Event() {
     // Make a workspace with 50 pixels, 200 events per pixel.
-    EventWorkspace_sptr work_in = WorkspaceCreationHelper::CreateEventWorkspace(
+    EventWorkspace_sptr work_in = WorkspaceCreationHelper::createEventWorkspace(
         50, 100, 100, 0.0, 1.0, 2, 1);
     Instrument_sptr inst =
         ComponentCreationHelper::createTestInstrumentCylindrical(10);
diff --git a/Framework/Algorithms/test/FindPeakBackgroundTest.h b/Framework/Algorithms/test/FindPeakBackgroundTest.h
index cf9b571571b8e0fac3480d7993f4ebc56d690a94..fe421b5cfb80aede4f43583a1b43419ba38053ef 100644
--- a/Framework/Algorithms/test/FindPeakBackgroundTest.h
+++ b/Framework/Algorithms/test/FindPeakBackgroundTest.h
@@ -4,6 +4,7 @@
 #include <cxxtest/TestSuite.h>
 
 #include "MantidAlgorithms/FindPeakBackground.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/ITableWorkspace.h"
diff --git a/Framework/Algorithms/test/FitPeakTest.h b/Framework/Algorithms/test/FitPeakTest.h
index ca3b79ae1d207b8e8e49c6bb2c822ebdab565a9f..333ec2fe645114389a87490cf5bc19fa176b5de0 100644
--- a/Framework/Algorithms/test/FitPeakTest.h
+++ b/Framework/Algorithms/test/FitPeakTest.h
@@ -4,6 +4,7 @@
 #include <cxxtest/TestSuite.h>
 
 #include "MantidAlgorithms/FitPeak.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/FrameworkManager.h"
 #include "MantidAPI/WorkspaceFactory.h"
diff --git a/Framework/Algorithms/test/GeneralisedSecondDifferenceTest.h b/Framework/Algorithms/test/GeneralisedSecondDifferenceTest.h
index db41133460d98600342b30cc10385a5e9f22415e..2496d91bda7f3aaae20cfe9dcdc0ca48d86ba7a6 100644
--- a/Framework/Algorithms/test/GeneralisedSecondDifferenceTest.h
+++ b/Framework/Algorithms/test/GeneralisedSecondDifferenceTest.h
@@ -79,9 +79,9 @@ public:
   }
 
   void setUp() override {
-    inputMatrix = WorkspaceCreationHelper::Create2DWorkspaceBinned(10000, 1000);
+    inputMatrix = WorkspaceCreationHelper::create2DWorkspaceBinned(10000, 1000);
     inputEvent =
-        WorkspaceCreationHelper::CreateEventWorkspace(10000, 1000, 5000);
+        WorkspaceCreationHelper::createEventWorkspace(10000, 1000, 5000);
   }
 
   void tearDown() override {
diff --git a/Framework/Algorithms/test/GenerateIPythonNotebookTest.h b/Framework/Algorithms/test/GenerateIPythonNotebookTest.h
index feeb64359c0f7736674a6085b904f645074725df..161da6b66676e8cdb6a629117882ae84222db436 100644
--- a/Framework/Algorithms/test/GenerateIPythonNotebookTest.h
+++ b/Framework/Algorithms/test/GenerateIPythonNotebookTest.h
@@ -14,6 +14,7 @@
 #include "MantidAPI/AlgorithmManager.h"
 #include "MantidAPI/FrameworkManager.h"
 #include "MantidAPI/MatrixWorkspace.h"
+#include "MantidAPI/WorkspaceHistory.h"
 #include "MantidKernel/make_unique.h"
 #include <Poco/File.h>
 
diff --git a/Framework/Algorithms/test/GeneratePeaksTest.h b/Framework/Algorithms/test/GeneratePeaksTest.h
index 570b26760c52ba2c95c3fd2355e535cc7a06339e..ae60baf4145b7266ec5fb6894f1fcc4fbf16c167 100644
--- a/Framework/Algorithms/test/GeneratePeaksTest.h
+++ b/Framework/Algorithms/test/GeneratePeaksTest.h
@@ -7,6 +7,7 @@
 
 #include "MantidAlgorithms/GeneratePeaks.h"
 #include "MantidDataObjects/TableWorkspace.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Column.h"
 #include "MantidAPI/TableRow.h"
 #include "MantidAPI/MatrixWorkspace.h"
@@ -575,4 +576,4 @@ private:
   API::MatrixWorkspace_sptr inputws;
 };
 
-#endif /* MANTID_ALGORITHMS_GENERATEPEAKSTEST_H_ */
\ No newline at end of file
+#endif /* MANTID_ALGORITHMS_GENERATEPEAKSTEST_H_ */
diff --git a/Framework/Algorithms/test/GeneratePythonScriptTest.h b/Framework/Algorithms/test/GeneratePythonScriptTest.h
index 1192374f2b6c9db682f819958f450def6c220e7c..67ac94d0a325c0b133ba0c14d194724bd09ecf18 100644
--- a/Framework/Algorithms/test/GeneratePythonScriptTest.h
+++ b/Framework/Algorithms/test/GeneratePythonScriptTest.h
@@ -10,6 +10,7 @@
 #include "MantidAPI/AlgorithmManager.h"
 #include "MantidAPI/FrameworkManager.h"
 #include "MantidAPI/MatrixWorkspace.h"
+#include "MantidAPI/WorkspaceHistory.h"
 #include "MantidKernel/make_unique.h"
 #include "MantidKernel/Timer.h"
 #include "MantidKernel/System.h"
diff --git a/Framework/Algorithms/test/GetAllEiTest.h b/Framework/Algorithms/test/GetAllEiTest.h
index 2365239cc9f39add70f91a4ec9d0d8e269d013d5..0693b03e9d25f4dc3fe59f8a49ce418928d563bb 100644
--- a/Framework/Algorithms/test/GetAllEiTest.h
+++ b/Framework/Algorithms/test/GetAllEiTest.h
@@ -4,6 +4,7 @@
 #include <memory>
 #include <cxxtest/TestSuite.h>
 #include "MantidAlgorithms/GetAllEi.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidGeometry/Instrument.h"
 #include "MantidKernel/TimeSeriesProperty.h"
 #include "MantidTestHelpers/WorkspaceCreationHelper.h"
@@ -39,12 +40,11 @@ DataObjects::Workspace2D_sptr createTestingWS(bool noLogs = false) {
   paramMap.add<bool>("bool", chopper.get(), "filter_with_derivative", false);
 
   // test instrument parameters (obtained from workspace):
-  auto moderator = pInstrument->getSource();
-  auto detector1 = ws->getDetector(0);
-  auto detector2 = ws->getDetector(1);
-  double l_chop = chopper->getDistance(*moderator);
-  double l_mon1 = detector1->getDistance(*moderator);
-  double l_mon2 = detector2->getDistance(*moderator);
+  auto moderatorPosition = pInstrument->getSource()->getPos();
+  auto &spectrumInfo = ws->spectrumInfo();
+  double l_chop = chopper->getPos().distance(moderatorPosition);
+  double l_mon1 = spectrumInfo.position(0).distance(moderatorPosition);
+  double l_mon2 = spectrumInfo.position(1).distance(moderatorPosition);
   //,l_mon1(20-9),l_mon2(20-2);
   double t_chop(delay + inital_chop_phase / chopSpeed);
   double Period =
@@ -409,8 +409,9 @@ public:
     Mantid::DataObjects::Workspace2D_sptr tws =
         WorkspaceCreationHelper::create2DWorkspaceWithFullInstrument(5, 100,
                                                                      true);
-    auto det1 = tws->getDetector(0);
-    auto det2 = tws->getDetector(4);
+    auto &spectrumInfoT = tws->spectrumInfo();
+    auto det1TPosition = spectrumInfoT.position(0);
+    auto det2TPosition = spectrumInfoT.position(4);
     auto detID1 = tws->getSpectrum(0).getDetectorIDs();
     auto detID2 = tws->getSpectrum(4).getDetectorIDs();
 
@@ -423,12 +424,13 @@ public:
     size_t wsIndex0;
     auto wws = m_getAllEi.buildWorkspaceToFit(tws, wsIndex0);
 
-    auto det1p = wws->getDetector(0);
-    auto det2p = wws->getDetector(1);
+    auto &spectrumInfoW = wws->spectrumInfo();
+    auto det1WPosition = spectrumInfoW.position(0);
+    auto det2WPosition = spectrumInfoW.position(1);
     TSM_ASSERT_EQUALS("should be the same first detector position",
-                      det1p->getRelativePos(), det1->getRelativePos());
+                      det1WPosition, det1TPosition);
     TSM_ASSERT_EQUALS("should be the same second detector position",
-                      det2p->getRelativePos(), det2->getRelativePos());
+                      det2WPosition, det2TPosition);
 
     TSM_ASSERT_EQUALS("Detector's ID for the first spectrum and new workspace "
                       "should coincide",
diff --git a/Framework/Algorithms/test/GetDetOffsetsMultiPeaksTest.h b/Framework/Algorithms/test/GetDetOffsetsMultiPeaksTest.h
index 9721c6548d7a69a478ecb619770433f776c40a66..09bf98918e8cbf5ddc6a5796dac2fd88ad1ae056 100644
--- a/Framework/Algorithms/test/GetDetOffsetsMultiPeaksTest.h
+++ b/Framework/Algorithms/test/GetDetOffsetsMultiPeaksTest.h
@@ -5,6 +5,7 @@
 #include "MantidAPI/AlgorithmManager.h"
 #include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Axis.h"
+#include "MantidAPI/DetectorInfo.h"
 #include "MantidAPI/FrameworkManager.h"
 #include "MantidAPI/TableRow.h"
 #include "MantidDataObjects/OffsetsWorkspace.h"
@@ -88,7 +89,7 @@ public:
             maskWS));
     if (!mask)
       return;
-    TS_ASSERT(!mask->getInstrument()->getDetector(1)->isMasked());
+    TS_ASSERT(!mask->detectorInfo().isMasked(0));
   }
 
   //----------------------------------------------------------------------------------------------
@@ -97,7 +98,7 @@ public:
   void testExecWithGroup() {
     // --------- Workspace with summed spectra -------
     MatrixWorkspace_sptr WS =
-        WorkspaceCreationHelper::CreateGroupedWorkspace2D(3, 200, 1.0);
+        WorkspaceCreationHelper::createGroupedWorkspace2D(3, 200, 1.0);
     WS->getAxis(0)->unit() =
         Mantid::Kernel::UnitFactory::Instance().create("dSpacing");
 
@@ -143,7 +144,7 @@ public:
             maskWS));
     if (!mask)
       return;
-    TS_ASSERT(!mask->getInstrument()->getDetector(1)->isMasked());
+    TS_ASSERT(!mask->detectorInfo().isMasked(0));
   }
 
   //----------------------------------------------------------------------------------------------
@@ -214,7 +215,7 @@ public:
             maskWS));
     if (!mask)
       return;
-    TS_ASSERT(!mask->getInstrument()->getDetector(1)->isMasked());
+    TS_ASSERT(!mask->detectorInfo().isMasked(0));
   }
 
   //----------------------------------------------------------------------------------------------
@@ -285,7 +286,7 @@ public:
             maskWS));
     if (!mask)
       return;
-    TS_ASSERT(!mask->getInstrument()->getDetector(1)->isMasked());
+    TS_ASSERT(!mask->detectorInfo().isMasked(0));
   }
 
   //----------------------------------------------------------------------------------------------
@@ -355,7 +356,7 @@ public:
             maskWS));
     if (!mask)
       return;
-    TS_ASSERT(!mask->getInstrument()->getDetector(1)->isMasked());
+    TS_ASSERT(!mask->detectorInfo().isMasked(0));
   }
 
   //----------------------------------------------------------------------------------------------
@@ -416,7 +417,7 @@ public:
     TS_ASSERT_THROWS_NOTHING(
         mask = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(
             maskWS));
-    TS_ASSERT(mask->getInstrument()->getDetector(1)->isMasked());
+    TS_ASSERT(mask->detectorInfo().isMasked(0));
 
     return;
   }
diff --git a/Framework/Algorithms/test/GetDetectorOffsetsTest.h b/Framework/Algorithms/test/GetDetectorOffsetsTest.h
index 510063e9e5cac33fcc9bf616be0b90b9687d638a..0a319d79f8fe67ff1dc44a1b4a3d5ef8c0d743ec 100644
--- a/Framework/Algorithms/test/GetDetectorOffsetsTest.h
+++ b/Framework/Algorithms/test/GetDetectorOffsetsTest.h
@@ -9,6 +9,7 @@
 #include <cxxtest/TestSuite.h>
 #include "MantidDataObjects/OffsetsWorkspace.h"
 #include "MantidAPI/AlgorithmManager.h"
+#include "MantidAPI/DetectorInfo.h"
 #include "MantidAPI/FrameworkManager.h"
 
 using namespace Mantid::API;
@@ -85,13 +86,13 @@ public:
             maskWS));
     if (!mask)
       return;
-    TS_ASSERT(!mask->getInstrument()->getDetector(1)->isMasked());
+    TS_ASSERT(!mask->detectorInfo().isMasked(0));
   }
 
   void testExecWithGroup() {
     // --------- Workspace with summed spectra -------
     MatrixWorkspace_sptr WS =
-        WorkspaceCreationHelper::CreateGroupedWorkspace2D(3, 200, 1.0);
+        WorkspaceCreationHelper::createGroupedWorkspace2D(3, 200, 1.0);
     WS->getAxis(0)->unit() =
         Mantid::Kernel::UnitFactory::Instance().create("dSpacing");
 
@@ -136,7 +137,7 @@ public:
             maskWS));
     if (!mask)
       return;
-    TS_ASSERT(!mask->getInstrument()->getDetector(1)->isMasked());
+    TS_ASSERT(!mask->detectorInfo().isMasked(0));
   }
 
   void testExecAbsolute() {
@@ -191,7 +192,7 @@ public:
             maskWS));
     if (!mask)
       return;
-    TS_ASSERT(!mask->getInstrument()->getDetector(1)->isMasked());
+    TS_ASSERT(!mask->detectorInfo().isMasked(0));
   }
 
 private:
diff --git a/Framework/Algorithms/test/GetEiMonDet2Test.h b/Framework/Algorithms/test/GetEiMonDet2Test.h
index f43bfbdb25a0fd239074fb52fcb1e777c49002a7..14cb0a3ed521aa8a351e2335d276fc1016c43f6c 100644
--- a/Framework/Algorithms/test/GetEiMonDet2Test.h
+++ b/Framework/Algorithms/test/GetEiMonDet2Test.h
@@ -54,12 +54,15 @@ public:
     TS_ASSERT(algorithm.isInitialized())
   }
 
-  void testSuccessOnMinimumInput() {
+  void testSuccessOnMinimalInput() {
     const double realEi = 0.97 * EI;
     const auto peaks =
         peakCentres(100, realEi, std::numeric_limits<double>::max());
-    std::vector<bool> successes(peaks.size(), true);
-    auto eppTable = createEPPTable(peaks, successes);
+    std::vector<EPPTableRow> eppRows(peaks.size());
+    for (size_t i = 0; i < peaks.size(); ++i) {
+      eppRows[i].peakCentre = peaks[i];
+    }
+    auto eppTable = createEPPTableWorkspace(eppRows);
     auto ws = createWorkspace();
     GetEiMonDet2 algorithm;
     setupSimple(ws, eppTable, algorithm);
@@ -77,13 +80,20 @@ public:
     auto detectorPeakCentres =
         peakCentres(timeAtMonitor, realEi, pulseInterval);
     detectorPeakCentres.erase(detectorPeakCentres.begin());
-    std::vector<bool> successes(detectorPeakCentres.size(), true);
-    auto detectorEPPTable = createEPPTable(detectorPeakCentres, successes);
+    std::vector<EPPTableRow> eppRows(detectorPeakCentres.size());
+    for (size_t i = 0; i < detectorPeakCentres.size(); ++i) {
+      eppRows[i].peakCentre = detectorPeakCentres[i];
+    }
+    auto detectorEPPTable = createEPPTableWorkspace(eppRows);
+    eppRows.clear();
     auto monitorPeakCentres = peakCentres(timeAtMonitor, realEi, pulseInterval);
     monitorPeakCentres.erase(monitorPeakCentres.begin() + 1,
                              monitorPeakCentres.end());
-    successes = std::vector<bool>(monitorPeakCentres.size(), true);
-    auto monitorEPPTable = createEPPTable(monitorPeakCentres, successes);
+    eppRows.resize(monitorPeakCentres.size());
+    for (size_t i = 0; i < monitorPeakCentres.size(); ++i) {
+      eppRows[i].peakCentre = monitorPeakCentres[i];
+    }
+    auto monitorEPPTable = createEPPTableWorkspace(eppRows);
     auto ws = createWorkspace();
     ws->mutableRun().removeProperty("Ei");
     // Break workspace into separate monitor and detector workspaces.
@@ -105,6 +115,7 @@ public:
     MatrixWorkspace_sptr detectorWs =
         spectrumExtraction.getProperty("OutputWorkspace");
     GetEiMonDet2 algorithm;
+    algorithm.setRethrows(true);
     TS_ASSERT_THROWS_NOTHING(algorithm.initialize())
     TS_ASSERT(algorithm.isInitialized())
     TS_ASSERT_THROWS_NOTHING(
@@ -112,7 +123,7 @@ public:
     TS_ASSERT_THROWS_NOTHING(
         algorithm.setProperty("DetectorEPPTable", detectorEPPTable))
     TS_ASSERT_THROWS_NOTHING(
-        algorithm.setProperty("IndexType", "SpectrumNumber"))
+        algorithm.setProperty("IndexType", "Spectrum Number"))
     TS_ASSERT_THROWS_NOTHING(algorithm.setProperty("Detectors", "2"))
     TS_ASSERT_THROWS_NOTHING(algorithm.setProperty("NominalIncidentEnergy", EI))
     TS_ASSERT_THROWS_NOTHING(
@@ -129,12 +140,23 @@ public:
         realEi, 1e-6)
   }
 
+  void testSuccessOnPulseIntervalInProperties() {
+    runPulseIntervalInputsTest(PulseIntervalInputs::AS_PROPERTY);
+  }
+
+  void testSuccessOnPulseIntervalInSampleLogs() {
+    runPulseIntervalInputsTest(PulseIntervalInputs::AS_SAMLPE_LOG);
+  }
+
   void testFailureOnAllDetectorsMasked() {
     const double realEi = EI;
     const auto peaks =
         peakCentres(100, realEi, std::numeric_limits<double>::max());
-    std::vector<bool> successes(peaks.size(), true);
-    auto eppTable = createEPPTable(peaks, successes);
+    std::vector<EPPTableRow> eppRows(peaks.size());
+    for (size_t i = 0; i < peaks.size(); ++i) {
+      eppRows[i].peakCentre = peaks[i];
+    }
+    auto eppTable = createEPPTableWorkspace(eppRows);
     auto ws = createWorkspace();
     MaskDetectors maskDetectors;
     maskDetectors.initialize();
@@ -144,7 +166,7 @@ public:
     maskDetectors.execute();
     GetEiMonDet2 algorithm;
     setupSimple(ws, eppTable, algorithm);
-    TS_ASSERT_THROWS_NOTHING(algorithm.execute())
+    TS_ASSERT_THROWS(algorithm.execute(), std::runtime_error)
     TS_ASSERT(!algorithm.isExecuted())
   }
 
@@ -152,8 +174,11 @@ public:
     const double realEi = EI;
     const auto peaks =
         peakCentres(100, realEi, std::numeric_limits<double>::max());
-    std::vector<bool> successes(peaks.size(), true);
-    auto eppTable = createEPPTable(peaks, successes);
+    std::vector<EPPTableRow> eppRows(peaks.size());
+    for (size_t i = 0; i < peaks.size(); ++i) {
+      eppRows[i].peakCentre = peaks[i];
+    }
+    auto eppTable = createEPPTableWorkspace(eppRows);
     auto ws = createWorkspace();
     MaskDetectors maskDetectors;
     maskDetectors.initialize();
@@ -163,7 +188,7 @@ public:
     maskDetectors.execute();
     GetEiMonDet2 algorithm;
     setupSimple(ws, eppTable, algorithm);
-    TS_ASSERT_THROWS_NOTHING(algorithm.execute())
+    TS_ASSERT_THROWS(algorithm.execute(), std::runtime_error)
     TS_ASSERT(!algorithm.isExecuted())
   }
 
@@ -171,14 +196,18 @@ public:
     const double realEi = EI;
     const auto peaks =
         peakCentres(100, realEi, std::numeric_limits<double>::max());
-    std::vector<bool> successes(peaks.size(), false);
+    std::vector<EPPTableRow> eppRows(peaks.size());
+    for (size_t i = 0; i < peaks.size(); ++i) {
+      eppRows[i].peakCentre = peaks[i];
+      eppRows[i].fitStatus = EPPTableRow::FitStatus::FAILURE;
+    }
     // Monitor should still say 'success'.
-    successes.front() = true;
-    auto eppTable = createEPPTable(peaks, successes);
+    eppRows.front().fitStatus = EPPTableRow::FitStatus::SUCCESS;
+    auto eppTable = createEPPTableWorkspace(eppRows);
     auto ws = createWorkspace();
     GetEiMonDet2 algorithm;
     setupSimple(ws, eppTable, algorithm);
-    TS_ASSERT_THROWS_NOTHING(algorithm.execute())
+    TS_ASSERT_THROWS(algorithm.execute(), std::runtime_error)
     TS_ASSERT(!algorithm.isExecuted())
   }
 
@@ -186,13 +215,16 @@ public:
     const double realEi = EI;
     const auto peaks =
         peakCentres(100, realEi, std::numeric_limits<double>::max());
-    std::vector<bool> successes(peaks.size(), true);
-    successes.front() = false;
-    auto eppTable = createEPPTable(peaks, successes);
+    std::vector<EPPTableRow> eppRows(peaks.size());
+    for (size_t i = 0; i < peaks.size(); ++i) {
+      eppRows[i].peakCentre = peaks[i];
+    }
+    eppRows.front().fitStatus = EPPTableRow::FitStatus::FAILURE;
+    auto eppTable = createEPPTableWorkspace(eppRows);
     auto ws = createWorkspace();
     GetEiMonDet2 algorithm;
     setupSimple(ws, eppTable, algorithm);
-    TS_ASSERT_THROWS_NOTHING(algorithm.execute())
+    TS_ASSERT_THROWS(algorithm.execute(), std::runtime_error)
     TS_ASSERT(!algorithm.isExecuted())
   }
 
@@ -200,10 +232,14 @@ public:
     const double realEi = EI;
     const auto peaks =
         peakCentres(100, realEi, std::numeric_limits<double>::max());
-    std::vector<bool> successes(peaks.size(), true);
-    auto eppTable = createEPPTable(peaks, successes);
+    std::vector<EPPTableRow> eppRows(peaks.size());
+    for (size_t i = 0; i < peaks.size(); ++i) {
+      eppRows[i].peakCentre = peaks[i];
+    }
+    auto eppTable = createEPPTableWorkspace(eppRows);
     auto ws = createWorkspace();
     GetEiMonDet2 algorithm;
+    algorithm.setRethrows(true);
     TS_ASSERT_THROWS_NOTHING(algorithm.initialize())
     TS_ASSERT(algorithm.isInitialized())
     TS_ASSERT_THROWS_NOTHING(algorithm.setProperty("DetectorWorkspace", ws))
@@ -211,7 +247,7 @@ public:
         algorithm.setProperty("DetectorEPPTable", eppTable))
     TS_ASSERT_THROWS_NOTHING(algorithm.setProperty("Detectors", "1"))
     TS_ASSERT_THROWS_NOTHING(algorithm.setPropertyValue("Monitor", "1"))
-    TS_ASSERT_THROWS_NOTHING(algorithm.execute())
+    TS_ASSERT_THROWS(algorithm.execute(), std::runtime_error)
     TS_ASSERT(!algorithm.isExecuted())
   }
 
@@ -219,8 +255,11 @@ public:
     const double realEi = EI;
     const auto peaks =
         peakCentres(100, realEi, std::numeric_limits<double>::max());
-    std::vector<bool> successes(peaks.size(), true);
-    auto eppTable = createEPPTable(peaks, successes);
+    std::vector<EPPTableRow> eppRows(peaks.size());
+    for (size_t i = 0; i < peaks.size(); ++i) {
+      eppRows[i].peakCentre = peaks[i];
+    }
+    auto eppTable = createEPPTableWorkspace(eppRows);
     auto ws = createWorkspace();
     GetEiMonDet2 algorithm;
     algorithm.setRethrows(true);
@@ -230,7 +269,7 @@ public:
     TS_ASSERT_THROWS_NOTHING(
         algorithm.setProperty("DetectorEPPTable", eppTable))
     TS_ASSERT_THROWS_NOTHING(
-        algorithm.setProperty("IndexType", "WorkspaceIndex"))
+        algorithm.setProperty("IndexType", "Workspace Index"))
     TS_ASSERT_THROWS_NOTHING(algorithm.setProperty("Detectors", "1"))
     TS_ASSERT_THROWS_NOTHING(algorithm.setPropertyValue("Monitor", "-1"))
     const std::string exceptionMessage("Monitor cannot be negative.");
@@ -239,14 +278,18 @@ public:
     TS_ASSERT(!algorithm.isExecuted())
   }
 
-  void testFailuroOnNonexistentDetectorIndex() {
+  void testFailureOnNonexistentDetectorIndex() {
     const double realEi = EI;
     const auto peaks =
         peakCentres(100, realEi, std::numeric_limits<double>::max());
-    std::vector<bool> successes(peaks.size(), true);
-    auto eppTable = createEPPTable(peaks, successes);
+    std::vector<EPPTableRow> eppRows(peaks.size());
+    for (size_t i = 0; i < peaks.size(); ++i) {
+      eppRows[i].peakCentre = peaks[i];
+    }
+    auto eppTable = createEPPTableWorkspace(eppRows);
     auto ws = createWorkspace();
     GetEiMonDet2 algorithm;
+    algorithm.setRethrows(true);
     TS_ASSERT_THROWS_NOTHING(algorithm.initialize())
     TS_ASSERT(algorithm.isInitialized())
     TS_ASSERT_THROWS_NOTHING(algorithm.setProperty("DetectorWorkspace", ws))
@@ -254,18 +297,22 @@ public:
         algorithm.setProperty("DetectorEPPTable", eppTable))
     TS_ASSERT_THROWS_NOTHING(algorithm.setProperty("Detectors", "42"))
     TS_ASSERT_THROWS_NOTHING(algorithm.setPropertyValue("Monitor", "0"))
-    TS_ASSERT_THROWS_NOTHING(algorithm.execute())
+    TS_ASSERT_THROWS(algorithm.execute(), std::runtime_error)
     TS_ASSERT(!algorithm.isExecuted())
   }
 
-  void testFailuroOnNonexistentMonitorIndex() {
+  void testFailureOnNonexistentMonitorIndex() {
     const double realEi = EI;
     const auto peaks =
         peakCentres(100, realEi, std::numeric_limits<double>::max());
-    std::vector<bool> successes(peaks.size(), true);
-    auto eppTable = createEPPTable(peaks, successes);
+    std::vector<EPPTableRow> eppRows(peaks.size());
+    for (size_t i = 0; i < peaks.size(); ++i) {
+      eppRows[i].peakCentre = peaks[i];
+    }
+    auto eppTable = createEPPTableWorkspace(eppRows);
     auto ws = createWorkspace();
     GetEiMonDet2 algorithm;
+    algorithm.setRethrows(true);
     TS_ASSERT_THROWS_NOTHING(algorithm.initialize())
     TS_ASSERT(algorithm.isInitialized())
     TS_ASSERT_THROWS_NOTHING(algorithm.setProperty("DetectorWorkspace", ws))
@@ -273,28 +320,15 @@ public:
         algorithm.setProperty("DetectorEPPTable", eppTable))
     TS_ASSERT_THROWS_NOTHING(algorithm.setProperty("Detectors", "1"))
     TS_ASSERT_THROWS_NOTHING(algorithm.setPropertyValue("Monitor", "42"))
-    TS_ASSERT_THROWS_NOTHING(algorithm.execute())
+    TS_ASSERT_THROWS(algorithm.execute(), std::runtime_error)
     TS_ASSERT(!algorithm.isExecuted())
   }
 
-private:
-  ITableWorkspace_sptr
-  createEPPTable(const std::vector<double> &peakCentres,
-                 const std::vector<bool> &fitSuccesses,
-                 const std::string &centresColumnName = "PeakCentre",
-                 const std::string &successesColumnName = "FitStatus") {
-    ITableWorkspace_sptr ws =
-        boost::make_shared<TableWorkspace>(peakCentres.size());
-    auto centreColumn = ws->addColumn("double", centresColumnName);
-    auto statusColumn = ws->addColumn("str", successesColumnName);
-    for (size_t i = 0; i != peakCentres.size(); ++i) {
-      centreColumn->cell<double>(i) = peakCentres[i];
-      statusColumn->cell<std::string>(i) =
-          fitSuccesses[i] ? "success" : "failed";
-    }
-    return ws;
+  void testFailureOnPulseIntervalMissing() {
+    runPulseIntervalInputsTest(PulseIntervalInputs::NONE);
   }
 
+private:
   static void attachInstrument(MatrixWorkspace_sptr targetWs) {
     // The reference frame used by createInstrumentForWorkspaceWithDistances
     // is left handed with y pointing up, x along beam (2016-08-12).
@@ -315,7 +349,7 @@ private:
   static MatrixWorkspace_sptr createWorkspace() {
     const size_t nDetectors = 1;
     // Number of spectra = detectors + monitor.
-    auto ws = Create2DWorkspace(nDetectors + 1, 2);
+    auto ws = create2DWorkspace(nDetectors + 1, 2);
     ws->getAxis(0)->unit() = UnitFactory::Instance().create("TOF");
     attachInstrument(ws);
     ws->mutableRun().addProperty("Ei", EI, true);
@@ -337,6 +371,7 @@ private:
   // Mininum setup for GetEiMonDet2.
   void setupSimple(MatrixWorkspace_sptr ws, ITableWorkspace_sptr eppTable,
                    GetEiMonDet2 &algorithm) {
+    algorithm.setRethrows(true);
     TS_ASSERT_THROWS_NOTHING(algorithm.initialize())
     TS_ASSERT(algorithm.isInitialized())
     TS_ASSERT_THROWS_NOTHING(algorithm.setProperty("DetectorWorkspace", ws))
@@ -345,6 +380,51 @@ private:
     TS_ASSERT_THROWS_NOTHING(algorithm.setProperty("Detectors", "1"))
     TS_ASSERT_THROWS_NOTHING(algorithm.setPropertyValue("Monitor", "0"))
   }
+
+  enum class PulseIntervalInputs { AS_PROPERTY, AS_SAMLPE_LOG, NONE };
+
+  void
+  runPulseIntervalInputsTest(const PulseIntervalInputs pulseIntervalInput) {
+    const double realEi = 1.18 * EI;
+    const double pulseInterval = std::floor(time_of_flight(velocity(EI)) / 2);
+    const double timeAtMonitor = 0.34 * pulseInterval;
+    auto peaks = peakCentres(timeAtMonitor, realEi, pulseInterval);
+    std::vector<EPPTableRow> eppRows(peaks.size());
+    for (size_t i = 0; i != peaks.size(); ++i) {
+      eppRows[i] =
+          EPPTableRow(peaks[i], 1.0, 1.0, EPPTableRow::FitStatus::SUCCESS);
+    }
+    auto eppTable = createEPPTableWorkspace(eppRows);
+    auto ws = createWorkspace();
+    if (pulseIntervalInput == PulseIntervalInputs::AS_SAMLPE_LOG) {
+      ws->mutableRun().addProperty("pulse_interval", pulseInterval * 1e-6);
+    }
+    GetEiMonDet2 algorithm;
+    algorithm.setRethrows(true);
+    TS_ASSERT_THROWS_NOTHING(algorithm.initialize())
+    TS_ASSERT(algorithm.isInitialized())
+    TS_ASSERT_THROWS_NOTHING(algorithm.setProperty("DetectorWorkspace", ws));
+    TS_ASSERT_THROWS_NOTHING(
+        algorithm.setProperty("DetectorEPPTable", eppTable))
+    TS_ASSERT_THROWS_NOTHING(
+        algorithm.setProperty("IndexType", "Spectrum Number"))
+    TS_ASSERT_THROWS_NOTHING(algorithm.setProperty("Detectors", "2"))
+    TS_ASSERT_THROWS_NOTHING(algorithm.setProperty("Monitor", 1))
+    if (pulseIntervalInput == PulseIntervalInputs::AS_PROPERTY) {
+      TS_ASSERT_THROWS_NOTHING(
+          algorithm.setProperty("PulseInterval", pulseInterval));
+    }
+    if (pulseIntervalInput == PulseIntervalInputs::NONE) {
+      TS_ASSERT_THROWS(algorithm.execute(), std::runtime_error)
+      TS_ASSERT(!algorithm.isExecuted())
+    } else {
+      TS_ASSERT_THROWS_NOTHING(algorithm.execute())
+      TS_ASSERT(algorithm.isExecuted())
+      TS_ASSERT_DELTA(static_cast<decltype(realEi)>(
+                          algorithm.getProperty("IncidentEnergy")),
+                      realEi, 1e-6)
+    }
+  }
 };
 
 #endif // GETEIMONDET2TEST_H_
diff --git a/Framework/Algorithms/test/GroupWorkspacesTest.h b/Framework/Algorithms/test/GroupWorkspacesTest.h
index a1f0cbfd1b90a2c6f894db09c1988f3d532d6cb2..0b9fa7e31c0bb1bba51c9b562e415d4be0c32ae7 100644
--- a/Framework/Algorithms/test/GroupWorkspacesTest.h
+++ b/Framework/Algorithms/test/GroupWorkspacesTest.h
@@ -3,6 +3,7 @@
 
 #include <cxxtest/TestSuite.h>
 #include "MantidAlgorithms/GroupWorkspaces.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidTestHelpers/WorkspaceCreationHelper.h"
 
 class GroupWorkspacesTest : public CxxTest::TestSuite {
@@ -202,12 +203,12 @@ private:
 
   void addTestMatrixWorkspaceToADS(const std::string &name) {
     auto &ads = Mantid::API::AnalysisDataService::Instance();
-    ads.add(name, WorkspaceCreationHelper::Create2DWorkspace(1, 1));
+    ads.add(name, WorkspaceCreationHelper::create2DWorkspace(1, 1));
   }
 
   void addTestEventWorkspaceToADS(const std::string &name) {
     auto &ads = Mantid::API::AnalysisDataService::Instance();
-    ads.add(name, WorkspaceCreationHelper::CreateEventWorkspace());
+    ads.add(name, WorkspaceCreationHelper::createEventWorkspace());
   }
 
   void addTestTableWorkspaceToADS(const std::string &name) {
diff --git a/Framework/Algorithms/test/HRPDSlabCanAbsorptionTest.h b/Framework/Algorithms/test/HRPDSlabCanAbsorptionTest.h
index 15cf3386b69f0601af987b5ac85c4ce6c0cdff48..c765aefbdd0f9df1e50181fa6ebcf29821037976 100644
--- a/Framework/Algorithms/test/HRPDSlabCanAbsorptionTest.h
+++ b/Framework/Algorithms/test/HRPDSlabCanAbsorptionTest.h
@@ -7,6 +7,7 @@
 #include "MantidAPI/Axis.h"
 #include "MantidKernel/UnitFactory.h"
 #include "MantidGeometry/Instrument.h"
+#include "MantidGeometry/Objects/Object.h"
 #include "MantidTestHelpers/WorkspaceCreationHelper.h"
 
 using namespace Mantid::Geometry;
@@ -29,14 +30,13 @@ public:
       atten.initialize();
 
     MatrixWorkspace_sptr testWS =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(3, 10, 0.25, 0.5);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(3, 10, 0.25, 0.5);
     // Needs to have units of wavelength
     testWS->getAxis(0)->unit() =
         Mantid::Kernel::UnitFactory::Instance().create("Wavelength");
 
     boost::shared_ptr<Instrument> testInst =
         boost::make_shared<Instrument>("testInst");
-    testWS->setInstrument(testInst);
 
     // Define a source and sample position
     // Define a source component
@@ -68,6 +68,8 @@ public:
     testInst->add(det3);
     testInst->markAsDetector(det3);
 
+    testWS->setInstrument(testInst);
+
     TS_ASSERT_THROWS_NOTHING(
         atten.setProperty<MatrixWorkspace_sptr>("InputWorkspace", testWS));
     std::string outputWS("factors");
diff --git a/Framework/Algorithms/test/He3TubeEfficiencyTest.h b/Framework/Algorithms/test/He3TubeEfficiencyTest.h
index 198e9e09615e0395825c68ca638f5f4165817d7f..6cbe36ada6d806523974c108842948f5e5431309 100644
--- a/Framework/Algorithms/test/He3TubeEfficiencyTest.h
+++ b/Framework/Algorithms/test/He3TubeEfficiencyTest.h
@@ -180,7 +180,6 @@ private:
       space2D->setBinEdges(i, x);
       space2D->setCounts(i, y);
       space2D->setCountStandardDeviations(i, e);
-      space2D->getSpectrum(i).setSpectrumNo(i);
     }
 
     AnalysisDataService::Instance().add(inputWS, space2D);
@@ -196,7 +195,7 @@ private:
 
   void createEventWorkspace() {
     EventWorkspace_sptr event =
-        WorkspaceCreationHelper::CreateEventWorkspace(4, 5, 5, 0, 0.9, 3, 0);
+        WorkspaceCreationHelper::createEventWorkspace(4, 5, 5, 0, 0.9, 3, 0);
     event->getAxis(0)->unit() = UnitFactory::Instance().create("Wavelength");
     AnalysisDataService::Instance().add(inputEvWS, event);
 
diff --git a/Framework/Algorithms/test/IQTransformTest.h b/Framework/Algorithms/test/IQTransformTest.h
index e6eb6943def48ff52d1f28a271a0e3e28d76fb9b..96c82adcdc3bef23dc7ed7f02c35823893509068 100644
--- a/Framework/Algorithms/test/IQTransformTest.h
+++ b/Framework/Algorithms/test/IQTransformTest.h
@@ -6,6 +6,7 @@
 
 #include "MantidAlgorithms/IQTransform.h"
 #include "MantidAPI/Axis.h"
+#include "MantidKernel/Unit.h"
 #include "MantidKernel/UnitFactory.h"
 
 class IQTransformTest : public CxxTest::TestSuite {
@@ -17,12 +18,12 @@ public:
     iq.setChild(
         true); // This means the ADS is not involved anywhere in this test
 
-    inWS_hist = WorkspaceCreationHelper::Create2DWorkspaceBinned(1, 2);
+    inWS_hist = WorkspaceCreationHelper::create2DWorkspaceBinned(1, 2);
     inWS_hist->getAxis(0)->unit() =
         Mantid::Kernel::UnitFactory::Instance().create("MomentumTransfer");
     inWS_hist->setDistribution(true);
 
-    inWS_point = WorkspaceCreationHelper::Create2DWorkspace154(1, 1);
+    inWS_point = WorkspaceCreationHelper::create2DWorkspace154(1, 1);
     inWS_point->dataX(0)[0] = 3.0; // 1 is not a good number to test with
     inWS_point->getAxis(0)->unit() =
         Mantid::Kernel::UnitFactory::Instance().create("MomentumTransfer");
@@ -228,7 +229,7 @@ public:
     TS_ASSERT_THROWS_NOTHING(iq.setPropertyValue("TransformType", "Holtzer"));
     TS_ASSERT_THROWS_NOTHING(iq.setProperty<Mantid::API::MatrixWorkspace_sptr>(
         "BackgroundWorkspace",
-        WorkspaceCreationHelper::Create2DWorkspace123(1, 1)));
+        WorkspaceCreationHelper::create2DWorkspace123(1, 1)));
     TS_ASSERT(iq.execute());
 
     // Remember that a constant value of 1.5 will also be subtracted because
diff --git a/Framework/Algorithms/test/IdentifyNoisyDetectorsTest.h b/Framework/Algorithms/test/IdentifyNoisyDetectorsTest.h
index b295914329142e50670f190fc2bfdb965bda7ef7..5a8d998ad3e9e59c21955dae1b6cde08217d27ca 100644
--- a/Framework/Algorithms/test/IdentifyNoisyDetectorsTest.h
+++ b/Framework/Algorithms/test/IdentifyNoisyDetectorsTest.h
@@ -5,6 +5,7 @@
 
 #include "MantidAlgorithms/IdentifyNoisyDetectors.h"
 #include "MantidDataHandling/LoadRaw3.h"
+#include "MantidAPI/AnalysisDataService.h"
 
 using namespace Mantid::API;
 using namespace Mantid::Algorithms;
diff --git a/Framework/Algorithms/test/ImggTomographicReconstructionTest.h b/Framework/Algorithms/test/ImggTomographicReconstructionTest.h
index a6d196ddc4b9ea0f997c9b2df42ba3088a1536a6..878c21dc91234bde38d01dd8c6ffedc824bef778 100644
--- a/Framework/Algorithms/test/ImggTomographicReconstructionTest.h
+++ b/Framework/Algorithms/test/ImggTomographicReconstructionTest.h
@@ -5,6 +5,7 @@
 
 #include "MantidAlgorithms/ImggTomographicReconstruction.h"
 #include "MantidAPI/AlgorithmManager.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidKernel/Exception.h"
 
 #include "MantidTestHelpers/WorkspaceCreationHelper.h"
@@ -63,7 +64,7 @@ public:
 
   void test_exec_fails_wrong_workspace() {
     API::MatrixWorkspace_sptr a =
-        WorkspaceCreationHelper::CreateWorkspaceSingleValue(3);
+        WorkspaceCreationHelper::createWorkspaceSingleValue(3);
 
     ImggTomographicReconstruction alg;
     TS_ASSERT_THROWS_NOTHING(alg.initialize());
@@ -74,7 +75,7 @@ public:
     TS_ASSERT(!alg.isExecuted());
 
     API::MatrixWorkspace_sptr wsSingle =
-        WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+        WorkspaceCreationHelper::create2DWorkspace(10, 10);
 
     ImggTomographicReconstruction algTwo;
     TS_ASSERT_THROWS_NOTHING(algTwo.initialize());
@@ -88,7 +89,7 @@ public:
   void test_exec_fails_single_proj() {
     const std::string projectionsGrpName("only_one_projection");
     API::WorkspaceGroup_sptr projectionsGrp =
-        WorkspaceCreationHelper::CreateWorkspaceGroup(1, 4, 4,
+        WorkspaceCreationHelper::createWorkspaceGroup(1, 4, 4,
                                                       projectionsGrpName);
 
     ImggTomographicReconstruction alg;
@@ -107,7 +108,7 @@ public:
   void test_exec_fails_wrong_center() {
     const std::string projectionsGrpName("only_two_small_projections");
     API::WorkspaceGroup_sptr projectionsGrp =
-        WorkspaceCreationHelper::CreateWorkspaceGroup(2, 4, 4,
+        WorkspaceCreationHelper::createWorkspaceGroup(2, 4, 4,
                                                       projectionsGrpName);
 
     ImggTomographicReconstruction alg;
@@ -130,7 +131,7 @@ public:
     int xsize = 16;
     int numProj = 4;
     API::WorkspaceGroup_sptr projectionsGrp =
-        WorkspaceCreationHelper::CreateWorkspaceGroup(numProj, ysize, xsize,
+        WorkspaceCreationHelper::createWorkspaceGroup(numProj, ysize, xsize,
                                                       projectionsGrpName);
 
     for (size_t proj = 0; proj < static_cast<size_t>(proj); ++proj) {
@@ -197,7 +198,7 @@ public:
     int xsize = 8;
     int numProj = 2;
     API::WorkspaceGroup_sptr projectionsGrp =
-        WorkspaceCreationHelper::CreateWorkspaceGroup(numProj, ysize, xsize,
+        WorkspaceCreationHelper::createWorkspaceGroup(numProj, ysize, xsize,
                                                       projectionsGrpName);
 
     for (size_t proj = 0; proj < static_cast<size_t>(proj); ++proj) {
diff --git a/Framework/Algorithms/test/IntegrateByComponentTest.h b/Framework/Algorithms/test/IntegrateByComponentTest.h
index 18bfc9580e9ead8474643230f421cb230e9b1db0..5e97930a18c7cb07cc8b8c0dd11416935c926559 100644
--- a/Framework/Algorithms/test/IntegrateByComponentTest.h
+++ b/Framework/Algorithms/test/IntegrateByComponentTest.h
@@ -3,6 +3,8 @@
 
 #include <cxxtest/TestSuite.h>
 
+#include "MantidAPI/DetectorInfo.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidAlgorithms/IntegrateByComponent.h"
 #include "MantidDataObjects/Workspace2D.h"
 #include "MantidGeometry/Instrument/ParameterMap.h"
@@ -223,11 +225,12 @@ public:
     TS_ASSERT(result);
     if (!result)
       return;
+    const auto &spectrumInfo = result->spectrumInfo();
     for (size_t i = 0; i < result->getNumberHistograms() / 4; i++) {
       TS_ASSERT_DELTA(result->readY(4 * i + 1)[0], 8 * i + 4, 1e-10);
       TS_ASSERT_DELTA(result->readY(4 * i + 2)[0], 8 * i + 4, 1e-10);
       TS_ASSERT_DELTA(result->readY(4 * i + 3)[0], 8 * i + 4, 1e-10);
-      TS_ASSERT(result->getDetector(4 * i)->isMasked());
+      TS_ASSERT(spectrumInfo.isMasked(4 * i));
     }
 
     // Remove workspace from the data service.
@@ -239,17 +242,16 @@ private:
   void ABCtestWorkspace(std::string inputWSname, bool mask) {
     int nSpectra(12);
     Workspace2D_sptr ws2D =
-        WorkspaceCreationHelper::Create2DWorkspaceWhereYIsWorkspaceIndex(
+        WorkspaceCreationHelper::create2DWorkspaceWhereYIsWorkspaceIndex(
             nSpectra, 2);
     ws2D->setInstrument(
         ComponentCreationHelper::createTestInstrumentRectangular(3, 2, 0));
 
-    Mantid::Geometry::ParameterMap &pmap = ws2D->instrumentParameters();
+    auto &detectorInfo = ws2D->mutableDetectorInfo();
     for (int i = 0; i < nSpectra; i++) {
       ws2D->getSpectrum(i).setDetectorID(i + 4);
       if (mask && (i % 4 == 0)) {
-        Mantid::Geometry::IDetector_const_sptr det = ws2D->getDetector(i);
-        pmap.addBool(det.get(), "masked", true);
+        detectorInfo.setMasked(i, true);
       }
     }
 
diff --git a/Framework/Algorithms/test/IntegrationTest.h b/Framework/Algorithms/test/IntegrationTest.h
index 923a0fd3587512d315e2a8a19f1111ae8143ca31..06321633d382c4f53550de98c78f30e4e098b36c 100644
--- a/Framework/Algorithms/test/IntegrationTest.h
+++ b/Framework/Algorithms/test/IntegrationTest.h
@@ -221,7 +221,7 @@ public:
                    int StartWorkspaceIndex, int EndWorkspaceIndex) {
     int numPixels = 100;
     int numBins = 50;
-    EventWorkspace_sptr inWS = WorkspaceCreationHelper::CreateEventWorkspace(
+    EventWorkspace_sptr inWS = WorkspaceCreationHelper::createEventWorkspace(
         numPixels, numBins, numBins, 0.0, 1.0, 2);
     AnalysisDataService::Instance().addOrReplace(inName, inWS);
 
@@ -287,7 +287,7 @@ public:
                       const bool IncludePartialBins, const int expectedNumHists,
                       const double expectedVals[]) {
     RebinnedOutput_sptr inWS =
-        WorkspaceCreationHelper::CreateRebinnedOutputWorkspace();
+        WorkspaceCreationHelper::createRebinnedOutputWorkspace();
     std::string inName = inWS->getName();
     AnalysisDataService::Instance().addOrReplace(inName, inWS);
     std::string outName = "rebinInt";
diff --git a/Framework/Algorithms/test/InterpolationOptionTest.h b/Framework/Algorithms/test/InterpolationOptionTest.h
new file mode 100644
index 0000000000000000000000000000000000000000..c29b2b9f5c07fbea0f96e8f37fd219636566fa4a
--- /dev/null
+++ b/Framework/Algorithms/test/InterpolationOptionTest.h
@@ -0,0 +1,105 @@
+#ifndef MANTID_ALGORITHMS_INTERPOLATIONOPTIONTEST_H_
+#define MANTID_ALGORITHMS_INTERPOLATIONOPTIONTEST_H_
+
+#include <cxxtest/TestSuite.h>
+
+#include "MantidAlgorithms/InterpolationOption.h"
+#include "MantidHistogramData/Histogram.h"
+#include "MantidHistogramData/Points.h"
+#include "MantidHistogramData/LinearGenerator.h"
+#include "MantidKernel/PropertyWithValue.h"
+#include "MantidTestHelpers/HistogramDataTestHelper.h"
+
+using Mantid::Algorithms::InterpolationOption;
+using namespace Mantid::HistogramData;
+
+class InterpolationOptionTest : public CxxTest::TestSuite {
+public:
+  // This pair of boilerplate methods prevent the suite being created statically
+  // This means the constructor isn't called when running other tests
+  static InterpolationOptionTest *createSuite() {
+    return new InterpolationOptionTest();
+  }
+  static void destroySuite(InterpolationOptionTest *suite) { delete suite; }
+
+  //----------------------------------------------------------------------------
+  // Success tests
+  //----------------------------------------------------------------------------
+  void test_Property_Defaults_To_Linear_Interpolation() {
+    InterpolationOption interpolateOpt;
+    auto prop = interpolateOpt.property();
+
+    TS_ASSERT(prop);
+    TS_ASSERT_EQUALS("Interpolation", prop->name());
+    TS_ASSERT_EQUALS("Linear", prop->getDefault());
+  }
+
+  void test_Documentation_Is_Not_Empty() {
+    InterpolationOption interpolateOpt;
+
+    TS_ASSERT(!interpolateOpt.propertyDoc().empty())
+  }
+
+  void test_Apply_With_Linear_Succeeds() {
+    using namespace Mantid::HistogramData;
+    InterpolationOption interpolateOpt;
+
+    Histogram inOut(Points(7, LinearGenerator(0, 0.5)),
+                    Counts({-3, 0, -4, 0, 4, 0, 3}));
+    Histogram input(inOut);
+    interpolateOpt.applyInplace(inOut, 2);
+
+    const std::vector<double> expectedY = {-3, -3.5, -4, 0, 4, 3.5, 3};
+    checkData(input, inOut, expectedY);
+  }
+
+  void test_Apply_With_CSpline_Succeeds() {
+    InterpolationOption interpolateOptEnum;
+    // Set by enum
+    interpolateOptEnum.set(InterpolationOption::Value::CSpline);
+
+    Histogram inOut(Points(7, LinearGenerator(0, 0.5)),
+                    Counts({-3, 0, -4, 0, 4, 0, 3}));
+    const Histogram input(inOut);
+    interpolateOptEnum.applyInplace(inOut, 2);
+
+    const std::vector<double> expectedY = {-3, -4.625, -4, 0., 4, 4.625, 3};
+    checkData(input, inOut, expectedY);
+
+    // Set by string
+    InterpolationOption interpolateOptStr;
+    interpolateOptStr.set("CSpline");
+
+    Histogram inOutStr(input);
+    interpolateOptStr.applyInplace(inOutStr, 2);
+
+    checkData(input, inOutStr, expectedY);
+  }
+
+  //----------------------------------------------------------------------------
+  // Failure tests
+  //----------------------------------------------------------------------------
+  void test_set_From_String_Throws_With_Unknown_Type() {
+    InterpolationOption interpolateOpt;
+    TS_ASSERT_THROWS(interpolateOpt.set("Unknown"), std::invalid_argument);
+  }
+
+  void test_set_From_String_Throws_With_Empty_String() {
+    InterpolationOption interpolateOpt;
+    TS_ASSERT_THROWS(interpolateOpt.set(""), std::invalid_argument);
+  }
+
+private:
+  void checkData(const Histogram &input, const Histogram &output,
+                 const std::vector<double> &expectedY) {
+    TS_ASSERT_EQUALS(input.x(), output.x());
+    TS_ASSERT_EQUALS(input.xMode(), output.xMode());
+    TS_ASSERT_EQUALS(input.yMode(), output.yMode());
+    const auto &outY = output.y();
+    for (size_t i = 0; i < expectedY.size(); ++i) {
+      TS_ASSERT_DELTA(expectedY[i], outY[i], 1e-14);
+    }
+  }
+};
+
+#endif /* MANTID_ALGORITHMS_INTERPOLATIONOPTIONTEST_H_ */
diff --git a/Framework/Algorithms/test/LogarithmTest.h b/Framework/Algorithms/test/LogarithmTest.h
index 86bbd36497927f8100ffe46afc98c547a2b04db5..9d58b03c18054f60602997773bfbac379125659e 100644
--- a/Framework/Algorithms/test/LogarithmTest.h
+++ b/Framework/Algorithms/test/LogarithmTest.h
@@ -30,7 +30,7 @@ public:
 
     // Register the workspace in the data service
     MatrixWorkspace_sptr work_in1 =
-        WorkspaceCreationHelper::Create1DWorkspaceFib(sizex);
+        WorkspaceCreationHelper::create1DWorkspaceFib(sizex);
     AnalysisDataService::Instance().add("test_inLn", work_in1);
 
     Logarithm alg;
@@ -59,9 +59,9 @@ public:
     int nHist = 10, nBins = 20;
     // Register the workspace in the data service
     MatrixWorkspace_sptr work_in2 =
-        WorkspaceCreationHelper::Create2DWorkspace154(nHist, nBins);
+        WorkspaceCreationHelper::create2DWorkspace154(nHist, nBins);
     Workspace2D_sptr work_ou2 =
-        WorkspaceCreationHelper::Create2DWorkspace(nHist, nBins);
+        WorkspaceCreationHelper::create2DWorkspace(nHist, nBins);
 
     Logarithm alg;
     AnalysisDataService::Instance().add("test_inLn2", work_in2);
@@ -89,7 +89,7 @@ public:
 
   void testEvents() {
     // evin has 0 events per bin in pixel0, 1 in pixel 1, 2 in pixel2, ...
-    EventWorkspace_sptr evin = WorkspaceCreationHelper::CreateEventWorkspace(
+    EventWorkspace_sptr evin = WorkspaceCreationHelper::createEventWorkspace(
                             5, 3, 1000, 0, 1, 4),
                         evout;
     AnalysisDataService::Instance().add("test_ev_log", evin);
diff --git a/Framework/Algorithms/test/LorentzCorrectionTest.h b/Framework/Algorithms/test/LorentzCorrectionTest.h
index 1703fd8c1815b77afbfcfd9e216dbe645d0991f8..e9621a61d86af246c98c9b784ead7f829d03f1a7 100644
--- a/Framework/Algorithms/test/LorentzCorrectionTest.h
+++ b/Framework/Algorithms/test/LorentzCorrectionTest.h
@@ -10,6 +10,7 @@
 #include "MantidGeometry/Instrument/Detector.h"
 #include "MantidGeometry/Instrument/ObjComponent.h"
 #include "MantidGeometry/Instrument/ReferenceFrame.h"
+#include "MantidKernel/Unit.h"
 #include "MantidKernel/V3D.h"
 #include "MantidTestHelpers/WorkspaceCreationHelper.h"
 #include <cmath>
@@ -65,7 +66,7 @@ private:
     const int nSpectra = 1;
     const double deltaX = 10;
     const double startX = 0;
-    auto workspace = Create2DWorkspaceBinned(nSpectra, nBins, startX,
+    auto workspace = create2DWorkspaceBinned(nSpectra, nBins, startX,
                                              deltaX); // Creates histogram data
     workspace->mutableY(0) = 1.0;
     workspace->mutableE(0) = 1.0;
diff --git a/Framework/Algorithms/test/MCAbsorptionStrategyTest.h b/Framework/Algorithms/test/MCAbsorptionStrategyTest.h
index 0b703dedf4fffba164463197e14b7756cee76dbf..c352450a75e2761d2adc9628323145c909371834 100644
--- a/Framework/Algorithms/test/MCAbsorptionStrategyTest.h
+++ b/Framework/Algorithms/test/MCAbsorptionStrategyTest.h
@@ -35,14 +35,10 @@ public:
 
     MockRNG rng;
     auto mcabsorb = createTestObject();
-    // Expectations
-    Sequence rand;
-    const double step = static_cast<double>(1) / static_cast<double>(m_nevents);
-    const double start = step;
-    for (size_t i = 0; i < m_nevents; ++i) {
-      double next = start + static_cast<double>(i) * step;
-      EXPECT_CALL(rng, nextValue()).InSequence(rand).WillOnce(Return(next));
-    }
+    // 3 random numbers per event expected
+    EXPECT_CALL(rng, nextValue())
+        .Times(Exactly(30))
+        .WillRepeatedly(Return(0.5));
     const Mantid::Algorithms::IBeamProfile::Ray testRay = {V3D(-2, 0, 0),
                                                            V3D(1, 0, 0)};
     EXPECT_CALL(m_testBeamProfile, generatePoint(_, _))
@@ -54,7 +50,7 @@ public:
     double factor(0.0), error(0.0);
     std::tie(factor, error) =
         mcabsorb.calculate(rng, endPos, lambdaBefore, lambdaAfter);
-    TS_ASSERT_DELTA(8.05621154e-03, factor, 1e-08);
+    TS_ASSERT_DELTA(0.0043828472, factor, 1e-08);
     TS_ASSERT_DELTA(1.0 / std::sqrt(m_nevents), error, 1e-08);
   }
 
@@ -72,10 +68,16 @@ private:
     MOCK_CONST_METHOD2(generatePoint,
                        Ray(Mantid::Kernel::PseudoRandomNumberGenerator &,
                            const Mantid::Geometry::BoundingBox &));
+    MOCK_CONST_METHOD1(defineActiveRegion, Mantid::Geometry::BoundingBox(
+                                               const Mantid::API::Sample &));
     GCC_DIAG_ON_SUGGEST_OVERRIDE
   };
 
   MCAbsorptionStrategy createTestObject() {
+    using namespace ::testing;
+
+    EXPECT_CALL(m_testBeamProfile, defineActiveRegion(_))
+        .WillOnce(Return(m_testSample.getShape().getBoundingBox()));
     return MCAbsorptionStrategy(m_testBeamProfile, m_testSample, m_nevents);
   }
 
diff --git a/Framework/Algorithms/test/MCInteractionVolumeTest.h b/Framework/Algorithms/test/MCInteractionVolumeTest.h
index ce32e772b139be86c3facfcf1392ce467be29eb2..fff2c55c0369fb80a7abae932521b504102a7767 100644
--- a/Framework/Algorithms/test/MCInteractionVolumeTest.h
+++ b/Framework/Algorithms/test/MCInteractionVolumeTest.h
@@ -25,9 +25,9 @@ public:
   void test_Bounding_Volume_Matches_Sample() {
     using namespace MonteCarloTesting;
     auto sample = createTestSample(TestSampleType::SolidSphere);
-    MCInteractionVolume interactor(sample);
-
     const auto sampleBox = sample.getShape().getBoundingBox();
+    MCInteractionVolume interactor(sample, sampleBox);
+
     const auto interactionBox = interactor.getBoundingBox();
     TS_ASSERT_EQUALS(sampleBox.minPoint(), interactionBox.minPoint());
     TS_ASSERT_EQUALS(sampleBox.maxPoint(), interactionBox.maxPoint());
@@ -39,18 +39,18 @@ public:
     using namespace ::testing;
 
     // Testing inputs
-    const V3D startPos(-2.0, 0.0, 0.0), direc(1.0, 0.0, 0.0),
-        endPos(0.7, 0.7, 1.4);
+    const V3D startPos(-2.0, 0.0, 0.0), endPos(0.7, 0.7, 1.4);
     const double lambdaBefore(2.5), lambdaAfter(3.5);
     MockRNG rng;
-    EXPECT_CALL(rng, nextInt(1, 1)).Times(Exactly(0));
-    EXPECT_CALL(rng, nextValue()).Times(Exactly(1)).WillOnce(Return(0.25));
+    EXPECT_CALL(rng, nextValue())
+        .Times(Exactly(3))
+        .WillRepeatedly(Return(0.25));
 
     auto sample = createTestSample(TestSampleType::SolidSphere);
-    MCInteractionVolume interactor(sample);
+    MCInteractionVolume interactor(sample, sample.getShape().getBoundingBox());
     const double factor = interactor.calculateAbsorption(
-        rng, startPos, direc, endPos, lambdaBefore, lambdaAfter);
-    TS_ASSERT_DELTA(1.06797501e-02, factor, 1e-8);
+        rng, startPos, endPos, lambdaBefore, lambdaAfter);
+    TS_ASSERT_DELTA(0.0028357258, factor, 1e-8);
   }
 
   void test_Absorption_In_Sample_With_Hole_Container_Scatter_In_All_Segments() {
@@ -59,28 +59,29 @@ public:
     using namespace ::testing;
 
     // Testing inputs
-    const V3D startPos(-2.0, 0.0, 0.0), direc(1.0, 0.0, 0.0),
-        endPos(2.0, 0.0, 0.0);
+    const V3D startPos(-2.0, 0.0, 0.0), endPos(2.0, 0.0, 0.0);
     const double lambdaBefore(2.5), lambdaAfter(3.5);
     auto sample = createTestSample(TestSampleType::Annulus);
 
     MockRNG rng;
     // force scatter in segment 1
-    EXPECT_CALL(rng, nextInt(1, 2)).Times(Exactly(1)).WillOnce(Return(1));
-    EXPECT_CALL(rng, nextValue()).Times(Exactly(1)).WillOnce(Return(0.25));
+    EXPECT_CALL(rng, nextValue())
+        .Times(Exactly(3))
+        .WillRepeatedly(Return(0.25));
 
-    MCInteractionVolume interactor(sample);
+    MCInteractionVolume interactor(sample, sample.getShape().getBoundingBox());
     const double factorSeg1 = interactor.calculateAbsorption(
-        rng, startPos, direc, endPos, lambdaBefore, lambdaAfter);
-    TS_ASSERT_DELTA(5.35624555e-02, factorSeg1, 1e-8);
+        rng, startPos, endPos, lambdaBefore, lambdaAfter);
+    TS_ASSERT_DELTA(0.030489479, factorSeg1, 1e-8);
     Mock::VerifyAndClearExpectations(&rng);
 
     // force scatter in segment 2
-    EXPECT_CALL(rng, nextInt(1, 2)).Times(Exactly(1)).WillOnce(Return(2));
-    EXPECT_CALL(rng, nextValue()).Times(Exactly(1)).WillOnce(Return(0.35));
+    EXPECT_CALL(rng, nextValue())
+        .Times(Exactly(3))
+        .WillRepeatedly(Return(0.75));
     const double factorSeg2 = interactor.calculateAbsorption(
-        rng, startPos, direc, endPos, lambdaBefore, lambdaAfter);
-    TS_ASSERT_DELTA(7.30835693e-02, factorSeg2, 1e-8);
+        rng, startPos, endPos, lambdaBefore, lambdaAfter);
+    TS_ASSERT_DELTA(0.033119242, factorSeg2, 1e-8);
     Mock::VerifyAndClearExpectations(&rng);
   }
 
@@ -91,50 +92,38 @@ public:
     using namespace ::testing;
 
     // Testing inputs
-    const V3D startPos(-2.0, 0.0, 0.0), direc(1.0, 0.0, 0.0),
-        endPos(2.0, 0.0, 0.0);
+    const V3D startPos(-2.0, 0.0, 0.0), endPos(2.0, 0.0, 0.0);
     const double lambdaBefore(2.5), lambdaAfter(3.5);
 
     auto sample = createTestSample(TestSampleType::SamplePlusContainer);
     MockRNG rng;
     // force scatter in segment can
-    EXPECT_CALL(rng, nextInt(1, 3)).Times(Exactly(1)).WillOnce(Return(1));
-    EXPECT_CALL(rng, nextValue()).Times(Exactly(1)).WillOnce(Return(0.3));
-
-    MCInteractionVolume interactor(sample);
+    EXPECT_CALL(rng, nextInt(1, 1)).Times(Exactly(1)).WillOnce(Return(1));
+    EXPECT_CALL(rng, nextValue())
+        .Times(Exactly(4))
+        .WillOnce(Return(0.75))
+        .WillOnce(Return(0.02))
+        .WillOnce(Return(0.5))
+        .WillOnce(Return(0.5));
+
+    MCInteractionVolume interactor(sample,
+                                   sample.getEnvironment().boundingBox());
     const double factorContainer = interactor.calculateAbsorption(
-        rng, startPos, direc, endPos, lambdaBefore, lambdaAfter);
-    TS_ASSERT_DELTA(6.919239804e-01, factorContainer, 1e-8);
+        rng, startPos, endPos, lambdaBefore, lambdaAfter);
+    TS_ASSERT_DELTA(0.69223681, factorContainer, 1e-8);
     Mock::VerifyAndClearExpectations(&rng);
 
     // force scatter in sample
-    EXPECT_CALL(rng, nextInt(1, 3)).Times(Exactly(1)).WillOnce(Return(2));
-    EXPECT_CALL(rng, nextValue()).Times(Exactly(1)).WillOnce(Return(0.35));
-
+    EXPECT_CALL(rng, nextValue())
+        .Times(Exactly(4))
+        .WillOnce(Return(0.25))
+        .WillRepeatedly(Return(0.25));
     const double factorSample = interactor.calculateAbsorption(
-        rng, startPos, direc, endPos, lambdaBefore, lambdaAfter);
-    TS_ASSERT_DELTA(6.9620991317e-01, factorSample, 1e-8);
+        rng, startPos, endPos, lambdaBefore, lambdaAfter);
+    TS_ASSERT_DELTA(0.73100698, factorSample, 1e-8);
     Mock::VerifyAndClearExpectations(&rng);
   }
 
-  void test_Track_With_Zero_Intersections_Returns_Negative_Factor() {
-    using Mantid::Kernel::V3D;
-    using namespace MonteCarloTesting;
-    using namespace ::testing;
-
-    // Testing inputs
-    const V3D startPos(-2.0, 0.0, 0.0), direc(0.0, 1.0, 0.0),
-        endPos(0.7, 0.7, 1.4);
-    const double lambdaBefore(2.5), lambdaAfter(3.5);
-    MockRNG rng;
-    EXPECT_CALL(rng, nextValue()).Times(Exactly(0));
-
-    auto sample = createTestSample(TestSampleType::SolidSphere);
-    MCInteractionVolume interactor(sample);
-    TS_ASSERT(interactor.calculateAbsorption(rng, startPos, direc, endPos,
-                                             lambdaBefore, lambdaAfter) < 0.0);
-  }
-
   //----------------------------------------------------------------------------
   // Failure cases
   //----------------------------------------------------------------------------
@@ -143,10 +132,13 @@ public:
 
     Sample sample;
     // nothing
-    TS_ASSERT_THROWS(MCInteractionVolume mcv(sample), std::invalid_argument);
+    TS_ASSERT_THROWS(
+        MCInteractionVolume mcv(sample, sample.getShape().getBoundingBox()),
+        std::invalid_argument);
     // valid shape
     sample.setShape(*ComponentCreationHelper::createSphere(1));
-    TS_ASSERT_THROWS_NOTHING(MCInteractionVolume mcv(sample));
+    TS_ASSERT_THROWS_NOTHING(
+        MCInteractionVolume mcv(sample, sample.getShape().getBoundingBox()));
   }
 };
 
diff --git a/Framework/Algorithms/test/MaskBinsFromTableTest.h b/Framework/Algorithms/test/MaskBinsFromTableTest.h
index c6476453d23efdff5a3306c53ae4437085084cb4..b40be104933f9a1b4be3f219127c4a7554a72dd5 100644
--- a/Framework/Algorithms/test/MaskBinsFromTableTest.h
+++ b/Framework/Algorithms/test/MaskBinsFromTableTest.h
@@ -36,7 +36,7 @@ public:
     const std::string workspaceName("raggedMask");
     int nBins = 10;
     MatrixWorkspace_sptr WS =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(5, nBins, 0.0);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(5, nBins, 0.0);
     AnalysisDataService::Instance().add(workspaceName, WS);
 
     // 2. Generate a TableWorskpace
@@ -84,7 +84,7 @@ public:
     const std::string opWSName("maskedWorkspace");
     int nBins = 10;
     MatrixWorkspace_sptr WS =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(5, nBins, 0.0);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(5, nBins, 0.0);
     AnalysisDataService::Instance().add(workspaceName, WS);
 
     // 2. Generate a TableWorskpace
@@ -134,7 +134,7 @@ public:
     int nBins = 10;
     int nHist = 12;
     MatrixWorkspace_sptr WS =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(nHist, nBins, 0.0);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(nHist, nBins, 0.0);
     AnalysisDataService::Instance().add(workspaceName, WS);
 
     // 2. Generate a TableWorskpace
@@ -221,7 +221,7 @@ public:
     const std::string workspaceName("raggedMask");
     int nBins = 10;
     MatrixWorkspace_sptr WS =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(5, nBins, 0.0);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(5, nBins, 0.0);
     AnalysisDataService::Instance().add(workspaceName, WS);
 
     // 2. Generate a TableWorskpace
@@ -268,7 +268,7 @@ public:
     const std::string workspaceName("raggedMask5");
     int nBins = 10;
     MatrixWorkspace_sptr dataws =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(5, nBins, 0.0);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(5, nBins, 0.0);
     AnalysisDataService::Instance().add(workspaceName, dataws);
 
     // Find out mapping between spectra/workspace indexes and detectors IDs
diff --git a/Framework/Algorithms/test/MaskBinsTest.h b/Framework/Algorithms/test/MaskBinsTest.h
index 4b8e92be5af2fa6bc7eb988b273be47982b1342d..400cc908631288871159a671c675033d3a9ed160 100644
--- a/Framework/Algorithms/test/MaskBinsTest.h
+++ b/Framework/Algorithms/test/MaskBinsTest.h
@@ -5,7 +5,6 @@
 #include <cxxtest/TestSuite.h>
 
 #include "MantidAlgorithms/MaskBins.h"
-#include "MantidDataHandling/LoadEventPreNexus.h"
 #include "MantidDataObjects/EventList.h"
 #include "MantidDataObjects/EventWorkspace.h"
 
@@ -34,7 +33,7 @@ public:
     const std::string resultWorkspaceName("masked");
     AnalysisDataServiceImpl &ads = AnalysisDataService::Instance();
     ads.add(workspaceName,
-            WorkspaceCreationHelper::Create2DWorkspaceBinned(5, 25, 0.0));
+            WorkspaceCreationHelper::create2DWorkspaceBinned(5, 25, 0.0));
 
     TS_ASSERT_THROWS_NOTHING(
         masker.setPropertyValue("InputWorkspace", workspaceName));
@@ -90,7 +89,7 @@ public:
     // Create a dummy workspace
     const std::string workspaceName("raggedMask");
     MatrixWorkspace_sptr WS =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(3, 10, 0.0);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(3, 10, 0.0);
     // Now change one set of bin boundaries so that the don't match the others
     WS->mutableX(1) += -10;
     AnalysisDataService::Instance().add(workspaceName, WS);
@@ -129,7 +128,7 @@ public:
     // Create a dummy workspace
     const std::string workspaceName("raggedMask");
     MatrixWorkspace_sptr WS =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(10, 10, 0.0);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(10, 10, 0.0);
     AnalysisDataService::Instance().add(workspaceName, WS);
 
     Mantid::Algorithms::MaskBins masker2;
@@ -150,7 +149,7 @@ public:
     const std::string workspaceName("raggedMask");
     int nBins = 10;
     MatrixWorkspace_sptr WS =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(5, nBins, 0.0);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(5, nBins, 0.0);
     AnalysisDataService::Instance().add(workspaceName, WS);
 
     Mantid::Algorithms::MaskBins masker2;
@@ -182,7 +181,7 @@ public:
 
     int nBins = 10;
     MatrixWorkspace_sptr WS =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(5, nBins, 0.0);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(5, nBins, 0.0);
     AnalysisDataService::Instance().add(workspaceName, WS);
 
     Mantid::Algorithms::MaskBins masker2;
@@ -224,7 +223,7 @@ public:
     int nBins = 10;
     int numHist = 5;
     EventWorkspace_sptr WS =
-        WorkspaceCreationHelper::CreateEventWorkspace(numHist, nBins);
+        WorkspaceCreationHelper::createEventWorkspace(numHist, nBins);
     AnalysisDataService::Instance().add(workspaceName, WS);
 
     Mantid::Algorithms::MaskBins masker2;
@@ -259,7 +258,7 @@ public:
     int nBins = 10;
     int numHist = 5;
     EventWorkspace_sptr WS =
-        WorkspaceCreationHelper::CreateEventWorkspace(numHist, nBins);
+        WorkspaceCreationHelper::createEventWorkspace(numHist, nBins);
     AnalysisDataService::Instance().add(workspaceName, WS);
 
     Mantid::Algorithms::MaskBins masker2;
@@ -299,7 +298,7 @@ public:
     int nBins = 10;
     int numHist = 5;
     EventWorkspace_sptr WS =
-        WorkspaceCreationHelper::CreateEventWorkspace(numHist, nBins);
+        WorkspaceCreationHelper::createEventWorkspace(numHist, nBins);
     AnalysisDataService::Instance().add(workspaceName, WS);
     std::size_t events_before = WS->getNumberEvents();
 
@@ -334,7 +333,7 @@ public:
     int nBins = 10;
     int numHist = 5;
     EventWorkspace_sptr WS =
-        WorkspaceCreationHelper::CreateEventWorkspace(numHist, nBins);
+        WorkspaceCreationHelper::createEventWorkspace(numHist, nBins);
     AnalysisDataService::Instance().add(workspaceName, WS);
     std::size_t events_before = WS->getNumberEvents();
 
diff --git a/Framework/Algorithms/test/MaskDetectorsIfTest.h b/Framework/Algorithms/test/MaskDetectorsIfTest.h
new file mode 100644
index 0000000000000000000000000000000000000000..b9c5718309f0d56731b3fd980ec7970521ca3b5a
--- /dev/null
+++ b/Framework/Algorithms/test/MaskDetectorsIfTest.h
@@ -0,0 +1,240 @@
+#ifndef MASKDETECTORSIFTEST_H_
+#define MASKDETECTORSIFTEST_H_
+
+#include <cxxtest/TestSuite.h>
+
+#include "MantidAlgorithms/MaskDetectorsIf.h"
+#include "MantidAPI/MatrixWorkspace.h"
+#include "MantidTestHelpers/ScopedFileHelper.h"
+#include "MantidTestHelpers/WorkspaceCreationHelper.h"
+#include <Poco/File.h>
+#include <fstream>
+
+using namespace Mantid;
+using namespace Mantid::Algorithms;
+using namespace Mantid::API;
+using ScopedFileHelper::ScopedFile;
+
+class MaskDetectorsIfTest : public CxxTest::TestSuite {
+public:
+  // This pair of boilerplate methods prevent the suite being created statically
+  // This means the constructor isn't called when running other tests
+  static MaskDetectorsIfTest *createSuite() {
+    return new MaskDetectorsIfTest();
+  }
+  static void destroySuite(MaskDetectorsIfTest *suite) { delete suite; }
+
+  void testDeselectIfNotEqual() {
+    // setup and run the algorithm (includes basic checks)
+    MaskDetectorsIf alg;
+    setupAlgorithm(alg, "DeselectIf", "NotEqual", 2.2);
+    std::ifstream file;
+    runAlgorithm(alg, file);
+
+    // specific checks
+    if (file.is_open()) {
+      readAndCheckLine(file, 0, 4, 0.0, 0, 1); // 2.0
+      readAndCheckLine(file, 1, 5, 0.0, 0, 1); // 2.1
+      readAndCheckLine(file, 2, 6, 0.0, 1, 2); // 2.2
+      readAndCheckLine(file, 3, 7, 0.0, 0, 2); // 2.3
+      file.close();
+    }
+  }
+
+  void testDeselectIfLess() {
+    // setup and run the algorithm (includes basic checks)
+    MaskDetectorsIf alg;
+    setupAlgorithm(alg, "DeselectIf", "Less", 2.2);
+    std::ifstream file;
+    runAlgorithm(alg, file);
+
+    // specific checks
+    if (file.is_open()) {
+      readAndCheckLine(file, 0, 4, 0.0, 0, 1); // 2.0
+      readAndCheckLine(file, 1, 5, 0.0, 0, 1); // 2.1
+      readAndCheckLine(file, 2, 6, 0.0, 1, 2); // 2.2
+      readAndCheckLine(file, 3, 7, 0.0, 1, 2); // 2.3
+      file.close();
+    }
+  }
+
+  void testDeselectIfLessEqual() {
+    // setup and run the algorithm (includes basic checks)
+    MaskDetectorsIf alg;
+    setupAlgorithm(alg, "DeselectIf", "LessEqual", 2.2);
+    std::ifstream file;
+    runAlgorithm(alg, file);
+
+    // specific checks
+    if (file.is_open()) {
+      readAndCheckLine(file, 0, 4, 0.0, 0, 1); // 2.0
+      readAndCheckLine(file, 1, 5, 0.0, 0, 1); // 2.1
+      readAndCheckLine(file, 2, 6, 0.0, 0, 2); // 2.2
+      readAndCheckLine(file, 3, 7, 0.0, 1, 2); // 2.3
+      file.close();
+    }
+  }
+
+  void testDeselectIfGreater() {
+    // setup and run the algorithm (includes basic checks)
+    MaskDetectorsIf alg;
+    setupAlgorithm(alg, "DeselectIf", "Greater", 2.2);
+    std::ifstream file;
+    runAlgorithm(alg, file);
+
+    // specific checks
+    if (file.is_open()) {
+      readAndCheckLine(file, 0, 4, 0.0, 1, 1); // 2.0
+      readAndCheckLine(file, 1, 5, 0.0, 1, 1); // 2.1
+      readAndCheckLine(file, 2, 6, 0.0, 1, 2); // 2.2
+      readAndCheckLine(file, 3, 7, 0.0, 0, 2); // 2.3
+      file.close();
+    }
+  }
+
+  void testDeselectIfGreaterEqual() {
+    // setup and run the algorithm (includes basic checks)
+    MaskDetectorsIf alg;
+    setupAlgorithm(alg, "DeselectIf", "GreaterEqual", 2.2);
+    std::ifstream file;
+    runAlgorithm(alg, file);
+
+    // specific checks
+    if (file.is_open()) {
+      readAndCheckLine(file, 0, 4, 0.0, 1, 1); // 2.0
+      readAndCheckLine(file, 1, 5, 0.0, 1, 1); // 2.1
+      readAndCheckLine(file, 2, 6, 0.0, 0, 2); // 2.2
+      readAndCheckLine(file, 3, 7, 0.0, 0, 2); // 2.3
+      file.close();
+    }
+  }
+
+  void testSelectIfEqual() {
+    // Create an input file where the detectors are all deselected
+    // initially (so we can tell whether the SelectIf worked).
+    ScopedFile inputFile = makeFakeInputFile();
+
+    // setup and run the algorithm (includes basic checks)
+    MaskDetectorsIf alg;
+    setupAlgorithm(alg, "SelectIf", "Equal", 2.2, inputFile.getFileName());
+    std::ifstream file;
+    runAlgorithm(alg, file);
+
+    // specific checks
+    if (file.is_open()) {
+      readAndCheckLine(file, 0, 4, 0.0, 0, 1); // 2.0
+      readAndCheckLine(file, 1, 5, 0.0, 0, 1); // 2.1
+      readAndCheckLine(file, 2, 6, 0.0, 1, 2); // 2.2
+      readAndCheckLine(file, 3, 7, 0.0, 0, 2); // 2.3
+      file.close();
+    }
+  }
+
+private:
+  // Create a fake input file. This is the same as
+  // 4detector_cal_example_file.cal but with all the detectors deselected.
+  ScopedFile makeFakeInputFile() {
+    std::ostringstream os;
+
+    os << "# Ariel detector file, written Sat Nov 24 16:52:56 2007\n";
+    os << "# Format: number  UDET offset  select  group\n";
+    os << "0          4  0.0000000  0    1\n";
+    os << "1          5  0.0000000  0    1\n";
+    os << "2          6  0.0000000  0    2\n";
+    os << "3          7  0.0000000  0    2\n";
+
+    return ScopedFile(os.str(), "MaskDetectorsIfTestInput.cal");
+  }
+
+  const MatrixWorkspace_sptr makeFakeWorkspace() {
+    // create the workspace
+    MatrixWorkspace_sptr ws =
+        WorkspaceCreationHelper::create2DWorkspaceWithRectangularInstrument(
+            1, 2, 1);
+
+    // Default y values are all 2.0. Change them so they're different
+    // for each spectrum (this gives us the values 2.0, 2.1, 2.2, ...)
+    for (size_t wi = 0; wi < ws->getNumberHistograms(); ++wi) {
+      ws->mutableY(wi)[0] += static_cast<double>(wi) * 0.1;
+    }
+
+    return ws;
+  }
+
+  // Initialise the algorithm and set the properties. Creates a fake
+  // workspace for the input.
+  void setupAlgorithm(
+      MaskDetectorsIf &alg, const std::string &mode, const std::string &op,
+      const double value,
+      const std::string &inputFile = "4detector_cal_example_file.cal") {
+    // create the workspace
+    const MatrixWorkspace_sptr inWS = makeFakeWorkspace();
+
+    // set up the algorithm
+    if (!alg.isInitialized())
+      alg.initialize();
+    alg.setProperty("InputWorkspace", inWS);
+    alg.setProperty("InputCalFile", inputFile);
+    alg.setProperty("Mode", mode);
+    alg.setProperty("Operator", op);
+    alg.setProperty("Value", value);
+    alg.setProperty("OutputCalFile", "MaskDetectorsIfTestOutput.cal");
+  }
+
+  // Run the algorithm and do some basic checks. Opens the output file
+  // stream if everything is ok (leaves it closed if not).
+  void runAlgorithm(MaskDetectorsIf &alg, std::ifstream &outFile) {
+    // run the algorithm
+    TS_ASSERT_THROWS_NOTHING(alg.execute());
+    TS_ASSERT(alg.isExecuted());
+
+    // check that the algorithm has written a file to disk
+    std::string outputFile = alg.getProperty("OutputCalFile");
+    bool fileExists = false;
+    TS_ASSERT(fileExists = Poco::File(outputFile).exists());
+
+    // check that we can open the file
+    if (fileExists) {
+      outFile.open(outputFile.c_str());
+      TS_ASSERT(outFile.is_open());
+
+      // skip the header, and check that there is still content left
+      if (outFile.is_open()) {
+        skipHeader(outFile);
+        TS_ASSERT(!outFile.eof());
+
+        if (outFile.eof())
+          outFile.close();
+      }
+    }
+  }
+
+  void skipHeader(std::ifstream &file) {
+    // our test file has 2 lines in the header
+    std::string line;
+    for (int i = 0; i < 2 && !file.eof(); ++i) {
+      std::getline(file, line);
+    }
+  }
+
+  // Read the next line from the given file and check
+  // that the values match those given.
+  void readAndCheckLine(std::ifstream &file, const int num, const int udet,
+                        const double offset, const int select,
+                        const int group) {
+    TS_ASSERT(!file.eof());
+
+    if (!file.eof()) {
+      int i1, i2, i3, i4;
+      double d1;
+      file >> i1 >> i2 >> d1 >> i3 >> i4;
+      TS_ASSERT_EQUALS(i1, num);
+      TS_ASSERT_EQUALS(i2, udet);
+      TS_ASSERT_DELTA(d1, offset, 1e-06);
+      TS_ASSERT_EQUALS(i3, select);
+      TS_ASSERT_EQUALS(i4, group);
+    }
+  }
+};
+
+#endif /*MASKDETECTORSIFTEST_H_*/
diff --git a/Framework/Algorithms/test/MaxEntTest.h b/Framework/Algorithms/test/MaxEntTest.h
index 0f4a83f63435ff3b1c2668faaee945e4af2a9a33..54777091115be58d830efe04902042e1b2ac422e 100644
--- a/Framework/Algorithms/test/MaxEntTest.h
+++ b/Framework/Algorithms/test/MaxEntTest.h
@@ -7,6 +7,7 @@
 #include "MantidAPI/FrameworkManager.h"
 #include "MantidAPI/TextAxis.h"
 #include "MantidAPI/WorkspaceFactory.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidAlgorithms/MaxEnt.h"
 #include "MantidKernel/UnitFactory.h"
 #include "MantidTestHelpers/WorkspaceCreationHelper.h"
@@ -44,7 +45,7 @@ public:
     // Run one iteration, we just want to test the output workspaces' dimensions
     int nHist = 5;
     int nBins = 10;
-    auto ws = WorkspaceCreationHelper::Create2DWorkspace(nHist, nBins);
+    auto ws = WorkspaceCreationHelper::create2DWorkspace(nHist, nBins);
 
     IAlgorithm_sptr alg = AlgorithmManager::Instance().create("MaxEnt");
     alg->initialize();
@@ -78,7 +79,7 @@ public:
     // Run one iteration, we just want to test the output workspaces' dimensions
     int nHist = 6;
     int nBins = 10;
-    auto ws = WorkspaceCreationHelper::Create2DWorkspace(nHist, nBins);
+    auto ws = WorkspaceCreationHelper::create2DWorkspace(nHist, nBins);
 
     IAlgorithm_sptr alg = AlgorithmManager::Instance().create("MaxEnt");
     alg->initialize();
@@ -111,7 +112,7 @@ public:
 
   void test_bad_complex_data() {
 
-    auto ws = WorkspaceCreationHelper::Create2DWorkspace(5, 10);
+    auto ws = WorkspaceCreationHelper::create2DWorkspace(5, 10);
 
     IAlgorithm_sptr alg = AlgorithmManager::Instance().create("MaxEnt");
     alg->initialize();
@@ -421,9 +422,9 @@ public:
    */
   void testValidateInputsWithWSGroup() {
     auto ws1 = boost::static_pointer_cast<Workspace>(
-        WorkspaceCreationHelper::Create2DWorkspace(5, 10));
+        WorkspaceCreationHelper::create2DWorkspace(5, 10));
     auto ws2 = boost::static_pointer_cast<Workspace>(
-        WorkspaceCreationHelper::Create2DWorkspace(5, 10));
+        WorkspaceCreationHelper::create2DWorkspace(5, 10));
     AnalysisDataService::Instance().add("workspace1", ws1);
     AnalysisDataService::Instance().add("workspace2", ws2);
     auto group = boost::make_shared<WorkspaceGroup>();
@@ -656,7 +657,7 @@ public:
   static void destroySuite(MaxEntTestPerformance *suite) { delete suite; }
 
   MaxEntTestPerformance() {
-    input = WorkspaceCreationHelper::Create2DWorkspaceBinned(10000, 100);
+    input = WorkspaceCreationHelper::create2DWorkspaceBinned(10000, 100);
     alg = AlgorithmManager::Instance().create("MaxEnt");
   }
 
diff --git a/Framework/Algorithms/test/MaxMinTest.h b/Framework/Algorithms/test/MaxMinTest.h
index c1e57993479048a2dad2e4418320181d73718b9b..fdbcfa4144b53551b20c937abd396f692a2edf4d 100644
--- a/Framework/Algorithms/test/MaxMinTest.h
+++ b/Framework/Algorithms/test/MaxMinTest.h
@@ -1,6 +1,7 @@
 #ifndef MAXMINTEST_H_
 #define MAXMINTEST_H_
 
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAlgorithms/CreateWorkspace.h"
 #include "MantidAlgorithms/Max.h"
diff --git a/Framework/Algorithms/test/MayersSampleCorrectionStrategyTest.h b/Framework/Algorithms/test/MayersSampleCorrectionStrategyTest.h
index 60ddd593b217a45fc7d873e8e5536e5e345202fc..750b2f7b61e94d7715847af29cfddd8cf7f113fc 100644
--- a/Framework/Algorithms/test/MayersSampleCorrectionStrategyTest.h
+++ b/Framework/Algorithms/test/MayersSampleCorrectionStrategyTest.h
@@ -8,6 +8,8 @@
 #include <algorithm>
 #include <cmath>
 
+#include <iomanip>
+
 using Mantid::Algorithms::MayersSampleCorrectionStrategy;
 using namespace Mantid::HistogramData;
 
@@ -50,8 +52,7 @@ public:
                     Counts(nypts, 2.0));
     MayersSampleCorrectionStrategy mscat(createTestParameters(), histo);
 
-    auto outHisto = mscat.getCorrectedHisto();
-
+    const auto outHisto = mscat.getCorrectedHisto();
     const auto &tof = outHisto.x();
     const auto &signal = outHisto.y();
     const auto &error = outHisto.e();
@@ -75,8 +76,7 @@ public:
                     Counts(nypts, 2.0));
     MayersSampleCorrectionStrategy mscat(createTestParameters(), histo);
 
-    auto outHisto = mscat.getCorrectedHisto();
-
+    const auto outHisto = mscat.getCorrectedHisto();
     const auto &tof = outHisto.x();
     const auto &signal = outHisto.y();
     const auto &error = outHisto.e();
@@ -95,7 +95,7 @@ public:
 
   void test_Corrects_For_Absorption_For_Histogram_Data() {
     const size_t nypts(100);
-    bool mscatOn(false);
+    const bool mscatOn(false);
     Histogram histo(BinEdges(nypts + 1, LinearGenerator(99.5, 1.0)),
                     Counts(nypts, 2.0));
     MayersSampleCorrectionStrategy mscat(createTestParameters(mscatOn), histo);
@@ -118,6 +118,60 @@ public:
     TS_ASSERT_DELTA(1.6609527, error.back(), delta);
   }
 
+  void test_MutlipleScattering_NEvents_Parameter() {
+    const size_t nypts(100);
+    Histogram histo(BinEdges(nypts + 1, LinearGenerator(99.5, 1.0)),
+                    Counts(nypts, 2.0));
+    const bool mscatOn(true);
+    auto corrPars = createTestParameters(mscatOn);
+    corrPars.msNEvents = 1000;
+    MayersSampleCorrectionStrategy mscat(corrPars, histo);
+
+    const auto outHisto = mscat.getCorrectedHisto();
+    const auto tof = outHisto.x();
+    const auto signal = outHisto.y();
+    const auto error = outHisto.e();
+
+    // Check some values
+    // Check some values
+    const double delta(1e-06);
+    TS_ASSERT_DELTA(99.5, tof.front(), delta);
+    TS_ASSERT_DELTA(199.5, tof.back(), delta);
+
+    TS_ASSERT_DELTA(0.37553636, signal.front(), delta);
+    TS_ASSERT_DELTA(0.37554482, signal.back(), delta);
+
+    TS_ASSERT_DELTA(0.26554431, error.front(), delta);
+    TS_ASSERT_DELTA(0.26555029, error.back(), delta);
+  }
+
+  void test_MutlipleScattering_NRuns_Parameter() {
+    const size_t nypts(100);
+    Histogram histo(BinEdges(nypts + 1, LinearGenerator(99.5, 1.0)),
+                    Counts(nypts, 2.0));
+    const bool mscatOn(true);
+    auto corrPars = createTestParameters(mscatOn);
+    corrPars.msNRuns = 2;
+    MayersSampleCorrectionStrategy mscat(corrPars, histo);
+
+    const auto outHisto = mscat.getCorrectedHisto();
+    const auto tof = outHisto.x();
+    const auto signal = outHisto.y();
+    const auto error = outHisto.e();
+
+    // Check some values
+    // Check some values
+    const double delta(1e-06);
+    TS_ASSERT_DELTA(99.5, tof.front(), delta);
+    TS_ASSERT_DELTA(199.5, tof.back(), delta);
+
+    TS_ASSERT_DELTA(0.37376334, signal.front(), delta);
+    TS_ASSERT_DELTA(0.37123648, signal.back(), delta);
+
+    TS_ASSERT_DELTA(0.26429059, error.front(), delta);
+    TS_ASSERT_DELTA(0.26250383, error.back(), delta);
+  }
+
   // ---------------------- Failure tests -----------------------------
   void test_Tof_Not_Monotonically_Increasing_Throws_Invalid_Argument() {
     const size_t nypts(10);
@@ -138,12 +192,14 @@ private:
     pars.l1 = 14.0;
     pars.l2 = 2.2;
     pars.twoTheta = 0.10821;
-    pars.phi = 0.0;
+    pars.azimuth = 0.0;
     pars.rho = 0.07261;
     pars.sigmaSc = 5.1;
     pars.sigmaAbs = 5.08;
     pars.cylRadius = 0.0025;
     pars.cylHeight = 0.04;
+    pars.msNEvents = 10000;
+    pars.msNRuns = 10;
     return pars;
   }
 };
diff --git a/Framework/Algorithms/test/MayersSampleCorrectionTest.h b/Framework/Algorithms/test/MayersSampleCorrectionTest.h
index cf786e43669ae71563d47ad806add42c0c10b9bc..8f52899a1c4c2f3fb7fa9204d7c4e51ed78a2995 100644
--- a/Framework/Algorithms/test/MayersSampleCorrectionTest.h
+++ b/Framework/Algorithms/test/MayersSampleCorrectionTest.h
@@ -41,11 +41,11 @@ public:
     TS_ASSERT_DELTA(99.5, tof.front(), delta);
     TS_ASSERT_DELTA(199.5, tof.back(), delta);
 
-    TS_ASSERT_DELTA(0.37497317, signal.front(), delta);
-    TS_ASSERT_DELTA(0.37629282, signal.back(), delta);
+    TS_ASSERT_DELTA(0.37666067, signal.front(), delta);
+    TS_ASSERT_DELTA(0.37553044, signal.back(), delta);
 
-    TS_ASSERT_DELTA(0.26514607, error.front(), delta);
-    TS_ASSERT_DELTA(0.2660792, error.back(), delta);
+    TS_ASSERT_DELTA(0.26633931, error.front(), delta);
+    TS_ASSERT_DELTA(0.26554012, error.back(), delta);
   }
 
   void test_Success_With_Just_Absorption_Correction() {
@@ -96,6 +96,8 @@ private:
     alg->initialize();
     alg->setProperty("InputWorkspace", inputWS);
     alg->setProperty("MultipleScattering", mscatOn);
+    alg->setProperty("MSEvents", 2000);
+    alg->setProperty("MSRuns", 5);
     alg->setPropertyValue("OutputWorkspace", "_unused_for_child");
     alg->execute();
     return alg;
@@ -109,12 +111,12 @@ private:
     using Mantid::Kernel::Material;
     using Mantid::Kernel::V3D;
     using Mantid::PhysicalConstants::getNeutronAtom;
-    using WorkspaceCreationHelper::Create2DWorkspaceBinned;
+    using WorkspaceCreationHelper::create2DWorkspaceBinned;
 
     const int nhist(1), nbins(100);
     const double xstart(99.5), deltax(1.0);
     // Filled Y with 2.0 and E with sqrt(2)
-    auto testWS = Create2DWorkspaceBinned(nhist, nbins, xstart, deltax);
+    auto testWS = create2DWorkspaceBinned(nhist, nbins, xstart, deltax);
 
     const int nbanks(1);
     // Ids 1->9
@@ -147,7 +149,7 @@ private:
   MatrixWorkspace_sptr createTestWorkspaceWithNoInstrument() {
     const int nhist(1), nbins(1);
     const double xstart(99.5), deltax(1.0);
-    return WorkspaceCreationHelper::Create2DWorkspaceBinned(nhist, nbins,
+    return WorkspaceCreationHelper::create2DWorkspaceBinned(nhist, nbins,
                                                             xstart, deltax);
   }
 
@@ -156,11 +158,11 @@ private:
     using Mantid::Geometry::ObjComponent;
     using Mantid::Geometry::Object;
     using Mantid::Kernel::V3D;
-    using WorkspaceCreationHelper::Create2DWorkspaceBinned;
+    using WorkspaceCreationHelper::create2DWorkspaceBinned;
 
     const int nhist(1), nbins(1);
     const double xstart(99.5), deltax(1.0);
-    auto testWS = Create2DWorkspaceBinned(nhist, nbins, xstart, deltax);
+    auto testWS = create2DWorkspaceBinned(nhist, nbins, xstart, deltax);
 
     const int nbanks(1);
     auto testInst = createTestInstrumentCylindrical(nbanks, V3D(0., 0., -14.));
diff --git a/Framework/Algorithms/test/MedianDetectorTestTest.h b/Framework/Algorithms/test/MedianDetectorTestTest.h
index 01666e3928ab782fc1a1a05cc380f48ec83ea72f..474e58505f4663e873a2d6225861f505cfb52540 100644
--- a/Framework/Algorithms/test/MedianDetectorTestTest.h
+++ b/Framework/Algorithms/test/MedianDetectorTestTest.h
@@ -9,10 +9,10 @@
 #include "MantidKernel/UnitFactory.h"
 #include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Axis.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidDataObjects/Workspace2D.h"
 #include "MantidDataHandling/LoadInstrument.h"
-//#include "MantidDataHandling/LoadEmptyInstrument.h"
 #include <boost/shared_ptr.hpp>
 #include <boost/lexical_cast.hpp>
 #include <Poco/File.h>
@@ -71,7 +71,6 @@ public:
     input =
         AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(m_IWSName);
     TS_ASSERT(input);
-    // TS_ASSERT(input->getInstrument()->isDetectorMasked(input->getSpectrum(THEMASKED).getDetectorIDs()));
 
     MatrixWorkspace_sptr outputMat =
         boost::dynamic_pointer_cast<MatrixWorkspace>(output);
@@ -213,8 +212,6 @@ public:
 
       m_2DWS->setCounts(j, spectrum);
       m_2DWS->setCountStandardDeviations(j, errors);
-      // Just set the spectrum number to match the index
-      m_2DWS->getSpectrum(j).setSpectrumNo(j + 1);
     }
 
     // Register the workspace in the data service
@@ -233,7 +230,8 @@ public:
     m_2DWS->getAxis(0)->unit() = UnitFactory::Instance().create("TOF");
 
     // mask the detector
-    m_2DWS->maskWorkspaceIndex(THEMASKED);
+    m_2DWS->getSpectrum(THEMASKED).clearData();
+    m_2DWS->mutableSpectrumInfo().setMasked(THEMASKED, true);
   }
 
 private:
diff --git a/Framework/Algorithms/test/MergeRunsTest.h b/Framework/Algorithms/test/MergeRunsTest.h
index 8a6c76ae12501d6da3e410d985f3529f6fd74e07..3666a269bb4b7ba96ba6509a42449e9e6b5f4227 100644
--- a/Framework/Algorithms/test/MergeRunsTest.h
+++ b/Framework/Algorithms/test/MergeRunsTest.h
@@ -13,7 +13,6 @@
 #include "MantidAlgorithms/GroupWorkspaces.h"
 #include "MantidAlgorithms/MergeRuns.h"
 #include "MantidAlgorithms/GroupWorkspaces.h"
-#include "MantidDataHandling/LoadEventPreNexus.h"
 #include "MantidGeometry/Instrument.h"
 #include "MantidAPI/AnalysisDataService.h"
 #include "MantidKernel/TimeSeriesProperty.h"
@@ -27,8 +26,6 @@ using namespace Mantid::Algorithms;
 using namespace Mantid::DataObjects;
 using namespace Mantid::Geometry;
 using namespace Mantid::Kernel;
-using Mantid::DataHandling::LoadEventPreNexus;
-
 class MergeRunsTest : public CxxTest::TestSuite {
 
 private:
@@ -55,9 +52,9 @@ private:
   /// matrixworkspaces. BUT WITHOUT MULTIPERIOD LOGS.
   WorkspaceGroup_sptr create_good_workspace_group() {
     MatrixWorkspace_sptr a =
-        WorkspaceCreationHelper::Create2DWorkspace123(3, 10, 1);
+        WorkspaceCreationHelper::create2DWorkspace123(3, 10, 1);
     MatrixWorkspace_sptr b =
-        WorkspaceCreationHelper::Create2DWorkspace123(3, 10, 1);
+        WorkspaceCreationHelper::create2DWorkspace123(3, 10, 1);
     // a->setName("a1");
     // b->setName("b1");
     WorkspaceGroup_sptr group = boost::make_shared<WorkspaceGroup>();
@@ -74,9 +71,9 @@ private:
   /// matrixworkspaces. BUT WITHOUT MULTIPERIOD LOGS AT ZERO.
   WorkspaceGroup_sptr create_good_zerod_multiperiod_workspace_group() {
     MatrixWorkspace_sptr a =
-        WorkspaceCreationHelper::Create2DWorkspace123(3, 10, 1);
+        WorkspaceCreationHelper::create2DWorkspace123(3, 10, 1);
     MatrixWorkspace_sptr b =
-        WorkspaceCreationHelper::Create2DWorkspace123(3, 10, 1);
+        WorkspaceCreationHelper::create2DWorkspace123(3, 10, 1);
     // a->setName("a2");
     // b->setName("b2");
     WorkspaceGroup_sptr group = boost::make_shared<WorkspaceGroup>();
@@ -99,9 +96,9 @@ private:
   /// 5
   WorkspaceGroup_sptr create_corrupted_multiperiod_workspace_group() {
     MatrixWorkspace_sptr a =
-        WorkspaceCreationHelper::Create2DWorkspace123(3, 10, 1);
+        WorkspaceCreationHelper::create2DWorkspace123(3, 10, 1);
     MatrixWorkspace_sptr b =
-        WorkspaceCreationHelper::Create2DWorkspace123(3, 10, 1);
+        WorkspaceCreationHelper::create2DWorkspace123(3, 10, 1);
     // a->setName("a4");
     // b->setName("b4");
     WorkspaceGroup_sptr group = boost::make_shared<WorkspaceGroup>();
@@ -124,9 +121,9 @@ private:
   /// matrixworkspaces.
   WorkspaceGroup_sptr create_good_multiperiod_workspace_group() {
     MatrixWorkspace_sptr a =
-        WorkspaceCreationHelper::Create2DWorkspace123(3, 10, 1);
+        WorkspaceCreationHelper::create2DWorkspace123(3, 10, 1);
     MatrixWorkspace_sptr b =
-        WorkspaceCreationHelper::Create2DWorkspace123(3, 10, 1);
+        WorkspaceCreationHelper::create2DWorkspace123(3, 10, 1);
     // a->setName("a3");
     // b->setName("b3");
     WorkspaceGroup_sptr group = boost::make_shared<WorkspaceGroup>();
@@ -234,7 +231,7 @@ private:
     MergeRuns alg;
     alg.initialize();
     TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue(
-        "InputWorkspaces", input->name() + "," + input->name()));
+        "InputWorkspaces", input->getName() + "," + input->getName()));
     TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("OutputWorkspace", "out"));
     TS_ASSERT_THROWS_NOTHING(alg.execute());
     MatrixWorkspace_sptr wsOut = Mantid::API::AnalysisDataService::Instance()
@@ -263,17 +260,17 @@ public:
 
   MergeRunsTest() {
     AnalysisDataService::Instance().add(
-        "in1", WorkspaceCreationHelper::Create2DWorkspaceBinned(3, 10, 1));
+        "in1", WorkspaceCreationHelper::create2DWorkspaceBinned(3, 10, 1));
     AnalysisDataService::Instance().add(
-        "in2", WorkspaceCreationHelper::Create2DWorkspaceBinned(3, 10, 1));
+        "in2", WorkspaceCreationHelper::create2DWorkspaceBinned(3, 10, 1));
     AnalysisDataService::Instance().add(
-        "in3", WorkspaceCreationHelper::Create2DWorkspaceBinned(3, 10, 1));
+        "in3", WorkspaceCreationHelper::create2DWorkspaceBinned(3, 10, 1));
     AnalysisDataService::Instance().add(
-        "in4", WorkspaceCreationHelper::Create2DWorkspaceBinned(3, 5, 20));
+        "in4", WorkspaceCreationHelper::create2DWorkspaceBinned(3, 5, 20));
     AnalysisDataService::Instance().add(
-        "in5", WorkspaceCreationHelper::Create2DWorkspaceBinned(3, 5, 3.5, 2));
+        "in5", WorkspaceCreationHelper::create2DWorkspaceBinned(3, 5, 3.5, 2));
     AnalysisDataService::Instance().add(
-        "in6", WorkspaceCreationHelper::Create2DWorkspaceBinned(3, 3, 2, 2));
+        "in6", WorkspaceCreationHelper::create2DWorkspaceBinned(3, 3, 2, 2));
   }
 
   void checkOutput(std::string wsname) {
@@ -334,48 +331,48 @@ public:
 
   void EventSetup() {
     ev1 =
-        WorkspaceCreationHelper::CreateEventWorkspace(3, 10, 100, 0.0, 1.0, 3);
+        WorkspaceCreationHelper::createEventWorkspace(3, 10, 100, 0.0, 1.0, 3);
     AnalysisDataService::Instance().addOrReplace(
         "ev1", boost::dynamic_pointer_cast<MatrixWorkspace>(ev1)); // 100 ev
     AnalysisDataService::Instance().addOrReplace(
         "ev2", boost::dynamic_pointer_cast<MatrixWorkspace>(
-                   WorkspaceCreationHelper::CreateEventWorkspace(
+                   WorkspaceCreationHelper::createEventWorkspace(
                        3, 10, 100, 0.0, 1.0, 2))); // 200 ev
     AnalysisDataService::Instance().addOrReplace(
         "ev3", boost::dynamic_pointer_cast<MatrixWorkspace>(
-                   WorkspaceCreationHelper::CreateEventWorkspace(
+                   WorkspaceCreationHelper::createEventWorkspace(
                        3, 10, 100, 0.0, 1.0, 2, 100))); // 200 events per
                                                         // spectrum, but the
                                                         // spectra are at
                                                         // different pixel ids
     // Make one with weird units
     MatrixWorkspace_sptr ev4 = boost::dynamic_pointer_cast<MatrixWorkspace>(
-        WorkspaceCreationHelper::CreateEventWorkspace(3, 10, 100, 0.0, 1.0, 2,
+        WorkspaceCreationHelper::createEventWorkspace(3, 10, 100, 0.0, 1.0, 2,
                                                       100));
     ev4->setYUnit("Microfurlongs per Megafortnights");
     AnalysisDataService::Instance().addOrReplace("ev4_weird_units", ev4);
     AnalysisDataService::Instance().addOrReplace(
         "ev5", boost::dynamic_pointer_cast<MatrixWorkspace>(
-                   WorkspaceCreationHelper::CreateEventWorkspace(
+                   WorkspaceCreationHelper::createEventWorkspace(
                        5, 10, 100, 0.0, 1.0, 2, 100))); // 200 events per
                                                         // spectrum, but the
                                                         // spectra are at
                                                         // different pixel ids
-    ev6 = WorkspaceCreationHelper::CreateEventWorkspace(6, 10, 100, 0.0, 1.0,
+    ev6 = WorkspaceCreationHelper::createEventWorkspace(6, 10, 100, 0.0, 1.0,
                                                         3); // ids 0-5
     AnalysisDataService::Instance().addOrReplace(
         "ev6", boost::dynamic_pointer_cast<MatrixWorkspace>(ev6));
     // a 2d workspace with the value 2 in each bin
     AnalysisDataService::Instance().addOrReplace(
         "in2D",
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(3, 10, 0.0, 1.0));
+        WorkspaceCreationHelper::create2DWorkspaceBinned(3, 10, 0.0, 1.0));
 
     std::vector<std::vector<int>> groups;
 
     groups.clear();
     groups.push_back(makeVector(3, 0, 1, 2));
     groups.push_back(makeVector(3, 3, 4, 5));
-    evg1 = WorkspaceCreationHelper::CreateGroupedEventWorkspace(groups, 100);
+    evg1 = WorkspaceCreationHelper::createGroupedEventWorkspace(groups, 100);
     AnalysisDataService::Instance().addOrReplace(
         "evg1", boost::dynamic_pointer_cast<MatrixWorkspace>(evg1));
 
@@ -391,7 +388,7 @@ public:
     groups.push_back(makeVector(2, 3, 4));
     groups.push_back(makeVector(3, 0, 1, 2));
     groups.push_back(makeVector(1, 15));
-    evg2 = WorkspaceCreationHelper::CreateGroupedEventWorkspace(groups, 100);
+    evg2 = WorkspaceCreationHelper::createGroupedEventWorkspace(groups, 100);
     AnalysisDataService::Instance().addOrReplace(
         "evg2", boost::dynamic_pointer_cast<MatrixWorkspace>(evg2));
   }
@@ -736,7 +733,7 @@ public:
     TS_ASSERT_THROWS(merge2.execute(), std::runtime_error);
     TS_ASSERT(!merge2.isExecuted());
     MatrixWorkspace_sptr badIn =
-        WorkspaceCreationHelper::Create2DWorkspace123(3, 10, 1);
+        WorkspaceCreationHelper::create2DWorkspace123(3, 10, 1);
     badIn->mutableX(0) = 2.0;
     AnalysisDataService::Instance().add("badIn", badIn);
     TS_ASSERT_THROWS_ANYTHING(
@@ -834,7 +831,7 @@ public:
     MergeRuns alg;
     alg.setRethrows(true);
     alg.initialize();
-    alg.setPropertyValue("InputWorkspaces", a->name() + "," + b->name());
+    alg.setPropertyValue("InputWorkspaces", a->getName() + "," + b->getName());
     alg.setPropertyValue("OutputWorkspace", "out");
     TS_ASSERT_THROWS_ANYTHING(alg.execute());
   }
@@ -882,7 +879,7 @@ public:
     MergeRuns alg;
     alg.initialize();
     TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue(
-        "InputWorkspaces", input->name() + "," + input->name()));
+        "InputWorkspaces", input->getName() + "," + input->getName()));
     TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("OutputWorkspace", "outer"));
     TS_ASSERT_THROWS_NOTHING(alg.execute());
     WorkspaceGroup_sptr wsgroup =
@@ -960,7 +957,7 @@ public:
                                             const bool noOutput = false) {
 
     TS_ASSERT_THROWS_NOTHING(
-        alg.setPropertyValue("InputWorkspaces", input->name()));
+        alg.setPropertyValue("InputWorkspaces", input->getName()));
     TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("OutputWorkspace", "outWS"));
     TS_ASSERT_THROWS_NOTHING(alg.execute());
 
@@ -1267,7 +1264,7 @@ public:
 
     MergeRuns alg;
     alg.initialize();
-    alg.setPropertyValue("InputWorkspaces", ws->name());
+    alg.setPropertyValue("InputWorkspaces", ws->getName());
     alg.setPropertyValue("OutputWorkspace", "outWS");
     TS_ASSERT_THROWS_NOTHING(alg.execute());
 
@@ -1302,7 +1299,7 @@ public:
 
     MergeRuns alg;
     alg.initialize();
-    alg.setPropertyValue("InputWorkspaces", ws->name());
+    alg.setPropertyValue("InputWorkspaces", ws->getName());
     alg.setPropertyValue("OutputWorkspace", "outWS1");
     TS_ASSERT_THROWS_NOTHING(alg.execute());
 
@@ -1311,7 +1308,7 @@ public:
 
     MergeRuns alg2;
     alg2.initialize();
-    alg2.setPropertyValue("InputWorkspaces", ws2->name());
+    alg2.setPropertyValue("InputWorkspaces", ws2->getName());
     alg2.setPropertyValue("OutputWorkspace", "outWS2");
     TS_ASSERT_THROWS_NOTHING(alg2.execute());
 
@@ -1350,7 +1347,7 @@ public:
 
     MergeRuns alg;
     alg.initialize();
-    alg.setPropertyValue("InputWorkspaces", ws->name());
+    alg.setPropertyValue("InputWorkspaces", ws->getName());
     alg.setPropertyValue("OutputWorkspace", "outWS1");
     TS_ASSERT_THROWS_NOTHING(alg.execute());
 
diff --git a/Framework/Algorithms/test/ModeratorTzeroLinearTest.h b/Framework/Algorithms/test/ModeratorTzeroLinearTest.h
index 7dc0324e597a800065c40d1d00cd94a9b588c91c..365b49c8d4b3378a4590114dda509e8ce8efd9bb 100644
--- a/Framework/Algorithms/test/ModeratorTzeroLinearTest.h
+++ b/Framework/Algorithms/test/ModeratorTzeroLinearTest.h
@@ -3,7 +3,6 @@
 
 #include "MantidAPI/Axis.h"
 #include "MantidAlgorithms/ModeratorTzeroLinear.h"
-#include "MantidDataHandling/LoadAscii.h"
 #include "MantidDataHandling/LoadInstrument.h"
 #include "MantidDataObjects/Events.h"
 #include "MantidHistogramData/LinearGenerator.h"
diff --git a/Framework/Algorithms/test/MonteCarloAbsorptionTest.h b/Framework/Algorithms/test/MonteCarloAbsorptionTest.h
index dc73c12e9fbb5236bbcdb134136ef6d823154e4d..702ff7361a4615842e9e74fa7f0f8e3014755aa6 100644
--- a/Framework/Algorithms/test/MonteCarloAbsorptionTest.h
+++ b/Framework/Algorithms/test/MonteCarloAbsorptionTest.h
@@ -98,15 +98,15 @@ public:
     const double delta(1e-05);
     const size_t middle_index(4);
 
-    TS_ASSERT_DELTA(0.019012, outputWS->y(0).front(), delta);
-    TS_ASSERT_DELTA(0.0021002, outputWS->y(0)[middle_index], delta);
-    TS_ASSERT_DELTA(0.00010066, outputWS->y(0).back(), delta);
-    TS_ASSERT_DELTA(0.019074, outputWS->y(2).front(), delta);
-    TS_ASSERT_DELTA(0.001629, outputWS->y(2)[middle_index], delta);
-    TS_ASSERT_DELTA(9.4268e-05, outputWS->y(2).back(), delta);
-    TS_ASSERT_DELTA(0.019256, outputWS->y(4).front(), delta);
-    TS_ASSERT_DELTA(0.0014369, outputWS->y(4)[middle_index], delta);
-    TS_ASSERT_DELTA(9.8238e-05, outputWS->y(4).back(), delta);
+    TS_ASSERT_DELTA(0.0074366635, outputWS->y(0).front(), delta);
+    TS_ASSERT_DELTA(0.00014222815, outputWS->y(0)[middle_index], delta);
+    TS_ASSERT_DELTA(1.64562e-05, outputWS->y(0).back(), delta);
+    TS_ASSERT_DELTA(0.0073977126, outputWS->y(2).front(), delta);
+    TS_ASSERT_DELTA(0.0001373456, outputWS->y(2)[middle_index], delta);
+    TS_ASSERT_DELTA(1.3673737e-05, outputWS->y(2).back(), delta);
+    TS_ASSERT_DELTA(0.0074180214, outputWS->y(4).front(), delta);
+    TS_ASSERT_DELTA(0.00013650999, outputWS->y(4)[middle_index], delta);
+    TS_ASSERT_DELTA(1.2496885e-05, outputWS->y(4).back(), delta);
   }
 
   void test_Workspace_With_Just_Sample_For_Direct() {
@@ -119,9 +119,9 @@ public:
     const double delta(1e-05);
     const size_t middle_index(4);
 
-    TS_ASSERT_DELTA(0.0087756, outputWS->y(0).front(), delta);
-    TS_ASSERT_DELTA(0.0031353, outputWS->y(0)[middle_index], delta);
-    TS_ASSERT_DELTA(0.00087368, outputWS->y(0).back(), delta);
+    TS_ASSERT_DELTA(0.0032600806, outputWS->y(0).front(), delta);
+    TS_ASSERT_DELTA(0.00040160571, outputWS->y(0)[middle_index], delta);
+    TS_ASSERT_DELTA(0.00027626768, outputWS->y(0).back(), delta);
   }
 
   void test_Workspace_With_Just_Sample_For_Indirect() {
@@ -134,9 +134,9 @@ public:
     const double delta(1e-05);
     const size_t middle_index(4);
 
-    TS_ASSERT_DELTA(0.0038337, outputWS->y(0).front(), delta);
-    TS_ASSERT_DELTA(0.0013434, outputWS->y(0)[middle_index], delta);
-    TS_ASSERT_DELTA(0.00019552, outputWS->y(0).back(), delta);
+    TS_ASSERT_DELTA(0.0014451101, outputWS->y(0).front(), delta);
+    TS_ASSERT_DELTA(9.4166161e-05, outputWS->y(0)[middle_index], delta);
+    TS_ASSERT_DELTA(4.0118175e-05, outputWS->y(0).back(), delta);
   }
 
   void test_Workspace_With_Sample_And_Container() {
@@ -149,9 +149,9 @@ public:
     const double delta(1e-05);
     const size_t middle_index(4);
 
-    TS_ASSERT_DELTA(0.016547, outputWS->y(0).front(), delta);
-    TS_ASSERT_DELTA(0.0022329, outputWS->y(0)[middle_index], delta);
-    TS_ASSERT_DELTA(0.00024214, outputWS->y(0).back(), delta);
+    TS_ASSERT_DELTA(0.0035900048, outputWS->y(0).front(), delta);
+    TS_ASSERT_DELTA(4.5651813e-05, outputWS->y(0)[middle_index], delta);
+    TS_ASSERT_DELTA(1.2391338e-06, outputWS->y(0).back(), delta);
   }
 
   void test_Workspace_Beam_Size_Set() {
@@ -163,10 +163,10 @@ public:
     verifyDimensions(wsProps, outputWS);
     const double delta(1e-05);
     const size_t middle_index(4);
-
-    TS_ASSERT_DELTA(0.0045478, outputWS->y(0).front(), delta);
-    TS_ASSERT_DELTA(0.00036224, outputWS->y(0)[middle_index], delta);
-    TS_ASSERT_DELTA(6.5735e-05, outputWS->y(0).back(), delta);
+    TS_ASSERT_DELTA(0.004365258, outputWS->y(0).front(), delta);
+    TS_ASSERT_DELTA(9.8703289e-05, outputWS->y(0)[middle_index], delta);
+    const double delta2(1e-08);
+    TS_ASSERT_DELTA(1.7373459e-08, outputWS->y(0).back(), delta2);
   }
 
   void test_Linear_Interpolation() {
@@ -174,15 +174,32 @@ public:
     TestWorkspaceDescriptor wsProps = {1, 10, Environment::SampleOnly,
                                        DeltaEMode::Elastic, -1, -1};
     const int nlambda(5);
-    auto outputWS = runAlgorithm(wsProps, nlambda);
+    const std::string interpolation("Linear");
+    auto outputWS = runAlgorithm(wsProps, nlambda, interpolation);
 
     verifyDimensions(wsProps, outputWS);
     const double delta(1e-05);
-    const size_t middle_index(4);
+    TS_ASSERT_DELTA(0.0074366635, outputWS->y(0).front(), delta);
+    TS_ASSERT_DELTA(0.00041446262, outputWS->y(0)[3], delta);
+    TS_ASSERT_DELTA(0.00048307523, outputWS->y(0)[4], delta);
+    TS_ASSERT_DELTA(2.8600668e-05, outputWS->y(0).back(), delta);
+  }
+
+  void test_CSpline_Interpolation() {
+    using Mantid::Kernel::DeltaEMode;
+    TestWorkspaceDescriptor wsProps = {1, 10, Environment::SampleOnly,
+                                       DeltaEMode::Elastic, -1, -1};
+    const int nlambda(5);
+    const std::string interpolation("CSpline");
+    auto outputWS = runAlgorithm(wsProps, nlambda, interpolation);
 
-    TS_ASSERT_DELTA(0.019012, outputWS->y(0).front(), delta);
-    TS_ASSERT_DELTA(0.0026940, outputWS->y(0)[middle_index], delta);
-    TS_ASSERT_DELTA(0.00042886, outputWS->y(0).back(), delta);
+    verifyDimensions(wsProps, outputWS);
+    const double delta(1e-05);
+    TS_ASSERT_DELTA(0.0074366635, outputWS->y(0).front(), delta);
+    // Interpolation gives negative value due to test setup
+    TS_ASSERT_DELTA(-7.0992356e-05, outputWS->y(0)[3], delta);
+    TS_ASSERT_DELTA(0.00048307523, outputWS->y(0)[4], delta);
+    TS_ASSERT_DELTA(2.8600668e-05, outputWS->y(0).back(), delta);
   }
 
   //---------------------------------------------------------------------------
@@ -193,7 +210,7 @@ public:
 
     auto mcAbsorb = createAlgorithm();
     // Create a simple test workspace that has no instrument
-    auto testWS = WorkspaceCreationHelper::Create2DWorkspace(1, 1);
+    auto testWS = WorkspaceCreationHelper::create2DWorkspace(1, 1);
 
     TS_ASSERT_THROWS(mcAbsorb->setProperty("InputWorkspace", testWS),
                      std::invalid_argument);
@@ -214,7 +231,8 @@ public:
 
 private:
   Mantid::API::MatrixWorkspace_const_sptr
-  runAlgorithm(const TestWorkspaceDescriptor &wsProps, int nlambda = -1) {
+  runAlgorithm(const TestWorkspaceDescriptor &wsProps, int nlambda = -1,
+               const std::string &interpolate = "") {
     auto inputWS = setUpWS(wsProps);
     auto mcabs = createAlgorithm();
     TS_ASSERT_THROWS_NOTHING(mcabs->setProperty("InputWorkspace", inputWS));
@@ -222,6 +240,10 @@ private:
       TS_ASSERT_THROWS_NOTHING(
           mcabs->setProperty("NumberOfWavelengthPoints", nlambda));
     }
+    if (!interpolate.empty()) {
+      TS_ASSERT_THROWS_NOTHING(
+          mcabs->setProperty("Interpolation", interpolate));
+    }
     mcabs->execute();
     return getOutputWorkspace(mcabs);
   }
diff --git a/Framework/Algorithms/test/MonteCarloTesting.h b/Framework/Algorithms/test/MonteCarloTesting.h
index 26dd5a02aeda6ac98c3b6dd72c7c9c2e69b4d81b..249d477724744ade2eb0ee478bbf7d0ef1950acb 100644
--- a/Framework/Algorithms/test/MonteCarloTesting.h
+++ b/Framework/Algorithms/test/MonteCarloTesting.h
@@ -8,6 +8,7 @@
 #include "MantidKernel/Material.h"
 #include "MantidKernel/PseudoRandomNumberGenerator.h"
 #include "MantidKernel/WarningSuppressions.h"
+#include "MantidKernel/make_unique.h"
 #include "MantidTestHelpers/ComponentCreationHelper.h"
 
 #include <gmock/gmock.h>
@@ -32,6 +33,8 @@ public:
   MOCK_METHOD0(restore, void());
   MOCK_METHOD1(setSeed, void(size_t));
   MOCK_METHOD2(setRange, void(const double, const double));
+  MOCK_CONST_METHOD0(min, double());
+  MOCK_CONST_METHOD0(max, double());
   GCC_DIAG_ON_SUGGEST_OVERRIDE
 };
 
diff --git a/Framework/Algorithms/test/MultipleScatteringCylinderAbsorptionTest.h b/Framework/Algorithms/test/MultipleScatteringCylinderAbsorptionTest.h
index 61c675dc867704ade168a81cfb7d89d0b742042c..eaafc4b956cb5093ec13ed2ec68ba0fc5088c46e 100644
--- a/Framework/Algorithms/test/MultipleScatteringCylinderAbsorptionTest.h
+++ b/Framework/Algorithms/test/MultipleScatteringCylinderAbsorptionTest.h
@@ -64,7 +64,7 @@ public:
   void testCalculationHist() {
     // setup the test workspace
     Workspace2D_sptr wksp =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(9, 16, 1000, 1000);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(9, 16, 1000, 1000);
     wksp->setInstrument(
         ComponentCreationHelper::createTestInstrumentCylindrical(1));
     wksp->getAxis(0)->setUnit("TOF");
diff --git a/Framework/Algorithms/test/MultiplyDivideTest.in.h b/Framework/Algorithms/test/MultiplyDivideTest.in.h
index 37e0b89832f1666850256d671c46f6491cf204fb..c185ea41dc7bcc1c77db57916a46401142609f55 100644
--- a/Framework/Algorithms/test/MultiplyDivideTest.in.h
+++ b/Framework/Algorithms/test/MultiplyDivideTest.in.h
@@ -11,6 +11,7 @@
 #include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidDataObjects/Workspace2D.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidAPI/WorkspaceProperty.h"
 #include "MantidAPI/WorkspaceOpOverloads.h"
 #include "MantidDataObjects/EventWorkspaceHelpers.h"
@@ -23,7 +24,7 @@ using Mantid::Geometry::IDetector_const_sptr;
 
 /*****************************************************************************************/
 /********** PLEASE NOTE! THIS FILE WAS AUTO-GENERATED FROM CMAKE.  ***********************/
-/********** Source = MultiplyDivideTest.h.in *********************************************/
+/********** Source = MultiplyDivideTest.in.h *********************************************/
 /*****************************************************************************************/
 
 class @MULTIPLYDIVIDETEST_CLASS@ : public CxxTest::TestSuite
@@ -42,11 +43,11 @@ public:
   {
     DO_DIVIDE = @MULTIPLYDIVIDETEST_DO_DIVIDE@;
 
-    fibWS1d = WorkspaceCreationHelper::Create1DWorkspaceFib(5);
-    histWS_5x10_123 = WorkspaceCreationHelper::Create2DWorkspace123(5,10);
-    histWS_5x10_154 = WorkspaceCreationHelper::Create2DWorkspace154(5,10);
-    histWS_5x10_bin = WorkspaceCreationHelper::Create2DWorkspace(5,10);
-    eventWS_5x10_50 = WorkspaceCreationHelper::CreateEventWorkspace(5,10,50,0.0,1.0,2);
+    fibWS1d = WorkspaceCreationHelper::create1DWorkspaceFib(5);
+    histWS_5x10_123 = WorkspaceCreationHelper::create2DWorkspace123(5,10);
+    histWS_5x10_154 = WorkspaceCreationHelper::create2DWorkspace154(5,10);
+    histWS_5x10_bin = WorkspaceCreationHelper::create2DWorkspace(5,10);
+    eventWS_5x10_50 = WorkspaceCreationHelper::createEventWorkspace(5,10,50,0.0,1.0,2);
   }
 
 
@@ -84,9 +85,9 @@ public:
   void testCompoundAssignment()
   {
 
-    MatrixWorkspace_sptr a = WorkspaceCreationHelper::CreateWorkspaceSingleValue(3);
+    MatrixWorkspace_sptr a = WorkspaceCreationHelper::createWorkspaceSingleValue(3);
     const Workspace_const_sptr b = a;
-    MatrixWorkspace_sptr c = WorkspaceCreationHelper::CreateWorkspaceSingleValue(2);
+    MatrixWorkspace_sptr c = WorkspaceCreationHelper::createWorkspaceSingleValue(2);
     if (DO_DIVIDE)
     {
       a /= 5;
@@ -125,7 +126,7 @@ public:
 
   void test_2D_2D_inPlace()
   {
-    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::Create2DWorkspace(5,10);
+    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::create2DWorkspace(5,10);
     MatrixWorkspace_sptr work_in2 = histWS_5x10_bin;
     performTest(work_in1,work_in2, false /*not event*/,
         DO_DIVIDE ? 1.0 : 4.0, DO_DIVIDE ? 1.0 : 4.0, false, false, true /*in place*/);
@@ -136,8 +137,8 @@ public:
     if(DO_DIVIDE)
     {
     int nHist = 5,nBins=5;
-    MatrixWorkspace_sptr numerator  = WorkspaceCreationHelper::Create2DWorkspace123(nHist-1,nBins); // Cropped
-    MatrixWorkspace_sptr denominator = WorkspaceCreationHelper::Create2DWorkspace123(nHist, 1); // Integrated
+    MatrixWorkspace_sptr numerator  = WorkspaceCreationHelper::create2DWorkspace123(nHist-1,nBins); // Cropped
+    MatrixWorkspace_sptr denominator = WorkspaceCreationHelper::create2DWorkspace123(nHist, 1); // Integrated
     Divide alg;
     alg.initialize();
     alg.setChild(true);
@@ -156,8 +157,8 @@ public:
     for (int inplace=0; inplace<2; inplace++)
     {
       int nHist = 5,nBins=10;
-      MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::Create2DWorkspace(nHist,nBins);
-      MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::Create2DWorkspace(nHist,1);
+      MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::create2DWorkspace(nHist,nBins);
+      MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::create2DWorkspace(nHist,1);
       performTest(work_in1,work_in2, false /*not event*/,
           DO_DIVIDE ? 1.0 : 4.0, DO_DIVIDE ? 1.0 : 4.0, false, false, inplace!=0 /*in place*/);
     }
@@ -166,15 +167,15 @@ public:
   void test_1D_Rand2D()
   {
     int nHist = 5,nBins=5;
-    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::Create2DWorkspace154(nHist,nBins);
-    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::Create1DWorkspaceRand(nBins);
+    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::create2DWorkspace154(nHist,nBins);
+    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::create1DWorkspaceRand(nBins);
     performTest(work_in1,work_in2);
   }
 
   void test_2D_1DVertical()
   {
     MatrixWorkspace_sptr work_in1 = histWS_5x10_154;
-    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::Create2DWorkspace123(1,10);
+    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::create2DWorkspace123(1,10);
     performTest(work_in1,work_in2);
   }
 
@@ -182,8 +183,8 @@ public:
   {
     //In 2D workspaces, the X bins have to match
     int nHist = 20,nBins=10;
-    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::Create2DWorkspace123(nHist,nBins);
-    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::Create2DWorkspace154(1,nBins*5);
+    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::create2DWorkspace123(nHist,nBins);
+    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::create2DWorkspace154(1,nBins*5);
     performTest_fails(work_in1, work_in2);
   }
 
@@ -218,7 +219,7 @@ public:
 
   void test_2D_2DbyOperatorOverload_inPlace()
   {
-    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::Create2DWorkspace(5,10);
+    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::create2DWorkspace(5,10);
     MatrixWorkspace_sptr work_in2 = histWS_5x10_bin;
     MatrixWorkspace_sptr work_out1;
     if (DO_DIVIDE)
@@ -237,15 +238,15 @@ public:
   void test_1D_SingleValue()
   {
     MatrixWorkspace_sptr work_in1 = fibWS1d;
-    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::CreateWorkspaceSingleValue(2.2);
+    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::createWorkspaceSingleValue(2.2);
     performTest(work_in1,work_in2);
   }
 
   void test_SingleValue_1D()
   {
     int nBins = 5;
-    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::CreateWorkspaceSingleValue(10.0);
-    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::Create2DWorkspace(1,nBins);
+    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::createWorkspaceSingleValue(10.0);
+    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::create2DWorkspace(1,nBins);
     if (DO_DIVIDE)
       performTest(work_in1,work_in2,false,
           5.0, 3.8729, false, true /*commutes*/);
@@ -258,8 +259,8 @@ public:
     for (int inplace=0; inplace<2; inplace++)
     {
       int nHist = 5,nBins=10;
-      MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::Create2DWorkspace(nHist,nBins);
-      MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::CreateWorkspaceSingleValue(2.0);
+      MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::create2DWorkspace(nHist,nBins);
+      MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::createWorkspaceSingleValue(2.0);
       performTest(work_in1,work_in2, false /*not event*/,
           DO_DIVIDE ? 1.0 : 4.0, DO_DIVIDE ? 1.0 : 4.0, false, false, inplace!=0 /*in place*/);
     }
@@ -267,7 +268,7 @@ public:
 
   void test_SingleValue_2D()
   {
-    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::CreateWorkspaceSingleValue(10.0);
+    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::createWorkspaceSingleValue(10.0);
     MatrixWorkspace_sptr work_in2 = histWS_5x10_bin;
     if (DO_DIVIDE)
       performTest(work_in1,work_in2,false,
@@ -279,7 +280,7 @@ public:
   void test_2D_SingleValueNoError()
   {
     MatrixWorkspace_sptr work_in1 = histWS_5x10_bin;
-    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::CreateWorkspaceSingleValueWithError(5.0, 0.0);
+    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::createWorkspaceSingleValueWithError(5.0, 0.0);
     performTest(work_in1,work_in2);
   }
 
@@ -299,8 +300,8 @@ public:
   void test_1DVertical_EventWithOneBin_willCommute()
   {
     int nBins=1,nHist=10;
-    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::Create2DWorkspace(nHist,nBins);
-    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::CreateEventWorkspace(nHist, nBins,50,0.0,1.0,2);
+    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::create2DWorkspace(nHist,nBins);
+    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::createEventWorkspace(nHist, nBins,50,0.0,1.0,2);
     if (DO_DIVIDE)
       performTest(work_in1,work_in2, false /*output is not Event */, 1.0, 1.0, false, false, false /* not in place */);
     else
@@ -310,8 +311,8 @@ public:
   void test_1DVertical_EventWithOneBin_willCommute_inplace()
   {
     int nBins=1,nHist=10;
-    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::Create2DWorkspace(nHist,nBins);
-    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::CreateEventWorkspace(nHist, nBins,50,0.0,1.0,2);
+    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::create2DWorkspace(nHist,nBins);
+    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::createEventWorkspace(nHist, nBins,50,0.0,1.0,2);
     if (DO_DIVIDE)
       performTest(work_in1,work_in2, false /*output is not Event */, 1.0, 1.0, false, false, true /*in place*/);
     else
@@ -320,7 +321,7 @@ public:
 
   void test_2D_Event_inPlace()
   {
-    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::Create2DWorkspace(5,10);
+    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::create2DWorkspace(5,10);
     MatrixWorkspace_sptr work_in2 = eventWS_5x10_50;
     if (DO_DIVIDE)
       performTest(work_in1,work_in2, false /*output is not Event */, 1.0, sqrt(1.0), false, false, true);
@@ -331,7 +332,7 @@ public:
   void test_2D_Event_RHSEventWorkspaceHasOnebin()
   {
     MatrixWorkspace_sptr work_in1 = histWS_5x10_bin;
-    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::CreateEventWorkspace(5, 1,50,0.0,100.0,2);
+    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::createEventWorkspace(5, 1,50,0.0,100.0,2);
     if (DO_DIVIDE)
       performTest(work_in1,work_in2, false /*output is not Event */, 1.0, sqrt(1.0), false, false, false);
     else
@@ -341,8 +342,8 @@ public:
   void test_2D_Event_inPlace_RHSEventWorkspaceHasOnebin()
   {
     int nHist = 5,nBins=10;
-    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::Create2DWorkspace(nHist,nBins);
-    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::CreateEventWorkspace(nHist, 1,50,0.0,100.0,2);
+    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::create2DWorkspace(nHist,nBins);
+    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::createEventWorkspace(nHist, 1,50,0.0,100.0,2);
     if (DO_DIVIDE)
       performTest(work_in1,work_in2, false /*output is not Event */, 1.0, sqrt(1.0), false, false, true);
     else
@@ -352,8 +353,8 @@ public:
   void test_2D_Event_inPlace_RHSEventWorkspaceHasOnebinAndOneSpectrum()
   {
     int nHist = 5,nBins=10;
-    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::Create2DWorkspace(nHist,nBins);
-    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::CreateEventWorkspace(1, 1,50,0.0,100.0,2);
+    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::create2DWorkspace(nHist,nBins);
+    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::createEventWorkspace(1, 1,50,0.0,100.0,2);
     if (DO_DIVIDE)
       performTest(work_in1,work_in2, false /*output is not Event*/, 1.0, sqrt(1.0), false, false, true);
     else
@@ -363,8 +364,8 @@ public:
   void test_Event_2D_inplace_LHSEventWorkspaceHasOnebin()
   {
     int nHist = 5,nBins=10;
-    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::CreateEventWorkspace(nHist, 1, 2, 0.0, 1.0, 2); // Events are at 0.5
-    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::Create2DWorkspace(nHist,nBins);
+    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::createEventWorkspace(nHist, 1, 2, 0.0, 1.0, 2); // Events are at 0.5
+    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::create2DWorkspace(nHist,nBins);
     if (DO_DIVIDE)
       performTest(work_in1,work_in2, true /*output is Event */, 1.0, 0.8660, false, false, true);
     else
@@ -375,8 +376,8 @@ public:
   void test_Event_2D_inplace_LHSEventWorkspaceHasOnebinAndOneSpectrum()
   {
     int nHist = 5,nBins=10;
-    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::CreateEventWorkspace(1, 1, 2, 0.0, 1.0, 2); // Events are at 0.5
-    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::Create2DWorkspace(nHist,nBins);
+    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::createEventWorkspace(1, 1, 2, 0.0, 1.0, 2); // Events are at 0.5
+    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::create2DWorkspace(nHist,nBins);
     if (DO_DIVIDE)
       performTest_fails(work_in1,work_in2); // Incompatible sizes
     else
@@ -397,8 +398,8 @@ public:
   void test_Event_2D_inPlace()
   {
     int nHist = 5,nBins=10;
-    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::CreateEventWorkspace(nHist,nBins,50,0.0,1.0,2);
-    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::Create2DWorkspace(nHist,nBins);
+    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::createEventWorkspace(nHist,nBins,50,0.0,1.0,2);
+    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::create2DWorkspace(nHist,nBins);
     if (DO_DIVIDE)
       performTest(work_in1,work_in2, true, 1.0, sqrt(0.75), false, false, true);
     else
@@ -412,7 +413,7 @@ public:
   void test_Event_2DSingleSpectrum()
   {
     MatrixWorkspace_sptr work_in1 = eventWS_5x10_50;
-    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::Create2DWorkspace(1, 10);
+    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::create2DWorkspace(1, 10);
     if (DO_DIVIDE)
       performTest(work_in1,work_in2, true, 1.0, sqrt(0.75));
     else
@@ -422,8 +423,8 @@ public:
   void test_Event_2DSingleSpectrum_inPlace()
   {
     int nHist = 10,nBins=20;
-    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::CreateEventWorkspace(nHist,nBins,100,0.0,1.0,2);
-    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::Create2DWorkspace(1, nBins);
+    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::createEventWorkspace(nHist,nBins,100,0.0,1.0,2);
+    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::create2DWorkspace(1, nBins);
     if (DO_DIVIDE)
       performTest(work_in1,work_in2, true, 1.0, sqrt(0.75), false, false, true /* in-place */);
     else
@@ -434,7 +435,7 @@ public:
   {
     //Unlike 2D workspaces, you can divide by a single spectrum with different X bins!
     MatrixWorkspace_sptr work_in1 = eventWS_5x10_50;
-    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::Create2DWorkspace(1, 5*2);
+    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::create2DWorkspace(1, 5*2);
     if (DO_DIVIDE)
       performTest(work_in1,work_in2, true, 1.0, sqrt(0.75));
     else
@@ -443,7 +444,7 @@ public:
 
   void test_2DSingleSpectrum_Event()
   {
-    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::Create2DWorkspace(1, 10);
+    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::create2DWorkspace(1, 10);
     MatrixWorkspace_sptr work_in2 = eventWS_5x10_50;
     if (DO_DIVIDE)
       performTest_fails(work_in1,work_in2); /* Fails for dividing, since you can't commute */
@@ -454,8 +455,8 @@ public:
   void test_2DSingleSpectrum_Event_inPlace()
   {
     int nHist = 5,nBins=10;
-    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::Create2DWorkspace(1, nBins);
-    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::CreateEventWorkspace(nHist,nBins,50,0.0,1.0,2);
+    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::create2DWorkspace(1, nBins);
+    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::createEventWorkspace(nHist,nBins,50,0.0,1.0,2);
     if (DO_DIVIDE)
       performTest_fails(work_in1,work_in2); /* Fails for dividing, since you can't commute */
     else
@@ -466,8 +467,8 @@ public:
   {
     //Unlike 2D workspaces, you can divide by a single spectrum with different X bins!
     int nBins = 5,nHist=5;
-    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::Create2DWorkspace(1, nHist*2);
-    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::CreateEventWorkspace(nBins,nHist,50,0.0,1.0,2);
+    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::create2DWorkspace(1, nHist*2);
+    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::createEventWorkspace(nBins,nHist,50,0.0,1.0,2);
     if (DO_DIVIDE)
       performTest_fails(work_in1,work_in2); /* Fails for dividing, since you can't commute */
     else
@@ -478,8 +479,8 @@ public:
   {
     //Unlike 2D workspaces, you can divide by a single spectrum with different X bins!
     int nBins = 5,nHist=5;
-    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::Create2DWorkspace(1, nBins*2);
-    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::CreateEventWorkspace(nBins,nHist,50,0.0,1.0,2);
+    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::create2DWorkspace(1, nBins*2);
+    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::createEventWorkspace(nBins,nHist,50,0.0,1.0,2);
     if (DO_DIVIDE)
       performTest_fails(work_in1,work_in2); /* Fails for dividing, since you can't commute */
     else
@@ -489,7 +490,7 @@ public:
   void test_Event_SingleValue()
   {
     MatrixWorkspace_sptr work_in1 = eventWS_5x10_50;
-    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::CreateWorkspaceSingleValue(2.0);
+    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::createWorkspaceSingleValue(2.0);
     if (DO_DIVIDE)
       performTest(work_in1,work_in2, true, 1.0, sqrt(0.75));
     else
@@ -499,8 +500,8 @@ public:
   void test_Event_SingleValue_inPlace()
   {
     int nHist = 5,nBins=10;
-    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::CreateEventWorkspace(nHist,nBins,50,0.0,1.0,2);
-    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::CreateWorkspaceSingleValue(2.0);
+    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::createEventWorkspace(nHist,nBins,50,0.0,1.0,2);
+    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::createWorkspaceSingleValue(2.0);
     if (DO_DIVIDE)
       performTest(work_in1,work_in2, true, 1.0, sqrt(0.75), false, false, true /* in-place */);
     else
@@ -510,8 +511,8 @@ public:
   void test_SingleValue_Event()
   {
     int nHist = 5,nBins=10;
-    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::CreateWorkspaceSingleValue(10.0);
-    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::CreateEventWorkspace(nHist,nBins,50,0.0,1.0,2);
+    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::createWorkspaceSingleValue(10.0);
+    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::createEventWorkspace(nHist,nBins,50,0.0,1.0,2);
     if (DO_DIVIDE)
       performTest(work_in1,work_in2, false /*NOT events*/,
           5.0, 3.8729, false, true /*commutes*/);
@@ -523,8 +524,8 @@ public:
   {
     // Doing in-place on a single value is silly since it just gets overwritten, but it works!
     int nHist = 5,nBins=10;
-    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::CreateWorkspaceSingleValue(2.0);
-    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::CreateEventWorkspace(nHist,nBins,50,0.0,1.0,2);
+    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::createWorkspaceSingleValue(2.0);
+    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::createEventWorkspace(nHist,nBins,50,0.0,1.0,2);
     if (DO_DIVIDE)
       performTest(work_in1,work_in2, false /*NOT events*/,
           1.0, 1.0, false, true /*commutes*/);
@@ -535,7 +536,7 @@ public:
   void test_Event_SingleValueNoError()
   {
     MatrixWorkspace_sptr work_in1 = eventWS_5x10_50;
-    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::CreateWorkspaceSingleValueWithError(2.0, 0.0);
+    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::createWorkspaceSingleValueWithError(2.0, 0.0);
     performTest(work_in1,work_in2, true);
   }
 
@@ -552,8 +553,8 @@ public:
   void test_Event_Event_inPlace()
   {
     int nHist = 5,nBins=10;
-    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::CreateEventWorkspace(nHist,nBins,50,0.0,1.0,2);
-    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::CreateEventWorkspace(nHist,nBins,50,0.0,1.0,2);
+    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::createEventWorkspace(nHist,nBins,50,0.0,1.0,2);
+    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::createEventWorkspace(nHist,nBins,50,0.0,1.0,2);
     if (DO_DIVIDE)
       performTest(work_in1,work_in2, true, 1.0, sqrt(0.75), false, false, true /* in-place */);
     else
@@ -585,13 +586,13 @@ public:
       rhs[i/rhs_grouping].push_back(i);
     }
     // Grouped workspace will have lhs_grouping events in each bin (also).
-    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::CreateGroupedEventWorkspace(lhs, 10, 1.0);
+    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::createGroupedEventWorkspace(lhs, 10, 1.0);
     if (lhs2D)
       work_in1 = EventWorkspaceHelpers::convertEventTo2D(work_in1);
     TS_ASSERT_DELTA( work_in1->readE(0)[0], sqrt( double(lhs_grouping*1.0) ), 1e-5);
 
     // Grouped workspace will have rhs_grouping events in each bin (also).
-    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::CreateGroupedEventWorkspace(rhs, 10, 1.0);
+    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::createGroupedEventWorkspace(rhs, 10, 1.0);
     if (rhs2D)
       work_in2 = EventWorkspaceHelpers::convertEventTo2D(work_in2);
     TS_ASSERT_DELTA( work_in2->readE(0)[0], sqrt( double(rhs_grouping*1.0) ), 1e-5);
@@ -917,8 +918,8 @@ public:
     masking.insert(2);
     masking.insert(7);
 
-    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::Create2DWorkspace123(nHist,nBins, 0, masking);
-    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::Create2DWorkspace154(nHist,nBins, 0, masking);
+    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::create2DWorkspace123(nHist,nBins, 0, masking);
+    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::create2DWorkspace154(nHist,nBins, 0, masking);
     const std::string lhs("work_in1"), rhs("work_in2");
     AnalysisDataService::Instance().add(lhs, work_in1);
     AnalysisDataService::Instance().add(rhs, work_in2);
@@ -956,18 +957,17 @@ public:
     MatrixWorkspace_sptr output = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("work_in1");
     TS_ASSERT(output);
 
+    const auto &spectrumInfo = output->spectrumInfo();
     for( int i = 0; i < nHist; ++i )
     {
-      IDetector_const_sptr det = output->getDetector(i);
-      TS_ASSERT(det);
-      if( !det ) TS_FAIL("No detector found");
+      TS_ASSERT(spectrumInfo.hasDetectors(i));
       if( masking.count(i) == 0 )
       {
-        TS_ASSERT_EQUALS(det->isMasked(), false);
+        TS_ASSERT_EQUALS(spectrumInfo.isMasked(i), false);
       }
       else
       {
-        TS_ASSERT_EQUALS(det->isMasked(), true);
+        TS_ASSERT_EQUALS(spectrumInfo.isMasked(i), true);
         double yValue = output->readY(i)[0];
         TS_ASSERT_EQUALS(yValue, yValue );
         TS_ASSERT( !std::isinf(yValue) );
diff --git a/Framework/Algorithms/test/MultiplyRangeTest.h b/Framework/Algorithms/test/MultiplyRangeTest.h
index 0f5af7a9b103748cb1e17cdcf058713f70a52a9c..95bc78af4f70b6bcfbb745ee2d1554b6b7af1a03 100644
--- a/Framework/Algorithms/test/MultiplyRangeTest.h
+++ b/Framework/Algorithms/test/MultiplyRangeTest.h
@@ -4,6 +4,7 @@
 #include <cxxtest/TestSuite.h>
 #include "MantidAlgorithms/MultiplyRange.h"
 #include "MantidDataHandling/LoadRaw3.h"
+#include "MantidAPI/AnalysisDataService.h"
 
 using namespace Mantid::API;
 using namespace Mantid::Kernel;
diff --git a/Framework/Algorithms/test/MuonGroupDetectorsTest.h b/Framework/Algorithms/test/MuonGroupDetectorsTest.h
index cb318bf170d63f9022a077f633fd2c7279a7f329..b59025c97719804a48a288349d16a781a8ef509c 100644
--- a/Framework/Algorithms/test/MuonGroupDetectorsTest.h
+++ b/Framework/Algorithms/test/MuonGroupDetectorsTest.h
@@ -35,7 +35,7 @@ public:
     const std::string outWSName("MuonGroupDetectorsTest_OutputWS");
 
     MatrixWorkspace_sptr inWS =
-        WorkspaceCreationHelper::Create2DWorkspace123(5, 3);
+        WorkspaceCreationHelper::create2DWorkspace123(5, 3);
 
     for (size_t i = 0; i < inWS->getNumberHistograms(); ++i)
       inWS->getSpectrum(i).setDetectorID(static_cast<detid_t>(
diff --git a/Framework/Algorithms/test/NormaliseByCurrentTest.h b/Framework/Algorithms/test/NormaliseByCurrentTest.h
index 33d772f65e5ecb0d08079f1b25d44eafdda4d7e5..aec6785889a70e7514d372e424c528d5fae4f41b 100644
--- a/Framework/Algorithms/test/NormaliseByCurrentTest.h
+++ b/Framework/Algorithms/test/NormaliseByCurrentTest.h
@@ -139,7 +139,7 @@ public:
 
   void test_exec() {
     AnalysisDataService::Instance().add(
-        "normIn", WorkspaceCreationHelper::Create2DWorkspaceBinned(10, 3, 1));
+        "normIn", WorkspaceCreationHelper::create2DWorkspaceBinned(10, 3, 1));
     doTest("normIn", "normOut", 1.0, 0.5 * M_SQRT2);
     AnalysisDataService::Instance().remove("normIn");
     AnalysisDataService::Instance().remove("normOut");
@@ -152,17 +152,17 @@ public:
     // uniform error value of 3.0.
 
     MatrixWorkspace_sptr a =
-        WorkspaceCreationHelper::Create2DWorkspace123(3, 10, 1);
+        WorkspaceCreationHelper::create2DWorkspace123(3, 10, 1);
     a->setYUnit("Counts");
     addMultiPeriodLogsTo(a, 1, protonChargeByPeriod);
 
     MatrixWorkspace_sptr b =
-        WorkspaceCreationHelper::Create2DWorkspace123(3, 10, 1);
+        WorkspaceCreationHelper::create2DWorkspace123(3, 10, 1);
     b->setYUnit("Counts");
     addMultiPeriodLogsTo(b, 2, protonChargeByPeriod);
 
     MatrixWorkspace_sptr c =
-        WorkspaceCreationHelper::Create2DWorkspace123(3, 10, 1);
+        WorkspaceCreationHelper::create2DWorkspace123(3, 10, 1);
     c->setYUnit("Counts");
     addMultiPeriodLogsTo(c, 3, protonChargeByPeriod);
 
@@ -177,7 +177,7 @@ public:
     const std::string protonChargeByPeriod = "2.0, 4.0, 8.0";
 
     MatrixWorkspace_sptr ws =
-        WorkspaceCreationHelper::Create2DWorkspace123(3, 10, 1);
+        WorkspaceCreationHelper::create2DWorkspace123(3, 10, 1);
     ws->setYUnit("Counts");
     addMultiPeriodLogsTo(ws, 1, protonChargeByPeriod); // If this worked, we
                                                        // would be normalising
@@ -194,7 +194,7 @@ public:
     const std::string protonChargeByPeriod = "2.0, 4.0, 8.0";
 
     MatrixWorkspace_sptr ws =
-        WorkspaceCreationHelper::Create2DWorkspace123(3, 10, 1);
+        WorkspaceCreationHelper::create2DWorkspace123(3, 10, 1);
     ws->setYUnit("Counts");
     addMultiPeriodLogsTo(ws, 1, protonChargeByPeriod); // If this worked, we
                                                        // would be normalising
@@ -212,7 +212,7 @@ public:
     const std::string protonChargeByPeriod = "2.0, 4.0";
 
     MatrixWorkspace_sptr ws =
-        WorkspaceCreationHelper::Create2DWorkspace123(3, 10, 1);
+        WorkspaceCreationHelper::create2DWorkspace123(3, 10, 1);
     ws->setYUnit("Counts");
     addMultiPeriodLogsTo(ws, 1, protonChargeByPeriod); // If this worked, we
                                                        // would be normalising
@@ -229,7 +229,7 @@ public:
   void testThrowsWithoutCURRENT_PERIOD_Log() {
     const std::string protonChargeByPeriod = "2.0, 4.0, 8.0";
     MatrixWorkspace_sptr ws =
-        WorkspaceCreationHelper::Create2DWorkspace123(3, 10, 1);
+        WorkspaceCreationHelper::create2DWorkspace123(3, 10, 1);
     ws->setYUnit("Counts");
     addMultiPeriodLogsTo(ws, 1, protonChargeByPeriod); // If this worked, we
                                                        // would be normalising
@@ -252,7 +252,7 @@ public:
   void testThrowsWithoutPROTON_CHARGE_BY_PERIOD_Log() {
     const std::string protonChargeByPeriod = "2.0, 4.0, 8.0";
     MatrixWorkspace_sptr ws =
-        WorkspaceCreationHelper::Create2DWorkspace123(3, 10, 1);
+        WorkspaceCreationHelper::create2DWorkspace123(3, 10, 1);
     ws->setYUnit("Counts");
     addMultiPeriodLogsTo(ws, 1, protonChargeByPeriod); // If this worked, we
                                                        // would be normalising
@@ -277,7 +277,7 @@ public:
 
   void test_execInPlace() {
     AnalysisDataService::Instance().add(
-        "normIn", WorkspaceCreationHelper::Create2DWorkspaceBinned(10, 3, 1));
+        "normIn", WorkspaceCreationHelper::create2DWorkspaceBinned(10, 3, 1));
     doTest("normIn", "normIn", 1.0, 0.5 * M_SQRT2);
     AnalysisDataService::Instance().remove("normIn");
   }
@@ -285,7 +285,7 @@ public:
   void test_execEvent() {
     AnalysisDataService::Instance().add(
         "normInEvent",
-        WorkspaceCreationHelper::CreateEventWorkspace(10, 3, 100, 0.0, 1.0, 2));
+        WorkspaceCreationHelper::createEventWorkspace(10, 3, 100, 0.0, 1.0, 2));
 
     EventWorkspace_const_sptr outputEvent;
     outputEvent = boost::dynamic_pointer_cast<const EventWorkspace>(
@@ -300,7 +300,7 @@ public:
   void test_execEventInPlace() {
     AnalysisDataService::Instance().add(
         "normInEvent",
-        WorkspaceCreationHelper::CreateEventWorkspace(10, 3, 100, 0.0, 1.0, 2));
+        WorkspaceCreationHelper::createEventWorkspace(10, 3, 100, 0.0, 1.0, 2));
 
     EventWorkspace_const_sptr outputEvent;
     outputEvent = boost::dynamic_pointer_cast<const EventWorkspace>(
@@ -313,7 +313,7 @@ public:
 
   void test_execZero() {
     AnalysisDataService::Instance().add(
-        "normIn", WorkspaceCreationHelper::Create2DWorkspace123(3, 10, 1));
+        "normIn", WorkspaceCreationHelper::create2DWorkspace123(3, 10, 1));
 
     NormaliseByCurrent norm1;
     norm1.initialize();
@@ -359,21 +359,21 @@ public:
     // test_execPerformance
     AnalysisDataService::Instance().add(
         execWSIn,
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(nHist, nBins, 1));
+        WorkspaceCreationHelper::create2DWorkspaceBinned(nHist, nBins, 1));
 
     // test_execInPlacePerformance
     AnalysisDataService::Instance().add(
         execInPlaceWSIn,
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(nHist, nBins, 1));
+        WorkspaceCreationHelper::create2DWorkspaceBinned(nHist, nBins, 1));
 
     // test_execEventPerformance
     AnalysisDataService::Instance().add(
-        execEventWSIn, WorkspaceCreationHelper::CreateEventWorkspace(
+        execEventWSIn, WorkspaceCreationHelper::createEventWorkspace(
                            nHist, nBins, nPixels, 0.0, 1.0, 2));
 
     // test_execEventInPlacePerformance
     AnalysisDataService::Instance().add(
-        execEventInPlaceWSIn, WorkspaceCreationHelper::CreateEventWorkspace(
+        execEventInPlaceWSIn, WorkspaceCreationHelper::createEventWorkspace(
                                   nHist, nBins, nPixels, 0.0, 1.0, 2));
 
     // test_multiPeriodDataPerformance
@@ -382,17 +382,17 @@ public:
     // Note that CreateWorkspace123 creates uniform signal value of 2.0, and
     // uniform error value of 3.0.
     multiPeriodWS1 =
-        WorkspaceCreationHelper::Create2DWorkspace123(nHist, nBins, 1);
+        WorkspaceCreationHelper::create2DWorkspace123(nHist, nBins, 1);
     multiPeriodWS1->setYUnit("Counts");
     addMultiPeriodLogsTo(multiPeriodWS1, 1, protonChargeByPeriod);
 
     multiPeriodWS2 =
-        WorkspaceCreationHelper::Create2DWorkspace123(nHist, nBins, 1);
+        WorkspaceCreationHelper::create2DWorkspace123(nHist, nBins, 1);
     multiPeriodWS2->setYUnit("Counts");
     addMultiPeriodLogsTo(multiPeriodWS2, 2, protonChargeByPeriod);
 
     multiPeriodWS3 =
-        WorkspaceCreationHelper::Create2DWorkspace123(nHist, nBins, 1);
+        WorkspaceCreationHelper::create2DWorkspace123(nHist, nBins, 1);
     multiPeriodWS3->setYUnit("Counts");
     addMultiPeriodLogsTo(multiPeriodWS3, 3, protonChargeByPeriod);
   }
diff --git a/Framework/Algorithms/test/NormaliseToMonitorTest.h b/Framework/Algorithms/test/NormaliseToMonitorTest.h
index d25254cc9933d206e58da00a49ae110ec564161c..13f0ff9d816b07c3f607e243f14479b0564f97d8 100644
--- a/Framework/Algorithms/test/NormaliseToMonitorTest.h
+++ b/Framework/Algorithms/test/NormaliseToMonitorTest.h
@@ -20,7 +20,7 @@ using Mantid::Geometry::Instrument;
 namespace {
 void setUpWorkspace(int histograms = 3, int bins = 10) {
   MatrixWorkspace_sptr input =
-      WorkspaceCreationHelper::Create2DWorkspace123(histograms, bins, 1);
+      WorkspaceCreationHelper::create2DWorkspace123(histograms, bins, 1);
   // Change the data in the monitor spectrum
   input->mutableY(0).assign(bins, 10.0);
   // Need to change bins
@@ -42,7 +42,6 @@ void setUpWorkspace(int histograms = 3, int bins = 10) {
   input->getSpectrum(1).setSpectrumNo(1);
   input->getSpectrum(2).setSpectrumNo(2);
   boost::shared_ptr<Instrument> instr = boost::make_shared<Instrument>();
-  input->setInstrument(instr);
   Mantid::Geometry::Detector *mon =
       new Mantid::Geometry::Detector("monitor", 0, NULL);
   instr->add(mon);
@@ -51,12 +50,13 @@ void setUpWorkspace(int histograms = 3, int bins = 10) {
       new Mantid::Geometry::Detector("NOTmonitor", 1, NULL);
   instr->add(det);
   instr->markAsDetector(det);
+  input->setInstrument(instr);
 
   AnalysisDataService::Instance().addOrReplace("normMon", input);
 
   // Create a single spectrum workspace to be the monitor one
   MatrixWorkspace_sptr monWS =
-      WorkspaceCreationHelper::Create2DWorkspaceBinned(1, 20, 0.1, 0.5);
+      WorkspaceCreationHelper::create2DWorkspaceBinned(1, 20, 0.1, 0.5);
   monWS->getAxis(0)->unit() =
       Mantid::Kernel::UnitFactory::Instance().create("Wavelength");
   // Now need to set up a minimal instrument and spectra-detector map
@@ -395,7 +395,7 @@ public:
     // now deal with ws without monitors
     // create ws without monitors.
     MatrixWorkspace_sptr input =
-        WorkspaceCreationHelper::Create2DWorkspace123(3, 10, 1);
+        WorkspaceCreationHelper::create2DWorkspace123(3, 10, 1);
     boost::shared_ptr<Instrument> instr = boost::make_shared<Instrument>();
     input->setInstrument(instr);
     AnalysisDataService::Instance().add("someWS", input);
diff --git a/Framework/Algorithms/test/OneMinusExponentialCorTest.h b/Framework/Algorithms/test/OneMinusExponentialCorTest.h
index 87155739a4789dd704af1f5aecb17413ea6eb79d..7e478f782088289b4b34a6be85e12430ca5886fe 100644
--- a/Framework/Algorithms/test/OneMinusExponentialCorTest.h
+++ b/Framework/Algorithms/test/OneMinusExponentialCorTest.h
@@ -54,7 +54,7 @@ public:
 
   void testDivide() {
     MatrixWorkspace_sptr inputWS =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(2, 3, 0.5);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(2, 3, 0.5);
     AnalysisDataService::Instance().add("InputWS", inputWS);
 
     Mantid::Algorithms::OneMinusExponentialCor expon3;
@@ -91,7 +91,7 @@ public:
 
   void testDivideWithPrefactor() {
     MatrixWorkspace_sptr inputWS =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(2, 3, 0.5);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(2, 3, 0.5);
     AnalysisDataService::Instance().add("InputWS", inputWS);
 
     Mantid::Algorithms::OneMinusExponentialCor expon3;
@@ -130,7 +130,7 @@ public:
 
   void testMultiply() {
     MatrixWorkspace_sptr inputWS =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(2, 3, 0.5);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(2, 3, 0.5);
     AnalysisDataService::Instance().add("InputWS", inputWS);
 
     Mantid::Algorithms::OneMinusExponentialCor expon3;
@@ -168,7 +168,7 @@ public:
 
   void testMultiplyWithPrefactor() {
     MatrixWorkspace_sptr inputWS =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(2, 3, 0.5);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(2, 3, 0.5);
     AnalysisDataService::Instance().add("InputWS", inputWS);
 
     Mantid::Algorithms::OneMinusExponentialCor expon3;
@@ -207,7 +207,7 @@ public:
   }
 
   void testEvents() {
-    EventWorkspace_sptr evin = WorkspaceCreationHelper::CreateEventWorkspace(
+    EventWorkspace_sptr evin = WorkspaceCreationHelper::createEventWorkspace(
                             1, 5, 10, 0, 1, 3),
                         evout;
     AnalysisDataService::Instance().add("test_ev_omec", evin);
diff --git a/Framework/Algorithms/test/PDCalibrationTest.h b/Framework/Algorithms/test/PDCalibrationTest.h
index 650cfadc4b9bd85a643df3c5f5b31d768470c417..c9ba6ec54b2f7f6dd0281e979e8dc17b7c34a528 100644
--- a/Framework/Algorithms/test/PDCalibrationTest.h
+++ b/Framework/Algorithms/test/PDCalibrationTest.h
@@ -3,6 +3,7 @@
 
 #include <cxxtest/TestSuite.h>
 
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/FrameworkManager.h"
 #include "MantidAPI/ITableWorkspace.h"
 #include "MantidAPI/MatrixWorkspace.h"
diff --git a/Framework/Algorithms/test/PDDetermineCharacterizationsTest.h b/Framework/Algorithms/test/PDDetermineCharacterizationsTest.h
index 53ed207b16aeed91bfb6c488d953e4f235ba75a7..5466489117689f1ca5cd9ad341d8b92a120c020b 100644
--- a/Framework/Algorithms/test/PDDetermineCharacterizationsTest.h
+++ b/Framework/Algorithms/test/PDDetermineCharacterizationsTest.h
@@ -33,7 +33,8 @@ public:
   }
 
   void createLogWksp(const std::string &frequency,
-                     const std::string &wavelength) {
+                     const std::string &wavelength,
+                     const std::string &canName = std::string("")) {
     m_logWSName = "_det_char_log";
 
     {
@@ -64,52 +65,79 @@ public:
       alg->setPropertyValue("Workspace", m_logWSName);
       TS_ASSERT(alg->execute());
     }
+
+    if (!canName.empty()) {
+      auto alg = FrameworkManager::Instance().createAlgorithm("AddSampleLog");
+      alg->setPropertyValue("LogName", "SampleContainer");
+      alg->setPropertyValue("LogText", canName);
+      alg->setPropertyValue("LogType", "String");
+      alg->setPropertyValue("Workspace", m_logWSName);
+      TS_ASSERT(alg->execute());
+    }
   }
 
-  void addRow(ITableWorkspace_sptr wksp, double freq, double wl, int bank,
-              std::string van, std::string can, std::string empty,
-              std::string dmin, std::string dmax, double tofmin,
-              double tofmax) {
+  void addRow(ITableWorkspace_sptr wksp, const double freq, const double wl,
+              const int bank, const std::string &van,
+              const std::string &van_back, const std::string &can,
+              const std::string &empty_env, const std::string &empty_inst,
+              const std::string &dmin, const std::string &dmax,
+              const double tofmin, const double tofmax, const double wlmin,
+              const double wlmax,
+              const std::string &canExtra = std::string("")) {
     Mantid::API::TableRow row = wksp->appendRow();
     row << freq;
     row << wl;
     row << bank;
     row << van;
+    row << van_back;
     row << can;
-    row << empty;
+    row << empty_env;
+    row << empty_inst;
     row << dmin;
     row << dmax;
     row << tofmin;
     row << tofmax;
+    row << wlmin;
+    row << wlmax;
+    if (!canExtra.empty())
+      row << canExtra;
   }
 
-  ITableWorkspace_sptr createEmptyTableWksp() {
+  ITableWorkspace_sptr
+  createEmptyTableWksp(const std::string &canName = std::string("")) {
     ITableWorkspace_sptr wksp = WorkspaceFactory::Instance().createTable();
     wksp->addColumn("double", "frequency");
     wksp->addColumn("double", "wavelength");
     wksp->addColumn("int", "bank");
     wksp->addColumn("str", "vanadium");
+    wksp->addColumn("str", "vanadium_background");
     wksp->addColumn("str", "container");
-    wksp->addColumn("str", "empty");
+    wksp->addColumn("str", "empty_environment");
+    wksp->addColumn("str", "empty_instrument");
     wksp->addColumn("str", "d_min"); // b/c it is an array for NOMAD
     wksp->addColumn("str", "d_max"); // b/c it is an array for NOMAD
     wksp->addColumn("double", "tof_min");
     wksp->addColumn("double", "tof_max");
+    wksp->addColumn("double", "wavelength_min");
+    wksp->addColumn("double", "wavelength_max");
+    if (!canName.empty()) {
+      wksp->addColumn("str", canName);
+    }
 
     return wksp;
   }
 
   ITableWorkspace_sptr createTableWkspPG3() {
-    ITableWorkspace_sptr wksp = createEmptyTableWksp();
+    ITableWorkspace_sptr wksp = createEmptyTableWksp("PAC08");
 
-    addRow(wksp, 60., 0.533, 1, "17702", "17711", "0", "0.05", "2.20", 0000.00,
-           16666.67);
-    addRow(wksp, 60., 1.333, 3, "17703", "17712", "0", "0.43", "5.40", 12500.00,
-           29166.67);
-    addRow(wksp, 60., 2.665, 4, "17704", "17713", "0", "1.15", "9.20", 33333.33,
-           50000.00);
-    addRow(wksp, 60., 4.797, 5, "17705", "17714", "0", "2.00", "15.35",
-           66666.67, 83333.67);
+    addRow(wksp, 60., 0.533, 1, "17702", "1234", "17711", "0", "0", "0.05",
+           "2.20", 0000.00, 16666.67, 0., 0., "12345");
+    addRow(wksp, 60., 1.333, 3, "17703", "1235", "17712", "0", "0", "0.43",
+           "5.40", 12500.00, 29166.67, 0., 0., "12346");
+    addRow(wksp, 60., 2.665, 4, "17704", "1236", "17713", "0", "0", "1.15",
+           "9.20", 33333.33, 50000.00, 0., 0., "12347");
+    addRow(wksp, 60., 4.797, 5, "17705", "1237", "17714", "0", "0", "2.00",
+           "15.35", 66666.67, 83333.67, 0., 0., "12348");
 
     return wksp;
   }
@@ -117,18 +145,30 @@ public:
   ITableWorkspace_sptr createTableWkspNOM() {
     ITableWorkspace_sptr wksp = createEmptyTableWksp();
 
-    addRow(wksp, 60., 1.4, 1, "0", "0", "0", ".31,.25,.13,.13,.13,.42",
-           "13.66,5.83,3.93,2.09,1.57,31.42", 300.00, 16666.67);
+    addRow(wksp, 60., 1.4, 1, "0", "0", "0", "0", "0",
+           ".31,.25,.13,.13,.13,.42", "13.66,5.83,3.93,2.09,1.57,31.42", 300.00,
+           16666.67, 0., 0.);
+
+    return wksp;
+  }
+
+  ITableWorkspace_sptr createTableWkspNOM_withwl() {
+    ITableWorkspace_sptr wksp = createEmptyTableWksp();
+
+    addRow(wksp, 60., 1.4, 1, "0", "0", "0", "0", "0",
+           ".31,.25,.13,.13,.13,.42", "13.66,5.83,3.93,2.09,1.57,31.42", 300.00,
+           16666.67, .9, 2.1);
 
     return wksp;
   }
 
   PropertyManager_sptr
   createExpectedInfo(const double freq, const double wl, const int bank,
-                     const std::string &van, const std::string &can,
-                     const std::string &empty, const std::string &dmin,
-                     const std::string &dmax, const double tofmin,
-                     const double tofmax) {
+                     const std::string &van, const std::string &vanback,
+                     const std::string &can, const std::string &empty,
+                     const std::string &dmin, const std::string &dmax,
+                     const double tofmin, const double tofmax,
+                     const double wlmin, const double wlmax) {
 
     PropertyManager_sptr expectedInfo = boost::make_shared<PropertyManager>();
     expectedInfo->declareProperty(
@@ -139,10 +179,17 @@ public:
         make_unique<PropertyWithValue<int>>("bank", bank));
     expectedInfo->declareProperty(
         Mantid::Kernel::make_unique<ArrayProperty<int32_t>>("vanadium", van));
+    expectedInfo->declareProperty(
+        Mantid::Kernel::make_unique<ArrayProperty<int32_t>>(
+            "vanadium_background", vanback));
     expectedInfo->declareProperty(
         Mantid::Kernel::make_unique<ArrayProperty<int32_t>>("container", can));
     expectedInfo->declareProperty(
-        Mantid::Kernel::make_unique<ArrayProperty<int32_t>>("empty", empty));
+        Mantid::Kernel::make_unique<ArrayProperty<int32_t>>("empty_environment",
+                                                            "0"));
+    expectedInfo->declareProperty(
+        Mantid::Kernel::make_unique<ArrayProperty<int32_t>>("empty_instrument",
+                                                            empty));
     expectedInfo->declareProperty(
         Mantid::Kernel::make_unique<ArrayProperty<double>>("d_min", dmin));
     expectedInfo->declareProperty(
@@ -151,6 +198,10 @@ public:
         make_unique<PropertyWithValue<double>>("tof_min", tofmin));
     expectedInfo->declareProperty(
         make_unique<PropertyWithValue<double>>("tof_max", tofmax));
+    expectedInfo->declareProperty(
+        make_unique<PropertyWithValue<double>>("wavelength_min", wlmin));
+    expectedInfo->declareProperty(
+        make_unique<PropertyWithValue<double>>("wavelength_max", wlmax));
 
     return expectedInfo;
   }
@@ -187,8 +238,8 @@ public:
     TS_ASSERT_THROWS_NOTHING(alg.execute(););
     TS_ASSERT(alg.isExecuted());
 
-    auto expectedInfo =
-        createExpectedInfo(0., 0., 1, "0", "0", "0", "", "", 0., 0.);
+    auto expectedInfo = createExpectedInfo(0., 0., 1, "0", "0", "0", "0", "",
+                                           "", 0., 0., 0., 0.);
 
     compareResult(expectedInfo, PropertyManagerDataService::Instance().retrieve(
                                     PROPERTY_MANAGER_NAME));
@@ -208,8 +259,8 @@ public:
     TS_ASSERT_THROWS_NOTHING(alg.execute(););
     TS_ASSERT(alg.isExecuted());
 
-    auto expectedInfo =
-        createExpectedInfo(0., 0., 1, "0", "0", "0", "", "", 0., 0.);
+    auto expectedInfo = createExpectedInfo(0., 0., 1, "0", "0", "0", "0", "",
+                                           "", 0., 0., 0., 0.);
 
     compareResult(expectedInfo, PropertyManagerDataService::Instance().retrieve(
                                     PROPERTY_MANAGER_NAME));
@@ -229,8 +280,9 @@ public:
     TS_ASSERT_THROWS_NOTHING(alg.execute(););
     TS_ASSERT(alg.isExecuted());
 
-    auto expectedInfo = createExpectedInfo(60., 0.533, 1, "17702", "17711", "0",
-                                           "0.05", "2.20", 0000.00, 16666.67);
+    auto expectedInfo =
+        createExpectedInfo(60., 0.533, 1, "17702", "1234", "17711", "0", "0.05",
+                           "2.20", 0000.00, 16666.67, 0., 0.);
 
     compareResult(expectedInfo, PropertyManagerDataService::Instance().retrieve(
                                     PROPERTY_MANAGER_NAME));
@@ -253,8 +305,31 @@ public:
     TS_ASSERT_THROWS_NOTHING(alg.execute(););
     TS_ASSERT(alg.isExecuted());
 
-    auto expectedInfo = createExpectedInfo(60., 0.533, 1, "0", "0", "0", "0.05",
-                                           "2.20", 0000.00, 16666.67);
+    auto expectedInfo =
+        createExpectedInfo(60., 0.533, 1, "0", "0", "0", "0", "0.05", "2.20",
+                           0000.00, 16666.67, 0., 0.);
+
+    compareResult(expectedInfo, PropertyManagerDataService::Instance().retrieve(
+                                    PROPERTY_MANAGER_NAME));
+  }
+
+  void testFullCharWithCan() {
+    createLogWksp("60.", "0.533", "PAC 08");
+    auto tableWS = createTableWkspPG3();
+
+    PDDetermineCharacterizations alg;
+    TS_ASSERT_THROWS_NOTHING(alg.initialize());
+    TS_ASSERT_THROWS_NOTHING(
+        alg.setPropertyValue("InputWorkspace", m_logWSName));
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("Characterizations", tableWS));
+    TS_ASSERT_THROWS_NOTHING(
+        alg.setPropertyValue("ReductionProperties", PROPERTY_MANAGER_NAME));
+    TS_ASSERT_THROWS_NOTHING(alg.execute(););
+    TS_ASSERT(alg.isExecuted());
+
+    auto expectedInfo =
+        createExpectedInfo(60., 0.533, 1, "17702", "1234", "12345", "0", "0.05",
+                           "2.20", 0000.00, 16666.67, 0., 0.);
 
     compareResult(expectedInfo, PropertyManagerDataService::Instance().retrieve(
                                     PROPERTY_MANAGER_NAME));
@@ -275,8 +350,8 @@ public:
     TS_ASSERT(alg.isExecuted());
 
     auto expectedInfo = createExpectedInfo(
-        60., 1.4, 1, "0", "0", "0", ".31,.25,.13,.13,.13,.42",
-        "13.66,5.83,3.93,2.09,1.57,31.42", 300.00, 16666.67);
+        60., 1.4, 1, "0", "0", "0", "0", ".31,.25,.13,.13,.13,.42",
+        "13.66,5.83,3.93,2.09,1.57,31.42", 300.00, 16666.67, 0., 0.);
 
     compareResult(expectedInfo, PropertyManagerDataService::Instance().retrieve(
                                     PROPERTY_MANAGER_NAME));
@@ -300,8 +375,30 @@ public:
     TS_ASSERT(alg.isExecuted());
 
     auto expectedInfo = createExpectedInfo(
-        60., 1.4, 1, "1,2", "3,4", "5,6", ".31,.25,.13,.13,.13,.42",
-        "13.66,5.83,3.93,2.09,1.57,31.42", 300.00, 16666.67);
+        60., 1.4, 1, "1,2", "5,6", "3,4", "0", ".31,.25,.13,.13,.13,.42",
+        "13.66,5.83,3.93,2.09,1.57,31.42", 300.00, 16666.67, 0., 0.);
+
+    compareResult(expectedInfo, PropertyManagerDataService::Instance().retrieve(
+                                    PROPERTY_MANAGER_NAME));
+  }
+
+  void testNomWithWL() {
+    createLogWksp("60.", "1.4");
+    auto tableWS = createTableWkspNOM_withwl();
+
+    PDDetermineCharacterizations alg;
+    TS_ASSERT_THROWS_NOTHING(alg.initialize());
+    TS_ASSERT_THROWS_NOTHING(
+        alg.setPropertyValue("InputWorkspace", m_logWSName));
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("Characterizations", tableWS));
+    TS_ASSERT_THROWS_NOTHING(
+        alg.setPropertyValue("ReductionProperties", PROPERTY_MANAGER_NAME));
+    TS_ASSERT_THROWS_NOTHING(alg.execute(););
+    TS_ASSERT(alg.isExecuted());
+
+    auto expectedInfo = createExpectedInfo(
+        60., 1.4, 1, "0", "0", "0", "0", ".31,.25,.13,.13,.13,.42",
+        "13.66,5.83,3.93,2.09,1.57,31.42", 300.00, 16666.67, .9, 2.1);
 
     compareResult(expectedInfo, PropertyManagerDataService::Instance().retrieve(
                                     PROPERTY_MANAGER_NAME));
diff --git a/Framework/Algorithms/test/PerformIndexOperationsTest.h b/Framework/Algorithms/test/PerformIndexOperationsTest.h
index da5036892cc04d50f542b3c92b46f983e5396561..b8554d36c142268a841d26024f301a21136aa4c6 100644
--- a/Framework/Algorithms/test/PerformIndexOperationsTest.h
+++ b/Framework/Algorithms/test/PerformIndexOperationsTest.h
@@ -4,6 +4,7 @@
 #include <cxxtest/TestSuite.h>
 #include "MantidAlgorithms/PerformIndexOperations.h"
 #include "MantidAPI/AlgorithmManager.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/MatrixWorkspace.h"
 
 using Mantid::Algorithms::PerformIndexOperations;
diff --git a/Framework/Algorithms/test/PhaseQuadMuonTest.h b/Framework/Algorithms/test/PhaseQuadMuonTest.h
index ec8dfc94a65b43a12950ba7b39ebef118e30d0ff..0bef833612188a0b3c22b33381d26448bda8dcda 100644
--- a/Framework/Algorithms/test/PhaseQuadMuonTest.h
+++ b/Framework/Algorithms/test/PhaseQuadMuonTest.h
@@ -3,6 +3,7 @@
 
 #include <cxxtest/TestSuite.h>
 #include "MantidAPI/AlgorithmManager.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Axis.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidDataObjects/TableWorkspace.h"
@@ -133,4 +134,4 @@ private:
   IAlgorithm_sptr phaseQuad;
 };
 
-#endif /* MANTID_ALGORITHMS_PHASEQUADMUONTEST_H_ */
\ No newline at end of file
+#endif /* MANTID_ALGORITHMS_PHASEQUADMUONTEST_H_ */
diff --git a/Framework/Algorithms/test/PlusMinusTest.in.h b/Framework/Algorithms/test/PlusMinusTest.in.h
index c58ae6c369e0e266ce03d3e0a1330fe59c145c5d..2f7391d33ff1c93a12279564a388d35400de4391 100644
--- a/Framework/Algorithms/test/PlusMinusTest.in.h
+++ b/Framework/Algorithms/test/PlusMinusTest.in.h
@@ -23,7 +23,7 @@ using namespace Mantid::DataObjects;
 
 /*****************************************************************************************/
 /********** PLEASE NOTE! THIS FILE WAS AUTO-GENERATED FROM CMAKE.  ***********************/
-/********** Source = PlusMinusTest.h.in **************************************************/
+/********** Source = PlusMinusTest.in.h **************************************************/
 /*****************************************************************************************/
 
 class @PLUSMINUSTEST_CLASS@ : public CxxTest::TestSuite
@@ -43,12 +43,12 @@ public:
     wsNameOut = "MinusTest_outputWorkspace";
     DO_PLUS = @PLUSMINUSTEST_DO_PLUS@;
 
-    fibWS1d = WorkspaceCreationHelper::Create1DWorkspaceFib(5);
-    histWS_5x10_123 = WorkspaceCreationHelper::Create2DWorkspace123(5,10);
-    histWS_5x10_154 = WorkspaceCreationHelper::Create2DWorkspace154(5,10);
-    histWS_5x10_bin = WorkspaceCreationHelper::Create2DWorkspace(5,10);
-    eventWS_5x10_50 = WorkspaceCreationHelper::CreateEventWorkspace(5,10,50,0.0,1.0,2);
-    eventWS_small = WorkspaceCreationHelper::CreateEventWorkspace(numPixels, numBins, numBins, 0.0, 1.0, 2);
+    fibWS1d = WorkspaceCreationHelper::create1DWorkspaceFib(5);
+    histWS_5x10_123 = WorkspaceCreationHelper::create2DWorkspace123(5,10);
+    histWS_5x10_154 = WorkspaceCreationHelper::create2DWorkspace154(5,10);
+    histWS_5x10_bin = WorkspaceCreationHelper::create2DWorkspace(5,10);
+    eventWS_5x10_50 = WorkspaceCreationHelper::createEventWorkspace(5,10,50,0.0,1.0,2);
+    eventWS_small = WorkspaceCreationHelper::createEventWorkspace(numPixels, numBins, numBins, 0.0, 1.0, 2);
   }
 
   void testInit()
@@ -82,9 +82,9 @@ public:
 
   void test_CompoundAssignment()
   {
-    Workspace2D_sptr a = WorkspaceCreationHelper::Create2DWorkspace(5,5);
+    Workspace2D_sptr a = WorkspaceCreationHelper::create2DWorkspace(5,5);
     const Workspace_const_sptr b = a;
-    Workspace2D_sptr c = WorkspaceCreationHelper::Create2DWorkspace(5,5);
+    Workspace2D_sptr c = WorkspaceCreationHelper::create2DWorkspace(5,5);
     if (DO_PLUS)
     {
       a += 5;
@@ -129,9 +129,9 @@ public:
   {
     if (DO_PLUS)
     {
-      MatrixWorkspace_sptr a = WorkspaceCreationHelper::CreateWorkspaceSingleValue(3);
+      MatrixWorkspace_sptr a = WorkspaceCreationHelper::createWorkspaceSingleValue(3);
       a->mutableRun().setProtonCharge(10.);
-      MatrixWorkspace_sptr b = WorkspaceCreationHelper::CreateWorkspaceSingleValue(2);
+      MatrixWorkspace_sptr b = WorkspaceCreationHelper::createWorkspaceSingleValue(2);
       b->mutableRun().setProtonCharge(5.);
       AnalysisDataService::Instance().add("a", a);
       AnalysisDataService::Instance().add("b", b);
@@ -167,7 +167,7 @@ public:
   {
     int nBins = 5;
     MatrixWorkspace_sptr work_in1 = fibWS1d;
-    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::Create1DWorkspaceRand(nBins);
+    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::create1DWorkspaceRand(nBins);
     performTest(work_in1,work_in2);
   }
 
@@ -182,7 +182,7 @@ public:
   void test_2D_2D_inplace()
   {
     int nHist = 5,nBins=10;
-    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::Create2DWorkspaceBinned(nHist,nBins);
+    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::create2DWorkspaceBinned(nHist,nBins);
     MatrixWorkspace_sptr work_in2 = histWS_5x10_bin;
     performTest(work_in1,work_in2, true /*inplace*/, false /*not event*/,
         DO_PLUS ? 4.0 : 0.0,   2.0);
@@ -198,16 +198,16 @@ public:
   void test_2D_2D_Histograms()
   {
     int nHist = 5,nBins=10;
-    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::Create2DWorkspace123(nHist,nBins, true);
-    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::Create2DWorkspace154(nHist,nBins, true);
+    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::create2DWorkspace123(nHist,nBins, true);
+    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::create2DWorkspace154(nHist,nBins, true);
     performTest(work_in1,work_in2);
   }
 
   void test_1D_Rand2D()
   {
     int nHist = 5,nBins=5;
-    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::Create2DWorkspace154(nHist,nBins);
-    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::Create1DWorkspaceRand(nBins);
+    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::create2DWorkspace154(nHist,nBins);
+    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::create1DWorkspaceRand(nBins);
     performTest(work_in1,work_in2);
   }
 
@@ -215,14 +215,14 @@ public:
   {
     int nBins=10;
     MatrixWorkspace_sptr work_in1 = histWS_5x10_154;
-    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::Create2DWorkspace123(1,nBins);
+    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::create2DWorkspace123(1,nBins);
     performTest(work_in1,work_in2);
   }
 
   void test_1DVertical_2D()
   {
     int nBins=10;
-    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::Create2DWorkspace123(1,nBins);
+    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::create2DWorkspace123(1,nBins);
     MatrixWorkspace_sptr work_in2 = histWS_5x10_154;
     if (DO_PLUS)
     {
@@ -238,8 +238,8 @@ public:
   {
     //In 2D workspaces, the X bins have to match
     int nHist = 10,nBins=5;
-    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::Create2DWorkspace123(nHist,nBins);
-    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::Create2DWorkspace154(1,nBins*5);
+    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::create2DWorkspace123(nHist,nBins);
+    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::create2DWorkspace154(1,nBins*5);
     performTest_fails(work_in1, work_in2);
   }
 
@@ -274,15 +274,15 @@ public:
   void test_1D_SingleValue()
   {
     MatrixWorkspace_sptr work_in1 = fibWS1d;
-    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::CreateWorkspaceSingleValue(2.2);
+    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::createWorkspaceSingleValue(2.2);
     performTest(work_in1,work_in2);
   }
 
   void test_SingleValue_1D()
   {
     int nBins = 5;
-    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::CreateWorkspaceSingleValue(2.2);
-    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::Create2DWorkspaceBinned(1,nBins);
+    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::createWorkspaceSingleValue(2.2);
+    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::create2DWorkspaceBinned(1,nBins);
     if (DO_PLUS)
       MatrixWorkspace_sptr out = performTest(work_in1,work_in2,
           false /*in place*/, false /*not event*/,
@@ -296,22 +296,22 @@ public:
   void test_2D_SingleValue()
   {
     MatrixWorkspace_sptr work_in1 = histWS_5x10_bin;
-    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::CreateWorkspaceSingleValue(4.455);
+    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::createWorkspaceSingleValue(4.455);
     performTest(work_in1,work_in2);
   }
 
   void test_2D_SingleValue_InPlace()
   {
     int nHist =5,nBins=10;
-    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::Create2DWorkspaceBinned(nHist,nBins);
-    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::CreateWorkspaceSingleValue(4.455);
+    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::create2DWorkspaceBinned(nHist,nBins);
+    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::createWorkspaceSingleValue(4.455);
     performTest(work_in1,work_in2, true /*in place*/, false /*not event*/,
         DO_PLUS ? 6.455 : -2.455,   2.5406);
   }
 
   void test_SingleValue_2D()
   {
-    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::CreateWorkspaceSingleValue(4.455);
+    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::createWorkspaceSingleValue(4.455);
     MatrixWorkspace_sptr work_in2 = histWS_5x10_bin;
     if (DO_PLUS)
     {
@@ -330,7 +330,7 @@ public:
   void test_2D_SingleValueNoError()
   {
     MatrixWorkspace_sptr work_in1 = histWS_5x10_bin;
-    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::CreateWorkspaceSingleValueWithError(5.0, 0.0);
+    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::createWorkspaceSingleValueWithError(5.0, 0.0);
     performTest(work_in1,work_in2);
   }
 
@@ -341,7 +341,7 @@ public:
   void test_Event_SingleValue()
   {
     MatrixWorkspace_sptr work_in1 = eventWS_5x10_50;
-    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::CreateWorkspaceSingleValue(2.0);
+    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::createWorkspaceSingleValue(2.0);
     // Become a WS2D
     performTest(work_in1, work_in2, false, false /*output is NOT event*/ );
   }
@@ -349,13 +349,13 @@ public:
   void test_Event_SingleValue_inPlace_fails()
   {
     MatrixWorkspace_sptr work_in1 = eventWS_5x10_50;
-    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::CreateWorkspaceSingleValue(2.0);
+    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::createWorkspaceSingleValue(2.0);
     performTest_fails(work_in1, work_in2, true);
   }
 
   void test_SingleValue_Event()
   {
-    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::CreateWorkspaceSingleValue(2.0);
+    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::createWorkspaceSingleValue(2.0);
     MatrixWorkspace_sptr work_in2 = eventWS_5x10_50;
     // Become a WS2D
     if (DO_PLUS)
@@ -374,7 +374,7 @@ public:
   void test_SingleValue_Event_inPlace_fails()
   {
     MatrixWorkspace_sptr work_in1 = eventWS_5x10_50;
-    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::CreateWorkspaceSingleValue(2.0);
+    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::createWorkspaceSingleValue(2.0);
     // Become a WS2D
     performTest_fails(work_in1, work_in2, true);
   }
@@ -391,7 +391,7 @@ public:
   void test_2D_Event_inPlace()
   {
     int nHist = 5, nBins=10;
-    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::Create2DWorkspace(nHist,nBins);
+    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::create2DWorkspace(nHist,nBins);
     MatrixWorkspace_sptr work_in2 = eventWS_5x10_50;
     // You have to specify the expected output value because in1 gets changed.
     performTest(work_in1,work_in2, true, false /*not event out*/,
@@ -417,14 +417,14 @@ public:
   void test_Event_2DSingleSpectrum()
   {
     MatrixWorkspace_sptr work_in1 = eventWS_5x10_50;
-    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::Create2DWorkspace(1, 10);
+    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::create2DWorkspace(1, 10);
     performTest(work_in1,work_in2, false);
   }
 
   void test_Event_2DSingleSpectrum_inPlace_fails()
   {
     MatrixWorkspace_sptr work_in1 = eventWS_5x10_50;
-    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::Create2DWorkspace(1, 10);
+    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::create2DWorkspace(1, 10);
     performTest_fails(work_in1,work_in2, true);
   }
 
@@ -432,7 +432,7 @@ public:
   {
     for(int inplace=0; inplace<2;inplace++)
     {
-      MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::Create2DWorkspace(1, 10);
+      MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::create2DWorkspace(1, 10);
       MatrixWorkspace_sptr work_in2 = eventWS_5x10_50;
       if (DO_PLUS)
       {
@@ -480,7 +480,7 @@ public:
   void test_Event_Event_inPlace()
   {
     int nHist = 5,nBins=10;
-    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::CreateEventWorkspace(nHist,nBins,50,0.0,1.0,2);
+    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::createEventWorkspace(nHist,nBins,50,0.0,1.0,2);
     MatrixWorkspace_sptr work_in2 = eventWS_5x10_50;
     MatrixWorkspace_sptr work_out = performTest(work_in1,work_in2, true, true /*outputIsEvent*/,
         DO_PLUS ? 4.0 : 0.0,   DO_PLUS ? 2.0 : 2.0);
@@ -489,13 +489,13 @@ public:
   void test_Event_EventSingleSpectrum_fails()
   {
     MatrixWorkspace_sptr work_in1 = eventWS_5x10_50;
-    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::CreateEventWorkspace(1,10,50,0.0,1.0,2);
+    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::createEventWorkspace(1,10,50,0.0,1.0,2);
     performTest_fails(work_in1,work_in2, false);
   }
 
   void test_EventSingleSpectrum_Event_fails()
   {
-    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::CreateEventWorkspace(1,10,50,0.0,1.0,2);
+    MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::createEventWorkspace(1,10,50,0.0,1.0,2);
     MatrixWorkspace_sptr work_in2 = eventWS_5x10_50;
     performTest_fails(work_in1,work_in2, false);
   }
@@ -506,8 +506,8 @@ public:
     for(int inplace=0; inplace<2;inplace++)
     {
       int nHist = 5,nBins=1;
-      MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::CreateEventWorkspace(nHist,nBins,50,0.0,1.0,2);
-      MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::CreateEventWorkspace(nHist,nBins,50,0.0,1.0,2);
+      MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::createEventWorkspace(nHist,nBins,50,0.0,1.0,2);
+      MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::createEventWorkspace(nHist,nBins,50,0.0,1.0,2);
       MatrixWorkspace_sptr work_out = performTest(work_in1,work_in2, inplace!=0, true /*outputIsEvent*/,
           DO_PLUS ? 4.0 : 0.0,   DO_PLUS ? 2.0 : 2.0);
     }
@@ -518,8 +518,8 @@ public:
     for(int inplace=0; inplace<2;inplace++)
     {
       int nHist = 5,nBins=10;
-      MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::CreateEventWorkspace(nHist,nBins,50,0.0,1.0,2);
-      MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::CreateEventWorkspace(nHist,1,50,0.0,1.0,2);
+      MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::createEventWorkspace(nHist,nBins,50,0.0,1.0,2);
+      MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::createEventWorkspace(nHist,1,50,0.0,1.0,2);
       MatrixWorkspace_sptr work_out = performTest(work_in1,work_in2, inplace!=0, true /*outputIsEvent*/,
           DO_PLUS ? 4.0 : 0.0,   DO_PLUS ? 2.0 : 2.0);
     }
@@ -529,7 +529,7 @@ public:
   {
     for(int inplace=0; inplace<2;inplace++)
     {
-      MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::CreateEventWorkspace(5,1,50,0.0,1.0,2);
+      MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::createEventWorkspace(5,1,50,0.0,1.0,2);
       MatrixWorkspace_sptr work_in2 = eventWS_5x10_50;
       MatrixWorkspace_sptr work_out = performTest(work_in1,work_in2, inplace!=0, true /*outputIsEvent*/,
           DO_PLUS ? 4.0 : 0.0,   DO_PLUS ? 2.0 : 2.0);
@@ -541,8 +541,8 @@ public:
     for(int inplace=0; inplace<2;inplace++)
     {
       int nHist=1,nBins=1;
-      MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::CreateEventWorkspace(nHist,nBins,50,0.0,1.0,2);
-      MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::CreateEventWorkspace(nHist,nBins,50,0.0,1.0,2);
+      MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::createEventWorkspace(nHist,nBins,50,0.0,1.0,2);
+      MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::createEventWorkspace(nHist,nBins,50,0.0,1.0,2);
       MatrixWorkspace_sptr work_out = performTest(work_in1,work_in2, inplace!=0, true /*outputIsEvent*/,
           DO_PLUS ? 4.0 : 0.0,   DO_PLUS ? 2.0 : 2.0);
     }
@@ -556,7 +556,7 @@ public:
   void test_Event_IncompatibleUnits_fails()
   {
     MatrixWorkspace_sptr work_in1 = eventWS_5x10_50;
-    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::CreateEventWorkspace(5,10,50,0.0,1.0,2);
+    MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::createEventWorkspace(5,10,50,0.0,1.0,2);
     work_in2->setYUnit("Microfurlongs per Megafortnights");
     performTest_fails(work_in1,work_in2, false /*not inplace*/);
   }
@@ -567,8 +567,8 @@ public:
   {
     for (int inplace =0; inplace < 2; inplace++)
     {
-      MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::CreateEventWorkspace(3,10,50, 0.0, 1.0, 3); // 5 ev
-      MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::CreateEventWorkspace(3,10,50, 0.0, 1.0, 2, 100); //100 events per spectrum, but the spectra are at different pixel ids
+      MatrixWorkspace_sptr work_in1 = WorkspaceCreationHelper::createEventWorkspace(3,10,50, 0.0, 1.0, 3); // 5 ev
+      MatrixWorkspace_sptr work_in2 = WorkspaceCreationHelper::createEventWorkspace(3,10,50, 0.0, 1.0, 2, 100); //100 events per spectrum, but the spectra are at different pixel ids
 
       //First pixel id of rhs is 100
       TS_ASSERT( work_in2->getSpectrum(0).hasDetectorID(100) );
@@ -1049,7 +1049,7 @@ public:
   void test_EventWorkspace_EventWorkspace_clearRHS()
   {
     EventWorkspace_sptr lhs = eventWS_small;
-    EventWorkspace_sptr rhs = WorkspaceCreationHelper::CreateEventWorkspace(numPixels, numBins, numBins, 0.0, 1.0, 2);
+    EventWorkspace_sptr rhs = WorkspaceCreationHelper::createEventWorkspace(numPixels, numBins, numBins, 0.0, 1.0, 2);
     performTest_withClearRHS(lhs,rhs, true, true, lhs->getNumberEvents() + rhs->getNumberEvents(), true);
   }
 
@@ -1063,7 +1063,7 @@ public:
   void test_Workspace2D_EventWorkspace_clearRHS()
   {
     MatrixWorkspace_sptr lhs = histWS_5x10_bin;
-    EventWorkspace_sptr rhs = WorkspaceCreationHelper::CreateEventWorkspace(numPixels, numBins, numBins, 0.0, 1.0, 2);
+    EventWorkspace_sptr rhs = WorkspaceCreationHelper::createEventWorkspace(numPixels, numBins, numBins, 0.0, 1.0, 2);
     performTest_withClearRHS(lhs,rhs, true, false, 0, true);
   }
 
@@ -1077,28 +1077,28 @@ public:
   void test_EventWorkspace_Workspace2D_clearRHS()
   {
     EventWorkspace_sptr lhs = eventWS_small;
-    MatrixWorkspace_sptr rhs = WorkspaceCreationHelper::Create2DWorkspace(numPixels, numBins);
+    MatrixWorkspace_sptr rhs = WorkspaceCreationHelper::create2DWorkspace(numPixels, numBins);
     performTest_withClearRHS(lhs,rhs, true, false, 0, false);
   }
 
 
   void test_EventWorkspace_EventWorkspace_inPlace_of_lhs()
   {
-    EventWorkspace_sptr lhs = WorkspaceCreationHelper::CreateEventWorkspace(numPixels, numBins, numBins, 0.0, 1.0, 2);
-    EventWorkspace_sptr rhs = WorkspaceCreationHelper::CreateEventWorkspace(numPixels, numBins, numBins, 0.0, 1.0, 2);
+    EventWorkspace_sptr lhs = WorkspaceCreationHelper::createEventWorkspace(numPixels, numBins, numBins, 0.0, 1.0, 2);
+    EventWorkspace_sptr rhs = WorkspaceCreationHelper::createEventWorkspace(numPixels, numBins, numBins, 0.0, 1.0, 2);
     performTest_withClearRHS(lhs,rhs, false, true, lhs->getNumberEvents() + rhs->getNumberEvents(), false, 1);
   }
 
   void test_EventWorkspace_EventWorkspace_inPlace_of_rhs()
   {
-    EventWorkspace_sptr lhs = WorkspaceCreationHelper::CreateEventWorkspace(numPixels, numBins, numBins, 0.0, 1.0, 2);
-    EventWorkspace_sptr rhs = WorkspaceCreationHelper::CreateEventWorkspace(numPixels, numBins, numBins, 0.0, 1.0, 2);
+    EventWorkspace_sptr lhs = WorkspaceCreationHelper::createEventWorkspace(numPixels, numBins, numBins, 0.0, 1.0, 2);
+    EventWorkspace_sptr rhs = WorkspaceCreationHelper::createEventWorkspace(numPixels, numBins, numBins, 0.0, 1.0, 2);
     performTest_withClearRHS(lhs,rhs, false, true, lhs->getNumberEvents() + rhs->getNumberEvents(), false, 2);
   }
 
   void test_EventWorkspace_EventWorkspace_inPlace_AND_lhs_is_rhs()
   {
-    EventWorkspace_sptr lhs = WorkspaceCreationHelper::CreateEventWorkspace(numPixels, numBins, numBins, 0.0, 1.0, 2);
+    EventWorkspace_sptr lhs = WorkspaceCreationHelper::createEventWorkspace(numPixels, numBins, numBins, 0.0, 1.0, 2);
     EventWorkspace_sptr rhs = lhs;
     performTest_withClearRHS(lhs,rhs, false, true, lhs->getNumberEvents() + rhs->getNumberEvents(), false, 1);
   }
@@ -1112,15 +1112,15 @@ public:
 
   void test_EventWorkspace_EventWorkspace_lhs_is_rhs_with_clearRHS_set_doesnt_clearRHS()
   {
-    EventWorkspace_sptr lhs = WorkspaceCreationHelper::CreateEventWorkspace(numPixels, numBins, numBins, 0.0, 1.0, 2);
+    EventWorkspace_sptr lhs = WorkspaceCreationHelper::createEventWorkspace(numPixels, numBins, numBins, 0.0, 1.0, 2);
     EventWorkspace_sptr rhs = lhs;
     performTest_withClearRHS(lhs,rhs, false, true, lhs->getNumberEvents() + rhs->getNumberEvents(), false);
   }
 
   void test_EventWorkspace_EventWorkspace_inPlace_of_rhs_with_clearRHS_set_doesnt_clearRHS()
   {
-    EventWorkspace_sptr lhs = WorkspaceCreationHelper::CreateEventWorkspace(numPixels, numBins, numBins, 0.0, 1.0, 2);
-    EventWorkspace_sptr rhs = WorkspaceCreationHelper::CreateEventWorkspace(numPixels, numBins, numBins, 0.0, 1.0, 2);
+    EventWorkspace_sptr lhs = WorkspaceCreationHelper::createEventWorkspace(numPixels, numBins, numBins, 0.0, 1.0, 2);
+    EventWorkspace_sptr rhs = WorkspaceCreationHelper::createEventWorkspace(numPixels, numBins, numBins, 0.0, 1.0, 2);
     performTest_withClearRHS(lhs,rhs, false, true, lhs->getNumberEvents() + rhs->getNumberEvents(), false, 2);
   }
 
@@ -1148,8 +1148,8 @@ public:
   
   void setUp() override
   {
-  	ws2D_1 = WorkspaceCreationHelper::Create2DWorkspace(10000 /*histograms*/, 1000/*bins*/);
-   	ws2D_2 = WorkspaceCreationHelper::Create2DWorkspace(10000 /*histograms*/, 1000/*bins*/);
+  	ws2D_1 = WorkspaceCreationHelper::create2DWorkspace(10000 /*histograms*/, 1000/*bins*/);
+   	ws2D_2 = WorkspaceCreationHelper::create2DWorkspace(10000 /*histograms*/, 1000/*bins*/);
   }
   
   void test_large_2D()
diff --git a/Framework/Algorithms/test/PointByPointVCorrectionTest.h b/Framework/Algorithms/test/PointByPointVCorrectionTest.h
index 2fd6d9756f078177c191c560f07c520cc1e30263..27a3facbc81640a9fc2afc4918ede3101357a508 100644
--- a/Framework/Algorithms/test/PointByPointVCorrectionTest.h
+++ b/Framework/Algorithms/test/PointByPointVCorrectionTest.h
@@ -26,9 +26,9 @@ public:
       pbpv.initialize();
 
     MatrixWorkspace_sptr testSample =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(2, 5, 0.5, 1.5);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(2, 5, 0.5, 1.5);
     MatrixWorkspace_sptr testVanadium =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(2, 5, 0.5, 1.5);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(2, 5, 0.5, 1.5);
     // Make the instruments match
     Mantid::Geometry::Instrument_sptr inst(new Mantid::Geometry::Instrument);
     testSample->setInstrument(inst);
@@ -81,9 +81,9 @@ public:
 
   void setUp() override {
     MatrixWorkspace_sptr testSample =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(20000, 5, 0.5, 1.5);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(20000, 5, 0.5, 1.5);
     MatrixWorkspace_sptr testVanadium =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(20000, 5, 0.5, 1.5);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(20000, 5, 0.5, 1.5);
     // Make the instruments match
     Mantid::Geometry::Instrument_sptr inst(new Mantid::Geometry::Instrument);
     testSample->setInstrument(inst);
diff --git a/Framework/Algorithms/test/PoissonErrorsTest.h b/Framework/Algorithms/test/PoissonErrorsTest.h
index 184450dd3b4061dc1a61a2f7966710fa9ff19b30..ddcbd42bb10b6eb56ce0286af31274d554f7062c 100644
--- a/Framework/Algorithms/test/PoissonErrorsTest.h
+++ b/Framework/Algorithms/test/PoissonErrorsTest.h
@@ -48,9 +48,9 @@ public:
     int nBins = 10;
     // Register the workspace in the data service
     MatrixWorkspace_sptr work_in1 =
-        WorkspaceCreationHelper::Create1DWorkspaceFib(nBins);
+        WorkspaceCreationHelper::create1DWorkspaceFib(nBins);
     MatrixWorkspace_sptr work_in2 =
-        WorkspaceCreationHelper::Create1DWorkspaceFib(nBins);
+        WorkspaceCreationHelper::create1DWorkspaceFib(nBins);
     AnalysisDataService::Instance().add("test_in11", work_in1);
     AnalysisDataService::Instance().add("test_in12", work_in2);
 
@@ -78,9 +78,9 @@ public:
     int nBins = 10;
     // Register the workspace in the data service
     MatrixWorkspace_sptr work_in1 =
-        WorkspaceCreationHelper::Create1DWorkspaceFib(nBins);
+        WorkspaceCreationHelper::create1DWorkspaceFib(nBins);
     MatrixWorkspace_sptr work_in2 =
-        WorkspaceCreationHelper::Create1DWorkspaceRand(nBins);
+        WorkspaceCreationHelper::create1DWorkspaceRand(nBins);
     AnalysisDataService::Instance().add("test_in11", work_in1);
     AnalysisDataService::Instance().add("test_in12", work_in2);
 
@@ -108,9 +108,9 @@ public:
     int nHist = 10, nBins = 20;
     // Register the workspace in the data service
     MatrixWorkspace_sptr work_in1 =
-        WorkspaceCreationHelper::Create2DWorkspace154(nHist, nBins);
+        WorkspaceCreationHelper::create2DWorkspace154(nHist, nBins);
     MatrixWorkspace_sptr work_in2 =
-        WorkspaceCreationHelper::Create2DWorkspace123(nHist, nBins);
+        WorkspaceCreationHelper::create2DWorkspace123(nHist, nBins);
 
     PoissonErrors alg;
 
@@ -138,9 +138,9 @@ public:
     int nHist = 10, nBins = 20;
     // Register the workspace in the data service
     MatrixWorkspace_sptr work_in1 =
-        WorkspaceCreationHelper::Create2DWorkspace154(nHist, nBins);
+        WorkspaceCreationHelper::create2DWorkspace154(nHist, nBins);
     MatrixWorkspace_sptr work_in2 =
-        WorkspaceCreationHelper::Create1DWorkspaceFib(nBins);
+        WorkspaceCreationHelper::create1DWorkspaceFib(nBins);
 
     PoissonErrors alg;
 
@@ -162,9 +162,9 @@ public:
     int nHist = 10, nBins = 20;
     // Register the workspace in the data service
     MatrixWorkspace_sptr work_in2 =
-        WorkspaceCreationHelper::Create1DWorkspaceRand(nBins);
+        WorkspaceCreationHelper::create1DWorkspaceRand(nBins);
     MatrixWorkspace_sptr work_in1 =
-        WorkspaceCreationHelper::Create2DWorkspace154(nHist, nBins);
+        WorkspaceCreationHelper::create2DWorkspace154(nHist, nBins);
 
     PoissonErrors alg;
 
@@ -187,9 +187,9 @@ public:
     // Register the workspace in the data service
 
     MatrixWorkspace_sptr work_in1 =
-        WorkspaceCreationHelper::Create1DWorkspaceFib(nBins);
+        WorkspaceCreationHelper::create1DWorkspaceFib(nBins);
     MatrixWorkspace_sptr work_in2 =
-        WorkspaceCreationHelper::CreateWorkspaceSingleValue(2.2);
+        WorkspaceCreationHelper::createWorkspaceSingleValue(2.2);
     AnalysisDataService::Instance().add("test_in11", work_in1);
     AnalysisDataService::Instance().add("test_in12", work_in2);
 
@@ -211,9 +211,9 @@ public:
     int nBins = 300;
     // Register the workspace in the data service
     MatrixWorkspace_sptr work_in1 =
-        WorkspaceCreationHelper::Create1DWorkspaceFib(nBins);
+        WorkspaceCreationHelper::create1DWorkspaceFib(nBins);
     MatrixWorkspace_sptr work_in2 =
-        WorkspaceCreationHelper::CreateWorkspaceSingleValue(4.455);
+        WorkspaceCreationHelper::createWorkspaceSingleValue(4.455);
 
     PoissonErrors alg;
 
diff --git a/Framework/Algorithms/test/PolarizationCorrectionTest.h b/Framework/Algorithms/test/PolarizationCorrectionTest.h
index 64118deb7130cf520392197adf4a02ec10e7b611..e5e9c6ee69677d9e367ea672a0b16093b1981bb5 100644
--- a/Framework/Algorithms/test/PolarizationCorrectionTest.h
+++ b/Framework/Algorithms/test/PolarizationCorrectionTest.h
@@ -9,6 +9,7 @@
 #include <boost/make_shared.hpp>
 #include "MantidTestHelpers/WorkspaceCreationHelper.h"
 #include "MantidAPI/AlgorithmManager.h"
+#include "MantidAPI/WorkspaceGroup.h"
 
 using namespace Mantid::API;
 using namespace Mantid::Algorithms;
@@ -136,7 +137,7 @@ public:
 
   MatrixWorkspace_sptr create1DWorkspace(int size, double signal,
                                          double error) {
-    auto ws = Create1DWorkspaceConstant(size, signal, error);
+    auto ws = create1DWorkspaceConstant(size, signal, error);
     ws->getAxis(0)->setUnit("Wavelength");
     return ws;
   }
diff --git a/Framework/Algorithms/test/PolynomialCorrectionTest.h b/Framework/Algorithms/test/PolynomialCorrectionTest.h
index 769385b750e38a68456e8cf1a7dfa29ee592e9f7..143e1e4539c7df55c7e6e064112ca8f7c200ae05 100644
--- a/Framework/Algorithms/test/PolynomialCorrectionTest.h
+++ b/Framework/Algorithms/test/PolynomialCorrectionTest.h
@@ -50,7 +50,7 @@ public:
     const std::string wsName = "PolynomialCorrectionTest_inputWS";
     const std::string wsNameOut = "PolynomialCorrectionTest_outputWS";
     MatrixWorkspace_sptr inputWS =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(2, 3, 0.5);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(2, 3, 0.5);
     AnalysisDataService::Instance().add(wsName, inputWS);
 
     Mantid::Algorithms::PolynomialCorrection poly3;
@@ -89,7 +89,7 @@ public:
     const std::string wsName = "PolynomialCorrectionTest_inputWS";
     const std::string wsNameOut = "PolynomialCorrectionTest_outputWS";
     MatrixWorkspace_sptr inputWS =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(2, 3, 0.5);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(2, 3, 0.5);
     AnalysisDataService::Instance().add(wsName, inputWS);
 
     Mantid::Algorithms::PolynomialCorrection poly3;
@@ -126,7 +126,7 @@ public:
   }
 
   void testEvents() {
-    EventWorkspace_sptr evin = WorkspaceCreationHelper::CreateEventWorkspace(
+    EventWorkspace_sptr evin = WorkspaceCreationHelper::createEventWorkspace(
                             1, 5, 10, 0, 1, 3),
                         evout;
     AnalysisDataService::Instance().add("test_ev_polyc", evin);
diff --git a/Framework/Algorithms/test/PowerLawCorrectionTest.h b/Framework/Algorithms/test/PowerLawCorrectionTest.h
index 4f4927b4a9017f3fa0714859827ffd572a5f0425..e3565a8ff2b1f4ca6ecf6ef4ed722504b85b08b4 100644
--- a/Framework/Algorithms/test/PowerLawCorrectionTest.h
+++ b/Framework/Algorithms/test/PowerLawCorrectionTest.h
@@ -49,7 +49,7 @@ public:
 
   void testMultiply() {
     MatrixWorkspace_sptr inputWS =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(2, 3, 0.5);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(2, 3, 0.5);
     AnalysisDataService::Instance().add("PowerLawCorrectionInputWS", inputWS);
 
     Mantid::Algorithms::PowerLawCorrection expon3;
@@ -86,7 +86,7 @@ public:
   }
 
   void testEvents() {
-    EventWorkspace_sptr evin = WorkspaceCreationHelper::CreateEventWorkspace(
+    EventWorkspace_sptr evin = WorkspaceCreationHelper::createEventWorkspace(
                             1, 5, 10, 0, 1, 3),
                         evout;
     AnalysisDataService::Instance().add("test_ev_powlc", evin);
diff --git a/Framework/Algorithms/test/PowerTest.h b/Framework/Algorithms/test/PowerTest.h
index e8107f27f74fad6c0df3cd18168353b5728b09aa..e187dac0b6434f1a6fdcd084668a0180e59a3089 100644
--- a/Framework/Algorithms/test/PowerTest.h
+++ b/Framework/Algorithms/test/PowerTest.h
@@ -54,7 +54,7 @@ public:
 
   void testSetProperties() {
     WorkspaceSingleValue_sptr baseWs =
-        WorkspaceCreationHelper::CreateWorkspaceSingleValue(2);
+        WorkspaceCreationHelper::createWorkspaceSingleValue(2);
     AnalysisDataService::Instance().add("InputWS", baseWs);
 
     Power power;
@@ -98,7 +98,7 @@ public:
 
   void testPowerCalculation() {
     WorkspaceSingleValue_sptr baseWs =
-        WorkspaceCreationHelper::CreateWorkspaceSingleValue(2);
+        WorkspaceCreationHelper::createWorkspaceSingleValue(2);
     AnalysisDataService::Instance().add("InputWS", baseWs);
 
     Power power;
@@ -126,7 +126,7 @@ public:
 
   void testPowerCalculationWithNegativeExponent() {
     WorkspaceSingleValue_sptr baseWs =
-        WorkspaceCreationHelper::CreateWorkspaceSingleValue(2);
+        WorkspaceCreationHelper::createWorkspaceSingleValue(2);
     AnalysisDataService::Instance().add("InputWS", baseWs);
 
     Power power;
@@ -162,7 +162,7 @@ public:
     // if x = p ^ y, then err_x = y * x * err_p / p
 
     WorkspaceSingleValue_sptr baseWs =
-        WorkspaceCreationHelper::CreateWorkspaceSingleValue(4);
+        WorkspaceCreationHelper::createWorkspaceSingleValue(4);
     AnalysisDataService::Instance().add("InputWS", baseWs);
 
     Power power;
@@ -188,7 +188,7 @@ public:
 
   void testEvents() {
     // evin has 0 events per bin in pixel0, 1 in pixel 1, 2 in pixel2, ...
-    EventWorkspace_sptr evin = WorkspaceCreationHelper::CreateEventWorkspace(
+    EventWorkspace_sptr evin = WorkspaceCreationHelper::createEventWorkspace(
                             5, 3, 1000, 0, 1, 4),
                         evout;
     AnalysisDataService::Instance().add("test_ev_pow", evin);
diff --git a/Framework/Algorithms/test/Q1D2Test.h b/Framework/Algorithms/test/Q1D2Test.h
index 95192a24e8970b792ad3a05201f1adc6bd782902..b7e7f20235dbb1b37f116d847ff84c1adff8c37b 100644
--- a/Framework/Algorithms/test/Q1D2Test.h
+++ b/Framework/Algorithms/test/Q1D2Test.h
@@ -590,7 +590,7 @@ void createInputWorkspaces(int start, int end,
       Mantid::API::AnalysisDataService::Instance().retrieve(wsName));
   wave = boost::dynamic_pointer_cast<Mantid::API::MatrixWorkspace>(
       Mantid::API::AnalysisDataService::Instance().retrieve(wavNorm));
-  pixels = WorkspaceCreationHelper::Create2DWorkspaceBinned(29, 1);
+  pixels = WorkspaceCreationHelper::create2DWorkspaceBinned(29, 1);
   for (int i = 0; i < 29; ++i) {
     pixels->mutableY(i)[0] = flat_cell061Ys[i];
     pixels->mutableE(i)[0] = flat_cell061Es[i];
diff --git a/Framework/Algorithms/test/Q1DWeightedTest.h b/Framework/Algorithms/test/Q1DWeightedTest.h
index e7f5fe2de36134ed0e540b2e43a733db6f2e4f97..64f974552c36326d84f16204ceb639496d410d6d 100644
--- a/Framework/Algorithms/test/Q1DWeightedTest.h
+++ b/Framework/Algorithms/test/Q1DWeightedTest.h
@@ -5,6 +5,7 @@
 #include "MantidAlgorithms/Q1DWeighted.h"
 #include "MantidDataHandling/LoadSpice2D.h"
 #include "MantidDataHandling/MoveInstrumentComponent.h"
+#include "MantidAPI/WorkspaceGroup.h"
 
 using namespace Mantid::API;
 using namespace Mantid::Kernel;
diff --git a/Framework/Algorithms/test/QxyTest.h b/Framework/Algorithms/test/QxyTest.h
index 5bade76b90cb94bd51b1ebf5829a5a53ad475c50..47d46058f4b8507c77774e31b10c2e65e1e8c9e1 100644
--- a/Framework/Algorithms/test/QxyTest.h
+++ b/Framework/Algorithms/test/QxyTest.h
@@ -4,6 +4,7 @@
 #include <cxxtest/TestSuite.h>
 #include "MantidAlgorithms/Qxy.h"
 #include "MantidAlgorithms/ConvertUnits.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Axis.h"
 #include "MantidDataHandling/LoadRaw3.h"
 
diff --git a/Framework/Algorithms/test/RRFMuonTest.h b/Framework/Algorithms/test/RRFMuonTest.h
index 0010979b6022b5cddfa8ed43d91a000c3fa29533..bd8deab5baf0b9cce469eb78bf6646e1ce91cd76 100644
--- a/Framework/Algorithms/test/RRFMuonTest.h
+++ b/Framework/Algorithms/test/RRFMuonTest.h
@@ -3,6 +3,7 @@
 
 #include <cxxtest/TestSuite.h>
 #include "MantidAlgorithms/RRFMuon.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Axis.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/WorkspaceFactory.h"
diff --git a/Framework/Algorithms/test/RadiusSumTest.h b/Framework/Algorithms/test/RadiusSumTest.h
index a1b16948c93fba515470b2b465be7d234a9a935f..658732b7b3345dfb5e32d23f0bfc0515a27ec0e7 100644
--- a/Framework/Algorithms/test/RadiusSumTest.h
+++ b/Framework/Algorithms/test/RadiusSumTest.h
@@ -3,6 +3,7 @@
 
 #include "MantidAPI/NumericAxis.h"
 #include "MantidAlgorithms/RadiusSum.h"
+#include "MantidKernel/Unit.h"
 #include "MantidTestHelpers/WorkspaceCreationHelper.h"
 #include "RingProfileTest.h"
 #include <boost/shared_ptr.hpp>
diff --git a/Framework/Algorithms/test/Rebin2DTest.h b/Framework/Algorithms/test/Rebin2DTest.h
index d24a362220616e876ad1bcdfc86d71a74f2bdd24..c96f34fe799c60172321270e639933cbc0daffaa 100644
--- a/Framework/Algorithms/test/Rebin2DTest.h
+++ b/Framework/Algorithms/test/Rebin2DTest.h
@@ -39,7 +39,7 @@ MatrixWorkspace_sptr makeInputWS(const bool distribution,
     }
   }
 
-  MatrixWorkspace_sptr ws = WorkspaceCreationHelper::Create2DWorkspaceBinned(
+  MatrixWorkspace_sptr ws = WorkspaceCreationHelper::create2DWorkspaceBinned(
       int(nhist), int(nbins), x0, deltax);
 
   // We need something other than a spectrum axis, call this one theta
diff --git a/Framework/Algorithms/test/RebinByTimeAtSampleTest.h b/Framework/Algorithms/test/RebinByTimeAtSampleTest.h
index 2bdce2739cc0643bc0fd9e32bba1de81d926c09d..9579fd88b3ceee5d32791a41ca8ac73f8058ebe1 100644
--- a/Framework/Algorithms/test/RebinByTimeAtSampleTest.h
+++ b/Framework/Algorithms/test/RebinByTimeAtSampleTest.h
@@ -248,13 +248,13 @@ public:
     TSM_ASSERT_EQUALS("Should not loose spectrum", 3,
                       result->getNumberHistograms());
 
-    auto y1 = result->readY(0);
+    auto &y1 = result->y(0);
     auto y1Sum = std::accumulate(y1.begin(), y1.end(), 0.0);
 
-    auto y2 = result->readY(1);
+    auto &y2 = result->y(1);
     auto y2Sum = std::accumulate(y2.begin(), y2.end(), 0.0);
 
-    auto y3 = result->readY(2);
+    auto &y3 = result->y(2);
     auto y3Sum = std::accumulate(y3.begin(), y3.end(), 0.0);
 
     TSM_ASSERT_EQUALS("Spectrum 1 not rebinned to sample time correctly", 1.0,
diff --git a/Framework/Algorithms/test/RebinByTimeBaseTest.h b/Framework/Algorithms/test/RebinByTimeBaseTest.h
index f77193fd85c8e9c213e56d62048535bf61aef4a5..1b67a58ec840c9a3f421d5d2d4d58118eaaecf6b 100644
--- a/Framework/Algorithms/test/RebinByTimeBaseTest.h
+++ b/Framework/Algorithms/test/RebinByTimeBaseTest.h
@@ -14,6 +14,7 @@
 #include "MantidDataObjects/Events.h"
 #include "MantidDataObjects/Workspace2D.h"
 #include "MantidKernel/DateAndTime.h"
+#include "MantidKernel/Unit.h"
 #include "MantidKernel/WarningSuppressions.h"
 #include "MantidTestHelpers/WorkspaceCreationHelper.h"
 #include <boost/make_shared.hpp>
@@ -96,6 +97,8 @@ public:
   MOCK_CONST_METHOD1(getSpectrum,
                      const Mantid::API::IEventList &(const std::size_t));
   MOCK_METHOD3(init, void(const size_t &, const size_t &, const size_t &));
+  MOCK_METHOD2(init,
+               void(const size_t &, const Mantid::HistogramData::Histogram &));
   MOCK_CONST_METHOD0(getSpecialCoordinateSystem,
                      Mantid::Kernel::SpecialCoordinateSystem());
 
@@ -104,6 +107,10 @@ private:
     throw std::runtime_error(
         "Cloning of MockIEventWorkspace is not implemented.");
   }
+  MockIEventWorkspace *doCloneEmpty() const override {
+    throw std::runtime_error(
+        "Cloning of MockIEventWorkspace is not implemented.");
+  }
 };
 }
 
@@ -162,7 +169,7 @@ private:
     for (int i = 0; i < nSpectra; ++i) {
       // Check that the x-axis has been set-up properly. It should mirror the
       // original rebin parameters.
-      const Mantid::MantidVec &X = outWS->readX(i);
+      auto &X = outWS->x(i);
       TS_ASSERT_EQUALS(nBinsToBinTo + 1, X.size());
       for (uint64_t j = 0; j < X.size(); ++j) {
         TS_ASSERT_EQUALS(static_cast<int>(step * j), static_cast<int>(X[j]));
@@ -170,7 +177,7 @@ private:
 
       // Check that the y-axis has been set-up properly.
 
-      const Mantid::MantidVec &Y = outWS->readY(i);
+      auto &Y = outWS->y(i);
       TS_ASSERT_EQUALS(nBinsToBinTo, Y.size());
       for (uint64_t j = 0; j < Y.size(); ++j) {
         TS_ASSERT_EQUALS(nUniformDistributedEvents / nBinsToBinTo, Y[j]);
@@ -405,7 +412,7 @@ public:
 
     MatrixWorkspace_sptr outWS =
         AnalysisDataService::Instance().retrieveWS<Workspace2D>("outWS");
-    const Mantid::MantidVec &X = outWS->readX(0);
+    auto &X = outWS->x(0);
 
     // Check that xmin and xmax have been caclulated correctly.
     TS_ASSERT_EQUALS(nBinsToBinTo, X.size());
@@ -459,14 +466,14 @@ public:
 
     MatrixWorkspace_sptr outWS =
         AnalysisDataService::Instance().retrieveWS<Workspace2D>("outWS");
-    const Mantid::MantidVec &X = outWS->readX(0);
+    auto &X = outWS->x(0);
 
     // Check that xmin and xmax have been caclulated correctly.
     TS_ASSERT_EQUALS(nBinsToBinTo + 1, X.size());
     TS_ASSERT_EQUALS(pulseTimeMin, X.front());
     TS_ASSERT_EQUALS(pulseTimeMax, X.back());
 
-    const Mantid::MantidVec &Y = outWS->readY(0);
+    auto &Y = outWS->y(0);
     TS_ASSERT_EQUALS(nBinsToBinTo, Y.size());
 
     TS_ASSERT_EQUALS(nUniformDistributedEvents / nBinsToBinTo, Y[0]);
diff --git a/Framework/Algorithms/test/RebinTest.h b/Framework/Algorithms/test/RebinTest.h
index 2cc44e8b174a6e713750ef537240ed44cb437c1b..5010df2b9d40d8e6c1660a601f22be5e06197347 100644
--- a/Framework/Algorithms/test/RebinTest.h
+++ b/Framework/Algorithms/test/RebinTest.h
@@ -3,17 +3,17 @@
 
 #include <cxxtest/TestSuite.h>
 
-#include "MantidHistogramData/LinearGenerator.h"
-#include "MantidDataObjects/Workspace2D.h"
-#include "MantidDataObjects/EventWorkspace.h"
 #include "MantidAPI/AnalysisDataService.h"
-#include "MantidAlgorithms/Rebin.h"
-#include "MantidAlgorithms/MaskBins.h"
-#include "MantidAPI/WorkspaceProperty.h"
-#include "MantidTestHelpers/WorkspaceCreationHelper.h"
 #include "MantidAPI/RefAxis.h"
-#include "MantidAPI/SpectraAxis.h"
 #include "MantidAPI/ScopedWorkspace.h"
+#include "MantidAPI/SpectraAxis.h"
+#include "MantidAPI/WorkspaceProperty.h"
+#include "MantidAlgorithms/MaskBins.h"
+#include "MantidAlgorithms/Rebin.h"
+#include "MantidDataObjects/EventWorkspace.h"
+#include "MantidDataObjects/Workspace2D.h"
+#include "MantidHistogramData/LinearGenerator.h"
+#include "MantidTestHelpers/WorkspaceCreationHelper.h"
 
 using namespace Mantid;
 using namespace Mantid::Kernel;
@@ -58,9 +58,9 @@ public:
     TS_ASSERT(rebin.isExecuted());
     MatrixWorkspace_sptr rebindata =
         AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("test_out");
-    const Mantid::MantidVec outX = rebindata->readX(0);
-    const Mantid::MantidVec outY = rebindata->readY(0);
-    const Mantid::MantidVec outE = rebindata->readE(0);
+    auto &outX = rebindata->x(0);
+    auto &outY = rebindata->y(0);
+    auto &outE = rebindata->e(0);
 
     TS_ASSERT_DELTA(outX[7], 15.5, 0.000001);
     TS_ASSERT_DELTA(outY[7], 3.0, 0.000001);
@@ -93,9 +93,9 @@ public:
     MatrixWorkspace_sptr rebindata =
         AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("test_out");
 
-    const Mantid::MantidVec outX = rebindata->readX(0);
-    const Mantid::MantidVec outY = rebindata->readY(0);
-    const Mantid::MantidVec outE = rebindata->readE(0);
+    auto &outX = rebindata->x(0);
+    auto &outY = rebindata->y(0);
+    auto &outE = rebindata->e(0);
 
     TS_ASSERT_DELTA(outX[7], 15.5, 0.000001);
     TS_ASSERT_DELTA(outY[7], 8.0, 0.000001);
@@ -130,9 +130,7 @@ public:
     TS_ASSERT(rebin.isExecuted());
     MatrixWorkspace_sptr rebindata =
         AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("test_out");
-    const Mantid::MantidVec outX = rebindata->readX(0);
-    const Mantid::MantidVec outY = rebindata->readY(0);
-    const Mantid::MantidVec outE = rebindata->readE(0);
+    auto &outX = rebindata->x(0);
 
     TS_ASSERT_EQUALS(outX.size(), 11);
     TS_ASSERT_DELTA(outX[0], 1.0, 1e-5);
@@ -161,9 +159,9 @@ public:
     MatrixWorkspace_sptr rebindata =
         AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("test_out");
 
-    const Mantid::MantidVec outX = rebindata->readX(5);
-    const Mantid::MantidVec outY = rebindata->readY(5);
-    const Mantid::MantidVec outE = rebindata->readE(5);
+    auto &outX = rebindata->x(5);
+    auto &outY = rebindata->y(5);
+    auto &outE = rebindata->e(5);
     TS_ASSERT_DELTA(outX[7], 15.5, 0.000001);
     TS_ASSERT_DELTA(outY[7], 3.0, 0.000001);
     TS_ASSERT_DELTA(outE[7], sqrt(4.5) / 2.0, 0.000001);
@@ -191,7 +189,7 @@ public:
                               bool PreserveEvents, bool expectOutputEvent) {
     // Two events per bin
     EventWorkspace_sptr test_in =
-        WorkspaceCreationHelper::CreateEventWorkspace2(50, 100);
+        WorkspaceCreationHelper::createEventWorkspace2(50, 100);
     test_in->switchEventType(eventType);
 
     std::string inName("test_inEvent");
@@ -230,9 +228,9 @@ public:
         TS_ASSERT(eventOutWS == test_in);
     }
 
-    const MantidVec &X = outWS->readX(0);
-    const MantidVec &Y = outWS->readY(0);
-    const MantidVec &E = outWS->readE(0);
+    auto &X = outWS->x(0);
+    auto &Y = outWS->y(0);
+    auto &E = outWS->e(0);
 
     TS_ASSERT_EQUALS(X.size(), 26);
     TS_ASSERT_DELTA(X[0], 0.0, 1e-5);
@@ -334,9 +332,9 @@ public:
     TS_ASSERT(!outWS->isHistogramData());
     TS_ASSERT_EQUALS(outWS->getNumberHistograms(), 1);
 
-    TS_ASSERT_EQUALS(outWS->readX(0)[0], 7.3750);
-    TS_ASSERT_EQUALS(outWS->readX(0)[10], 14.8750);
-    TS_ASSERT_EQUALS(outWS->readX(0)[20], 22.3750);
+    TS_ASSERT_EQUALS(outWS->x(0)[0], 7.3750);
+    TS_ASSERT_EQUALS(outWS->x(0)[10], 14.8750);
+    TS_ASSERT_EQUALS(outWS->x(0)[20], 22.3750);
 
     AnalysisDataService::Instance().remove("test_RebinPointDataInput");
     AnalysisDataService::Instance().remove("test_RebinPointDataOutput");
@@ -358,14 +356,14 @@ public:
     MatrixWorkspace_sptr rebindata =
         AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(
             "test_Rebin_masked_ws");
-    const MantidVec &outX = rebindata->readX(0);
-    const MantidVec &outY = rebindata->readY(0);
+    auto &outX = rebindata->x(0);
+    auto &outY = rebindata->y(0);
 
     MatrixWorkspace_sptr input =
         AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(
             "test_Rebin_mask_dist");
-    const MantidVec &inX = input->readX(0);
-    const MantidVec &inY = input->readY(0);
+    auto &inX = input->x(0);
+    auto &inY = input->y(0);
 
     const MatrixWorkspace::MaskList &mask = rebindata->maskedBins(0);
 
@@ -412,8 +410,8 @@ public:
     MatrixWorkspace_sptr input =
         AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(
             "test_Rebin_unmasked");
-    const Mantid::MantidVec inX = input->readX(0);
-    const Mantid::MantidVec inY = input->readY(0);
+    auto &inX = input->x(0);
+    auto &inY = input->y(0);
 
     maskFirstBins("test_Rebin_mask_raw", "test_Rebin_masked_ws", 10.0);
 
@@ -424,8 +422,8 @@ public:
     MatrixWorkspace_sptr masked =
         AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(
             "test_Rebin_masked_ws");
-    const Mantid::MantidVec outX = masked->readX(0);
-    const Mantid::MantidVec outY = masked->readY(0);
+    auto &outX = masked->x(0);
+    auto &outY = masked->y(0);
 
     const MatrixWorkspace::MaskList &mask = masked->maskedBins(0);
 
@@ -538,11 +536,11 @@ private:
       return; // Nothing else to check
     }
 
-    auto xValues = ws->readX(0);
-    TS_ASSERT_DELTA(xValues, xExpected, 0.001);
+    auto &xValues = ws->x(0);
+    TS_ASSERT_DELTA(xValues.rawData(), xExpected, 0.001);
 
-    auto yValues = ws->readY(0);
-    TS_ASSERT_DELTA(yValues, yExpected, 0.001);
+    auto &yValues = ws->y(0);
+    TS_ASSERT_DELTA(yValues.rawData(), yExpected, 0.001);
   }
 };
 
@@ -556,7 +554,7 @@ public:
   static void destroySuite(RebinTestPerformance *suite) { delete suite; }
 
   RebinTestPerformance() {
-    ws = WorkspaceCreationHelper::Create2DWorkspaceBinned(5000, 20000);
+    ws = WorkspaceCreationHelper::create2DWorkspaceBinned(5000, 20000);
   }
 
   void test_rebin() {
diff --git a/Framework/Algorithms/test/RebinToWorkspaceTest.h b/Framework/Algorithms/test/RebinToWorkspaceTest.h
index e759354bfbcd8f3dafbc39d2bc20525e876eeef2..71a4bf756a55ffe63c47477a80705ab335849f4b 100644
--- a/Framework/Algorithms/test/RebinToWorkspaceTest.h
+++ b/Framework/Algorithms/test/RebinToWorkspaceTest.h
@@ -4,9 +4,9 @@
 //-------------------
 // Includes
 //--------------------
-#include <cxxtest/TestSuite.h>
 #include "MantidAlgorithms/RebinToWorkspace.h"
 #include "MantidTestHelpers/WorkspaceCreationHelper.h"
+#include <cxxtest/TestSuite.h>
 
 #include <numeric>
 
@@ -28,7 +28,7 @@ public:
     // Creates a workspace with 10 points
     const int numYPoints(10);
     const int numSpectra(2);
-    Workspace2D_sptr testWS = WorkspaceCreationHelper::Create2DWorkspace123(
+    Workspace2D_sptr testWS = WorkspaceCreationHelper::create2DWorkspace123(
         numSpectra, numYPoints, false);
     // Reset the X data to something reasonable
     Points x(numYPoints);
@@ -54,9 +54,9 @@ public:
     // Need to input workspaces to test this
     using namespace Mantid::DataObjects;
     Workspace2D_sptr rebinThis =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(10, 50, 5.0, 1.0);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(10, 50, 5.0, 1.0);
     Workspace2D_sptr matchToThis =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(15, 30, 3.0, 2.5);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(15, 30, 3.0, 2.5);
     // Register them with the DataService
     using namespace Mantid::API;
     TS_ASSERT_THROWS_NOTHING(
@@ -96,11 +96,11 @@ public:
         boost::dynamic_pointer_cast<Workspace2D>(workspace);
 
     // Test x-vectors from this and "matchToThis" are the same
-    TS_ASSERT_EQUALS(output2D->dataX(0).size(), matchToThis->dataX(0).size());
-    TS_ASSERT_DIFFERS(output2D->dataX(0).size(), rebinThis->dataX(0).size());
+    TS_ASSERT_EQUALS(output2D->x(0).size(), matchToThis->x(0).size());
+    TS_ASSERT_DIFFERS(output2D->x(0).size(), rebinThis->x(0).size());
 
     // Test a random x bin for matching value
-    TS_ASSERT_EQUALS(output2D->dataX(0)[22], matchToThis->dataX(0)[22]);
+    TS_ASSERT_EQUALS(output2D->x(0)[22], matchToThis->x(0)[22]);
   }
 
 private:
diff --git a/Framework/Algorithms/test/RebunchTest.h b/Framework/Algorithms/test/RebunchTest.h
index 9955c1d5798c9ea01918881b894125ea4b3095ba..a250437f5ebeba2cf28aba06d5b9315b0958162e 100644
--- a/Framework/Algorithms/test/RebunchTest.h
+++ b/Framework/Algorithms/test/RebunchTest.h
@@ -3,11 +3,11 @@
 
 #include <cxxtest/TestSuite.h>
 
-#include "MantidHistogramData/LinearGenerator.h"
-#include "MantidDataObjects/Workspace2D.h"
 #include "MantidAPI/AnalysisDataService.h"
-#include "MantidAlgorithms/Rebunch.h"
 #include "MantidAPI/WorkspaceProperty.h"
+#include "MantidAlgorithms/Rebunch.h"
+#include "MantidDataObjects/Workspace2D.h"
+#include "MantidHistogramData/LinearGenerator.h"
 
 #include <numeric>
 
@@ -35,9 +35,9 @@ public:
     rebunch.execute();
     MatrixWorkspace_sptr rebunchdata =
         AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("test_out");
-    const Mantid::MantidVec outX = rebunchdata->dataX(0);
-    const Mantid::MantidVec outY = rebunchdata->dataY(0);
-    const Mantid::MantidVec outE = rebunchdata->dataE(0);
+    auto &outX = rebunchdata->x(0);
+    auto &outY = rebunchdata->y(0);
+    auto &outE = rebunchdata->e(0);
 
     TS_ASSERT_DELTA(outX[0], 1.5, 0.000001);
     TS_ASSERT_DELTA(outY[0], 3.0, 0.000001);
@@ -66,9 +66,9 @@ public:
     MatrixWorkspace_sptr rebunchdata =
         AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("test_out");
 
-    const Mantid::MantidVec outX = rebunchdata->dataX(0);
-    const Mantid::MantidVec outY = rebunchdata->dataY(0);
-    const Mantid::MantidVec outE = rebunchdata->dataE(0);
+    auto &outX = rebunchdata->x(0);
+    auto &outY = rebunchdata->y(0);
+    auto &outE = rebunchdata->e(0);
 
     TS_ASSERT_DELTA(outX[0], 0.5, 0.000001);
     TS_ASSERT_DELTA(outY[0], 28, 0.000001);
@@ -100,9 +100,9 @@ public:
     MatrixWorkspace_sptr rebunchdata =
         AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("test_out");
 
-    const Mantid::MantidVec outX = rebunchdata->dataX(5);
-    const Mantid::MantidVec outY = rebunchdata->dataY(5);
-    const Mantid::MantidVec outE = rebunchdata->dataE(5);
+    auto &outX = rebunchdata->x(5);
+    auto &outY = rebunchdata->y(5);
+    auto &outE = rebunchdata->e(5);
 
     TS_ASSERT_DELTA(outX[0], 0.5, 0.000001);
     TS_ASSERT_DELTA(outY[0], 3, 0.000001);
@@ -132,9 +132,9 @@ public:
     rebunch.execute();
     MatrixWorkspace_sptr rebunchdata =
         AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("test_out");
-    const Mantid::MantidVec outX = rebunchdata->dataX(5);
-    const Mantid::MantidVec outY = rebunchdata->dataY(5);
-    const Mantid::MantidVec outE = rebunchdata->dataE(5);
+    auto &outX = rebunchdata->x(5);
+    auto &outY = rebunchdata->y(5);
+    auto &outE = rebunchdata->e(5);
 
     TS_ASSERT_DELTA(outX[0], 2.75, 0.000001);
     TS_ASSERT_DELTA(outY[0], 5.5, 0.000001);
@@ -154,17 +154,10 @@ private:
   Workspace2D_sptr Create1DWorkspaceHist(int size) {
     Workspace2D_sptr retVal(new Workspace2D);
     retVal->initialize(1, size, size - 1);
-    double j = 1.0;
-    for (int i = 0; i < size; i++) {
-      retVal->dataX(0)[i] = j * 0.5;
-      j += 1.5;
-    }
-    j = 1.0;
-    for (int i = 0; i < size - 1; i++) {
-      retVal->dataY(0)[i] = j;
-      retVal->dataE(0)[i] = sqrt(j);
-      j += 1;
-    }
+    BinEdges x(static_cast<size_t>(size), LinearGenerator(0.5, 0.75));
+    Counts y(size - 1, LinearGenerator(1.0, 1.0));
+
+    retVal->setHistogram(0, x, y);
 
     return retVal;
   }
@@ -172,67 +165,75 @@ private:
   Workspace2D_sptr Create1DWorkspacePnt(int size) {
     Workspace2D_sptr retVal(new Workspace2D);
     retVal->initialize(1, size, size);
-    double j = 1.0;
-    for (int i = 0; i < size; i++) {
-      retVal->dataX(0)[i] = j * 0.5;
-      retVal->dataY(0)[i] = j;
-      retVal->dataE(0)[i] = sqrt(j);
-      j += 1.0;
-    }
+    Points x(size, LinearGenerator(0.5, 0.5));
+    Counts y(size, LinearGenerator(1.0, 1.0));
+
+    retVal->setHistogram(0, x, y);
 
     return retVal;
   }
 
   Workspace2D_sptr Create2DWorkspaceHist(int xlen, int ylen) {
-    BinEdges x1(xlen, LinearGenerator(0.0, 1.0));
+    BinEdges x1(xlen, LinearGenerator(0.5, 0.75));
 
     Workspace2D_sptr retVal(new Workspace2D);
     retVal->initialize(ylen, xlen, xlen - 1);
-    double j = 1.0;
-
-    for (auto &x : x1) {
-      x = j * 0.5;
-      j += 1.5;
-    }
 
-    Counts y1(xlen - 1);
-    CountVariances e1(xlen - 1);
-    std::iota(y1.begin(), y1.end(), 1.0);
-    std::iota(e1.begin(), e1.end(), 1.0);
+    Counts y1(xlen - 1, LinearGenerator(1.0, 1.0));
 
     for (int i = 0; i < ylen; i++) {
-      retVal->setBinEdges(i, x1);
-      retVal->setCounts(i, y1);
-      retVal->setCountVariances(i, e1);
+      retVal->setHistogram(i, x1, y1);
     }
 
     return retVal;
   }
 
   Workspace2D_sptr Create2DWorkspacePnt(int xlen, int ylen) {
-    Points x1(xlen, LinearGenerator(0.0, 1.0));
+    Points x1(xlen, LinearGenerator(0.5, 0.75));
 
     Workspace2D_sptr retVal(new Workspace2D);
     retVal->initialize(ylen, xlen, xlen);
-    double j = 1.0;
 
-    for (auto &x : x1) {
-      x = j * 0.5;
-      j += 1.5;
-    }
-
-    Counts y1(xlen);
-    std::iota(y1.begin(), y1.end(), 0.0);
-    y1 = 1.5 * y1 + 1.0;
-    CountVariances e1(y1.begin(), y1.end());
+    Counts y1(xlen, LinearGenerator(1.0, 1.5));
 
     for (int i = 0; i < ylen; i++) {
-      retVal->setPoints(i, x1);
-      retVal->setCounts(i, y1);
-      retVal->setCountVariances(i, e1);
+      retVal->setHistogram(i, x1, y1);
     }
 
     return retVal;
   }
 };
+
+class RebunchTestPerformance : public CxxTest::TestSuite {
+public:
+  static RebunchTestPerformance *createSuite() {
+    return new RebunchTestPerformance();
+  }
+
+  static void destroySuite(RebunchTestPerformance *suite) { delete suite; }
+
+  void setUp() override {
+    input = boost::make_shared<Workspace2D>();
+    input->initialize(100000, 3000, 2999);
+    input->setDistribution(true);
+    AnalysisDataService::Instance().add("input", input);
+  }
+
+  void tearDown() override {
+    AnalysisDataService::Instance().remove("input");
+    AnalysisDataService::Instance().remove("test_out");
+  }
+
+  void testExec() {
+    Rebunch rebunch;
+    rebunch.initialize();
+    rebunch.setPropertyValue("InputWorkspace", "input");
+    rebunch.setPropertyValue("OutputWorkspace", "test_out");
+    rebunch.setPropertyValue("NBunch", "5");
+    rebunch.execute();
+  }
+
+private:
+  Workspace2D_sptr input;
+};
 #endif /* REBUNCHTEST */
diff --git a/Framework/Algorithms/test/RectangularBeamProfileTest.h b/Framework/Algorithms/test/RectangularBeamProfileTest.h
index 28074255f6c617993a6cac1727b5d4a9a6529fcc..973a622ca00d9708c449a1db986fc6b036147363 100644
--- a/Framework/Algorithms/test/RectangularBeamProfileTest.h
+++ b/Framework/Algorithms/test/RectangularBeamProfileTest.h
@@ -4,8 +4,11 @@
 #include <cxxtest/TestSuite.h>
 
 #include "MantidAlgorithms/SampleCorrections/RectangularBeamProfile.h"
-#include "MonteCarloTesting.h"
+#include "MantidAPI/Sample.h"
 #include "MantidGeometry/Instrument/ReferenceFrame.h"
+#include "MantidTestHelpers/ComponentCreationHelper.h"
+
+#include "MonteCarloTesting.h"
 
 using Mantid::Algorithms::RectangularBeamProfile;
 
@@ -79,12 +82,27 @@ public:
     TS_ASSERT_EQUALS(V3D(1.0, 0, 0), ray.unitDir);
   }
 
+  void test_DefineActiveRegion() {
+    using Mantid::API::Sample;
+    using Mantid::Kernel::V3D;
+    const double width(0.1), height(0.2);
+    const V3D center;
+    RectangularBeamProfile profile(createTestFrame(), center, width, height);
+    Sample testSample;
+    testSample.setShape(*ComponentCreationHelper::createSphere(0.5));
+
+    auto region = profile.defineActiveRegion(testSample);
+    TS_ASSERT(region.isNonNull());
+    TS_ASSERT_EQUALS(V3D(-0.5, -0.05, -0.1), region.minPoint());
+    TS_ASSERT_EQUALS(V3D(0.5, 0.05, 0.1), region.maxPoint());
+  }
+
 private:
   Mantid::Geometry::ReferenceFrame createTestFrame() {
     using Mantid::Geometry::ReferenceFrame;
     using Mantid::Geometry::PointingAlong;
     using Mantid::Geometry::Handedness;
-
+    // up = Z, beam = X
     return ReferenceFrame(PointingAlong::Z, PointingAlong::X, Handedness::Right,
                           "source");
   }
diff --git a/Framework/Algorithms/test/ReflectometryReductionOneAutoTest.h b/Framework/Algorithms/test/ReflectometryReductionOneAutoTest.h
index 1465fecad01cd4357ea537824619e1dc7f9a91c5..082e83c04bba5dc49f4914d43d10c7d9be2fe308 100644
--- a/Framework/Algorithms/test/ReflectometryReductionOneAutoTest.h
+++ b/Framework/Algorithms/test/ReflectometryReductionOneAutoTest.h
@@ -7,6 +7,9 @@
 #include "MantidAPI/AlgorithmManager.h"
 #include "MantidAPI/Axis.h"
 #include "MantidAPI/FrameworkManager.h"
+#include "MantidAPI/WorkspaceGroup.h"
+#include "MantidAPI/WorkspaceHistory.h"
+#include "MantidGeometry/Instrument.h"
 #include "MantidGeometry/Instrument/ReferenceFrame.h"
 #include "MantidTestHelpers/WorkspaceCreationHelper.h"
 
@@ -252,7 +255,7 @@ public:
     auto tempInst = m_TOF->getInstrument();
     m_TOF->setInstrument(m_dataWorkspace->getInstrument());
     alg->setProperty("InputWorkspace", m_TOF);
-    TS_ASSERT_THROWS(alg->execute(), std::invalid_argument);
+    TS_ASSERT_THROWS(alg->execute(), std::runtime_error);
     m_TOF->setInstrument(tempInst);
   }
   void
@@ -572,4 +575,4 @@ public:
   }
 };
 
-#endif /* MANTID_ALGORITHMS_REFLECTOMETRYREDUCTIONONEAUTOTEST_H_ */
\ No newline at end of file
+#endif /* MANTID_ALGORITHMS_REFLECTOMETRYREDUCTIONONEAUTOTEST_H_ */
diff --git a/Framework/Algorithms/test/ReflectometryReductionOneTest.h b/Framework/Algorithms/test/ReflectometryReductionOneTest.h
index 845c37071d55a69d848e119973053054b9ee57ca..2e246ecd85bbdd9d9ea489057b1f93669740b188 100644
--- a/Framework/Algorithms/test/ReflectometryReductionOneTest.h
+++ b/Framework/Algorithms/test/ReflectometryReductionOneTest.h
@@ -11,6 +11,7 @@
 #include "MantidTestHelpers/WorkspaceCreationHelper.h"
 #include "MantidGeometry/Instrument/ReferenceFrame.h"
 #include "MantidGeometry/Instrument.h"
+#include "MantidKernel/Unit.h"
 
 using namespace Mantid;
 using namespace Mantid::Kernel;
@@ -87,7 +88,7 @@ public:
     TS_ASSERT_EQUALS(map[specId1], 0);
 
     // Check the cropped x range
-    Mantid::MantidVec copyX = detectorWS->readX(0);
+    auto copyX = detectorWS->x(0);
     std::sort(copyX.begin(), copyX.end());
     TS_ASSERT(copyX.front() >= wavelengthMin);
     TS_ASSERT(copyX.back() <= wavelengthMax);
@@ -105,7 +106,8 @@ public:
   }
 
   IAlgorithm_sptr construct_standard_algorithm() {
-    auto alg = AlgorithmManager::Instance().create("ReflectometryReductionOne");
+    auto alg =
+        AlgorithmManager::Instance().create("ReflectometryReductionOne", 1);
     alg->setRethrows(true);
     alg->setChild(true);
     alg->initialize();
@@ -118,7 +120,7 @@ public:
     alg->setProperty("MonitorIntegrationWavelengthMin", 1.2);
     alg->setProperty("MonitorIntegrationWavelengthMax", 1.5);
     alg->setProperty("MomentumTransferStep", 0.1);
-    alg->setPropertyValue("ProcessingInstructions", "1");
+    alg->setPropertyValue("ProcessingInstructions", "0");
     alg->setPropertyValue("OutputWorkspace", "x");
     alg->setPropertyValue("OutputWorkspaceWavelength", "y");
     alg->setRethrows(true);
@@ -224,8 +226,8 @@ public:
     TS_ASSERT_THROWS_NOTHING(alg->execute());
     MatrixWorkspace_sptr scaledWS = alg->getProperty("OutputWorkspace");
     // compare y data instead of workspaces.
-    auto scaledYData = scaledWS->readY(0);
-    auto nonScaledYData = nonScaledWS->readY(0);
+    auto &scaledYData = scaledWS->y(0);
+    auto &nonScaledYData = nonScaledWS->y(0);
     TS_ASSERT_EQUALS(scaledYData.front(), 2 * nonScaledYData.front());
     TS_ASSERT_EQUALS(scaledYData[scaledYData.size() / 2],
                      2 * nonScaledYData[nonScaledYData.size() / 2]);
@@ -236,20 +238,20 @@ public:
   }
   void test_post_processing_rebin_step_with_params_not_provided() {
     auto alg = construct_standard_algorithm();
-    auto inWS = Create2DWorkspace154(1, 10, true);
+    auto inWS = create2DWorkspace154(1, 10, true);
     // this instrument does not have a "slit-gap" property
     // defined in the IPF, so CalculateResolution should throw.
     inWS->setInstrument(m_tinyReflWS->getInstrument());
     inWS->getAxis(0)->setUnit("Wavelength");
     // Setup bad bin edges, Rebin will throw (not CalculateResolution?)
-    inWS->dataX(0).assign(inWS->readX(0).size(), inWS->readX(0)[0]);
+    inWS->mutableX(0) = inWS->x(0)[0];
     alg->setProperty("InputWorkspace", inWS);
     alg->setProperty("OutputWorkspace", "rebinnedWS");
     TS_ASSERT_THROWS(alg->execute(), std::invalid_argument);
   }
   void test_post_processing_rebin_step_with_partial_params_provided() {
     auto alg = construct_standard_algorithm();
-    auto inWS = Create2DWorkspace154(1, 10, true);
+    auto inWS = create2DWorkspace154(1, 10, true);
     inWS->setInstrument(m_tinyReflWS->getInstrument());
     inWS->getAxis(0)->setUnit("Wavelength");
     alg->setProperty("InputWorkspace", inWS);
@@ -257,7 +259,7 @@ public:
     alg->setProperty("OutputWorkspace", "rebinnedWS");
     TS_ASSERT_THROWS_NOTHING(alg->execute());
     MatrixWorkspace_sptr rebinnedIvsQWS = alg->getProperty("OutputWorkspace");
-    auto xData = rebinnedIvsQWS->readX(0);
+    auto &xData = rebinnedIvsQWS->x(0);
     // based off the equation for logarithmic binning X(i+1)=X(i)(1+|dX|)
     double binWidthFromLogarithmicEquation = fabs((xData[1] / xData[0]) - 1);
     TSM_ASSERT_DELTA("DQQ should be the same as abs(x[1]/x[0] - 1)",
@@ -267,7 +269,7 @@ public:
   }
   void test_post_processing_rebin_step_with_logarithmic_rebinning() {
     auto alg = construct_standard_algorithm();
-    auto inWS = Create2DWorkspace154(1, 10, true);
+    auto inWS = create2DWorkspace154(1, 10, true);
     inWS->setInstrument(m_tinyReflWS->getInstrument());
     inWS->getAxis(0)->setUnit("Wavelength");
     alg->setProperty("InputWorkspace", inWS);
@@ -277,7 +279,7 @@ public:
     alg->setProperty("OutputWorkspace", "rebinnedWS");
     TS_ASSERT_THROWS_NOTHING(alg->execute());
     MatrixWorkspace_sptr rebinnedIvsQWS = alg->getProperty("OutputWorkspace");
-    auto xData = rebinnedIvsQWS->readX(0);
+    auto &xData = rebinnedIvsQWS->x(0);
     TSM_ASSERT_EQUALS("QMin should be the same as first Param entry (1.0)",
                       xData[0], 1.0);
     // based off the equation for logarithmic binning X(i+1)=X(i)(1+|dX|)
@@ -289,7 +291,7 @@ public:
   }
   void test_post_processing_rebin_step_with_linear_rebinning() {
     auto alg = construct_standard_algorithm();
-    auto inWS = Create2DWorkspace154(1, 10, true);
+    auto inWS = create2DWorkspace154(1, 10, true);
     inWS->setInstrument(m_tinyReflWS->getInstrument());
     inWS->getAxis(0)->setUnit("Wavelength");
     alg->setProperty("InputWorkspace", inWS);
@@ -299,7 +301,7 @@ public:
     alg->setProperty("OutputWorkspace", "rebinnedWS");
     TS_ASSERT_THROWS_NOTHING(alg->execute());
     MatrixWorkspace_sptr rebinnedIvsQWS = alg->getProperty("OutputWorkspace");
-    auto xData = rebinnedIvsQWS->readX(0);
+    auto &xData = rebinnedIvsQWS->x(0);
     TSM_ASSERT_DELTA("QMin should be the same as the first Param entry (1.577)",
                      xData[0], 1.577, 1e-06);
     TSM_ASSERT_DELTA("DQQ should the same as 0.2", xData[1] - xData[0], 0.2,
@@ -371,16 +373,16 @@ public:
     // convert from degrees to radians for sin() function
     double outThetaInRadians = outTheta * M_PI / 180;
 
-    double lamMin = inLam->readX(0).front();
-    double lamMax = inLam->readX(0).back();
+    double lamMin = inLam->x(0).front();
+    double lamMax = inLam->x(0).back();
 
     // Derive our QMin and QMax from the equation
     double qMinFromEQ = (4 * M_PI * sin(outThetaInRadians)) / lamMax;
     double qMaxFromEQ = (4 * M_PI * sin(outThetaInRadians)) / lamMin;
 
     // Get our QMin and QMax from the workspace
-    auto qMinFromWS = inQ->readX(0).front();
-    auto qMaxFromWS = inQ->readX(0).back();
+    auto qMinFromWS = inQ->x(0).front();
+    auto qMaxFromWS = inQ->x(0).back();
 
     // Compare the two values (they should be identical)
     TS_ASSERT_DELTA(qMinFromEQ, qMinFromWS, 0.00001);
diff --git a/Framework/Algorithms/test/RegroupTest.h b/Framework/Algorithms/test/RegroupTest.h
index fafaeb4a2c36b6fd45254a6d0aa83725647a7a51..7f806387cf2583ccfff81fcfc18270e54a712d5d 100644
--- a/Framework/Algorithms/test/RegroupTest.h
+++ b/Framework/Algorithms/test/RegroupTest.h
@@ -3,12 +3,12 @@
 
 #include <cxxtest/TestSuite.h>
 
-#include "MantidHistogramData/LinearGenerator.h"
-#include "MantidDataObjects/Workspace2D.h"
 #include "MantidAPI/AnalysisDataService.h"
-#include "MantidAlgorithms/Regroup.h"
-#include "MantidAPI/WorkspaceProperty.h"
 #include "MantidAPI/WorkspaceFactory.h"
+#include "MantidAPI/WorkspaceProperty.h"
+#include "MantidAlgorithms/Regroup.h"
+#include "MantidDataObjects/Workspace2D.h"
+#include "MantidHistogramData/LinearGenerator.h"
 
 using namespace Mantid::Kernel;
 using namespace Mantid::DataObjects;
@@ -46,7 +46,7 @@ public:
     TS_ASSERT(regroup.isExecuted())
 
     MatrixWorkspace_sptr rebindata = regroup.getProperty("OutputWorkspace");
-    const Mantid::MantidVec outX = rebindata->dataX(0);
+    auto &outX = rebindata->x(0);
 
     TS_ASSERT_DELTA(outX[7], 12.5, 0.000001);
     TS_ASSERT_DELTA(outX[12], 20.75, 0.000001);
@@ -58,27 +58,21 @@ public:
 private:
   Workspace2D_sptr Create1DWorkspace(int size) {
     auto retVal = createWorkspace<Workspace2D>(1, size, size - 1);
-    double j = 1.0;
-    for (int i = 0; i < size; i++) {
-      retVal->dataX(0)[i] = j * 0.5;
-      j += 1.5;
-    }
-    retVal->setCounts(0, size - 1, 3.0);
-    retVal->setCountVariances(0, size - 1, 3.0);
+    BinEdges x(size, LinearGenerator(0.5, 0.75));
+    Counts y(size - 1, 3.0);
+
+    retVal->setHistogram(0, x, y);
     return retVal;
   }
 
   Workspace2D_sptr Create2DWorkspace(int xlen, int ylen) {
     BinEdges x1(xlen, LinearGenerator(0.5, 0.75));
     Counts y1(xlen - 1, 3.0);
-    CountStandardDeviations e1(xlen - 1, sqrt(3.0));
 
     auto retVal = createWorkspace<Workspace2D>(ylen, xlen, xlen - 1);
 
     for (int i = 0; i < ylen; i++) {
-      retVal->setBinEdges(i, x1);
-      retVal->setCounts(i, y1);
-      retVal->setCountStandardDeviations(i, e1);
+      retVal->setHistogram(i, x1, y1);
     }
 
     return retVal;
diff --git a/Framework/Algorithms/test/RemoveBackgroundTest.h b/Framework/Algorithms/test/RemoveBackgroundTest.h
index 5c2ef5d40fc79688e766b58b3a3b10824d1513c1..c01c9209a077cc5256ef2ef3c76c8841d49e1f65 100644
--- a/Framework/Algorithms/test/RemoveBackgroundTest.h
+++ b/Framework/Algorithms/test/RemoveBackgroundTest.h
@@ -107,9 +107,9 @@ public:
     int emode = static_cast<int>(Kernel::DeltaEMode().fromString("Direct"));
     bgRemoval.initialize(BgWS, SourceWS, emode);
 
-    MantidVec &dataX = clone->dataX(0);
-    MantidVec &dataY = clone->dataY(0);
-    MantidVec &dataE = clone->dataE(0);
+    auto &dataX = clone->mutableX(0);
+    auto &dataY = clone->mutableY(0);
+    auto &dataE = clone->mutableE(0);
 
     bgRemoval.removeBackground(0, dataX, dataY, dataE);
 
@@ -117,8 +117,8 @@ public:
         API::AnalysisDataService::Instance().retrieveWS<API::MatrixWorkspace>(
             "sampleWSdE");
 
-    const MantidVec &sampleX = SampleWS->readX(0);
-    const MantidVec &sampleY = SampleWS->readY(0);
+    auto &sampleX = SampleWS->x(0);
+    auto &sampleY = SampleWS->y(0);
     // const MantidVec & sampleE = SampleWS->readE(0);
     for (size_t i = 0; i < sampleY.size(); i++) {
       TS_ASSERT_DELTA(dataX[i], sampleX[i], 1.e-7);
@@ -144,11 +144,11 @@ public:
             "sampleWSdE");
     auto result = clone;
 
-    const MantidVec &sampleX = SampleWS->readX(0);
-    const MantidVec &sampleY = SampleWS->readY(0);
+    auto &sampleX = SampleWS->x(0);
+    auto &sampleY = SampleWS->y(0);
 
-    const MantidVec &resultX = result->readX(0);
-    const MantidVec &resultY = result->readY(0);
+    auto &resultX = result->x(0);
+    auto &resultY = result->y(0);
 
     // const MantidVec & sampleE = SampleWS->readE(0);
     for (size_t i = 0; i < sampleY.size(); i++) {
@@ -177,11 +177,11 @@ public:
         API::AnalysisDataService::Instance().retrieveWS<API::MatrixWorkspace>(
             "TestWS2");
 
-    const MantidVec &sampleX = SampleWS->readX(0);
-    const MantidVec &sampleY = SampleWS->readY(0);
+    auto &sampleX = SampleWS->x(0);
+    auto &sampleY = SampleWS->y(0);
 
-    const MantidVec &resultX = result->readX(0);
-    const MantidVec &resultY = result->readY(0);
+    auto &resultX = result->x(0);
+    auto &resultY = result->y(0);
 
     // const MantidVec & sampleE = SampleWS->readE(0);
     for (size_t i = 0; i < sampleY.size(); i++) {
@@ -205,9 +205,9 @@ public:
     auto binEdges = {0.0, 1.0};
     bgWS->setBinEdges(0, binEdges);
     bgWS->getAxis(0)->setUnit("TOF");
-    MantidVec &Ybg = bgWS->dataY(0);
+    auto &Ybg = bgWS->mutableY(0);
     Ybg[0] = 0;
-    MantidVec &Ebg = bgWS->dataE(0);
+    auto &Ebg = bgWS->mutableE(0);
     Ebg[0] = 0;
 
     // remove background. If bacground is fully 0, algorithm just removes
@@ -226,8 +226,8 @@ public:
         API::AnalysisDataService::Instance().retrieveWS<API::MatrixWorkspace>(
             "RemovedBgWS");
 
-    const MantidVec &resY = result->dataY(0);
-    const MantidVec &resE = result->readE(0);
+    auto &resY = result->y(0);
+    auto &resE = result->e(0);
 
     // const MantidVec & sampleE = SampleWS->readE(0);
     for (size_t i = 0; i < resY.size(); i++) {
@@ -240,10 +240,7 @@ private:
   API::MatrixWorkspace_sptr cloneSourceWS() {
     auto cloneWS = API::WorkspaceFactory::Instance().create(SourceWS);
 
-    auto X = SourceWS->refX(0);
-    cloneWS->setX(0, X);
-    cloneWS->dataY(0) = SourceWS->readY(0);
-    cloneWS->dataE(0) = SourceWS->readE(0);
+    cloneWS->setHistogram(0, SourceWS->histogram(0));
 
     return cloneWS;
   }
@@ -264,7 +261,6 @@ public:
   }
 
   RemoveBackgroundTestPerformance() {
-
     init_workspaces(1000, 15000, BgWS, SourceWS);
   }
 
@@ -277,31 +273,7 @@ public:
     bkgRem.setPropertyValue("BkgWorkspace", BgWS->getName());
     bkgRem.setPropertyValue("EMode", "Direct");
 
-    TS_ASSERT_THROWS_NOTHING(bkgRem.execute());
-
-    auto SampleWS =
-        API::AnalysisDataService::Instance().retrieveWS<API::MatrixWorkspace>(
-            "sampleWSdE");
-    auto result =
-        API::AnalysisDataService::Instance().retrieveWS<API::MatrixWorkspace>(
-            "sourceWSdE");
-
-    size_t spectra[] = {0, 10, 100, 999};
-    std::vector<size_t> list_to_check(spectra, spectra + 4);
-
-    for (size_t i = 0; i < list_to_check.size(); i++) {
-      const MantidVec &sampleX = SampleWS->readX(list_to_check[i]);
-      const MantidVec &sampleY = SampleWS->readY(list_to_check[i]);
-
-      const MantidVec &resultX = result->readX(list_to_check[i]);
-      const MantidVec &resultY = result->readY(list_to_check[i]);
-
-      // const MantidVec & sampleE = SampleWS->readE(0);
-      for (size_t i = 0; i < sampleY.size(); i++) {
-        TS_ASSERT_DELTA(resultX[i], sampleX[i], 1.e-7);
-        TS_ASSERT_DELTA(resultY[i], sampleY[i], 1.e-7);
-      }
-    }
+    bkgRem.execute();
   }
 
 private:
diff --git a/Framework/Algorithms/test/RemoveBinsTest.h b/Framework/Algorithms/test/RemoveBinsTest.h
index 4b7baf49b908fdb5168f2724e437ab5d78f6d116..5513c2e71160cc04f37426f84215874c693d1463 100644
--- a/Framework/Algorithms/test/RemoveBinsTest.h
+++ b/Framework/Algorithms/test/RemoveBinsTest.h
@@ -4,20 +4,23 @@
 #include <cxxtest/TestSuite.h>
 
 #include <sstream>
-#include <string>
 #include <stdexcept>
+#include <string>
 
-#include "MantidAlgorithms/RemoveBins.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Axis.h"
+#include "MantidAPI/WorkspaceFactory.h"
+#include "MantidAlgorithms/RemoveBins.h"
 #include "MantidDataHandling/LoadMuonNexus2.h"
-#include "MantidDataHandling/LoadInstrument.h"
 #include "MantidDataObjects/Workspace2D.h"
+#include "MantidHistogramData/LinearGenerator.h"
 #include "MantidKernel/UnitFactory.h"
 
 using namespace Mantid::Algorithms;
 using namespace Mantid::API;
 using namespace Mantid::DataObjects;
 using Mantid::HistogramData::BinEdges;
+using Mantid::HistogramData::LinearGenerator;
 
 class RemoveBinsTest : public CxxTest::TestSuite {
 public:
@@ -55,10 +58,10 @@ public:
     // 10   20   30   40   X
     //     2     5     6       Y
 
-    TS_ASSERT_EQUALS(outputWS->dataX(0).size(), 4);
-    TS_ASSERT_EQUALS(outputWS->dataY(0).size(), 3);
-    TS_ASSERT_EQUALS(outputWS->dataX(0)[0], 10);
-    TS_ASSERT_EQUALS(outputWS->dataY(0)[0], 2);
+    TS_ASSERT_EQUALS(outputWS->x(0).size(), 4);
+    TS_ASSERT_EQUALS(outputWS->y(0).size(), 3);
+    TS_ASSERT_EQUALS(outputWS->x(0)[0], 10);
+    TS_ASSERT_EQUALS(outputWS->y(0)[0], 2);
   }
 
   void testRemoveFromBack() {
@@ -85,12 +88,12 @@ public:
     // 0   10   20   30    X
     //   0     2     5        Y
 
-    TS_ASSERT_EQUALS(outputWS->dataX(0).size(), 4);
-    TS_ASSERT_EQUALS(outputWS->dataY(0).size(), 3);
-    TS_ASSERT_EQUALS(outputWS->dataX(0)[0], 0);
-    TS_ASSERT_EQUALS(outputWS->dataY(0)[0], 0);
-    TS_ASSERT_EQUALS(outputWS->dataX(0)[3], 30);
-    TS_ASSERT_EQUALS(outputWS->dataY(0)[2], 5);
+    TS_ASSERT_EQUALS(outputWS->x(0).size(), 4);
+    TS_ASSERT_EQUALS(outputWS->y(0).size(), 3);
+    TS_ASSERT_EQUALS(outputWS->x(0)[0], 0);
+    TS_ASSERT_EQUALS(outputWS->y(0)[0], 0);
+    TS_ASSERT_EQUALS(outputWS->x(0)[3], 30);
+    TS_ASSERT_EQUALS(outputWS->y(0)[2], 5);
   }
 
   void testRemoveFromMiddle() {
@@ -118,14 +121,14 @@ public:
     // 0   10   20   30   40   X
     //   0     2     4     6       Y
 
-    TS_ASSERT_EQUALS(outputWS->dataX(0).size(), 5);
-    TS_ASSERT_EQUALS(outputWS->dataY(0).size(), 4);
-    TS_ASSERT_EQUALS(outputWS->dataX(0)[0], 0);
-    TS_ASSERT_EQUALS(outputWS->dataX(0)[3], 30);
-    TS_ASSERT_EQUALS(outputWS->dataY(0)[0], 0);
-    TS_ASSERT_EQUALS(outputWS->dataY(0)[1], 1.5);
-    TS_ASSERT_EQUALS(outputWS->dataY(0)[2], 3);
-    TS_ASSERT_EQUALS(outputWS->dataY(0)[3], 6);
+    TS_ASSERT_EQUALS(outputWS->x(0).size(), 5);
+    TS_ASSERT_EQUALS(outputWS->y(0).size(), 4);
+    TS_ASSERT_EQUALS(outputWS->x(0)[0], 0);
+    TS_ASSERT_EQUALS(outputWS->x(0)[3], 30);
+    TS_ASSERT_EQUALS(outputWS->y(0)[0], 0);
+    TS_ASSERT_EQUALS(outputWS->y(0)[1], 1.5);
+    TS_ASSERT_EQUALS(outputWS->y(0)[2], 3);
+    TS_ASSERT_EQUALS(outputWS->y(0)[3], 6);
   }
 
   void testSingleSpectrum() {
@@ -144,13 +147,13 @@ public:
         AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("input2D");
     MatrixWorkspace_const_sptr outputWS =
         AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("output4");
-    TS_ASSERT_EQUALS(inputWS->readX(0), outputWS->readX(0))
-    TS_ASSERT_EQUALS(inputWS->readX(1), outputWS->readX(1))
-    TS_ASSERT_EQUALS(inputWS->readY(1), outputWS->readY(1))
-    TS_ASSERT_EQUALS(inputWS->readE(1), outputWS->readE(1))
+    TS_ASSERT_EQUALS(inputWS->x(0).rawData(), outputWS->x(0).rawData())
+    TS_ASSERT_EQUALS(inputWS->x(1).rawData(), outputWS->x(1).rawData())
+    TS_ASSERT_EQUALS(inputWS->y(1).rawData(), outputWS->y(1).rawData())
+    TS_ASSERT_EQUALS(inputWS->e(1).rawData(), outputWS->e(1).rawData())
     for (int i = 0; i < 4; ++i) {
-      TS_ASSERT_EQUALS(outputWS->readY(0)[i], 0.0)
-      TS_ASSERT_EQUALS(outputWS->readE(0)[i], 0.0)
+      TS_ASSERT_EQUALS(outputWS->y(0)[i], 0.0)
+      TS_ASSERT_EQUALS(outputWS->e(0)[i], 0.0)
     }
 
     AnalysisDataService::Instance().remove("output4");
@@ -173,13 +176,13 @@ public:
     MatrixWorkspace_const_sptr outputWS =
         AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(
             outputWSName);
-    TS_ASSERT_EQUALS(inputWS->readX(1), outputWS->readX(1))
-    TS_ASSERT_EQUALS(inputWS->readX(0), outputWS->readX(0))
-    TS_ASSERT_EQUALS(inputWS->readY(0), outputWS->readY(0))
-    TS_ASSERT_EQUALS(inputWS->readE(0), outputWS->readE(0))
+    TS_ASSERT_EQUALS(inputWS->x(1).rawData(), outputWS->x(1).rawData())
+    TS_ASSERT_EQUALS(inputWS->x(0).rawData(), outputWS->x(0).rawData())
+    TS_ASSERT_EQUALS(inputWS->y(0).rawData(), outputWS->y(0).rawData())
+    TS_ASSERT_EQUALS(inputWS->e(0).rawData(), outputWS->e(0).rawData())
     for (int i = 0; i < 4; ++i) {
-      TS_ASSERT_EQUALS(outputWS->readY(1)[i], 0.0)
-      TS_ASSERT_EQUALS(outputWS->readE(1)[i], 0.0)
+      TS_ASSERT_EQUALS(outputWS->y(1)[i], 0.0)
+      TS_ASSERT_EQUALS(outputWS->e(1)[i], 0.0)
     }
 
     AnalysisDataService::Instance().remove(outputWSName);
@@ -211,7 +214,7 @@ public:
     MatrixWorkspace_const_sptr outputWS =
         AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("result1");
 
-    TS_ASSERT_EQUALS(outputWS->dataX(0).size(), 1994);
+    TS_ASSERT_EQUALS(outputWS->x(0).size(), 1994);
   }
 
   Workspace2D_sptr makeDummyWorkspace2D() {
@@ -220,16 +223,16 @@ public:
     testWorkspace->setTitle("input2D");
     testWorkspace->initialize(2, 5, 4);
 
-    BinEdges X{0, 10, 20, 30, 40};
+    BinEdges X(5, LinearGenerator(0, 10));
     std::vector<double> Y{0, 2, 5, 6};
     std::vector<double> E{0, 2, 5, 6};
 
     testWorkspace->setBinEdges(0, X);
     testWorkspace->setBinEdges(1, X);
-    testWorkspace->dataY(0) = Y;
-    testWorkspace->dataE(0) = E;
-    testWorkspace->dataY(1) = Y;
-    testWorkspace->dataE(1) = E;
+    testWorkspace->mutableY(0) = Y;
+    testWorkspace->mutableE(0) = E;
+    testWorkspace->mutableY(1) = std::move(Y);
+    testWorkspace->mutableE(1) = std::move(E);
 
     testWorkspace->getAxis(0)->unit() =
         Mantid::Kernel::UnitFactory::Instance().create("TOF");
@@ -246,4 +249,57 @@ private:
   RemoveBins alg4;
 };
 
+class RemoveBinsTestPerformance : public CxxTest::TestSuite {
+public:
+  static RemoveBinsTestPerformance *createSuite() {
+    return new RemoveBinsTestPerformance();
+  }
+
+  static void destroySuite(RemoveBinsTestPerformance *suite) { delete suite; }
+
+  RemoveBinsTestPerformance() {
+    auto wksp = boost::make_shared<Workspace2D>();
+    wksp->setTitle("input");
+    wksp->initialize(numHists, 10000, 9999);
+    BinEdges edges(10000, LinearGenerator(0, 10));
+
+    for (size_t i = 0; i < numHists; i++)
+      wksp->setBinEdges(i, edges);
+
+    wksp->getAxis(0)->unit() =
+        Mantid::Kernel::UnitFactory::Instance().create("TOF");
+
+    AnalysisDataService::Instance().addOrReplace("input", wksp);
+  }
+
+  ~RemoveBinsTestPerformance() {
+    AnalysisDataService::Instance().remove("input");
+    AnalysisDataService::Instance().remove("outputBack");
+    AnalysisDataService::Instance().remove("outputMiddle");
+  }
+
+  void testRemoveFromBack() {
+    alg.initialize();
+    alg.setPropertyValue("InputWorkspace", "input");
+    alg.setPropertyValue("OutputWorkspace", "outputBack");
+    alg.setPropertyValue("XMin", "80000");
+    alg.setPropertyValue("XMax", "100000");
+    alg.setPropertyValue("Interpolation", "Linear");
+    alg.execute();
+  }
+
+  void testRemoveFromMiddle() {
+    alg.initialize();
+    alg.setPropertyValue("InputWorkspace", "input");
+    alg.setPropertyValue("OutputWorkspace", "outputMiddle");
+    alg.setPropertyValue("XMin", "32000");
+    alg.setPropertyValue("XMax", "53000");
+    alg.setPropertyValue("Interpolation", "Linear");
+    alg.execute();
+  }
+
+private:
+  const size_t numHists = 10000;
+  RemoveBins alg;
+};
 #endif /*RemoveBinsTest_H_*/
diff --git a/Framework/Algorithms/test/RemoveExpDecayTest.h b/Framework/Algorithms/test/RemoveExpDecayTest.h
index dfcdf1a8ad8b4b2d92679188846bdcd426ccf314..76a136302b9d7260f3e8d8b1ca7abecc2c8a474b 100644
--- a/Framework/Algorithms/test/RemoveExpDecayTest.h
+++ b/Framework/Algorithms/test/RemoveExpDecayTest.h
@@ -3,6 +3,7 @@
 
 #include <cxxtest/TestSuite.h>
 #include "MantidAlgorithms/RemoveExpDecay.h"
+#include "MantidKernel/PhysicalConstants.h"
 #include "MantidAPI/FrameworkManager.h"
 #include "MantidAPI/AlgorithmManager.h"
 #include "MantidHistogramData/LinearGenerator.h"
diff --git a/Framework/Algorithms/test/RemoveLowResTOFTest.h b/Framework/Algorithms/test/RemoveLowResTOFTest.h
index b3a67a4138630bf9ab56571ecc586b31c5af0d07..3eab32dccbed5532f2ed1e300612fc4ce0d7406c 100644
--- a/Framework/Algorithms/test/RemoveLowResTOFTest.h
+++ b/Framework/Algorithms/test/RemoveLowResTOFTest.h
@@ -29,7 +29,7 @@ private:
 
   void makeFakeEventWorkspace(std::string wsName) {
     // Make an event workspace with 2 events in each bin.
-    EventWorkspace_sptr test_in = WorkspaceCreationHelper::CreateEventWorkspace(
+    EventWorkspace_sptr test_in = WorkspaceCreationHelper::createEventWorkspace(
         NUMPIXELS, NUMBINS, NUMBINS, 0.0, BIN_DELTA, 2);
     // Fake a TOF unit in the data.
     test_in->getAxis(0)->unit() = UnitFactory::Instance().create("TOF");
diff --git a/Framework/Algorithms/test/RemoveMaskedSpectraTest.h b/Framework/Algorithms/test/RemoveMaskedSpectraTest.h
index 79c73b9322e8711d625d631e30d8a8c9b1594f05..bdbd9bbf38fdd326f41b956edd0066fe9a48a80d 100644
--- a/Framework/Algorithms/test/RemoveMaskedSpectraTest.h
+++ b/Framework/Algorithms/test/RemoveMaskedSpectraTest.h
@@ -5,6 +5,7 @@
 
 #include "MantidAlgorithms/RemoveMaskedSpectra.h"
 #include "MantidAPI/AlgorithmManager.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidHistogramData/LinearGenerator.h"
diff --git a/Framework/Algorithms/test/RemovePromptPulseTest.h b/Framework/Algorithms/test/RemovePromptPulseTest.h
index d1a442aa97eb3ed554ecb1da37f5b53984b91e4f..7ead65949a204e934837714401b8bdf2123d94c3 100644
--- a/Framework/Algorithms/test/RemovePromptPulseTest.h
+++ b/Framework/Algorithms/test/RemovePromptPulseTest.h
@@ -30,7 +30,7 @@ private:
 
   void makeFakeEventWorkspace(std::string wsName) {
     // Make an event workspace with 2 events in each bin.
-    EventWorkspace_sptr test_in = WorkspaceCreationHelper::CreateEventWorkspace(
+    EventWorkspace_sptr test_in = WorkspaceCreationHelper::createEventWorkspace(
         NUMPIXELS, NUMBINS, NUMEVENTS, 1000., BIN_DELTA, 2);
     // Fake a TOF unit in the data.
     test_in->getAxis(0)->unit() = UnitFactory::Instance().create("TOF");
diff --git a/Framework/Algorithms/test/RemoveWorkspaceHistoryTest.h b/Framework/Algorithms/test/RemoveWorkspaceHistoryTest.h
index aa2e8cded73256e8939a3d7804aa8487c5ab45dc..4c10f4a53ccf584a88c87ba1b9b8078e75ca587c 100644
--- a/Framework/Algorithms/test/RemoveWorkspaceHistoryTest.h
+++ b/Framework/Algorithms/test/RemoveWorkspaceHistoryTest.h
@@ -4,8 +4,11 @@
 #include <cxxtest/TestSuite.h>
 
 #include "MantidAlgorithms/RemoveWorkspaceHistory.h"
+#include "MantidAPI/AnalysisDataService.h"
+#include "MantidAPI/WorkspaceHistory.h"
 #include "MantidTestHelpers/FakeObjects.h"
 
+using namespace Mantid::Kernel;
 using Mantid::Algorithms::RemoveWorkspaceHistory;
 
 class RemoveWorkspaceHistoryTest : public CxxTest::TestSuite {
@@ -131,4 +134,4 @@ public:
   }
 };
 
-#endif /* MANTID_ALGORITHMS_REMOVEWORKSPACEHISTORYTEST_H_ */
\ No newline at end of file
+#endif /* MANTID_ALGORITHMS_REMOVEWORKSPACEHISTORYTEST_H_ */
diff --git a/Framework/Algorithms/test/RenameWorkspaceTest.h b/Framework/Algorithms/test/RenameWorkspaceTest.h
index fa94ec20dda2ec6bc1323add4f477d6e8c945b2e..936fc0c4182f2b866f43741ab1f386e911c48e34 100644
--- a/Framework/Algorithms/test/RenameWorkspaceTest.h
+++ b/Framework/Algorithms/test/RenameWorkspaceTest.h
@@ -6,6 +6,7 @@
 #include "MantidTestHelpers/WorkspaceCreationHelper.h"
 #include "MantidAlgorithms/RenameWorkspace.h"
 #include "MantidAPI/AnalysisDataService.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidKernel/Exception.h"
 
 using namespace Mantid::API;
@@ -145,9 +146,9 @@ public:
     // course
     TS_ASSERT_EQUALS(resultGroup->size(), 2)
     TS_ASSERT_EQUALS(resultGroup->getItem(0), member1)
-    TS_ASSERT_EQUALS(resultGroup->getItem(0)->name(), "newName_1")
+    TS_ASSERT_EQUALS(resultGroup->getItem(0)->getName(), "newName_1")
     TS_ASSERT_EQUALS(resultGroup->getItem(1), member2)
-    TS_ASSERT_EQUALS(resultGroup->getItem(1)->name(), "newName_2")
+    TS_ASSERT_EQUALS(resultGroup->getItem(1)->getName(), "newName_2")
     // The old ones should not be in the ADS
     TS_ASSERT_THROWS(ads.retrieve("oldName"),
                      Mantid::Kernel::Exception::NotFoundError)
@@ -224,7 +225,7 @@ public:
   }
   MatrixWorkspace_sptr createWorkspace() {
     MatrixWorkspace_sptr inputWS =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(4, 4, 0.5);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(4, 4, 0.5);
 
     return inputWS;
   }
diff --git a/Framework/Algorithms/test/RenameWorkspacesTest.h b/Framework/Algorithms/test/RenameWorkspacesTest.h
index 84edbac9066301f1a0f87dbd01d9610a4550f64e..f711912ce6d04403cf86a1c513028d462c49aa8c 100644
--- a/Framework/Algorithms/test/RenameWorkspacesTest.h
+++ b/Framework/Algorithms/test/RenameWorkspacesTest.h
@@ -6,6 +6,7 @@
 #include "MantidTestHelpers/WorkspaceCreationHelper.h"
 #include "MantidAlgorithms/RenameWorkspaces.h"
 #include "MantidAPI/AnalysisDataService.h"
+#include "MantidAPI/WorkspaceGroup.h"
 
 using namespace Mantid::API;
 using namespace Mantid::Kernel;
@@ -264,7 +265,7 @@ public:
 
   MatrixWorkspace_sptr createWorkspace() {
     MatrixWorkspace_sptr inputWS =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(4, 4, 0.5);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(4, 4, 0.5);
     return inputWS;
   }
 
diff --git a/Framework/Algorithms/test/ReplaceSpecialValuesTest.h b/Framework/Algorithms/test/ReplaceSpecialValuesTest.h
index 95dbbd337bab8ce0d62ce2f6e8c4bc469a2a9d59..6e090cfce8abe867e6c45bb089e7c1c2cd44a6fd 100644
--- a/Framework/Algorithms/test/ReplaceSpecialValuesTest.h
+++ b/Framework/Algorithms/test/ReplaceSpecialValuesTest.h
@@ -25,30 +25,28 @@ public:
     TS_ASSERT(alg2.isInitialized());
 
     const std::vector<Property *> props = alg2.getProperties();
-    TS_ASSERT_EQUALS(props.size(), 9);
+    TS_ASSERT_EQUALS(props.size(), 12);
 
     TS_ASSERT_EQUALS(props[0]->name(), "InputWorkspace");
-    TS_ASSERT(props[0]->isDefault());
     TS_ASSERT(dynamic_cast<WorkspaceProperty<MatrixWorkspace> *>(props[0]));
 
     TS_ASSERT_EQUALS(props[1]->name(), "OutputWorkspace");
-    TS_ASSERT(props[1]->isDefault());
     TS_ASSERT(dynamic_cast<WorkspaceProperty<MatrixWorkspace> *>(props[1]));
 
     TS_ASSERT_EQUALS(props[2]->name(), "NaNValue");
-    TS_ASSERT(props[2]->isDefault());
     TS_ASSERT_EQUALS(props[3]->name(), "NaNError");
-    TS_ASSERT(props[3]->isDefault());
     TS_ASSERT_EQUALS(props[4]->name(), "InfinityValue");
-    TS_ASSERT(props[4]->isDefault());
     TS_ASSERT_EQUALS(props[5]->name(), "InfinityError");
-    TS_ASSERT(props[5]->isDefault());
     TS_ASSERT_EQUALS(props[6]->name(), "BigNumberThreshold");
-    TS_ASSERT(props[6]->isDefault());
     TS_ASSERT_EQUALS(props[7]->name(), "BigNumberValue");
-    TS_ASSERT(props[7]->isDefault());
     TS_ASSERT_EQUALS(props[8]->name(), "BigNumberError");
-    TS_ASSERT(props[8]->isDefault());
+    TS_ASSERT_EQUALS(props[9]->name(), "SmallNumberThreshold");
+    TS_ASSERT_EQUALS(props[10]->name(), "SmallNumberValue");
+    TS_ASSERT_EQUALS(props[11]->name(), "SmallNumberError");
+
+    for (const auto prop : props) {
+      assert_property_is_default(prop);
+    }
   }
 
   void testExecCheckBoth() {
@@ -137,8 +135,8 @@ public:
   void testExecCheckBig() {
     MatrixWorkspace_sptr inputWS = createWorkspace();
     // Put in some 'big' values
-    inputWS->dataY(0)[0] = 1.0E12;
-    inputWS->dataY(0)[1] = 1.000001E10;
+    inputWS->mutableY(0)[0] = 1.0E12;
+    inputWS->mutableY(0)[1] = 1.000001E10;
     AnalysisDataService::Instance().add("InputWS", inputWS);
 
     Mantid::Algorithms::ReplaceSpecialValues alg3;
@@ -164,13 +162,60 @@ public:
     for (size_t i = 0; i < result->getNumberHistograms(); ++i) {
       for (int j = 0; j < 4; ++j) {
         if ((i == 0 && j != 3) || (i == 1 && j == 0)) {
-          TS_ASSERT_EQUALS(result->readY(i)[j], 999);
-          TS_ASSERT_EQUALS(result->readE(i)[j], 0.00005);
-        } else if (inputWS->readY(i)[j] != inputWS->readY(i)[j]) // nan
+          TS_ASSERT_EQUALS(result->y(i)[j], 999);
+          TS_ASSERT_EQUALS(result->e(i)[j], 0.00005);
+        } else if (inputWS->y(i)[j] != inputWS->y(i)[j]) // NaN
         {
-          TS_ASSERT_DIFFERS(result->readY(i)[j], result->readY(i)[j]);
+          TS_ASSERT_DIFFERS(result->y(i)[j], result->y(i)[j]);
         } else {
-          TS_ASSERT_EQUALS(result->readY(i)[j], inputWS->readY(i)[j]);
+          TS_ASSERT_EQUALS(result->y(i)[j], inputWS->y(i)[j]);
+        }
+      }
+    }
+
+    AnalysisDataService::Instance().remove("InputWS");
+    AnalysisDataService::Instance().remove("WSCor");
+  }
+
+  void testExecCheckSmall() {
+    MatrixWorkspace_sptr inputWS = createWorkspace();
+    // Put in some small values
+    inputWS->dataY(0)[0] = 2.0E-7;
+    inputWS->dataY(0)[1] = 1.99E-7;
+    AnalysisDataService::Instance().add("InputWS", inputWS);
+
+    Mantid::Algorithms::ReplaceSpecialValues alg3;
+    alg3.initialize();
+    TS_ASSERT_THROWS_NOTHING(
+        alg3.setPropertyValue("InputWorkspace", "InputWS"));
+    TS_ASSERT_THROWS_NOTHING(alg3.setPropertyValue("OutputWorkspace", "WSCor"));
+    TS_ASSERT_THROWS_NOTHING(
+        alg3.setPropertyValue("SmallNumberThreshold", "2.0E-7"));
+    TS_ASSERT_THROWS_NOTHING(
+        alg3.setPropertyValue("SmallNumberValue", "0.123"));
+    TS_ASSERT_THROWS_NOTHING(
+        alg3.setPropertyValue("SmallNumberError", "0.456"));
+
+    TS_ASSERT_THROWS_NOTHING(alg3.execute());
+    TS_ASSERT(alg3.isExecuted());
+
+    MatrixWorkspace_sptr result;
+    TS_ASSERT_THROWS_NOTHING(
+        result = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(
+            "WSCor"));
+    TS_ASSERT(result);
+
+    TS_ASSERT_EQUALS(result->y(0)[1], 0.123);
+    TS_ASSERT_EQUALS(result->e(0)[1], 0.456);
+
+    for (size_t i = 0; i < result->getNumberHistograms(); ++i) {
+      for (int j = 0; j < 4; ++j) {
+        if ((i == 0 && j == 1) || !std::isnormal(inputWS->y(i)[j])) {
+          // Skip our changed one or any we can't compare
+          continue;
+        } else {
+          TS_ASSERT_EQUALS(result->y(i)[j], inputWS->y(i)[j]);
+          TS_ASSERT_EQUALS(result->e(i)[j], inputWS->e(i)[j]);
         }
       }
     }
@@ -202,25 +247,25 @@ public:
 
     for (size_t i = 0; i < result->getNumberHistograms(); ++i) {
       for (int j = 1; j < 5; ++j) {
-        TS_ASSERT_EQUALS(result->dataX(i)[j - 1], inputWS->dataX(i)[j - 1]);
+        TS_ASSERT_EQUALS(result->x(i)[j - 1], inputWS->x(i)[j - 1]);
 
-        if (infCheck && std::isinf(inputWS->dataY(i)[j - 1])) {
-          if (std::isinf(result->dataY(i)[j - 1])) {
-            TS_FAIL("Infinity detected that shold have been replaced");
+        if (infCheck && std::isinf(inputWS->y(i)[j - 1])) {
+          if (std::isinf(result->y(i)[j - 1])) {
+            TS_FAIL("Infinity detected that should have been replaced");
           } else {
-            TS_ASSERT_DELTA(result->dataY(i)[j - 1], 999.0, 1e-8);
-            TS_ASSERT_DELTA(result->dataE(i)[j - 1], 0.00005, 1e-8);
+            TS_ASSERT_DELTA(result->y(i)[j - 1], 999.0, 1e-8);
+            TS_ASSERT_DELTA(result->e(i)[j - 1], 0.00005, 1e-8);
           }
-        } else if (naNCheck && std::isnan(inputWS->dataY(i)[j - 1])) {
-          TS_ASSERT_DELTA(result->dataY(i)[j - 1], -99.0, 1e-8);
-          TS_ASSERT_DELTA(result->dataE(i)[j - 1], -50.0, 1e-8);
+        } else if (naNCheck && std::isnan(inputWS->y(i)[j - 1])) {
+          TS_ASSERT_DELTA(result->y(i)[j - 1], -99.0, 1e-8);
+          TS_ASSERT_DELTA(result->e(i)[j - 1], -50.0, 1e-8);
         } else {
-          if (!naNCheck && std::isnan(inputWS->dataY(i)[j - 1])) {
-            TS_ASSERT_DIFFERS(result->dataY(i)[j - 1], result->dataY(i)[j - 1]);
+          if (!naNCheck && std::isnan(inputWS->y(i)[j - 1])) {
+            TS_ASSERT_DIFFERS(result->y(i)[j - 1], result->y(i)[j - 1]);
           } else {
-            TS_ASSERT_EQUALS(result->dataY(i)[j - 1], inputWS->dataY(i)[j - 1]);
+            TS_ASSERT_EQUALS(result->y(i)[j - 1], inputWS->y(i)[j - 1]);
           }
-          TS_ASSERT_EQUALS(result->dataE(i)[j - 1], inputWS->dataE(i)[j - 1]);
+          TS_ASSERT_EQUALS(result->e(i)[j - 1], inputWS->e(i)[j - 1]);
         }
       }
     }
@@ -228,8 +273,8 @@ public:
 
   MatrixWorkspace_sptr createWorkspace() {
     MatrixWorkspace_sptr inputWS =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(4, 4, 0.5);
-    // put some infinitis and NaNs in there
+        WorkspaceCreationHelper::create2DWorkspaceBinned(4, 4, 0.5);
+    // put some infinities and NaNs in there
     double inf = std::numeric_limits<double>::infinity();
     inputWS->dataY(0)[2] = inf;
     inputWS->dataY(1)[0] = -inf;
@@ -241,7 +286,7 @@ public:
   }
 
   void testEvents() {
-    EventWorkspace_sptr evin = WorkspaceCreationHelper::CreateEventWorkspace(
+    EventWorkspace_sptr evin = WorkspaceCreationHelper::createEventWorkspace(
                             1, 5, 10, 0, 1, 3),
                         evout;
     AnalysisDataService::Instance().add("test_ev_rep", evin);
@@ -286,6 +331,10 @@ public:
 
 private:
   Mantid::Algorithms::ReplaceSpecialValues alg;
+
+  void assert_property_is_default(const Property *propToCheck) {
+    TS_ASSERT(propToCheck->isDefault());
+  }
 };
 
 #endif /*REPLACESPECIALVALUESTEST_H_*/
diff --git a/Framework/Algorithms/test/ResampleXTest.h b/Framework/Algorithms/test/ResampleXTest.h
index 0621a3c96240b672106fa8a48dfa6630daf56497..e50b72d4d56c162eed3ca7daddb1515745ba5c93 100644
--- a/Framework/Algorithms/test/ResampleXTest.h
+++ b/Framework/Algorithms/test/ResampleXTest.h
@@ -4,6 +4,7 @@
 #include <cxxtest/TestSuite.h>
 
 #include "MantidAlgorithms/ResampleX.h"
+#include "MantidAPI/AnalysisDataService.h"
 
 using namespace Mantid::API;
 using Mantid::Algorithms::ResampleX;
diff --git a/Framework/Algorithms/test/ResetNegativesTest.h b/Framework/Algorithms/test/ResetNegativesTest.h
index c14284f079c8e616cf42e063b8f0f4a20cc5face..29281e1919d09bc0adf0d65e84d1dde6c26721b7 100644
--- a/Framework/Algorithms/test/ResetNegativesTest.h
+++ b/Framework/Algorithms/test/ResetNegativesTest.h
@@ -146,7 +146,7 @@ private:
     constexpr int nhist = 3;
     constexpr int nbins = 256;
     MatrixWorkspace_sptr inputWS =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(nhist, nbins, 1., .2);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(nhist, nbins, 1., .2);
     for (int i = 0; i < nhist; i++) {
       double value = offset + static_cast<double>(i);
       auto &y = inputWS->mutableY(i);
@@ -189,7 +189,7 @@ private:
     constexpr int nhist = 50000;
     constexpr int nbins = 1000;
     MatrixWorkspace_sptr inputWS =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(nhist, nbins, 1., .2);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(nhist, nbins, 1., .2);
     for (int i = 0; i < nhist; i++) {
       double value = offset + static_cast<double>(i);
       auto &y = inputWS->mutableY(i);
diff --git a/Framework/Algorithms/test/ResizeRectangularDetectorTest.h b/Framework/Algorithms/test/ResizeRectangularDetectorTest.h
index c0ef9d7de6b08624a39d328fdaf50a20e0037aa7..4fd48ccd2c7d0df17ad03db6c63a43b9381eb277 100644
--- a/Framework/Algorithms/test/ResizeRectangularDetectorTest.h
+++ b/Framework/Algorithms/test/ResizeRectangularDetectorTest.h
@@ -3,6 +3,7 @@
 
 #include "MantidAlgorithms/ResizeRectangularDetector.h"
 #include "MantidAPI/MatrixWorkspace.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidDataObjects/EventWorkspace.h"
 #include "MantidGeometry/Instrument.h"
 #include "MantidGeometry/Instrument/RectangularDetector.h"
@@ -56,14 +57,14 @@ public:
     TS_ASSERT_EQUALS(pos, V3D(0.008 * 2, 0.008 * 0.5, 5.0));
     TS_ASSERT_DELTA(det->xstep(), 0.008 * 2, 1e-6);
 
-    // Check that accessing through getDetector() also works
-    IDetector_const_sptr pixel;
+    // Check that accessing through spectrumInfo.detector() also works
     const RectangularDetectorPixel *recDetPix;
-    pixel = ws->getDetector(11);
+    const auto &spectrumInfo = ws->spectrumInfo();
+    const auto &pixel = spectrumInfo.detector(11);
     recDetPix = dynamic_cast<const RectangularDetectorPixel *>(
         det->getAtXY(1, 1).get());
     TSM_ASSERT("getDetector() returns a RectangularDetectorPixel", recDetPix);
-    pos = pixel->getPos();
+    pos = pixel.getPos();
     TS_ASSERT_EQUALS(pos, V3D(0.008 * 2, 0.008 * 0.5, 5.0));
 
     // Bank 2 did not get scaled
diff --git a/Framework/Algorithms/test/RingProfileTest.h b/Framework/Algorithms/test/RingProfileTest.h
index 5d2941637a503bf0368ec0064cc80bfd16e4bed4..3c3b62424dda795e6aaf503c2e7bf34a099aa5b4 100644
--- a/Framework/Algorithms/test/RingProfileTest.h
+++ b/Framework/Algorithms/test/RingProfileTest.h
@@ -110,7 +110,7 @@ public:
    */
   static MatrixWorkspace_sptr create_2d_workspace() {
     MatrixWorkspace_sptr goodWS =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(5, 5, -0.3, 0.12);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(5, 5, -0.3, 0.12);
     NumericAxis *yAxis = new NumericAxis(5);
 
     for (int i = 0; i < 5; ++i) {
diff --git a/Framework/Algorithms/test/SANSCollimationLengthEstimatorTest.h b/Framework/Algorithms/test/SANSCollimationLengthEstimatorTest.h
index 4eac613b723ddef3b96317eb60677d28fb81fcb4..6be6c9e16041371f99fc505b0386a09da35c18e9 100644
--- a/Framework/Algorithms/test/SANSCollimationLengthEstimatorTest.h
+++ b/Framework/Algorithms/test/SANSCollimationLengthEstimatorTest.h
@@ -123,7 +123,7 @@ Mantid::API::MatrixWorkspace_sptr createTestWorkspace(
     double numberOfGuides = 5, V3D sourcePosition = V3D(0.0, 0.0, -25.0),
     V3D samplePosition = V3D(0.0, 0.0, 0.0),
     std::vector<double> guideLogDetails = std::vector<double>()) {
-  auto ws2d = WorkspaceCreationHelper::Create2DWorkspaceFromFunction(
+  auto ws2d = WorkspaceCreationHelper::create2DWorkspaceFromFunction(
       ones(), static_cast<int>(nhist), x0, x1, dx);
 
   // Add the instrument with a single detector
diff --git a/Framework/Algorithms/test/SassenaFFTTest.h b/Framework/Algorithms/test/SassenaFFTTest.h
index 721b6a800efd8a4aa92b288d9ef316dd63207d0c..4c15d0aa2fc5219da2356e5a9f2e1f2b96e7434c 100644
--- a/Framework/Algorithms/test/SassenaFFTTest.h
+++ b/Framework/Algorithms/test/SassenaFFTTest.h
@@ -8,6 +8,7 @@
 #include "MantidKernel/UnitFactory.h"
 #include "MantidDataHandling/SaveAscii.h"
 #include "MantidAPI/FileProperty.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidKernel/PhysicalConstants.h"
 
 using namespace Mantid;
diff --git a/Framework/Algorithms/test/ScaleTest.h b/Framework/Algorithms/test/ScaleTest.h
index 6d48b67eed41afb8042cccebc6d8b506e075e393..a74ffea69d3412d294fd66e42ffb1e1a7aaef864 100644
--- a/Framework/Algorithms/test/ScaleTest.h
+++ b/Framework/Algorithms/test/ScaleTest.h
@@ -27,7 +27,7 @@ public:
       scale.initialize();
 
     AnalysisDataService::Instance().add(
-        "tomultiply", WorkspaceCreationHelper::Create2DWorkspace123(10, 10));
+        "tomultiply", WorkspaceCreationHelper::create2DWorkspace123(10, 10));
     TS_ASSERT_THROWS_NOTHING(
         scale.setPropertyValue("InputWorkspace", "tomultiply"));
     TS_ASSERT_THROWS_NOTHING(
@@ -59,7 +59,7 @@ public:
     scale2.initialize();
 
     AnalysisDataService::Instance().add(
-        "toadd", WorkspaceCreationHelper::Create2DWorkspace123(10, 10));
+        "toadd", WorkspaceCreationHelper::create2DWorkspace123(10, 10));
     TS_ASSERT_THROWS_NOTHING(
         scale2.setPropertyValue("InputWorkspace", "toadd"));
     TS_ASSERT_THROWS_NOTHING(
@@ -133,7 +133,7 @@ private:
     bool isHist = true;
     std::string wsName = "input_scaling";
     Mantid::API::AnalysisDataService::Instance().add(
-        wsName, WorkspaceCreationHelper::Create2DWorkspaceWithValuesAndXerror(
+        wsName, WorkspaceCreationHelper::create2DWorkspaceWithValuesAndXerror(
                     nHist, nBins, isHist, xValue, value, error, xError));
     std::string outWorkspaceName;
     if (outIsIn) {
diff --git a/Framework/Algorithms/test/ScaleXTest.h b/Framework/Algorithms/test/ScaleXTest.h
index 5004f5de9b2b4079d6a1fd8699d997c391a53af3..4f6fbf2d8e9a348030ce85698fc61388df8062d0 100644
--- a/Framework/Algorithms/test/ScaleXTest.h
+++ b/Framework/Algorithms/test/ScaleXTest.h
@@ -34,7 +34,7 @@ public:
     using namespace Mantid::API;
     using namespace Mantid::Kernel;
 
-    auto inputWS = WorkspaceCreationHelper::Create2DWorkspace123(10, 10);
+    auto inputWS = WorkspaceCreationHelper::create2DWorkspace123(10, 10);
     double factor = 2.5;
     auto result = runScaleX(inputWS, "Multiply", factor);
     checkScaleFactorApplied(inputWS, result, factor, true); // multiply=true
@@ -44,7 +44,7 @@ public:
     using namespace Mantid::API;
     using namespace Mantid::Kernel;
 
-    auto inputWS = WorkspaceCreationHelper::Create2DWorkspace123(10, 10);
+    auto inputWS = WorkspaceCreationHelper::create2DWorkspace123(10, 10);
     double factor = 2.5;
     auto result = runScaleX(inputWS, "Add", factor);
     checkScaleFactorApplied(inputWS, result, factor, false); // multiply=false
@@ -57,7 +57,7 @@ public:
     Mantid::Algorithms::ScaleX scale;
     scale.initialize();
 
-    auto inputWS = WorkspaceCreationHelper::CreateEventWorkspace2(10, 10);
+    auto inputWS = WorkspaceCreationHelper::createEventWorkspace2(10, 10);
     double factor(2.5);
     auto result = runScaleX(inputWS, "Multiply", factor);
     TS_ASSERT_EQUALS("EventWorkspace", result->id());
@@ -71,7 +71,7 @@ public:
     Mantid::Algorithms::ScaleX scale;
     scale.initialize();
 
-    auto inputWS = WorkspaceCreationHelper::CreateEventWorkspace2(10, 10);
+    auto inputWS = WorkspaceCreationHelper::createEventWorkspace2(10, 10);
     double factor(2.5);
     auto result = runScaleX(inputWS, "Add", factor);
     TS_ASSERT_EQUALS("EventWorkspace", result->id());
@@ -393,9 +393,9 @@ public:
   static void destroySuite(ScaleXTestPerformance *suite) { delete suite; }
 
   void setUp() override {
-    inputMatrix = WorkspaceCreationHelper::Create2DWorkspaceBinned(10000, 1000);
+    inputMatrix = WorkspaceCreationHelper::create2DWorkspaceBinned(10000, 1000);
     inputEvent =
-        WorkspaceCreationHelper::CreateEventWorkspace(10000, 1000, 5000);
+        WorkspaceCreationHelper::createEventWorkspace(10000, 1000, 5000);
   }
 
   void tearDown() override {
diff --git a/Framework/Algorithms/test/SetUncertaintiesTest.h b/Framework/Algorithms/test/SetUncertaintiesTest.h
index 4faebf9124b7c94389b5530102d4859043daa065..1fb51ce41ce14233ecb82d72c6dafd8c80a8984d 100644
--- a/Framework/Algorithms/test/SetUncertaintiesTest.h
+++ b/Framework/Algorithms/test/SetUncertaintiesTest.h
@@ -25,7 +25,7 @@ public:
   */
   API::MatrixWorkspace_sptr runAlg(const std::string &mode) {
     // random data mostly works
-    auto inWksp = WorkspaceCreationHelper::Create1DWorkspaceRand(30);
+    auto inWksp = WorkspaceCreationHelper::create1DWorkspaceRand(30);
     // Ensure first elements of random workspace are zero so test don't
     // pass randomly
     auto &E = inWksp->mutableE(0);
@@ -58,7 +58,7 @@ public:
       TS_ASSERT_EQUALS(item, 0.);
     }
 
-    API::AnalysisDataService::Instance().remove(outWS->name());
+    API::AnalysisDataService::Instance().remove(outWS->getName());
   }
 
   void test_sqrt() {
@@ -70,7 +70,7 @@ public:
       TS_ASSERT_DELTA(Y[i], E[i] * E[i], .001);
     }
 
-    API::AnalysisDataService::Instance().remove(outWS->name());
+    API::AnalysisDataService::Instance().remove(outWS->getName());
   }
 
   void test_oneIfZero() {
@@ -80,7 +80,7 @@ public:
     for (const auto item : E) {
       TS_ASSERT(item > 0.);
     }
-    API::AnalysisDataService::Instance().remove(outWS->name());
+    API::AnalysisDataService::Instance().remove(outWS->getName());
   }
 
   void test_sqrtOrOne() {
@@ -96,7 +96,7 @@ public:
       }
     }
 
-    API::AnalysisDataService::Instance().remove(outWS->name());
+    API::AnalysisDataService::Instance().remove(outWS->getName());
   }
 };
 
@@ -111,7 +111,7 @@ public:
     constexpr size_t wsSize(1000000);
 
     // random data mostly works
-    inputWs = WorkspaceCreationHelper::Create1DWorkspaceRand(wsSize);
+    inputWs = WorkspaceCreationHelper::create1DWorkspaceRand(wsSize);
     algZero.setProperty("InputWorkspace", inputWs);
     algZero.setProperty("SetError", "zero");
     algZero.setProperty("OutputWorkspace", wsName);
diff --git a/Framework/Algorithms/test/ShiftLogTimeTest.h b/Framework/Algorithms/test/ShiftLogTimeTest.h
index 6f65dd18ebeb24d1e205b6b97e09cf367608958e..7c7f0c77aaa1240a167178f78c8f9ee2b552b0c5 100644
--- a/Framework/Algorithms/test/ShiftLogTimeTest.h
+++ b/Framework/Algorithms/test/ShiftLogTimeTest.h
@@ -7,6 +7,7 @@
 #include "MantidKernel/System.h"
 #include "MantidKernel/Timer.h"
 #include "MantidKernel/TimeSeriesProperty.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Run.h"
 
 using namespace Mantid;
diff --git a/Framework/Algorithms/test/SignalOverErrorTest.h b/Framework/Algorithms/test/SignalOverErrorTest.h
index 66b47972ef7467c927796029aa53eaeb8a7f8df4..fb9096f56410f7fa1f8dc672fa19c32bc5aebe3b 100644
--- a/Framework/Algorithms/test/SignalOverErrorTest.h
+++ b/Framework/Algorithms/test/SignalOverErrorTest.h
@@ -25,7 +25,7 @@ public:
     // Name of the output workspace.
     std::string outWSName("SignalOverErrorTest_OutputWS");
 
-    Workspace2D_sptr inWS = WorkspaceCreationHelper::Create2DWorkspace(2, 10);
+    Workspace2D_sptr inWS = WorkspaceCreationHelper::create2DWorkspace(2, 10);
 
     SignalOverError alg;
     TS_ASSERT_THROWS_NOTHING(alg.initialize())
diff --git a/Framework/Algorithms/test/SmoothDataTest.h b/Framework/Algorithms/test/SmoothDataTest.h
index 10c44e51808ee99d4a70f915cc0ea4fe296f5bce..de76f00e0612f49b36e5f35bfb886f26af1dcd08 100644
--- a/Framework/Algorithms/test/SmoothDataTest.h
+++ b/Framework/Algorithms/test/SmoothDataTest.h
@@ -189,7 +189,7 @@ public:
     constexpr size_t numBins(1000000);
 
     inputWs =
-        WorkspaceCreationHelper::Create2DWorkspace(numHistograms, numBins);
+        WorkspaceCreationHelper::create2DWorkspace(numHistograms, numBins);
 
     auto &yVals = inputWs->mutableY(0);
     auto &eVals = inputWs->mutableE(0);
diff --git a/Framework/Algorithms/test/SofQWNormalisedPolygonTest.h b/Framework/Algorithms/test/SofQWNormalisedPolygonTest.h
index a13a89691303427d4b497ef7fe0b52a8a5c3d9ee..ed87aaa6f7ddbfa17ba6e7194ab8974fa7f553f6 100644
--- a/Framework/Algorithms/test/SofQWNormalisedPolygonTest.h
+++ b/Framework/Algorithms/test/SofQWNormalisedPolygonTest.h
@@ -3,6 +3,7 @@
 
 #include <cxxtest/TestSuite.h>
 #include "MantidAlgorithms/SofQWNormalisedPolygon.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Axis.h"
 #include "MantidKernel/Unit.h"
 
diff --git a/Framework/Algorithms/test/SofQWPolygonTest.h b/Framework/Algorithms/test/SofQWPolygonTest.h
index 14091af984018ed5a323ccc1fc6ff8ad934c43ca..0461c8819f44e43af499e859adb22829ec5741e0 100644
--- a/Framework/Algorithms/test/SofQWPolygonTest.h
+++ b/Framework/Algorithms/test/SofQWPolygonTest.h
@@ -3,6 +3,7 @@
 
 #include <cxxtest/TestSuite.h>
 #include "MantidAlgorithms/SofQWPolygon.h"
+#include "MantidAPI/WorkspaceHistory.h"
 
 #include "SofQWTest.h"
 
diff --git a/Framework/Algorithms/test/SofQWTest.h b/Framework/Algorithms/test/SofQWTest.h
index dd07d12e2fcef8e4491459f16e16b37628ab0181..695e9b5dbb6361df26bfe01a4be8a52f0a32528a 100644
--- a/Framework/Algorithms/test/SofQWTest.h
+++ b/Framework/Algorithms/test/SofQWTest.h
@@ -3,8 +3,10 @@
 
 #include <cxxtest/TestSuite.h>
 #include "MantidAlgorithms/SofQW.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Axis.h"
 #include "MantidAPI/MatrixWorkspace.h"
+#include "MantidAPI/WorkspaceHistory.h"
 #include "MantidKernel/Unit.h"
 #include "MantidDataHandling/LoadNexusProcessed.h"
 
diff --git a/Framework/Algorithms/test/SolidAngleTest.h b/Framework/Algorithms/test/SolidAngleTest.h
index 7fbd26fcaeb0497c305f5b44213f815a44c819f5..fbd06c446c84213f2d351ba40e4b7618ae3b7f38 100644
--- a/Framework/Algorithms/test/SolidAngleTest.h
+++ b/Framework/Algorithms/test/SolidAngleTest.h
@@ -6,9 +6,11 @@
 
 #include "MantidAlgorithms/SolidAngle.h"
 #include "MantidKernel/PhysicalConstants.h"
+#include "MantidKernel/Unit.h"
 #include "MantidKernel/UnitFactory.h"
 #include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Axis.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidDataObjects/Workspace2D.h"
 #include "MantidDataHandling/LoadInstrument.h"
@@ -39,8 +41,6 @@ public:
       space2D->setBinEdges(j, x);
       space2D->setCounts(j, a);
       space2D->setCountVariances(j, e);
-      // Just set the spectrum number to match the index
-      space2D->getSpectrum(j).setSpectrumNo(j + 1);
     }
 
     // Register the workspace in the data service
@@ -60,9 +60,7 @@ public:
     space2D->getAxis(0)->unit() = UnitFactory::Instance().create("TOF");
 
     // Mark one detector dead to test that it leads to zero solid angle
-    IDetector_const_sptr det143 = space2D->getDetector(143);
-    ParameterMap &pmap = space2D->instrumentParameters();
-    pmap.addBool(det143.get(), "masked", true);
+    space2D->mutableSpectrumInfo().setMasked(143, true);
   }
 
   void testInit() {
diff --git a/Framework/Algorithms/test/SortEventsTest.h b/Framework/Algorithms/test/SortEventsTest.h
index bc49c37416f0df28fbcef297716badfa0ce32e59..a4594137bff4d0294c5ecafa5d7ff01b927776e1 100644
--- a/Framework/Algorithms/test/SortEventsTest.h
+++ b/Framework/Algorithms/test/SortEventsTest.h
@@ -35,11 +35,11 @@ public:
   void testSortByTof() {
     std::string wsName("test_inEvent3");
     EventWorkspace_sptr test_in =
-        WorkspaceCreationHelper::CreateRandomEventWorkspace(NUMBINS, NUMPIXELS);
+        WorkspaceCreationHelper::createRandomEventWorkspace(NUMBINS, NUMPIXELS);
     AnalysisDataService::Instance().add(wsName, test_in);
 
     Workspace2D_sptr test_in_ws2d =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(NUMBINS, NUMPIXELS);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(NUMBINS, NUMPIXELS);
     AnalysisDataService::Instance().add("workspace2d", test_in_ws2d);
 
     SortEvents sort;
@@ -70,7 +70,7 @@ public:
   void testSortByPulseTime() {
     std::string wsName("test_inEvent4");
     EventWorkspace_sptr test_in =
-        WorkspaceCreationHelper::CreateRandomEventWorkspace(NUMBINS, NUMPIXELS);
+        WorkspaceCreationHelper::createRandomEventWorkspace(NUMBINS, NUMPIXELS);
     AnalysisDataService::Instance().add(wsName, test_in);
 
     SortEvents sort;
@@ -94,7 +94,7 @@ public:
   void testSortByPulseTimeTOF() {
     std::string wsName("test_inEvent4");
     EventWorkspace_sptr test_in =
-        WorkspaceCreationHelper::CreateRandomEventWorkspace(NUMBINS, NUMPIXELS);
+        WorkspaceCreationHelper::createRandomEventWorkspace(NUMBINS, NUMPIXELS);
     AnalysisDataService::Instance().add(wsName, test_in);
 
     SortEvents sort;
diff --git a/Framework/Algorithms/test/SpatialGroupingTest.h b/Framework/Algorithms/test/SpatialGroupingTest.h
index f7e04c0c97abd8e22eae7c07a66f256b9923c7d7..32aa0cfb08d95fa3cdb576180448ac5fbe1e1308 100644
--- a/Framework/Algorithms/test/SpatialGroupingTest.h
+++ b/Framework/Algorithms/test/SpatialGroupingTest.h
@@ -38,7 +38,7 @@ public:
     const int nhist(18);
     Mantid::API::MatrixWorkspace_sptr workspace =
         boost::dynamic_pointer_cast<Mantid::API::MatrixWorkspace>(
-            WorkspaceCreationHelper::Create2DWorkspaceBinned(nhist, 1));
+            WorkspaceCreationHelper::create2DWorkspaceBinned(nhist, 1));
     // Create a parameterised instrument
     Mantid::Geometry::Instrument_sptr instrument =
         boost::dynamic_pointer_cast<Mantid::Geometry::Instrument>(
diff --git a/Framework/Algorithms/test/SpecularReflectionCalculateThetaTest.h b/Framework/Algorithms/test/SpecularReflectionCalculateThetaTest.h
index 1f06f4dd00f713de8d0fc19e09ea6f6e2f71a359..1a1fa6281c8e5cdce36e5f0ae639e2538cb836f0 100644
--- a/Framework/Algorithms/test/SpecularReflectionCalculateThetaTest.h
+++ b/Framework/Algorithms/test/SpecularReflectionCalculateThetaTest.h
@@ -49,7 +49,7 @@ public:
     IAlgorithm_sptr alg = makeAlgorithm();
     alg->setProperty(
         "InputWorkspace",
-        WorkspaceCreationHelper::Create1DWorkspaceConstant(1, 1, 1));
+        WorkspaceCreationHelper::create1DWorkspaceConstant(1, 1, 1));
 
     SpecularReflectionAlgorithmTest::
         test_throws_if_SpectrumNumbersOfDetectors_less_than_zero(alg);
@@ -59,7 +59,7 @@ public:
     IAlgorithm_sptr alg = makeAlgorithm();
     alg->setProperty(
         "InputWorkspace",
-        WorkspaceCreationHelper::Create1DWorkspaceConstant(1, 1, 1));
+        WorkspaceCreationHelper::create1DWorkspaceConstant(1, 1, 1));
 
     SpecularReflectionAlgorithmTest::
         test_throws_if_SpectrumNumbersOfDetectors_outside_range(alg);
diff --git a/Framework/Algorithms/test/SpecularReflectionPositionCorrectTest.h b/Framework/Algorithms/test/SpecularReflectionPositionCorrectTest.h
index cffecc4535e2978c919a7bdb66cdb1184567c75a..e12557edfae065e64aad4b59aab082342794c2ad 100644
--- a/Framework/Algorithms/test/SpecularReflectionPositionCorrectTest.h
+++ b/Framework/Algorithms/test/SpecularReflectionPositionCorrectTest.h
@@ -46,7 +46,7 @@ public:
     alg.initialize();
     alg.setProperty(
         "InputWorkspace",
-        WorkspaceCreationHelper::Create1DWorkspaceConstant(1, 1, 1));
+        WorkspaceCreationHelper::create1DWorkspaceConstant(1, 1, 1));
     alg.setPropertyValue("OutputWorkspace", "test_out");
     TS_ASSERT_THROWS(alg.execute(), std::runtime_error &);
   }
@@ -57,7 +57,7 @@ public:
     alg.initialize();
     alg.setProperty(
         "InputWorkspace",
-        WorkspaceCreationHelper::Create1DWorkspaceConstant(1, 1, 1));
+        WorkspaceCreationHelper::create1DWorkspaceConstant(1, 1, 1));
     alg.setPropertyValue("OutputWorkspace", "test_out");
     TS_ASSERT_THROWS(alg.setProperty("TwoThetaIn", 0.0),
                      std::invalid_argument &);
@@ -69,7 +69,7 @@ public:
     alg.initialize();
     alg.setProperty(
         "InputWorkspace",
-        WorkspaceCreationHelper::Create1DWorkspaceConstant(1, 1, 1));
+        WorkspaceCreationHelper::create1DWorkspaceConstant(1, 1, 1));
     alg.setPropertyValue("OutputWorkspace", "test_out");
     TS_ASSERT_THROWS(alg.setProperty("TwoThetaIn", 90.0),
                      std::invalid_argument &);
@@ -82,7 +82,7 @@ public:
     alg->initialize();
     alg->setProperty(
         "InputWorkspace",
-        WorkspaceCreationHelper::Create1DWorkspaceConstant(1, 1, 1));
+        WorkspaceCreationHelper::create1DWorkspaceConstant(1, 1, 1));
     alg->setPropertyValue("OutputWorkspace", "test_out");
     alg->setProperty("TwoThetaIn", 10.0);
 
diff --git a/Framework/Algorithms/test/Stitch1DManyTest.h b/Framework/Algorithms/test/Stitch1DManyTest.h
index 4e3ba5d1ecd4f55ca8b391ee56f2dc5176e5c8cb..f5e911fd8842a9a0896b4776e0250b88825169fe 100644
--- a/Framework/Algorithms/test/Stitch1DManyTest.h
+++ b/Framework/Algorithms/test/Stitch1DManyTest.h
@@ -3,30 +3,42 @@
 
 #include <cxxtest/TestSuite.h>
 
-#include "MantidAlgorithms/Stitch1D.h"
-#include "MantidAlgorithms/Stitch1DMany.h"
 #include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Axis.h"
 #include "MantidAPI/ITableWorkspace.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/WorkspaceFactory.h"
+#include "MantidAPI/WorkspaceGroup.h"
+#include "MantidAPI/WorkspaceHistory.h"
+#include "MantidAlgorithms/CreateWorkspace.h"
+#include "MantidAlgorithms/GroupWorkspaces.h"
+#include "MantidAlgorithms/Stitch1D.h"
+#include "MantidAlgorithms/Stitch1DMany.h"
 #include "MantidKernel/UnitFactory.h"
 #include <math.h>
 
 using namespace Mantid::API;
 using namespace Mantid::Kernel;
 using Mantid::Algorithms::Stitch1DMany;
+using Mantid::Algorithms::CreateWorkspace;
+using Mantid::Algorithms::GroupWorkspaces;
 
 class Stitch1DManyTest : public CxxTest::TestSuite {
 private:
-  /** Create a histogram workspace with two spectra and 10 bins
+  /** Create a histogram workspace with two spectra and 10 bins. This can also
+  * be run using the CreateWorkspace algorithm which leaves the output workspace
+  * in the ADS as well.
   * @param xstart :: the first X value (common to both spectra)
   * @param deltax :: the bin width
   * @param value1 :: the Y counts in the first spectrum (constant for all X)
   * @param value2 :: the Y counts in the second spectrum (constant for all X)
+  * @param runAlg :: set true to run the CreateWorkspace algorithm
+  * @oaram outWSName :: output workspace name used if running CreateWorkspace
   */
   MatrixWorkspace_sptr createUniformWorkspace(double xstart, double deltax,
-                                              double value1, double value2) {
+                                              double value1, double value2,
+                                              bool runAlg = false,
+                                              std::string outWSName = "") {
 
     const int nbins = 10;
     std::vector<double> xData1(nbins + 1);
@@ -49,19 +61,72 @@ private:
     xData1[nbins] = xData1[nbins - 1] + deltax;
     xData2[nbins] = xData2[nbins - 1] + deltax;
 
-    MatrixWorkspace_sptr ws =
-        WorkspaceFactory::Instance().create("Workspace2D", 2, nbins + 1, nbins);
-    ws->dataX(0) = xData1;
-    ws->dataX(1) = xData2;
-    ws->dataY(0) = yData1;
-    ws->dataY(1) = yData2;
-    ws->dataE(0) = eData1;
-    ws->dataE(1) = eData2;
-    ws->getAxis(0)->unit() = UnitFactory::Instance().create("Wavelength");
+    MatrixWorkspace_sptr ws;
+
+    if (!runAlg) {
+      ws = WorkspaceFactory::Instance().create("Workspace2D", 2, nbins + 1,
+                                               nbins);
+      ws->dataX(0) = xData1;
+      ws->dataX(1) = xData2;
+      ws->dataY(0) = yData1;
+      ws->dataY(1) = yData2;
+      ws->dataE(0) = eData1;
+      ws->dataE(1) = eData2;
+      ws->getAxis(0)->unit() = UnitFactory::Instance().create("Wavelength");
+    } else {
+      // Concatenate data vectors into one vector
+      xData1.insert(xData1.end(), xData2.begin(), xData2.end());
+      yData1.insert(yData1.end(), yData2.begin(), yData2.end());
+      eData1.insert(eData1.end(), eData2.begin(), eData2.end());
+
+      CreateWorkspace cw;
+      cw.initialize();
+      cw.setProperty("DataX", xData1);
+      cw.setProperty("DataY", yData1);
+      cw.setProperty("DataE", eData1);
+      cw.setProperty("NSpec", 2);
+      cw.setProperty("UnitX", "Wavelength");
+      cw.setPropertyValue("OutputWorkspace", outWSName);
+      cw.execute();
+
+      ws = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(
+          outWSName);
+    }
+
+    return ws;
+  }
 
+  /** Groups workspaces using GroupWorkspaces algorithm. The output workpace is
+  * left in the ADS as well.
+  * @param inputWSNames :: input workspaces names
+  * @param outputWSName :: output workspace name
+  */
+  WorkspaceGroup_sptr doGroupWorkspaces(std::string inputWSNames,
+                                        std::string outWSName) {
+    GroupWorkspaces gw;
+    gw.initialize();
+    gw.setProperty("InputWorkspaces", inputWSNames);
+    gw.setProperty("OutputWorkspace", outWSName);
+    gw.execute();
+
+    WorkspaceGroup_sptr ws =
+        AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>(outWSName);
     return ws;
   }
 
+  /** Obtain all algorithm histories from a workspace
+  * @param inputWS :: the input workspace
+  * @return vector of names of algorithm histories
+  */
+  std::vector<std::string> getHistory(MatrixWorkspace_sptr inputWS) {
+    std::vector<std::string> histNames;
+    auto histories = inputWS->history().getAlgorithmHistories();
+    for (auto &hist : histories) {
+      histNames.push_back(hist->name());
+    }
+    return histNames;
+  }
+
 public:
   // This pair of boilerplate methods prevent the suite being created statically
   // This means the constructor isn't called when running other tests
@@ -163,6 +228,46 @@ public:
     TS_ASSERT_THROWS(alg.execute(), std::runtime_error);
   }
 
+  void test_scale_factor_from_period_out_of_range_throws() {
+
+    // First group
+    auto ws1 = createUniformWorkspace(0.1, 0.1, 1., 2.);
+    auto ws2 = createUniformWorkspace(0.1, 0.1, 1.5, 2.5);
+    WorkspaceGroup_sptr group1 = boost::make_shared<WorkspaceGroup>();
+    group1->addWorkspace(ws1);
+    group1->addWorkspace(ws2);
+    // Second group
+    auto ws3 = createUniformWorkspace(0.8, 0.1, 1.1, 2.1);
+    auto ws4 = createUniformWorkspace(0.8, 0.1, 1.6, 2.6);
+    WorkspaceGroup_sptr group2 = boost::make_shared<WorkspaceGroup>();
+    group2->addWorkspace(ws3);
+    group2->addWorkspace(ws4);
+    // Third group
+    auto ws5 = createUniformWorkspace(1.6, 0.1, 1.5, 2.5);
+    auto ws6 = createUniformWorkspace(1.6, 0.1, 1.6, 3.0);
+    WorkspaceGroup_sptr group3 = boost::make_shared<WorkspaceGroup>();
+    group3->addWorkspace(ws5);
+    group3->addWorkspace(ws6);
+
+    // The algorithm needs the workspaces to be in the ADS
+    AnalysisDataService::Instance().addOrReplace("group1", group1);
+    AnalysisDataService::Instance().addOrReplace("group2", group2);
+    AnalysisDataService::Instance().addOrReplace("group3", group3);
+
+    Stitch1DMany alg;
+    alg.setChild(true);
+    alg.initialize();
+    alg.setProperty("InputWorkspaces", "group1, group2, group3");
+    alg.setProperty("Params", "0.1, 0.1, 2.6");
+    alg.setProperty("StartOverlaps", "0.8, 1.6");
+    alg.setProperty("EndOverlaps", "1.1, 1.9");
+    alg.setProperty("UseManualScaleFactor", "1");
+    alg.setProperty("ManualScaleFactor", 1.0);
+    alg.setProperty("ScaleFactorFromPeriod", 4);
+    alg.setPropertyValue("OutputWorkspace", "outws");
+    TS_ASSERT_THROWS(alg.execute(), std::runtime_error);
+  }
+
   void test_two_workspaces() {
     // Two matrix workspaces with two spectra each
 
@@ -187,20 +292,20 @@ public:
     auto stitched = boost::dynamic_pointer_cast<MatrixWorkspace>(outws);
     TS_ASSERT_EQUALS(stitched->getNumberHistograms(), 2);
     TS_ASSERT_EQUALS(stitched->blocksize(), 17);
-    TS_ASSERT_DELTA(stitched->readY(0)[0], 1, 0.00001);
-    TS_ASSERT_DELTA(stitched->readY(0)[9], 1, 0.00001);
-    TS_ASSERT_DELTA(stitched->readY(0)[16], 1, 0.00001);
-    TS_ASSERT_DELTA(stitched->readY(1)[0], 2, 0.00001);
-    TS_ASSERT_DELTA(stitched->readY(1)[9], 2, 0.00001);
-    TS_ASSERT_DELTA(stitched->readY(1)[16], 2, 0.00001);
-    TS_ASSERT_DELTA(stitched->readE(0)[0], 1, 0.00001);
-    TS_ASSERT_DELTA(stitched->readE(0)[9], 0.77919, 0.00001);
-    TS_ASSERT_DELTA(stitched->readE(0)[16], 1.24316, 0.00001);
-    TS_ASSERT_DELTA(stitched->readE(1)[0], 1.41421, 0.00001);
-    TS_ASSERT_DELTA(stitched->readE(1)[9], 1.10982, 0.00001);
-    TS_ASSERT_DELTA(stitched->readE(1)[16], 1.79063, 0.00001);
-
-    // Test out sclae factors
+    TS_ASSERT_DELTA(stitched->y(0)[0], 1, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(0)[9], 1, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(0)[16], 1, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(1)[0], 2, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(1)[9], 2, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(1)[16], 2, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(0)[0], 1, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(0)[9], 0.77919, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(0)[16], 1.24316, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(1)[0], 1.41421, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(1)[9], 1.10982, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(1)[16], 1.79063, 0.00001);
+
+    // Test out scale factors
     std::vector<double> scales = alg.getProperty("OutScaleFactors");
     TS_ASSERT_EQUALS(scales.size(), 1);
     // Only scale factor for first spectrum is returned
@@ -220,9 +325,10 @@ public:
     alg2.setPropertyValue("OutputWorkspace", "outws");
     alg2.execute();
     MatrixWorkspace_sptr stitched2 = alg2.getProperty("OutputWorkspace");
-    TS_ASSERT_EQUALS(stitched->readX(0), stitched2->readX(0));
-    TS_ASSERT_EQUALS(stitched->readY(0), stitched2->readY(0));
-    TS_ASSERT_EQUALS(stitched->readE(0), stitched2->readE(0));
+
+    TS_ASSERT_EQUALS(stitched->x(0).rawData(), stitched2->x(0).rawData());
+    TS_ASSERT_EQUALS(stitched->y(0).rawData(), stitched2->y(0).rawData());
+    TS_ASSERT_EQUALS(stitched->e(0).rawData(), stitched2->e(0).rawData());
 
     // Remove workspaces from ADS
     AnalysisDataService::Instance().remove("ws1");
@@ -256,27 +362,27 @@ public:
     TS_ASSERT_EQUALS(stitched->getNumberHistograms(), 2);
     TS_ASSERT_EQUALS(stitched->blocksize(), 25);
     // First spectrum, Y values
-    TS_ASSERT_DELTA(stitched->readY(0)[0], 1, 0.00001);
-    TS_ASSERT_DELTA(stitched->readY(0)[9], 1, 0.00001);
-    TS_ASSERT_DELTA(stitched->readY(0)[16], 1, 0.00001);
-    TS_ASSERT_DELTA(stitched->readY(0)[24], 1, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(0)[0], 1, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(0)[9], 1, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(0)[16], 1, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(0)[24], 1, 0.00001);
     // Second spectrum, Y values
-    TS_ASSERT_DELTA(stitched->readY(1)[0], 2, 0.00001);
-    TS_ASSERT_DELTA(stitched->readY(1)[9], 2, 0.00001);
-    TS_ASSERT_DELTA(stitched->readY(1)[16], 2, 0.00001);
-    TS_ASSERT_DELTA(stitched->readY(1)[24], 2, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(1)[0], 2, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(1)[9], 2, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(1)[16], 2, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(1)[24], 2, 0.00001);
     // First spectrum, E values
-    TS_ASSERT_DELTA(stitched->readE(0)[0], 1, 0.00001);
-    TS_ASSERT_DELTA(stitched->readE(0)[9], 0.77919, 0.00001);
-    TS_ASSERT_DELTA(stitched->readE(0)[16], 0.90865, 0.00001);
-    TS_ASSERT_DELTA(stitched->readE(0)[24], 1.33144, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(0)[0], 1, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(0)[9], 0.77919, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(0)[16], 0.90865, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(0)[24], 1.33144, 0.00001);
     // Second spectrum, E values
-    TS_ASSERT_DELTA(stitched->readE(1)[0], 1.41421, 0.00001);
-    TS_ASSERT_DELTA(stitched->readE(1)[9], 1.10982, 0.00001);
-    TS_ASSERT_DELTA(stitched->readE(1)[16], 1.33430, 0.00001);
-    TS_ASSERT_DELTA(stitched->readE(1)[24], 2.00079, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(1)[0], 1.41421, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(1)[9], 1.10982, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(1)[16], 1.33430, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(1)[24], 2.00079, 0.00001);
 
-    // Test out sclae factors
+    // Test out scale factors
     std::vector<double> scales = alg.getProperty("OutScaleFactors");
     TS_ASSERT_EQUALS(scales.size(), 2);
     TS_ASSERT_DELTA(scales.front(), 0.9090, 0.0001);
@@ -336,23 +442,23 @@ public:
     TS_ASSERT_EQUALS(stitched->getNumberHistograms(), 2);
     TS_ASSERT_EQUALS(stitched->blocksize(), 25);
     // First spectrum, Y values
-    TS_ASSERT_DELTA(stitched->readY(0)[0], 1, 0.00001);
-    TS_ASSERT_DELTA(stitched->readY(0)[10], 0.55000, 0.00001);
-    TS_ASSERT_DELTA(stitched->readY(0)[18], 0.75000, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(0)[0], 1, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(0)[10], 0.55000, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(0)[18], 0.75000, 0.00001);
     // Second spectrum, Y values
-    TS_ASSERT_DELTA(stitched->readY(1)[0], 2, 0.00001);
-    TS_ASSERT_DELTA(stitched->readY(1)[10], 1.05000, 0.00001);
-    TS_ASSERT_DELTA(stitched->readY(1)[18], 1.25000, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(1)[0], 2, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(1)[10], 1.05000, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(1)[18], 1.25000, 0.00001);
     // First spectrum, E values
-    TS_ASSERT_DELTA(stitched->readE(0)[0], 1.00000, 0.00001);
-    TS_ASSERT_DELTA(stitched->readE(0)[10], 0.52440, 0.00001);
-    TS_ASSERT_DELTA(stitched->readE(0)[18], 0.61237, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(0)[0], 1.00000, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(0)[10], 0.52440, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(0)[18], 0.61237, 0.00001);
     // Second spectrum, E values
-    TS_ASSERT_DELTA(stitched->readE(1)[0], 1.41421, 0.00001);
-    TS_ASSERT_DELTA(stitched->readE(1)[10], 0.72457, 0.00001);
-    TS_ASSERT_DELTA(stitched->readE(1)[18], 0.79057, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(1)[0], 1.41421, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(1)[10], 0.72457, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(1)[18], 0.79057, 0.00001);
 
-    // Test out sclae factors
+    // Test out scale factors
     std::vector<double> scales = alg.getProperty("OutScaleFactors");
     TS_ASSERT_EQUALS(scales.size(), 2);
     TS_ASSERT_EQUALS(scales.front(), 0.5);
@@ -384,9 +490,7 @@ public:
     alg.setProperty("StartOverlaps", "0.8");
     alg.setProperty("EndOverlaps", "1.1");
     alg.setPropertyValue("OutputWorkspace", "outws");
-    auto results = alg.validateInputs();
-    TS_ASSERT_EQUALS(results["InputWorkspaces"],
-                     "At least 2 input workspaces required.")
+    TS_ASSERT_THROWS(alg.execute(), std::runtime_error);
 
     AnalysisDataService::Instance().clear();
   }
@@ -432,27 +536,27 @@ public:
     TS_ASSERT_EQUALS(stitched->getNumberHistograms(), 2);
     TS_ASSERT_EQUALS(stitched->blocksize(), 25);
     // First spectrum, Y values
-    TS_ASSERT_DELTA(stitched->readY(0)[0], 1, 0.00001);
-    TS_ASSERT_DELTA(stitched->readY(0)[9], 1, 0.00001);
-    TS_ASSERT_DELTA(stitched->readY(0)[16], 1, 0.00001);
-    TS_ASSERT_DELTA(stitched->readY(0)[24], 1, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(0)[0], 1, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(0)[9], 1, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(0)[16], 1, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(0)[24], 1, 0.00001);
     // Second spectrum, Y values
-    TS_ASSERT_DELTA(stitched->readY(1)[0], 2, 0.00001);
-    TS_ASSERT_DELTA(stitched->readY(1)[9], 2, 0.00001);
-    TS_ASSERT_DELTA(stitched->readY(1)[16], 2, 0.00001);
-    TS_ASSERT_DELTA(stitched->readY(1)[24], 2, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(1)[0], 2, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(1)[9], 2, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(1)[16], 2, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(1)[24], 2, 0.00001);
     // First spectrum, E values
-    TS_ASSERT_DELTA(stitched->readE(0)[0], 1, 0.00001);
-    TS_ASSERT_DELTA(stitched->readE(0)[9], 0.77919, 0.00001);
-    TS_ASSERT_DELTA(stitched->readE(0)[16], 0.90865, 0.00001);
-    TS_ASSERT_DELTA(stitched->readE(0)[24], 1.33144, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(0)[0], 1, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(0)[9], 0.77919, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(0)[16], 0.90865, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(0)[24], 1.33144, 0.00001);
     // Second spectrum, E values
-    TS_ASSERT_DELTA(stitched->readE(1)[0], 1.41421, 0.00001);
-    TS_ASSERT_DELTA(stitched->readE(1)[9], 1.10982, 0.00001);
-    TS_ASSERT_DELTA(stitched->readE(1)[16], 1.33430, 0.00001);
-    TS_ASSERT_DELTA(stitched->readE(1)[24], 2.00079, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(1)[0], 1.41421, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(1)[9], 1.10982, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(1)[16], 1.33430, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(1)[24], 2.00079, 0.00001);
 
-    // Test out sclae factors
+    // Test out scale factors
     std::vector<double> scales = alg.getProperty("OutScaleFactors");
     TS_ASSERT_EQUALS(scales.size(), 2);
     TS_ASSERT_DELTA(scales.front(), 0.9090, 0.0001);
@@ -507,44 +611,44 @@ public:
     TS_ASSERT_EQUALS(stitched->getNumberHistograms(), 2);
     TS_ASSERT_EQUALS(stitched->blocksize(), 17);
     // First spectrum, Y values
-    TS_ASSERT_DELTA(stitched->readY(0)[0], 1, 0.00001);
-    TS_ASSERT_DELTA(stitched->readY(0)[9], 1, 0.00001);
-    TS_ASSERT_DELTA(stitched->readY(0)[16], 1, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(0)[0], 1, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(0)[9], 1, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(0)[16], 1, 0.00001);
     // Second spectrum, Y values
-    TS_ASSERT_DELTA(stitched->readY(1)[0], 2, 0.00001);
-    TS_ASSERT_DELTA(stitched->readY(1)[9], 2, 0.00001);
-    TS_ASSERT_DELTA(stitched->readY(1)[16], 2, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(1)[0], 2, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(1)[9], 2, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(1)[16], 2, 0.00001);
     // First spectrum, E values
-    TS_ASSERT_DELTA(stitched->readE(0)[0], 1, 0.00001);
-    TS_ASSERT_DELTA(stitched->readE(0)[9], 0.77919, 0.00001);
-    TS_ASSERT_DELTA(stitched->readE(0)[16], 1.24316, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(0)[0], 1, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(0)[9], 0.77919, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(0)[16], 1.24316, 0.00001);
     // Second spectrum, E values
-    TS_ASSERT_DELTA(stitched->readE(1)[0], 1.41421, 0.00001);
-    TS_ASSERT_DELTA(stitched->readE(1)[9], 1.10982, 0.00001);
-    TS_ASSERT_DELTA(stitched->readE(1)[16], 1.79063, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(1)[0], 1.41421, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(1)[9], 1.10982, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(1)[16], 1.79063, 0.00001);
 
     // Second item in the output group
     stitched = boost::dynamic_pointer_cast<MatrixWorkspace>(group->getItem(1));
     TS_ASSERT_EQUALS(stitched->getNumberHistograms(), 2);
     TS_ASSERT_EQUALS(stitched->blocksize(), 17);
     // First spectrum, Y values
-    TS_ASSERT_DELTA(stitched->readY(0)[0], 1.5, 0.00001);
-    TS_ASSERT_DELTA(stitched->readY(0)[9], 1.5, 0.00001);
-    TS_ASSERT_DELTA(stitched->readY(0)[16], 1.5, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(0)[0], 1.5, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(0)[9], 1.5, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(0)[16], 1.5, 0.00001);
     // Second spectrum, Y values
-    TS_ASSERT_DELTA(stitched->readY(1)[0], 2.5, 0.00001);
-    TS_ASSERT_DELTA(stitched->readY(1)[9], 2.5, 0.00001);
-    TS_ASSERT_DELTA(stitched->readY(1)[16], 2.5, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(1)[0], 2.5, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(1)[9], 2.5, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(1)[16], 2.5, 0.00001);
     // First spectrum, E values
-    TS_ASSERT_DELTA(stitched->readE(0)[0], 1.22474, 0.00001);
-    TS_ASSERT_DELTA(stitched->readE(0)[9], 0.95883, 0.00001);
-    TS_ASSERT_DELTA(stitched->readE(0)[16], 1.54110, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(0)[0], 1.22474, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(0)[9], 0.95883, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(0)[16], 1.54110, 0.00001);
     // Second spectrum, E values
-    TS_ASSERT_DELTA(stitched->readE(1)[0], 1.58114, 0.00001);
-    TS_ASSERT_DELTA(stitched->readE(1)[9], 1.24263, 0.00001);
-    TS_ASSERT_DELTA(stitched->readE(1)[16], 2.00959, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(1)[0], 1.58114, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(1)[9], 1.24263, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(1)[16], 2.00959, 0.00001);
 
-    // Test out sclae factors
+    // Test out scale factors
     std::vector<double> scales = alg.getProperty("OutScaleFactors");
     TS_ASSERT_EQUALS(scales.size(), 2);
     TS_ASSERT_DELTA(scales.front(), 0.9090, 0.0001); // 1.0/1.1
@@ -605,44 +709,44 @@ public:
     TS_ASSERT_EQUALS(stitched->getNumberHistograms(), 2);
     TS_ASSERT_EQUALS(stitched->blocksize(), 17);
     // First spectrum, Y values
-    TS_ASSERT_DELTA(stitched->readY(0)[0], 1, 0.00001);
-    TS_ASSERT_DELTA(stitched->readY(0)[9], 0.64705, 0.00001);
-    TS_ASSERT_DELTA(stitched->readY(0)[16], 0.55000, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(0)[0], 1, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(0)[9], 0.64705, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(0)[16], 0.55000, 0.00001);
     // Second spectrum, Y values
-    TS_ASSERT_DELTA(stitched->readY(1)[0], 2, 0.00001);
-    TS_ASSERT_DELTA(stitched->readY(1)[9], 1.24752, 0.00001);
-    TS_ASSERT_DELTA(stitched->readY(1)[16], 1.05000, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(1)[0], 2, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(1)[9], 1.24752, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(1)[16], 1.05000, 0.00001);
     // First spectrum, E values
-    TS_ASSERT_DELTA(stitched->readE(0)[0], 1, 0.00001);
-    TS_ASSERT_DELTA(stitched->readE(0)[9], 0.46442, 0.00001);
-    TS_ASSERT_DELTA(stitched->readE(0)[16], 0.52440, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(0)[0], 1, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(0)[9], 0.46442, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(0)[16], 0.52440, 0.00001);
     // Second spectrum, E values
-    TS_ASSERT_DELTA(stitched->readE(1)[0], 1.41421, 0.00001);
-    TS_ASSERT_DELTA(stitched->readE(1)[9], 0.64485, 0.00001);
-    TS_ASSERT_DELTA(stitched->readE(1)[16], 0.72456, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(1)[0], 1.41421, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(1)[9], 0.64485, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(1)[16], 0.72456, 0.00001);
 
     // Second item in the output group
     stitched = boost::dynamic_pointer_cast<MatrixWorkspace>(group->getItem(1));
     TS_ASSERT_EQUALS(stitched->getNumberHistograms(), 2);
     TS_ASSERT_EQUALS(stitched->blocksize(), 17);
     // First spectrum, Y values
-    TS_ASSERT_DELTA(stitched->readY(0)[0], 1.5, 0.00001);
-    TS_ASSERT_DELTA(stitched->readY(0)[9], 0.94736, 0.00001);
-    TS_ASSERT_DELTA(stitched->readY(0)[16], 0.8, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(0)[0], 1.5, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(0)[9], 0.94736, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(0)[16], 0.8, 0.00001);
     // Second spectrum, Y values
-    TS_ASSERT_DELTA(stitched->readY(1)[0], 2.5, 0.00001);
-    TS_ASSERT_DELTA(stitched->readY(1)[9], 1.54762, 0.00001);
-    TS_ASSERT_DELTA(stitched->readY(1)[16], 1.3, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(1)[0], 2.5, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(1)[9], 1.54762, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(1)[16], 1.3, 0.00001);
     // First spectrum, E values
-    TS_ASSERT_DELTA(stitched->readE(0)[0], 1.22474, 0.00001);
-    TS_ASSERT_DELTA(stitched->readE(0)[9], 0.56195, 0.00001);
-    TS_ASSERT_DELTA(stitched->readE(0)[16], 0.63245, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(0)[0], 1.22474, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(0)[9], 0.56195, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(0)[16], 0.63245, 0.00001);
     // Second spectrum, E values
-    TS_ASSERT_DELTA(stitched->readE(1)[0], 1.58114, 0.00001);
-    TS_ASSERT_DELTA(stitched->readE(1)[9], 0.71824, 0.00001);
-    TS_ASSERT_DELTA(stitched->readE(1)[16], 0.80622, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(1)[0], 1.58114, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(1)[9], 0.71824, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(1)[16], 0.80622, 0.00001);
 
-    // Test out sclae factors
+    // Test out scale factors
     std::vector<double> scales = alg.getProperty("OutScaleFactors");
     TS_ASSERT_EQUALS(scales.size(), 2);
     TS_ASSERT_DELTA(scales.front(), 0.5000, 0.0001);
@@ -651,6 +755,264 @@ public:
     // Clear the ADS
     AnalysisDataService::Instance().clear();
   }
+
+  void test_two_groups_with_three_workspaces_scale_factor_from_period() {
+    // Three groups with two matrix workspaces each.
+    // Each matrix workspace has two spectra.
+
+    // First group
+    auto ws1 = createUniformWorkspace(0.1, 0.1, 1., 2.);
+    auto ws2 = createUniformWorkspace(0.1, 0.1, 1.5, 2.5);
+    WorkspaceGroup_sptr group1 = boost::make_shared<WorkspaceGroup>();
+    group1->addWorkspace(ws1);
+    group1->addWorkspace(ws2);
+    // Second group
+    auto ws3 = createUniformWorkspace(0.8, 0.1, 1.1, 2.1);
+    auto ws4 = createUniformWorkspace(0.8, 0.1, 1.6, 2.6);
+    WorkspaceGroup_sptr group2 = boost::make_shared<WorkspaceGroup>();
+    group2->addWorkspace(ws3);
+    group2->addWorkspace(ws4);
+    // Third group
+    auto ws5 = createUniformWorkspace(1.6, 0.1, 1.5, 2.5);
+    auto ws6 = createUniformWorkspace(1.6, 0.1, 1.6, 3.0);
+    WorkspaceGroup_sptr group3 = boost::make_shared<WorkspaceGroup>();
+    group3->addWorkspace(ws5);
+    group3->addWorkspace(ws6);
+
+    // The algorithm needs the workspaces to be in the ADS
+    AnalysisDataService::Instance().addOrReplace("group1", group1);
+    AnalysisDataService::Instance().addOrReplace("group2", group2);
+    AnalysisDataService::Instance().addOrReplace("group3", group3);
+
+    // ws1 will be stitched with ws3 and ws5
+    // ws2 will be stitched with ws4 and ws6
+
+    Stitch1DMany alg;
+    alg.setChild(true);
+    alg.initialize();
+    alg.setProperty("InputWorkspaces", "group1, group2, group3");
+    alg.setProperty("Params", "0.1, 0.1, 2.6");
+    alg.setProperty("StartOverlaps", "0.8, 1.6");
+    alg.setProperty("EndOverlaps", "1.1, 1.9");
+    alg.setProperty("UseManualScaleFactor", "1");
+    alg.setProperty("ManualScaleFactor", 1.0);
+    alg.setProperty("ScaleFactorFromPeriod", 2);
+    alg.setPropertyValue("OutputWorkspace", "outws");
+    alg.execute();
+
+    // By setting ManualScaleFactor to 1.0 (default value) it allows workspaces
+    // in other periods to be scaled by scale factors from a specific period.
+    // Periods 0 and 2 workspaces will be scaled by scale factors from period 1.
+
+    // Test output ws
+    Workspace_sptr outws = alg.getProperty("OutputWorkspace");
+    auto group = boost::dynamic_pointer_cast<WorkspaceGroup>(outws);
+    TS_ASSERT_EQUALS(group->getNumberOfEntries(), 2);
+
+    // First item in the output group
+    auto stitched =
+        boost::dynamic_pointer_cast<MatrixWorkspace>(group->getItem(0));
+    TS_ASSERT_EQUALS(stitched->getNumberHistograms(), 2);
+    TS_ASSERT_EQUALS(stitched->blocksize(), 25);
+    // First spectrum, Y values
+    TS_ASSERT_DELTA(stitched->y(0)[0], 1, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(0)[9], 1.01589, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(0)[16], 0.97288, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(0)[24], 0.9375, 0.00001);
+    // Second spectrum, Y values
+    TS_ASSERT_DELTA(stitched->y(1)[0], 2, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(1)[9], 1.98375, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(1)[16], 1.70307, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(1)[24], 1.56250, 0.00001);
+    // First spectrum, E values
+    TS_ASSERT_DELTA(stitched->e(0)[0], 1, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(0)[9], 0.70111, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(0)[16], 0.60401, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(0)[24], 0.76547, 0.00001);
+    // Second spectrum, E values
+    TS_ASSERT_DELTA(stitched->e(1)[0], 1.41421, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(1)[9], 0.97973, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(1)[16], 0.79916, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(1)[24], 0.98821, 0.00001);
+
+    // Second item in the output group
+    stitched = boost::dynamic_pointer_cast<MatrixWorkspace>(group->getItem(1));
+
+    TS_ASSERT_EQUALS(stitched->getNumberHistograms(), 2);
+    TS_ASSERT_EQUALS(stitched->blocksize(), 25);
+    // First spectrum, Y values
+    TS_ASSERT_DELTA(stitched->y(0)[0], 1.5, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(0)[9], 1.5, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(0)[16], 1.15385, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(0)[24], 1, 0.00001);
+    // Second spectrum, Y values
+    TS_ASSERT_DELTA(stitched->y(1)[0], 2.5, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(1)[9], 2.46735, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(1)[16], 2.06568, 0.00001);
+    TS_ASSERT_DELTA(stitched->y(1)[24], 1.87500, 0.00001);
+    // First spectrum, E values
+    TS_ASSERT_DELTA(stitched->e(0)[0], 1.22474, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(0)[9], 0.85194, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(0)[16], 0.65779, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(0)[24], 0.79057, 0.00001);
+    // Second spectrum, E values
+    TS_ASSERT_DELTA(stitched->e(1)[0], 1.58114, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(1)[9], 1.09265, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(1)[16], 0.88013, 0.00001);
+    TS_ASSERT_DELTA(stitched->e(1)[24], 1.08253, 0.00001);
+
+    // Test out scale factors
+    std::vector<double> scales = alg.getProperty("OutScaleFactors");
+    TS_ASSERT_EQUALS(scales.size(), 4);
+    TS_ASSERT_DELTA(scales[0], 0.9375, 0.0001);
+    TS_ASSERT_DELTA(scales[1], 0.6249, 0.0001);
+    TS_ASSERT_DELTA(scales[2], 0.9375, 0.0001);
+    TS_ASSERT_DELTA(scales[3], 0.6249, 0.0001);
+
+    // Clear the ADS
+    AnalysisDataService::Instance().clear();
+  }
+
+  void test_two_workspaces_history() {
+    // This test is functionally similar to test_two_workspaces
+
+    // Two matrix workspaces with two spectra each
+    auto ws1 = createUniformWorkspace(0.1, 0.1, 1., 2., true, "ws1");
+    auto ws2 = createUniformWorkspace(0.8, 0.1, 1.1, 2.1, true, "ws2");
+
+    Stitch1DMany alg;
+    alg.initialize();
+    alg.setProperty("InputWorkspaces", "ws1, ws2");
+    alg.setProperty("Params", "0.1, 0.1, 1.8");
+    alg.setProperty("StartOverlaps", "0.8");
+    alg.setProperty("EndOverlaps", "1.1");
+    alg.setPropertyValue("OutputWorkspace", "outws");
+    alg.execute();
+
+    Workspace_sptr outws = alg.getProperty("OutputWorkspace");
+    auto stitched =
+        AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("outws");
+
+    // Test the algorithm histories
+    std::vector<std::string> histNames;
+    auto histories = stitched->history().getAlgorithmHistories();
+    for (auto &hist : histories) {
+      histNames.push_back(hist->name());
+    }
+
+    TS_ASSERT_EQUALS(histNames[0], "CreateWorkspace");
+    TS_ASSERT_EQUALS(histNames[1], "CreateWorkspace");
+    TS_ASSERT_EQUALS(histNames[2], "Stitch1DMany");
+
+    // Remove workspaces from ADS
+    AnalysisDataService::Instance().clear();
+  }
+
+  void test_two_groups_history() {
+    // This test is functionally similar to
+    // test_two_groups_with_two_workspaces_each
+
+    // Two groups with two matrix workspaces each.
+    // Each matrix workspace has two spectra.
+
+    // First group
+    auto ws1 = createUniformWorkspace(0.1, 0.1, 1., 2., true, "ws1");
+    auto ws2 = createUniformWorkspace(0.1, 0.1, 1.5, 2.5, true, "ws2");
+    WorkspaceGroup_sptr group1 = doGroupWorkspaces("ws1, ws2", "group1");
+    // Second group
+    auto ws3 = createUniformWorkspace(0.8, 0.1, 1.1, 2.1, true, "ws3");
+    auto ws4 = createUniformWorkspace(0.8, 0.1, 1.6, 2.6, true, "ws4");
+    WorkspaceGroup_sptr group2 = doGroupWorkspaces("ws3, ws4", "group2");
+
+    Stitch1DMany alg;
+    alg.initialize();
+    alg.setProperty("InputWorkspaces", "group1, group2");
+    alg.setProperty("Params", "0.1");
+    alg.setProperty("StartOverlaps", "0.8");
+    alg.setProperty("EndOverlaps", "1.1");
+    alg.setPropertyValue("OutputWorkspace", "outws");
+    alg.execute();
+
+    // Test output ws
+    Workspace_sptr outws = alg.getProperty("OutputWorkspace");
+    auto group =
+        AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>("outws");
+    TS_ASSERT_EQUALS(group->getNumberOfEntries(), 2);
+
+    // First item in the output group
+    auto stitched =
+        boost::dynamic_pointer_cast<MatrixWorkspace>(group->getItem(0));
+
+    // Test the algorithm histories
+    std::vector<std::string> histNames;
+    auto histories = stitched->history().getAlgorithmHistories();
+    for (auto &hist : histories) {
+      histNames.push_back(hist->name());
+    }
+
+    TS_ASSERT_EQUALS(histNames[0], "CreateWorkspace");
+    TS_ASSERT_EQUALS(histNames[1], "GroupWorkspaces");
+    TS_ASSERT_EQUALS(histNames[2], "CreateWorkspace");
+    TS_ASSERT_EQUALS(histNames[3], "GroupWorkspaces");
+    TS_ASSERT_EQUALS(histNames[4], "Stitch1DMany");
+
+    // Remove workspaces from ADS
+    AnalysisDataService::Instance().clear();
+  }
+
+  void test_two_groups_scale_factor_from_period_history() {
+    // This test is functionally similar to
+    // test_two_groups_with_three_workspaces_scale_factor_from_period
+
+    // Three groups with two matrix workspaces each.
+    // Each matrix workspace has two spectra.
+
+    // First group
+    auto ws1 = createUniformWorkspace(0.1, 0.1, 1., 2., true, "ws1");
+    auto ws2 = createUniformWorkspace(0.1, 0.1, 1.5, 2.5, true, "ws2");
+    WorkspaceGroup_sptr group1 = doGroupWorkspaces("ws1, ws2", "group1");
+    // Second group
+    auto ws3 = createUniformWorkspace(0.8, 0.1, 1.1, 2.1, true, "ws3");
+    auto ws4 = createUniformWorkspace(0.8, 0.1, 1.6, 2.6, true, "ws4");
+    WorkspaceGroup_sptr group2 = doGroupWorkspaces("ws3, ws4", "group2");
+    // Third group
+    auto ws5 = createUniformWorkspace(1.6, 0.1, 1.5, 2.5, true, "ws5");
+    auto ws6 = createUniformWorkspace(1.6, 0.1, 1.6, 3.0, true, "ws6");
+    WorkspaceGroup_sptr group3 = doGroupWorkspaces("ws5, ws6", "group3");
+
+    Stitch1DMany alg;
+    alg.initialize();
+    alg.setProperty("InputWorkspaces", "group1, group2, group3");
+    alg.setProperty("Params", "0.1, 0.1, 2.6");
+    alg.setProperty("StartOverlaps", "0.8, 1.6");
+    alg.setProperty("EndOverlaps", "1.1, 1.9");
+    alg.setProperty("UseManualScaleFactor", "1");
+    alg.setProperty("ManualScaleFactor", 1.0);
+    alg.setProperty("ScaleFactorFromPeriod", 2);
+    alg.setPropertyValue("OutputWorkspace", "outws");
+    alg.execute();
+
+    // Test output ws
+    Workspace_sptr outws = alg.getProperty("OutputWorkspace");
+    auto group =
+        AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>("outws");
+    auto stitched =
+        boost::dynamic_pointer_cast<MatrixWorkspace>(group->getItem(0));
+
+    // Test the algorithm histories
+    std::vector<std::string> histNames;
+    auto histories = stitched->history().getAlgorithmHistories();
+    for (auto &hist : histories) {
+      histNames.push_back(hist->name());
+    }
+
+    TS_ASSERT_EQUALS(histNames[0], "CreateWorkspace");
+    TS_ASSERT_EQUALS(histNames[1], "CreateWorkspace");
+    TS_ASSERT_EQUALS(histNames[2], "GroupWorkspaces");
+
+    // Clear the ADS
+    AnalysisDataService::Instance().clear();
+  }
 };
 
 #endif /* MANTID_ALGORITHMS_STITCH1DMANYTEST_H_ */
diff --git a/Framework/Algorithms/test/Stitch1DTest.h b/Framework/Algorithms/test/Stitch1DTest.h
index 95d75140e46c3e9c0a793fa51093dc056b86b9a3..5c23756d31daf65d1f72cdba44108cf2940aba9d 100644
--- a/Framework/Algorithms/test/Stitch1DTest.h
+++ b/Framework/Algorithms/test/Stitch1DTest.h
@@ -4,6 +4,7 @@
 #include <cxxtest/TestSuite.h>
 
 #include "MantidAlgorithms/Stitch1D.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Axis.h"
 #include "MantidKernel/UnitFactory.h"
 #include "MantidDataObjects/Workspace2D.h"
diff --git a/Framework/Algorithms/test/StripPeaksTest.h b/Framework/Algorithms/test/StripPeaksTest.h
index 025981db15c0cc5b4c1033675c96935c9c50f1ea..20a75c97df4ccdaf9261c3a6229e18c81a20e535 100644
--- a/Framework/Algorithms/test/StripPeaksTest.h
+++ b/Framework/Algorithms/test/StripPeaksTest.h
@@ -21,7 +21,7 @@ public:
   StripPeaksTest() {
     FrameworkManager::Instance();
     MatrixWorkspace_sptr WS =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(2, 200, 0.5, 0.02);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(2, 200, 0.5, 0.02);
     WS->getAxis(0)->unit() =
         Mantid::Kernel::UnitFactory::Instance().create("dSpacing");
 
@@ -111,7 +111,7 @@ public:
   void setUp() override {
     FrameworkManager::Instance();
     MatrixWorkspace_sptr WS =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(2, 200, 0.5, 0.02);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(2, 200, 0.5, 0.02);
     WS->getAxis(0)->unit() =
         Mantid::Kernel::UnitFactory::Instance().create("dSpacing");
 
diff --git a/Framework/Algorithms/test/SumEventsByLogValueTest.h b/Framework/Algorithms/test/SumEventsByLogValueTest.h
index 749d0587c73fde428883ff0fd78f03fbbd244c8b..c0fad83aa1fcb1e8efb04e04ba3e740dd710372d 100644
--- a/Framework/Algorithms/test/SumEventsByLogValueTest.h
+++ b/Framework/Algorithms/test/SumEventsByLogValueTest.h
@@ -28,10 +28,10 @@ public:
     // InputWorkspace has to be an EventWorkspace
     TS_ASSERT_THROWS(
         alg.setProperty("InputWorkspace",
-                        WorkspaceCreationHelper::Create2DWorkspace(1, 1)),
+                        WorkspaceCreationHelper::create2DWorkspace(1, 1)),
         std::invalid_argument);
     TS_ASSERT_THROWS_NOTHING(alg.setProperty(
-        "InputWorkspace", WorkspaceCreationHelper::CreateEventWorkspace()));
+        "InputWorkspace", WorkspaceCreationHelper::createEventWorkspace()));
 
     // LogName must not be empty
     TS_ASSERT_THROWS(alg.setProperty("LogName", ""), std::invalid_argument);
@@ -39,7 +39,7 @@ public:
 
   void test_validateInputs() {
     // Create and event workspace. We don't care what data is in it.
-    EventWorkspace_sptr ws = WorkspaceCreationHelper::CreateEventWorkspace();
+    EventWorkspace_sptr ws = WorkspaceCreationHelper::createEventWorkspace();
     // Add a single-number log
     ws->mutableRun().addProperty("SingleValue", 5);
     // Add a time-series property
@@ -145,7 +145,7 @@ private:
 
   EventWorkspace_sptr createWorkspace() {
     EventWorkspace_sptr ws =
-        WorkspaceCreationHelper::CreateEventWorkspace(3, 1);
+        WorkspaceCreationHelper::createEventWorkspace(3, 1);
     Run &run = ws->mutableRun();
 
     DateAndTime run_start("2010-01-01T00:00:00");
@@ -186,7 +186,7 @@ public:
   }
 
   SumEventsByLogValueTestPerformance() {
-    ws = WorkspaceCreationHelper::CreateEventWorkspace(100, 100, 1000);
+    ws = WorkspaceCreationHelper::createEventWorkspace(100, 100, 1000);
     // Add a bunch of logs
     std::vector<DateAndTime> times;
     std::vector<int> index;
diff --git a/Framework/Algorithms/test/SumRowColumnTest.h b/Framework/Algorithms/test/SumRowColumnTest.h
index 293087a08276ddeb091c20630b93a5602cb60ec2..a663a144df64dee5a5191f30c1c1a3b43ede908a 100644
--- a/Framework/Algorithms/test/SumRowColumnTest.h
+++ b/Framework/Algorithms/test/SumRowColumnTest.h
@@ -4,6 +4,7 @@
 #include <cxxtest/TestSuite.h>
 #include "MantidAlgorithms/SumRowColumn.h"
 #include "MantidAPI/Axis.h"
+#include "MantidKernel/Unit.h"
 #include "MantidTestHelpers/WorkspaceCreationHelper.h"
 
 using namespace Mantid::API;
@@ -16,7 +17,7 @@ public:
 
   SumRowColumnTest() : inputWS("SumRowColumnTestWS") {
     AnalysisDataService::Instance().add(
-        inputWS, WorkspaceCreationHelper::Create2DWorkspaceBinned(100, 10));
+        inputWS, WorkspaceCreationHelper::create2DWorkspaceBinned(100, 10));
   }
 
   ~SumRowColumnTest() override { AnalysisDataService::Instance().clear(); }
diff --git a/Framework/Algorithms/test/SumSpectraTest.h b/Framework/Algorithms/test/SumSpectraTest.h
index 17b4481d03557ccc7c4242ff41be4dfc33b06b93..528debc48b55b6e49d5ef4536b3f266c367823a2 100644
--- a/Framework/Algorithms/test/SumSpectraTest.h
+++ b/Framework/Algorithms/test/SumSpectraTest.h
@@ -3,12 +3,15 @@
 
 #include "MantidAlgorithms/SumSpectra.h"
 #include "MantidAPI/AnalysisDataService.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidDataObjects/Workspace2D.h"
 #include "MantidGeometry/Instrument/ParameterMap.h"
 #include "MantidTestHelpers/WorkspaceCreationHelper.h"
 #include <boost/lexical_cast.hpp>
 #include <cxxtest/TestSuite.h>
+#include <limits>
+#include <cmath>
 
 using namespace Mantid;
 using namespace Mantid::API;
@@ -24,8 +27,7 @@ public:
     this->inputSpace =
         WorkspaceCreationHelper::create2DWorkspaceWithFullInstrument(nTestHist,
                                                                      102, true);
-    this->inputSpace->instrumentParameters().addBool(
-        inputSpace->getDetector(1).get(), "masked", true);
+    inputSpace->mutableSpectrumInfo().setMasked(1, true);
 
     inputSpace->mutableE(5)[38] = 0.0;
   }
@@ -38,8 +40,10 @@ public:
   }
 
   void testExecWithLimits() {
-    if (!alg.isInitialized())
+    if (!alg.isInitialized()) {
       alg.initialize();
+      alg.setRethrows(true);
+    }
 
     // Set the properties
     TS_ASSERT_THROWS_NOTHING(alg.setProperty("InputWorkspace", inputSpace));
@@ -184,7 +188,7 @@ public:
     int numPixels = 100;
     int numBins = 20;
     int numEvents = 20;
-    EventWorkspace_sptr input = WorkspaceCreationHelper::CreateEventWorkspace(
+    EventWorkspace_sptr input = WorkspaceCreationHelper::createEventWorkspace(
         numPixels, numBins, numEvents);
     AnalysisDataService::Instance().addOrReplace(inName, input);
 
@@ -219,7 +223,7 @@ public:
   void testRebinnedOutputSum() {
     AnalysisDataService::Instance().clear();
     RebinnedOutput_sptr ws =
-        WorkspaceCreationHelper::CreateRebinnedOutputWorkspace();
+        WorkspaceCreationHelper::createRebinnedOutputWorkspace();
     std::string inName = "rebinTest";
     std::string outName = "rebin_sum";
 
@@ -235,6 +239,7 @@ public:
     alg3.setPropertyValue("InputWorkspace", inName);
     alg3.setPropertyValue("OutputWorkspace", outName);
     alg3.setProperty("IncludeMonitors", false);
+    alg3.setProperty("RemoveSpecialValues", true);
     alg3.execute();
     TS_ASSERT(alg3.isExecuted());
 
@@ -246,12 +251,12 @@ public:
     TS_ASSERT_EQUALS(output->getNumberHistograms(), 1);
     TS_ASSERT_EQUALS(output->blocksize(), 6);
     // Row with full acceptance
-    TS_ASSERT_EQUALS(output->mutableY(0)[1], 1.);
-    TS_ASSERT_DELTA(output->mutableE(0)[1], 0.40824829046386296, 1.e-5);
+    TS_ASSERT_EQUALS(output->y(0)[1], 1.);
+    TS_ASSERT_DELTA(output->e(0)[1], 0.40824829046386296, 1.e-5);
     TS_ASSERT_EQUALS(output->dataF(0)[1], 6.);
     // Row with limited, but non-zero acceptance, shouldn't have nans!
-    TS_ASSERT_DELTA(output->mutableY(0)[5], 0.66666, 1.e-5);
-    TS_ASSERT_DELTA(output->mutableE(0)[5], 0.47140452079103173, 1.e-5);
+    TS_ASSERT_DELTA(output->y(0)[5], 0.66666, 1.e-5);
+    TS_ASSERT_DELTA(output->e(0)[5], 0.47140452079103173, 1.e-5);
     TS_ASSERT_EQUALS(output->dataF(0)[5], 3.);
 
     TS_ASSERT(output->run().hasProperty("NumAllSpectra"))
@@ -345,7 +350,7 @@ public:
     int nHist = 4;
 
     MatrixWorkspace_sptr tws =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(nHist, nBins);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(nHist, nBins);
     std::string inName = "rebinTest";
     std::string outName = "sumWS";
 
@@ -422,6 +427,80 @@ public:
     AnalysisDataService::Instance().remove(outName);
   }
 
+  void testRemoveSpecialValuesOn() {
+    constexpr size_t numOfHistos = 2;
+    auto inWs =
+        WorkspaceCreationHelper::create2DWorkspace123(numOfHistos, 3, true);
+    auto &yVals = inWs->mutableY(1);
+
+    yVals[0] = std::numeric_limits<double>::infinity();
+    yVals[1] = NAN;
+
+    Mantid::Algorithms::SumSpectra sumSpectraAlg;
+    sumSpectraAlg.initialize();
+    sumSpectraAlg.setRethrows(true);
+
+    sumSpectraAlg.setProperty("InputWorkspace", inWs);
+    const std::string outWsName = "testSpecialVals";
+    sumSpectraAlg.setPropertyValue("OutputWorkspace", outWsName);
+    sumSpectraAlg.setProperty("RemoveSpecialValues", true);
+
+    TS_ASSERT_THROWS_NOTHING(sumSpectraAlg.execute());
+    TS_ASSERT(sumSpectraAlg.isExecuted());
+
+    Workspace_sptr output;
+    TS_ASSERT_THROWS_NOTHING(
+        output = AnalysisDataService::Instance().retrieve(outWsName));
+    Workspace2D_const_sptr output2D =
+        boost::dynamic_pointer_cast<const Workspace2D>(output);
+
+    auto outYVals = output2D->y(0);
+    // We expect one less because of inf and NaN
+    TS_ASSERT_EQUALS(outYVals[0], 2.);
+    TS_ASSERT_EQUALS(outYVals[1], 2.);
+    // Should get the correct amount now
+    TS_ASSERT_EQUALS(outYVals[2], 4.);
+
+    AnalysisDataService::Instance().remove(outWsName);
+  }
+
+  void testRemoveSpecialValuesOff() {
+    constexpr size_t numOfHistos = 2;
+    auto inWs =
+        WorkspaceCreationHelper::create2DWorkspace123(numOfHistos, 3, true);
+    auto &yVals = inWs->mutableY(1);
+
+    yVals[0] = std::numeric_limits<double>::infinity();
+    yVals[1] = NAN;
+
+    Mantid::Algorithms::SumSpectra sumSpectraAlg;
+    sumSpectraAlg.initialize();
+    sumSpectraAlg.setRethrows(true);
+
+    sumSpectraAlg.setProperty("InputWorkspace", inWs);
+    const std::string outWsName = "testSpecialVals";
+    sumSpectraAlg.setPropertyValue("OutputWorkspace", outWsName);
+    sumSpectraAlg.setProperty("RemoveSpecialValues", false);
+
+    TS_ASSERT_THROWS_NOTHING(sumSpectraAlg.execute());
+    TS_ASSERT(sumSpectraAlg.isExecuted());
+
+    Workspace_sptr output;
+    TS_ASSERT_THROWS_NOTHING(
+        output = AnalysisDataService::Instance().retrieve(outWsName));
+    Workspace2D_const_sptr output2D =
+        boost::dynamic_pointer_cast<const Workspace2D>(output);
+
+    auto outYVals = output2D->y(0);
+    // We expect a NaN and an Inf to propagate here
+    TS_ASSERT_EQUALS(std::isnormal(outYVals[0]), false);
+    TS_ASSERT_EQUALS(std::isnormal(outYVals[1]), false);
+    // Should get the correct amount now
+    TS_ASSERT_EQUALS(outYVals[2], 4.);
+
+    AnalysisDataService::Instance().remove(outWsName);
+  }
+
 private:
   int nTestHist;
   Mantid::Algorithms::SumSpectra alg; // Test with range limits
@@ -441,9 +520,9 @@ public:
   }
 
   SumSpectraTestPerformance() {
-    input = WorkspaceCreationHelper::Create2DWorkspaceBinned(40000, 10000);
+    input = WorkspaceCreationHelper::create2DWorkspaceBinned(40000, 10000);
     inputEvent =
-        WorkspaceCreationHelper::CreateEventWorkspace(20000, 1000, 2000);
+        WorkspaceCreationHelper::createEventWorkspace(20000, 1000, 2000);
   }
 
   void testExec2D() {
diff --git a/Framework/Algorithms/test/TOFSANSResolutionByPixelTest.h b/Framework/Algorithms/test/TOFSANSResolutionByPixelTest.h
index 272ad4e9c8cfe25cb067d28290c02ad4c3d6a9db..65a5fe6bb7c7f6cf1dc03fbabefa32782925cc4b 100644
--- a/Framework/Algorithms/test/TOFSANSResolutionByPixelTest.h
+++ b/Framework/Algorithms/test/TOFSANSResolutionByPixelTest.h
@@ -137,10 +137,10 @@ Mantid::API::MatrixWorkspace_sptr createTestWorkspace(
     std::vector<double> guideLogDetails = std::vector<double>()) {
   Mantid::API::MatrixWorkspace_sptr ws2d;
   if (isModerator) {
-    ws2d = WorkspaceCreationHelper::Create2DWorkspaceFromFunction(
+    ws2d = WorkspaceCreationHelper::create2DWorkspaceFromFunction(
         twos(), static_cast<int>(nhist), x0, x1, dx, true);
   } else {
-    ws2d = WorkspaceCreationHelper::Create2DWorkspaceFromFunction(
+    ws2d = WorkspaceCreationHelper::create2DWorkspaceFromFunction(
         ones(), static_cast<int>(nhist), x0, x1, dx, true);
   }
 
diff --git a/Framework/Algorithms/test/TimeAtSampleStrategyDirectTest.h b/Framework/Algorithms/test/TimeAtSampleStrategyDirectTest.h
index 48e76832755cf42a93e48e5a444793051e944734..c99a41e1302dfa2a8d9fec56273b0cce7bc4cd59 100644
--- a/Framework/Algorithms/test/TimeAtSampleStrategyDirectTest.h
+++ b/Framework/Algorithms/test/TimeAtSampleStrategyDirectTest.h
@@ -40,7 +40,6 @@ public:
 
     const size_t detectorIndex = 0; // detector workspace index.
     const double ei = 12;           // MeV
-    auto detector = ws->getDetector(detectorIndex);
 
     const double L1 = source->getPos().distance(sample->getPos());
 
diff --git a/Framework/Algorithms/test/TimeAtSampleStrategyElasticTest.h b/Framework/Algorithms/test/TimeAtSampleStrategyElasticTest.h
index 09ee280c9b4220aa66c68ec8a24fd4148d5fa8dd..cfb1f17f668a642e19e535f5302a96ee36d90771 100644
--- a/Framework/Algorithms/test/TimeAtSampleStrategyElasticTest.h
+++ b/Framework/Algorithms/test/TimeAtSampleStrategyElasticTest.h
@@ -12,6 +12,7 @@
 #include "MantidGeometry/Instrument/ReferenceFrame.h"
 #include "MantidKernel/V3D.h"
 #include "MantidAPI/MatrixWorkspace.h"
+#include "MantidAPI/SpectrumInfo.h"
 
 using namespace Mantid::Algorithms;
 using namespace Mantid::Geometry;
@@ -41,9 +42,9 @@ public:
     auto source = instrument->getSource();
 
     const size_t detectorIndex = 0; // detector workspace index.
-    auto detector = ws->getDetector(detectorIndex);
+    const auto &spectrumInfo = ws->spectrumInfo();
 
-    const double L1 = source->getPos().distance(sample->getPos());
+    const double L1 = spectrumInfo.l1();
 
     TimeAtSampleStrategyElastic strategy(ws);
     Correction correction = strategy.calculate(detectorIndex);
@@ -51,8 +52,7 @@ public:
     const double ratio = correction.factor;
 
     TSM_ASSERT_EQUALS("L1 / (L1 + L2)",
-                      L1 / (L1 + sample->getPos().distance(detector->getPos())),
-                      ratio);
+                      L1 / (L1 + spectrumInfo.l2(detectorIndex)), ratio);
   }
 
   void test_L2_monitor() {
diff --git a/Framework/Algorithms/test/TransposeTest.h b/Framework/Algorithms/test/TransposeTest.h
index a6a35a2fd7023d11bee54a4fc9ced90c71104a50..6ff040702992b08782a45521b77f2d549aed1693 100644
--- a/Framework/Algorithms/test/TransposeTest.h
+++ b/Framework/Algorithms/test/TransposeTest.h
@@ -101,7 +101,7 @@ public:
 
   void testRebinnedOutput() {
     RebinnedOutput_sptr inputWS =
-        WorkspaceCreationHelper::CreateRebinnedOutputWorkspace();
+        WorkspaceCreationHelper::createRebinnedOutputWorkspace();
     std::string inName = inputWS->getName();
     AnalysisDataService::Instance().addOrReplace(inName, inputWS);
     std::string outName = "rebinTrans";
@@ -169,7 +169,7 @@ public:
 
     // set up testRebinnedOutputPerformance
     RebinnedOutput_sptr inputWS =
-        WorkspaceCreationHelper::CreateRebinnedOutputWorkspace();
+        WorkspaceCreationHelper::createRebinnedOutputWorkspace();
     std::string inName = rebinned_inputWS;
     AnalysisDataService::Instance().addOrReplace(inName, inputWS);
   }
diff --git a/Framework/Algorithms/test/UnGroupWorkspaceTest.h b/Framework/Algorithms/test/UnGroupWorkspaceTest.h
index 601170796c3990c3f10b43a6ffdcd761e453c634..70a5ea9404c01f1d1bb99a5e6f909149074df88e 100644
--- a/Framework/Algorithms/test/UnGroupWorkspaceTest.h
+++ b/Framework/Algorithms/test/UnGroupWorkspaceTest.h
@@ -4,6 +4,7 @@
 #include <cxxtest/TestSuite.h>
 #include "MantidAlgorithms/UnGroupWorkspace.h"
 #include "MantidAPI/AnalysisDataService.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidTestHelpers/WorkspaceCreationHelper.h"
 
 class UnGroupWorkspaceTest : public CxxTest::TestSuite {
@@ -111,7 +112,7 @@ private:
   Mantid::API::MatrixWorkspace_sptr
   addTestMatrixWorkspaceToADS(const std::string &name) {
     auto &ads = Mantid::API::AnalysisDataService::Instance();
-    auto ws = WorkspaceCreationHelper::Create2DWorkspace(1, 1);
+    auto ws = WorkspaceCreationHelper::create2DWorkspace(1, 1);
     ads.add(name, ws);
     return ws;
   }
diff --git a/Framework/Algorithms/test/UnaryOperationTest.h b/Framework/Algorithms/test/UnaryOperationTest.h
index 2e0ec86d23ee01bb83b5d9e7de82858d44363bab..c76a88bc8ee9c6da7a1e547a50b4b96a5238fa49 100644
--- a/Framework/Algorithms/test/UnaryOperationTest.h
+++ b/Framework/Algorithms/test/UnaryOperationTest.h
@@ -65,7 +65,7 @@ public:
 
   void testExec() {
     MatrixWorkspace_sptr inputWS =
-        WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+        WorkspaceCreationHelper::create2DWorkspace(10, 10);
     AnalysisDataService::Instance().add("InputWS", inputWS);
 
     UnaryOpHelper helper3;
diff --git a/Framework/Algorithms/test/UnwrapMonitorTest.h b/Framework/Algorithms/test/UnwrapMonitorTest.h
new file mode 100644
index 0000000000000000000000000000000000000000..d36ec712420d96b1432b233188e71311f522685c
--- /dev/null
+++ b/Framework/Algorithms/test/UnwrapMonitorTest.h
@@ -0,0 +1,188 @@
+#ifndef MANTID_ALGORITHMS_UNWRAPMONITORTEST_H_
+#define MANTID_ALGORITHMS_UNWRAPMONITORTEST_H_
+
+#include <cxxtest/TestSuite.h>
+#include "MantidAPI/Axis.h"
+#include "MantidTestHelpers/WorkspaceCreationHelper.h"
+
+#include <string>
+
+#include "MantidAlgorithms/UnwrapMonitor.h"
+
+using namespace Mantid::Algorithms;
+using namespace Mantid::API;
+using namespace Mantid::DataObjects;
+using namespace Mantid::Kernel;
+
+class UnwrapMonitorTest : public CxxTest::TestSuite {
+public:
+  // This pair of boilerplate methods prevent the suite being created statically
+  // This means the constructor isn't called when running other tests
+  static UnwrapMonitorTest *createSuite() { return new UnwrapMonitorTest(); }
+  static void destroySuite(UnwrapMonitorTest *suite) { delete suite; }
+
+  void testLrefLessThanLd() {
+    // setup and run the algorithm (includes basic checks)
+    UnwrapMonitor algo;
+    const MatrixWorkspace_const_sptr inWS = setupAlgorithm(algo, 11.0);
+    const MatrixWorkspace_const_sptr outWS = runAlgorithm(algo, inWS);
+
+    // specific checks
+    const Mantid::MantidVec outX = outWS->readX(0);
+    TS_ASSERT_EQUALS(outX.size(), 23);
+    TS_ASSERT_DELTA(outX[0], 0.0, 1e-6);
+    TS_ASSERT_DELTA(outX[11], 0.008991, 1e-6);
+    TS_ASSERT_DELTA(outX[22], 0.017982, 1e-6);
+
+    const Mantid::MantidVec outY = outWS->readY(0);
+    TS_ASSERT_EQUALS(outY.size(), 22);
+    TS_ASSERT_DELTA(outY[3], 0.0, 1e-6);
+    TS_ASSERT_DELTA(outY[4], 2.991736, 1e-6);
+    TS_ASSERT_DELTA(outY[8], 6.198347, 1e-6);
+    TS_ASSERT_DELTA(outY[11], 3.818182, 1e-6);
+    TS_ASSERT_DELTA(outY[12], 0.0, 1e-6);
+
+    const double joinWavelength = algo.getProperty("JoinWavelength");
+    TS_ASSERT_DELTA(joinWavelength, 0.003692, 1e-6);
+  }
+
+  void testLrefGreaterThanLd() {
+    // setup and run the algorithm (includes basic checks)
+    UnwrapMonitor algo;
+    const MatrixWorkspace_const_sptr inWS = setupAlgorithm(algo, 17.0);
+    const MatrixWorkspace_const_sptr outWS = runAlgorithm(algo, inWS);
+
+    // specific checks
+    const Mantid::MantidVec outX = outWS->readX(0);
+    TS_ASSERT_EQUALS(outX.size(), 45);
+    TS_ASSERT_DELTA(outX[0], 0.0, 1e-6);
+    TS_ASSERT_DELTA(outX[22], 0.005818, 1e-6);
+    TS_ASSERT_DELTA(outX[44], 0.011635, 1e-6);
+
+    const Mantid::MantidVec outY = outWS->readY(0);
+    TS_ASSERT_EQUALS(outY.size(), 44);
+    TS_ASSERT_DELTA(outY[0], 2.005348, 1e-6);
+    TS_ASSERT_DELTA(outY[22], 2.005348, 1e-6);
+    TS_ASSERT_DELTA(outY[42], 2.005348, 1e-6);
+    TS_ASSERT_DELTA(outY[43], 1.770053, 1e-6);
+
+    const double joinWavelength = algo.getProperty("JoinWavelength");
+    TS_ASSERT_DELTA(joinWavelength, 0.001582, 1e-6);
+  }
+
+  void testLrefEqualsLd() {
+    // setup and run the algorithm (includes basic checks)
+    UnwrapMonitor algo;
+    const MatrixWorkspace_const_sptr inWS = setupAlgorithm(algo, 15.0);
+    const MatrixWorkspace_const_sptr outWS = runAlgorithm(algo, inWS);
+
+    // specific checks
+    const Mantid::MantidVec outX = outWS->readX(0);
+    TS_ASSERT_EQUALS(outX.size(), 50);
+    TS_ASSERT_DELTA(outX[0], 0.0, 1e-6);
+    TS_ASSERT_DELTA(outX[25], 0.006728, 1e-6);
+    TS_ASSERT_DELTA(outX[49], 0.013187, 1e-6);
+
+    const Mantid::MantidVec outY = outWS->readY(0);
+    TS_ASSERT_EQUALS(outY.size(), 49);
+    TS_ASSERT_DELTA(outY[0], 2.040816, 1e-6);
+    TS_ASSERT_DELTA(outY[25], 2.040816, 1e-6);
+    TS_ASSERT_DELTA(outY[47], 2.040816, 1e-6);
+    TS_ASSERT_DELTA(outY[48], 0.040816, 1e-6);
+
+    const double joinWavelength = algo.getProperty("JoinWavelength");
+    TS_ASSERT_DELTA(joinWavelength, 0.000264, 1e-6);
+  }
+
+  void testMinPossibleLref() {
+    // setup and run the algorithm (includes basic checks)
+    UnwrapMonitor algo;
+    const MatrixWorkspace_const_sptr inWS = setupAlgorithm(algo, 0.01);
+    const MatrixWorkspace_const_sptr outWS = runAlgorithm(algo, inWS);
+
+    // specific checks
+    const Mantid::MantidVec outX = outWS->readX(0);
+    TS_ASSERT_EQUALS(outX.size(), 51);
+    TS_ASSERT_DELTA(outX[0], 0.0, 1e-6);
+    TS_ASSERT_DELTA(outX[25], 9.890085, 1e-6);
+    TS_ASSERT_DELTA(outX[50], 19.780170, 1e-6);
+
+    const Mantid::MantidVec outY = outWS->readY(0);
+    TS_ASSERT_EQUALS(outY.size(), 50);
+    TS_ASSERT_DELTA(outY[0], 100.0, 1e-6);
+    TS_ASSERT_DELTA(outY[1], 0.0, 1e-6);
+    TS_ASSERT_DELTA(outY[25], 0.0, 1e-6);
+    TS_ASSERT_DELTA(outY[49], 0.0, 1e-6);
+
+    const double joinWavelength = algo.getProperty("JoinWavelength");
+    TS_ASSERT_DELTA(joinWavelength, 0.0, 1e-6);
+  }
+
+  void testLargeLref() {
+    // setup and run the algorithm (includes basic checks)
+    UnwrapMonitor algo;
+    const MatrixWorkspace_const_sptr inWS = setupAlgorithm(algo, 100.0);
+    const MatrixWorkspace_const_sptr outWS = runAlgorithm(algo, inWS);
+
+    // specific checks
+    const Mantid::MantidVec outX = outWS->readX(0);
+    TS_ASSERT_EQUALS(outX.size(), 11);
+    TS_ASSERT_DELTA(outX[0], 0.0, 1e-6);
+    TS_ASSERT_DELTA(outX[5], 0.000989, 1e-6);
+    TS_ASSERT_DELTA(outX[10], 0.001978, 1e-6);
+
+    const Mantid::MantidVec outY = outWS->readY(0);
+    TS_ASSERT_EQUALS(outY.size(), 10);
+    TS_ASSERT_DELTA(outY[0], 1.5, 1e-6);
+    TS_ASSERT_DELTA(outY[5], 1.5, 1e-6);
+    TS_ASSERT_DELTA(outY[9], 0.5, 1e-6);
+
+    const double joinWavelength = algo.getProperty("JoinWavelength");
+    TS_ASSERT_DELTA(joinWavelength, 0.0, 1e-6);
+  }
+
+private:
+  const MatrixWorkspace_sptr makeFakeWorkspace() {
+    const MatrixWorkspace_sptr testWS =
+        WorkspaceCreationHelper::create2DWorkspaceWithRectangularInstrument(
+            2, 3, 50);
+    testWS->getAxis(0)->setUnit("TOF");
+    return testWS;
+  }
+
+  // Initialise the algorithm and set the properties. Creates a fake workspace
+  // for the input and returns it.
+  MatrixWorkspace_const_sptr setupAlgorithm(UnwrapMonitor &algo,
+                                            const double lref) {
+    // create the workspace
+    const MatrixWorkspace_sptr inWS = makeFakeWorkspace();
+
+    // set up the algorithm
+    if (!algo.isInitialized())
+      algo.initialize();
+    algo.setChild(true);
+    algo.setProperty("InputWorkspace", inWS);
+    algo.setPropertyValue("OutputWorkspace", "outWS");
+    algo.setProperty("LRef", lref);
+
+    return inWS;
+  }
+
+  // Run the algorithm and do some basic checks. Returns the output workspace.
+  MatrixWorkspace_const_sptr
+  runAlgorithm(UnwrapMonitor &algo, const MatrixWorkspace_const_sptr inWS) {
+    // run the algorithm
+    TS_ASSERT(algo.execute());
+    TS_ASSERT(algo.isExecuted());
+
+    // verify the output workspace
+    const MatrixWorkspace_const_sptr outWS =
+        algo.getProperty("OutputWorkspace");
+    TS_ASSERT_EQUALS(inWS->getNumberHistograms(),
+                     outWS->getNumberHistograms()); // shouldn't drop histograms
+
+    return outWS;
+  }
+};
+
+#endif /* MANTID_ALGORITHMS_UNWRAPMONITORTEST_H_ */
diff --git a/Framework/Algorithms/test/UnwrapMonitorsInTOFTest.h b/Framework/Algorithms/test/UnwrapMonitorsInTOFTest.h
index f220595bc1b85e9236cf35e25927986fd4d128cd..fb58d1949fb3d9caa17365459e4debccea25467c 100644
--- a/Framework/Algorithms/test/UnwrapMonitorsInTOFTest.h
+++ b/Framework/Algorithms/test/UnwrapMonitorsInTOFTest.h
@@ -7,6 +7,7 @@
 #include "MantidTestHelpers/WorkspaceCreationHelper.h"
 #include "MantidGeometry/Instrument.h"
 #include "MantidAPI/AnalysisDataService.h"
+#include "MantidAPI/SpectrumInfo.h"
 
 using Mantid::Algorithms::UnwrapMonitorsInTOF;
 
@@ -232,9 +233,9 @@ private:
         intialWorkspace);
 
     // Set the monitor bins to the expected values
+    const auto &spectrumInfo = workspace->spectrumInfo();
     for (size_t index = 0; index < numberOfHistograms; ++index) {
-      auto detector = workspace->getDetector(index);
-      if (detector->isMonitor()) {
+      if (spectrumInfo.isMonitor(index)) {
         auto histogram = workspace->histogram(index);
         Mantid::HistogramData::Counts counts{2, 2, 2, 2, 2, 1, 1, 1, 1, 1};
         auto binEdges = histogram.binEdges();
diff --git a/Framework/Algorithms/test/UnwrapSNSTest.h b/Framework/Algorithms/test/UnwrapSNSTest.h
index 78f1661f1a8c5f74eab87d7f580431ad1f50debb..3c03b24c4d0ba2ccf1b4d2469da8ffe82c22da52 100644
--- a/Framework/Algorithms/test/UnwrapSNSTest.h
+++ b/Framework/Algorithms/test/UnwrapSNSTest.h
@@ -27,7 +27,7 @@ private:
 
   void makeFakeEventWorkspace(std::string wsName) {
     // Make an event workspace with 2 events in each bin.
-    EventWorkspace_sptr test_in = WorkspaceCreationHelper::CreateEventWorkspace(
+    EventWorkspace_sptr test_in = WorkspaceCreationHelper::createEventWorkspace(
         NUMPIXELS, NUMBINS, NUMBINS, 0.0, BIN_DELTA, 2);
     // Fake a d-spacing unit in the data.
     test_in->getAxis(0)->unit() = UnitFactory::Instance().create("TOF");
diff --git a/Framework/Algorithms/test/VesuvioL1ThetaResolutionTest.h b/Framework/Algorithms/test/VesuvioL1ThetaResolutionTest.h
index 73e411e2f247f4eeb31ce35bd62ab2c69cad0a59..eb5e081c2da3e59d1c27d4774025d8fa11bdf83b 100644
--- a/Framework/Algorithms/test/VesuvioL1ThetaResolutionTest.h
+++ b/Framework/Algorithms/test/VesuvioL1ThetaResolutionTest.h
@@ -5,6 +5,7 @@
 
 #include "MantidAlgorithms/VesuvioL1ThetaResolution.h"
 
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/NumericAxis.h"
 #include "MantidAPI/SpectraAxis.h"
diff --git a/Framework/Algorithms/test/WeightedMeanOfWorkspaceTest.h b/Framework/Algorithms/test/WeightedMeanOfWorkspaceTest.h
index f00686b59302d7fd0def80bb4388da07f4bbd8da..d5a20882197977c1939f10cbf3ef0c4c44e53010 100644
--- a/Framework/Algorithms/test/WeightedMeanOfWorkspaceTest.h
+++ b/Framework/Algorithms/test/WeightedMeanOfWorkspaceTest.h
@@ -116,11 +116,11 @@ private:
     if (doMasked) {
       masked.insert(0);
     }
-    return WorkspaceCreationHelper::Create2DWorkspace123(4, 3, true, masked);
+    return WorkspaceCreationHelper::create2DWorkspace123(4, 3, true, masked);
   }
 
   EventWorkspace_sptr createEventWorkspace() {
-    return WorkspaceCreationHelper::CreateEventWorkspace();
+    return WorkspaceCreationHelper::createEventWorkspace();
   }
 };
 
diff --git a/Framework/Algorithms/test/WeightedMeanTest.h b/Framework/Algorithms/test/WeightedMeanTest.h
index 76617fc580749934275e348efd49f5f7c1e16839..7c994c4b3ece5087dbc9ebfc4f96cf3a1339d384 100644
--- a/Framework/Algorithms/test/WeightedMeanTest.h
+++ b/Framework/Algorithms/test/WeightedMeanTest.h
@@ -2,6 +2,7 @@
 #define WEIGHTEDMEANTEST_H_
 
 #include <cxxtest/TestSuite.h>
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAlgorithms/WeightedMean.h"
 #include "MantidDataHandling/LoadRaw3.h"
 
diff --git a/Framework/Algorithms/test/WienerSmoothTest.h b/Framework/Algorithms/test/WienerSmoothTest.h
index a0816cee670e2cdc161d50c6b90913ac9bd797a0..87d856f4d7793bc2b20d656cb20c5da0b2f94e1b 100644
--- a/Framework/Algorithms/test/WienerSmoothTest.h
+++ b/Framework/Algorithms/test/WienerSmoothTest.h
@@ -4,6 +4,7 @@
 #include <cxxtest/TestSuite.h>
 
 #include "MantidAlgorithms/WienerSmooth.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/FrameworkManager.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/WorkspaceFactory.h"
diff --git a/Framework/Algorithms/test/WorkflowAlgorithmRunnerTest.h b/Framework/Algorithms/test/WorkflowAlgorithmRunnerTest.h
index d72182ee6dcac587a89c9a190baf868f4a9d7b5e..d349d0cf3beebcb27ebe526946b61d7bb837579b 100644
--- a/Framework/Algorithms/test/WorkflowAlgorithmRunnerTest.h
+++ b/Framework/Algorithms/test/WorkflowAlgorithmRunnerTest.h
@@ -6,6 +6,7 @@
 #include "MantidAlgorithms/WorkflowAlgorithmRunner.h"
 
 #include "MantidAlgorithms/DeleteWorkspace.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/ITableWorkspace.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/WorkspaceFactory.h"
diff --git a/Framework/Algorithms/test/WorkspaceGroupTest.h b/Framework/Algorithms/test/WorkspaceGroupTest.h
index 978c70964f0d1dd4a55fc696b71dd732345533d3..658b5a34ddc362b4df58e49ffb209b7fe7d451a6 100644
--- a/Framework/Algorithms/test/WorkspaceGroupTest.h
+++ b/Framework/Algorithms/test/WorkspaceGroupTest.h
@@ -91,13 +91,13 @@ public:
     int nHist = 20, nBins = 10;
     // Register the workspace in the data service
     MatrixWorkspace_sptr work_in1 =
-        WorkspaceCreationHelper::Create2DWorkspace123(nHist, nBins);
+        WorkspaceCreationHelper::create2DWorkspace123(nHist, nBins);
     MatrixWorkspace_sptr work_in2 =
-        WorkspaceCreationHelper::Create2DWorkspace154(nHist, nBins);
+        WorkspaceCreationHelper::create2DWorkspace154(nHist, nBins);
     MatrixWorkspace_sptr work_in3 =
-        WorkspaceCreationHelper::Create2DWorkspace123(nHist, nBins);
+        WorkspaceCreationHelper::create2DWorkspace123(nHist, nBins);
     MatrixWorkspace_sptr work_in4 =
-        WorkspaceCreationHelper::Create2DWorkspace154(nHist, nBins);
+        WorkspaceCreationHelper::create2DWorkspace154(nHist, nBins);
 
     WorkspaceGroup_sptr wsSptr = WorkspaceGroup_sptr(new WorkspaceGroup);
     if (wsSptr) {
@@ -177,12 +177,10 @@ public:
     int nHist = 20, nBins = 10;
     // Register the workspace in the data service
     Workspace2D_sptr work_in1 =
-        WorkspaceCreationHelper::Create2DWorkspace154(nHist, nBins, 1);
+        WorkspaceCreationHelper::create2DWorkspace154(nHist, nBins, 1);
     Workspace2D_sptr work_in2 =
-        WorkspaceCreationHelper::Create2DWorkspace154(nHist, nBins, 1);
+        WorkspaceCreationHelper::create2DWorkspace154(nHist, nBins, 1);
     Instrument_sptr instr(new Instrument);
-    work_in1->setInstrument(instr);
-    work_in2->setInstrument(instr);
 
     // set some dead detectors
     Counts yDead(nBins, 0);
@@ -198,6 +196,8 @@ public:
       instr->add(det);
       instr->markAsDetector(det);
     }
+    work_in1->setInstrument(instr);
+    work_in2->setInstrument(instr);
 
     for (int i = 0; i < nBins; i++) {
       if (i % 2 == 0) {
@@ -304,9 +304,9 @@ public:
     constexpr int nHist = 20, nBins = 10;
     // Register the workspace in the data service
     MatrixWorkspace_sptr work_in1 =
-        WorkspaceCreationHelper::Create2DWorkspace123(nHist, nBins);
+        WorkspaceCreationHelper::create2DWorkspace123(nHist, nBins);
     MatrixWorkspace_sptr work_in2 =
-        WorkspaceCreationHelper::Create2DWorkspace154(nHist, nBins);
+        WorkspaceCreationHelper::create2DWorkspace154(nHist, nBins);
 
     const std::string ws1Name = "test_ws1";
     const std::string ws2Name = "test_ws2";
@@ -344,11 +344,11 @@ public:
     constexpr int nHist = 20, nBins = 10;
     // Register the workspace in the data service
     MatrixWorkspace_sptr work_in1 =
-        WorkspaceCreationHelper::Create2DWorkspace123(nHist, nBins);
+        WorkspaceCreationHelper::create2DWorkspace123(nHist, nBins);
     MatrixWorkspace_sptr work_in2 =
-        WorkspaceCreationHelper::Create2DWorkspace154(nHist, nBins);
+        WorkspaceCreationHelper::create2DWorkspace154(nHist, nBins);
     MatrixWorkspace_sptr work_in3 =
-        WorkspaceCreationHelper::Create2DWorkspace154(nHist, nBins);
+        WorkspaceCreationHelper::create2DWorkspace154(nHist, nBins);
 
     const std::string ws1Name = "test_ws1";
     const std::string ws2Name = "test_ws2";
@@ -388,11 +388,11 @@ public:
     constexpr int nHist = 20, nBins = 10;
     // Register the workspace in the data service
     MatrixWorkspace_sptr inGroupWs1 =
-        WorkspaceCreationHelper::Create2DWorkspace123(nHist, nBins);
+        WorkspaceCreationHelper::create2DWorkspace123(nHist, nBins);
     MatrixWorkspace_sptr inGroupWs2 =
-        WorkspaceCreationHelper::Create2DWorkspace123(nHist, nBins);
+        WorkspaceCreationHelper::create2DWorkspace123(nHist, nBins);
     MatrixWorkspace_sptr notInGroupWs =
-        WorkspaceCreationHelper::Create2DWorkspace154(nHist, nBins);
+        WorkspaceCreationHelper::create2DWorkspace154(nHist, nBins);
 
     const std::string inGroupWsName1 = "test_ws1";
     const std::string inGroupWsName2 = "test_ws2";
@@ -436,22 +436,22 @@ public:
     int nHist = 10, nBins = 20;
     // Register the workspace in the data service
     MatrixWorkspace_sptr worklhs_in1 =
-        WorkspaceCreationHelper::Create2DWorkspace123(nHist, nBins);
+        WorkspaceCreationHelper::create2DWorkspace123(nHist, nBins);
     MatrixWorkspace_sptr worklhs_in2 =
-        WorkspaceCreationHelper::Create2DWorkspace154(nHist, nBins);
+        WorkspaceCreationHelper::create2DWorkspace154(nHist, nBins);
     MatrixWorkspace_sptr worklhs_in3 =
-        WorkspaceCreationHelper::Create2DWorkspace123(nHist, nBins);
+        WorkspaceCreationHelper::create2DWorkspace123(nHist, nBins);
     MatrixWorkspace_sptr worklhs_in4 =
-        WorkspaceCreationHelper::Create2DWorkspace154(nHist, nBins);
+        WorkspaceCreationHelper::create2DWorkspace154(nHist, nBins);
 
     MatrixWorkspace_sptr workrhs_in1 =
-        WorkspaceCreationHelper::Create2DWorkspace123(nHist, nBins);
+        WorkspaceCreationHelper::create2DWorkspace123(nHist, nBins);
     MatrixWorkspace_sptr workrhs_in2 =
-        WorkspaceCreationHelper::Create2DWorkspace154(nHist, nBins);
+        WorkspaceCreationHelper::create2DWorkspace154(nHist, nBins);
     MatrixWorkspace_sptr workrhs_in3 =
-        WorkspaceCreationHelper::Create2DWorkspace123(nHist, nBins);
+        WorkspaceCreationHelper::create2DWorkspace123(nHist, nBins);
     MatrixWorkspace_sptr workrhs_in4 =
-        WorkspaceCreationHelper::Create2DWorkspace154(nHist, nBins);
+        WorkspaceCreationHelper::create2DWorkspace154(nHist, nBins);
 
     WorkspaceGroup_sptr wsSptr = WorkspaceGroup_sptr(new WorkspaceGroup);
     if (wsSptr) {
@@ -562,18 +562,18 @@ public:
     int nHist = 10, nBins = 20;
 
     MatrixWorkspace_sptr worklhs_in1 =
-        WorkspaceCreationHelper::Create2DWorkspace123(nHist, nBins);
+        WorkspaceCreationHelper::create2DWorkspace123(nHist, nBins);
     if (worklhs_in1)
       AnalysisDataService::Instance().add("testlhs_in1", worklhs_in1);
 
     MatrixWorkspace_sptr workrhs_in1 =
-        WorkspaceCreationHelper::Create2DWorkspace123(nHist, nBins);
+        WorkspaceCreationHelper::create2DWorkspace123(nHist, nBins);
     MatrixWorkspace_sptr workrhs_in2 =
-        WorkspaceCreationHelper::Create2DWorkspace154(nHist, nBins);
+        WorkspaceCreationHelper::create2DWorkspace154(nHist, nBins);
     MatrixWorkspace_sptr workrhs_in3 =
-        WorkspaceCreationHelper::Create2DWorkspace123(nHist, nBins);
+        WorkspaceCreationHelper::create2DWorkspace123(nHist, nBins);
     MatrixWorkspace_sptr workrhs_in4 =
-        WorkspaceCreationHelper::Create2DWorkspace154(nHist, nBins);
+        WorkspaceCreationHelper::create2DWorkspace154(nHist, nBins);
 
     WorkspaceGroup_sptr wsSptr1 = WorkspaceGroup_sptr(new WorkspaceGroup);
     if (wsSptr1) {
@@ -658,13 +658,13 @@ public:
     int nHist = 10, nBins = 20;
     // Register the workspace in the data service
     MatrixWorkspace_sptr worklhs_in1 =
-        WorkspaceCreationHelper::Create2DWorkspace123(nHist, nBins);
+        WorkspaceCreationHelper::create2DWorkspace123(nHist, nBins);
     MatrixWorkspace_sptr worklhs_in2 =
-        WorkspaceCreationHelper::Create2DWorkspace154(nHist, nBins);
+        WorkspaceCreationHelper::create2DWorkspace154(nHist, nBins);
     MatrixWorkspace_sptr worklhs_in3 =
-        WorkspaceCreationHelper::Create2DWorkspace123(nHist, nBins);
+        WorkspaceCreationHelper::create2DWorkspace123(nHist, nBins);
     MatrixWorkspace_sptr worklhs_in4 =
-        WorkspaceCreationHelper::Create2DWorkspace154(nHist, nBins);
+        WorkspaceCreationHelper::create2DWorkspace154(nHist, nBins);
 
     WorkspaceGroup_sptr wsSptr = WorkspaceGroup_sptr(new WorkspaceGroup);
     if (wsSptr) {
diff --git a/Framework/Beamline/CMakeLists.txt b/Framework/Beamline/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..7b30b183d5d4d9a6174857f762bf1a90cc41f6f3
--- /dev/null
+++ b/Framework/Beamline/CMakeLists.txt
@@ -0,0 +1,47 @@
+set ( SRC_FILES
+	src/DetectorInfo.cpp
+)
+
+set ( INC_FILES
+	inc/MantidBeamline/DetectorInfo.h
+)
+
+set ( TEST_FILES
+	DetectorInfoTest.h
+)
+
+if (COVERALLS)
+  foreach( loop_var ${SRC_FILES} ${INC_FILES})
+    set_property(GLOBAL APPEND PROPERTY COVERAGE_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/${loop_var}")
+  endforeach(loop_var)
+endif()
+
+if(UNITY_BUILD)
+  include(UnityBuild)
+  enable_unity_build(Beamline SRC_FILES SRC_UNITY_IGNORE_FILES 10)
+endif(UNITY_BUILD)
+
+# Add the target for this directory
+add_library ( Beamline ${SRC_FILES} ${INC_FILES} )
+# Set the name of the generated library
+set_target_properties ( Beamline PROPERTIES OUTPUT_NAME MantidBeamline
+  COMPILE_DEFINITIONS IN_MANTID_BEAMLINE )
+
+if (OSX_VERSION VERSION_GREATER 10.8)
+  set_target_properties ( Beamline PROPERTIES INSTALL_RPATH "@loader_path/../MacOS")
+endif ()
+
+# Add to the 'Framework' group in VS
+set_property ( TARGET Beamline PROPERTY FOLDER "MantidFramework" )
+
+target_link_libraries ( Beamline LINK_PRIVATE ${TCMALLOC_LIBRARIES_LINKTIME} 
+                        ${GSL_LIBRARIES} ${MANTIDLIBS} )
+
+# Add the unit tests directory
+add_subdirectory ( test )
+
+###########################################################################
+# Installation settings
+###########################################################################
+
+install ( TARGETS Beamline ${SYSTEM_PACKAGE_TARGET} DESTINATION ${LIB_DIR} )
diff --git a/Framework/Beamline/inc/MantidBeamline/DetectorInfo.h b/Framework/Beamline/inc/MantidBeamline/DetectorInfo.h
new file mode 100644
index 0000000000000000000000000000000000000000..dbc4335708f675f73424a29d71a4d3c5676c25b0
--- /dev/null
+++ b/Framework/Beamline/inc/MantidBeamline/DetectorInfo.h
@@ -0,0 +1,77 @@
+#ifndef MANTID_BEAMLINE_DETECTORINFO_H_
+#define MANTID_BEAMLINE_DETECTORINFO_H_
+
+#include "MantidBeamline/DllConfig.h"
+#include "MantidKernel/cow_ptr.h"
+
+namespace Mantid {
+namespace Beamline {
+
+/** Beamline::DetectorInfo provides easy access to commonly used parameters of
+  individual detectors (pixels) in a beamline, such as mask and monitor flags,
+  positions, L2, and 2-theta.
+
+  Currently only a limited subset of functionality is implemented in
+  Beamline::DetectorInfo. The remainder is available in API::DetectorInfo which
+  acts as a wrapper around the old instrument implementation. API::DetectorInfo
+  will be removed once all functionality has been moved to
+  Beamline::DetectorInfo. For the time being, API::DetectorInfo will forward
+  calls to Beamline::DetectorInfo when applicable.
+
+  The reason for having both DetectorInfo classes in parallel is:
+  - We need to be able to move around the DetectorInfo object including data it
+    contains such as a vector of mask flags. This is relevant for the interface
+    of ExperimentInfo, when replacing the ParameterMap or when setting a new
+    instrument.
+  - API::DetectorInfo contains a caching mechanism and is frequently flushed
+    upon modification of the instrument and is thus hard to handle outside the
+    context of its owning workspace.
+  Splitting DetectorInfo into two classes seemed to be the safest and easiest
+  solution to this.
+
+
+  @author Simon Heybrock
+  @date 2016
+
+  Copyright &copy; 2016 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>
+*/
+class MANTID_BEAMLINE_DLL DetectorInfo {
+public:
+  DetectorInfo(const size_t numberOfDetectors);
+  DetectorInfo(const size_t numberOfDetectors,
+               const std::vector<size_t> &monitorIndices);
+
+  size_t size() const;
+
+  bool isMonitor(const size_t index) const;
+  bool isMasked(const size_t index) const;
+  void setMasked(const size_t index, bool masked);
+
+private:
+  Kernel::cow_ptr<std::vector<bool>> m_isMonitor;
+  Kernel::cow_ptr<std::vector<bool>> m_isMasked;
+};
+
+} // namespace Beamline
+} // namespace Mantid
+
+#endif /* MANTID_BEAMLINE_DETECTORINFO_H_ */
diff --git a/Framework/Beamline/inc/MantidBeamline/DllConfig.h b/Framework/Beamline/inc/MantidBeamline/DllConfig.h
new file mode 100644
index 0000000000000000000000000000000000000000..2fa2c3a5b80990c1cd1bc8f13dcae29e53a9cb77
--- /dev/null
+++ b/Framework/Beamline/inc/MantidBeamline/DllConfig.h
@@ -0,0 +1,37 @@
+#ifndef MANTID_BEAMLINE_DLLCONFIG_H_
+#define MANTID_BEAMLINE_DLLCONFIG_H_
+
+/*
+  This file contains the DLLExport/DLLImport linkage configuration for the
+  Beamline library
+
+  Copyright &copy; 2016 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 "MantidKernel/System.h"
+
+#ifdef IN_MANTID_BEAMLINE
+#define MANTID_BEAMLINE_DLL DLLExport
+#else
+#define MANTID_BEAMLINE_DLL DLLImport
+#endif // IN_MANTID_BEAMLINE
+
+#endif // MANTID_BEAMLINE_DLLCONFIG_H_
diff --git a/Framework/Beamline/src/DetectorInfo.cpp b/Framework/Beamline/src/DetectorInfo.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3b2096c8707f1231b41cecd721b73f1311d0cee7
--- /dev/null
+++ b/Framework/Beamline/src/DetectorInfo.cpp
@@ -0,0 +1,42 @@
+#include "MantidBeamline/DetectorInfo.h"
+#include "MantidKernel/make_cow.h"
+
+namespace Mantid {
+namespace Beamline {
+
+DetectorInfo::DetectorInfo(const size_t numberOfDetectors)
+    : m_isMonitor(Kernel::make_cow<std::vector<bool>>(numberOfDetectors)),
+      m_isMasked(Kernel::make_cow<std::vector<bool>>(numberOfDetectors)) {}
+
+DetectorInfo::DetectorInfo(const size_t numberOfDetectors,
+                           const std::vector<size_t> &monitorIndices)
+    : DetectorInfo(numberOfDetectors) {
+  for (const auto i : monitorIndices)
+    m_isMonitor.access().at(i) = true;
+}
+
+/// Returns the size of the DetectorInfo, i.e., the number of detectors in the
+/// instrument.
+size_t DetectorInfo::size() const {
+  if (!m_isMasked)
+    return 0;
+  return m_isMasked->size();
+}
+
+/// Returns true if the detector is a monitor.
+bool DetectorInfo::isMonitor(const size_t index) const {
+  return (*m_isMonitor)[index];
+}
+
+/// Returns true if the detector is masked.
+bool DetectorInfo::isMasked(const size_t index) const {
+  return (*m_isMasked)[index];
+}
+
+/// Set the mask flag of the detector with given index. Not thread safe.
+void DetectorInfo::setMasked(const size_t index, bool masked) {
+  m_isMasked.access()[index] = masked;
+}
+
+} // namespace Beamline
+} // namespace Mantid
diff --git a/Framework/Beamline/test/CMakeLists.txt b/Framework/Beamline/test/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..522c138e12a98d2bbe0d4045e80c8d2454d84ab1
--- /dev/null
+++ b/Framework/Beamline/test/CMakeLists.txt
@@ -0,0 +1,13 @@
+if ( CXXTEST_FOUND )
+  include_directories ( SYSTEM ${CXXTEST_INCLUDE_DIR} ${GMOCK_INCLUDE_DIR} ${GTEST_INCLUDE_DIR} ../../TestHelpers/inc)
+
+  cxxtest_add_test ( BeamlineTest ${TEST_FILES} ${GMOCK_TEST_FILES})
+  target_link_libraries( BeamlineTest LINK_PRIVATE ${TCMALLOC_LIBRARIES_LINKTIME}
+    Beamline
+    ${Boost_LIBRARIES}
+    ${GTEST_LIBRARIES} )
+  
+  add_dependencies ( FrameworkTests BeamlineTest )
+  # Add to the 'FrameworkTests' group in VS
+  set_property ( TARGET BeamlineTest PROPERTY FOLDER "UnitTests" )
+endif ()
diff --git a/Framework/Beamline/test/DetectorInfoTest.h b/Framework/Beamline/test/DetectorInfoTest.h
new file mode 100644
index 0000000000000000000000000000000000000000..1e6c99390c56b6468c1cd42868fb18e5f8f7cd03
--- /dev/null
+++ b/Framework/Beamline/test/DetectorInfoTest.h
@@ -0,0 +1,116 @@
+#ifndef MANTID_BEAMLINE_DETECTORINFOTEST_H_
+#define MANTID_BEAMLINE_DETECTORINFOTEST_H_
+
+#include <cxxtest/TestSuite.h>
+
+#include "MantidBeamline/DetectorInfo.h"
+#include "MantidKernel/make_unique.h"
+
+using namespace Mantid;
+using Beamline::DetectorInfo;
+
+class DetectorInfoTest : public CxxTest::TestSuite {
+public:
+  // This pair of boilerplate methods prevent the suite being created statically
+  // This means the constructor isn't called when running other tests
+  static DetectorInfoTest *createSuite() { return new DetectorInfoTest(); }
+  static void destroySuite(DetectorInfoTest *suite) { delete suite; }
+
+  void test_constructor() {
+    std::unique_ptr<DetectorInfo> detInfo;
+    TS_ASSERT_THROWS_NOTHING(detInfo = Kernel::make_unique<DetectorInfo>(0));
+    TS_ASSERT_EQUALS(detInfo->size(), 0);
+    TS_ASSERT_THROWS_NOTHING(detInfo = Kernel::make_unique<DetectorInfo>(1));
+    TS_ASSERT_EQUALS(detInfo->size(), 1);
+  }
+
+  void test_constructor_with_monitors() {
+    std::unique_ptr<DetectorInfo> info;
+    std::vector<size_t> mons{0, 2};
+    TS_ASSERT_THROWS_NOTHING(info = Kernel::make_unique<DetectorInfo>(3, mons));
+    TS_ASSERT_EQUALS(info->size(), 3);
+    TS_ASSERT_THROWS_NOTHING(DetectorInfo(3, {}));
+    TS_ASSERT_THROWS_NOTHING(DetectorInfo(3, {0}));
+    TS_ASSERT_THROWS_NOTHING(DetectorInfo(3, {0, 1, 2}));
+    TS_ASSERT_THROWS_NOTHING(DetectorInfo(3, {0, 0, 0}));
+    TS_ASSERT_THROWS(DetectorInfo(3, {3}), std::out_of_range);
+  }
+
+  void test_copy() {
+    const DetectorInfo source(7);
+    const auto copy(source);
+    TS_ASSERT_EQUALS(copy.size(), 7);
+  }
+
+  void test_move() {
+    DetectorInfo source(7);
+    const auto moved(std::move(source));
+    TS_ASSERT_EQUALS(moved.size(), 7);
+    TS_ASSERT_EQUALS(source.size(), 0);
+  }
+
+  void test_assign() {
+    const DetectorInfo source(7);
+    DetectorInfo assignee(1);
+    assignee = source;
+    TS_ASSERT_EQUALS(assignee.size(), 7);
+  }
+
+  void test_move_assign() {
+    DetectorInfo source(7);
+    DetectorInfo assignee(1);
+    assignee = std::move(source);
+    TS_ASSERT_EQUALS(assignee.size(), 7);
+    TS_ASSERT_EQUALS(source.size(), 0);
+  }
+
+  void test_no_monitors() {
+    DetectorInfo info(3);
+    TS_ASSERT(!info.isMonitor(0));
+    TS_ASSERT(!info.isMonitor(1));
+    TS_ASSERT(!info.isMonitor(2));
+  }
+
+  void test_monitors() {
+    std::vector<size_t> monitors{0, 2};
+    DetectorInfo info(3, monitors);
+    TS_ASSERT(info.isMonitor(0));
+    TS_ASSERT(!info.isMonitor(1));
+    TS_ASSERT(info.isMonitor(2));
+  }
+
+  void test_duplicate_monitors_ignored() {
+    std::vector<size_t> monitors{0, 0, 2, 2};
+    DetectorInfo info(3, monitors);
+    TS_ASSERT(info.isMonitor(0));
+    TS_ASSERT(!info.isMonitor(1));
+    TS_ASSERT(info.isMonitor(2));
+  }
+
+  void test_masking() {
+    DetectorInfo info(3);
+    TS_ASSERT(!info.isMasked(0));
+    TS_ASSERT(!info.isMasked(1));
+    TS_ASSERT(!info.isMasked(2));
+    info.setMasked(1, true);
+    TS_ASSERT(!info.isMasked(0));
+    TS_ASSERT(info.isMasked(1));
+    TS_ASSERT(!info.isMasked(2));
+    info.setMasked(1, false);
+    TS_ASSERT(!info.isMasked(0));
+    TS_ASSERT(!info.isMasked(1));
+    TS_ASSERT(!info.isMasked(2));
+  }
+
+  void test_masking_copy() {
+    DetectorInfo source(1);
+    source.setMasked(0, true);
+    DetectorInfo copy(source);
+    TS_ASSERT(copy.isMasked(0));
+    source.setMasked(0, false);
+    TS_ASSERT(!source.isMasked(0));
+    TS_ASSERT(copy.isMasked(0));
+  }
+};
+
+#endif /* MANTID_BEAMLINE_DETECTORINFOTEST_H_ */
diff --git a/Framework/CMakeLists.txt b/Framework/CMakeLists.txt
index 7b4aa84f22449c5e297015f991984fbbcf2f888c..e2a5e03d7a852c1b4b6b97dfe1a5b7629c8019ff 100644
--- a/Framework/CMakeLists.txt
+++ b/Framework/CMakeLists.txt
@@ -70,9 +70,18 @@ add_subdirectory (Kernel)
 include_directories (HistogramData/inc)
 add_subdirectory (HistogramData)
 
+include_directories (Indexing/inc)
+add_subdirectory (Indexing)
+
+include_directories (Beamline/inc)
+add_subdirectory (Beamline)
+
 # HistogramData has header-only dependency on Kernel, so Kernel comes after.
 set ( MANTIDLIBS ${MANTIDLIBS} HistogramData )
+# Indexing has header-only dependency on Kernel, so Kernel comes after.
+set ( MANTIDLIBS ${MANTIDLIBS} Indexing )
 set ( MANTIDLIBS ${MANTIDLIBS} Kernel )
+set ( MANTIDLIBS ${MANTIDLIBS} Beamline )
 
 include_directories (Geometry/inc)
 # muParser needed by Geometry and subsequent packages
@@ -134,7 +143,7 @@ add_subdirectory (ScriptRepository)
 # Add a custom target to build all of the Framework
 ###########################################################################
 
-set ( FRAMEWORK_LIBS Kernel HistogramData Geometry API DataObjects
+set ( FRAMEWORK_LIBS Kernel HistogramData Indexing Beamline Geometry API DataObjects
                      PythonKernelModule PythonGeometryModule PythonAPIModule
                      PythonDataObjectsModule
                      DataHandling Nexus Algorithms CurveFitting ICat
diff --git a/Framework/Crystal/inc/MantidCrystal/FindUBUsingLatticeParameters.h b/Framework/Crystal/inc/MantidCrystal/FindUBUsingLatticeParameters.h
index ae0a6de8e88df35bf913096fa01f221dcf2f8893..dc8eebab33015d1b5cf2c85e76db846ea74efa4d 100644
--- a/Framework/Crystal/inc/MantidCrystal/FindUBUsingLatticeParameters.h
+++ b/Framework/Crystal/inc/MantidCrystal/FindUBUsingLatticeParameters.h
@@ -1,8 +1,8 @@
 #ifndef MANTID_CRYSTAL_FIND_UB_USING_LATTICE_PARAMETERS_H_
 #define MANTID_CRYSTAL_FIND_UB_USING_LATTICE_PARAMETERS_H_
 
-#include "MantidKernel/System.h"
 #include "MantidAPI/Algorithm.h"
+#include "MantidKernel/System.h"
 
 namespace Mantid {
 namespace Crystal {
diff --git a/Framework/Crystal/inc/MantidCrystal/IndexSXPeaks.h b/Framework/Crystal/inc/MantidCrystal/IndexSXPeaks.h
index 9611706f997481becb78fb207517bbe128f7468c..bb7a92f68c9de6772634f8ec7a904cd75f01817a 100644
--- a/Framework/Crystal/inc/MantidCrystal/IndexSXPeaks.h
+++ b/Framework/Crystal/inc/MantidCrystal/IndexSXPeaks.h
@@ -1,14 +1,13 @@
 #ifndef MANTID_CRYSTAL_INDEX_SX_PEAKS_H_
 #define MANTID_CRYSTAL_INDEX_SX_PEAKS_H_
 
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidAPI/Algorithm.h"
 #include <boost/tuple/tuple.hpp>
 #include "MantidAPI/IPeaksWorkspace_fwd.h"
 #include "MantidGeometry/Crystal/UnitCell.h"
 #include "MantidKernel/V3D.h"
+
+#include <iterator>
 #include <set>
 
 namespace Mantid {
diff --git a/Framework/Crystal/inc/MantidCrystal/LoadIsawPeaks.h b/Framework/Crystal/inc/MantidCrystal/LoadIsawPeaks.h
index a20c141abfb32bf64436a78348b8473c0871b568..6bd149be3fca963d7651737212058c7d87a113e9 100644
--- a/Framework/Crystal/inc/MantidCrystal/LoadIsawPeaks.h
+++ b/Framework/Crystal/inc/MantidCrystal/LoadIsawPeaks.h
@@ -46,7 +46,6 @@ private:
 
   /// Reads calibration/detector section and returns first word of next line
   std::string ApplyCalibInfo(std::ifstream &in, std::string startChar,
-                             Geometry::Instrument_const_sptr instr_old,
                              Geometry::Instrument_const_sptr instr, double &T0);
 
   /// Reads first line of peaks file and returns first word of next line
diff --git a/Framework/Crystal/inc/MantidCrystal/PeakHKLErrors.h b/Framework/Crystal/inc/MantidCrystal/PeakHKLErrors.h
index c9d3a65b398adba66ce701aeee1d0b959a9bd52d..7f3ab7aeb958a6066c0ce66c776c767cee30f7b1 100644
--- a/Framework/Crystal/inc/MantidCrystal/PeakHKLErrors.h
+++ b/Framework/Crystal/inc/MantidCrystal/PeakHKLErrors.h
@@ -124,7 +124,7 @@ public:
     if (attName == "OptRuns") {
       OptRuns = value.asString();
 
-      if (OptRuns.size() < 1)
+      if (OptRuns.empty())
         return;
 
       if (OptRuns.at(0) != '/')
diff --git a/Framework/Crystal/src/AnvredCorrection.cpp b/Framework/Crystal/src/AnvredCorrection.cpp
index 48516938fb85b747bb99fefd5f5c1413c7281c6f..a51b6e243d22b6b8d0ad4cc59a22d1b8f9315ba1 100644
--- a/Framework/Crystal/src/AnvredCorrection.cpp
+++ b/Framework/Crystal/src/AnvredCorrection.cpp
@@ -7,10 +7,12 @@
 #include "MantidGeometry/Objects/ShapeFactory.h"
 #include "MantidKernel/BoundedValidator.h"
 #include "MantidKernel/Material.h"
+#include "MantidKernel/Unit.h"
 #include "MantidKernel/UnitFactory.h"
 #include "MantidKernel/Fast_Exponential.h"
 #include "MantidKernel/VectorHelper.h"
 #include "MantidGeometry/Instrument.h"
+#include "MantidDataObjects/WorkspaceCreation.h"
 
 /*  Following A.J.Schultz's anvred, the weight factors should be:
  *
@@ -263,17 +265,9 @@ void AnvredCorrection::execEvent() {
 
   const int64_t numHists =
       static_cast<int64_t>(m_inputWS->getNumberHistograms());
-
-  const std::string unitStr = m_inputWS->getAxis(0)->unit()->unitID();
-  // Create a new outputworkspace with not much in it
-  auto correctionFactors = boost::dynamic_pointer_cast<EventWorkspace>(
-      API::WorkspaceFactory::Instance().create("EventWorkspace", numHists, 2,
-                                               1));
-
+  std::string unitStr = m_inputWS->getAxis(0)->unit()->unitID();
+  auto correctionFactors = create<EventWorkspace>(*m_inputWS);
   correctionFactors->sortAll(TOF_SORT, nullptr);
-  // Copy required stuff from it
-  API::WorkspaceFactory::Instance().initializeFromParent(
-      m_inputWS, correctionFactors, true);
   bool inPlace = (this->getPropertyValue("InputWorkspace") ==
                   this->getPropertyValue("OutputWorkspace"));
   if (inPlace)
@@ -351,8 +345,6 @@ void AnvredCorrection::execEvent() {
 
     correctionFactors->getSpectrum(i) += events;
 
-    auto &dets = eventW->getSpectrum(i).getDetectorIDs();
-    correctionFactors->getSpectrum(i).addDetectorIDs(dets);
     // When focussing in place, you can clear out old memory from the input one!
     if (inPlace) {
       eventW->getSpectrum(i).clear();
@@ -369,8 +361,7 @@ void AnvredCorrection::execEvent() {
   run.addProperty<double>("Radius", m_radius, true);
   if (!m_onlySphericalAbsorption && !m_returnTransmissionOnly)
     run.addProperty<bool>("LorentzCorrection", 1, true);
-  setProperty("OutputWorkspace",
-              boost::dynamic_pointer_cast<MatrixWorkspace>(correctionFactors));
+  setProperty("OutputWorkspace", std::move(correctionFactors));
 
   // Now do some cleaning-up since destructor may not be called immediately
   this->cleanup();
diff --git a/Framework/Crystal/src/CalculatePeaksHKL.cpp b/Framework/Crystal/src/CalculatePeaksHKL.cpp
index f59327ce146338b764ef8d1550843fd781148c1b..7f5b556a522ec6bda12211082153f4b5c1256f0a 100644
--- a/Framework/Crystal/src/CalculatePeaksHKL.cpp
+++ b/Framework/Crystal/src/CalculatePeaksHKL.cpp
@@ -52,7 +52,7 @@ void CalculatePeaksHKL::exec() {
   const int n_peaks = ws->getNumberPeaks();
 
   OrientedLattice o_lattice = ws->mutableSample().getOrientedLattice();
-  Matrix<double> UB = o_lattice.getUB();
+  const Matrix<double> &UB = o_lattice.getUB();
 
   DblMatrix UB_inverse(UB);
 
diff --git a/Framework/Crystal/src/CentroidPeaks.cpp b/Framework/Crystal/src/CentroidPeaks.cpp
index cc719aa2e16f677f56bc5b3a92bd3a66ee2c763e..888876a15be223593d34f67be51e0b9a1960b22b 100644
--- a/Framework/Crystal/src/CentroidPeaks.cpp
+++ b/Framework/Crystal/src/CentroidPeaks.cpp
@@ -1,6 +1,7 @@
 #include "MantidDataObjects/PeaksWorkspace.h"
 #include "MantidCrystal/CentroidPeaks.h"
 #include "MantidGeometry/Instrument/RectangularDetector.h"
+#include "MantidKernel/Unit.h"
 #include "MantidKernel/VectorHelper.h"
 #include "MantidGeometry/Crystal/OrientedLattice.h"
 
diff --git a/Framework/Crystal/src/ClearUB.cpp b/Framework/Crystal/src/ClearUB.cpp
index 1e44ed75b80c0199c7235de4a5636a11ab1938a7..be14295b71967b0b33fdbc3be11a66257b76f3c2 100644
--- a/Framework/Crystal/src/ClearUB.cpp
+++ b/Framework/Crystal/src/ClearUB.cpp
@@ -2,6 +2,7 @@
 #include "MantidAPI/ExperimentInfo.h"
 #include "MantidAPI/MultipleExperimentInfos.h"
 #include "MantidAPI/Sample.h"
+#include "MantidAPI/Workspace.h"
 
 using namespace Mantid::Kernel;
 using namespace Mantid::API;
diff --git a/Framework/Crystal/src/FindUBUsingLatticeParameters.cpp b/Framework/Crystal/src/FindUBUsingLatticeParameters.cpp
index 12d301bc14f030b9c72c87bf59bc0ca836176eb0..eaf220109897dbfb46c5260b8855abd96ab5840d 100644
--- a/Framework/Crystal/src/FindUBUsingLatticeParameters.cpp
+++ b/Framework/Crystal/src/FindUBUsingLatticeParameters.cpp
@@ -46,6 +46,8 @@ void FindUBUsingLatticeParameters::init() {
                         "Number of Peaks to Use on First Pass(15)");
   this->declareProperty("Tolerance", 0.15, mustBePositive,
                         "Indexing Tolerance (0.15)");
+  this->declareProperty("FixParameters", false,
+                        "Do not optimise the UB after finding the orientation");
 }
 
 /** Execute the algorithm.
@@ -59,6 +61,7 @@ void FindUBUsingLatticeParameters::exec() {
   double gamma = this->getProperty("gamma");
   int num_initial = this->getProperty("NumInitial");
   double tolerance = this->getProperty("Tolerance");
+  auto fixAll = this->getProperty("FixParameters");
 
   int base_index = -1; // these "could" be properties if need be
   double degrees_per_step = 1.5;
@@ -77,12 +80,13 @@ void FindUBUsingLatticeParameters::exec() {
     q_vectors.push_back(peaks[i].getQSampleFrame());
 
   Matrix<double> UB(3, 3, false);
-  double error = IndexingUtils::Find_UB(UB, q_vectors, a, b, c, alpha, beta,
-                                        gamma, tolerance, base_index,
-                                        num_initial, degrees_per_step);
+  OrientedLattice lattice(a, b, c, alpha, beta, gamma);
+  double error =
+      IndexingUtils::Find_UB(UB, q_vectors, lattice, tolerance, base_index,
+                             num_initial, degrees_per_step, fixAll);
 
-  std::cout << "Error = " << error << '\n';
-  std::cout << "UB = " << UB << '\n';
+  g_log.notice() << "Error = " << error << '\n';
+  g_log.notice() << "UB = " << UB << '\n';
 
   if (!IndexingUtils::CheckUB(UB)) // UB not found correctly
   {
@@ -91,18 +95,6 @@ void FindUBUsingLatticeParameters::exec() {
     g_log.notice(std::string("UB NOT SAVED."));
   } else // tell user how many would be indexed
   {      // and save the UB in the sample
-
-    std::vector<double> sigabc(7);
-    std::vector<V3D> miller_ind;
-    std::vector<V3D> indexed_qs;
-    double fit_error;
-    miller_ind.reserve(q_vectors.size());
-    indexed_qs.reserve(q_vectors.size());
-    IndexingUtils::GetIndexedPeaks(UB, q_vectors, tolerance, miller_ind,
-                                   indexed_qs, fit_error);
-
-    IndexingUtils::Optimize_UB(UB, miller_ind, indexed_qs, sigabc);
-
     char logInfo[200];
     int num_indexed = IndexingUtils::NumberIndexed(UB, q_vectors, tolerance);
     sprintf(logInfo,
@@ -112,27 +104,21 @@ void FindUBUsingLatticeParameters::exec() {
             num_indexed, n_peaks, tolerance);
     g_log.notice(std::string(logInfo));
 
-    OrientedLattice o_lattice;
-    o_lattice.setUB(UB);
-    o_lattice.setError(sigabc[0], sigabc[1], sigabc[2], sigabc[3], sigabc[4],
-                       sigabc[5]);
-
-    o_lattice.setUB(UB);
-    double calc_a = o_lattice.a();
-    double calc_b = o_lattice.b();
-    double calc_c = o_lattice.c();
-    double calc_alpha = o_lattice.alpha();
-    double calc_beta = o_lattice.beta();
-    double calc_gamma = o_lattice.gamma();
+    double calc_a = lattice.a();
+    double calc_b = lattice.b();
+    double calc_c = lattice.c();
+    double calc_alpha = lattice.alpha();
+    double calc_beta = lattice.beta();
+    double calc_gamma = lattice.gamma();
     // Show the modified lattice parameters
-    g_log.notice() << o_lattice << "\n";
+    g_log.notice() << lattice << "\n";
 
     sprintf(logInfo, std::string("Lattice Parameters (Refined - Input): %11.6f "
                                  "%11.6f %11.6f %11.6f %11.6f %11.6f").c_str(),
             calc_a - a, calc_b - b, calc_c - c, calc_alpha - alpha,
             calc_beta - beta, calc_gamma - gamma);
     g_log.notice(std::string(logInfo));
-    ws->mutableSample().setOrientedLattice(&o_lattice);
+    ws->mutableSample().setOrientedLattice(&lattice);
   }
 }
 
diff --git a/Framework/Crystal/src/GoniometerAnglesFromPhiRotation.cpp b/Framework/Crystal/src/GoniometerAnglesFromPhiRotation.cpp
index 182a1499f49970e396ffecc378427994717d1fb3..797cfa9f3ef42c9bcc92cec397b5f5783f15edc5 100644
--- a/Framework/Crystal/src/GoniometerAnglesFromPhiRotation.cpp
+++ b/Framework/Crystal/src/GoniometerAnglesFromPhiRotation.cpp
@@ -162,9 +162,9 @@ void GoniometerAnglesFromPhiRotation::exec() {
 
     if (!PeaksRun1->sample().hasOrientedLattice()) {
       g_log.notice(std::string("Could not find UB for ") +
-                   std::string(PeaksRun1->name()));
+                   std::string(PeaksRun1->getName()));
       throw std::invalid_argument(std::string("Could not find UB for ") +
-                                  std::string(PeaksRun1->name()));
+                                  std::string(PeaksRun1->getName()));
     }
   }
   //-------------get UB raw :No goniometer----------------
@@ -179,9 +179,9 @@ void GoniometerAnglesFromPhiRotation::exec() {
 
   if (N1 < .6 * PeaksRun1->getNumberPeaks()) {
     g_log.notice(std::string("UB did not index well for ") +
-                 std::string(PeaksRun1->name()));
+                 std::string(PeaksRun1->getName()));
     throw std::invalid_argument(std::string("UB did not index well for ") +
-                                std::string(PeaksRun1->name()));
+                                std::string(PeaksRun1->getName()));
   }
 
   //----------------------------------------------
@@ -271,7 +271,7 @@ void GoniometerAnglesFromPhiRotation::exec() {
   MinData[4] = omchiphi[0];
 
   std::string FunctionArgs =
-      "name=PeakHKLErrors, PeakWorkspaceName=" + PeaksRun2->name() +
+      "name=PeakHKLErrors, PeakWorkspaceName=" + PeaksRun2->getName() +
       ",OptRuns=" + RunNumStr + ",phi" + RunNumStr + "=" +
       boost::lexical_cast<std::string>(MinData[2]) + ",chi" + RunNumStr + "=" +
       boost::lexical_cast<std::string>(MinData[3]) + ",omega" + RunNumStr +
diff --git a/Framework/Crystal/src/IndexPeaks.cpp b/Framework/Crystal/src/IndexPeaks.cpp
index dfb86fb5e615bc981917138d58a7e24b3f36ee99..ddc1c214b7db7ad624bbb50188faed559522527e 100644
--- a/Framework/Crystal/src/IndexPeaks.cpp
+++ b/Framework/Crystal/src/IndexPeaks.cpp
@@ -51,7 +51,7 @@ void IndexPeaks::exec() {
   }
 
   OrientedLattice o_lattice = ws->mutableSample().getOrientedLattice();
-  Matrix<double> UB = o_lattice.getUB();
+  const Matrix<double> &UB = o_lattice.getUB();
 
   if (!IndexingUtils::CheckUB(UB)) {
     throw std::runtime_error(
diff --git a/Framework/Crystal/src/IntegratePeakTimeSlices.cpp b/Framework/Crystal/src/IntegratePeakTimeSlices.cpp
index 1d7cce4ce184541e7a065da84438e09ee966f61d..cf64aa295ea73c1ecea764355360db1ddb766a11 100644
--- a/Framework/Crystal/src/IntegratePeakTimeSlices.cpp
+++ b/Framework/Crystal/src/IntegratePeakTimeSlices.cpp
@@ -1335,15 +1335,10 @@ void DataModeHandler::setHeightHalfWidthInfo(
   double offset = std::max<double>(.2, (maxCount - minCount) / 20);
   double TotR_max = 0;
   double TotR_min = 0;
-  int nedge1Cells = 0;
-  int nintCells = 0;
-  int nBoundEdge1Cells = 0;
-  int nBoundIntCells = 0;
   double TotRx0 = 0;
   double TotRy0 = 0;
   double TotCx = 0;
   double TotCy = 0;
-  double IntOffset = std::min<double>(highX - lowX, highY - lowY);
   for (int i = 0; i < N; i++) {
     if (C[i] > maxCount - offset) {
       TotMax += C[i];
@@ -1361,16 +1356,6 @@ void DataModeHandler::setHeightHalfWidthInfo(
                               (Y[i] - MaxY) * (Y[i] - MaxY));
     }
 
-    if (X[i] >= lowX && X[i] <= highX && Y[i] >= lowY && Y[i] <= highY) {
-      nedge1Cells++;
-      if (C[i] < minCount + offset)
-        nBoundEdge1Cells++;
-    }
-    if (fabs(MaxX - X[i]) < IntOffset && fabs(MaxY - Y[i]) < IntOffset) {
-      nintCells++;
-      if (C[i] < minCount + offset)
-        nBoundIntCells++;
-    }
     if (fabs(MaxY - Y[i]) < 1.2 && fabs(MaxX - X[i]) > 1.2 &&
         C[i] >= CountLow && C[i] <= CountUp && fabs(MaxX - X[i]) < dSpanx) {
       TotRx0 += (C[i] - minCount) * (X[i] - MaxX) * (X[i] - MaxX);
@@ -1578,7 +1563,6 @@ void IntegratePeakTimeSlices::SetUpData1(
   int nBoundaryCells = 0;
   double TotBoundaryVariances = 0;
 
-  int N = 0;
   double BoundaryRadius = min<double>(
       .90 * Radius, Radius - 1.5 * max<double>(m_cellWidth, m_cellHeight));
   double minRow = 20000, maxRow = -1, minCol = 20000, maxCol = -1;
@@ -1633,7 +1617,6 @@ void IntegratePeakTimeSlices::SetUpData1(
           variance += histoerrs[chan] * histoerrs[chan];
         }
 
-        N++;
         yvalB.push_back(intensity);
         double sigma = 1;
 
diff --git a/Framework/Crystal/src/IntegratePeaksHybrid.cpp b/Framework/Crystal/src/IntegratePeaksHybrid.cpp
index 7ccdfd32d0ee4f652fafde3f7edd23b78420b503..e36312aec51e1c528248271aa0783815b529f7ea 100644
--- a/Framework/Crystal/src/IntegratePeaksHybrid.cpp
+++ b/Framework/Crystal/src/IntegratePeaksHybrid.cpp
@@ -44,6 +44,7 @@
 #include "MantidAPI/IMDEventWorkspace.h"
 #include "MantidAPI/IMDHistoWorkspace.h"
 #include "MantidAPI/IMDIterator.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidKernel/CompositeValidator.h"
 #include "MantidKernel/MandatoryValidator.h"
 #include "MantidKernel/BoundedValidator.h"
diff --git a/Framework/Crystal/src/LoadIsawPeaks.cpp b/Framework/Crystal/src/LoadIsawPeaks.cpp
index 5c9ff368422c4360be891af663901c14a9384e1b..eacca1e5594803ee6383886487ffedbdd759edad 100644
--- a/Framework/Crystal/src/LoadIsawPeaks.cpp
+++ b/Framework/Crystal/src/LoadIsawPeaks.cpp
@@ -5,8 +5,10 @@
 #include "MantidAPI/Run.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidGeometry/Crystal/OrientedLattice.h"
+#include "MantidGeometry/Instrument/Goniometer.h"
 #include "MantidGeometry/Instrument/RectangularDetector.h"
 #include "MantidKernel/OptionalBool.h"
+#include "MantidKernel/Strings.h"
 #include "MantidKernel/Unit.h"
 
 using Mantid::Kernel::Strings::readToEndOfLine;
@@ -106,16 +108,14 @@ void LoadIsawPeaks::exec() {
 }
 
 //----------------------------------------------------------------------------------------------
-std::string
-LoadIsawPeaks::ApplyCalibInfo(std::ifstream &in, std::string startChar,
-                              Geometry::Instrument_const_sptr instr_old,
-                              Geometry::Instrument_const_sptr instr,
-                              double &T0) {
-  ParameterMap_sptr parMap1 = instr_old->getParameterMap();
+std::string LoadIsawPeaks::ApplyCalibInfo(std::ifstream &in,
+                                          std::string startChar,
+                                          Geometry::Instrument_const_sptr instr,
+                                          double &T0) {
 
   ParameterMap_sptr parMap = instr->getParameterMap();
 
-  while (in.good() && (startChar.size() < 1 || startChar != "7")) {
+  while (in.good() && (startChar.empty() || startChar != "7")) {
     readToEndOfLine(in, true);
     startChar = getWord(in, false);
   }
@@ -136,7 +136,7 @@ LoadIsawPeaks::ApplyCalibInfo(std::ifstream &in, std::string startChar,
     iss >> T0;
     V3D sampPos = instr->getSample()->getPos();
     SCDCalibratePanels::FixUpSourceParameterMap(instr, L1 / 100, sampPos,
-                                                parMap1);
+                                                parMap);
   } catch (...) {
     g_log.error() << "Invalid L1 or Time offset\n";
     throw std::invalid_argument("Invalid L1 or Time offset");
@@ -144,7 +144,7 @@ LoadIsawPeaks::ApplyCalibInfo(std::ifstream &in, std::string startChar,
 
   readToEndOfLine(in, true);
   startChar = getWord(in, false);
-  while (in.good() && (startChar.size() < 1 || startChar != "5")) {
+  while (in.good() && (startChar.empty() || startChar != "5")) {
     readToEndOfLine(in, true);
     startChar = getWord(in, false);
   }
@@ -159,7 +159,7 @@ LoadIsawPeaks::ApplyCalibInfo(std::ifstream &in, std::string startChar,
     std::string line;
     for (int i = 0; i < 16; i++) {
       std::string s = getWord(in, false);
-      if (s.size() < 1) {
+      if (s.empty()) {
         g_log.error() << "Not enough info to describe panel \n";
         throw std::length_error("Not enough info to describe panel ");
       }
@@ -196,7 +196,7 @@ LoadIsawPeaks::ApplyCalibInfo(std::ifstream &in, std::string startChar,
     }
     bankName += SbankNum;
     boost::shared_ptr<const Geometry::IComponent> bank =
-        getCachedBankByName(bankName, instr_old);
+        getCachedBankByName(bankName, instr);
 
     if (!bank) {
       g_log.error() << "There is no bank " << bankName
@@ -216,7 +216,7 @@ LoadIsawPeaks::ApplyCalibInfo(std::ifstream &in, std::string startChar,
     bankRot.inverse();
     Quat dRot = thisRot * bankRot;
 
-    boost::shared_ptr<const Geometry::RectangularDetector> bankR =
+    auto bankR =
         boost::dynamic_pointer_cast<const Geometry::RectangularDetector>(bank);
 
     if (!bankR)
@@ -227,11 +227,10 @@ LoadIsawPeaks::ApplyCalibInfo(std::ifstream &in, std::string startChar,
       DetWScale = width / bankR->xsize() / 100;
       DetHtScale = height / bankR->ysize() / 100;
     }
-    std::vector<std::string> bankNames;
-    bankNames.push_back(bankName);
+    const std::vector<std::string> bankNames{bankName};
 
     SCDCalibratePanels::FixUpBankParameterMap(
-        bankNames, instr, dPos, dRot, DetWScale, DetHtScale, parMap1, false);
+        bankNames, instr, dPos, dRot, DetWScale, DetHtScale, parMap, false);
   }
   return startChar;
 }
@@ -294,13 +293,9 @@ std::string LoadIsawPeaks::readHeader(PeaksWorkspace_sptr outWS,
   // Populate the instrument parameters in this workspace - this works around a
   // bug
   tempWS->populateInstrumentParameters();
-  Geometry::Instrument_const_sptr instr_old = tempWS->getInstrument();
-  auto instr = instr_old;
-  /*auto map = boost::make_shared<ParameterMap>();
-  auto instr = boost::make_shared<const Geometry::Instrument>(
-      instr_old->baseInstrument(), map);*/
+  Geometry::Instrument_const_sptr instr = tempWS->getInstrument();
 
-  std::string s = ApplyCalibInfo(in, "", instr_old, instr, T0);
+  std::string s = ApplyCalibInfo(in, "", instr, T0);
   outWS->setInstrument(instr);
 
   // Now skip all lines on L1, detector banks, etc. until we get to a block of
@@ -565,7 +560,7 @@ void LoadIsawPeaks::appendFile(PeaksWorkspace_sptr outWS,
       Peak peak = readPeak(outWS, s, in, seqNum, bankName, qSign);
 
       // Get the calculated goniometer matrix
-      Matrix<double> gonMat = uniGonio.getR();
+      const Matrix<double> &gonMat = uniGonio.getR();
 
       peak.setGoniometerMatrix(gonMat);
       peak.setRunNumber(run);
@@ -581,8 +576,9 @@ void LoadIsawPeaks::appendFile(PeaksWorkspace_sptr outWS,
       // Add the peak to workspace
       outWS->addPeak(peak);
     } catch (std::runtime_error &e) {
-      g_log.warning() << "Error reading peak SEQN " << seqNum << " : "
-                      << e.what() << '\n';
+      g_log.error() << "Error reading peak SEQN " << seqNum << " : " << e.what()
+                    << '\n';
+      throw std::runtime_error("Corrupted input file. ");
     }
 
     prog.report(in.tellg());
diff --git a/Framework/Crystal/src/LoadIsawUB.cpp b/Framework/Crystal/src/LoadIsawUB.cpp
index c89719269b45395c5eb78f0d14a30f30eae90987..49e754ec0fde92500122200220ca0b3de407ed4d 100644
--- a/Framework/Crystal/src/LoadIsawUB.cpp
+++ b/Framework/Crystal/src/LoadIsawUB.cpp
@@ -4,6 +4,7 @@
 #include <MantidGeometry/Crystal/OrientedLattice.h>
 #include "MantidAPI/IMDEventWorkspace.h"
 #include "MantidAPI/Sample.h"
+#include "MantidKernel/Strings.h"
 
 using namespace Mantid::Kernel::Strings;
 using Mantid::Kernel::DblMatrix;
diff --git a/Framework/Crystal/src/MaskPeaksWorkspace.cpp b/Framework/Crystal/src/MaskPeaksWorkspace.cpp
index 378be6b7113f2edc1b53afc1d796baaf688afb2d..18a5e7f8171133c6fe2c57defa3acec0bc0c1ab2 100644
--- a/Framework/Crystal/src/MaskPeaksWorkspace.cpp
+++ b/Framework/Crystal/src/MaskPeaksWorkspace.cpp
@@ -1,6 +1,3 @@
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidCrystal/MaskPeaksWorkspace.h"
 #include "MantidDataObjects/PeaksWorkspace.h"
 #include "MantidAPI/InstrumentValidator.h"
@@ -9,6 +6,7 @@
 #include "MantidAPI/IPeakFunction.h"
 #include "MantidKernel/VectorHelper.h"
 #include "MantidKernel/ArrayProperty.h"
+#include "MantidKernel/Strings.h"
 
 #include <boost/math/special_functions/round.hpp>
 
diff --git a/Framework/Crystal/src/NormaliseVanadium.cpp b/Framework/Crystal/src/NormaliseVanadium.cpp
index 26423a185c5ccc6cfb9af46a6da47282cb50f6a3..ffb43be47a99f0c6c2c7a7f966fedd5d5ebcd689 100644
--- a/Framework/Crystal/src/NormaliseVanadium.cpp
+++ b/Framework/Crystal/src/NormaliseVanadium.cpp
@@ -1,12 +1,10 @@
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidCrystal/NormaliseVanadium.h"
 #include "MantidAPI/Axis.h"
 #include "MantidAPI/InstrumentValidator.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidGeometry/Instrument.h"
 #include "MantidKernel/BoundedValidator.h"
+#include "MantidKernel/Unit.h"
 #include "MantidKernel/UnitFactory.h"
 #include "MantidKernel/Fast_Exponential.h"
 #include "MantidKernel/VectorHelper.h"
diff --git a/Framework/Crystal/src/OptimizeCrystalPlacement.cpp b/Framework/Crystal/src/OptimizeCrystalPlacement.cpp
index e7f720798cf62d2f2b8ff271075d4a4b3523a0d9..3654f822ad27f0302641f46325f950b519344413 100644
--- a/Framework/Crystal/src/OptimizeCrystalPlacement.cpp
+++ b/Framework/Crystal/src/OptimizeCrystalPlacement.cpp
@@ -14,6 +14,7 @@
 #include "MantidKernel/EnabledWhenProperty.h"
 #include "MantidGeometry/Crystal/IPeak.h"
 #include "MantidGeometry/Crystal/IndexingUtils.h"
+#include "MantidGeometry/Instrument/Goniometer.h"
 #include "MantidCrystal/PeakHKLErrors.h"
 #include "MantidCrystal/SCDCalibratePanels.h"
 
@@ -255,7 +256,7 @@ void OptimizeCrystalPlacement::exec() {
     message += "will be 'changed'";
     g_log.notice(message);
   }
-  if (OptRunNums.size() > 0 && !omitRuns)
+  if (!OptRunNums.empty() && !omitRuns)
     FuncArg += ",OptRuns=" + OptRunNums;
 
   //------------- Add initial parameter values to FuncArg -----------
diff --git a/Framework/Crystal/src/OptimizeExtinctionParameters.cpp b/Framework/Crystal/src/OptimizeExtinctionParameters.cpp
index b0c7647daf13914af0ec420c6d926562a204ca85..1ade805dbbdf5920561b6030e3dcc3b4797ab8f3 100644
--- a/Framework/Crystal/src/OptimizeExtinctionParameters.cpp
+++ b/Framework/Crystal/src/OptimizeExtinctionParameters.cpp
@@ -1,5 +1,6 @@
 #include "MantidCrystal/OptimizeExtinctionParameters.h"
 #include "MantidDataObjects/PeaksWorkspace.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/FileProperty.h"
 #include "MantidAPI/FunctionFactory.h"
 #include "MantidAPI/IPeakFunction.h"
diff --git a/Framework/Crystal/src/OptimizeLatticeForCellType.cpp b/Framework/Crystal/src/OptimizeLatticeForCellType.cpp
index a649c24ff547bcb23d98bb4804cbd017c726b2ee..0462e3b8952a1c81a6785b79ecf640e839d3043b 100644
--- a/Framework/Crystal/src/OptimizeLatticeForCellType.cpp
+++ b/Framework/Crystal/src/OptimizeLatticeForCellType.cpp
@@ -1,5 +1,6 @@
 #include "MantidCrystal/OptimizeLatticeForCellType.h"
 #include "MantidCrystal/GSLFunctions.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/FileProperty.h"
 #include "MantidAPI/FunctionFactory.h"
 #include "MantidAPI/IPeakFunction.h"
diff --git a/Framework/Crystal/src/PeakHKLErrors.cpp b/Framework/Crystal/src/PeakHKLErrors.cpp
index eb8f22274e23c2fe64209795ab9a30501e922ea3..73524bfd5b6f026f1bb4dee5b51a47fcdc5888a3 100644
--- a/Framework/Crystal/src/PeakHKLErrors.cpp
+++ b/Framework/Crystal/src/PeakHKLErrors.cpp
@@ -65,10 +65,10 @@ void PeakHKLErrors::setUpOptRuns() {
 
   std::vector<std::string> OptRunNums;
   std::string OptRunstemp(OptRuns);
-  if (OptRuns.size() > 0 && OptRuns.at(0) == '/')
+  if (!OptRuns.empty() && OptRuns.at(0) == '/')
     OptRunstemp = OptRunstemp.substr(1, OptRunstemp.size() - 1);
 
-  if (OptRunstemp.size() > 0 && OptRunstemp.at(OptRunstemp.size() - 1) == '/')
+  if (!OptRunstemp.empty() && OptRunstemp.at(OptRunstemp.size() - 1) == '/')
     OptRunstemp = OptRunstemp.substr(0, OptRunstemp.size() - 1);
 
   boost::split(OptRunNums, OptRunstemp, boost::is_any_of("/"));
diff --git a/Framework/Crystal/src/PeakIntegration.cpp b/Framework/Crystal/src/PeakIntegration.cpp
index c1524ad285c6567e5695450e65bda98c8f757349..012a062d0c24c173004dd404c35f9fe8579f0bae 100644
--- a/Framework/Crystal/src/PeakIntegration.cpp
+++ b/Framework/Crystal/src/PeakIntegration.cpp
@@ -95,7 +95,8 @@ void PeakIntegration::exec() {
   outputW = API::WorkspaceFactory::Instance().create(
       inputW, peaksW->getNumberPeaks(), YLength + 1, YLength);
   // Copy geometry over.
-  API::WorkspaceFactory::Instance().initializeFromParent(inputW, outputW, true);
+  API::WorkspaceFactory::Instance().initializeFromParent(*inputW, *outputW,
+                                                         true);
   size_t Numberwi = inputW->getNumberHistograms();
   int NumberPeaks = peaksW->getNumberPeaks();
   int MinPeaks = 0;
diff --git a/Framework/Crystal/src/PeakIntensityVsRadius.cpp b/Framework/Crystal/src/PeakIntensityVsRadius.cpp
index 8e2960f5a60102c2499a04a8e0c2129c32c4320a..25841bb6b620a634e9a6d7a3f2ef849435deb2d0 100644
--- a/Framework/Crystal/src/PeakIntensityVsRadius.cpp
+++ b/Framework/Crystal/src/PeakIntensityVsRadius.cpp
@@ -7,6 +7,7 @@
 #include "MantidAPI/WorkspaceFactory.h"
 
 #include "MantidKernel/ListValidator.h"
+#include "MantidKernel/Strings.h"
 
 using namespace Mantid::Kernel;
 using namespace Mantid::API;
diff --git a/Framework/Crystal/src/PeaksIntersection.cpp b/Framework/Crystal/src/PeaksIntersection.cpp
index 6051f4e2f2eb80051e983c5c6b8efed4fcb66414..d941a1e64eda259373571a837b7f489871fc51f8 100644
--- a/Framework/Crystal/src/PeaksIntersection.cpp
+++ b/Framework/Crystal/src/PeaksIntersection.cpp
@@ -5,6 +5,8 @@
 #include "MantidCrystal/PeaksIntersection.h"
 #include "MantidDataObjects/TableWorkspace.h"
 
+#include <boost/function.hpp>
+
 using namespace Mantid::API;
 using namespace Mantid::Geometry;
 using namespace Mantid::Kernel;
diff --git a/Framework/Crystal/src/PredictFractionalPeaks.cpp b/Framework/Crystal/src/PredictFractionalPeaks.cpp
index 86a4906756c942366c2d9c93837b1db763e7f3e1..d422382a590adff69201c6992606f3809c0b8146 100644
--- a/Framework/Crystal/src/PredictFractionalPeaks.cpp
+++ b/Framework/Crystal/src/PredictFractionalPeaks.cpp
@@ -161,7 +161,7 @@ void PredictFractionalPeaks::exec() {
     hkl[2] = peak0.getL();
   }
 
-  Kernel::DblMatrix UB = ol.getUB();
+  const Kernel::DblMatrix &UB = ol.getUB();
   vector<vector<int>> AlreadyDonePeaks;
   bool done = false;
   int ErrPos = 1; // Used to determine position in code of a throw
diff --git a/Framework/Crystal/src/PredictPeaks.cpp b/Framework/Crystal/src/PredictPeaks.cpp
index 5eb7006a96b6c541aead82ab58add40fb792df60..7cc823f794cb3ecae93c4673cfa470a99bfcdc32 100644
--- a/Framework/Crystal/src/PredictPeaks.cpp
+++ b/Framework/Crystal/src/PredictPeaks.cpp
@@ -216,7 +216,7 @@ void PredictPeaks::exec() {
   const Sample &sample = inputExperimentInfo->sample();
 
   // Retrieve the OrientedLattice (UnitCell) from the workspace
-  OrientedLattice orientedLattice = sample.getOrientedLattice();
+  const OrientedLattice &orientedLattice = sample.getOrientedLattice();
 
   // Get the UB matrix from it
   Matrix<double> ub(3, 3, true);
@@ -432,7 +432,7 @@ void PredictPeaks::calculateQAndAddToOutput(const V3D &hkl,
     p.setGoniometerMatrix(goniometerMatrix);
     // Save the run number found before.
     p.setRunNumber(m_runNumber);
-    p.setHKL(hkl);
+    p.setHKL(hkl * m_qConventionFactor);
 
     if (m_sfCalculator) {
       p.setIntensity(m_sfCalculator->getFSquared(hkl));
diff --git a/Framework/Crystal/src/SCDCalibratePanels.cpp b/Framework/Crystal/src/SCDCalibratePanels.cpp
index fdab7d7c0c83754edb0596d21fb2df1e09346f79..274ba9649f71c6aa0f118bc852f4a54e252452e9 100644
--- a/Framework/Crystal/src/SCDCalibratePanels.cpp
+++ b/Framework/Crystal/src/SCDCalibratePanels.cpp
@@ -1,4 +1,5 @@
 #include "MantidCrystal/SCDCalibratePanels.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/ConstraintFactory.h"
 #include "MantidKernel/BoundedValidator.h"
 #include "MantidKernel/EnabledWhenProperty.h"
@@ -368,7 +369,7 @@ void SCDCalibratePanels::exec() {
           "Workspace2D", MyBankNames.size(), nPeaks, nPeaks);
   TofWksp->setInstrument(inst);
   OrientedLattice lattice = peaksWs->mutableSample().getOrientedLattice();
-  DblMatrix UB = lattice.getUB();
+  const DblMatrix &UB = lattice.getUB();
   // sort again since edge peaks can trace to other banks
   peaksWs->sort(criteria);
   PARALLEL_FOR_IF(Kernel::threadSafe(*ColWksp, *RowWksp, *TofWksp))
diff --git a/Framework/Crystal/src/SCDPanelErrors.cpp b/Framework/Crystal/src/SCDPanelErrors.cpp
index 2a778427fe0572ffed02b6b6063bc7e9e850e4ea..adbfa3643f814aa37b0fd9b650e7e9932b515fe9 100644
--- a/Framework/Crystal/src/SCDPanelErrors.cpp
+++ b/Framework/Crystal/src/SCDPanelErrors.cpp
@@ -324,7 +324,7 @@ void SCDPanelErrors::setupData() const {
 
   m_bank = getAttribute("Bank").asString();
 
-  g_log.debug() << "Setting up " << m_workspace->name() << " bank " << m_bank
+  g_log.debug() << "Setting up " << m_workspace->getName() << " bank " << m_bank
                 << '\n';
 
   m_setupFinished = true;
diff --git a/Framework/Crystal/src/SaveHKL.cpp b/Framework/Crystal/src/SaveHKL.cpp
index 7273700621bed86560fd9e4767b60e33daaad096..04974daab13d6e092c78a7fa08388fbe24fc4bbd 100644
--- a/Framework/Crystal/src/SaveHKL.cpp
+++ b/Framework/Crystal/src/SaveHKL.cpp
@@ -6,8 +6,10 @@
 #include "MantidKernel/Utils.h"
 #include "MantidKernel/BoundedValidator.h"
 #include "MantidKernel/Material.h"
+#include "MantidKernel/Unit.h"
 #include "MantidKernel/UnitFactory.h"
 #include "MantidKernel/ListValidator.h"
+#include "MantidKernel/Strings.h"
 #include "MantidCrystal/AnvredCorrection.h"
 #include "MantidGeometry/Crystal/OrientedLattice.h"
 #include <fstream>
diff --git a/Framework/Crystal/src/SaveIsawPeaks.cpp b/Framework/Crystal/src/SaveIsawPeaks.cpp
index 8c5a7d110175704cb38ebb414d377d117bd9c902..7ba77820ef5a8c35cb7603b4787d946fe5754597 100644
--- a/Framework/Crystal/src/SaveIsawPeaks.cpp
+++ b/Framework/Crystal/src/SaveIsawPeaks.cpp
@@ -4,7 +4,9 @@
 #include "MantidCrystal/SaveIsawPeaks.h"
 #include "MantidDataObjects/Peak.h"
 #include "MantidDataObjects/PeaksWorkspace.h"
+#include "MantidGeometry/Instrument/Goniometer.h"
 #include "MantidGeometry/Instrument/RectangularDetector.h"
+#include "MantidKernel/Strings.h"
 #include "MantidKernel/Utils.h"
 #include "MantidDataObjects/Workspace2D.h"
 #include <fstream>
diff --git a/Framework/Crystal/src/SaveIsawUB.cpp b/Framework/Crystal/src/SaveIsawUB.cpp
index 92608c5fd002c1623f70e501f9a6f9a37cff46eb..9e13bc57b568b1a7460e5e24b43e94dbd5671d86 100644
--- a/Framework/Crystal/src/SaveIsawUB.cpp
+++ b/Framework/Crystal/src/SaveIsawUB.cpp
@@ -1,9 +1,11 @@
 #include "MantidAPI/FileProperty.h"
 #include "MantidCrystal/SaveIsawUB.h"
-#include <fstream>
 #include "MantidAPI/IMDEventWorkspace.h"
 #include "MantidAPI/Sample.h"
 
+#include <fstream>
+#include <iomanip>
+
 using Mantid::Kernel::DblMatrix;
 using Mantid::Geometry::UnitCell;
 using Mantid::Geometry::OrientedLattice;
diff --git a/Framework/Crystal/src/SaveLauenorm.cpp b/Framework/Crystal/src/SaveLauenorm.cpp
index 780faf5b3efc7397654ee0ef84949b65921e97e1..bb54a1cd9f371857569a662318e6676e042fca3a 100644
--- a/Framework/Crystal/src/SaveLauenorm.cpp
+++ b/Framework/Crystal/src/SaveLauenorm.cpp
@@ -7,6 +7,7 @@
 #include "MantidKernel/ListValidator.h"
 #include "MantidCrystal/AnvredCorrection.h"
 #include "MantidKernel/ArrayProperty.h"
+#include "MantidKernel/Strings.h"
 #include <fstream>
 #include <Poco/File.h>
 #include <Poco/Path.h>
diff --git a/Framework/Crystal/src/SetGoniometer.cpp b/Framework/Crystal/src/SetGoniometer.cpp
index d08034aeb20185dc6e56a71990a0165588ec30f9..104b3192fd1d13d3d68171111cea0c760824f10f 100644
--- a/Framework/Crystal/src/SetGoniometer.cpp
+++ b/Framework/Crystal/src/SetGoniometer.cpp
@@ -1,9 +1,14 @@
 #include "MantidCrystal/SetGoniometer.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/Run.h"
+#include "MantidGeometry/Instrument/Goniometer.h"
 #include "MantidKernel/ListValidator.h"
+#include "MantidKernel/Strings.h"
 #include "MantidKernel/TimeSeriesProperty.h"
 
+#include <boost/algorithm/string/classification.hpp>
+#include <boost/algorithm/string/split.hpp>
+
 using Mantid::Geometry::Goniometer;
 using namespace Mantid::Geometry;
 
diff --git a/Framework/Crystal/src/ShowPossibleCells.cpp b/Framework/Crystal/src/ShowPossibleCells.cpp
index 237c467f75c75b457ec0e961a42a302b6fdd185a..cd77926624a207893e675d677678bcfe6aff6327 100644
--- a/Framework/Crystal/src/ShowPossibleCells.cpp
+++ b/Framework/Crystal/src/ShowPossibleCells.cpp
@@ -51,7 +51,7 @@ void ShowPossibleCells::exec() {
   }
 
   OrientedLattice o_lattice = ws->sample().getOrientedLattice();
-  Matrix<double> UB = o_lattice.getUB();
+  const Matrix<double> &UB = o_lattice.getUB();
 
   if (!IndexingUtils::CheckUB(UB)) {
     throw std::runtime_error(
diff --git a/Framework/Crystal/src/SortHKL.cpp b/Framework/Crystal/src/SortHKL.cpp
index d02c068e22e2da46c5e212023a353c8e88c504a9..450084846821adc915a934e963639b84098ba9f5 100644
--- a/Framework/Crystal/src/SortHKL.cpp
+++ b/Framework/Crystal/src/SortHKL.cpp
@@ -1,3 +1,4 @@
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/FileProperty.h"
 #include "MantidAPI/Sample.h"
 
diff --git a/Framework/Crystal/test/AddPeakHKLTest.h b/Framework/Crystal/test/AddPeakHKLTest.h
index 2f9da672e41af04256ad13baa00e9a18fca5a6b3..fdc21c4c07d2a095e9dc0a74a74e2d5d05d16f96 100644
--- a/Framework/Crystal/test/AddPeakHKLTest.h
+++ b/Framework/Crystal/test/AddPeakHKLTest.h
@@ -9,6 +9,7 @@
 #include "MantidAPI/Sample.h"
 #include "MantidDataObjects/PeaksWorkspace.h"
 #include "MantidGeometry/Crystal/OrientedLattice.h"
+#include "MantidGeometry/Instrument/Goniometer.h"
 #include "MantidTestHelpers/ComponentCreationHelper.h"
 
 using Mantid::Crystal::AddPeakHKL;
diff --git a/Framework/Crystal/test/CMakeLists.txt b/Framework/Crystal/test/CMakeLists.txt
index a2dac3b1ae576649bf346f1514760f894d1e25e5..cd9aaeac4aef0e15e605809d65300c73b31375b2 100644
--- a/Framework/Crystal/test/CMakeLists.txt
+++ b/Framework/Crystal/test/CMakeLists.txt
@@ -17,6 +17,7 @@ if ( CXXTEST_FOUND )
             DataObjects
             Geometry
             HistogramData
+            Indexing
             Kernel
             MDAlgorithms
             ${Boost_LIBRARIES}
diff --git a/Framework/Crystal/test/CalculateUMatrixTest.h b/Framework/Crystal/test/CalculateUMatrixTest.h
index 6e6a5494ba365201065fc0181aac5ad9ba951716..60bd1aff51de6e93e31e2c0a2cab55fe76446967 100644
--- a/Framework/Crystal/test/CalculateUMatrixTest.h
+++ b/Framework/Crystal/test/CalculateUMatrixTest.h
@@ -4,6 +4,7 @@
 #include <cxxtest/TestSuite.h>
 #include "MantidKernel/Timer.h"
 #include "MantidKernel/System.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Run.h"
 #include "MantidAPI/Sample.h"
 
diff --git a/Framework/Crystal/test/CentroidPeaksTest.h b/Framework/Crystal/test/CentroidPeaksTest.h
index 466b01f5ae35ddf1524440b74f38a35fc8bc03df..6044ab107b5c944278eb5dccefa2648b2324a41f 100644
--- a/Framework/Crystal/test/CentroidPeaksTest.h
+++ b/Framework/Crystal/test/CentroidPeaksTest.h
@@ -8,6 +8,7 @@
 #include "MantidDataHandling/LoadInstrument.h"
 #include "MantidDataObjects/EventWorkspace.h"
 #include "MantidDataObjects/PeaksWorkspace.h"
+#include "MantidDataObjects/WorkspaceCreation.h"
 #include "MantidKernel/System.h"
 #include "MantidKernel/Timer.h"
 #include "MantidTestHelpers/ComponentCreationHelper.h"
@@ -28,8 +29,7 @@ using namespace Mantid::API;
 using namespace Mantid::DataObjects;
 using namespace Mantid::DataHandling;
 using namespace Mantid::Geometry;
-using Mantid::HistogramData::BinEdges;
-using Mantid::HistogramData::LinearGenerator;
+using namespace Mantid::HistogramData;
 
 class CentroidPeaksTest : public CxxTest::TestSuite {
 public:
@@ -67,15 +67,15 @@ public:
       gens[d] = gen;
     }
 
-    EventWorkspace_sptr retVal(new EventWorkspace);
-    retVal->initialize(numPixels, 1, 1);
+    boost::shared_ptr<EventWorkspace> retVal = create<EventWorkspace>(
+        numPixels, BinEdges(numBins, LinearGenerator(0.0, binDelta)));
 
     // --------- Load the instrument -----------
     LoadInstrument *loadInst = new LoadInstrument();
     loadInst->initialize();
     loadInst->setPropertyValue(
         "Filename", "IDFs_for_UNIT_TESTING/MINITOPAZ_Definition.xml");
-    loadInst->setProperty<MatrixWorkspace_sptr>("Workspace", retVal);
+    loadInst->setProperty("Workspace", retVal);
     loadInst->setProperty("RewriteSpectraMap",
                           Mantid::Kernel::OptionalBool(true));
     loadInst->execute();
@@ -88,8 +88,6 @@ public:
 
     for (int pix = 0; pix < numPixels; ++pix) {
       auto &el = retVal->getSpectrum(pix);
-      el.setSpectrumNo(pix);
-      el.setDetectorID(pix);
       // Background
       for (int i = 0; i < numBins; i++) {
         // Two events per bin
@@ -113,9 +111,6 @@ public:
     for (size_t d = 0; d < nd; ++d)
       delete gens[d];
 
-    // Set all the histograms at once.
-    retVal->setAllX(BinEdges(numBins, LinearGenerator(0.0, binDelta)));
-
     // Some sanity checks
     TS_ASSERT_EQUALS(retVal->getInstrument()->getName(), "MINITOPAZ");
     std::map<int, Geometry::IDetector_const_sptr> dets;
diff --git a/Framework/Crystal/test/ClearUBTest.h b/Framework/Crystal/test/ClearUBTest.h
index 1d684f54c7d316cb217502a48b559f8473b535ea..29eb8ba2e9cce7db5695348564b5880da8b38f72 100644
--- a/Framework/Crystal/test/ClearUBTest.h
+++ b/Framework/Crystal/test/ClearUBTest.h
@@ -32,7 +32,7 @@ private:
 
   // Helper method to create a matrix workspace.
   std::string createMatrixWorkspace(const bool withOrientedLattice = true) {
-    auto ws = WorkspaceCreationHelper::Create2DWorkspace(1, 2);
+    auto ws = WorkspaceCreationHelper::create2DWorkspace(1, 2);
     if (withOrientedLattice) {
       OrientedLattice latt(1.0, 2.0, 3.0, 90, 90, 90);
       ws->mutableSample().setOrientedLattice(&latt);
diff --git a/Framework/Crystal/test/FilterPeaksTest.h b/Framework/Crystal/test/FilterPeaksTest.h
index 2b45a5dad0a188c027ad0e27907b9e3211f4bae6..6947ea9fb102f93d4da702b1a22c71e53e0c2206 100644
--- a/Framework/Crystal/test/FilterPeaksTest.h
+++ b/Framework/Crystal/test/FilterPeaksTest.h
@@ -127,8 +127,8 @@ public:
     outWS = runAlgorithm(inWS, "h+k+l", h + k + l, "<=");
     TS_ASSERT_EQUALS(1, outWS->getNumberPeaks());
 
-    AnalysisDataService::Instance().remove(outWS->name());
-    AnalysisDataService::Instance().remove(inWS->name());
+    AnalysisDataService::Instance().remove(outWS->getName());
+    AnalysisDataService::Instance().remove(inWS->getName());
   }
 
   void test_filter_by_hkl_sq_sum() {
@@ -153,8 +153,8 @@ public:
     outWS = runAlgorithm(inWS, "h^2+k^2+l^2", h * h + k * k + l * l, "<=");
     TS_ASSERT_EQUALS(1, outWS->getNumberPeaks());
 
-    AnalysisDataService::Instance().remove(outWS->name());
-    AnalysisDataService::Instance().remove(inWS->name());
+    AnalysisDataService::Instance().remove(outWS->getName());
+    AnalysisDataService::Instance().remove(inWS->getName());
   }
 
   void test_filter_by_intensity() {
@@ -180,8 +180,8 @@ public:
     outWS = runAlgorithm(inWS, "Intensity", intensity, "<=");
     TS_ASSERT_EQUALS(1, outWS->getNumberPeaks());
 
-    AnalysisDataService::Instance().remove(outWS->name());
-    AnalysisDataService::Instance().remove(inWS->name());
+    AnalysisDataService::Instance().remove(outWS->getName());
+    AnalysisDataService::Instance().remove(inWS->getName());
   }
 
   void test_filter_by_signal_to_noise() {
@@ -209,8 +209,8 @@ public:
     outWS = runAlgorithm(inWS, "Signal/Noise", ratio, "<=");
     TS_ASSERT_EQUALS(1, outWS->getNumberPeaks());
 
-    AnalysisDataService::Instance().remove(outWS->name());
-    AnalysisDataService::Instance().remove(inWS->name());
+    AnalysisDataService::Instance().remove(outWS->getName());
+    AnalysisDataService::Instance().remove(inWS->getName());
   }
 };
 
diff --git a/Framework/Crystal/test/FindUBUsingFFTTest.h b/Framework/Crystal/test/FindUBUsingFFTTest.h
index 8666128f835f20a10d9dbb5832c0bc2ae9c64fe4..efa17e6c367388815c6192e6d2918ba50bd368d2 100644
--- a/Framework/Crystal/test/FindUBUsingFFTTest.h
+++ b/Framework/Crystal/test/FindUBUsingFFTTest.h
@@ -4,6 +4,7 @@
 #include <cxxtest/TestSuite.h>
 #include "MantidKernel/Timer.h"
 #include "MantidKernel/System.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Sample.h"
 
 #include "MantidCrystal/FindUBUsingFFT.h"
diff --git a/Framework/Crystal/test/FindUBUsingIndexedPeaksTest.h b/Framework/Crystal/test/FindUBUsingIndexedPeaksTest.h
index f33a81dd1a80da6ddbfa55654e7a74c87ad957f8..fc60c2c910fd55e8190620d88497193a36719204 100644
--- a/Framework/Crystal/test/FindUBUsingIndexedPeaksTest.h
+++ b/Framework/Crystal/test/FindUBUsingIndexedPeaksTest.h
@@ -4,6 +4,7 @@
 #include <cxxtest/TestSuite.h>
 #include "MantidKernel/Timer.h"
 #include "MantidKernel/System.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Sample.h"
 
 #include "MantidCrystal/FindUBUsingIndexedPeaks.h"
diff --git a/Framework/Crystal/test/FindUBUsingLatticeParametersTest.h b/Framework/Crystal/test/FindUBUsingLatticeParametersTest.h
index 22082cccdaf8cb1b6c55917b8e002cba82976518..540618630a36758e1c57cb74b30933ce734f9c0a 100644
--- a/Framework/Crystal/test/FindUBUsingLatticeParametersTest.h
+++ b/Framework/Crystal/test/FindUBUsingLatticeParametersTest.h
@@ -1,10 +1,12 @@
 #ifndef MANTID_CRYSTAL_FIND_UB_USING_LATTICE_PARAMETERS_TEST_H_
 #define MANTID_CRYSTAL_FIND_UB_USING_LATTICE_PARAMETERS_TEST_H_
 
-#include <cxxtest/TestSuite.h>
-#include "MantidKernel/Timer.h"
-#include "MantidKernel/System.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Sample.h"
+#include "MantidDataHandling/DeleteTableRows.h"
+#include "MantidKernel/System.h"
+#include "MantidKernel/Timer.h"
+#include <cxxtest/TestSuite.h>
 
 #include "MantidCrystal/FindUBUsingLatticeParameters.h"
 #include "MantidCrystal/LoadIsawPeaks.h"
@@ -27,28 +29,13 @@ public:
   }
 
   void test_exec() {
-    // Name of the output workspace.
-    std::string WSName("peaks");
-    LoadIsawPeaks loader;
-    TS_ASSERT_THROWS_NOTHING(loader.initialize());
-    TS_ASSERT(loader.isInitialized());
-    loader.setPropertyValue("Filename", "TOPAZ_3007.peaks");
-    loader.setPropertyValue("OutputWorkspace", WSName);
+    auto ws = loadPeaksWorkspace();
 
-    TS_ASSERT(loader.execute());
-    TS_ASSERT(loader.isExecuted());
-
-    PeaksWorkspace_sptr ws;
-    TS_ASSERT_THROWS_NOTHING(
-        ws = boost::dynamic_pointer_cast<PeaksWorkspace>(
-            AnalysisDataService::Instance().retrieve(WSName)));
-    TS_ASSERT(ws);
-    if (!ws)
-      return;
     FindUBUsingLatticeParameters alg;
     TS_ASSERT_THROWS_NOTHING(alg.initialize())
     TS_ASSERT(alg.isInitialized())
-    TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("PeaksWorkspace", WSName));
+    TS_ASSERT_THROWS_NOTHING(
+        alg.setPropertyValue("PeaksWorkspace", ws->getName()));
     TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("a", "14.131"));
     TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("b", "19.247"));
     TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("c", "8.606"));
@@ -75,8 +62,152 @@ public:
       TS_ASSERT_DELTA(correct_UB[i], UB_calculated[i], 5e-4);
     }
 
+    TS_ASSERT_DELTA(latt.a(), 14.131, 5e-4);
+    TS_ASSERT_DELTA(latt.b(), 19.247, 5e-4);
+    TS_ASSERT_DELTA(latt.c(), 8.606, 5e-4);
+
+    TS_ASSERT_DELTA(latt.alpha(), 90.0, 5e-1);
+    TS_ASSERT_DELTA(latt.beta(), 105.071, 5e-1);
+    TS_ASSERT_DELTA(latt.gamma(), 90.0, 5e-1);
+
+    // Check errors
+    TS_ASSERT_DELTA(latt.errora(), 0.0134, 5e-4);
+    TS_ASSERT_DELTA(latt.errorb(), 0.0243, 5e-4);
+    TS_ASSERT_DELTA(latt.errorc(), 0.0101, 5e-4);
+
+    TS_ASSERT_DELTA(latt.erroralpha(), 0.0994, 5e-4);
+    TS_ASSERT_DELTA(latt.errorbeta(), 0.0773, 5e-4);
+    TS_ASSERT_DELTA(latt.errorgamma(), 0.0906, 5e-4);
+
+    // Remove workspace from the data service.
+    AnalysisDataService::Instance().remove(ws->getName());
+  }
+
+  void test_fixAll() {
+    auto ws = loadPeaksWorkspace();
+
+    FindUBUsingLatticeParameters alg;
+    TS_ASSERT_THROWS_NOTHING(alg.initialize())
+    TS_ASSERT(alg.isInitialized())
+    TS_ASSERT_THROWS_NOTHING(
+        alg.setPropertyValue("PeaksWorkspace", ws->getName()));
+    TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("a", "14.131"));
+    TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("b", "19.247"));
+    TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("c", "8.606"));
+    TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("alpha", "90.0"));
+    TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("beta", "105.071"));
+    TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("gamma", "90.0"));
+    TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("NumInitial", "15"));
+    TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("Tolerance", "0.12"));
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("FixParameters", true));
+    TS_ASSERT_THROWS_NOTHING(alg.execute());
+    TS_ASSERT(alg.isExecuted());
+
+    // Check that we set an oriented lattice
+    TS_ASSERT(ws->mutableSample().hasOrientedLattice());
+    // Check that the UB matrix is the same as in TOPAZ_3007.mat
+    OrientedLattice latt = ws->mutableSample().getOrientedLattice();
+
+    double correct_UB[] = {0.04542050,  0.040619900, 0.0127661,
+                           -0.00198382, -0.00264404, -0.1165450,
+                           -0.05749760, 0.03223800,  -0.0257623};
+
+    std::vector<double> UB_calculated = latt.getUB().getVector();
+
+    for (size_t i = 0; i < 9; i++) {
+      TS_ASSERT_DELTA(correct_UB[i], UB_calculated[i], 5e-4);
+    }
+
+    TS_ASSERT_DELTA(latt.a(), 14.131, 5e-10);
+    TS_ASSERT_DELTA(latt.b(), 19.247, 5e-10);
+    TS_ASSERT_DELTA(latt.c(), 8.606, 5e-10);
+
+    TS_ASSERT_DELTA(latt.alpha(), 90.0, 5e-10);
+    TS_ASSERT_DELTA(latt.beta(), 105.071, 5e-10);
+    TS_ASSERT_DELTA(latt.gamma(), 90.0, 5e-10);
+
     // Remove workspace from the data service.
-    AnalysisDataService::Instance().remove(WSName);
+    AnalysisDataService::Instance().remove(ws->getName());
+  }
+
+  void test_smallNumberOfPeaks() {
+    // Use a tiny set of 3 peaks - the minimum required
+    /// to successfully find a UB matrix this checks the case that we still
+    /// get a UB (although perhaps not a very good one).
+    auto ws = loadPeaksWorkspace();
+    std::vector<size_t> rows;
+    for (size_t i = 3; i < ws->rowCount(); ++i) {
+      rows.push_back(i);
+    }
+
+    DataHandling::DeleteTableRows removeRowAlg;
+    removeRowAlg.initialize();
+    removeRowAlg.setPropertyValue("TableWorkspace", ws->getName());
+    removeRowAlg.setProperty("Rows", rows);
+    removeRowAlg.execute();
+
+    FindUBUsingLatticeParameters alg;
+    TS_ASSERT_THROWS_NOTHING(alg.initialize())
+    TS_ASSERT(alg.isInitialized())
+    TS_ASSERT_THROWS_NOTHING(
+        alg.setPropertyValue("PeaksWorkspace", ws->getName()));
+    TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("a", "14.131"));
+    TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("b", "19.247"));
+    TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("c", "8.606"));
+    TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("alpha", "90.0"));
+    TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("beta", "105.071"));
+    TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("gamma", "90.0"));
+    TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("NumInitial", "15"));
+    TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("Tolerance", "0.12"));
+    //    TS_ASSERT_THROWS_NOTHING(alg.setProperty("FixAll", true));
+    TS_ASSERT_THROWS_NOTHING(alg.execute());
+    TS_ASSERT(alg.isExecuted());
+
+    // Check that we set an oriented lattice
+    TS_ASSERT(ws->mutableSample().hasOrientedLattice());
+    // Check that the UB matrix is the same as in TOPAZ_3007.mat
+    OrientedLattice latt = ws->mutableSample().getOrientedLattice();
+
+    double correct_UB[] = {0.0450,  0.0407,  0.0127, -0.0008, -0.0044,
+                           -0.1158, -0.0584, 0.0307, -0.0242};
+
+    std::vector<double> UB_calculated = latt.getUB().getVector();
+
+    for (size_t i = 0; i < 9; i++) {
+      TS_ASSERT_DELTA(correct_UB[i], UB_calculated[i], 5e-4);
+    }
+    TS_ASSERT_DELTA(latt.a(), 13.9520, 5e-4);
+    TS_ASSERT_DELTA(latt.b(), 19.5145, 5e-4);
+    TS_ASSERT_DELTA(latt.c(), 8.6566, 5e-4);
+    TS_ASSERT_DELTA(latt.alpha(), 92.6267, 5e-4);
+    TS_ASSERT_DELTA(latt.beta(), 103.7440, 5e-4);
+    TS_ASSERT_DELTA(latt.gamma(), 90.0272, 5e-4);
+
+    // Remove workspace from the data service.
+    AnalysisDataService::Instance().remove(ws->getName());
+  }
+
+private:
+  /*
+   * Load a peaks workspace to use as input data
+   */
+  PeaksWorkspace_sptr loadPeaksWorkspace() const {
+    std::string WSName("peaks");
+    LoadIsawPeaks loader;
+    TS_ASSERT_THROWS_NOTHING(loader.initialize());
+    TS_ASSERT(loader.isInitialized());
+    loader.setPropertyValue("Filename", "TOPAZ_3007.peaks");
+    loader.setPropertyValue("OutputWorkspace", WSName);
+
+    TS_ASSERT(loader.execute());
+    TS_ASSERT(loader.isExecuted());
+
+    PeaksWorkspace_sptr ws;
+    TS_ASSERT_THROWS_NOTHING(
+        ws = boost::dynamic_pointer_cast<PeaksWorkspace>(
+            AnalysisDataService::Instance().retrieve(WSName)));
+    TS_ASSERT(ws);
+    return ws;
   }
 };
 
diff --git a/Framework/Crystal/test/FindUBUsingMinMaxDTest.h b/Framework/Crystal/test/FindUBUsingMinMaxDTest.h
index d39bd22926bc48d1fa9f55d00bd0250323e94aaa..c192e78b2e4666a4153991e12d91f79c731a767f 100644
--- a/Framework/Crystal/test/FindUBUsingMinMaxDTest.h
+++ b/Framework/Crystal/test/FindUBUsingMinMaxDTest.h
@@ -4,6 +4,7 @@
 #include <cxxtest/TestSuite.h>
 #include "MantidKernel/Timer.h"
 #include "MantidKernel/System.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Sample.h"
 
 #include "MantidCrystal/FindUBUsingMinMaxD.h"
diff --git a/Framework/Crystal/test/HasUBTest.h b/Framework/Crystal/test/HasUBTest.h
index 1fa14900271831068d1c01a0da41df08672d63cc..20a47032e5f84c5e7e9b87a944d82c774aed2f8b 100644
--- a/Framework/Crystal/test/HasUBTest.h
+++ b/Framework/Crystal/test/HasUBTest.h
@@ -21,7 +21,7 @@ class HasUBTest : public CxxTest::TestSuite {
 private:
   // Helper method to create a matrix workspace.
   std::string createMatrixWorkspace(const bool withOrientedLattice = true) {
-    auto ws = WorkspaceCreationHelper::Create2DWorkspace(1, 2);
+    auto ws = WorkspaceCreationHelper::create2DWorkspace(1, 2);
     if (withOrientedLattice) {
       OrientedLattice *latt = new OrientedLattice(1.0, 2.0, 3.0, 90, 90, 90);
       ws->mutableSample().setOrientedLattice(latt);
diff --git a/Framework/Crystal/test/IndexPeaksTest.h b/Framework/Crystal/test/IndexPeaksTest.h
index 2a4d066ca2d654438bdfc262222255dbff587229..8042fb3e5fa389fcfef58c9eda4ca75016ee70ab 100644
--- a/Framework/Crystal/test/IndexPeaksTest.h
+++ b/Framework/Crystal/test/IndexPeaksTest.h
@@ -4,6 +4,7 @@
 #include <cxxtest/TestSuite.h>
 #include "MantidKernel/Timer.h"
 #include "MantidKernel/System.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Sample.h"
 
 #include "MantidCrystal/IndexPeaks.h"
diff --git a/Framework/Crystal/test/IndexSXPeaksTest.h b/Framework/Crystal/test/IndexSXPeaksTest.h
index 67c6ab3140efbf7eb64e89e64dc514de3a62cfa9..abf8de06f31810d58034bba9f4a6599285d309f1 100644
--- a/Framework/Crystal/test/IndexSXPeaksTest.h
+++ b/Framework/Crystal/test/IndexSXPeaksTest.h
@@ -2,6 +2,7 @@
 #define INDEX_SX_PEAKS_TEST_H_
 
 #include <cxxtest/TestSuite.h>
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/ITableWorkspace.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidAPI/TableRow.h"
diff --git a/Framework/Crystal/test/LoadHKLTest.h b/Framework/Crystal/test/LoadHKLTest.h
index c3a29814ed2be30ef3b5d6edad9143e9d6ab176d..84395d8e9f99ec125bc7522def6d4f7363746590 100644
--- a/Framework/Crystal/test/LoadHKLTest.h
+++ b/Framework/Crystal/test/LoadHKLTest.h
@@ -9,6 +9,7 @@
 #include "MantidKernel/Material.h"
 #include "MantidKernel/System.h"
 #include "MantidKernel/Timer.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Run.h"
 #include "MantidAPI/Sample.h"
 #include "MantidTestHelpers/ComponentCreationHelper.h"
diff --git a/Framework/Crystal/test/LoadIsawPeaksTest.h b/Framework/Crystal/test/LoadIsawPeaksTest.h
index c39a8b2bfb4fe18c1e0affa3f2e8263212336b1d..c2b48afdea497c8ddda1e8a28a1476d7c71c2447 100644
--- a/Framework/Crystal/test/LoadIsawPeaksTest.h
+++ b/Framework/Crystal/test/LoadIsawPeaksTest.h
@@ -5,6 +5,7 @@
 #include "MantidCrystal/LoadIsawPeaks.h"
 #include "MantidDataObjects/Peak.h"
 #include "MantidDataObjects/PeaksWorkspace.h"
+#include "MantidGeometry/Instrument/Goniometer.h"
 #include "MantidKernel/Matrix.h"
 #include "MantidKernel/System.h"
 #include "MantidKernel/Timer.h"
diff --git a/Framework/Crystal/test/LoadIsawUBTest.h b/Framework/Crystal/test/LoadIsawUBTest.h
index dd991891e411921bc260cc070b14b32853e6e13f..aad1f9d4f15a96cbea4473d8a3e3a15e351a048b 100644
--- a/Framework/Crystal/test/LoadIsawUBTest.h
+++ b/Framework/Crystal/test/LoadIsawUBTest.h
@@ -30,7 +30,7 @@ public:
   void test_exec() {
     // Fake output WS
     MatrixWorkspace_sptr ws =
-        WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+        WorkspaceCreationHelper::create2DWorkspace(10, 10);
     AnalysisDataService::Instance().addOrReplace("LoadIsawUBTest_ws", ws);
 
     LoadIsawUB alg;
@@ -84,7 +84,7 @@ MaskPeaksWorkspace("TOPAZ_3007", "peaks")
    */
   void test_integration() {
     Workspace2D_sptr ws =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(10, 20);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(10, 20);
     PeaksWorkspace_sptr pw;
     AnalysisDataService::Instance().addOrReplace("TOPAZ_3007", ws);
 
@@ -94,7 +94,7 @@ MaskPeaksWorkspace("TOPAZ_3007", "peaks")
         "True");
 
     // Match the goniometer angles
-    WorkspaceCreationHelper::SetGoniometer(ws, 86.92, 135.00, -105.66);
+    WorkspaceCreationHelper::setGoniometer(ws, 86.92, 135.00, -105.66);
     // WorkspaceCreationHelper::SetGoniometer(ws, 0, 0, 0);
 
     // Load the .mat file into it
diff --git a/Framework/Crystal/test/OptimizeCrystalPlacementTest.h b/Framework/Crystal/test/OptimizeCrystalPlacementTest.h
index 582a25b2039fcc4ad448a83249b777f13d95b06e..f8984a84486aae7fecb5f9f60c294d70a3c3ff51 100644
--- a/Framework/Crystal/test/OptimizeCrystalPlacementTest.h
+++ b/Framework/Crystal/test/OptimizeCrystalPlacementTest.h
@@ -1,39 +1,65 @@
-/*
- * OptimizeCrystalPlacementTest.h
- *
- *  Created on: Mar 22, 2013
- *      Author: Ruth Mikkelson
- */
-
 #ifndef OPTIMIZECRYSTALPLACEMENTTEST_H_
 #define OPTIMIZECRYSTALPLACEMENTTEST_H_
+
 #include <cxxtest/TestSuite.h>
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidCrystal/LoadIsawPeaks.h"
+#include "MantidCrystal/LoadIsawUB.h"
 #include "MantidCrystal/OptimizeCrystalPlacement.h"
 #include "MantidCrystal/PeakHKLErrors.h"
 #include "MantidDataObjects/PeaksWorkspace.h"
-#include "MantidAPI/IFunction.h"
-#include "MantidCrystal/LoadIsawUB.h"
-#include "MantidCrystal/IndexPeaks.h"
-#include "MantidKernel/Matrix.h"
-#include "MantidDataObjects/TableWorkspace.h"
-#include "MantidAPI/AnalysisDataService.h"
 #include "MantidGeometry/Instrument/Goniometer.h"
-#include "MantidKernel/V3D.h"
-#include "MantidGeometry/Instrument/ParameterMap.h"
-#include "MantidGeometry/IObjComponent.h"
-#include "MantidAPI/ITableWorkspace.h"
-
-using namespace Mantid;
-using namespace Crystal;
 
+using Mantid::API::AnalysisDataService;
+using Mantid::API::ITableWorkspace;
+using Mantid::API::ITableWorkspace_sptr;
+using Mantid::API::Workspace_sptr;
+using Mantid::Crystal::PeakHKLErrors;
+using Mantid::Crystal::OptimizeCrystalPlacement;
+using Mantid::DataObjects::PeaksWorkspace;
 using Mantid::DataObjects::PeaksWorkspace_sptr;
-using Mantid::DataObjects::TableWorkspace_sptr;
-using Mantid::DataObjects::TableWorkspace_sptr;
 using Mantid::Geometry::Goniometer;
-using Mantid::Geometry::ParameterMap;
-using Mantid::Geometry::IObjComponent_const_sptr;
-using Mantid::API::ITableWorkspace;
+using Mantid::Geometry::Instrument;
+using Mantid::Kernel::Matrix;
+using Mantid::Kernel::V3D;
+
+namespace {
+using StringPairVector = std::vector<std::pair<std::string, std::string>>;
+using ResultType = std::pair<PeaksWorkspace_sptr, ITableWorkspace_sptr>;
+
+/**
+ * Run the OptimizeCrystalPlacement algorithm
+ * @param peaksWS Passed to the "PeaksWorkspace" property
+ * @param args Additional vector of arguments.
+ */
+ResultType
+runOptimizePlacement(const PeaksWorkspace_sptr &peaksWS,
+                     const StringPairVector &args = StringPairVector()) {
+  // This algorithm can not currently run without the ADS so add them and remove
+  // after
+  const std::string inputName("__runOptimizePlacement_PeaksWorkspace"),
+      modPeaksName("__runOptimizePlacement_ModPeaksWorkspace"),
+      fitTableName("__runOptimizePlacement_FitInfoTable");
+  auto &ads = AnalysisDataService::Instance();
+  ads.add(inputName, peaksWS);
+
+  OptimizeCrystalPlacement alg;
+  alg.initialize();
+  alg.setPropertyValue("PeaksWorkspace", inputName);
+  alg.setPropertyValue("ModifiedPeaksWorkspace", modPeaksName);
+  alg.setPropertyValue("FitInfoTable", fitTableName);
+  for (const auto &arg : args) {
+    alg.setPropertyValue(arg.first, arg.second);
+  }
+  alg.execute();
+  auto modifiedPeaksWS = ads.retrieveWS<PeaksWorkspace>(modPeaksName);
+  auto fitInfoWS = ads.retrieveWS<ITableWorkspace>(fitTableName);
+  ads.remove(inputName);
+  ads.remove(modPeaksName);
+  ads.remove(fitTableName);
+  return std::make_pair(modifiedPeaksWS, fitInfoWS);
+}
+}
 
 class OptimizeCrystalPlacementTest : public CxxTest::TestSuite {
 
@@ -47,223 +73,172 @@ public:
     delete suite;
   }
 
-  OptimizeCrystalPlacementTest() { initted = false; }
-
-  void init() {
-    if (initted)
-      return;
-    initted = true;
-    LoadIsawPeaks alg;
-    alg.initialize();
-    alg.setProperty("Filename", "TOPAZ_5637_8.peaks");
-    alg.setProperty("OutputWorkspace", "abcd");
-    alg.execute();
-
-    alg.setProperty("OutputWorkspace", "abcd");
-    API::Workspace_sptr ows = alg.getProperty("OutputWorkspace");
-    peaks = boost::dynamic_pointer_cast<DataObjects::PeaksWorkspace>(ows);
-
-    LoadIsawUB loadUB;
-    loadUB.initialize();
-    loadUB.setProperty("InputWorkspace",
-                       alg.getPropertyValue("OutputWorkspace"));
-    loadUB.setProperty("Filename", "ls5637.mat");
-    loadUB.execute();
-
-    // peaks->setName("abcd");
-  }
   void test_basic() {
-    init();
-    OptimizeCrystalPlacement alg;
-    alg.initialize();
-    alg.setPropertyValue("PeaksWorkspace", "abcd");
-    alg.setProperty("PeaksWorkspace", peaks);
-    alg.setPropertyValue("ModifiedPeaksWorkspace", "ModPeaks");
-    alg.setPropertyValue("FitInfoTable", "FitInfoTable");
-    alg.execute();
-
-    alg.setPropertyValue("ModifiedPeaksWorkspace", "ModPeaks");
-    peaks1 = alg.getProperty("ModifiedPeaksWorkspace");
-    alg.setPropertyValue("FitInfoTable", "FitInfoTable");
-    boost::shared_ptr<ITableWorkspace> table = alg.getProperty("FitInfoTable");
-
-    Kernel::Matrix<double> Gon;
-    Gon.zeroMatrix();
-    Kernel::Matrix<double> ZMat(Gon);
-
-    Kernel::Matrix<double> Rotx =
-        PeakHKLErrors::RotationMatrixAboutRegAxis(0.5, 'x');
-    Kernel::Matrix<double> Roty =
-        PeakHKLErrors::RotationMatrixAboutRegAxis(-1, 'y');
-
-    for (int i = 0; i < peaks1->getNumberPeaks(); ++i)
-      if (peaks1->getPeak(i).getRunNumber() == 5638) {
-        Geometry::IPeak &peak = peaks1->getPeak(i);
-        if (Gon == ZMat) {
-          origGon5638 = peak.getGoniometerMatrix();
-          Gon = Rotx * Roty * origGon5638;
+    auto modPeaksNoFix = calculateBasicPlacement();
+    Matrix<double> goniomMat, origGon5638Mat;
+    const auto rotx = PeakHKLErrors::RotationMatrixAboutRegAxis(0.5, 'x');
+    const auto roty = PeakHKLErrors::RotationMatrixAboutRegAxis(-1, 'y');
+
+    const auto npeaks = modPeaksNoFix->getNumberPeaks();
+    for (int i = 0; i < npeaks; ++i) {
+      if (modPeaksNoFix->getPeak(i).getRunNumber() == 5638) {
+        auto &peak = modPeaksNoFix->getPeak(i);
+        if (origGon5638Mat.numRows() == 0) {
+          origGon5638Mat = peak.getGoniometerMatrix();
+          goniomMat = rotx * roty * origGon5638Mat;
         }
-        peak.setGoniometerMatrix(Gon);
+        peak.setGoniometerMatrix(goniomMat);
       }
-    Geometry::Goniometer GonInst(Gon);
-    std::vector<double> chiphiOmega = GonInst.getEulerAngles("YZY");
-
-    OptimizeCrystalPlacement alg1;
-    alg1.initialize();
-    API::AnalysisDataService::Instance().addOrReplace("abcd1", peaks1);
-
-    alg1.setPropertyValue("PeaksWorkspace", "abcd1");
-    alg1.setPropertyValue("ModifiedPeaksWorkspace", "ModPeaks");
-    alg1.setPropertyValue("FitInfoTable", "FitInfoTable1");
-    alg1.setProperty("KeepGoniometerFixedfor", "5637");
-    alg1.execute();
-
-    alg1.setPropertyValue("FitInfoTable", "FitInfoTable1");
-    table = alg1.getProperty("FitInfoTable");
-
-    Geometry::Goniometer IGon(origGon5638);
-    std::vector<double> GonAngles5638 = IGon.getEulerAngles("YZY");
-
-    for (size_t i = 0; i < table->rowCount(); ++i) {
-      std::string nm = table->String(i, 0);
+    }
+    Goniometer instGoniom(goniomMat);
+    auto resultsFix5637 = runOptimizePlacement(
+        modPeaksNoFix, {{"KeepGoniometerFixedfor", "5637"}});
+    auto fitInfoFix5637 = resultsFix5637.second;
+    const auto angles5638 = Goniometer(origGon5638Mat).getEulerAngles("YZY");
+
+    for (size_t i = 0; i < fitInfoFix5637->rowCount(); ++i) {
+      const std::string nm = fitInfoFix5637->String(i, 0);
       double d = 0.0;
       if (nm == "chi5638")
-        d = GonAngles5638[1] - table->Double(i, 1);
+        d = angles5638[1] - fitInfoFix5637->Double(i, 1);
       else if (nm == "phi5638")
-        d = GonAngles5638[2] - table->Double(i, 1);
+        d = angles5638[2] - fitInfoFix5637->Double(i, 1);
       else if (nm == "omega5638")
-        d = GonAngles5638[0] - table->Double(i, 1);
-      TS_ASSERT_DELTA(d, 0, .3);
+        d = angles5638[0] - fitInfoFix5637->Double(i, 1);
+      TS_ASSERT_DELTA(d, 0, .4);
     }
   }
 
   void test_tilt() {
-    init();
-    Kernel::Matrix<double> tilt =
-        PeakHKLErrors::RotationMatrixAboutRegAxis(1, 'x') *
-        PeakHKLErrors::RotationMatrixAboutRegAxis(-2, 'y') *
-        PeakHKLErrors::RotationMatrixAboutRegAxis(1.3, 'z');
-
-    origGon5637.zeroMatrix();
-    Kernel::Matrix<double> ZMat;
-    ZMat.zeroMatrix();
+    auto modPeaksNoFix = calculateBasicPlacement();
+    const auto rotx = PeakHKLErrors::RotationMatrixAboutRegAxis(0.5, 'x');
+    const auto roty = PeakHKLErrors::RotationMatrixAboutRegAxis(-1, 'y');
+
+    Matrix<double> goniomMat, origGon5638Mat;
+    const auto npeaks = modPeaksNoFix->getNumberPeaks();
+    for (int i = 0; i < npeaks; ++i) {
+      if (modPeaksNoFix->getPeak(i).getRunNumber() == 5638) {
+        auto &peak = modPeaksNoFix->getPeak(i);
+        if (origGon5638Mat.numRows() == 0) {
+          origGon5638Mat = peak.getGoniometerMatrix();
+          goniomMat = rotx * roty * origGon5638Mat;
+        }
+        peak.setGoniometerMatrix(goniomMat);
+      }
+    }
 
-    for (int i = 0; i < peaks1->getNumberPeaks(); ++i) {
-      Geometry::IPeak &peak = peaks1->getPeak(i);
-      int RunNum = peak.getRunNumber();
+    const auto tilt = PeakHKLErrors::RotationMatrixAboutRegAxis(1, 'x') *
+                      PeakHKLErrors::RotationMatrixAboutRegAxis(-2, 'y') *
+                      PeakHKLErrors::RotationMatrixAboutRegAxis(1.3, 'z');
 
-      Kernel::Matrix<double> GG;
-      if (RunNum == 5637) {
-        if (origGon5637 == ZMat)
-          origGon5637 = peak.getGoniometerMatrix();
+    Matrix<double> origGon5637Mat;
+    for (int i = 0; i < npeaks; ++i) {
+      auto &peak = modPeaksNoFix->getPeak(i);
+      const int runNum = peak.getRunNumber();
 
-        peak.setGoniometerMatrix(tilt * origGon5637);
+      if (runNum == 5637) {
+        if (origGon5637Mat.numRows() == 0) {
+          origGon5637Mat = peak.getGoniometerMatrix();
+        }
+        peak.setGoniometerMatrix(tilt * origGon5637Mat);
       } else
-        peak.setGoniometerMatrix(tilt * origGon5638);
+        peak.setGoniometerMatrix(tilt * origGon5638Mat);
     }
 
-    Geometry::Goniometer IGon(origGon5638);
-    std::vector<double> GonAngles5638 = IGon.getEulerAngles("YZY");
-
-    Geometry::Goniometer IGon2(origGon5637);
-    std::vector<double> GonAngles5637 = IGon2.getEulerAngles("YZY");
+    const auto angles5638 = Goniometer(origGon5638Mat).getEulerAngles("YZY");
+    const auto angles5637 = Goniometer(origGon5637Mat).getEulerAngles("YZY");
+    const auto resultsTiltFixBoth = runOptimizePlacement(
+        modPeaksNoFix, {{"KeepGoniometerFixedfor", "5637, 5638"},
+                        {"OptimizeGoniometerTilt", "1"}});
 
-    OptimizeCrystalPlacement alg;
-    alg.initialize();
-    API::AnalysisDataService::Instance().addOrReplace("abcd2", peaks1);
-
-    alg.setPropertyValue("PeaksWorkspace", "abcd2");
-    alg.setPropertyValue("ModifiedPeaksWorkspace", "ModPeaks");
-    alg.setPropertyValue("FitInfoTable", "FitInfoTable2");
-    alg.setProperty("KeepGoniometerFixedfor", "5637,5638");
-    alg.setProperty("OptimizeGoniometerTilt", true);
-    alg.execute();
-    alg.setPropertyValue("FitInfoTable", "FitInfoTable2");
-    boost::shared_ptr<ITableWorkspace> table = alg.getProperty("FitInfoTable");
-
-    Kernel::V3D Rotxyz;
+    const auto table = resultsTiltFixBoth.second;
+    V3D rotXYZ;
     for (size_t i = 0; i < table->rowCount(); ++i) {
-      std::string nm = table->String(i, 0);
-
+      const std::string nm = table->String(i, 0);
       if (nm == "GonRotx")
-        Rotxyz[0] = table->Double(i, 1);
-
+        rotXYZ[0] = table->Double(i, 1);
       else if (nm == "GonRoty")
-        Rotxyz[1] = table->Double(i, 1);
-
+        rotXYZ[1] = table->Double(i, 1);
       else if (nm == "GonRotz")
-        Rotxyz[2] = table->Double(i, 1);
+        rotXYZ[2] = table->Double(i, 1);
     }
 
-    Kernel::Matrix<double> tilt2 =
-        PeakHKLErrors::RotationMatrixAboutRegAxis(Rotxyz[0], 'x') *
-        PeakHKLErrors::RotationMatrixAboutRegAxis(Rotxyz[1], 'y') *
-        PeakHKLErrors::RotationMatrixAboutRegAxis(Rotxyz[2], 'z');
-
-    Kernel::Matrix<double> Change = tilt2 * tilt;
-
-    Geometry::Goniometer IGon3(Change * origGon5637);
-    std::vector<double> GonAngles5637a = IGon3.getEulerAngles("YZY");
-
-    Geometry::Goniometer IGon4(Change * origGon5638);
-    std::vector<double> GonAngles5638a = IGon4.getEulerAngles("YZY");
+    const auto tilt2 =
+        PeakHKLErrors::RotationMatrixAboutRegAxis(rotXYZ[0], 'x') *
+        PeakHKLErrors::RotationMatrixAboutRegAxis(rotXYZ[1], 'y') *
+        PeakHKLErrors::RotationMatrixAboutRegAxis(rotXYZ[2], 'z');
+    const auto tiltChange = tilt2 * tilt;
+    const auto angles5637a =
+        Goniometer(tiltChange * origGon5637Mat).getEulerAngles("YZY");
+    const auto angles5638a =
+        Goniometer(tiltChange * origGon5638Mat).getEulerAngles("YZY");
 
     for (int i = 0; i < 3; i++) {
-      TS_ASSERT_DELTA(GonAngles5637[i], GonAngles5637a[i], .2);
-      TS_ASSERT_DELTA(GonAngles5638[i], GonAngles5638a[i], .15);
+      TS_ASSERT_DELTA(angles5637[i], angles5637a[i], .2);
+      TS_ASSERT_DELTA(angles5638[i], angles5638a[i], .15);
     }
   }
 
   void test_SamplePosition() {
-    init();
-    Geometry::IPeak &peak = peaks1->getPeak(0);
-    boost::shared_ptr<const Geometry::Instrument> Inst = peak.getInstrument();
-    Kernel::V3D SampPos(.0003, -.00025, .00015);
-
-    boost::shared_ptr<Geometry::ParameterMap> pmap =
-        Inst->getParameterMap(); // check if parameterized.
-    Geometry::IComponent_const_sptr sample = Inst->getSample();
-
-    pmap->addPositionCoordinate(sample.get(), "x", SampPos.X());
-    pmap->addPositionCoordinate(sample.get(), "y", SampPos.Y());
-    pmap->addPositionCoordinate(sample.get(), "z", SampPos.Z());
-    boost::shared_ptr<const Geometry::Instrument> newInstr(
-        new Geometry::Instrument(Inst->baseInstrument(), pmap));
-
-    for (int i = 0; i < peaks1->getNumberPeaks(); ++i)
-      peaks1->getPeak(i).setInstrument(newInstr);
-    OptimizeCrystalPlacement alg;
-    alg.initialize();
-
-    API::AnalysisDataService::Instance().addOrReplace("abcd3", peaks1);
-
-    alg.setPropertyValue("PeaksWorkspace", "abcd3");
-    alg.setPropertyValue("ModifiedPeaksWorkspace", "ModPeaks");
-    alg.setPropertyValue("FitInfoTable", "FitInfoTable2");
-    alg.setProperty("KeepGoniometerFixedfor", "5637,5638");
-    alg.setProperty("AdjustSampleOffsets", true);
-    alg.execute();
-
-    alg.setPropertyValue("FitInfoTable", "FitInfoTable2");
-    boost::shared_ptr<ITableWorkspace> table = alg.getProperty("FitInfoTable");
+    auto modPeaksNoFix = calculateBasicPlacement();
+    const auto &peak = modPeaksNoFix->getPeak(0);
+    auto inst = peak.getInstrument();
+    const V3D sampPos(.0003, -.00025, .00015);
+
+    auto pmap = inst->getParameterMap();
+    auto sample = inst->getSample();
+    pmap->addPositionCoordinate(sample.get(), "x", sampPos.X());
+    pmap->addPositionCoordinate(sample.get(), "y", sampPos.Y());
+    pmap->addPositionCoordinate(sample.get(), "z", sampPos.Z());
+    auto newInst =
+        boost::make_shared<const Instrument>(inst->baseInstrument(), pmap);
+
+    for (int i = 0; i < modPeaksNoFix->getNumberPeaks(); ++i) {
+      modPeaksNoFix->getPeak(i).setInstrument(newInst);
+    }
 
+    // optimize
+    const auto resultsSamplePos = runOptimizePlacement(
+        modPeaksNoFix, {{"KeepGoniometerFixedfor", "5637, 5638"},
+                        {"AdjustSampleOffsets", "1"}});
+    const auto table = resultsSamplePos.second;
     TS_ASSERT_DELTA(table->Double(0, 1), 0, .00024);
     TS_ASSERT_DELTA(table->Double(1, 1), 0, .00024);
     TS_ASSERT_DELTA(table->Double(2, 1), 0, .00024);
-
-    /*  for (size_t i = 0; i < table->rowCount(); ++i)
-       {
-       std::string nm = table->String(i, 0);
-       std::cout<<nm<<","<<table->Double(i,1)<<","<<table->Double(i,2)<<'\n';
-       }
-  */
   }
 
 private:
-  DataObjects::PeaksWorkspace_sptr peaks;
-  DataObjects::PeaksWorkspace_sptr peaks1;
-  Kernel::Matrix<double> origGon5637, origGon5638;
-  bool initted;
+  // Helper method to load peaks and optimize them in the basic
+  // case. Caches the result the first time it is called
+  PeaksWorkspace_sptr calculateBasicPlacement() {
+    if (!m_inputPeaksWS) {
+      m_inputPeaksWS = loadTestPeaksInput();
+    }
+    return runOptimizePlacement(m_inputPeaksWS).first;
+  }
+
+  PeaksWorkspace_sptr loadTestPeaksInput() {
+    using Mantid::Crystal::LoadIsawPeaks;
+    using Mantid::Crystal::LoadIsawUB;
+    // Load peaks input file and UB
+    LoadIsawPeaks alg;
+    alg.setChild(true);
+    alg.initialize();
+    alg.setProperty("Filename", "TOPAZ_5637_8.peaks");
+    alg.setProperty("OutputWorkspace", "__");
+    alg.execute();
+    Workspace_sptr peaksWS = alg.getProperty("OutputWorkspace");
+    LoadIsawUB loadUB;
+    loadUB.setChild(true);
+    loadUB.initialize();
+    loadUB.setProperty("InputWorkspace", peaksWS);
+    loadUB.setProperty("Filename", "ls5637.mat");
+    loadUB.execute();
+    Workspace_sptr ows = loadUB.getProperty("InputWorkspace");
+    return boost::dynamic_pointer_cast<PeaksWorkspace>(ows);
+  }
+
+  PeaksWorkspace_sptr m_inputPeaksWS;
 };
 
 #endif /* OPTIMIZECRYSTALPLACEMENTTEST_H_ */
diff --git a/Framework/Crystal/test/OptimizeLatticeForCellTypeTest.h b/Framework/Crystal/test/OptimizeLatticeForCellTypeTest.h
index 252fadaa9880427a921948dee2aa73011318b674..cf4b10c0195e36e631073d20fe73ac5d435bfc1d 100644
--- a/Framework/Crystal/test/OptimizeLatticeForCellTypeTest.h
+++ b/Framework/Crystal/test/OptimizeLatticeForCellTypeTest.h
@@ -4,6 +4,7 @@
 #include <cxxtest/TestSuite.h>
 #include "MantidKernel/Timer.h"
 #include "MantidKernel/System.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Sample.h"
 
 #include "MantidCrystal/OptimizeLatticeForCellType.h"
diff --git a/Framework/Crystal/test/PeakIntensityVsRadiusTest.h b/Framework/Crystal/test/PeakIntensityVsRadiusTest.h
index 8827c402542949544d3bad22c35facc724f0f0d2..9cae1b19c9f03c37dbaff81575b79e3bb4189617 100644
--- a/Framework/Crystal/test/PeakIntensityVsRadiusTest.h
+++ b/Framework/Crystal/test/PeakIntensityVsRadiusTest.h
@@ -2,6 +2,7 @@
 #define MANTID_CRYSTAL_PEAKINTENSITYVSRADIUSTEST_H_
 
 #include "MantidCrystal/PeakIntensityVsRadius.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidDataObjects/Peak.h"
 #include "MantidDataObjects/PeaksWorkspace.h"
diff --git a/Framework/Crystal/test/PredictPeaksTest.h b/Framework/Crystal/test/PredictPeaksTest.h
index 7ad049ace70959f769c6e9b5e12a299e6ad437ab..4e746bbd7ebc91cd819439a75df3d5cc99f31654 100644
--- a/Framework/Crystal/test/PredictPeaksTest.h
+++ b/Framework/Crystal/test/PredictPeaksTest.h
@@ -11,6 +11,7 @@
 #include <cxxtest/TestSuite.h>
 #include "MantidKernel/V3D.h"
 #include "MantidGeometry/IDTypes.h"
+#include "MantidGeometry/Instrument/Goniometer.h"
 #include "MantidKernel/ConfigService.h"
 #include "MantidAPI/Sample.h"
 
@@ -46,20 +47,20 @@ public:
   }
 
   void do_test_exec(std::string reflectionCondition, size_t expectedNumber,
-                    std::vector<V3D> hkls) {
+                    std::vector<V3D> hkls, int convention = 1) {
     // Name of the output workspace.
     std::string outWSName("PredictPeaksTest_OutputWS");
 
     // Make the fake input workspace
     MatrixWorkspace_sptr inWS =
-        WorkspaceCreationHelper::Create2DWorkspace(10000, 1);
+        WorkspaceCreationHelper::create2DWorkspace(10000, 1);
     Instrument_sptr inst =
         ComponentCreationHelper::createTestInstrumentRectangular(1, 100);
     inWS->setInstrument(inst);
 
     // Set ub and Goniometer rotation
-    WorkspaceCreationHelper::SetOrientedLattice(inWS, 12.0, 12.0, 12.0);
-    WorkspaceCreationHelper::SetGoniometer(inWS, 0., 0., 0.);
+    WorkspaceCreationHelper::setOrientedLattice(inWS, 12.0, 12.0, 12.0);
+    WorkspaceCreationHelper::setGoniometer(inWS, 0., 0., 0.);
 
     PeaksWorkspace_sptr hklPW = getHKLpw(inst, hkls, 10000);
 
@@ -89,7 +90,10 @@ public:
       return;
 
     TS_ASSERT_EQUALS(ws->getNumberPeaks(), expectedNumber);
-    // std::cout << ws->getPeak(0).getHKL() << " hkl\n";
+    V3D hklTest(-10, -6, 1);
+    hklTest *= convention;
+    if (expectedNumber > 1)
+      TS_ASSERT_EQUALS(ws->getPeak(0).getHKL(), hklTest);
 
     // Remove workspace from the data service.
     AnalysisDataService::Instance().remove(outWSName);
@@ -118,13 +122,13 @@ public:
 
     // Make the fake input workspace
     MatrixWorkspace_sptr inWS =
-        WorkspaceCreationHelper::Create2DWorkspace(10000, 1);
+        WorkspaceCreationHelper::create2DWorkspace(10000, 1);
     Instrument_sptr inst =
         ComponentCreationHelper::createTestInstrumentRectangular2(1, 100);
     inWS->setInstrument(inst);
 
     // Set ub and Goniometer rotation
-    WorkspaceCreationHelper::SetOrientedLattice(inWS, 10.0, 10.0, 10.0);
+    WorkspaceCreationHelper::setOrientedLattice(inWS, 10.0, 10.0, 10.0);
 
     // Make a U matrix of 22.5 degree rotation around +Y
     DblMatrix u(3, 3);
@@ -136,7 +140,7 @@ public:
 
     // Final rotation should add up to 45 degrees around +Y so that hkl 1,0,0
     // goes to +X
-    WorkspaceCreationHelper::SetGoniometer(inWS, GonioRotation, 0., 0.);
+    WorkspaceCreationHelper::setGoniometer(inWS, GonioRotation, 0., 0.);
 
     DblMatrix ub = inWS->sample().getOrientedLattice().getUB();
     PeaksWorkspace_sptr hklPW = getHKLpw(inst, {{-1, 0, 0}}, 0);
@@ -178,7 +182,7 @@ public:
   void test_crystallography() {
     Kernel::ConfigService::Instance().setString("Q.convention",
                                                 "Crystallography");
-    do_test_exec("Primitive", 10, std::vector<V3D>());
+    do_test_exec("Primitive", 10, std::vector<V3D>(), -1);
   }
 };
 
diff --git a/Framework/Crystal/test/SCDCalibratePanelsTest.h b/Framework/Crystal/test/SCDCalibratePanelsTest.h
index 627403b8803f7ea447952b238e0af56561dc47d1..ac348e0a5b840e245f8a85aa7354f45aaf5c7f21 100644
--- a/Framework/Crystal/test/SCDCalibratePanelsTest.h
+++ b/Framework/Crystal/test/SCDCalibratePanelsTest.h
@@ -9,6 +9,7 @@
 #define SCDCALIBRATEPANELSTEST_H_
 
 #include <cxxtest/TestSuite.h>
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidCrystal/SCDCalibratePanels.h"
 
 using namespace Mantid::API;
diff --git a/Framework/Crystal/test/SaveIsawUBTest.h b/Framework/Crystal/test/SaveIsawUBTest.h
index 77b9ce5e690cf6b1e5d5e6a432459dacf592f8b3..b4917fc7d821f170da2edd0db4b49cef07f79492 100644
--- a/Framework/Crystal/test/SaveIsawUBTest.h
+++ b/Framework/Crystal/test/SaveIsawUBTest.h
@@ -43,7 +43,7 @@ public:
   void test_exec() {
     // Fake output WS
     MatrixWorkspace_sptr ws =
-        WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+        WorkspaceCreationHelper::create2DWorkspace(10, 10);
     AnalysisDataService::Instance().addOrReplace("LoadIsawUBTest_ws", ws);
 
     std::string File1, File2;
diff --git a/Framework/Crystal/test/SelectCellOfTypeTest.h b/Framework/Crystal/test/SelectCellOfTypeTest.h
index 101eb3830c21b504887690ef3333e04618bb9b4c..a89c12976b28ddc4c7bfabe043e5edd840e3058b 100644
--- a/Framework/Crystal/test/SelectCellOfTypeTest.h
+++ b/Framework/Crystal/test/SelectCellOfTypeTest.h
@@ -10,6 +10,7 @@
 #include "MantidGeometry/Crystal/IndexingUtils.h"
 #include "MantidGeometry/Crystal/OrientedLattice.h"
 #include "MantidCrystal/LoadIsawUB.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Sample.h"
 
 using namespace Mantid;
diff --git a/Framework/Crystal/test/SelectCellWithFormTest.h b/Framework/Crystal/test/SelectCellWithFormTest.h
index eb5538814cebd1b3fec7714504ea49dbe5117b48..4f684f1214744df4e520d0e23831fc3b7eed5855 100644
--- a/Framework/Crystal/test/SelectCellWithFormTest.h
+++ b/Framework/Crystal/test/SelectCellWithFormTest.h
@@ -10,6 +10,7 @@
 #include "MantidGeometry/Crystal/IndexingUtils.h"
 #include "MantidGeometry/Crystal/OrientedLattice.h"
 #include "MantidCrystal/LoadIsawUB.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Sample.h"
 
 using namespace Mantid;
diff --git a/Framework/Crystal/test/SetGoniometerTest.h b/Framework/Crystal/test/SetGoniometerTest.h
index 7380082ff01a431c1cb76887ca0fecbdb95b610f..3b0013159e81e47f2a03a25f57e8c773fa8b0ceb 100644
--- a/Framework/Crystal/test/SetGoniometerTest.h
+++ b/Framework/Crystal/test/SetGoniometerTest.h
@@ -30,7 +30,7 @@ public:
   }
 
   void test_exec_fail() {
-    Workspace2D_sptr ws = WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+    Workspace2D_sptr ws = WorkspaceCreationHelper::create2DWorkspace(10, 10);
     AnalysisDataService::Instance().addOrReplace("SetGoniometerTest_ws", ws);
 
     SetGoniometer alg;
@@ -48,7 +48,7 @@ public:
 
   /** Create an "empty" goniometer by NOT giving any axes. */
   void test_exec_emptyGoniometer() {
-    Workspace2D_sptr ws = WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+    Workspace2D_sptr ws = WorkspaceCreationHelper::create2DWorkspace(10, 10);
     AnalysisDataService::Instance().addOrReplace("SetGoniometerTest_ws", ws);
 
     SetGoniometer alg;
@@ -69,7 +69,7 @@ public:
   }
 
   void test_exec() {
-    Workspace2D_sptr ws = WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+    Workspace2D_sptr ws = WorkspaceCreationHelper::create2DWorkspace(10, 10);
     AnalysisDataService::Instance().addOrReplace("SetGoniometerTest_ws", ws);
     FrameworkManager::Instance().exec(
         "AddSampleLog", 8, "Workspace", "SetGoniometerTest_ws", "LogName",
@@ -112,7 +112,7 @@ public:
     AnalysisDataService::Instance().remove("SetGoniometerTest_ws");
   }
   void test_universal() {
-    Workspace2D_sptr ws = WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+    Workspace2D_sptr ws = WorkspaceCreationHelper::create2DWorkspace(10, 10);
     AnalysisDataService::Instance().addOrReplace("SetUnivGoniometerTest_ws",
                                                  ws);
     FrameworkManager::Instance().exec(
@@ -152,7 +152,7 @@ public:
    * @param numExpected :: how many axes should be created (0 or 1)
    */
   void do_test_param(std::string axis0, size_t numExpected = 0) {
-    Workspace2D_sptr ws = WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+    Workspace2D_sptr ws = WorkspaceCreationHelper::create2DWorkspace(10, 10);
     AnalysisDataService::Instance().addOrReplace("SetGoniometerTest_ws", ws);
     FrameworkManager::Instance().exec(
         "AddSampleLog", 8, "Workspace", "SetGoniometerTest_ws", "LogName",
diff --git a/Framework/Crystal/test/SetUBTest.h b/Framework/Crystal/test/SetUBTest.h
index caa445891fdee1b32c1ec647d0e81920421b0b5c..7ce080fe464dd032985e8df94996f2eed3515700 100644
--- a/Framework/Crystal/test/SetUBTest.h
+++ b/Framework/Crystal/test/SetUBTest.h
@@ -39,7 +39,7 @@ public:
     std::string wsName("SetUBTest_WS");
     // Fake output WS
     MatrixWorkspace_sptr ws =
-        WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+        WorkspaceCreationHelper::create2DWorkspace(10, 10);
     AnalysisDataService::Instance().addOrReplace(wsName, ws);
 
     SetUB alg;
@@ -79,7 +79,7 @@ public:
     std::string wsName("SetUBTest_WS");
     // Fake output WS
     MatrixWorkspace_sptr ws =
-        WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+        WorkspaceCreationHelper::create2DWorkspace(10, 10);
     AnalysisDataService::Instance().addOrReplace(wsName, ws);
 
     SetUB alg;
@@ -126,7 +126,7 @@ public:
     std::string wsName("SetUBTest_WS");
     // Fake output WS
     MatrixWorkspace_sptr ws =
-        WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+        WorkspaceCreationHelper::create2DWorkspace(10, 10);
     AnalysisDataService::Instance().addOrReplace(wsName, ws);
 
     SetUB alg;
@@ -151,7 +151,7 @@ public:
     std::string wsName("SetUBTest_WS");
     // Fake output WS
     MatrixWorkspace_sptr ws =
-        WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+        WorkspaceCreationHelper::create2DWorkspace(10, 10);
     AnalysisDataService::Instance().addOrReplace(wsName, ws);
 
     SetUB alg;
@@ -173,7 +173,7 @@ public:
     std::string wsName("SetUBTest_WS");
     // Fake output WS
     MatrixWorkspace_sptr ws =
-        WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+        WorkspaceCreationHelper::create2DWorkspace(10, 10);
     AnalysisDataService::Instance().addOrReplace(wsName, ws);
 
     SetUB alg;
@@ -196,7 +196,7 @@ public:
     std::string wsName("SetUBTest_WS");
     // Fake output WS
     MatrixWorkspace_sptr ws =
-        WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+        WorkspaceCreationHelper::create2DWorkspace(10, 10);
     AnalysisDataService::Instance().addOrReplace(wsName, ws);
 
     SetUB alg;
diff --git a/Framework/Crystal/test/ShowPossibleCellsTest.h b/Framework/Crystal/test/ShowPossibleCellsTest.h
index b036c34003296a5e5f086d55582a964a30375f0b..e7b519d3e023f073d9f50c7c1835efa6e655cda0 100644
--- a/Framework/Crystal/test/ShowPossibleCellsTest.h
+++ b/Framework/Crystal/test/ShowPossibleCellsTest.h
@@ -10,6 +10,7 @@
 #include "MantidGeometry/Crystal/IndexingUtils.h"
 #include "MantidGeometry/Crystal/OrientedLattice.h"
 #include "MantidCrystal/LoadIsawUB.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Sample.h"
 
 using namespace Mantid;
diff --git a/Framework/Crystal/test/SortHKLTest.h b/Framework/Crystal/test/SortHKLTest.h
index 1cd0517b08fd284a63c8a2bb4c5300885bc1980b..db8210cfd56239f17121b21a750e2e0e1903e849 100644
--- a/Framework/Crystal/test/SortHKLTest.h
+++ b/Framework/Crystal/test/SortHKLTest.h
@@ -8,6 +8,7 @@
 #include "MantidKernel/Material.h"
 #include "MantidKernel/System.h"
 #include "MantidKernel/Timer.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Run.h"
 #include "MantidAPI/Sample.h"
 #include "MantidTestHelpers/ComponentCreationHelper.h"
diff --git a/Framework/Crystal/test/StatisticsOfPeaksWorkspaceTest.h b/Framework/Crystal/test/StatisticsOfPeaksWorkspaceTest.h
index e1b6b7a36fc55dbba80567e5fa6b83a39cd51a51..62516ad9472c07b69c23b3e2bf4bef5ed332113b 100644
--- a/Framework/Crystal/test/StatisticsOfPeaksWorkspaceTest.h
+++ b/Framework/Crystal/test/StatisticsOfPeaksWorkspaceTest.h
@@ -7,6 +7,7 @@
 #include "MantidGeometry/IDTypes.h"
 #include "MantidKernel/System.h"
 #include "MantidKernel/Timer.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Sample.h"
 #include "MantidTestHelpers/ComponentCreationHelper.h"
 #include "MantidGeometry/Crystal/OrientedLattice.h"
diff --git a/Framework/Crystal/test/TransformHKLTest.h b/Framework/Crystal/test/TransformHKLTest.h
index b548276707c2ad210b265fe16d863362f2ed1d41..ae5227531615359ff893ffa1e926fe2214897a35 100644
--- a/Framework/Crystal/test/TransformHKLTest.h
+++ b/Framework/Crystal/test/TransformHKLTest.h
@@ -10,6 +10,7 @@
 #include "MantidGeometry/Crystal/IndexingUtils.h"
 #include "MantidGeometry/Crystal/OrientedLattice.h"
 #include "MantidCrystal/LoadIsawUB.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Sample.h"
 
 using namespace Mantid;
diff --git a/Framework/CurveFitting/CMakeLists.txt b/Framework/CurveFitting/CMakeLists.txt
index fe6ef71f1920ecfbd2deb0ac1a8efa12fafedea9..6716713c08b5f92af31e8135cb424e5d160b208a 100644
--- a/Framework/CurveFitting/CMakeLists.txt
+++ b/Framework/CurveFitting/CMakeLists.txt
@@ -1,8 +1,10 @@
 set ( SRC_FILES
 	src/Algorithms/CalculateChiSquared.cpp
+	src/Algorithms/CalculateCostFunction.cpp
 	src/Algorithms/ConvertToYSpace.cpp
 	src/Algorithms/ConvolveWorkspaces.cpp
 	src/Algorithms/CrystalFieldEnergies.cpp
+	src/Algorithms/EstimateFitParameters.cpp
 	src/Algorithms/EstimatePeakErrors.cpp
 	src/Algorithms/EvaluateFunction.cpp
 	src/Algorithms/Fit.cpp
@@ -30,7 +32,7 @@ set ( SRC_FILES
 	src/CostFunctions/CostFuncUnweightedLeastSquares.cpp
 	src/FitMW.cpp
 	src/FuncMinimizers/BFGS_Minimizer.cpp
-	src/FuncMinimizers/DampingMinimizer.cpp
+	src/FuncMinimizers/DampedGaussNewtonMinimizer.cpp
 	src/FuncMinimizers/DerivMinimizer.cpp
 	src/FuncMinimizers/FABADAMinimizer.cpp
 	src/FuncMinimizers/FRConjugateGradientMinimizer.cpp
@@ -61,6 +63,10 @@ set ( SRC_FILES
 	src/Functions/CrystalFieldMultiSpectrum.cpp
 	src/Functions/CrystalFieldPeakUtils.cpp
 	src/Functions/CrystalFieldSpectrum.cpp
+	src/Functions/CrystalFieldHeatCapacity.cpp
+	src/Functions/CrystalFieldMagnetisation.cpp
+	src/Functions/CrystalFieldMoment.cpp
+	src/Functions/CrystalFieldSusceptibility.cpp
 	src/Functions/CubicSpline.cpp
 	src/Functions/DeltaFunction.cpp
 	src/Functions/DiffRotDiscreteCircle.cpp
@@ -76,6 +82,7 @@ set ( SRC_FILES
 	src/Functions/FlatBackground.cpp
 	src/Functions/FullprofPolynomial.cpp
 	src/Functions/FunctionGenerator.cpp
+	src/Functions/FunctionQDepends.cpp
 	src/Functions/GausDecay.cpp
 	src/Functions/GausOsc.cpp
 	src/Functions/Gaussian.cpp
@@ -90,7 +97,6 @@ set ( SRC_FILES
 	src/Functions/LinearBackground.cpp
 	src/Functions/LogNormal.cpp
 	src/Functions/Lorentzian.cpp
-	src/Functions/Lorentzian1D.cpp
 	src/Functions/MuonFInteraction.cpp
 	src/Functions/MultivariateGaussianComptonProfile.cpp
 	src/Functions/NeutronBk2BkExpConvPVoigt.cpp
@@ -147,9 +153,11 @@ set ( SRC_UNITY_IGNORE_FILES src/Fit1D.cpp src/GSLFunctions.cpp )
 
 set ( INC_FILES
 	inc/MantidCurveFitting/Algorithms/CalculateChiSquared.h
+	inc/MantidCurveFitting/Algorithms/CalculateCostFunction.h
 	inc/MantidCurveFitting/Algorithms/ConvertToYSpace.h
 	inc/MantidCurveFitting/Algorithms/ConvolveWorkspaces.h
 	inc/MantidCurveFitting/Algorithms/CrystalFieldEnergies.h
+	inc/MantidCurveFitting/Algorithms/EstimateFitParameters.h
 	inc/MantidCurveFitting/Algorithms/EstimatePeakErrors.h
 	inc/MantidCurveFitting/Algorithms/EvaluateFunction.h
 	inc/MantidCurveFitting/Algorithms/Fit.h
@@ -181,7 +189,7 @@ set ( INC_FILES
 	inc/MantidCurveFitting/FortranMatrix.h
 	inc/MantidCurveFitting/FortranVector.h
 	inc/MantidCurveFitting/FuncMinimizers/BFGS_Minimizer.h
-	inc/MantidCurveFitting/FuncMinimizers/DampingMinimizer.h
+	inc/MantidCurveFitting/FuncMinimizers/DampedGaussNewtonMinimizer.h
 	inc/MantidCurveFitting/FuncMinimizers/DerivMinimizer.h
 	inc/MantidCurveFitting/FuncMinimizers/FABADAMinimizer.h
 	inc/MantidCurveFitting/FuncMinimizers/FRConjugateGradientMinimizer.h
@@ -212,6 +220,10 @@ set ( INC_FILES
 	inc/MantidCurveFitting/Functions/CrystalFieldPeaksBase.h
 	inc/MantidCurveFitting/Functions/CrystalFieldPeakUtils.h
 	inc/MantidCurveFitting/Functions/CrystalFieldSpectrum.h
+	inc/MantidCurveFitting/Functions/CrystalFieldHeatCapacity.h
+	inc/MantidCurveFitting/Functions/CrystalFieldMagnetisation.h
+	inc/MantidCurveFitting/Functions/CrystalFieldMoment.h
+	inc/MantidCurveFitting/Functions/CrystalFieldSusceptibility.h
 	inc/MantidCurveFitting/Functions/CubicSpline.h
 	inc/MantidCurveFitting/Functions/DeltaFunction.h
 	inc/MantidCurveFitting/Functions/DiffRotDiscreteCircle.h
@@ -227,6 +239,7 @@ set ( INC_FILES
 	inc/MantidCurveFitting/Functions/FlatBackground.h
 	inc/MantidCurveFitting/Functions/FullprofPolynomial.h
 	inc/MantidCurveFitting/Functions/FunctionGenerator.h
+	inc/MantidCurveFitting/Functions/FunctionQDepends.h
 	inc/MantidCurveFitting/Functions/GausDecay.h
 	inc/MantidCurveFitting/Functions/GausOsc.h
 	inc/MantidCurveFitting/Functions/Gaussian.h
@@ -241,7 +254,6 @@ set ( INC_FILES
 	inc/MantidCurveFitting/Functions/LinearBackground.h
 	inc/MantidCurveFitting/Functions/LogNormal.h
 	inc/MantidCurveFitting/Functions/Lorentzian.h
-	inc/MantidCurveFitting/Functions/Lorentzian1D.h
 	inc/MantidCurveFitting/Functions/MuonFInteraction.h
 	inc/MantidCurveFitting/Functions/MultivariateGaussianComptonProfile.h
 	inc/MantidCurveFitting/Functions/NeutronBk2BkExpConvPVoigt.h
@@ -302,8 +314,10 @@ set ( TEST_FILES
 	# RefinePowderInstrumentParametersTest.h
 	#SCDPanelErrorsTest.h
 	Algorithms/CalculateChiSquaredTest.h
+	Algorithms/CalculateCostFunctionTest.h
 	Algorithms/ConvertToYSpaceTest.h
 	Algorithms/ConvolveWorkspacesTest.h
+	Algorithms/EstimateFitParametersTest.h
 	Algorithms/EstimatePeakErrorsTest.h
 	Algorithms/EvaluateFunctionTest.h
 	Algorithms/FitPowderDiffPeaksTest.h
@@ -332,7 +346,7 @@ set ( TEST_FILES
 	FortranMatrixTest.h
 	FortranVectorTest.h
 	FuncMinimizers/BFGSTest.h
-	FuncMinimizers/DampingMinimizerTest.h
+	FuncMinimizers/DampedGaussNewtonMinimizerTest.h
 	FuncMinimizers/FABADAMinimizerTest.h
 	FuncMinimizers/FRConjugateGradientTest.h
 	FuncMinimizers/LevenbergMarquardtMDTest.h
@@ -358,6 +372,10 @@ set ( TEST_FILES
 	Functions/CrystalFieldTest.h
 	Functions/CrystalFieldMultiSpectrumTest.h
 	Functions/CrystalFieldSpectrumTest.h
+	Functions/CrystalFieldHeatCapacityTest.h
+	Functions/CrystalFieldSusceptibilityTest.h
+	Functions/CrystalFieldMagnetisationTest.h
+	Functions/CrystalFieldMomentTest.h
 	Functions/CubicSplineTest.h
 	Functions/DeltaFunctionTest.h
 	Functions/DiffRotDiscreteCircleTest.h
@@ -370,6 +388,7 @@ set ( TEST_FILES
 	Functions/ExpDecayTest.h
 	Functions/FlatBackgroundTest.h
 	Functions/FullprofPolynomialTest.h
+	Functions/FunctionQDependsTest.h
 	Functions/GausDecayTest.h
 	Functions/GausOscTest.h
 	Functions/GaussianComptonProfileTest.h
@@ -381,7 +400,6 @@ set ( TEST_FILES
     Functions/KerenTest.h
 	Functions/LinearBackgroundTest.h
 	Functions/LogNormalTest.h
-	Functions/Lorentzian1DTest.h
 	Functions/LorentzianTest.h
 	Functions/MuonFInteractionTest.h
 	Functions/MultivariateGaussianComptonProfileTest.h
diff --git a/Framework/CurveFitting/inc/MantidCurveFitting/Algorithms/CalculateCostFunction.h b/Framework/CurveFitting/inc/MantidCurveFitting/Algorithms/CalculateCostFunction.h
new file mode 100644
index 0000000000000000000000000000000000000000..d66640fd091f0a6c0f0f085ab1f2034cc6d6a28f
--- /dev/null
+++ b/Framework/CurveFitting/inc/MantidCurveFitting/Algorithms/CalculateCostFunction.h
@@ -0,0 +1,59 @@
+#ifndef MANTID_CURVEFITTING_CALCULATECOSTFUNCTION_H_
+#define MANTID_CURVEFITTING_CALCULATECOSTFUNCTION_H_
+
+#include "MantidKernel/System.h"
+#include "MantidCurveFitting/IFittingAlgorithm.h"
+
+namespace Mantid {
+namespace CurveFitting {
+
+namespace CostFunctions {
+class CostFuncFitting;
+}
+
+namespace Algorithms {
+
+/**
+
+  Calculate cost function for a function and a data set in a workspace.
+
+  Copyright &copy; 2015 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>
+*/
+class DLLExport CalculateCostFunction : public IFittingAlgorithm {
+public:
+  const std::string name() const override;
+  int version() const override;
+  const std::string summary() const override;
+
+private:
+  void initConcrete() override;
+  void execConcrete() override;
+
+  /// Cache for the cost function
+  boost::shared_ptr<CostFunctions::CostFuncFitting> m_costFunction;
+};
+
+} // namespace Algorithms
+} // namespace CurveFitting
+} // namespace Mantid
+
+#endif /* MANTID_CURVEFITTING_CALCULATECOSTFUNCTION_H_ */
diff --git a/Framework/CurveFitting/inc/MantidCurveFitting/Algorithms/EstimateFitParameters.h b/Framework/CurveFitting/inc/MantidCurveFitting/Algorithms/EstimateFitParameters.h
new file mode 100644
index 0000000000000000000000000000000000000000..4e7bffa93e4ed0032f30e4c0d36bdd655f2e5216
--- /dev/null
+++ b/Framework/CurveFitting/inc/MantidCurveFitting/Algorithms/EstimateFitParameters.h
@@ -0,0 +1,51 @@
+#ifndef MANTID_CURVEFITTING_ESTIMATEFITPARAMETERS_H_
+#define MANTID_CURVEFITTING_ESTIMATEFITPARAMETERS_H_
+
+#include "MantidKernel/System.h"
+#include "MantidCurveFitting/IFittingAlgorithm.h"
+
+namespace Mantid {
+namespace CurveFitting {
+namespace Algorithms {
+
+/**
+
+  Estimate parameters of a fitting function using a Monte Carlo algorithm.
+
+  Copyright &copy; 2015 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>
+*/
+class DLLExport EstimateFitParameters : public IFittingAlgorithm {
+public:
+  const std::string name() const override;
+  int version() const override;
+  const std::string summary() const override;
+
+private:
+  void initConcrete() override;
+  void execConcrete() override;
+};
+
+} // namespace Algorithms
+} // namespace CurveFitting
+} // namespace Mantid
+
+#endif /* MANTID_CURVEFITTING_ESTIMATEFITPARAMETERS_H_ */
diff --git a/Framework/CurveFitting/inc/MantidCurveFitting/Algorithms/RefinePowderInstrumentParameters.h b/Framework/CurveFitting/inc/MantidCurveFitting/Algorithms/RefinePowderInstrumentParameters.h
index f6b1113bb2ef4548523aedf26a8b3f85b228327e..0cc87ff3ac99672bab7b751d72701fe1972d3e54 100644
--- a/Framework/CurveFitting/inc/MantidCurveFitting/Algorithms/RefinePowderInstrumentParameters.h
+++ b/Framework/CurveFitting/inc/MantidCurveFitting/Algorithms/RefinePowderInstrumentParameters.h
@@ -3,6 +3,7 @@
 
 #include "MantidKernel/System.h"
 #include "MantidAPI/Algorithm.h"
+#include "MantidAPI/DeprecatedAlgorithm.h"
 #include "MantidAPI/MatrixWorkspace_fwd.h"
 #include "MantidAPI/CompositeFunction.h"
 #include "MantidAPI/ITableWorkspace_fwd.h"
@@ -53,7 +54,9 @@ namespace Algorithms {
   File change history is stored at: <https://github.com/mantidproject/mantid>
   Code Documentation is available at: <http://doxygen.mantidproject.org>
 */
-class DLLExport RefinePowderInstrumentParameters : public API::Algorithm {
+class DLLExport RefinePowderInstrumentParameters
+    : public API::Algorithm,
+      public API::DeprecatedAlgorithm {
 public:
   RefinePowderInstrumentParameters();
 
diff --git a/Framework/CurveFitting/inc/MantidCurveFitting/Algorithms/SplineSmoothing.h b/Framework/CurveFitting/inc/MantidCurveFitting/Algorithms/SplineSmoothing.h
index a26ca2df67b1d6a93d9586dc2844855296e463e0..51ed2dce5c909e38a8ad6b8c417f4e456a3a9125 100644
--- a/Framework/CurveFitting/inc/MantidCurveFitting/Algorithms/SplineSmoothing.h
+++ b/Framework/CurveFitting/inc/MantidCurveFitting/Algorithms/SplineSmoothing.h
@@ -4,6 +4,7 @@
 #include "MantidKernel/System.h"
 #include "MantidAPI/Algorithm.h"
 #include "MantidAPI/WorkspaceFactory.h"
+#include "MantidAPI/WorkspaceGroup_fwd.h"
 #include "MantidCurveFitting/Functions/BSpline.h"
 
 namespace Mantid {
diff --git a/Framework/CurveFitting/inc/MantidCurveFitting/CostFunctions/CostFuncFitting.h b/Framework/CurveFitting/inc/MantidCurveFitting/CostFunctions/CostFuncFitting.h
index f7929e68470950c38c0e9497508c44ec0f92e2dc..67e6f86841b181c756bf5c3f0d4515b2a1f3c03d 100644
--- a/Framework/CurveFitting/inc/MantidCurveFitting/CostFunctions/CostFuncFitting.h
+++ b/Framework/CurveFitting/inc/MantidCurveFitting/CostFunctions/CostFuncFitting.h
@@ -74,6 +74,14 @@ public:
   API::FunctionDomain_sptr getDomain() const { return m_domain; }
   /// Get FunctionValues where function values are stored.
   API::FunctionValues_sptr getValues() const { return m_values; }
+  /// Apply ties in the fitting function
+  void applyTies();
+  /// Reset the fitting function (neccessary if parameters get fixed/unfixed)
+  void reset() const;
+  /// Set all parameters
+  void setParameters(const GSLVector &params);
+  /// Get values of all parameters
+  void getParameters(GSLVector &params) const;
 
 protected:
   /**
@@ -94,7 +102,9 @@ protected:
   /// Shared poinetr to the function values
   API::FunctionValues_sptr m_values;
   /// maps the cost function's parameters to the ones of the fitting function.
-  std::vector<size_t> m_indexMap;
+  mutable std::vector<size_t> m_indexMap;
+  /// Number of all parameters in the fitting function.
+  mutable size_t m_numberFunParams;
 
   mutable bool m_dirtyVal;     /// dirty value flag
   mutable bool m_dirtyDeriv;   /// dirty derivatives flag
diff --git a/Framework/CurveFitting/inc/MantidCurveFitting/CostFunctions/CostFuncLeastSquares.h b/Framework/CurveFitting/inc/MantidCurveFitting/CostFunctions/CostFuncLeastSquares.h
index 2b4552e9f2f4da6f543ebb573ba4c0bd986cc39b..982957eeb638436810fd4593f0f812d3a4443351 100644
--- a/Framework/CurveFitting/inc/MantidCurveFitting/CostFunctions/CostFuncLeastSquares.h
+++ b/Framework/CurveFitting/inc/MantidCurveFitting/CostFunctions/CostFuncLeastSquares.h
@@ -71,9 +71,6 @@ public:
   void pop();
   void drop();
 
-  void setParameters(const GSLVector &params);
-  void getParameters(GSLVector &params) const;
-
 protected:
   void calActiveCovarianceMatrix(GSLMatrix &covar,
                                  double epsrel = 1e-8) override;
diff --git a/Framework/CurveFitting/inc/MantidCurveFitting/FitMW.h b/Framework/CurveFitting/inc/MantidCurveFitting/FitMW.h
index 2a3e4764ec9e13165b5cf964bedaabf6c55aad52..7fe5d6ab4ba8150d20eeb77ee6d4b76a203f2e72 100644
--- a/Framework/CurveFitting/inc/MantidCurveFitting/FitMW.h
+++ b/Framework/CurveFitting/inc/MantidCurveFitting/FitMW.h
@@ -89,11 +89,15 @@ private:
   std::string m_maxSizePropertyName;
   /// Store Normalise property name
   std::string m_normalisePropertyName;
+  /// Store the Exclude property name
+  std::string m_excludePropertyName;
 
   /// Max size for seq domain
   mutable size_t m_maxSize;
   /// Option to normalise the data
   mutable bool m_normalise;
+  /// Ranges that must be excluded from fit
+  mutable std::vector<double> m_exclude;
 };
 
 } // namespace CurveFitting
diff --git a/Framework/CurveFitting/inc/MantidCurveFitting/FuncMinimizers/DampingMinimizer.h b/Framework/CurveFitting/inc/MantidCurveFitting/FuncMinimizers/DampedGaussNewtonMinimizer.h
similarity index 81%
rename from Framework/CurveFitting/inc/MantidCurveFitting/FuncMinimizers/DampingMinimizer.h
rename to Framework/CurveFitting/inc/MantidCurveFitting/FuncMinimizers/DampedGaussNewtonMinimizer.h
index 69e54e104788355b031d262ec5ac454c86629f82..8fe6c9b9b80c9bcb16c24140d9903b6e8653300b 100644
--- a/Framework/CurveFitting/inc/MantidCurveFitting/FuncMinimizers/DampingMinimizer.h
+++ b/Framework/CurveFitting/inc/MantidCurveFitting/FuncMinimizers/DampedGaussNewtonMinimizer.h
@@ -1,5 +1,5 @@
-#ifndef MANTID_CURVEFITTING_DAMPINGMINIMIZER_H_
-#define MANTID_CURVEFITTING_DAMPINGMINIMIZER_H_
+#ifndef MANTID_CURVEFITTING_DAMPEDGAUSSNEWTONMINIMIZER_H_
+#define MANTID_CURVEFITTING_DAMPEDGAUSSNEWTONMINIMIZER_H_
 
 //----------------------------------------------------------------------
 // Includes
@@ -16,7 +16,8 @@ class CostFuncLeastSquares;
 namespace FuncMinimisers {
 
 /**
-    Implements a least squares minimization algorithm with damping.
+    Implements a Gauss-Newton minimization algorithm with damping
+    for use with least squares cost function.
 
     @author Roman Tolchenov, Tessella plc
 
@@ -41,12 +42,12 @@ namespace FuncMinimisers {
     File change history is stored at: <https://github.com/mantidproject/mantid>.
     Code Documentation is available at: <http://doxygen.mantidproject.org>
 */
-class DLLExport DampingMinimizer : public API::IFuncMinimizer {
+class DLLExport DampedGaussNewtonMinimizer : public API::IFuncMinimizer {
 public:
   /// Constructor
-  DampingMinimizer(double relTol = 0.0001);
+  DampedGaussNewtonMinimizer(double relTol = 0.0001);
   /// Name of the minimizer.
-  std::string name() const override { return "DampingMinimizer"; }
+  std::string name() const override { return "DampedGaussNewtonMinimizer"; }
 
   /// Initialize minimizer, i.e. pass a function to minimize.
   void initialize(API::ICostFunction_sptr function,
@@ -68,4 +69,4 @@ private:
 } // namespace CurveFitting
 } // namespace Mantid
 
-#endif /*MANTID_CURVEFITTING_DAMPINGMINIMIZER_H_*/
+#endif /* MANTID_CURVEFITTING_DAMPEDGAUSSNEWTONMINIMIZER_H_*/
diff --git a/Framework/CurveFitting/inc/MantidCurveFitting/Functions/CrystalElectricField.h b/Framework/CurveFitting/inc/MantidCurveFitting/Functions/CrystalElectricField.h
index db91b639d364d5d951e9e28d8aab813f9bc6c8e0..50b42dff2fe324c1f791b81c83185e9e5cb5ab85 100644
--- a/Framework/CurveFitting/inc/MantidCurveFitting/Functions/CrystalElectricField.h
+++ b/Framework/CurveFitting/inc/MantidCurveFitting/Functions/CrystalElectricField.h
@@ -8,14 +8,31 @@ namespace Mantid {
 namespace CurveFitting {
 namespace Functions {
 
-void MANTID_CURVEFITTING_DLL
+void MANTID_CURVEFITTING_DLL calculateEigensystem(
+    DoubleFortranVector &eigenvalues, ComplexFortranMatrix &eigenvectors,
+    ComplexFortranMatrix &hamiltonian, ComplexFortranMatrix &hzeeman, int nre,
+    const DoubleFortranVector &bmol, const DoubleFortranVector &bext,
+    const ComplexFortranMatrix &bkq, double alpha_euler = 0.0,
+    double beta_euler = 0.0, double gamma_euler = 0.0);
+
+inline void MANTID_CURVEFITTING_DLL
 calculateEigensystem(DoubleFortranVector &eigenvalues,
                      ComplexFortranMatrix &eigenvectors,
                      ComplexFortranMatrix &hamiltonian, int nre,
                      const DoubleFortranVector &bmol,
                      const DoubleFortranVector &bext,
                      const ComplexFortranMatrix &bkq, double alpha_euler = 0.0,
-                     double beta_euler = 0.0, double gamma_euler = 0.0);
+                     double beta_euler = 0.0, double gamma_euler = 0.0) {
+  ComplexFortranMatrix hzeeman;
+  calculateEigensystem(eigenvalues, eigenvectors, hamiltonian, hzeeman, nre,
+                       bmol, bext, bkq, alpha_euler, beta_euler, gamma_euler);
+}
+
+void MANTID_CURVEFITTING_DLL
+calculateZeemanEigensystem(DoubleFortranVector &eigenvalues,
+                           ComplexFortranMatrix &eigenvectors,
+                           const ComplexFortranMatrix &hamiltonian, int nre,
+                           const DoubleFortranVector &bext);
 
 void MANTID_CURVEFITTING_DLL
 calculateIntensities(int nre, const DoubleFortranVector &energies,
@@ -31,6 +48,16 @@ calculateExcitations(const DoubleFortranVector &e_energies,
                      double di, DoubleFortranVector &e_excitations,
                      DoubleFortranVector &i_excitations);
 
+void MANTID_CURVEFITTING_DLL
+calculateMagneticMoment(const ComplexFortranMatrix &ev,
+                        const DoubleFortranVector &Hmag, const int nre,
+                        DoubleFortranVector &moment);
+
+void MANTID_CURVEFITTING_DLL
+calculateMagneticMomentMatrix(const ComplexFortranMatrix &ev,
+                              const std::vector<double> &Hdir, const int nre,
+                              ComplexFortranMatrix &mumat);
+
 } // namespace Functions
 } // namespace CurveFitting
 } // namespace Mantid
diff --git a/Framework/CurveFitting/inc/MantidCurveFitting/Functions/CrystalFieldHeatCapacity.h b/Framework/CurveFitting/inc/MantidCurveFitting/Functions/CrystalFieldHeatCapacity.h
new file mode 100644
index 0000000000000000000000000000000000000000..7d0d0e250d1bd2e3325066d31b8081c345850300
--- /dev/null
+++ b/Framework/CurveFitting/inc/MantidCurveFitting/Functions/CrystalFieldHeatCapacity.h
@@ -0,0 +1,59 @@
+#ifndef MANTID_CURVEFITTING_CRYSTALFIELDHEATCAPACITY_H_
+#define MANTID_CURVEFITTING_CRYSTALFIELDHEATCAPACITY_H_
+
+#include "MantidCurveFitting/Functions/CrystalFieldPeaksBase.h"
+#include "MantidCurveFitting/FortranDefs.h"
+#include "MantidAPI/IFunction1D.h"
+
+namespace Mantid {
+namespace CurveFitting {
+namespace Functions {
+
+/**
+  CrystalFieldHeatCapacity is a function that calculates the molar magnetic
+  heat capacity (in J/K/mol) due to the splitting of electronic energy levels
+  due to the crystal field.
+
+  Copyright &copy; 2016 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>
+*/
+
+class MANTID_CURVEFITTING_DLL CrystalFieldHeatCapacity
+    : public CrystalFieldPeaksBase,
+      public API::IFunction1D {
+public:
+  CrystalFieldHeatCapacity();
+  std::string name() const override { return "CrystalFieldHeatCapacity"; }
+  const std::string category() const override { return "General"; }
+  void setEnergy(const DoubleFortranVector &en);
+  void function1D(double *out, const double *xValues,
+                  const size_t nData) const override;
+
+private:
+  DoubleFortranVector m_en;
+  bool m_setDirect;
+};
+
+} // namespace Functions
+} // namespace CurveFitting
+} // namespace Mantid
+
+#endif /* MANTID_CURVEFITTING_CRYSTALFIELDHEATCAPACITY_H_ */
diff --git a/Framework/CurveFitting/inc/MantidCurveFitting/Functions/CrystalFieldMagnetisation.h b/Framework/CurveFitting/inc/MantidCurveFitting/Functions/CrystalFieldMagnetisation.h
new file mode 100644
index 0000000000000000000000000000000000000000..91debf56df891a2e7367076745624176d30e4365
--- /dev/null
+++ b/Framework/CurveFitting/inc/MantidCurveFitting/Functions/CrystalFieldMagnetisation.h
@@ -0,0 +1,61 @@
+#ifndef MANTID_CURVEFITTING_CRYSTALFIELDMAGNETISATION_H_
+#define MANTID_CURVEFITTING_CRYSTALFIELDMAGNETISATION_H_
+
+#include "MantidCurveFitting/Functions/CrystalFieldPeaksBase.h"
+#include "MantidCurveFitting/FortranDefs.h"
+#include "MantidAPI/IFunction1D.h"
+
+namespace Mantid {
+namespace CurveFitting {
+namespace Functions {
+
+/**
+  CrystalFieldMagnetisation is a function that calculates the induced
+  magnetic moment (in bohr magnetons per ion, Am^2 or erg/Gauss) as a function
+  of applied external magnetic field (in Tesla or Gauss), for a particular
+  crystal field splitting.
+
+  Copyright &copy; 2016 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>
+*/
+
+class MANTID_CURVEFITTING_DLL CrystalFieldMagnetisation
+    : public CrystalFieldPeaksBase,
+      public API::IFunction1D {
+public:
+  CrystalFieldMagnetisation();
+  std::string name() const override { return "CrystalFieldMagnetisation"; }
+  const std::string category() const override { return "General"; }
+  void setHamiltonian(const ComplexFortranMatrix &ham, const int nre);
+  void function1D(double *out, const double *xValues,
+                  const size_t nData) const override;
+
+private:
+  ComplexFortranMatrix m_ham;
+  int m_nre;
+  bool m_setDirect;
+};
+
+} // namespace Functions
+} // namespace CurveFitting
+} // namespace Mantid
+
+#endif /* MANTID_CURVEFITTING_CRYSTALFIELDMAGNETISATION_H_ */
diff --git a/Framework/CurveFitting/inc/MantidCurveFitting/Functions/CrystalFieldMoment.h b/Framework/CurveFitting/inc/MantidCurveFitting/Functions/CrystalFieldMoment.h
new file mode 100644
index 0000000000000000000000000000000000000000..a3f89a3321aebbb61cf12a2245a3eb7210651b60
--- /dev/null
+++ b/Framework/CurveFitting/inc/MantidCurveFitting/Functions/CrystalFieldMoment.h
@@ -0,0 +1,60 @@
+#ifndef MANTID_CURVEFITTING_CRYSTALFIELDMOMENT_H
+#define MANTID_CURVEFITTING_CRYSTALFIELDMOMENT_H
+
+#include "MantidCurveFitting/Functions/CrystalFieldPeaksBase.h"
+#include "MantidCurveFitting/FortranDefs.h"
+#include "MantidAPI/IFunction1D.h"
+
+namespace Mantid {
+namespace CurveFitting {
+namespace Functions {
+
+/**
+  CrystalFieldMoment is a function that calculates the induced
+  magnetic moment (in bohr magnetons per ion, Am^2 or erg/Gauss) at some
+  applied external magnetic field (in Tesla or Gauss) as a function of
+  temperature (in Kelvin) for a particular crystal field splitting.
+
+  Copyright &copy; 2016 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>
+*/
+
+class MANTID_CURVEFITTING_DLL CrystalFieldMoment : public CrystalFieldPeaksBase,
+                                                   public API::IFunction1D {
+public:
+  CrystalFieldMoment();
+  std::string name() const override { return "CrystalFieldMoment"; }
+  const std::string category() const override { return "General"; }
+  void setHamiltonian(const ComplexFortranMatrix &ham, const int nre);
+  void function1D(double *out, const double *xValues,
+                  const size_t nData) const override;
+
+private:
+  ComplexFortranMatrix m_ham;
+  int m_nre;
+  bool m_setDirect;
+};
+
+} // namespace Functions
+} // namespace CurveFitting
+} // namespace Mantid
+
+#endif /* MANTID_CURVEFITTING_CRYSTALFIELDMOMENT_H */
diff --git a/Framework/CurveFitting/inc/MantidCurveFitting/Functions/CrystalFieldMultiSpectrum.h b/Framework/CurveFitting/inc/MantidCurveFitting/Functions/CrystalFieldMultiSpectrum.h
index 420adb5e019841d575173ae9f8f66568ee54655d..328fb8ee636276bd702329613de90214c77c91db 100644
--- a/Framework/CurveFitting/inc/MantidCurveFitting/Functions/CrystalFieldMultiSpectrum.h
+++ b/Framework/CurveFitting/inc/MantidCurveFitting/Functions/CrystalFieldMultiSpectrum.h
@@ -41,6 +41,12 @@ public:
   void setAttribute(const std::string &name, const Attribute &) override;
   std::vector<API::IFunction_sptr> createEquivalentFunctions() const override;
   void buildTargetFunction() const override;
+  enum PhysicalProperty {
+    HeatCapacity = 1,   ///< Specify dataset is magnetic heat capacity Cv(T)
+    Susceptibility = 2, ///< Specify dataset is magnetic susceptibility chi(T)
+    Magnetisation = 3,  ///< Specify dataset is magnetisation vs field M(H)
+    MagneticMoment = 4  ///< Specify dataset is magnetisation vs temp M(T)
+  };
 
 protected:
   void updateTargetFunction() const override;
@@ -51,10 +57,15 @@ private:
                                     const ComplexFortranMatrix &wf,
                                     double temperature, double fwhm,
                                     size_t i) const;
+  API::IFunction_sptr buildPhysprop(int nre, const DoubleFortranVector &en,
+                                    const ComplexFortranMatrix &wf,
+                                    const ComplexFortranMatrix &ham,
+                                    double temperature, size_t iSpec) const;
   /// Update a function for a single spectrum.
   void updateSpectrum(API::IFunction &spectrum, int nre,
                       const DoubleFortranVector &en,
-                      const ComplexFortranMatrix &wf, double temperature,
+                      const ComplexFortranMatrix &wf,
+                      const ComplexFortranMatrix &ham, double temperature,
                       size_t i) const;
   /// Calculate excitations at given temperature
   void calcExcitations(int nre, const DoubleFortranVector &en,
@@ -62,6 +73,8 @@ private:
                        API::FunctionValues &values, size_t iSpec) const;
   /// Cache number of fitted peaks
   mutable std::vector<size_t> m_nPeaks;
+  /// Cache the list of "spectra" corresponding to physical properties
+  mutable std::vector<int> m_physprops;
   /// Caches of the width functions
   mutable std::vector<std::vector<double>> m_fwhmX;
   mutable std::vector<std::vector<double>> m_fwhmY;
diff --git a/Framework/CurveFitting/inc/MantidCurveFitting/Functions/CrystalFieldPeakUtils.h b/Framework/CurveFitting/inc/MantidCurveFitting/Functions/CrystalFieldPeakUtils.h
index b6b4c1af901fa0d2d320d30c7adbc6819a911c50..395b0cd61b765164f5ec00dd5598ed532873a695 100644
--- a/Framework/CurveFitting/inc/MantidCurveFitting/Functions/CrystalFieldPeakUtils.h
+++ b/Framework/CurveFitting/inc/MantidCurveFitting/Functions/CrystalFieldPeakUtils.h
@@ -43,7 +43,8 @@ size_t buildSpectrumFunction(API::CompositeFunction &spectrum,
                              const API::FunctionValues &centresAndIntensities,
                              const std::vector<double> &xVec,
                              const std::vector<double> &yVec,
-                             double fwhmVariation, double defaultFWHM);
+                             double fwhmVariation, double defaultFWHM,
+                             size_t nRequiredPeaks, bool fixAllPeaks);
 size_t updateSpectrumFunction(API::CompositeFunction &spectrum,
                               const API::FunctionValues &centresAndIntensities,
                               size_t nOriginalPeaks, size_t iFirst,
@@ -51,6 +52,7 @@ size_t updateSpectrumFunction(API::CompositeFunction &spectrum,
                               const std::vector<double> &yVec,
                               double fwhmVariation);
 size_t calculateNPeaks(const API::FunctionValues &centresAndIntensities);
+size_t calculateMaxNPeaks(size_t nPeaks);
 
 } // namespace CrystalFieldUtils
 } // namespace Functions
diff --git a/Framework/CurveFitting/inc/MantidCurveFitting/Functions/CrystalFieldPeaks.h b/Framework/CurveFitting/inc/MantidCurveFitting/Functions/CrystalFieldPeaks.h
index 9fe91456facd9ec4baec93659b801f1397402a14..d0af51655e311e34059e84857c1629e22e09cf03 100644
--- a/Framework/CurveFitting/inc/MantidCurveFitting/Functions/CrystalFieldPeaks.h
+++ b/Framework/CurveFitting/inc/MantidCurveFitting/Functions/CrystalFieldPeaks.h
@@ -2,6 +2,7 @@
 #define MANTID_CURVEFITTING_CRYSTALFIELDPEAKS_H_
 
 #include "MantidCurveFitting/Functions/CrystalFieldPeaksBase.h"
+#include "MantidAPI/IFunctionGeneral.h"
 
 namespace Mantid {
 namespace CurveFitting {
@@ -32,7 +33,8 @@ namespace Functions {
   File change history is stored at: <https://github.com/mantidproject/mantid>
   Code Documentation is available at: <http://doxygen.mantidproject.org>
 */
-class MANTID_CURVEFITTING_DLL CrystalFieldPeaks : public CrystalFieldPeaksBase {
+class MANTID_CURVEFITTING_DLL CrystalFieldPeaks : public CrystalFieldPeaksBase,
+                                                  public API::IFunctionGeneral {
 public:
   CrystalFieldPeaks();
   std::string name() const override;
@@ -52,4 +54,4 @@ private:
 } // namespace CurveFitting
 } // namespace Mantid
 
-#endif /* MANTID_CURVEFITTING_CRYSTALFIELDPEAKS_H_ */
\ No newline at end of file
+#endif /* MANTID_CURVEFITTING_CRYSTALFIELDPEAKS_H_ */
diff --git a/Framework/CurveFitting/inc/MantidCurveFitting/Functions/CrystalFieldPeaksBase.h b/Framework/CurveFitting/inc/MantidCurveFitting/Functions/CrystalFieldPeaksBase.h
index 394da9e8e1879b486623999c284c6c66c3d9b2a8..402a12475fb8dd5064958765cddb580f5442fef6 100644
--- a/Framework/CurveFitting/inc/MantidCurveFitting/Functions/CrystalFieldPeaksBase.h
+++ b/Framework/CurveFitting/inc/MantidCurveFitting/Functions/CrystalFieldPeaksBase.h
@@ -2,7 +2,6 @@
 #define MANTID_CURVEFITTING_CRYSTALFIELDPEAKSBASE_H_
 
 #include "MantidAPI/FunctionValues.h"
-#include "MantidAPI/IFunctionGeneral.h"
 #include "MantidAPI/ParamFunction.h"
 #include "MantidCurveFitting/DllConfig.h"
 #include "MantidCurveFitting/FortranDefs.h"
@@ -37,15 +36,20 @@ namespace Functions {
   Code Documentation is available at: <http://doxygen.mantidproject.org>
 */
 class MANTID_CURVEFITTING_DLL CrystalFieldPeaksBase
-    : public API::IFunctionGeneral,
-      public API::ParamFunction {
+    : public API::ParamFunction {
 public:
   CrystalFieldPeaksBase();
   void setAttribute(const std::string &name, const Attribute &) override;
 
   /// Calculate the crystal field eigensystem
   void calculateEigenSystem(DoubleFortranVector &en, ComplexFortranMatrix &wf,
+                            ComplexFortranMatrix &ham, ComplexFortranMatrix &hz,
                             int &nre) const;
+  inline void calculateEigenSystem(DoubleFortranVector &en,
+                                   ComplexFortranMatrix &wf, int &nre) const {
+    ComplexFortranMatrix ham, hz;
+    calculateEigenSystem(en, wf, ham, hz, nre);
+  }
 
 protected:
   /// Store the default domain size after first
@@ -57,4 +61,4 @@ protected:
 } // namespace CurveFitting
 } // namespace Mantid
 
-#endif /* MANTID_CURVEFITTING_CRYSTALFIELDPEAKSBASE_H_ */
\ No newline at end of file
+#endif /* MANTID_CURVEFITTING_CRYSTALFIELDPEAKSBASE_H_ */
diff --git a/Framework/CurveFitting/inc/MantidCurveFitting/Functions/CrystalFieldSpectrum.h b/Framework/CurveFitting/inc/MantidCurveFitting/Functions/CrystalFieldSpectrum.h
index 7416904993590d082e3915e566b714e6136bb6bd..b502e5b7e97ce3b0d715e78fc8a7fb0ffc9b9a28 100644
--- a/Framework/CurveFitting/inc/MantidCurveFitting/Functions/CrystalFieldSpectrum.h
+++ b/Framework/CurveFitting/inc/MantidCurveFitting/Functions/CrystalFieldSpectrum.h
@@ -36,6 +36,7 @@ public:
   std::string name() const override { return "CrystalFieldSpectrum"; }
   const std::string category() const override { return "General"; }
   void buildTargetFunction() const override;
+  std::string asString() const override;
 
 protected:
   void updateTargetFunction() const override;
diff --git a/Framework/CurveFitting/inc/MantidCurveFitting/Functions/CrystalFieldSusceptibility.h b/Framework/CurveFitting/inc/MantidCurveFitting/Functions/CrystalFieldSusceptibility.h
new file mode 100644
index 0000000000000000000000000000000000000000..211d0238a0f804e4ef9e739b8b26af687e493b2c
--- /dev/null
+++ b/Framework/CurveFitting/inc/MantidCurveFitting/Functions/CrystalFieldSusceptibility.h
@@ -0,0 +1,61 @@
+#ifndef MANTID_CURVEFITTING_CRYSTALFIELDSUSCEPTIBILITY_H_
+#define MANTID_CURVEFITTING_CRYSTALFIELDSUSCEPTIBILITY_H_
+
+#include "MantidCurveFitting/Functions/CrystalFieldPeaksBase.h"
+#include "MantidCurveFitting/FortranDefs.h"
+#include "MantidAPI/IFunction1D.h"
+
+namespace Mantid {
+namespace CurveFitting {
+namespace Functions {
+
+/**
+  CrystalFieldSusceptibility is a function that calculates the molar magnetic
+  susceptibility (in cm^3/mol or m^3/mol) due to the crystalline electric field.
+
+  Copyright &copy; 2016 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>
+*/
+
+class MANTID_CURVEFITTING_DLL CrystalFieldSusceptibility
+    : public CrystalFieldPeaksBase,
+      public API::IFunction1D {
+public:
+  CrystalFieldSusceptibility();
+  std::string name() const override { return "CrystalFieldSusceptibility"; }
+  const std::string category() const override { return "General"; }
+  void setEigensystem(const DoubleFortranVector &en,
+                      const ComplexFortranMatrix &wf, const int nre);
+  void function1D(double *out, const double *xValues,
+                  const size_t nData) const override;
+
+private:
+  DoubleFortranVector m_en;
+  ComplexFortranMatrix m_wf;
+  int m_nre;
+  bool m_setDirect;
+};
+
+} // namespace Functions
+} // namespace CurveFitting
+} // namespace Mantid
+
+#endif /* MANTID_CURVEFITTING_CRYSTALFIELDSUSCEPTIBILITY_H_ */
diff --git a/Framework/CurveFitting/inc/MantidCurveFitting/Functions/FunctionGenerator.h b/Framework/CurveFitting/inc/MantidCurveFitting/Functions/FunctionGenerator.h
index 751db034ebbf00a31b2116ea737760e49da81cb1..b3d391c2038feb72eb1e6d0a705138b853c22132 100644
--- a/Framework/CurveFitting/inc/MantidCurveFitting/Functions/FunctionGenerator.h
+++ b/Framework/CurveFitting/inc/MantidCurveFitting/Functions/FunctionGenerator.h
@@ -93,8 +93,8 @@ public:
   /// Return parameter index from a parameter reference.
   size_t getParameterIndex(const API::ParameterReference &ref) const override;
   /// Tie a parameter to other parameters (or a constant)
-  API::ParameterTie *tie(const std::string &parName, const std::string &expr,
-                         bool isDefault = false) override;
+  void tie(const std::string &parName, const std::string &expr,
+           bool isDefault = false) override;
   /// Apply the ties
   void applyTies() override;
   /// Remove all ties
@@ -107,7 +107,7 @@ public:
   API::ParameterTie *getTie(size_t i) const override;
 
   /// Add a constraint to function
-  void addConstraint(API::IConstraint *ic) override;
+  void addConstraint(std::unique_ptr<API::IConstraint> ic) override;
   /// Get constraint of i-th parameter
   API::IConstraint *getConstraint(size_t i) const override;
   /// Remove a constraint
@@ -125,7 +125,7 @@ protected:
                         const std::string &description = "") override;
 
   /// Add a new tie. Derived classes must provide storage for ties
-  void addTie(API::ParameterTie *tie) override;
+  void addTie(std::unique_ptr<API::ParameterTie> tie) override;
   //@}
 
 public:
diff --git a/Framework/CurveFitting/inc/MantidCurveFitting/Functions/FunctionQDepends.h b/Framework/CurveFitting/inc/MantidCurveFitting/Functions/FunctionQDepends.h
new file mode 100644
index 0000000000000000000000000000000000000000..d382bad8c1646a30d2ff1e1751fc8e0ed402ba4b
--- /dev/null
+++ b/Framework/CurveFitting/inc/MantidCurveFitting/Functions/FunctionQDepends.h
@@ -0,0 +1,81 @@
+#ifndef MANTID_CURVEFITTING_FUNCTIONQDEPENDS_H_
+#define MANTID_CURVEFITTING_FUNCTIONQDEPENDS_H_
+
+// Mantid Coding standars <http://www.mantidproject.org/Coding_Standards>
+
+// Mantid Headers from the same project
+#include "MantidAPI/IFunction.h"
+#include "MantidAPI/IFunction1D.h"
+#include "MantidAPI/ParamFunction.h"
+// Mantid headers from other projects
+// N/A
+// 3rd party library headers
+// N/A
+// Standard library
+// N/A
+
+namespace Mantid {
+namespace CurveFitting {
+namespace Functions {
+
+/** This is a specialization of IFunction1D for functions having the magnitude
+    of the momentum transfer (Q) as attribute.
+
+    Main features of this interface:
+     - Declares attributes "Q" and "WorkspaceIndex"
+     - Implements setMatrixWorkspace
+     - Extracts or compute Q values for each spectra, if possible
+
+    @author Jose Borreguero, NScD-ORNL
+    @date 12/10/2016
+
+    Copyright &copy; 2009 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>
+*/
+
+class DLLExport FunctionQDepends : public Mantid::API::IFunction1D,
+                                   public Mantid::API::ParamFunction {
+
+public:
+  /* -------------------
+     Overridden methods
+    -------------------*/
+  virtual void declareAttributes() override;
+  virtual void
+  setAttribute(const std::string &attName,
+               const Mantid::API::IFunction::Attribute &attValue) override;
+  void setMatrixWorkspace(
+      boost::shared_ptr<const Mantid::API::MatrixWorkspace> workspace,
+      size_t wi, double startX, double endX) override;
+
+private:
+  std::vector<double>
+  extractQValues(const Mantid::API::MatrixWorkspace &workspace);
+  // list of Q values associated to the spectra
+  std::vector<double> m_vQ;
+
+}; // end of class FunctionQDepends
+
+} // namespace Functions
+} // namespace CurveFitting
+} // namespace Mantid
+
+#endif /*MANTID_CURVEFITTING_FUNCTIONQDEPENDS_H_*/
diff --git a/Framework/CurveFitting/inc/MantidCurveFitting/Functions/IkedaCarpenterPV.h b/Framework/CurveFitting/inc/MantidCurveFitting/Functions/IkedaCarpenterPV.h
index ea596f6573049ae25213db7a5dfbc5218cfd5d59..ae97e2c00daac7a74cad5dfc5af2f662856e0f6b 100644
--- a/Framework/CurveFitting/inc/MantidCurveFitting/Functions/IkedaCarpenterPV.h
+++ b/Framework/CurveFitting/inc/MantidCurveFitting/Functions/IkedaCarpenterPV.h
@@ -54,13 +54,8 @@ public:
   std::string name() const override { return "IkedaCarpenterPV"; }
   const std::string category() const override { return "Peak"; }
 
-  // define these instead of functionLocal if you want to custom specify the
-  // calculation
-  // domain for this function
-  // virtual void function(double* out, const double* xValues, const int&
-  // nData)const;
-  // virtual void functionDeriv(API::Jacobian* out, const double* xValues, const
-  // int& nData);
+  /// Returns the integral intensity of the peak
+  double intensity() const override;
 
 protected:
   void functionLocal(double *out, const double *xValues,
diff --git a/Framework/CurveFitting/inc/MantidCurveFitting/Functions/Lorentzian1D.h b/Framework/CurveFitting/inc/MantidCurveFitting/Functions/Lorentzian1D.h
deleted file mode 100644
index 263fc8236a8aa0973c5b22afa6ba5978fb1a1503..0000000000000000000000000000000000000000
--- a/Framework/CurveFitting/inc/MantidCurveFitting/Functions/Lorentzian1D.h
+++ /dev/null
@@ -1,86 +0,0 @@
-#ifndef MANTID_CURVEFITTING_LORENTZIAN1D_H_
-#define MANTID_CURVEFITTING_LORENTZIAN1D_H_
-
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
-#include "MantidCurveFitting/Algorithms/Fit1D.h"
-
-namespace Mantid {
-namespace CurveFitting {
-namespace Functions {
-/**
-Deprecation notice: instead of using this algorithm please use the Fit algorithm
-where the Function parameter of this algorithm is used
-to specified the fitting function.
-
-Takes a histogram in a 2D workspace and fit it to a Lorentzian on top of
-a linear background.
-i.e. a function: Height*( HWHM^2/((x-PeakCentre)^2+HWHM^2) ) + BG0 + BG1*x
-
-Properties specific to this derived class:
-<UL>
-<LI> BG0 - background intercept value (default 0.0)</LI>
-<LI> BG1 - background slope value (default 0.0)</LI>
-<LI> Height - height of peak (default 0.0)</LI>
-<LI> PeakCentre - centre of peak (default 0.0)</LI>
-<LI> HWHM - half-width half-maximum (default 1.0)</LI>
-</UL>
-
-@author Anders Markvardsen, ISIS, RAL
-@date 24/5/2009
-
-Copyright &copy; 2007-9 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>
-*/
-class DLLExport Lorentzian1D : public Algorithms::Fit1D {
-public:
-  /// Algorithm's name for identification overriding a virtual method
-  const std::string name() const override { return "Lorentzian1D"; }
-  /// Summary of algorithms purpose
-  const std::string summary() const override {
-    return "== Deprecation notice == Instead of using this algorithm to fit a "
-           "Lorentzian please use the Fit algorithm where the Function "
-           "parameter of this algorithm is used to specified the fitting "
-           "function, including selecting a Lorentzian.";
-  }
-
-  /// Algorithm's version for identification overriding a virtual method
-  int version() const override { return (1); }
-  /// Algorithm's category for identification overriding a virtual method
-  const std::string category() const override {
-    return "Optimization\\FitAlgorithms";
-  }
-
-private:
-  // Overridden Fit1D methods
-  void declareParameters() override;
-  void function(const double *in, double *out, const double *xValues,
-                const size_t nData) override;
-  void functionDeriv(const double *in, API::Jacobian *out,
-                     const double *xValues, const size_t nData) override;
-};
-
-} // namespace Functions
-} // namespace Algorithm
-} // namespace Mantid
-
-#endif /*MANTID_CURVEFITTING_LORENTZIAN1D_H_*/
diff --git a/Framework/CurveFitting/inc/MantidCurveFitting/Functions/TeixeiraWaterSQE.h b/Framework/CurveFitting/inc/MantidCurveFitting/Functions/TeixeiraWaterSQE.h
index 1b812d45bab61f7de2333cd2765c11f3e4154b94..b0d5e9468e41ab2656d0d280df730a20527af167 100644
--- a/Framework/CurveFitting/inc/MantidCurveFitting/Functions/TeixeiraWaterSQE.h
+++ b/Framework/CurveFitting/inc/MantidCurveFitting/Functions/TeixeiraWaterSQE.h
@@ -4,11 +4,17 @@
 // Mantid Coding standars <http://www.mantidproject.org/Coding_Standards>
 // Mantid Headers from the same project
 // Mantid headers from other projects
-#include "MantidAPI/ParamFunction.h"
-#include "MantidAPI/IFunction1D.h"
+#include "MantidCurveFitting/Functions/FunctionQDepends.h"
 // 3rd party library headers (N/A)
 // standard library headers (N/A)
 
+namespace API {
+//----------------------------------------------------------------------
+// Forward declaration
+//----------------------------------------------------------------------
+class Jacobian;
+}
+
 namespace Mantid {
 namespace CurveFitting {
 namespace Functions {
@@ -41,23 +47,18 @@ Code Documentation is available at: <http://doxygen.mantidproject.org>
 /**
  * @brief Teixeira's model to describe the translational diffusion of water
  */
-class DLLExport TeixeiraWaterSQE : public API::ParamFunction,
-                                   public API::IFunction1D {
-public:
-  TeixeiraWaterSQE();
-
-  /// overwrite IFunction base class methods
-  void init() override;
+class DLLExport TeixeiraWaterSQE : public FunctionQDepends {
 
-  /// overwrite IFunction base class methods
+public:
   std::string name() const override { return "TeixeiraWaterSQE"; }
-
-  /// overwrite IFunction base class methods
   const std::string category() const override { return "QuasiElastic"; }
-
-protected:
   void function1D(double *out, const double *xValues,
                   const size_t nData) const override;
+  void functionDeriv1D(Mantid::API::Jacobian *jacobian, const double *xValues,
+                       const size_t nData) override;
+
+protected:
+  void declareParameters() override;
 };
 
 } // namespace Functions
diff --git a/Framework/CurveFitting/inc/MantidCurveFitting/Functions/Voigt.h b/Framework/CurveFitting/inc/MantidCurveFitting/Functions/Voigt.h
index 36b14ecff7d2c7b9164599b21079dc94e83c9890..c959d433208105829fbb328988ee1ed8901e7ca4 100644
--- a/Framework/CurveFitting/inc/MantidCurveFitting/Functions/Voigt.h
+++ b/Framework/CurveFitting/inc/MantidCurveFitting/Functions/Voigt.h
@@ -65,6 +65,10 @@ private:
   void setHeight(const double value) override;
   /// Set the FWHM of the peak
   void setFwhm(const double value) override;
+  /// Returns the integral intensity of the peak
+  double intensity() const override;
+  /// Sets the integral intensity of the peak
+  void setIntensity(const double value) override;
 };
 
 } // namespace Functions
diff --git a/Framework/CurveFitting/inc/MantidCurveFitting/IFittingAlgorithm.h b/Framework/CurveFitting/inc/MantidCurveFitting/IFittingAlgorithm.h
index 7ee55bed0c1c5fd2eaa493563eb3ad739baf4d74..0abe12832cbc8a9f1429ea903ceb9c6d272dd4cb 100644
--- a/Framework/CurveFitting/inc/MantidCurveFitting/IFittingAlgorithm.h
+++ b/Framework/CurveFitting/inc/MantidCurveFitting/IFittingAlgorithm.h
@@ -13,6 +13,10 @@ class IFunction;
 
 namespace CurveFitting {
 
+namespace CostFunctions {
+class CostFuncFitting;
+}
+
 /**
 
   A base class for fitting algorithms. It declares two properties:
@@ -68,6 +72,10 @@ private:
 protected:
   void setFunction();
   void addWorkspaces();
+  std::vector<std::string> getCostFunctionNames() const;
+  void declareCostFunctionProperty();
+  boost::shared_ptr<CostFunctions::CostFuncFitting>
+  getCostFunctionInitialized() const;
 
   /// Keep the domain type
   API::IDomainCreator::DomainType m_domainType{API::IDomainCreator::Simple};
diff --git a/Framework/CurveFitting/src/Algorithms/CalculateCostFunction.cpp b/Framework/CurveFitting/src/Algorithms/CalculateCostFunction.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..80f18582b398b17f9b9a98a3707f8ec75240976f
--- /dev/null
+++ b/Framework/CurveFitting/src/Algorithms/CalculateCostFunction.cpp
@@ -0,0 +1,57 @@
+#include "MantidCurveFitting/Algorithms/CalculateCostFunction.h"
+
+#include "MantidAPI/CostFunctionFactory.h"
+#include "MantidCurveFitting/CostFunctions/CostFuncFitting.h"
+#include "MantidKernel/ListValidator.h"
+
+namespace Mantid {
+namespace CurveFitting {
+namespace Algorithms {
+
+using namespace Kernel;
+using namespace API;
+
+// Register the algorithm into the AlgorithmFactory
+DECLARE_ALGORITHM(CalculateCostFunction)
+
+//----------------------------------------------------------------------------------------------
+
+/// Algorithms name for identification. @see Algorithm::name
+const std::string CalculateCostFunction::name() const {
+  return "CalculateCostFunction";
+}
+
+/// Algorithm's version for identification. @see Algorithm::version
+int CalculateCostFunction::version() const { return 1; }
+
+/// Algorithm's summary for use in the GUI and help. @see Algorithm::summary
+const std::string CalculateCostFunction::summary() const {
+  return "Calculate cost function for a function and a data set in a "
+         "workspace.";
+}
+
+//----------------------------------------------------------------------------------------------
+/// Initialize the algorithm's properties.
+void CalculateCostFunction::initConcrete() {
+  declareCostFunctionProperty();
+  declareProperty("Value", 0.0, "Output value of the cost function.",
+                  Direction::Output);
+}
+
+//----------------------------------------------------------------------------------------------
+/// Execute the algorithm.
+void CalculateCostFunction::execConcrete() {
+
+  if (!m_costFunction) {
+    m_costFunction = getCostFunctionInitialized();
+  }
+
+  // Get the result.
+  double value = m_costFunction->val();
+  // Store the result.
+  setProperty("Value", value);
+}
+
+} // namespace Algorithms
+} // namespace CurveFitting
+} // namespace Mantid
diff --git a/Framework/CurveFitting/src/Algorithms/ConvertToYSpace.cpp b/Framework/CurveFitting/src/Algorithms/ConvertToYSpace.cpp
index fe99f86d374f3b2d78dec702556751f331c83415..879188a934350402fbabd087ea7986f0dce016fa 100644
--- a/Framework/CurveFitting/src/Algorithms/ConvertToYSpace.cpp
+++ b/Framework/CurveFitting/src/Algorithms/ConvertToYSpace.cpp
@@ -4,6 +4,7 @@
 #include "MantidAPI/HistogramValidator.h"
 #include "MantidAPI/InstrumentValidator.h"
 #include "MantidAPI/MatrixWorkspace.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidAPI/WorkspaceUnitValidator.h"
 #include "MantidGeometry/Instrument.h"
@@ -196,6 +197,11 @@ void ConvertToYSpace::exec() {
   const int64_t nreports = nhist;
   auto progress = boost::make_shared<Progress>(this, 0.0, 1.0, nreports);
 
+  auto &spectrumInfo = m_outputWS->mutableSpectrumInfo();
+  SpectrumInfo *qSpectrumInfo{nullptr};
+  if (m_qOutputWS)
+    qSpectrumInfo = &m_qOutputWS->mutableSpectrumInfo();
+
   PARALLEL_FOR_IF(Kernel::threadSafe(*m_inputWS, *m_outputWS))
   for (int64_t i = 0; i < nhist; ++i) {
     PARALLEL_START_INTERUPT_REGION
@@ -203,9 +209,14 @@ void ConvertToYSpace::exec() {
     if (!convert(i)) {
       g_log.warning("No detector defined for index=" + std::to_string(i) +
                     ". Zeroing spectrum.");
-      m_outputWS->maskWorkspaceIndex(i);
-      if (m_qOutputWS)
-        m_qOutputWS->maskWorkspaceIndex(i);
+      m_outputWS->getSpectrum(i).clearData();
+      PARALLEL_CRITICAL(setMasked) {
+        spectrumInfo.setMasked(i, true);
+        if (m_qOutputWS) {
+          m_qOutputWS->getSpectrum(i).clearData();
+          qSpectrumInfo->setMasked(i, true);
+        }
+      }
     }
 
     PARALLEL_END_INTERUPT_REGION
diff --git a/Framework/CurveFitting/src/Algorithms/EstimateFitParameters.cpp b/Framework/CurveFitting/src/Algorithms/EstimateFitParameters.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..680aa066e296164a201a07e47cdfa715bd91bb87
--- /dev/null
+++ b/Framework/CurveFitting/src/Algorithms/EstimateFitParameters.cpp
@@ -0,0 +1,455 @@
+#include "MantidCurveFitting/Algorithms/EstimateFitParameters.h"
+
+#include "MantidAPI/ConstraintFactory.h"
+#include "MantidAPI/CostFunctionFactory.h"
+#include "MantidAPI/Expression.h"
+#include "MantidAPI/ITableWorkspace.h"
+#include "MantidAPI/TableRow.h"
+#include "MantidAPI/WorkspaceFactory.h"
+#include "MantidCurveFitting/Constraints/BoundaryConstraint.h"
+#include "MantidCurveFitting/CostFunctions/CostFuncFitting.h"
+#include "MantidCurveFitting/Functions/ChebfunBase.h"
+#include "MantidKernel/ListValidator.h"
+#include "MantidKernel/MersenneTwister.h"
+#include "MantidKernel/NormalDistribution.h"
+
+#include <map>
+#include <numeric>
+
+namespace Mantid {
+namespace CurveFitting {
+namespace Algorithms {
+
+using namespace Kernel;
+using namespace API;
+
+// Register the algorithm into the AlgorithmFactory
+DECLARE_ALGORITHM(EstimateFitParameters)
+
+namespace {
+
+const size_t MAX_APPROX_SIZE = 129;
+const double MIN_APPROX_TOLERANCE = 1e-4;
+
+/// Return a sum of constraints penalty values.
+double
+getConstraints(const std::vector<std::unique_ptr<IConstraint>> &constraints) {
+  return std::accumulate(constraints.begin(), constraints.end(), 0.0,
+                         [](double s, const std::unique_ptr<IConstraint> &c) {
+                           return s + c->check();
+                         });
+}
+
+/// Defines a 1D slice of a cost function along direction of
+/// one of its parameters.
+struct Slice {
+  double operator()(double p) {
+    m_costFunction.setParameter(m_paramIndex, p);
+    m_costFunction.applyTies();
+    return m_costFunction.val();
+  }
+  /// The cost function
+  CostFunctions::CostFuncFitting &m_costFunction;
+  /// Index of the running parameter
+  size_t m_paramIndex;
+};
+
+/// Try to estimate if any of the parameters can cause problems during fitting.
+/// If such parameters are found - fix them.
+/// @param costFunction :: The cost function.
+/// @param ranges :: The ranges of values within which the parameters may
+/// change.
+void fixBadParameters(CostFunctions::CostFuncFitting &costFunction,
+                      const std::vector<std::pair<double, double>> &ranges) {
+  std::vector<size_t> indicesOfFixed;
+  std::vector<double> P, A, D;
+  auto &fun = *costFunction.getFittingFunction();
+  for (size_t i = 0, j = 0; i < fun.nParams(); ++i) {
+    if (fun.isFixed(i)) {
+      continue;
+    }
+    auto lBound = ranges[j].first;
+    auto rBound = ranges[j].second;
+    auto storedParam = fun.getParameter(i);
+    Slice slice{costFunction, j};
+    auto base = Functions::ChebfunBase::bestFitAnyTolerance(
+        lBound, rBound, slice, P, A, 1.0, MIN_APPROX_TOLERANCE,
+        MAX_APPROX_SIZE);
+    bool fix = false;
+    if (!base) {
+      fun.setParameter(i, storedParam);
+      base = boost::make_shared<Functions::ChebfunBase>(
+          MAX_APPROX_SIZE, lBound, rBound, MIN_APPROX_TOLERANCE);
+      P = base->fit(slice);
+      A = base->calcA(P);
+    }
+    base->derivative(A, D);
+    auto roots = base->roots(D);
+    if (!roots.empty()) {
+      if (roots.size() * 2 >= base->size()) {
+        // If the approximating polynomial oscillates too much
+        // the parameter is likely to be bad.
+        fix = true;
+      }
+    }
+    fun.setParameter(i, storedParam);
+
+    if (fix) {
+      // Parameter is bad - fix it. Delay actual fixing until all bad ones
+      // found.
+      indicesOfFixed.push_back(i);
+    }
+    ++j;
+  }
+  for (auto i : indicesOfFixed) {
+    fun.tie(fun.parameterName(i), std::to_string(fun.getParameter(i)));
+  }
+}
+
+/// A class for sorting and storing sets of best function parameters.
+class BestParameters {
+  /// Maximum size of the store
+  size_t m_size;
+  /// Actual storage.
+  std::map<double, GSLVector> m_params;
+
+public:
+  /// Constructor
+  explicit BestParameters(size_t size) : m_size(size) {}
+  /// Test a cost function value if corresponding parameters must be stored.
+  bool isOneOfBest(double value) const {
+    return m_params.size() < m_size || value < m_params.rbegin()->first;
+  }
+  /// Insert a set of parameters to the store.
+  void insertParams(double value, const GSLVector &params) {
+    if (m_params.size() == m_size) {
+      auto it = m_params.find(m_params.rbegin()->first);
+      m_params.erase(it);
+    }
+    m_params[value] = params;
+  }
+  /// Return all stored parameters, drop function values.
+  std::vector<GSLVector> getParams() const {
+    std::vector<GSLVector> res;
+    res.reserve(m_params.size());
+    for (auto &it : m_params) {
+      res.push_back(it.second);
+    }
+    return res;
+  }
+};
+
+/// Run the Monte Carlo version of the algorithm.
+/// Generate random values of function parameters and return those that
+/// give the smallest cost function.
+/// @param costFunction :: The cost function.
+/// @param ranges :: The ranges of values defining the uniform distributions for
+/// the parameters.
+/// @param constraints :: Additional constraints.
+/// @param nSamples :: A number of samples to generate.
+/// @param seed :: A seed for the random number generator.
+std::vector<GSLVector>
+runMonteCarlo(CostFunctions::CostFuncFitting &costFunction,
+              const std::vector<std::pair<double, double>> &ranges,
+              const std::vector<std::unique_ptr<IConstraint>> &constraints,
+              const size_t nSamples, const size_t nOutput, const size_t seed) {
+
+  Kernel::MersenneTwister randGenerator;
+  if (seed != 0) {
+    randGenerator.setSeed(seed);
+  }
+  double value = costFunction.val() + getConstraints(constraints);
+  auto nParams = costFunction.nParams();
+  GSLVector params;
+  costFunction.getParameters(params);
+  BestParameters bestParams(nOutput);
+  bestParams.insertParams(value, params);
+
+  // Implicit cast from int to size_t
+  for (size_t it = 0; it < nSamples; ++it) {
+    for (size_t i = 0; i < nParams; ++i) {
+      const auto &range = ranges[i];
+      auto p = randGenerator.nextValue(range.first, range.second);
+      costFunction.setParameter(i, p);
+    }
+    costFunction.applyTies();
+    if (getConstraints(constraints) > 0.0) {
+      continue;
+    }
+    value = costFunction.val();
+    if (costFunction.nParams() != nParams) {
+      throw std::runtime_error("Cost function changed number of parameters " +
+                               std::to_string(nParams) + " -> " +
+                               std::to_string(costFunction.nParams()));
+    }
+    if (bestParams.isOneOfBest(value)) {
+      costFunction.getParameters(params);
+      bestParams.insertParams(value, params);
+    }
+  }
+  auto outputParams = bestParams.getParams();
+  costFunction.setParameters(outputParams.front());
+  return outputParams;
+}
+/// Run the Cross Entropy version of the algorithm.
+/// https://en.wikipedia.org/wiki/Cross-entropy_method
+/// How it works:
+///   1. Generate a few sets of function parameters such that their values are
+///   drawn from
+///   normal distributions with given means and sigmas.
+///   2. Calculate the cost function for each set of parameters and select a
+///   number of smallest values.
+///   3. Find the sample means and sigmas of the parameters from the subset
+///   selected in step 2.
+///   4. Repeat steps 1 - 3 a few times.
+///   5. Return parameters for the smallest cost function value found in the
+///   last iteration.
+/// @param costFunction :: The cost function.
+/// @param ranges :: The ranges of values defining the initial distributions for
+/// the parameters:
+///     The middle of the range gives the mean and the spread from the mean is a
+///     sigma.
+/// @param constraints :: Additional constraints.
+/// @param nSamples :: A number of parameter sets (samples) generated in step 1.
+/// @param nSelection :: A number of sets selected in step 2.
+/// @param nIterations :: A number of iterations of the algorithm.
+/// @param seed :: A seed for the random number generator.
+void runCrossEntropy(
+    CostFunctions::CostFuncFitting &costFunction,
+    const std::vector<std::pair<double, double>> &ranges,
+    const std::vector<std::unique_ptr<IConstraint>> &constraints,
+    size_t nSamples, size_t nSelection, size_t nIterations, size_t seed) {
+  // Initialise the normal distribution parameters (mean and sigma for each
+  // function parameter).
+  std::vector<std::pair<double, double>> distributionParams;
+  for (auto &range : ranges) {
+    auto mean = (range.first + range.second) / 2;
+    auto sigma = std::fabs(range.first - range.second) / 2;
+    distributionParams.push_back(std::make_pair(mean, sigma));
+  }
+
+  auto nParams = costFunction.nParams();
+  Kernel::NormalDistribution distribution;
+  if (seed != 0) {
+    distribution.setSeed(seed);
+  }
+  // Sets of function parameters (GSLVector) and corresponding values of the
+  // cost function (double)
+  using ParameterSet = std::pair<double, GSLVector>;
+  std::vector<ParameterSet> sampleSets(nSamples);
+  // Function for comparing parameter sets.
+  auto compareSets = [](const ParameterSet &p1, const ParameterSet &p2) {
+    return p1.first < p2.first;
+  };
+
+  // Run nIterations of the algorithm
+  for (size_t it = 0; it < nIterations; ++it) {
+    for (size_t isam = 0; isam < nSamples; ++isam) {
+      // Draw a set of function parameters from their distributions
+      auto &paramSet = sampleSets[isam];
+      if (paramSet.second.size() != nParams) {
+        paramSet.second.resize(nParams);
+      }
+      for (size_t i = 0; i < nParams; ++i) {
+        auto mean = distributionParams[i].first;
+        auto sigma = distributionParams[i].second;
+        auto p = distribution.randomValue(mean, sigma);
+        paramSet.second[i] = p;
+      }
+      // Calculate the cost function with those parameters
+      costFunction.setParameters(paramSet.second);
+      paramSet.first = costFunction.val() + getConstraints(constraints);
+      if (costFunction.nParams() != nParams) {
+        throw std::runtime_error("Cost function changed number of parameters " +
+                                 std::to_string(nParams) + " -> " +
+                                 std::to_string(costFunction.nParams()));
+      }
+    }
+    // Partially sort the parameter sets in ascending order of the cost
+    // function.
+    // Find nSelection smallest values.
+    std::partial_sort(sampleSets.begin(), sampleSets.begin() + nSelection,
+                      sampleSets.end(), compareSets);
+    // Estimate new distribution parameters from the sample of nSelection sets.
+    GSLVector means(nParams);
+    GSLVector variances(nParams);
+    for (size_t isam = 0; isam < nSelection; ++isam) {
+      auto &paramSet = sampleSets[isam];
+      for (size_t i = 0; i < nParams; ++i) {
+        auto p = paramSet.second[i];
+        means[i] += p;
+        variances[i] += p * p;
+      }
+    }
+    means *= 1.0 / double(nSelection);
+    variances *= 1.0 / double(nSelection);
+    for (size_t i = 0; i < nParams; ++i) {
+      auto mean = means[i];
+      auto sigma = sqrt(variances[i] - mean * mean);
+      distributionParams[i].first = mean;
+      distributionParams[i].second = sigma;
+    }
+  }
+  // Set parameters of the cost function to the best sample set.
+  costFunction.setParameters(sampleSets.front().second);
+}
+
+} // namespace
+
+//----------------------------------------------------------------------------------------------
+
+/// Algorithms name for identification. @see Algorithm::name
+const std::string EstimateFitParameters::name() const {
+  return "EstimateFitParameters";
+}
+
+/// Algorithm's version for identification. @see Algorithm::version
+int EstimateFitParameters::version() const { return 1; }
+
+/// Algorithm's summary for use in the GUI and help. @see Algorithm::summary
+const std::string EstimateFitParameters::summary() const {
+  return "Estimate parameters of a fitting function using a Monte Carlo "
+         "algorithm.";
+}
+
+//----------------------------------------------------------------------------------------------
+/// Initialize the algorithm's properties.
+void EstimateFitParameters::initConcrete() {
+  std::vector<std::string> types{"Monte Carlo", "Cross Entropy"};
+  Kernel::StringListValidator TypesValidator(types);
+
+  declareCostFunctionProperty();
+  declareProperty("NSamples", 100, "Number of samples.");
+  declareProperty("Constraints", "",
+                  "Additional constraints on tied parameters.");
+  declareProperty(
+      "Type", "Monte Carlo",
+      "Type of the algorithm: \"Monte Carlo\" or \"Cross Entropy\"");
+  declareProperty("NOutputs", 10, "Number of parameter sets to output to "
+                                  "OutputWorkspace. Unused if OutputWorkspace "
+                                  "isn't set. (Monte Carlo only)");
+  declareProperty(Kernel::make_unique<WorkspaceProperty<ITableWorkspace>>(
+                      "OutputWorkspace", "", Direction::Output,
+                      Mantid::API::PropertyMode::Optional),
+                  "Optional: A table workspace with parameter sets producing "
+                  "the smallest values of cost function. (Monte Carlo only)");
+  declareProperty("NIterations", 10,
+                  "Number of iterations of the Cross Entropy algorithm.");
+  declareProperty("Selection", 10, "Size of the selection in the Cross Entropy "
+                                   "algorithm from which to estimate new "
+                                   "distribution parameters for the next "
+                                   "iteration.");
+  declareProperty("FixBadParameters", false, "If true try to estimate which "
+                                             "parameters may cause problems "
+                                             "for fitting and fix them.");
+  declareProperty("Seed", 0, "A seed value for the random number generator. "
+                             "The default value (0) makes the generator use a "
+                             "random seed.");
+}
+
+//----------------------------------------------------------------------------------------------
+/// Execute the algorithm.
+void EstimateFitParameters::execConcrete() {
+  auto costFunction = getCostFunctionInitialized();
+  auto func = costFunction->getFittingFunction();
+
+  // Use additional constraints on parameters tied in some way
+  // to the varied parameters to exculde unwanted results.
+  std::vector<std::unique_ptr<IConstraint>> constraints;
+  std::string constraintStr = getProperty("Constraints");
+  if (!constraintStr.empty()) {
+    Expression expr;
+    expr.parse(constraintStr);
+    expr.toList();
+    for (auto &term : expr.terms()) {
+      IConstraint *c =
+          ConstraintFactory::Instance().createInitialized(func.get(), term);
+      constraints.push_back(std::unique_ptr<IConstraint>(c));
+    }
+  }
+
+  // Ranges to use with random number generators: one for each free parameter.
+  std::vector<std::pair<double, double>> ranges;
+  ranges.reserve(costFunction->nParams());
+  for (size_t i = 0; i < func->nParams(); ++i) {
+    if (func->isFixed(i)) {
+      continue;
+    }
+    auto constraint = func->getConstraint(i);
+    if (constraint == nullptr) {
+      func->fix(i);
+      continue;
+    }
+    auto boundary = dynamic_cast<Constraints::BoundaryConstraint *>(constraint);
+    if (boundary == nullptr) {
+      throw std::runtime_error("Parameter " + func->parameterName(i) +
+                               " must have a boundary constraint. ");
+    }
+    if (!boundary->hasLower()) {
+      throw std::runtime_error("Constraint of " + func->parameterName(i) +
+                               " must have a lower bound.");
+    }
+    if (!boundary->hasUpper()) {
+      throw std::runtime_error("Constraint of " + func->parameterName(i) +
+                               " must have an upper bound.");
+    }
+    // Use the lower and upper bounds of the constraint to set the range
+    // of a generator with uniform distribution.
+    ranges.push_back(std::make_pair(boundary->lower(), boundary->upper()));
+  }
+  // Number of parameters could have changed
+  costFunction->reset();
+  if (costFunction->nParams() == 0) {
+    throw std::runtime_error("No parameters are given for which to estimate "
+                             "initial values. Set boundary constraints to "
+                             "parameters that need to be estimated.");
+  }
+
+  size_t nSamples = static_cast<int>(getProperty("NSamples"));
+  size_t seed = static_cast<int>(getProperty("Seed"));
+
+  if (getPropertyValue("Type") == "Monte Carlo") {
+    int nOutput = getProperty("NOutputs");
+    auto outputWorkspaceProp = getPointerToProperty("OutputWorkspace");
+    if (outputWorkspaceProp->isDefault() || nOutput <= 0) {
+      nOutput = 1;
+    }
+    auto output = runMonteCarlo(*costFunction, ranges, constraints, nSamples,
+                                static_cast<size_t>(nOutput), seed);
+
+    if (!outputWorkspaceProp->isDefault()) {
+      auto table = API::WorkspaceFactory::Instance().createTable();
+      auto column = table->addColumn("str", "Name");
+      column->setPlotType(6);
+      for (size_t i = 0; i < output.size(); ++i) {
+        column = table->addColumn("double", std::to_string(i + 1));
+        column->setPlotType(2);
+      }
+
+      for (size_t i = 0, ia = 0; i < m_function->nParams(); ++i) {
+        if (!m_function->isFixed(i)) {
+          TableRow row = table->appendRow();
+          row << m_function->parameterName(i);
+          for (size_t j = 0; j < output.size(); ++j) {
+            row << output[j][ia];
+          }
+          ++ia;
+        }
+      }
+      setProperty("OutputWorkspace", table);
+    }
+  } else {
+    size_t nSelection = static_cast<int>(getProperty("Selection"));
+    size_t nIterations = static_cast<int>(getProperty("NIterations"));
+    runCrossEntropy(*costFunction, ranges, constraints, nSamples, nSelection,
+                    nIterations, seed);
+  }
+  bool fixBad = getProperty("FixBadParameters");
+  if (fixBad) {
+    fixBadParameters(*costFunction, ranges);
+  }
+}
+
+} // namespace Algorithms
+} // namespace CurveFitting
+} // namespace Mantid
diff --git a/Framework/CurveFitting/src/Algorithms/EvaluateFunction.cpp b/Framework/CurveFitting/src/Algorithms/EvaluateFunction.cpp
index 92dda1a5f9b5500b68fe025749d36d0b0b5b9b7d..5905625620ca01cdd65365534e6cec46fee2fd37 100644
--- a/Framework/CurveFitting/src/Algorithms/EvaluateFunction.cpp
+++ b/Framework/CurveFitting/src/Algorithms/EvaluateFunction.cpp
@@ -1,4 +1,5 @@
 #include "MantidCurveFitting/Algorithms/EvaluateFunction.h"
+#include "MantidAPI/Workspace.h"
 
 namespace Mantid {
 namespace CurveFitting {
@@ -45,6 +46,9 @@ void EvaluateFunction::execConcrete() {
   // Do something with the function which may depend on workspace.
   m_domainCreator->initFunction(m_function);
 
+  // Apply any ties.
+  m_function->applyTies();
+
   // Calculate function values.
   m_function->function(*domain, *values);
 
diff --git a/Framework/CurveFitting/src/Algorithms/Fit.cpp b/Framework/CurveFitting/src/Algorithms/Fit.cpp
index 7805de53b27461817170dbdb1da235c2a9df8fcb..f9341b161e864f711dbd3e75f82c1d7083e7452e 100644
--- a/Framework/CurveFitting/src/Algorithms/Fit.cpp
+++ b/Framework/CurveFitting/src/Algorithms/Fit.cpp
@@ -4,9 +4,7 @@
 #include "MantidCurveFitting/Algorithms/Fit.h"
 #include "MantidCurveFitting/CostFunctions/CostFuncFitting.h"
 
-#include "MantidAPI/CostFunctionFactory.h"
 #include "MantidAPI/FuncMinimizerFactory.h"
-#include "MantidAPI/FunctionValues.h"
 #include "MantidAPI/IFuncMinimizer.h"
 #include "MantidAPI/ITableWorkspace.h"
 #include "MantidAPI/MatrixWorkspace.h"
@@ -53,11 +51,7 @@ void Fit::initConcrete() {
       boost::make_shared<Kernel::StartsWithValidator>(minimizerOptions);
 
   declareProperty("Minimizer", "Levenberg-Marquardt", minimizerValidator,
-                  "Minimizer to use for fitting. Minimizers available are "
-                  "\"Levenberg-Marquardt\", \"Simplex\", \"FABADA\", "
-                  "\"Conjugate gradient (Fletcher-Reeves imp.)\", \"Conjugate "
-                  "gradient (Polak-Ribiere imp.)\", \"BFGS\", and "
-                  "\"Levenberg-MarquardtMD\"");
+                  "Minimizer to use for fitting.");
 
   std::vector<std::string> costFuncOptions =
       API::CostFunctionFactory::Instance().getKeys();
@@ -134,32 +128,16 @@ void Fit::execConcrete() {
     m_function->addConstraints(contstraints);
   }
 
-  // prepare the function for a fit
-  m_function->setUpForFit();
+  auto costFunc = getCostFunctionInitialized();
 
-  API::FunctionDomain_sptr domain;
-  API::FunctionValues_sptr values;
-  m_domainCreator->createDomain(domain, values);
-
-  // do something with the function which may depend on workspace
-  m_domainCreator->initFunction(m_function);
+  // Try to retrieve optional properties
+  int intMaxIterations = getProperty("MaxIterations");
+  const size_t maxIterations = static_cast<size_t>(intMaxIterations);
 
   // get the minimizer
   std::string minimizerName = getPropertyValue("Minimizer");
   API::IFuncMinimizer_sptr minimizer =
       API::FuncMinimizerFactory::Instance().createMinimizer(minimizerName);
-
-  // Try to retrieve optional properties
-  int intMaxIterations = getProperty("MaxIterations");
-  const size_t maxIterations = static_cast<size_t>(intMaxIterations);
-
-  // get the cost function which must be a CostFuncFitting
-  boost::shared_ptr<CostFunctions::CostFuncFitting> costFunc =
-      boost::dynamic_pointer_cast<CostFunctions::CostFuncFitting>(
-          API::CostFunctionFactory::Instance().create(
-              getPropertyValue("CostFunction")));
-
-  costFunc->setFittingFunction(m_function, domain, values);
   minimizer->initialize(costFunc, maxIterations);
 
   const int64_t nsteps = maxIterations * m_function->estimateNoProgressCalls();
@@ -205,7 +183,7 @@ void Fit::execConcrete() {
   setPropertyValue("OutputStatus", errorString);
 
   // degrees of freedom
-  size_t dof = domain->size() - costFunc->nParams();
+  size_t dof = costFunc->getDomain()->size() - costFunc->nParams();
   if (dof == 0)
     dof = 1;
   double rawcostfuncval = minimizer->costFunctionVal();
@@ -242,7 +220,7 @@ void Fit::execConcrete() {
     copyMinimizerOutput(*minimizer);
 
     if (baseName.empty()) {
-      baseName = ws->name();
+      baseName = ws->getName();
       if (baseName.empty()) {
         baseName = "Output";
       }
@@ -356,8 +334,8 @@ void Fit::execConcrete() {
       }
       m_domainCreator->separateCompositeMembersInOutput(unrollComposites,
                                                         convolveMembers);
-      m_domainCreator->createOutputWorkspace(baseName, m_function, domain,
-                                             values);
+      m_domainCreator->createOutputWorkspace(
+          baseName, m_function, costFunc->getDomain(), costFunc->getValues());
     }
   }
 
diff --git a/Framework/CurveFitting/src/Algorithms/FitPowderDiffPeaks.cpp b/Framework/CurveFitting/src/Algorithms/FitPowderDiffPeaks.cpp
index 0d5db13d4b630f2dbc56e6fd92645c67b249479a..88fc5cd25a35df8d609939b5a449c465db2a7663 100644
--- a/Framework/CurveFitting/src/Algorithms/FitPowderDiffPeaks.cpp
+++ b/Framework/CurveFitting/src/Algorithms/FitPowderDiffPeaks.cpp
@@ -24,10 +24,11 @@
 #include "MantidCurveFitting/Functions/Gaussian.h"
 #include "MantidCurveFitting/Functions/BackToBackExponential.h"
 #include "MantidCurveFitting/Functions/ThermalNeutronBk2BkExpConvPVoigt.h"
-#include "MantidCurveFitting/FuncMinimizers/DampingMinimizer.h"
+#include "MantidCurveFitting/FuncMinimizers/DampedGaussNewtonMinimizer.h"
 #include "MantidCurveFitting/CostFunctions/CostFuncFitting.h"
 
 #include <fstream>
+#include <iostream>
 
 #include <gsl/gsl_sf_erf.h>
 #include <cmath>
@@ -369,8 +370,7 @@ void FitPowderDiffPeaks::fitPeaksRobust() {
       m_vecPeakFunctions[0].second.second->getParameterNames();
 
   // II. Create local background function.
-  Polynomial_sptr backgroundfunction =
-      boost::make_shared<Polynomial>(Polynomial());
+  Polynomial_sptr backgroundfunction = boost::make_shared<Polynomial>();
   backgroundfunction->setAttributeValue("n", 1);
   backgroundfunction->initialize();
 
@@ -1104,8 +1104,7 @@ bool FitPowderDiffPeaks::fitSinglePeakSimulatedAnnealing(
  */
 void FitPowderDiffPeaks::fitPeaksWithGoodStartingValues() {
   // 1. Initialize (local) background function
-  Polynomial_sptr backgroundfunction =
-      boost::make_shared<Polynomial>(Polynomial());
+  Polynomial_sptr backgroundfunction = boost::make_shared<Polynomial>();
   backgroundfunction->setAttributeValue("n", 1);
   backgroundfunction->initialize();
 
@@ -1255,19 +1254,19 @@ bool FitPowderDiffPeaks::fitSinglePeakConfident(
   // a) Peak centre
   double peakcentreleftbound = peak->centre() - peak->fwhm();
   double peakcentrerightbound = peak->centre() + peak->fwhm();
-  BoundaryConstraint *x0bc = new BoundaryConstraint(
+  auto x0bc = Kernel::make_unique<BoundaryConstraint>(
       peak.get(), "X0", peakcentreleftbound, peakcentrerightbound);
-  peak->addConstraint(x0bc);
+  peak->addConstraint(std::move(x0bc));
 
   // b) A
-  BoundaryConstraint *abc =
-      new BoundaryConstraint(peak.get(), "A", 1.0E-10, false);
-  peak->addConstraint(abc);
+  auto abc =
+      Kernel::make_unique<BoundaryConstraint>(peak.get(), "A", 1.0E-10, false);
+  peak->addConstraint(std::move(abc));
 
   // c) B
-  BoundaryConstraint *bbc =
-      new BoundaryConstraint(peak.get(), "B", 1.0E-10, false);
-  peak->addConstraint(bbc);
+  auto bbc =
+      Kernel::make_unique<BoundaryConstraint>(peak.get(), "B", 1.0E-10, false);
+  peak->addConstraint(std::move(bbc));
 
   // d) Guessed height
   peak->setHeight(maxheight);
@@ -1523,26 +1522,26 @@ FitPowderDiffPeaks::doFitPeak(Workspace2D_sptr dataws,
     double tof_h = peakfunction->centre();
     double centerleftend = tof_h - guessedfwhm * 3.0;
     double centerrightend = tof_h + guessedfwhm * 3.0;
-    BoundaryConstraint *centerbound = new BoundaryConstraint(
+    auto centerbound = Kernel::make_unique<BoundaryConstraint>(
         peakfunction.get(), "X0", centerleftend, centerrightend, false);
-    peakfunction->addConstraint(centerbound);
+    peakfunction->addConstraint(std::move(centerbound));
 
     g_log.debug() << "[DoFitPeak] Peak Center Boundary = " << centerleftend
                   << ", " << centerrightend << '\n';
   }
 
   // A > 0, B > 0, S > 0
-  BoundaryConstraint *abound = new BoundaryConstraint(
+  auto abound = Kernel::make_unique<BoundaryConstraint>(
       peakfunction.get(), "A", 0.0000001, DBL_MAX, false);
-  peakfunction->addConstraint(abound);
+  peakfunction->addConstraint(std::move(abound));
 
-  BoundaryConstraint *bbound = new BoundaryConstraint(
+  auto bbound = Kernel::make_unique<BoundaryConstraint>(
       peakfunction.get(), "B", 0.0000001, DBL_MAX, false);
-  peakfunction->addConstraint(bbound);
+  peakfunction->addConstraint(std::move(bbound));
 
-  BoundaryConstraint *sbound =
-      new BoundaryConstraint(peakfunction.get(), "S", 0.0001, DBL_MAX, false);
-  peakfunction->addConstraint(sbound);
+  auto sbound = Kernel::make_unique<BoundaryConstraint>(peakfunction.get(), "S",
+                                                        0.0001, DBL_MAX, false);
+  peakfunction->addConstraint(std::move(sbound));
 
   // 2. Unfix all parameters
   vector<string> paramnames = peakfunction->getParameterNames();
@@ -1811,10 +1810,9 @@ bool FitPowderDiffPeaks::doFitGaussianPeak(DataObjects::Workspace2D_sptr dataws,
   // b) Constraint
   double centerleftend = in_center - leftfwhm * 0.5;
   double centerrightend = in_center + rightfwhm * 0.5;
-  Constraints::BoundaryConstraint *centerbound =
-      new Constraints::BoundaryConstraint(gaussianpeak.get(), "PeakCentre",
-                                          centerleftend, centerrightend, false);
-  gaussianpeak->addConstraint(centerbound);
+  auto centerbound = Kernel::make_unique<BoundaryConstraint>(
+      gaussianpeak.get(), "PeakCentre", centerleftend, centerrightend, false);
+  gaussianpeak->addConstraint(std::move(centerbound));
 
   // 3. Fit
   API::IAlgorithm_sptr fitalg = createChildAlgorithm("Fit", -1, -1, true);
@@ -2118,9 +2116,9 @@ void FitPowderDiffPeaks::setOverlappedPeaksConstraints(
     double leftcentrebound = centre - 0.5 * fwhm;
     double rightcentrebound = centre + 0.5 * fwhm;
 
-    BoundaryConstraint *bc = new BoundaryConstraint(
+    auto bc = Kernel::make_unique<BoundaryConstraint>(
         thispeak.get(), "X0", leftcentrebound, rightcentrebound, false);
-    thispeak->addConstraint(bc);
+    thispeak->addConstraint(std::move(bc));
   }
 }
 
@@ -2263,7 +2261,7 @@ void FitPowderDiffPeaks::importInstrumentParameterFromTable(
 
   size_t numrows = parameterWS->rowCount();
 
-  g_log.notice() << "[DBx409] Import TableWorkspace " << parameterWS->name()
+  g_log.notice() << "[DBx409] Import TableWorkspace " << parameterWS->getName()
                  << " containing " << numrows
                  << " instrument profile parameters\n";
 
@@ -2327,7 +2325,7 @@ void FitPowderDiffPeaks::parseBraggPeakTable(
 
   g_log.information() << "Import " << hklmaps.size()
                       << " entries from Bragg peak TableWorkspace "
-                      << peakws->name() << '\n';
+                      << peakws->getName() << '\n';
 }
 
 //----------------------------------------------------------------------------
@@ -2726,10 +2724,9 @@ FitPowderDiffPeaks::genPeak(map<string, int> hklmap,
                             map<string, string> bk2bk2braggmap, bool &good,
                             vector<int> &hkl, double &d_h) {
   // Generate a peak function
-  BackToBackExponential newpeak;
-  newpeak.initialize();
   BackToBackExponential_sptr newpeakptr =
-      boost::make_shared<BackToBackExponential>(newpeak);
+      boost::make_shared<BackToBackExponential>();
+  newpeakptr->initialize();
 
   // Check miller index (HKL) is a valid value in a miller indexes pool (hklmap)
   good = getHKLFromMap(hklmap, hkl);
diff --git a/Framework/CurveFitting/src/Algorithms/LeBailFit.cpp b/Framework/CurveFitting/src/Algorithms/LeBailFit.cpp
index cfc8bfa10d65cad1aa1988a7ab81a8941e14e504..52d1673447dde517b89adbb682ad4fe48e101edb 100644
--- a/Framework/CurveFitting/src/Algorithms/LeBailFit.cpp
+++ b/Framework/CurveFitting/src/Algorithms/LeBailFit.cpp
@@ -15,7 +15,9 @@
 #include <boost/algorithm/string.hpp>
 #include <boost/algorithm/string/split.hpp>
 
+#include <cctype>
 #include <fstream>
+#include <iomanip>
 
 const int OBSDATAINDEX(0);
 const int CALDATAINDEX(1);
@@ -206,7 +208,8 @@ void LeBailFit::init() {
   setPropertySettings("Minimizer", Kernel::make_unique<VisibleWhenProperty>(
                                        "Function", IS_EQUAL_TO, "LeBailFit"));
 
-  declareProperty("Damping", 1.0, "Damping factor if minizer is 'Damping'");
+  declareProperty("Damping", 1.0,
+                  "Damping factor if minimizer is 'Damped Gauss-Newton'");
   setPropertySettings("Damping", Kernel::make_unique<VisibleWhenProperty>(
                                      "Function", IS_EQUAL_TO, "LeBailFit"));
   setPropertySettings("Damping", Kernel::make_unique<VisibleWhenProperty>(
@@ -910,7 +913,7 @@ void LeBailFit::parseInstrumentParametersTable() {
   } else {
     g_log.information()
         << "[DB] Starting to parse instrument parameter table workspace "
-        << parameterWS->name() << ".\n";
+        << parameterWS->getName() << ".\n";
   }
 
   // 2. Import data to maps
@@ -967,7 +970,7 @@ void LeBailFit::parseInstrumentParametersTable() {
       newparameter.name = striter->second;
     } else {
       std::stringstream errmsg;
-      errmsg << "Parameter (table) workspace " << parameterWS->name()
+      errmsg << "Parameter (table) workspace " << parameterWS->getName()
              << " does not contain column 'Name'.  It is not a valid input.  "
                 "Quit ";
       g_log.error() << errmsg.str() << "\n";
@@ -988,7 +991,7 @@ void LeBailFit::parseInstrumentParametersTable() {
       newparameter.fit = tofit;
     } else {
       std::stringstream errmsg;
-      errmsg << "Parameter (table) workspace " << parameterWS->name()
+      errmsg << "Parameter (table) workspace " << parameterWS->getName()
              << " does not contain column 'FitOrTie'.  It is not a valid "
                 "input.  Quit ";
       g_log.error() << errmsg.str() << "\n";
@@ -1001,7 +1004,7 @@ void LeBailFit::parseInstrumentParametersTable() {
       newparameter.curvalue = dbliter->second;
     } else {
       std::stringstream errmsg;
-      errmsg << "Parameter (table) workspace " << parameterWS->name()
+      errmsg << "Parameter (table) workspace " << parameterWS->getName()
              << " does not contain column 'Value'.  It is not a valid input.  "
                 "Quit ";
       g_log.error() << errmsg.str() << "\n";
@@ -1057,7 +1060,7 @@ void LeBailFit::parseInstrumentParametersTable() {
 
   g_log.information()
       << "[DB]: Successfully Imported Peak Parameters TableWorkspace "
-      << parameterWS->name() << ". Imported " << m_funcParameters.size()
+      << parameterWS->getName() << ". Imported " << m_funcParameters.size()
       << " parameters. "
       << "\n";
 }
@@ -1148,7 +1151,7 @@ void LeBailFit::parseBackgroundTableWorkspace(TableWorkspace_sptr bkgdparamws,
   if (colnames.size() < 2) {
     stringstream errss;
     errss << "Input background parameter table workspace "
-          << bkgdparamws->name() << " has only " << colnames.size()
+          << bkgdparamws->getName() << " has only " << colnames.size()
           << " columns, which is fewer than 2 columns as required. ";
     g_log.error(errss.str());
     throw runtime_error(errss.str());
@@ -1179,7 +1182,7 @@ void LeBailFit::parseBackgroundTableWorkspace(TableWorkspace_sptr bkgdparamws,
     // Remove extra white spaces
     boost::algorithm::trim(parname);
 
-    if (parname.size() > 0 && (parname[0] == 'A' || parname == "Bkpos")) {
+    if (!parname.empty() && (parname[0] == 'A' || parname == "Bkpos")) {
       // Insert parameter name starting with A or Bkpos (special case for
       // FullprofPolynomial)
       parmap.emplace(parname, parvalue);
@@ -1403,8 +1406,7 @@ void LeBailFit::createOutputDataWorkspace() {
   // 4. Set axis
   m_outputWS->getAxis(0)->setUnit("TOF");
 
-  API::TextAxis *tAxis = nullptr;
-  tAxis = new API::TextAxis(nspec);
+  API::TextAxis *tAxis = new API::TextAxis(nspec);
   tAxis->setLabel(0, "Data");
   tAxis->setLabel(1, "Calc");
   tAxis->setLabel(2, "Diff");
diff --git a/Framework/CurveFitting/src/Algorithms/LeBailFunction.cpp b/Framework/CurveFitting/src/Algorithms/LeBailFunction.cpp
index a85af08502f8ccd97498e50cea3c1275831d541a..106535075f7cef1901e279ccd6768001f2d4bfd8 100644
--- a/Framework/CurveFitting/src/Algorithms/LeBailFunction.cpp
+++ b/Framework/CurveFitting/src/Algorithms/LeBailFunction.cpp
@@ -106,7 +106,7 @@ LeBailFunction::function(const Mantid::HistogramData::HistogramX &xvalues,
 
   // Reset output elements to zero
   std::vector<double> out(xvalues.size(), 0);
-  auto xvals = xvalues.rawData();
+  const auto &xvals = xvalues.rawData();
 
   // Peaks
   if (calpeaks) {
@@ -799,12 +799,9 @@ void LeBailFunction::groupPeaks(
 
         if (thispeak_rightbound < rightpeak_leftbound) {
           // this peak and its right peak are well separated.
-          // finish this group by a copy
-          vector<pair<double, IPowderDiffPeakFunction_sptr>> peakgroupcopy =
-              peakgroup;
-          peakgroupvec.push_back(peakgroupcopy);
-          //  clear for the next group
-          peakgroup.clear();
+          // finish this group by swapping values
+          peakgroupvec.push_back(std::move(peakgroup));
+          peakgroup = {};
         } else {
           // this peak and its right peak are close enough to be in same group.
           // do nothing
@@ -812,9 +809,7 @@ void LeBailFunction::groupPeaks(
         }
       } else {
         // Rightmost peak.  Finish the current peak
-        vector<pair<double, IPowderDiffPeakFunction_sptr>> peakgroupcopy =
-            peakgroup;
-        peakgroupvec.push_back(peakgroupcopy);
+        peakgroupvec.push_back(peakgroup);
       }
 
       ++ipk;
@@ -827,17 +822,14 @@ void LeBailFunction::groupPeaks(
                           << "peak over at maximum TOF = " << xmax << ".\n";
 
       if (!peakgroup.empty()) {
-        vector<pair<double, IPowderDiffPeakFunction_sptr>> peakgroupcopy =
-            peakgroup;
-        peakgroupvec.push_back(peakgroupcopy);
+        peakgroupvec.push_back(peakgroup);
       }
     } // FIRST out of boundary
   }   // ENDWHILE
 
   while (ipk < m_numPeaks) {
     // Group peaks out of uppper boundary to a separate vector of peaks
-    IPowderDiffPeakFunction_sptr thispeak = m_dspPeakVec[ipk].second;
-    outboundpeakvec.push_back(thispeak);
+    outboundpeakvec.push_back(m_dspPeakVec[ipk].second);
     ipk += 1;
   }
 
@@ -931,9 +923,9 @@ void LeBailFunction::setFitProfileParameter(string paramname, double minvalue,
   std::stringstream parss;
   parss << "f0." << paramname;
   string parnamef0 = parss.str();
-  Constraints::BoundaryConstraint *bc = new Constraints::BoundaryConstraint(
+  auto bc = Kernel::make_unique<Constraints::BoundaryConstraint>(
       m_compsiteFunction.get(), parnamef0, minvalue, maxvalue);
-  m_compsiteFunction->addConstraint(bc);
+  m_compsiteFunction->addConstraint(std::move(bc));
 }
 
 //----------------------------------------------------------------------------------------------
diff --git a/Framework/CurveFitting/src/Algorithms/PawleyFit.cpp b/Framework/CurveFitting/src/Algorithms/PawleyFit.cpp
index 54fb86e6d95048356d177a60064fd1917535834a..1463a19cbf1a3dfd1f0798ce56261e1d116a771a 100644
--- a/Framework/CurveFitting/src/Algorithms/PawleyFit.cpp
+++ b/Framework/CurveFitting/src/Algorithms/PawleyFit.cpp
@@ -14,6 +14,10 @@
 #include "MantidKernel/UnitFactory.h"
 #include "MantidKernel/UnitConversion.h"
 
+#include <boost/algorithm/string/classification.hpp>
+#include <boost/algorithm/string/split.hpp>
+#include <boost/algorithm/string/trim.hpp>
+
 #include <algorithm>
 
 namespace Mantid {
diff --git a/Framework/CurveFitting/src/Algorithms/PlotPeakByLogValue.cpp b/Framework/CurveFitting/src/Algorithms/PlotPeakByLogValue.cpp
index 415298121a8ce27786df0925435175a46418e6e2..88173dae6e3d976af24b062b3b3b12a7d54abd93 100644
--- a/Framework/CurveFitting/src/Algorithms/PlotPeakByLogValue.cpp
+++ b/Framework/CurveFitting/src/Algorithms/PlotPeakByLogValue.cpp
@@ -114,6 +114,14 @@ void PlotPeakByLogValue::init() {
   declareProperty("MaxIterations", 500,
                   "Stop after this number of iterations if a good fit is not "
                   "found");
+  declareProperty("PeakRadius", 0,
+                  "A value of the peak radius the peak functions should use. A "
+                  "peak radius defines an interval on the x axis around the "
+                  "centre of the peak where its values are calculated. Values "
+                  "outside the interval are not calculated and assumed zeros."
+                  "Numerically the radius is a whole number of peak widths "
+                  "(FWHM) that fit into the interval on each side from the "
+                  "centre. The default value of 0 means the whole x axis.");
 
   declareProperty("CreateOutput", false, "Set to true to create output "
                                          "workspaces with the results of the "
@@ -264,7 +272,7 @@ void PlotPeakByLogValue::exec() {
           setWorkspaceIndexAttribute(ifun, j);
         }
 
-        g_log.debug() << "Fitting " << data.ws->name() << " index " << j
+        g_log.debug() << "Fitting " << data.ws->getName() << " index " << j
                       << " with \n";
         g_log.debug() << ifun->asString() << '\n';
 
@@ -292,6 +300,7 @@ void PlotPeakByLogValue::exec() {
         fit->setPropertyValue("CostFunction", getPropertyValue("CostFunction"));
         fit->setPropertyValue("MaxIterations",
                               getPropertyValue("MaxIterations"));
+        fit->setPropertyValue("PeakRadius", getPropertyValue("PeakRadius"));
         fit->setProperty("CalcErrors", true);
         fit->setProperty("CreateOutput", createFitOutput);
         if (!histogramFit) {
@@ -303,7 +312,7 @@ void PlotPeakByLogValue::exec() {
 
         if (!fit->isExecuted()) {
           throw std::runtime_error("Fit child algorithm failed: " +
-                                   data.ws->name());
+                                   data.ws->getName());
         }
 
         ifun = fit->getProperty("Function");
@@ -545,7 +554,7 @@ PlotPeakByLogValue::makeNames() const {
       } else if (index.size() > 1 && index[0] == 'i') { // workspace index
         wi = boost::lexical_cast<int>(index.substr(1));
         spec = -1; // undefined yet
-      } else if (index.size() > 0 && index[0] == 'v') {
+      } else if (!index.empty() && index[0] == 'v') {
         if (index.size() > 1) { // there is some text after 'v'
           tokenizer range(index.substr(1), ":",
                           tokenizer::TOK_IGNORE_EMPTY | tokenizer::TOK_TRIM);
@@ -636,7 +645,7 @@ std::string PlotPeakByLogValue::getMinimizerString(const std::string &wsName,
     Mantid::API::WorkspaceProperty<> *wsProp =
         dynamic_cast<Mantid::API::WorkspaceProperty<> *>(minimizerProp);
     if (wsProp) {
-      std::string wsPropValue = minimizerProp->value();
+      const std::string &wsPropValue = minimizerProp->value();
       if (wsPropValue != "") {
         std::string wsPropName = minimizerProp->name();
         m_minimizerWorkspaces[wsPropName].push_back(wsPropValue);
diff --git a/Framework/CurveFitting/src/Algorithms/RefinePowderInstrumentParameters.cpp b/Framework/CurveFitting/src/Algorithms/RefinePowderInstrumentParameters.cpp
index 2868a4a164ea7f207b542ebef22649b8466687f2..982d06e0dc3bc84f2d77d9ac81d4e44c3324ff64 100644
--- a/Framework/CurveFitting/src/Algorithms/RefinePowderInstrumentParameters.cpp
+++ b/Framework/CurveFitting/src/Algorithms/RefinePowderInstrumentParameters.cpp
@@ -27,6 +27,8 @@
 #include <boost/algorithm/string/split.hpp>
 
 #include <fstream>
+#include <iomanip>
+#include <iostream>
 
 #include <gsl/gsl_sf_erf.h>
 
@@ -52,7 +54,9 @@ DECLARE_ALGORITHM(RefinePowderInstrumentParameters)
  */
 RefinePowderInstrumentParameters::RefinePowderInstrumentParameters()
     : m_BestGSLChi2(0.0), m_MinSigma(0.0), m_MinNumFittedPeaks(0),
-      m_MaxNumberStoredParameters(0) {}
+      m_MaxNumberStoredParameters(0) {
+  this->useAlgorithm("RefinePowderInstrumentParameters", 3);
+}
 
 //----------------------------------------------------------------------------------------------
 /** Parameter declaration
@@ -220,8 +224,7 @@ void RefinePowderInstrumentParameters::fitInstrumentParameters() {
   cout << "=========== Method [FitInstrumentParameters] ===============\n";
 
   // 1. Initialize the fitting function
-  ThermalNeutronDtoTOFFunction rawfunc;
-  m_Function = boost::make_shared<ThermalNeutronDtoTOFFunction>(rawfunc);
+  m_Function = boost::make_shared<ThermalNeutronDtoTOFFunction>();
   m_Function->initialize();
 
   API::FunctionDomain1DVector domain(m_dataWS->x(1).rawData());
@@ -597,9 +600,9 @@ void RefinePowderInstrumentParameters::doParameterSpaceRandomWalk(
     // Constraint
     double lowerb = lowerbounds[i];
     double upperb = upperbounds[i];
-    BoundaryConstraint *newconstraint =
-        new BoundaryConstraint(func4fit.get(), parname, lowerb, upperb);
-    func4fit->addConstraint(newconstraint);
+    auto newconstraint = Kernel::make_unique<BoundaryConstraint>(
+        func4fit.get(), parname, lowerb, upperb);
+    func4fit->addConstraint(std::move(newconstraint));
   }
   cout << "Function for fitting in MC: " << func4fit->asString() << '\n';
 
@@ -781,11 +784,8 @@ void RefinePowderInstrumentParameters::getD2TOFFuncParamNames(
   parnames.clear();
 
   // 2. Get the parameter names from function
-  ThermalNeutronDtoTOFFunction d2toffunc;
-  d2toffunc.initialize();
-  std::vector<std::string> funparamnames = d2toffunc.getParameterNames();
-
-  m_Function = boost::make_shared<ThermalNeutronDtoTOFFunction>(d2toffunc);
+  m_Function = boost::make_shared<ThermalNeutronDtoTOFFunction>();
+  std::vector<std::string> funparamnames = m_Function->getParameterNames();
 
   // 3. Copy
   parnames = funparamnames;
@@ -855,8 +855,9 @@ void RefinePowderInstrumentParameters::genPeaksFromTable(
 
   for (size_t ir = 0; ir < numrows; ++ir) {
     // a) Generate peak
-    BackToBackExponential newpeak;
-    newpeak.initialize();
+    BackToBackExponential_sptr newpeakptr =
+        boost::make_shared<BackToBackExponential>();
+    newpeakptr->initialize();
 
     // b) Parse parameters
     int h, k, l;
@@ -899,15 +900,11 @@ void RefinePowderInstrumentParameters::genPeaksFromTable(
       sigma = sqrt(sigma2);
 
     // c) Set peak parameters and etc.
-    newpeak.setParameter("A", alpha);
-    newpeak.setParameter("B", beta);
-    newpeak.setParameter("S", sigma);
-    newpeak.setParameter("X0", tof_h);
-    newpeak.setParameter("I", height);
-
-    // d) Make to share pointer and set to instance data structure (map)
-    BackToBackExponential_sptr newpeakptr =
-        boost::make_shared<BackToBackExponential>(newpeak);
+    newpeakptr->setParameter("A", alpha);
+    newpeakptr->setParameter("B", beta);
+    newpeakptr->setParameter("S", sigma);
+    newpeakptr->setParameter("X0", tof_h);
+    newpeakptr->setParameter("I", height);
 
     std::vector<int> hkl;
     hkl.push_back(h);
@@ -921,7 +918,7 @@ void RefinePowderInstrumentParameters::genPeaksFromTable(
     g_log.information() << "[Generatem_Peaks] Peak " << ir << " HKL = ["
                         << hkl[0] << ", " << hkl[1] << ", " << hkl[2]
                         << "], Input Center = " << setw(10) << setprecision(6)
-                        << newpeak.centre() << '\n';
+                        << newpeakptr->centre() << '\n';
 
   } // ENDFOR Each potential peak
 }
@@ -961,7 +958,7 @@ void RefinePowderInstrumentParameters::importParametersFromTable(
       trow >> parname >> value;
       parameters.emplace(parname, value);
     } catch (runtime_error &) {
-      g_log.error() << "Import table workspace " << parameterWS->name()
+      g_log.error() << "Import table workspace " << parameterWS->getName()
                     << " error in line " << ir << ".  "
                     << " Requires [string, double] in the first 2 columns.\n";
       throw;
@@ -1023,7 +1020,7 @@ void RefinePowderInstrumentParameters::importMonteCarloParametersFromTable(
       } catch (runtime_error &) {
         g_log.error() << "Import MC parameter " << colnames[ic]
                       << " error in row " << ir << " of workspace "
-                      << tablews->name() << '\n';
+                      << tablews->getName() << '\n';
         row >> tmpstr;
         g_log.error() << "Should be " << tmpstr << '\n';
       }
diff --git a/Framework/CurveFitting/src/Algorithms/RefinePowderInstrumentParameters3.cpp b/Framework/CurveFitting/src/Algorithms/RefinePowderInstrumentParameters3.cpp
index 9f1f11599a2a09003098dd110a7831f0eddc3012..6b492417ed453ddd39fab0b521cf37e8ae553102 100644
--- a/Framework/CurveFitting/src/Algorithms/RefinePowderInstrumentParameters3.cpp
+++ b/Framework/CurveFitting/src/Algorithms/RefinePowderInstrumentParameters3.cpp
@@ -6,6 +6,8 @@
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidKernel/ListValidator.h"
 
+#include <iomanip>
+
 using namespace Mantid::API;
 using namespace Mantid::CurveFitting;
 using namespace Mantid::CurveFitting::Functions;
@@ -86,13 +88,12 @@ void RefinePowderInstrumentParameters3::init() {
       "Algorithm to calculate the standard error of peak positions.");
 
   // Damping factor
-  declareProperty(
-      "Damping", 1.0,
-      "Damping factor for (1) minimizer 'damping'. (2) Monte Calro. ");
+  declareProperty("Damping", 1.0, "Damping factor for (1) minimizer 'Damped "
+                                  "Gauss-Newton'. (2) Monte Carlo. ");
 
   // Anealing temperature
   declareProperty("AnnealingTemperature", 1.0,
-                  "Starting aneealing temperature.");
+                  "Starting annealing temperature.");
 
   // Monte Carlo iterations
   declareProperty("MonteCarloIterations", 100,
@@ -113,8 +114,7 @@ void RefinePowderInstrumentParameters3::exec() {
   parseTableWorkspaces();
 
   // 3. Set up main function for peak positions
-  ThermalNeutronDtoTOFFunction rawfunc;
-  m_positionFunc = boost::make_shared<ThermalNeutronDtoTOFFunction>(rawfunc);
+  m_positionFunc = boost::make_shared<ThermalNeutronDtoTOFFunction>();
   m_positionFunc->initialize();
 
   // 3. Fit
@@ -275,7 +275,7 @@ void RefinePowderInstrumentParameters3::parseTableWorkspace(
 
     // If empty string, fit is default to be false
     bool fit = false;
-    if (fitq.size() > 0) {
+    if (!fitq.empty()) {
       if (fitq[0] == 'F' || fitq[0] == 'f')
         fit = true;
     }
@@ -374,7 +374,6 @@ double RefinePowderInstrumentParameters3::doSimulatedAnnealing(
 
   // 3. Monte Carlo starts
   double chisqx = chisq0;
-  int numtotalacceptance = 0;
   int numrecentacceptance = 0;
   int numrecentsteps = 0;
 
@@ -419,7 +418,6 @@ double RefinePowderInstrumentParameters3::doSimulatedAnnealing(
       }
 
       // e) MC strategy control
-      ++numtotalacceptance;
       ++numrecentacceptance;
       ++numrecentsteps;
     }
@@ -1226,10 +1224,9 @@ void RefinePowderInstrumentParameters3::setFunctionParameterFitSetups(
         double upperbound = param.maxvalue;
         if (lowerbound >= -DBL_MAX * 0.1 || upperbound <= DBL_MAX * 0.1) {
           // If there is a boundary
-          Constraints::BoundaryConstraint *bc =
-              new Constraints::BoundaryConstraint(
-                  function.get(), parname, lowerbound, upperbound, false);
-          function->addConstraint(bc);
+          auto bc = Kernel::make_unique<Constraints::BoundaryConstraint>(
+              function.get(), parname, lowerbound, upperbound, false);
+          function->addConstraint(std::move(bc));
         }
       } else {
         // If fix.
diff --git a/Framework/CurveFitting/src/Algorithms/SplineInterpolation.cpp b/Framework/CurveFitting/src/Algorithms/SplineInterpolation.cpp
index e2acc755258a63557b785a8eebf4654cb1501adf..2640d3716519783637645978f5f26786049670ba 100644
--- a/Framework/CurveFitting/src/Algorithms/SplineInterpolation.cpp
+++ b/Framework/CurveFitting/src/Algorithms/SplineInterpolation.cpp
@@ -3,6 +3,7 @@
 #include "MantidAPI/NumericAxis.h"
 #include "MantidAPI/Progress.h"
 #include "MantidAPI/WorkspaceFactory.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidKernel/BoundedValidator.h"
 #include "MantidCurveFitting/Algorithms/SplineInterpolation.h"
 
diff --git a/Framework/CurveFitting/src/Algorithms/SplineSmoothing.cpp b/Framework/CurveFitting/src/Algorithms/SplineSmoothing.cpp
index 92ccf5bcc43ac0779448261a6758d4fc27b6ea3f..f93d19d3f8609b79854c88d795c3cb2fcab4bd29 100644
--- a/Framework/CurveFitting/src/Algorithms/SplineSmoothing.cpp
+++ b/Framework/CurveFitting/src/Algorithms/SplineSmoothing.cpp
@@ -5,6 +5,7 @@
 #include "MantidAPI/Progress.h"
 #include "MantidAPI/TextAxis.h"
 #include "MantidAPI/WorkspaceFactory.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidKernel/BoundedValidator.h"
 
 #include <algorithm>
diff --git a/Framework/CurveFitting/src/Algorithms/VesuvioCalculateGammaBackground.cpp b/Framework/CurveFitting/src/Algorithms/VesuvioCalculateGammaBackground.cpp
index 3749bf274f9c92e7958dcb9b987328197305a5dc..22c9e5deba499e47b056e2663cbde2cd6fbe8aa9 100644
--- a/Framework/CurveFitting/src/Algorithms/VesuvioCalculateGammaBackground.cpp
+++ b/Framework/CurveFitting/src/Algorithms/VesuvioCalculateGammaBackground.cpp
@@ -17,6 +17,8 @@
 
 #include "MantidGeometry/Instrument.h"
 #include "MantidGeometry/Instrument/ReferenceFrame.h"
+#include "MantidGeometry/Objects/BoundingBox.h"
+#include "MantidGeometry/Objects/Object.h"
 
 namespace Mantid {
 namespace CurveFitting {
diff --git a/Framework/CurveFitting/src/Algorithms/VesuvioCalculateMS.cpp b/Framework/CurveFitting/src/Algorithms/VesuvioCalculateMS.cpp
index 752ddd013fe56e91da7dda48f57bbef7f2d6f67b..a231eacdd29b47dae7e5f3b499096a79e2a66cdd 100644
--- a/Framework/CurveFitting/src/Algorithms/VesuvioCalculateMS.cpp
+++ b/Framework/CurveFitting/src/Algorithms/VesuvioCalculateMS.cpp
@@ -5,6 +5,7 @@
 #include "MantidCurveFitting/Functions/VesuvioResolution.h"
 
 #include "MantidAPI/Axis.h"
+#include "MantidAPI/DetectorInfo.h"
 #include "MantidAPI/Sample.h"
 #include "MantidAPI/SampleShapeValidator.h"
 #include "MantidAPI/SpectrumInfo.h"
@@ -254,31 +255,28 @@ void VesuvioCalculateMS::cacheInputs() {
   m_sampleProps->mu = numberDensity * m_sampleProps->totalxsec * 1e-28;
 
   // -- Detector geometry -- choose first detector that is not a monitor
-  Geometry::IDetector_const_sptr detPixel;
+  const auto &spectrumInfo = m_inputWS->spectrumInfo();
+  int64_t index = -1;
   for (size_t i = 0; i < m_inputWS->getNumberHistograms(); ++i) {
-    try {
-      detPixel = m_inputWS->getDetector(i);
-    } catch (Exception::NotFoundError &) {
+    if (!spectrumInfo.hasDetectors(i))
       continue;
-    }
-    if (!detPixel->isMonitor())
+    if (!spectrumInfo.isMonitor(i)) {
+      index = i;
       break;
+    }
   }
   // Bounding box in detector frame
-  if (!detPixel) {
+  if (index < 0) {
     throw std::runtime_error("Failed to get detector");
   }
-  Geometry::Object_const_sptr pixelShape;
-  Geometry::DetectorGroup_const_sptr detPixelGroup =
-      boost::dynamic_pointer_cast<const Geometry::DetectorGroup>(detPixel);
-  if (detPixelGroup) {
-    // If is a detector group then take shape of first pixel
-    // All detectors in same bansk should be same shape anyway
-    if (detPixelGroup->nDets() > 0)
-      pixelShape = detPixelGroup->getDetectors()[0]->shape();
-  } else {
-    pixelShape = detPixel->shape();
-  }
+  // If is a detector group then take shape of first pixel
+  // All detectors in same bansk should be same shape anyway
+  // If the detector is a DetectorGroup, getID gives ID of first detector.
+  const auto &detectorInfo = m_inputWS->detectorInfo();
+  const size_t detIndex =
+      detectorInfo.indexOf(spectrumInfo.detector(index).getID());
+  const auto pixelShape = detectorInfo.detector(detIndex).shape();
+
   if (!pixelShape || !pixelShape->hasValidShape()) {
     throw std::invalid_argument("Detector pixel has no defined shape!");
   }
diff --git a/Framework/CurveFitting/src/CostFunctions/CostFuncFitting.cpp b/Framework/CurveFitting/src/CostFunctions/CostFuncFitting.cpp
index ea709388c4f29f93f1a72940fc5663057a7d08b3..aaa5aef879b33277ea5059d91e9566aba6553c95 100644
--- a/Framework/CurveFitting/src/CostFunctions/CostFuncFitting.cpp
+++ b/Framework/CurveFitting/src/CostFunctions/CostFuncFitting.cpp
@@ -16,7 +16,8 @@ namespace CostFunctions {
  * Constructor.
  */
 CostFuncFitting::CostFuncFitting()
-    : m_dirtyVal(true), m_dirtyDeriv(true), m_dirtyHessian(true) {}
+    : m_numberFunParams(0), m_dirtyVal(true), m_dirtyDeriv(true),
+      m_dirtyHessian(true) {}
 
 /**
  * Set all dirty flags.
@@ -64,23 +65,30 @@ void CostFuncFitting::setFittingFunction(API::IFunction_sptr function,
   m_function = function;
   m_domain = domain;
   m_values = values;
-  m_indexMap.clear();
-  for (size_t i = 0; i < m_function->nParams(); ++i) {
-    if (m_function->isActive(i)) {
-      m_indexMap.push_back(i);
-    }
-    API::IConstraint *c = m_function->getConstraint(i);
-    if (c) {
-      c->setParamToSatisfyConstraint();
-    }
-  }
+  reset();
 }
 
 /**
  * Is the function set and valid?
  */
 bool CostFuncFitting::isValid() const {
-  return m_function != API::IFunction_sptr();
+  if (m_function == API::IFunction_sptr()) {
+    return false;
+  }
+  if (m_function->nParams() != m_numberFunParams) {
+    reset();
+  }
+  auto nActive = m_indexMap.size();
+  for (size_t i = 0, j = 0; i < m_numberFunParams; ++i) {
+    if (m_function->isActive(i)) {
+      if (j >= nActive || m_indexMap[j] != i) {
+        reset();
+        break;
+      }
+      ++j;
+    }
+  }
+  return true;
 }
 
 /**
@@ -116,20 +124,19 @@ void CostFuncFitting::calActiveCovarianceMatrix(GSLMatrix &covar,
   * @param epsrel :: Is used to remove linear-dependent columns
   */
 void CostFuncFitting::calCovarianceMatrix(GSLMatrix &covar, double epsrel) {
+  checkValidity();
   GSLMatrix c;
   calActiveCovarianceMatrix(c, epsrel);
 
   size_t np = m_function->nParams();
 
   bool isTransformationIdentity = true;
-  size_t ii = 0;
   for (size_t i = 0; i < np; ++i) {
     if (!m_function->isActive(i))
       continue;
     isTransformationIdentity =
         isTransformationIdentity &&
         (m_function->activeParameter(i) == m_function->getParameter(i));
-    ++ii;
   }
 
   if (isTransformationIdentity) {
@@ -150,6 +157,7 @@ void CostFuncFitting::calCovarianceMatrix(GSLMatrix &covar, double epsrel) {
  * @param chi2 :: The final chi-squared of the fit.
  */
 void CostFuncFitting::calFittingErrors(const GSLMatrix &covar, double chi2) {
+  checkValidity();
   size_t np = m_function->nParams();
   auto covarMatrix = boost::shared_ptr<Kernel::Matrix<double>>(
       new Kernel::Matrix<double>(np, np));
@@ -199,6 +207,58 @@ void CostFuncFitting::calTransformationMatrixNumerically(GSLMatrix &tm) {
   }
 }
 
+/// Apply ties in the fitting function
+void CostFuncFitting::applyTies() {
+  if (m_function) {
+    m_function->applyTies();
+  }
+}
+
+/// Reset the fitting function (neccessary if parameters get fixed/unfixed)
+void CostFuncFitting::reset() const {
+  m_numberFunParams = m_function->nParams();
+  m_indexMap.clear();
+  for (size_t i = 0; i < m_numberFunParams; ++i) {
+    if (m_function->isActive(i)) {
+      m_indexMap.push_back(i);
+    }
+    API::IConstraint *c = m_function->getConstraint(i);
+    if (c) {
+      c->setParamToSatisfyConstraint();
+    }
+  }
+  m_dirtyDeriv = true;
+  m_dirtyHessian = true;
+}
+
+/**
+ * Copy the parameter values from a GSLVector.
+ * @param params :: A vector to copy the parameters from
+ */
+void CostFuncFitting::setParameters(const GSLVector &params) {
+  if (nParams() != params.size()) {
+    throw std::runtime_error(
+        "Parameter vector has wrong size in CostFuncLeastSquares.");
+  }
+  for (size_t i = 0; i < nParams(); ++i) {
+    setParameter(i, params.get(i));
+  }
+  m_function->applyTies();
+}
+
+/**
+ * Copy the parameter values to a GSLVector.
+ * @param params :: A vector to copy the parameters to
+ */
+void CostFuncFitting::getParameters(GSLVector &params) const {
+  if (params.size() != nParams()) {
+    params.resize(nParams());
+  }
+  for (size_t i = 0; i < nParams(); ++i) {
+    params.set(i, getParameter(i));
+  }
+}
+
 } // namespace CostFunctions
 } // namespace CurveFitting
 } // namespace Mantid
diff --git a/Framework/CurveFitting/src/CostFunctions/CostFuncLeastSquares.cpp b/Framework/CurveFitting/src/CostFunctions/CostFuncLeastSquares.cpp
index 71c2cf6968889493a16c99231af1569208bc24ae..66f351761edd931cf703e6d87f42be7bec14dd6e 100644
--- a/Framework/CurveFitting/src/CostFunctions/CostFuncLeastSquares.cpp
+++ b/Framework/CurveFitting/src/CostFunctions/CostFuncLeastSquares.cpp
@@ -366,34 +366,6 @@ void CostFuncLeastSquares::drop() {
   setDirty();
 }
 
-/**
- * Copy the parameter values from a GSLVector.
- * @param params :: A vector to copy the parameters from
- */
-void CostFuncLeastSquares::setParameters(const GSLVector &params) {
-  if (nParams() != params.size()) {
-    throw std::runtime_error(
-        "Parameter vector has wrong size in CostFuncLeastSquares.");
-  }
-  for (size_t i = 0; i < nParams(); ++i) {
-    setParameter(i, params.get(i));
-  }
-  m_function->applyTies();
-}
-
-/**
- * Copy the parameter values to a GSLVector.
- * @param params :: A vector to copy the parameters to
- */
-void CostFuncLeastSquares::getParameters(GSLVector &params) const {
-  if (params.size() != nParams()) {
-    params.resize(nParams());
-  }
-  for (size_t i = 0; i < nParams(); ++i) {
-    params.set(i, getParameter(i));
-  }
-}
-
 /**
   * Calculates covariance matrix for fitting function's active parameters.
   * @param covar :: Output cavariance matrix.
diff --git a/Framework/CurveFitting/src/FitMW.cpp b/Framework/CurveFitting/src/FitMW.cpp
index e6476795227c74aad3531f76fbdc3f86fe5fd476..def14515b166fd3a5f78a669c9f40bb0c4777e9f 100644
--- a/Framework/CurveFitting/src/FitMW.cpp
+++ b/Framework/CurveFitting/src/FitMW.cpp
@@ -1,27 +1,29 @@
 // Includes
 //----------------------------------------------------------------------
 #include "MantidCurveFitting/FitMW.h"
-#include "MantidCurveFitting/SeqDomain.h"
 #include "MantidCurveFitting/Functions/Convolution.h"
 #include "MantidCurveFitting/ParameterEstimator.h"
+#include "MantidCurveFitting/SeqDomain.h"
 
 #include "MantidAPI/CompositeFunction.h"
-#include "MantidAPI/WorkspaceFactory.h"
-#include "MantidAPI/MatrixWorkspace.h"
-#include "MantidAPI/FunctionProperty.h"
 #include "MantidAPI/FunctionDomain1D.h"
+#include "MantidAPI/FunctionProperty.h"
 #include "MantidAPI/FunctionValues.h"
+#include "MantidAPI/IEventWorkspace.h"
 #include "MantidAPI/IFunctionMW.h"
+#include "MantidAPI/MatrixWorkspace.h"
+#include "MantidAPI/TextAxis.h"
+#include "MantidAPI/WorkspaceFactory.h"
 #include "MantidAPI/WorkspaceProperty.h"
-#include "MantidAPI/IEventWorkspace.h"
 
-#include "MantidAPI/TextAxis.h"
+#include "MantidKernel/ArrayOrderedPairsValidator.h"
+#include "MantidKernel/ArrayProperty.h"
 #include "MantidKernel/BoundedValidator.h"
 #include "MantidKernel/EmptyValues.h"
 #include "MantidKernel/Matrix.h"
 
-#include <cmath>
 #include <algorithm>
+#include <cmath>
 
 namespace Mantid {
 namespace CurveFitting {
@@ -33,6 +35,183 @@ using API::MatrixWorkspace;
 using API::Algorithm;
 using API::Jacobian;
 
+namespace {
+
+/// Helper calss that finds if a point should be excluded from fit.
+/// It keeps the boundaries of the relevant exclusion region for
+/// the last checked value. A relevant region is the one which either
+/// includes the value or the nearest one with the left boundary greater
+/// than the value.
+/// The class also keeps the index of the region (its left boundary) for
+/// efficient search.
+class ExcludeRangeFinder {
+  /// Index of current excluded range
+  size_t m_exclIndex;
+  /// Start of current excluded range
+  double m_startExcludedRange;
+  /// End of current excluded range
+  double m_endExcludeRange;
+  /// Reference to a list of exclusion ranges.
+  const std::vector<double> &m_exclude;
+  /// Size of m_exclude.
+  const size_t m_size;
+
+public:
+  /// Constructor.
+  /// @param exclude :: The value of the "Exclude" property.
+  /// @param startX :: The start of the overall fit interval.
+  /// @param endX :: The end of the overall fit interval.
+  ExcludeRangeFinder(const std::vector<double> &exclude, double startX,
+                     double endX)
+      : m_exclIndex(exclude.size()), m_startExcludedRange(),
+        m_endExcludeRange(), m_exclude(exclude), m_size(exclude.size()) {
+    // m_exclIndex is initialised with exclude.size() to be the default when
+    // there are no exclusion ranges defined.
+    if (!m_exclude.empty()) {
+      if (startX < m_exclude.back() && endX > m_exclude.front()) {
+        // In this case there are some ranges, the index starts with 0
+        // and first range is found.
+        m_exclIndex = 0;
+        findNextExcludedRange(startX);
+      }
+    }
+  }
+
+  /// Check if an x-value lies in an exclusion range.
+  /// @param value :: A value to check.
+  /// @returns true if the value lies in an exclusion range and should be
+  /// excluded from fit.
+  bool isExcluded(double value) {
+    if (m_exclIndex < m_size) {
+      if (value < m_startExcludedRange) {
+        // If a value is below the start of the current interval
+        // it is not in any other interval by the workings of
+        // findNextExcludedRange
+        return false;
+      } else if (value <= m_endExcludeRange) {
+        // value is inside
+        return true;
+      } else {
+        // Value is past the current range. Find the next one or set the index
+        // to m_exclude.size() to stop further searches.
+        findNextExcludedRange(value);
+        // The value can find itself inside another range.
+        return isExcluded(value);
+      }
+    }
+    return false;
+  }
+
+private:
+  /// Find the range from m_exclude that may contain points x >= p .
+  /// @param p :: An x value to use in the seach.
+  void findNextExcludedRange(double p) {
+    if (p > m_exclude.back()) {
+      // If the value is past the last point stop any searches or checks.
+      m_exclIndex = m_size;
+      return;
+    }
+    // Starting with the current index m_exclIndex find the first value in
+    // m_exclude that is greater than p. If this point is a start than the
+    // end will be the following point. If it's an end then the start is
+    // the previous point. Keep index m_exclIndex pointing to the start.
+    for (auto it = m_exclude.begin() + m_exclIndex; it != m_exclude.end();
+         ++it) {
+      if (*it >= p) {
+        m_exclIndex = static_cast<size_t>(std::distance(m_exclude.begin(), it));
+        if (m_exclIndex % 2 == 0) {
+          // A number at an even position in m_exclude starts an exclude
+          // range
+          m_startExcludedRange = *it;
+          m_endExcludeRange = *(it + 1);
+        } else {
+          // A number at an odd position in m_exclude ends an exclude range
+          m_startExcludedRange = *(it - 1);
+          m_endExcludeRange = *it;
+          --m_exclIndex;
+        }
+        break;
+      }
+    }
+    // No need for additional checks as p < m_exclude.back()
+    // and m_exclude[m_exclIndex] < p due to conditions at the calls
+    // so the break statement will always be reached.
+  }
+};
+
+/// Helper struct for helping with joining exclusion ranges.
+/// Endge points of the ranges can be wrapped in this struct
+/// and sorted together without loosing their function.
+struct RangePoint {
+  enum Kind : char { Openning, Closing };
+  /// The kind of the point: either openning or closing the range.
+  Kind kind;
+  /// The value of the point.
+  double value;
+  /// Comparison of two points.
+  /// @param point :: Another point to compare with.
+  bool operator<(const RangePoint &point) const {
+    if (this->value == point.value) {
+      // If an Openning and Closing points have the same value
+      // the Openning one should go first (be "smaller").
+      // This way the procedure of joinOverlappingRanges will join
+      // the ranges that meet at these points.
+      return this->kind == Openning;
+    }
+    return this->value < point.value;
+  }
+};
+
+/// Find any overlapping ranges in a vector and join them.
+/// @param[in,out] exclude :: A vector with the ranges some of which may
+/// overlap. On output all overlapping ranges are joined and the vector contains
+/// increasing series of doubles (an even number of them).
+void joinOverlappingRanges(std::vector<double> &exclude) {
+  if (exclude.empty()) {
+    return;
+  }
+  // The situation here is similar to matching brackets in an expression.
+  // If we sort all the points in the input vector remembering their kind
+  // then a separate exclusion region starts with the first openning bracket
+  // and ends with the matching closing bracket. All brackets (points) inside
+  // them can be dropped.
+
+  // Wrap the points into helper struct RangePoint
+  std::vector<RangePoint> points;
+  points.reserve(exclude.size());
+  for (auto point = exclude.begin(); point != exclude.end(); point += 2) {
+    points.push_back(RangePoint{RangePoint::Openning, *point});
+    points.push_back(RangePoint{RangePoint::Closing, *(point + 1)});
+  }
+  // Sort the points according to the operator defined in RangePoint.
+  std::sort(points.begin(), points.end());
+
+  // Clear the argument vector.
+  exclude.clear();
+  // Start the level counter which shows the number of unmatched openning
+  // brackets.
+  size_t level(0);
+  for (auto &point : points) {
+    if (point.kind == RangePoint::Openning) {
+      if (level == 0) {
+        // First openning bracket starts a new exclusion range.
+        exclude.push_back(point.value);
+      }
+      // Each openning bracket increases the level
+      ++level;
+    } else {
+      if (level == 1) {
+        // The bracket that makes level 0 is an end of a range.
+        exclude.push_back(point.value);
+      }
+      // Each closing bracket decreases the level
+      --level;
+    }
+  }
+}
+
+} // namespace
+
 /**
  * Constructor.
  * @param fit :: Property manager with properties defining the domain to be
@@ -57,7 +236,9 @@ FitMW::FitMW(FitMW::DomainType domainType)
       m_normalise(false) {}
 
 /**
- * Set all parameters
+ * Set all parameters.
+ * @throws std::runtime_error if the Exclude property has an odd number of
+ * entries.
  */
 void FitMW::setParameters() const {
   IMWDomainCreator::setParameters();
@@ -69,6 +250,13 @@ void FitMW::setParameters() const {
       m_maxSize = static_cast<size_t>(maxSizeInt);
     }
     m_normalise = m_manager->getProperty(m_normalisePropertyName);
+    m_exclude = m_manager->getProperty(m_excludePropertyName);
+    if (m_exclude.size() % 2 != 0) {
+      throw std::runtime_error("Exclude property has an odd number of entries. "
+                               "It has to be even as each pair specifies a "
+                               "start and an end of an interval to exclude.");
+    }
+    joinOverlappingRanges(m_exclude);
   }
 }
 
@@ -82,6 +270,7 @@ void FitMW::declareDatasetProperties(const std::string &suffix, bool addProp) {
   IMWDomainCreator::declareDatasetProperties(suffix, addProp);
   m_maxSizePropertyName = "MaxSize" + suffix;
   m_normalisePropertyName = "Normalise" + suffix;
+  m_excludePropertyName = "Exclude" + suffix;
 
   if (addProp) {
     if (m_domainType != Simple &&
@@ -98,6 +287,14 @@ void FitMW::declareDatasetProperties(const std::string &suffix, bool addProp) {
           "An option to normalise the histogram data (divide be the bin "
           "width).");
     }
+    if (!m_manager->existsProperty(m_excludePropertyName)) {
+      auto mustBeOrderedPairs =
+          boost::make_shared<ArrayOrderedPairsValidator<double>>();
+      declareProperty(
+          new ArrayProperty<double>(m_excludePropertyName, mustBeOrderedPairs),
+          "A list of pairs of doubles that specify ranges that "
+          "must be excluded from fit.");
+    }
   }
 }
 
@@ -167,7 +364,10 @@ void FitMW::createDomain(boost::shared_ptr<API::FunctionDomain> &domain,
   if (endIndex > Y.size()) {
     throw std::runtime_error("FitMW: Inconsistent MatrixWorkspace");
   }
-  // bool foundZeroOrNegativeError = false;
+
+  // Helps find points excluded form fit.
+  ExcludeRangeFinder excludeFinder(m_exclude, X.front(), X.back());
+
   for (size_t i = m_startIndex; i < endIndex; ++i) {
     size_t j = i - m_startIndex + i0;
     double y = Y[i];
@@ -183,13 +383,15 @@ void FitMW::createDomain(boost::shared_ptr<API::FunctionDomain> &domain,
       error /= binWidth;
     }
 
-    if (!std::isfinite(y)) // nan or inf data
-    {
+    if (excludeFinder.isExcluded(X[i])) {
+      weight = 0.0;
+    } else if (!std::isfinite(y)) {
+      // nan or inf data
       if (!m_ignoreInvalidData)
         throw std::runtime_error("Infinte number or NaN found in input data.");
-      y = 0.0;                        // leaving inf or nan would break the fit
-    } else if (!std::isfinite(error)) // nan or inf error
-    {
+      y = 0.0; // leaving inf or nan would break the fit
+    } else if (!std::isfinite(error)) {
+      // nan or inf error
       if (!m_ignoreInvalidData)
         throw std::runtime_error("Infinte number or NaN found in input data.");
     } else if (error <= 0) {
@@ -197,6 +399,12 @@ void FitMW::createDomain(boost::shared_ptr<API::FunctionDomain> &domain,
         weight = 1.0;
     } else {
       weight = 1.0 / error;
+      if (!std::isfinite(weight)) {
+        if (!m_ignoreInvalidData)
+          throw std::runtime_error(
+              "Error of a data point is probably too small.");
+        weight = 0.0;
+      }
     }
 
     values->setFitData(j, y);
diff --git a/Framework/CurveFitting/src/FuncMinimizers/DampingMinimizer.cpp b/Framework/CurveFitting/src/FuncMinimizers/DampedGaussNewtonMinimizer.cpp
similarity index 81%
rename from Framework/CurveFitting/src/FuncMinimizers/DampingMinimizer.cpp
rename to Framework/CurveFitting/src/FuncMinimizers/DampedGaussNewtonMinimizer.cpp
index 6120555a14a19f050fd5a2dd0cfecfacf85c5d1b..36435eeac77b0d2ffe90aeeaefa37e9dac3e1550 100644
--- a/Framework/CurveFitting/src/FuncMinimizers/DampingMinimizer.cpp
+++ b/Framework/CurveFitting/src/FuncMinimizers/DampedGaussNewtonMinimizer.cpp
@@ -1,7 +1,7 @@
 //----------------------------------------------------------------------
 // Includes
 //----------------------------------------------------------------------
-#include "MantidCurveFitting/FuncMinimizers/DampingMinimizer.h"
+#include "MantidCurveFitting/FuncMinimizers/DampedGaussNewtonMinimizer.h"
 #include "MantidCurveFitting/CostFunctions/CostFuncLeastSquares.h"
 
 #include "MantidAPI/CostFunctionFactory.h"
@@ -21,30 +21,32 @@ namespace FuncMinimisers {
 
 namespace {
 /// static logger
-Kernel::Logger g_log("DampingMinimizer");
+Kernel::Logger g_log("DampedGaussNewtonMinimizer");
 }
 
-DECLARE_FUNCMINIMIZER(DampingMinimizer, Damping)
+DECLARE_FUNCMINIMIZER(DampedGaussNewtonMinimizer, Damped GaussNewton)
 
 /// Constructor
-DampingMinimizer::DampingMinimizer(double relTol)
+DampedGaussNewtonMinimizer::DampedGaussNewtonMinimizer(double relTol)
     : IFuncMinimizer(), m_relTol(relTol) {
   declareProperty("Damping", 0.0, "The damping parameter.");
 }
 
 /// Initialize minimizer, i.e. pass a function to minimize.
-void DampingMinimizer::initialize(API::ICostFunction_sptr function, size_t) {
+void DampedGaussNewtonMinimizer::initialize(API::ICostFunction_sptr function,
+                                            size_t) {
   m_leastSquares =
       boost::dynamic_pointer_cast<CostFunctions::CostFuncLeastSquares>(
           function);
   if (!m_leastSquares) {
-    throw std::invalid_argument("Damping minimizer works only with least "
-                                "squares. Different function was given.");
+    throw std::invalid_argument(
+        "Damped Gauss-Newton minimizer works only with least "
+        "squares. Different function was given.");
   }
 }
 
 /// Do one iteration.
-bool DampingMinimizer::iterate(size_t) {
+bool DampedGaussNewtonMinimizer::iterate(size_t) {
   const bool debug = false;
 
   const double damping = getProperty("Damping");
@@ -113,7 +115,7 @@ bool DampingMinimizer::iterate(size_t) {
 }
 
 /// Return current value of the cost function
-double DampingMinimizer::costFunctionVal() {
+double DampedGaussNewtonMinimizer::costFunctionVal() {
   if (!m_leastSquares) {
     throw std::runtime_error("Cost function isn't set up.");
   }
diff --git a/Framework/CurveFitting/src/Functions/BivariateNormal.cpp b/Framework/CurveFitting/src/Functions/BivariateNormal.cpp
index b6b7c423fbec28daa544a8b2ad2b07b97cbc95df..9a42d4556fc1bbae17f6635c9f923516f629aee4 100644
--- a/Framework/CurveFitting/src/Functions/BivariateNormal.cpp
+++ b/Framework/CurveFitting/src/Functions/BivariateNormal.cpp
@@ -7,6 +7,7 @@
 
 #include "MantidHistogramData/HistogramY.h"
 
+#include "MantidKernel/make_unique.h"
 #include "MantidKernel/PhysicalConstants.h"
 #include "MantidKernel/System.h"
 
@@ -475,8 +476,8 @@ double BivariateNormal::initCommon() {
 
     if (getConstraint(0) == nullptr) {
 
-      addConstraint((new BoundaryConstraint(this, "Background", 0,
-                                            Attrib[S_int] / Attrib[S_1])));
+      addConstraint((Kernel::make_unique<BoundaryConstraint>(
+          this, "Background", 0, Attrib[S_int] / Attrib[S_1])));
     }
 
     double maxIntensity = Attrib[S_int] + 3 * sqrt(Attrib[S_int]);
@@ -485,20 +486,23 @@ double BivariateNormal::initCommon() {
       maxIntensity = 100;
 
     if (getConstraint(1) == nullptr) {
-      addConstraint(new BoundaryConstraint(this, "Intensity", 0, maxIntensity));
+      addConstraint(Kernel::make_unique<BoundaryConstraint>(this, "Intensity",
+                                                            0, maxIntensity));
     }
 
     double minMeany = MinY * .9 + .1 * MaxY;
     double maxMeany = MinY * .1 + .9 * MaxY;
 
     if (getConstraint(3) == nullptr) {
-      addConstraint(new BoundaryConstraint(this, "Mrow", minMeany, maxMeany));
+      addConstraint(Kernel::make_unique<BoundaryConstraint>(
+          this, "Mrow", minMeany, maxMeany));
     }
 
     double minMeanx = MinX * .9 + .1 * MaxX;
     double maxMeanx = MinX * .1 + .9 * MaxX;
     if (getConstraint(2) == nullptr) {
-      addConstraint(new BoundaryConstraint(this, "Mcol", minMeanx, maxMeanx));
+      addConstraint(Kernel::make_unique<BoundaryConstraint>(
+          this, "Mcol", minMeanx, maxMeanx));
     }
 
     if (CalcVariances && nParams() > 6) {
diff --git a/Framework/CurveFitting/src/Functions/CrystalElectricField.cpp b/Framework/CurveFitting/src/Functions/CrystalElectricField.cpp
index 099f22cc1c90317899991b1332c8888d56bc0268..ff78903bee0f07145917c2fa53f51d354b1356d8 100644
--- a/Framework/CurveFitting/src/Functions/CrystalElectricField.cpp
+++ b/Framework/CurveFitting/src/Functions/CrystalElectricField.cpp
@@ -51,8 +51,8 @@ const double me = 9.109389754;  // x 10**(-31) kg, electron mass
 //       10*ee/kb =: fmevkelvin = 11.6047...
 //       this means 1 meV is nearly 11.6 K
 const double c_fmevkelvin = 10 * ee / kb;
-//  magneton of Bohr in kelvin per tesla
-const double c_myb = hq / me / 2 * c_fmevkelvin;
+//  magneton of Bohr in meV per tesla
+const double c_myb = hq / me / 2;
 
 //--------------------------------
 // define the delta function
@@ -335,7 +335,7 @@ double binom(int n, int k) {
 
 //--------------------------------------------------------
 //              (k)
-// calculates  D    (a,b,c)
+// calculates  D    (a,b,c)   [ The Wigner D-matrix ]
 //              ms m
 //
 // see Lindner A, 'Drehimpulse in der Quantenmechanik',
@@ -566,31 +566,129 @@ double c_occupation_factor(const DoubleFortranVector &energy, double dimj,
   return occupation_factor;
 }
 
+//--------------------------------------
+// calculation of the zeeman hamiltonian
+//--------------------------------------
+void zeeman(ComplexFortranMatrix &hamiltonian, const int nre,
+            const DoubleFortranVector &bext, const DoubleFortranVector &bmol) {
+  auto i = ComplexType(0.0, 1.0);
+  auto bmolp = bmol(1) + i * bmol(2);
+  auto bmolm = bmol(1) - i * bmol(2);
+  auto bmolz = bmol(3);
+  auto bextp = bext(1) + i * bext(2);
+  auto bextm = bext(1) - i * bext(2);
+  ComplexType bextz = bext(3);
+  auto gj = ggj[nre - 1];
+  auto facmol = 2 * (gj - 1) * c_myb;
+  auto facext = gj * c_myb;
+  auto dimj = ddimj[nre - 1];
+  auto j = 0.5 * (dimj - 1.0);
+  int dim = static_cast<int>(dimj);
+  hamiltonian.allocate(1, dim, 1, dim);
+  hamiltonian.zero();
+  //-------------------------------------------------------------------
+  //       define only the lower triangle of h(m,n)
+  //-------------------------------------------------------------------
+  for (int m = 1; m <= dim; ++m) { //	do 10 m=1,dim
+    auto mj = double(m) - j - 1.0;
+    for (int n = 1; n <= m; ++n) { // do 20 n=1,m
+      auto nj = double(n) - j - 1.0;
+      // add the molecular field
+      //  f*J*B = f*( 1/2*(J+ * B-  +  J- * B+) + Jz*Bz )
+      hamiltonian(m, n) =
+          hamiltonian(m, n) +
+          0.5 * facmol * bmolm * delta(mj, nj + 1, j) * jp(nj, j) +
+          0.5 * facmol * bmolp * delta(mj, nj - 1, j) * jm(nj, j) +
+          facmol * bmolz * delta(mj, nj, j) * nj +
+          // c add an external magnetic field
+          0.5 * facext * bextm * delta(mj, nj + 1, j) * jp(nj, j) +
+          0.5 * facext * bextp * delta(mj, nj - 1, j) * jm(nj, j) +
+          facext * bextz * delta(mj, nj, j) * nj;
+      hamiltonian(n, m) = conjg(hamiltonian(m, n));
+    }
+  }
+}
+
+//---------------------------------------
+// Calculation of the eigenvalues/vectors
+//---------------------------------------
+void diagonalise(const ComplexFortranMatrix &hamiltonian,
+                 DoubleFortranVector &eigenvalues,
+                 ComplexFortranMatrix &eigenvectors) {
+  // Diagonalisation of the hamiltonian
+  auto dim = hamiltonian.len1();
+  eigenvalues.allocate(1, dim);
+  eigenvectors.allocate(1, dim, 1, dim);
+  ComplexFortranMatrix h = hamiltonian;
+  h.eigenSystemHermitian(eigenvalues, eigenvectors);
+
+  // Sort the eigenvalues in ascending order
+  auto sortedIndices = eigenvalues.sortIndices();
+  eigenvalues.sort(sortedIndices);
+  // Eigenvectors are in columns. Sort the columns
+  // to match the sorted eigenvalues.
+  eigenvectors.sortColumns(sortedIndices);
+
+  // Shift the lowest energy level to 0
+  auto indexMin = static_cast<int>(eigenvalues.indexOfMinElement() + 1);
+  auto eshift = eigenvalues(indexMin);
+  eigenvalues += -eshift;
+}
+
 #ifdef __clang__
 #pragma clang diagnostic pop
 #endif
 
 } // anonymous namespace
 
+/// Calculates the eigenvalues/vectors of a crystal field Hamiltonian in a
+/// specified external magnetic field.
+/// @param eigenvalues :: Output. The eigenvalues in ascending order. The
+/// smallest value is subtracted from all eigenvalues so they always
+/// start with 0.
+/// @param eigenvectors :: Output. The matrix of eigenvectors. The eigenvectors
+///    are in columns with indices corresponding to the indices of eigenvalues.
+/// @param hamiltonian  :: The crystal field hamiltonian in meV.
+/// @param nre :: A number denoting the type of ion.
+///  |1=Ce|2=Pr|3=Nd|4=Pm|5=Sm|6=Eu|7=Gd|8=Tb|9=Dy|10=Ho|11=Er|12=Tm|13=Yb|
+/// @param bext :: The external field in Cartesians (Hx, Hy, Hz) in Tesla
+///    The z-axis is parallel to the crystal field quantisation axis.
+void calculateZeemanEigensystem(DoubleFortranVector &eigenvalues,
+                                ComplexFortranMatrix &eigenvectors,
+                                const ComplexFortranMatrix &hamiltonian,
+                                int nre, const DoubleFortranVector &bext) {
+  ComplexFortranMatrix h = hamiltonian;
+  DoubleFortranVector bmol(1, 3);
+  bmol.zero();
+  // Adds the external and molecular fields
+  ComplexFortranMatrix hz;
+  zeeman(hz, nre, bext, bmol);
+  h -= hz;
+  // Now run the actual diagonalisation
+  diagonalise(h, eigenvalues, eigenvectors);
+}
+
 /// Calculate eigenvalues and eigenvectors of the crystal field hamiltonian.
 /// @param eigenvalues :: Output. The eigenvalues in ascending order. The
 /// smallest value is subtracted from all eigenvalues so they always
 /// start with 0.
 /// @param eigenvectors :: Output. The matrix of eigenvectors. The eigenvectors
 ///    are in columns with indices corresponding to the indices of eigenvalues.
-/// @param hamiltonian  :: Output. The hamiltonian.
+/// @param hamiltonian  :: Output. The crystal field hamiltonian.
+/// @param hzeeman  :: Output. The zeeman hamiltonian.
 /// @param nre :: A number denoting the type of ion.
 ///  |1=Ce|2=Pr|3=Nd|4=Pm|5=Sm|6=Eu|7=Gd|8=Tb|9=Dy|10=Ho|11=Er|12=Tm|13=Yb|
-/// @param bmol :: Parameters of the molecular field. TODO: ref. frame, units.
-/// @param bext :: Parameters of the external field. TODO: ref. frame, units.
-/// @param bkq :: The crystal field parameters. TODO: confirm units. It look
-/// like in meV.
-/// @param alpha_euler :: The alpha Euler angle. TOD: units.
-/// @param beta_euler :: The beta Euler angle. TOD: units.
-/// @param gamma_euler :: The gamma Euler angle. TOD: units.
+/// @param bmol :: The molecular field in Cartesian (Bx, By, Bz) in Tesla
+/// @param bext :: The external field in Cartesian (Hx, Hy, Hz) in Tesla
+///    The z-axis is parallel to the crystal field quantisation axis.
+/// @param bkq :: The crystal field parameters in meV.
+/// @param alpha_euler :: The alpha Euler angle in radians
+/// @param beta_euler :: The beta Euler angle in radians
+/// @param gamma_euler :: The gamma Euler angle in radians
 void calculateEigensystem(DoubleFortranVector &eigenvalues,
                           ComplexFortranMatrix &eigenvectors,
-                          ComplexFortranMatrix &hamiltonian, int nre,
+                          ComplexFortranMatrix &hamiltonian,
+                          ComplexFortranMatrix &hzeeman, int nre,
                           const DoubleFortranVector &bmol,
                           const DoubleFortranVector &bext,
                           const ComplexFortranMatrix &bkq, double alpha_euler,
@@ -600,11 +698,8 @@ void calculateEigensystem(DoubleFortranVector &eigenvalues,
   }
 
   // initialize some rare earth constants
-  auto gj = ggj[nre - 1];
   auto dimj = ddimj[nre - 1];
 
-  // magneton of Bohr in kelvin per tesla
-  auto myb = c_myb;
   //------------------------------------------------------------
   //       transform the Bkq with
   //       H = sum_k=0 Bk0 Ok0 + sum_k>0_q>0  ReBkq ReOkq + ImBkq ImOkq
@@ -636,7 +731,22 @@ void calculateEigensystem(DoubleFortranVector &eigenvalues,
     }
   }
   //-------------------------------------------------------------------
-  // Rotate the crystal field (?)
+  // Rotate the crystal field quantisation axis by the specified
+  // Euler angles. In some cases the number of CF parameters can be
+  // reduced by chosing the quantisation axis along a high symmetry
+  // rotation axis, rather than along a crystallographic axis.
+  // The eigenvalues should remain the same, but the eigenvectors will
+  // change.
+  // The rotation is done using a Wigner D-matrix. As noted by
+  // Buckmaster, the Stevens operators cannot be rotated as is, because
+  // the have an inconsistent normalisation between differen k, q terms
+  // Thus they have to be converted to and from the "Wybourne"
+  // normalisation using the epsilon / omega values.
+  // There was a bug in the original FOCUS code. Multiplying by
+  // omega*epsilon converts Wybourne parameters to Stevens parameters.
+  // Thus to convert the original dkq_star(k,qs) from Steven to Wybourn
+  // we should divide by epsilon(k,qs)*omega(k,qs) and then multiply by
+  // the new dkq_star(k,q) by epsilon(k,q)*omega(k,q).
   //-------------------------------------------------------------------
   ComplexFortranMatrix rdkq_star(1, 6, -6, 6);
   for (int k = 2; k <= 6; k += 2) { // do k=2,6,2
@@ -645,8 +755,8 @@ void calculateEigensystem(DoubleFortranVector &eigenvalues,
       for (int qs = -k; qs <= k; ++qs) { // do qs=-k,k
         rdkq_star(k, q) =
             rdkq_star(k, q) +
-            dkq_star(k, qs) * epsilon(k, qs) / epsilon(k, q) * omega(k, qs) /
-                omega(k, q) *
+            dkq_star(k, qs) * epsilon(k, q) / epsilon(k, qs) * omega(k, q) /
+                omega(k, qs) *
                 ddrot(k, q, qs, alpha_euler, beta_euler, gamma_euler);
       }
     }
@@ -684,21 +794,10 @@ void calculateEigensystem(DoubleFortranVector &eigenvalues,
           bex(1, qs) * ddrot(1, q, qs, alpha_euler, beta_euler, gamma_euler);
     }
   }
-
-  ComplexType rbextp, rbextm, rbextz;
-  rbextp = rbex(1, -1) * M_SQRT2;
-  rbextm = rbex(1, 1) * (-M_SQRT2);
-  rbextz = rbex(1, 0);
-
-  auto facmol = 2 * (gj - 1) * myb;
-  auto facext = gj * myb;
-
-  auto bmolp = bmol(1) + i * bmol(2);
-  auto bmolm = bmol(1) - i * bmol(2);
-  auto bmolz = bmol(3);
-  auto bextp = rbextp;
-  auto bextm = rbextm;
-  auto bextz = rbextz;
+  DoubleFortranVector rbext(1, 3);
+  rbext(1) = real(static_cast<ComplexType>(rbex(1, -1))) * M_SQRT2;
+  rbext(2) = imag(static_cast<ComplexType>(rbex(1, -1))) * M_SQRT2;
+  rbext(3) = real(static_cast<ComplexType>(rbex(1, 0)));
 
   int dim = static_cast<int>(dimj);
   hamiltonian.allocate(1, dim, 1, dim);
@@ -719,47 +818,16 @@ void calculateEigensystem(DoubleFortranVector &eigenvalues,
               hamiltonian(m, n) + rdkq_star(k, q) * full_okq(k, q, mj, nj, j);
         }
       }
-    }
-  }
-  //-------------------------------------------------------------------
-  //       define only the lower triangle of h(m,n)
-  //-------------------------------------------------------------------
-  for (int m = 1; m <= dim; ++m) { //	do 10 m=1,dim
-    auto mj = double(m) - j - 1.0;
-    for (int n = 1; n <= m; ++n) { // do 20 n=1,m
-      auto nj = double(n) - j - 1.0;
-      // add the molecular field
-      //  f*J*B = f*( 1/2*(J+ * B-  +  J- * B+) + Jz*Bz )
-      hamiltonian(m, n) =
-          hamiltonian(m, n) +
-          0.5 * facmol * bmolm * delta(mj, nj + 1, j) * jp(nj, j) +
-          0.5 * facmol * bmolp * delta(mj, nj - 1, j) * jm(nj, j) +
-          facmol * bmolz * delta(mj, nj, j) * nj +
-          // c add an external magnetic field
-          0.5 * facext * bextm * delta(mj, nj + 1, j) * jp(nj, j) +
-          0.5 * facext * bextp * delta(mj, nj - 1, j) * jm(nj, j) +
-          facext * bextz * delta(mj, nj, j) * nj;
       hamiltonian(n, m) = conjg(hamiltonian(m, n));
     }
   }
 
-  // Diagonalisation of the hamiltonian
-  eigenvalues.allocate(1, dim);
-  eigenvectors.allocate(1, dim, 1, dim);
-  ComplexFortranMatrix h = hamiltonian;
-  h.eigenSystemHermitian(eigenvalues, eigenvectors);
-
-  // Sort the eigenvalues in ascending order
-  auto sortedIndices = eigenvalues.sortIndices();
-  eigenvalues.sort(sortedIndices);
-  // Eigenvectors are in columns. Sort the columns
-  // to match the sorted eigenvalues.
-  eigenvectors.sortColumns(sortedIndices);
+  // Adds the external and molecular fields
+  zeeman(hzeeman, nre, rbext, bmol);
+  hamiltonian -= hzeeman;
 
-  // Shift the lowest energy level to 0
-  auto indexMin = static_cast<int>(eigenvalues.indexOfMinElement() + 1);
-  auto eshift = eigenvalues(indexMin);
-  eigenvalues += -eshift;
+  // Now run the actual diagonalisation
+  diagonalise(hamiltonian, eigenvalues, eigenvectors);
 }
 
 //-------------------------
@@ -973,6 +1041,47 @@ void calculateExcitations(const DoubleFortranVector &e_energies,
   }
 }
 
+/// Calculate the diagonal matrix elements of the magnetic moment operator
+/// in a particular eigenvector basis.
+/// @param ev :: Input. The eigenvector basis.
+/// @param Hdir :: Input. Cartesian direction of the magnetic moment operator
+/// @param nre :: Input. The ion number to calculate for.
+/// @param moment :: Output. The diagonal elements of the magnetic moment matrix
+void calculateMagneticMoment(const ComplexFortranMatrix &ev,
+                             const DoubleFortranVector &Hdir, const int nre,
+                             DoubleFortranVector &moment) {
+  int dim = (int)ddimj[nre - 1];
+  auto gj = ggj[nre - 1];
+  moment.allocate(dim);
+  for (auto i = 1; i <= dim; ++i) {
+    moment(i) = real(matjx(ev, i, i, dim)) * Hdir(1) + // <ev|jx|ev>
+                real(matjy(ev, i, i, dim)) * Hdir(2) + // <ev|jy|ev>
+                real(matjz(ev, i, i, dim)) * Hdir(3);  // <ev|jz|ev>
+  }
+  moment *= gj;
+}
+
+/// Calculate the full magnetic moment matrix in a particular eigenvector basis.
+/// @param ev :: Input. The eigenvector basis.
+/// @param Hdir :: Input. Cartesian direction of the magnetic moment operator
+/// @param nre :: Input. The ion number to calculate for.
+/// @param mumat :: Output. The matrix elements of the magnetic moment matrix
+void calculateMagneticMomentMatrix(const ComplexFortranMatrix &ev,
+                                   const std::vector<double> &Hdir,
+                                   const int nre, ComplexFortranMatrix &mumat) {
+  int dim = (int)ddimj[nre - 1];
+  auto gj = ggj[nre - 1];
+  mumat.allocate(1, dim, 1, dim);
+  for (auto i = 1; i <= dim; ++i) {
+    for (auto j = 1; j <= dim; ++j) {
+      mumat(i, j) = matjx(ev, i, j, dim) * Hdir[0] + // <ev|jx|ev'>
+                    matjy(ev, i, j, dim) * Hdir[1] + // <ev|jy|ev'>
+                    matjz(ev, i, j, dim) * Hdir[2];  // <ev|jz|ev'>
+    }
+  }
+  mumat *= gj;
+}
+
 } // namespace Functions
 } // namespace CurveFitting
 } // namespace Mantid
diff --git a/Framework/CurveFitting/src/Functions/CrystalFieldHeatCapacity.cpp b/Framework/CurveFitting/src/Functions/CrystalFieldHeatCapacity.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..bfda161af7db22fd88736d61fe80e74e82904d5e
--- /dev/null
+++ b/Framework/CurveFitting/src/Functions/CrystalFieldHeatCapacity.cpp
@@ -0,0 +1,84 @@
+#include "MantidCurveFitting/Functions/CrystalFieldHeatCapacity.h"
+#include "MantidCurveFitting/Functions/CrystalFieldPeaksBase.h"
+#include "MantidCurveFitting/FortranDefs.h"
+#include "MantidAPI/FunctionFactory.h"
+#include "MantidAPI/FunctionValues.h"
+#include "MantidAPI/FunctionDomain.h"
+#include "MantidAPI/FunctionDomain1D.h"
+#include "MantidAPI/IFunction1D.h"
+#include "MantidAPI/Jacobian.h"
+#include "MantidKernel/Exception.h"
+#include "MantidKernel/PhysicalConstants.h"
+#include <cmath>
+
+namespace Mantid {
+namespace CurveFitting {
+namespace Functions {
+
+namespace {
+
+// Does the actual calculation of the heat capacity
+void calculate(double *out, const double *xValues, const size_t nData,
+               const DoubleFortranVector &en) {
+  const double k_B = PhysicalConstants::BoltzmannConstant; // in meV/K
+  // Want output in J/K/mol
+  const double convfact = PhysicalConstants::N_A * PhysicalConstants::meV;
+  int nlevels = en.len();
+  for (size_t iT = 0; iT < nData; iT++) {
+    double expfact;
+    double Z = 0.;
+    double U = 0.;
+    double U2 = 0.;
+    const double beta = 1 / (k_B * xValues[iT]);
+    // Using fortran indexing...
+    for (auto iE = 1; iE <= nlevels; iE++) {
+      expfact = exp(-beta * en(iE));
+      Z += expfact;
+      U += en(iE) * expfact;
+      U2 += en(iE) * en(iE) * expfact;
+    }
+    U /= Z;
+    U2 /= Z;
+    out[iT] = ((U2 - U * U) / (k_B * xValues[iT] * xValues[iT])) * convfact;
+  }
+}
+}
+
+DECLARE_FUNCTION(CrystalFieldHeatCapacity)
+
+CrystalFieldHeatCapacity::CrystalFieldHeatCapacity()
+    : CrystalFieldPeaksBase(), API::IFunction1D(), m_setDirect(false) {
+  declareAttribute("ScaleFactor", Attribute(1.0)); // Only for multi-site use
+}
+
+// Sets the eigenvectors / values directly
+void CrystalFieldHeatCapacity::setEnergy(const DoubleFortranVector &en) {
+  m_setDirect = true;
+  m_en = en;
+}
+
+void CrystalFieldHeatCapacity::function1D(double *out, const double *xValues,
+                                          const size_t nData) const {
+  if (!m_setDirect) {
+    // Because this method is const, we can't change the stored en / wf
+    // Use temporary variables instead.
+    DoubleFortranVector en;
+    ComplexFortranMatrix wf;
+    int nre = 0;
+    calculateEigenSystem(en, wf, nre);
+    calculate(out, xValues, nData, en);
+  } else {
+    // Use stored values
+    calculate(out, xValues, nData, m_en);
+  }
+  auto fact = getAttribute("ScaleFactor").asDouble();
+  if (fact != 1.0) {
+    for (size_t i = 0; i < nData; i++) {
+      out[i] *= fact;
+    }
+  }
+}
+
+} // namespace Functions
+} // namespace CurveFitting
+} // namespace Mantid
diff --git a/Framework/CurveFitting/src/Functions/CrystalFieldMagnetisation.cpp b/Framework/CurveFitting/src/Functions/CrystalFieldMagnetisation.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ef00d78219aa5d64e047a94f42ff083335e7dc7a
--- /dev/null
+++ b/Framework/CurveFitting/src/Functions/CrystalFieldMagnetisation.cpp
@@ -0,0 +1,158 @@
+#include "MantidCurveFitting/Functions/CrystalFieldMagnetisation.h"
+#include "MantidCurveFitting/Functions/CrystalFieldPeaksBase.h"
+#include "MantidCurveFitting/Functions/CrystalElectricField.h"
+#include "MantidCurveFitting/FortranDefs.h"
+#include "MantidAPI/FunctionFactory.h"
+#include "MantidAPI/FunctionValues.h"
+#include "MantidAPI/FunctionDomain.h"
+#include "MantidAPI/FunctionDomain1D.h"
+#include "MantidAPI/IFunction1D.h"
+#include "MantidAPI/Jacobian.h"
+#include "MantidKernel/Exception.h"
+#include "MantidKernel/PhysicalConstants.h"
+#include <cmath>
+#include <boost/algorithm/string/predicate.hpp>
+
+namespace Mantid {
+namespace CurveFitting {
+namespace Functions {
+
+namespace {
+
+// Does the actual calculation of the magnetisation
+void calculate(double *out, const double *xValues, const size_t nData,
+               const ComplexFortranMatrix &ham, const int nre,
+               const DoubleFortranVector Hmag, const double T,
+               const double convfact, const bool iscgs) {
+  const double beta = 1 / (PhysicalConstants::BoltzmannConstant * T);
+  // x-data is the applied field magnitude. We need to recalculate
+  // the Zeeman term and diagonalise the Hamiltonian at each x-point.
+  int nlevels = ham.len1();
+  for (size_t iH = 0; iH < nData; iH++) {
+    DoubleFortranVector en;
+    ComplexFortranMatrix ev;
+    DoubleFortranVector H = Hmag;
+    H *= xValues[iH];
+    if (iscgs) {
+      H *= 0.0001; // Converts from Gauss to Tesla.
+    }
+    calculateZeemanEigensystem(en, ev, ham, nre, H);
+    // Calculates the diagonal of the magnetic moment operator <wf|mu|wf>
+    DoubleFortranVector moment;
+    calculateMagneticMoment(ev, Hmag, nre, moment);
+    double expfact;
+    double Z = 0.;
+    double M = 0.;
+    for (auto iE = 1; iE <= nlevels; iE++) {
+      expfact = exp(-beta * en(iE));
+      Z += expfact;
+      M += moment(iE) * expfact;
+    }
+    out[iH] = convfact * M / Z;
+  }
+}
+
+// Calculate powder average - Mpowder = (Mx + My + Mz)/3
+void calculate_powder(double *out, const double *xValues, const size_t nData,
+                      const ComplexFortranMatrix &ham, const int nre,
+                      const double T, const double convfact, const bool cgs) {
+  for (size_t j = 0; j < nData; j++) {
+    out[j] = 0.;
+  }
+  // Loop over the x, y, z directions
+  DoubleFortranVector Hmag(1, 3);
+  std::vector<double> tmp(nData, 0.);
+  for (int i = 1; i <= 3; i++) {
+    Hmag.zero();
+    Hmag(i) = 1.;
+    calculate(&tmp[0], xValues, nData, ham, nre, Hmag, T, convfact, cgs);
+    for (size_t j = 0; j < nData; j++) {
+      out[j] += tmp[j];
+    }
+  }
+  for (size_t j = 0; j < nData; j++) {
+    out[j] /= 3.;
+  }
+}
+}
+
+DECLARE_FUNCTION(CrystalFieldMagnetisation)
+
+CrystalFieldMagnetisation::CrystalFieldMagnetisation()
+    : CrystalFieldPeaksBase(), API::IFunction1D(), m_setDirect(false) {
+  declareAttribute("Hdir", Attribute(std::vector<double>{0., 0., 1.}));
+  declareAttribute("Temperature", Attribute(1.0));
+  declareAttribute("Unit", Attribute("bohr")); // others = "SI", "cgs"
+  declareAttribute("powder", Attribute(false));
+  declareAttribute("ScaleFactor", Attribute(1.0)); // Only for multi-site use
+}
+
+// Sets the base crystal field Hamiltonian matrix
+void CrystalFieldMagnetisation::setHamiltonian(const ComplexFortranMatrix &ham,
+                                               const int nre) {
+  m_setDirect = true;
+  m_ham = ham;
+  m_nre = nre;
+}
+
+void CrystalFieldMagnetisation::function1D(double *out, const double *xValues,
+                                           const size_t nData) const {
+  // Get the field direction
+  auto Hdir = getAttribute("Hdir").asVector();
+  if (Hdir.size() != 3) {
+    throw std::invalid_argument("Hdir must be a three-element vector.");
+  }
+  auto T = getAttribute("Temperature").asDouble();
+  auto powder = getAttribute("powder").asBool();
+  double Hnorm =
+      sqrt(Hdir[0] * Hdir[0] + Hdir[1] * Hdir[1] + Hdir[2] * Hdir[2]);
+  DoubleFortranVector H(1, 3);
+  if (fabs(Hnorm) > 1.e-6) {
+    for (auto i = 0; i < 3; i++) {
+      H(i + 1) = Hdir[i] / Hnorm;
+    }
+  }
+  auto unit = getAttribute("Unit").asString();
+  const double NAMUB = 5.5849397; // N_A*mu_B - J/T/mol
+  // Converts to different units - SI is in J/T/mol or Am^2/mol.
+  // cgs is in erg/Gauss/mol (emu/mol). The value of uB in erg/G is 1000x in J/T
+  // NB. Atomic ("bohr") units gives magnetisation in uB/ion, but other units
+  // give the molar magnetisation.
+  double convfact = boost::iequals(unit, "SI")
+                        ? NAMUB
+                        : (boost::iequals(unit, "cgs") ? NAMUB * 1000. : 1.);
+  const bool iscgs = boost::iequals(unit, "cgs");
+  if (!m_setDirect) {
+    // Because this method is const, we can't change the stored en / wf
+    // Use temporary variables instead.
+    DoubleFortranVector en;
+    ComplexFortranMatrix wf;
+    ComplexFortranMatrix ham;
+    ComplexFortranMatrix hz;
+    int nre = 0;
+    calculateEigenSystem(en, wf, ham, hz, nre);
+    ham += hz;
+    if (powder) {
+      calculate_powder(out, xValues, nData, ham, nre, T, convfact, iscgs);
+    } else {
+      calculate(out, xValues, nData, ham, nre, H, T, convfact, iscgs);
+    }
+  } else {
+    // Use stored values
+    if (powder) {
+      calculate_powder(out, xValues, nData, m_ham, m_nre, T, convfact, iscgs);
+    } else {
+      calculate(out, xValues, nData, m_ham, m_nre, H, T, convfact, iscgs);
+    }
+  }
+  auto fact = getAttribute("ScaleFactor").asDouble();
+  if (fact != 1.0) {
+    for (size_t i = 0; i < nData; i++) {
+      out[i] *= fact;
+    }
+  }
+}
+
+} // namespace Functions
+} // namespace CurveFitting
+} // namespace Mantid
diff --git a/Framework/CurveFitting/src/Functions/CrystalFieldMoment.cpp b/Framework/CurveFitting/src/Functions/CrystalFieldMoment.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..0089fa2c264f843cc9809be14cc0a9b40b814252
--- /dev/null
+++ b/Framework/CurveFitting/src/Functions/CrystalFieldMoment.cpp
@@ -0,0 +1,161 @@
+#include "MantidCurveFitting/Functions/CrystalFieldMoment.h"
+#include "MantidCurveFitting/Functions/CrystalFieldPeaksBase.h"
+#include "MantidCurveFitting/Functions/CrystalElectricField.h"
+#include "MantidCurveFitting/FortranDefs.h"
+#include "MantidAPI/FunctionFactory.h"
+#include "MantidAPI/FunctionValues.h"
+#include "MantidAPI/FunctionDomain.h"
+#include "MantidAPI/FunctionDomain1D.h"
+#include "MantidAPI/IFunction1D.h"
+#include "MantidAPI/Jacobian.h"
+#include "MantidKernel/Exception.h"
+#include "MantidKernel/PhysicalConstants.h"
+#include <cmath>
+#include <boost/algorithm/string/predicate.hpp>
+
+namespace Mantid {
+namespace CurveFitting {
+namespace Functions {
+
+namespace {
+
+// Does the actual calculation of the magnetic moment
+void calculate(double *out, const double *xValues, const size_t nData,
+               const ComplexFortranMatrix &ham, const int nre,
+               const DoubleFortranVector Hdir, const double Hmag,
+               const double convfact) {
+  const double k_B = PhysicalConstants::BoltzmannConstant;
+  DoubleFortranVector en;
+  ComplexFortranMatrix ev;
+  DoubleFortranVector H = Hdir;
+  H *= Hmag;
+  calculateZeemanEigensystem(en, ev, ham, nre, H);
+  // Calculates the diagonal of the magnetic moment operator <wf|mu|wf>
+  DoubleFortranVector moment;
+  calculateMagneticMoment(ev, Hdir, nre, moment);
+  int nlevels = ham.len1();
+  // x-data is the temperature.
+  for (size_t iT = 0; iT < nData; iT++) {
+    double expfact;
+    double Z = 0.;
+    double M = 0.;
+    const double beta = 1 / (k_B * xValues[iT]);
+    for (auto iE = 1; iE <= nlevels; iE++) {
+      expfact = exp(-beta * en(iE));
+      Z += expfact;
+      M += moment(iE) * expfact;
+    }
+    out[iT] = convfact * M / Z;
+  }
+}
+
+// Powder averaging - sum over calculations along x, y, z
+void calculate_powder(double *out, const double *xValues, const size_t nData,
+                      const ComplexFortranMatrix &ham, const int nre,
+                      const double Hmag, const double convfact) {
+  for (size_t j = 0; j < nData; j++) {
+    out[j] = 0.;
+  }
+  DoubleFortranVector Hd(1, 3);
+  std::vector<double> tmp(nData, 0.);
+  for (int i = 1; i <= 3; i++) {
+    Hd.zero();
+    Hd(i) = 1.;
+    calculate(&tmp[0], xValues, nData, ham, nre, Hd, Hmag, convfact);
+    for (size_t j = 0; j < nData; j++) {
+      out[j] += tmp[j];
+    }
+  }
+  for (size_t j = 0; j < nData; j++) {
+    out[j] /= 3.;
+  }
+}
+}
+
+DECLARE_FUNCTION(CrystalFieldMoment)
+
+CrystalFieldMoment::CrystalFieldMoment()
+    : CrystalFieldPeaksBase(), API::IFunction1D(), m_setDirect(false) {
+  declareAttribute("Hdir", Attribute(std::vector<double>{0., 0., 1.}));
+  declareAttribute("Hmag", Attribute(1.0));
+  declareAttribute("Unit", Attribute("bohr")); // others = "SI", "cgs"
+  declareAttribute("inverse", Attribute(false));
+  declareAttribute("powder", Attribute(false));
+  declareAttribute("ScaleFactor", Attribute(1.0)); // Only for multi-site use
+}
+
+// Sets the base crystal field Hamiltonian matrix
+void CrystalFieldMoment::setHamiltonian(const ComplexFortranMatrix &ham,
+                                        const int nre) {
+  m_setDirect = true;
+  m_ham = ham;
+  m_nre = nre;
+}
+
+void CrystalFieldMoment::function1D(double *out, const double *xValues,
+                                    const size_t nData) const {
+  // Get the field direction
+  auto Hdir = getAttribute("Hdir").asVector();
+  if (Hdir.size() != 3) {
+    throw std::invalid_argument("Hdir must be a three-element vector.");
+  }
+  auto Hmag = getAttribute("Hmag").asDouble();
+  auto powder = getAttribute("powder").asBool();
+  double Hnorm =
+      sqrt(Hdir[0] * Hdir[0] + Hdir[1] * Hdir[1] + Hdir[2] * Hdir[2]);
+  DoubleFortranVector H(1, 3);
+  if (fabs(Hnorm) > 1.e-6) {
+    for (auto i = 0; i < 3; i++) {
+      H(i + 1) = Hdir[i] / Hnorm;
+    }
+  }
+  auto unit = getAttribute("Unit").asString();
+  const double NAMUB = 5.5849397; // N_A*mu_B - J/T/mol
+  // Converts to different units - SI is in J/T/mol or Am^2/mol. cgs in emu/mol.
+  // NB. Atomic ("bohr") units gives magnetisation in bohr magneton/ion, but
+  // other units give the molar magnetisation.
+  double convfact = boost::iequals(unit, "SI")
+                        ? NAMUB
+                        : (boost::iequals(unit, "cgs") ? NAMUB * 1000. : 1.);
+  if (boost::iequals(unit, "cgs")) {
+    Hmag *= 0.0001; // Converts field from Gauss to Tesla (calcs in SI).
+  }
+  if (!m_setDirect) {
+    // Because this method is const, we can't change the stored en / wf
+    // Use temporary variables instead.
+    DoubleFortranVector en;
+    ComplexFortranMatrix wf;
+    ComplexFortranMatrix ham;
+    ComplexFortranMatrix hz;
+    int nre = 0;
+    calculateEigenSystem(en, wf, ham, hz, nre);
+    ham += hz;
+    if (powder) {
+      calculate_powder(out, xValues, nData, ham, nre, Hmag, convfact);
+    } else {
+      calculate(out, xValues, nData, ham, nre, H, Hmag, convfact);
+    }
+  } else {
+    // Use stored values
+    if (powder) {
+      calculate_powder(out, xValues, nData, m_ham, m_nre, Hmag, convfact);
+    } else {
+      calculate(out, xValues, nData, m_ham, m_nre, H, Hmag, convfact);
+    }
+  }
+  if (getAttribute("inverse").asBool()) {
+    for (size_t i = 0; i < nData; i++) {
+      out[i] = 1. / out[i];
+    }
+  }
+  auto fact = getAttribute("ScaleFactor").asDouble();
+  if (fact != 1.0) {
+    for (size_t i = 0; i < nData; i++) {
+      out[i] *= fact;
+    }
+  }
+}
+
+} // namespace Functions
+} // namespace CurveFitting
+} // namespace Mantid
diff --git a/Framework/CurveFitting/src/Functions/CrystalFieldMultiSpectrum.cpp b/Framework/CurveFitting/src/Functions/CrystalFieldMultiSpectrum.cpp
index 259a12529cc0ced43b7d016442b0d9dffd173570..1f3ae4e0ff55a6d85608f1ff8995d8d5f904191a 100644
--- a/Framework/CurveFitting/src/Functions/CrystalFieldMultiSpectrum.cpp
+++ b/Framework/CurveFitting/src/Functions/CrystalFieldMultiSpectrum.cpp
@@ -2,9 +2,14 @@
 #include "MantidCurveFitting/Functions/CrystalElectricField.h"
 #include "MantidCurveFitting/Functions/CrystalFieldPeaks.h"
 #include "MantidCurveFitting/Functions/CrystalFieldPeakUtils.h"
+#include "MantidCurveFitting/Functions/CrystalFieldHeatCapacity.h"
+#include "MantidCurveFitting/Functions/CrystalFieldSusceptibility.h"
+#include "MantidCurveFitting/Functions/CrystalFieldMagnetisation.h"
+#include "MantidCurveFitting/Functions/CrystalFieldMoment.h"
 
 #include "MantidAPI/FunctionFactory.h"
 #include "MantidAPI/IConstraint.h"
+#include "MantidAPI/IFunction1D.h"
 #include "MantidAPI/IPeakFunction.h"
 #include "MantidAPI/MultiDomainFunction.h"
 #include "MantidAPI/ParameterTie.h"
@@ -25,7 +30,7 @@ namespace {
 
 /// Define the source function for CrystalFieldMultiSpectrum.
 /// Its function() method is not needed.
-class Peaks : public CrystalFieldPeaksBase {
+class Peaks : public CrystalFieldPeaksBase, public API::IFunctionGeneral {
 public:
   Peaks() : CrystalFieldPeaksBase() {}
   std::string name() const override { return "Peaks"; }
@@ -42,14 +47,38 @@ public:
     throw Exception::NotImplementedError(
         "This method is intentionally not implemented.");
   }
-  /// Decalre the intensity scaling parameters: one per spectrum.
+  std::vector<size_t> m_IntensityScalingIdx;
+  std::vector<size_t> m_PPLambdaIdxChild;
+  std::vector<size_t> m_PPLambdaIdxSelf;
+  /// Declare the intensity scaling parameters: one per spectrum.
   void declareIntensityScaling(size_t nSpec) {
+    m_IntensityScalingIdx.clear();
+    m_PPLambdaIdxChild.resize(nSpec, -1);
+    m_PPLambdaIdxSelf.resize(nSpec, -1);
     for (size_t i = 0; i < nSpec; ++i) {
       auto si = std::to_string(i);
-      declareParameter("IntensityScaling" + si, 1.0,
-                       "Intensity scaling factor for spectrum " + si);
+      try { // If parameter has already been declared, don't declare it.
+        declareParameter("IntensityScaling" + si, 1.0,
+                         "Intensity scaling factor for spectrum " + si);
+      } catch (std::invalid_argument &) {
+      }
+      m_IntensityScalingIdx.push_back(parameterIndex("IntensityScaling" + si));
     }
   }
+  /// Declare the Lambda parameter for susceptibility
+  void declarePPLambda(size_t iSpec) {
+    if (m_PPLambdaIdxSelf.size() <= iSpec) {
+      m_PPLambdaIdxSelf.resize(iSpec + 1, -1);
+      m_PPLambdaIdxChild.resize(iSpec + 1, -1);
+    }
+    auto si = std::to_string(iSpec);
+    try { // If parameter has already been declared, don't declare it.
+      declareParameter("Lambda" + si, 0.0,
+                       "Effective exchange coupling of dataset " + si);
+    } catch (std::invalid_argument &) {
+    }
+    m_PPLambdaIdxSelf[iSpec] = parameterIndex("Lambda" + si);
+  }
 };
 }
 
@@ -63,6 +92,10 @@ CrystalFieldMultiSpectrum::CrystalFieldMultiSpectrum()
   declareAttribute("FWHMX0", Attribute(std::vector<double>()));
   declareAttribute("FWHMY0", Attribute(std::vector<double>()));
   declareAttribute("FWHMVariation", Attribute(0.1));
+  declareAttribute("NPeaks", Attribute(0));
+  declareAttribute("FixAllPeaks", Attribute(false));
+  declareAttribute("PhysicalProperties",
+                   Attribute(std::vector<double>(1, 0.0)));
 }
 
 size_t CrystalFieldMultiSpectrum::getNumberDomains() const {
@@ -101,6 +134,31 @@ void CrystalFieldMultiSpectrum::setAttribute(const std::string &name,
       declareAttribute("FWHMY" + suffix, Attribute(m_fwhmY[iSpec]));
     }
   }
+  if (name == "PhysicalProperties") {
+    auto physpropId = attr.asVector();
+    auto nSpec = physpropId.size();
+    auto &source = dynamic_cast<Peaks &>(*m_source);
+    for (size_t iSpec = 0; iSpec < nSpec; ++iSpec) {
+      auto suffix = std::to_string(iSpec);
+      auto pptype = static_cast<int>(physpropId[iSpec]);
+      switch (pptype) {
+      case MagneticMoment: // Hmag, Hdir, inverse, Unit, powder
+        declareAttribute("Hmag" + suffix, Attribute(1.0));
+      case Susceptibility: // Hdir, inverse, Unit, powder
+        declareAttribute("inverse" + suffix, Attribute(false));
+      case Magnetisation: // Hdir, Unit, powder
+        declareAttribute("Hdir" + suffix,
+                         Attribute(std::vector<double>{0., 0., 1.}));
+        declareAttribute("Unit" + suffix, Attribute("bohr"));
+        declareAttribute("powder" + suffix, Attribute(false));
+        break;
+      }
+      if (pptype == Susceptibility) {
+        source.declarePPLambda(iSpec);
+        m_nOwnParams = m_source->nParams();
+      }
+    }
+  }
   FunctionGenerator::setAttribute(name, attr);
 }
 
@@ -114,9 +172,12 @@ void CrystalFieldMultiSpectrum::buildTargetFunction() const {
 
   DoubleFortranVector en;
   ComplexFortranMatrix wf;
+  ComplexFortranMatrix ham;
+  ComplexFortranMatrix hz;
   int nre = 0;
   auto &peakCalculator = dynamic_cast<Peaks &>(*m_source);
-  peakCalculator.calculateEigenSystem(en, wf, nre);
+  peakCalculator.calculateEigenSystem(en, wf, ham, hz, nre);
+  ham += hz;
 
   // Get the temperatures from the attribute
   auto temperatures = getAttribute("Temperatures").asVector();
@@ -137,20 +198,44 @@ void CrystalFieldMultiSpectrum::buildTargetFunction() const {
                                "Temperatures or have size 1.");
     }
   }
-  // Create the single-spectrum functions.
   auto nSpec = temperatures.size();
+  // Get a list of "spectra" which corresponds to physical properties
+  auto physprops = getAttribute("PhysicalProperties").asVector();
+  if (physprops.empty()) {
+    m_physprops.resize(nSpec, 0); // Assume no physical properties - just INS
+  } else if (physprops.size() != nSpec) {
+    if (physprops.size() == 1) {
+      int physprop = (int)physprops.front();
+      m_physprops.resize(nSpec, physprop);
+    } else {
+      throw std::runtime_error("Vector of PhysicalProperties must have same "
+                               "size as Temperatures or size 1.");
+    }
+  } else {
+    m_physprops.clear();
+    for (auto elem : physprops) {
+      m_physprops.push_back((int)elem);
+    }
+  }
+  // Create the single-spectrum functions.
   m_nPeaks.resize(nSpec);
   if (m_fwhmX.empty()) {
     m_fwhmX.resize(nSpec);
     m_fwhmY.resize(nSpec);
   }
   for (size_t i = 0; i < nSpec; ++i) {
-    if (m_fwhmX[i].empty()) {
-      auto suffix = std::to_string(i);
-      m_fwhmX[i] = IFunction::getAttribute("FWHMX" + suffix).asVector();
-      m_fwhmY[i] = IFunction::getAttribute("FWHMY" + suffix).asVector();
+    if (m_physprops[i] > 0) {
+      // This "spectrum" is actually a physical properties dataset.
+      fun->addFunction(buildPhysprop(nre, en, wf, ham, temperatures[i], i));
+    } else {
+      if (m_fwhmX[i].empty()) {
+        auto suffix = std::to_string(i);
+        m_fwhmX[i] = IFunction::getAttribute("FWHMX" + suffix).asVector();
+        m_fwhmY[i] = IFunction::getAttribute("FWHMY" + suffix).asVector();
+      }
+      fun->addFunction(
+          buildSpectrum(nre, en, wf, temperatures[i], fwhms[i], i));
     }
-    fun->addFunction(buildSpectrum(nre, en, wf, temperatures[i], fwhms[i], i));
     fun->setDomainIndex(i, i);
   }
 }
@@ -173,7 +258,13 @@ void CrystalFieldMultiSpectrum::calcExcitations(
   const size_t nSpec = m_nPeaks.size();
   // Get intensity scaling parameter "IntensityScaling" + std::to_string(iSpec)
   // using an index instead of a name for performance reasons
-  double intensityScaling = getParameter(m_nOwnParams - nSpec + iSpec);
+  auto &source = dynamic_cast<Peaks &>(*m_source);
+  double intensityScaling;
+  if (source.m_IntensityScalingIdx.size() == 0) {
+    intensityScaling = getParameter(m_nOwnParams - nSpec + iSpec);
+  } else {
+    intensityScaling = getParameter(source.m_IntensityScalingIdx[iSpec]);
+  }
   auto nPeaks = eExcitations.size();
   values.expand(2 * nPeaks);
   for (size_t i = 0; i < nPeaks; ++i) {
@@ -193,6 +284,8 @@ API::IFunction_sptr CrystalFieldMultiSpectrum::buildSpectrum(
   auto fwhmVariation = getAttribute("FWHMVariation").asDouble();
   auto peakShape = IFunction::getAttribute("PeakShape").asString();
   auto bkgdShape = IFunction::getAttribute("Background").asUnquotedString();
+  size_t nRequiredPeaks = IFunction::getAttribute("NPeaks").asInt();
+  bool fixAllPeaks = getAttribute("FixAllPeaks").asBool();
 
   if (!bkgdShape.empty() && bkgdShape.find("name=") != 0 &&
       bkgdShape.front() != '(') {
@@ -203,14 +296,65 @@ API::IFunction_sptr CrystalFieldMultiSpectrum::buildSpectrum(
   auto background =
       API::FunctionFactory::Instance().createInitialized(bkgdShape);
   spectrum->addFunction(background);
+  if (fixAllPeaks) {
+    background->fixAll();
+  }
 
   m_nPeaks[iSpec] = CrystalFieldUtils::buildSpectrumFunction(
       *spectrum, peakShape, values, m_fwhmX[iSpec], m_fwhmY[iSpec],
-      fwhmVariation, fwhm);
-
+      fwhmVariation, fwhm, nRequiredPeaks, fixAllPeaks);
   return IFunction_sptr(spectrum);
 }
 
+API::IFunction_sptr CrystalFieldMultiSpectrum::buildPhysprop(
+    int nre, const DoubleFortranVector &en, const ComplexFortranMatrix &wf,
+    const ComplexFortranMatrix &ham, double temperature, size_t iSpec) const {
+  switch (m_physprops[iSpec]) {
+  case HeatCapacity: {
+    IFunction_sptr retval = IFunction_sptr(new CrystalFieldHeatCapacity);
+    auto &spectrum = dynamic_cast<CrystalFieldHeatCapacity &>(*retval);
+    spectrum.setEnergy(en);
+    return retval;
+  }
+  case Susceptibility: {
+    IFunction_sptr retval = IFunction_sptr(new CrystalFieldSusceptibility);
+    auto &spectrum = dynamic_cast<CrystalFieldSusceptibility &>(*retval);
+    spectrum.setEigensystem(en, wf, nre);
+    auto suffix = std::to_string(iSpec);
+    spectrum.setAttribute("Hdir", getAttribute("Hdir" + suffix));
+    spectrum.setAttribute("inverse", getAttribute("inverse" + suffix));
+    spectrum.setAttribute("powder", getAttribute("powder" + suffix));
+    dynamic_cast<Peaks &>(*m_source).m_PPLambdaIdxChild[iSpec] =
+        spectrum.parameterIndex("Lambda");
+    return retval;
+  }
+  case Magnetisation: {
+    IFunction_sptr retval = IFunction_sptr(new CrystalFieldMagnetisation);
+    auto &spectrum = dynamic_cast<CrystalFieldMagnetisation &>(*retval);
+    spectrum.setHamiltonian(ham, nre);
+    spectrum.setAttribute("Temperature", Attribute(temperature));
+    auto suffix = std::to_string(iSpec);
+    spectrum.setAttribute("Unit", getAttribute("Unit" + suffix));
+    spectrum.setAttribute("Hdir", getAttribute("Hdir" + suffix));
+    spectrum.setAttribute("powder", getAttribute("powder" + suffix));
+    return retval;
+  }
+  case MagneticMoment: {
+    IFunction_sptr retval = IFunction_sptr(new CrystalFieldMoment);
+    auto &spectrum = dynamic_cast<CrystalFieldMoment &>(*retval);
+    spectrum.setHamiltonian(ham, nre);
+    auto suffix = std::to_string(iSpec);
+    spectrum.setAttribute("Unit", getAttribute("Unit" + suffix));
+    spectrum.setAttribute("Hdir", getAttribute("Hdir" + suffix));
+    spectrum.setAttribute("Hmag", getAttribute("Hmag" + suffix));
+    spectrum.setAttribute("inverse", getAttribute("inverse" + suffix));
+    spectrum.setAttribute("powder", getAttribute("powder" + suffix));
+    return retval;
+  }
+  }
+  throw std::runtime_error("Physical property type not understood");
+}
+
 /// Update m_spectrum function.
 void CrystalFieldMultiSpectrum::updateTargetFunction() const {
   if (!m_target) {
@@ -221,28 +365,63 @@ void CrystalFieldMultiSpectrum::updateTargetFunction() const {
 
   DoubleFortranVector en;
   ComplexFortranMatrix wf;
+  ComplexFortranMatrix ham;
+  ComplexFortranMatrix hz;
   int nre = 0;
   auto &peakCalculator = dynamic_cast<Peaks &>(*m_source);
-  peakCalculator.calculateEigenSystem(en, wf, nre);
+  peakCalculator.calculateEigenSystem(en, wf, ham, hz, nre);
+  ham += hz;
 
-  auto &fun = dynamic_cast<MultiDomainFunction &>(*m_target);
   auto temperatures = getAttribute("Temperatures").asVector();
-  for (size_t i = 0; i < temperatures.size(); ++i) {
-    updateSpectrum(*fun.getFunction(i), nre, en, wf, temperatures[i], i);
+  auto &fun = dynamic_cast<MultiDomainFunction &>(*m_target);
+  try {
+    for (size_t i = 0; i < temperatures.size(); ++i) {
+      updateSpectrum(*fun.getFunction(i), nre, en, wf, ham, temperatures[i], i);
+    }
+  } catch (std::out_of_range &) {
+    buildTargetFunction();
+    return;
   }
 }
 
 /// Update a function for a single spectrum.
 void CrystalFieldMultiSpectrum::updateSpectrum(
     API::IFunction &spectrum, int nre, const DoubleFortranVector &en,
-    const ComplexFortranMatrix &wf, double temperature, size_t iSpec) const {
-  auto fwhmVariation = getAttribute("FWHMVariation").asDouble();
-  FunctionValues values;
-  calcExcitations(nre, en, wf, temperature, values, iSpec);
-  auto &composite = dynamic_cast<API::CompositeFunction &>(spectrum);
-  m_nPeaks[iSpec] = CrystalFieldUtils::updateSpectrumFunction(
-      composite, values, m_nPeaks[iSpec], 1, m_fwhmX[iSpec], m_fwhmY[iSpec],
-      fwhmVariation);
+    const ComplexFortranMatrix &wf, const ComplexFortranMatrix &ham,
+    double temperature, size_t iSpec) const {
+  switch (m_physprops[iSpec]) {
+  case HeatCapacity: {
+    auto &heatcap = dynamic_cast<CrystalFieldHeatCapacity &>(spectrum);
+    heatcap.setEnergy(en);
+    break;
+  }
+  case Susceptibility: {
+    auto &suscept = dynamic_cast<CrystalFieldSusceptibility &>(spectrum);
+    suscept.setEigensystem(en, wf, nre);
+    auto &source = dynamic_cast<Peaks &>(*m_source);
+    suscept.setParameter(source.m_PPLambdaIdxChild[iSpec],
+                         getParameter(source.m_PPLambdaIdxSelf[iSpec]));
+    break;
+  }
+  case Magnetisation: {
+    auto &magnetisation = dynamic_cast<CrystalFieldMagnetisation &>(spectrum);
+    magnetisation.setHamiltonian(ham, nre);
+    break;
+  }
+  case MagneticMoment: {
+    auto &moment = dynamic_cast<CrystalFieldMoment &>(spectrum);
+    moment.setHamiltonian(ham, nre);
+    break;
+  }
+  default:
+    auto fwhmVariation = getAttribute("FWHMVariation").asDouble();
+    FunctionValues values;
+    calcExcitations(nre, en, wf, temperature, values, iSpec);
+    auto &composite = dynamic_cast<API::CompositeFunction &>(spectrum);
+    m_nPeaks[iSpec] = CrystalFieldUtils::updateSpectrumFunction(
+        composite, values, m_nPeaks[iSpec], 1, m_fwhmX[iSpec], m_fwhmY[iSpec],
+        fwhmVariation);
+  }
 }
 
 } // namespace Functions
diff --git a/Framework/CurveFitting/src/Functions/CrystalFieldPeakUtils.cpp b/Framework/CurveFitting/src/Functions/CrystalFieldPeakUtils.cpp
index c251fd8c87b9dd81668d00bfee9fdcc2dab88ab2..0831b47dff7622d6290b92f0477fe80761fae177 100644
--- a/Framework/CurveFitting/src/Functions/CrystalFieldPeakUtils.cpp
+++ b/Framework/CurveFitting/src/Functions/CrystalFieldPeakUtils.cpp
@@ -1,9 +1,10 @@
 #include "MantidCurveFitting/Functions/CrystalFieldPeakUtils.h"
 
 #include "MantidAPI/CompositeFunction.h"
-#include "MantidAPI/IPeakFunction.h"
 #include "MantidAPI/FunctionFactory.h"
+#include "MantidAPI/IPeakFunction.h"
 #include "MantidCurveFitting/Constraints/BoundaryConstraint.h"
+#include "MantidKernel/make_unique.h"
 
 #include <algorithm>
 #include <math.h>
@@ -61,9 +62,9 @@ void setWidthConstraint(API::IPeakFunction &peak, double fwhm,
       return;
     }
     peak.removeConstraint("FWHM");
-    auto constraint = new Constraints::BoundaryConstraint(
+    auto constraint = Kernel::make_unique<Constraints::BoundaryConstraint>(
         &peak, "FWHM", lowerBound, upperBound);
-    peak.addConstraint(constraint);
+    peak.addConstraint(std::move(constraint));
   } else if (peak.name() == "Gaussian") {
     if (fix) {
       peak.fixParameter("Sigma");
@@ -73,9 +74,9 @@ void setWidthConstraint(API::IPeakFunction &peak, double fwhm,
     lowerBound /= WIDTH_TO_SIGMA;
     upperBound /= WIDTH_TO_SIGMA;
     peak.removeConstraint("Sigma");
-    auto constraint = new Constraints::BoundaryConstraint(
+    auto constraint = Kernel::make_unique<Constraints::BoundaryConstraint>(
         &peak, "Sigma", lowerBound, upperBound);
-    peak.addConstraint(constraint);
+    peak.addConstraint(std::move(constraint));
   } else {
     throw std::runtime_error("Cannot set constraint on width of " +
                              peak.name());
@@ -110,13 +111,16 @@ inline void ignorePeak(API::IPeakFunction &peak, double fwhm) {
 /// @param fwhmVariation :: A variation in the peak width allowed in a fit.
 /// @param defaultFWHM :: A default value for the FWHM to use if xVec and yVec
 ///        are empty.
+/// @param nRequiredPeaks :: A number of peaks required to be created.
+/// @param fixAllPeaks :: If true fix all peak parameters
 /// @return :: The number of peaks that will be actually fitted.
 size_t buildSpectrumFunction(API::CompositeFunction &spectrum,
                              const std::string &peakShape,
                              const API::FunctionValues &centresAndIntensities,
                              const std::vector<double> &xVec,
                              const std::vector<double> &yVec,
-                             double fwhmVariation, double defaultFWHM) {
+                             double fwhmVariation, double defaultFWHM,
+                             size_t nRequiredPeaks, bool fixAllPeaks) {
   if (xVec.size() != yVec.size()) {
     throw std::runtime_error("WidthX and WidthY must have the same size.");
   }
@@ -124,6 +128,9 @@ size_t buildSpectrumFunction(API::CompositeFunction &spectrum,
   bool useDefaultFWHM = xVec.empty();
   auto nPeaks = calculateNPeaks(centresAndIntensities);
   auto maxNPeaks = calculateMaxNPeaks(nPeaks);
+  if (nRequiredPeaks > maxNPeaks) {
+    maxNPeaks = nRequiredPeaks;
+  }
   for (size_t i = 0; i < maxNPeaks; ++i) {
     auto fun = API::FunctionFactory::Instance().createFunction(peakShape);
     auto peak = boost::dynamic_pointer_cast<API::IPeakFunction>(fun);
@@ -132,8 +139,6 @@ size_t buildSpectrumFunction(API::CompositeFunction &spectrum,
     }
     if (i < nPeaks) {
       auto centre = centresAndIntensities.getCalculated(i);
-      peak->fixCentre();
-      peak->fixIntensity();
       peak->setCentre(centre);
       peak->setIntensity(centresAndIntensities.getCalculated(i + nPeaks));
       if (useDefaultFWHM) {
@@ -147,9 +152,14 @@ size_t buildSpectrumFunction(API::CompositeFunction &spectrum,
           ignorePeak(*peak, defaultFWHM);
         }
       }
+      peak->fixCentre();
+      peak->fixIntensity();
     } else {
       ignorePeak(*peak, defaultFWHM);
     }
+    if (fixAllPeaks) {
+      peak->fixAll();
+    }
     spectrum.addFunction(peak);
   }
   return nPeaks;
@@ -177,7 +187,7 @@ size_t updateSpectrumFunction(API::CompositeFunction &spectrum,
                               const std::vector<double> &yVec,
                               double fwhmVariation) {
   size_t nGoodPeaks = calculateNPeaks(centresAndIntensities);
-  size_t maxNPeaks = spectrum.nFunctions() - iFirst;
+  size_t maxNPeaks = calculateMaxNPeaks(nGoodPeaks);
   bool mustUpdateWidth = !xVec.empty();
 
   for (size_t i = 0; i < maxNPeaks; ++i) {
@@ -197,6 +207,8 @@ size_t updateSpectrumFunction(API::CompositeFunction &spectrum,
           setWidthConstraint(peak, expectedFwhm, fwhmVariation);
         }
       }
+      peak.unfixIntensity();
+      peak.fixIntensity();
     } else {
       peak.setHeight(0.0);
       if (i > nOriginalPeaks) {
diff --git a/Framework/CurveFitting/src/Functions/CrystalFieldPeaks.cpp b/Framework/CurveFitting/src/Functions/CrystalFieldPeaks.cpp
index 48509909c7ff67b5e013aad7d4a234d7b1ebd6bb..966ee0f36eb6eae9b840ca71df251190f39deb2c 100644
--- a/Framework/CurveFitting/src/Functions/CrystalFieldPeaks.cpp
+++ b/Framework/CurveFitting/src/Functions/CrystalFieldPeaks.cpp
@@ -13,7 +13,7 @@ DECLARE_FUNCTION(CrystalFieldPeaks)
 
 /// Constructor
 CrystalFieldPeaks::CrystalFieldPeaks()
-    : CrystalFieldPeaksBase(), m_defaultDomainSize(0) {
+    : CrystalFieldPeaksBase(), API::IFunctionGeneral(), m_defaultDomainSize(0) {
 
   declareAttribute("Temperature", Attribute(1.0));
   declareParameter("IntensityScaling", 1.0,
diff --git a/Framework/CurveFitting/src/Functions/CrystalFieldPeaksBase.cpp b/Framework/CurveFitting/src/Functions/CrystalFieldPeaksBase.cpp
index 26dfbddec3998cda7a8a44cf7813093d1e7de243..f044d747fed62571991bbb9c01e67080854c28ae 100644
--- a/Framework/CurveFitting/src/Functions/CrystalFieldPeaksBase.cpp
+++ b/Framework/CurveFitting/src/Functions/CrystalFieldPeaksBase.cpp
@@ -269,7 +269,7 @@ const std::map<std::string, std::function<void(API::IFunction &)>> SYMMETRY_MAP{
 
 /// Constructor
 CrystalFieldPeaksBase::CrystalFieldPeaksBase()
-    : API::IFunctionGeneral(), API::ParamFunction(), m_defaultDomainSize(0) {
+    : API::ParamFunction(), m_defaultDomainSize(0) {
 
   declareAttribute("Ion", Attribute("Ce"));
   declareAttribute("Symmetry", Attribute("Ci"));
@@ -320,9 +320,13 @@ CrystalFieldPeaksBase::CrystalFieldPeaksBase()
 /// Calculate the crystal field eigensystem
 /// @param en :: Output eigenvalues.
 /// @param wf :: Output eigenvectors.
+/// @param ham :: Output crystal field hamiltonian (without external field)
+/// @param hz :: Output Zeeman hamiltonian (external field term)
 /// @param nre :: Output ion code.
 void CrystalFieldPeaksBase::calculateEigenSystem(DoubleFortranVector &en,
                                                  ComplexFortranMatrix &wf,
+                                                 ComplexFortranMatrix &ham,
+                                                 ComplexFortranMatrix &hz,
                                                  int &nre) const {
 
   auto ion = getAttribute("Ion").asString();
@@ -342,6 +346,9 @@ void CrystalFieldPeaksBase::calculateEigenSystem(DoubleFortranVector &en,
   bmol(2) = getParameter("BmolY");
   bmol(3) = getParameter("BmolZ");
 
+  // For CrystalFieldSusceptibility and CrystalFieldMagnetisation we need
+  //   to be able to override the external field set here, since in these
+  //   measurements, a different external field is applied.
   DoubleFortranVector bext(1, 3);
   bext(1) = getParameter("BextX");
   bext(2) = getParameter("BextY");
@@ -393,8 +400,7 @@ void CrystalFieldPeaksBase::calculateEigenSystem(DoubleFortranVector &en,
   bkq(6, 5) = ComplexType(B65, IB65);
   bkq(6, 6) = ComplexType(B66, IB66);
 
-  ComplexFortranMatrix ham;
-  calculateEigensystem(en, wf, ham, nre, bmol, bext, bkq);
+  calculateEigensystem(en, wf, ham, hz, nre, bmol, bext, bkq);
   // MaxPeakCount is a read-only "mutable" attribute.
   const_cast<CrystalFieldPeaksBase *>(this)
       ->setAttributeValue("MaxPeakCount", static_cast<int>(en.size()));
diff --git a/Framework/CurveFitting/src/Functions/CrystalFieldSpectrum.cpp b/Framework/CurveFitting/src/Functions/CrystalFieldSpectrum.cpp
index ca81f18c4bb3bb47e6ed5b41fc1e2ad257f807c0..8c60bd38a19644861b01f5723b28eda4576461d4 100644
--- a/Framework/CurveFitting/src/Functions/CrystalFieldSpectrum.cpp
+++ b/Framework/CurveFitting/src/Functions/CrystalFieldSpectrum.cpp
@@ -8,6 +8,7 @@
 #include "MantidAPI/FunctionFactory.h"
 #include "MantidAPI/ParameterTie.h"
 #include "MantidCurveFitting/Constraints/BoundaryConstraint.h"
+#include "MantidKernel/Strings.h"
 
 #include <algorithm>
 #include <iostream>
@@ -17,9 +18,7 @@ namespace CurveFitting {
 namespace Functions {
 
 using namespace CurveFitting;
-
 using namespace Kernel;
-
 using namespace API;
 
 DECLARE_FUNCTION(CrystalFieldSpectrum)
@@ -33,6 +32,8 @@ CrystalFieldSpectrum::CrystalFieldSpectrum()
   declareAttribute("FWHMX", Attribute(vec));
   declareAttribute("FWHMY", Attribute(vec));
   declareAttribute("FWHMVariation", Attribute(0.1));
+  declareAttribute("NPeaks", Attribute(0));
+  declareAttribute("FixAllPeaks", Attribute(false));
 }
 
 /// Uses m_crystalField to calculate peak centres and intensities
@@ -41,6 +42,7 @@ void CrystalFieldSpectrum::buildTargetFunction() const {
   m_dirty = false;
   auto spectrum = new CompositeFunction;
   m_target.reset(spectrum);
+  m_target->setAttribute("NumDeriv", this->getAttribute("NumDeriv"));
 
   FunctionDomainGeneral domain;
   FunctionValues values;
@@ -55,14 +57,18 @@ void CrystalFieldSpectrum::buildTargetFunction() const {
         "CrystalFieldPeaks returned odd number of values.");
   }
 
-  auto xVec = IFunction::getAttribute("FWHMX").asVector();
-  auto yVec = IFunction::getAttribute("FWHMY").asVector();
+  auto xVec = getAttribute("FWHMX").asVector();
+  auto yVec = getAttribute("FWHMY").asVector();
   auto fwhmVariation = getAttribute("FWHMVariation").asDouble();
 
-  auto peakShape = IFunction::getAttribute("PeakShape").asString();
-  auto defaultFWHM = IFunction::getAttribute("FWHM").asDouble();
+  auto peakShape = getAttribute("PeakShape").asString();
+  auto defaultFWHM = getAttribute("FWHM").asDouble();
+  size_t nRequiredPeaks = getAttribute("NPeaks").asInt();
+  bool fixAllPeaks = getAttribute("FixAllPeaks").asBool();
   m_nPeaks = CrystalFieldUtils::buildSpectrumFunction(
-      *spectrum, peakShape, values, xVec, yVec, fwhmVariation, defaultFWHM);
+      *spectrum, peakShape, values, xVec, yVec, fwhmVariation, defaultFWHM,
+      nRequiredPeaks, fixAllPeaks);
+  storeReadOnlyAttribute("NPeaks", Attribute(static_cast<int>(m_nPeaks)));
 }
 
 /// Update m_spectrum function.
@@ -72,15 +78,108 @@ void CrystalFieldSpectrum::updateTargetFunction() const {
     return;
   }
   m_dirty = false;
-  auto xVec = IFunction::getAttribute("FWHMX").asVector();
-  auto yVec = IFunction::getAttribute("FWHMY").asVector();
+  auto xVec = getAttribute("FWHMX").asVector();
+  auto yVec = getAttribute("FWHMY").asVector();
   auto fwhmVariation = getAttribute("FWHMVariation").asDouble();
   FunctionDomainGeneral domain;
   FunctionValues values;
   m_source->function(domain, values);
+  m_target->setAttribute("NumDeriv", this->getAttribute("NumDeriv"));
   auto &spectrum = dynamic_cast<CompositeFunction &>(*m_target);
-  m_nPeaks = CrystalFieldUtils::updateSpectrumFunction(
-      spectrum, values, m_nPeaks, 0, xVec, yVec, fwhmVariation);
+  m_nPeaks = CrystalFieldUtils::calculateNPeaks(values);
+  auto maxNPeaks = CrystalFieldUtils::calculateMaxNPeaks(m_nPeaks);
+  if (maxNPeaks > spectrum.nFunctions()) {
+    buildTargetFunction();
+  } else {
+    CrystalFieldUtils::updateSpectrumFunction(spectrum, values, m_nPeaks, 0,
+                                              xVec, yVec, fwhmVariation);
+  }
+  storeReadOnlyAttribute("NPeaks", Attribute(static_cast<int>(m_nPeaks)));
+}
+
+/// Custom string conversion method
+std::string CrystalFieldSpectrum::asString() const {
+  std::ostringstream ostr;
+  ostr << "name=" << this->name();
+  // Print the attributes
+  std::vector<std::string> attr = this->getAttributeNames();
+  for (const auto &attName : attr) {
+    std::string attValue = this->getAttribute(attName).value();
+    if (!attValue.empty() && attValue != "\"\"" && attValue != "()") {
+      ostr << ',' << attName << '=' << attValue;
+    }
+  }
+  // Print own parameters
+  for (size_t i = 0; i < m_nOwnParams; i++) {
+    const ParameterTie *tie = getTie(i);
+    if (!tie || !tie->isDefault()) {
+      ostr << ',' << parameterName(i) << '=' << getParameter(i);
+    }
+  }
+
+  // collect non-default constraints
+  std::vector<std::string> constraints;
+  for (size_t i = 0; i < m_nOwnParams; i++) {
+    auto constraint = writeConstraint(i);
+    if (!constraint.empty()) {
+      constraints.push_back(constraint);
+    }
+  }
+
+  // collect the non-default ties
+  std::vector<std::string> ties;
+  for (size_t i = 0; i < m_nOwnParams; i++) {
+    auto tie = writeTie(i);
+    if (!tie.empty()) {
+      ties.push_back(tie);
+    }
+  }
+
+  // Print parameters of the important peaks only
+  const CompositeFunction &spectrum =
+      dynamic_cast<const CompositeFunction &>(*m_target);
+  for (size_t ip = 0; ip < m_nPeaks; ++ip) {
+    const auto &peak = dynamic_cast<IPeakFunction &>(*spectrum.getFunction(ip));
+    // Print peak's atributes
+    auto attr = peak.getAttributeNames();
+    for (const auto &attName : attr) {
+      std::string attValue = peak.getAttribute(attName).value();
+      if (!attValue.empty() && attValue != "\"\"") {
+        ostr << ",f" << ip << "." << attName << '=' << attValue;
+      }
+    }
+    // Print peak's parameters
+    for (size_t i = 0; i < peak.nParams(); i++) {
+      const ParameterTie *tie = peak.getTie(i);
+      if (!tie || !tie->isDefault()) {
+        ostr << ",f" << ip << "." << peak.parameterName(i) << '='
+             << peak.getParameter(i);
+      }
+      auto constraint = writeConstraint(i);
+      if (!constraint.empty()) {
+        constraints.push_back(constraint);
+      }
+      auto tieStr = writeTie(i);
+      if (!tieStr.empty()) {
+        ties.push_back(tieStr);
+      }
+    }
+  } // for peaks
+
+  // print constraints
+  if (!constraints.empty()) {
+    ostr << ",constraints=("
+         << Kernel::Strings::join(constraints.begin(), constraints.end(), ",")
+         << ")";
+  }
+
+  // print the ties
+  if (!ties.empty()) {
+    ostr << ",ties=(" << Kernel::Strings::join(ties.begin(), ties.end(), ",")
+         << ")";
+  }
+
+  return ostr.str();
 }
 
 } // namespace Functions
diff --git a/Framework/CurveFitting/src/Functions/CrystalFieldSusceptibility.cpp b/Framework/CurveFitting/src/Functions/CrystalFieldSusceptibility.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..50a2582014cfa40331986eac459938325004f5ef
--- /dev/null
+++ b/Framework/CurveFitting/src/Functions/CrystalFieldSusceptibility.cpp
@@ -0,0 +1,189 @@
+#include "MantidCurveFitting/Functions/CrystalFieldSusceptibility.h"
+#include "MantidCurveFitting/Functions/CrystalFieldPeaksBase.h"
+#include "MantidCurveFitting/Functions/CrystalElectricField.h"
+#include "MantidCurveFitting/FortranDefs.h"
+#include "MantidAPI/FunctionFactory.h"
+#include "MantidAPI/FunctionValues.h"
+#include "MantidAPI/FunctionDomain.h"
+#include "MantidAPI/FunctionDomain1D.h"
+#include "MantidAPI/IFunction1D.h"
+#include "MantidAPI/Jacobian.h"
+#include "MantidKernel/Exception.h"
+#include "MantidKernel/PhysicalConstants.h"
+#include <cmath>
+#include <boost/algorithm/string/predicate.hpp>
+
+namespace Mantid {
+namespace CurveFitting {
+namespace Functions {
+
+namespace {
+
+// Get a complex conjugate of the value returned by
+// ComplexMatrix::operator(i,j)
+ComplexType conj(const ComplexMatrixValueConverter &conv) {
+  return std::conj(static_cast<ComplexType>(conv));
+}
+
+// Does the actual calculation of the susceptibility
+void calculate(double *out, const double *xValues, const size_t nData,
+               const DoubleFortranVector &en, const ComplexFortranMatrix &wf,
+               const int nre, const std::vector<double> &H,
+               const double convfact) {
+  // Some constants
+  const double k_B = PhysicalConstants::BoltzmannConstant; // in meV/K
+  const double eps = 1.e-6; // for degeneracy calculations
+  // First calculates the matrix elements of the magnetic moment operator
+  ComplexFortranMatrix mumat;
+  calculateMagneticMomentMatrix(wf, H, nre, mumat);
+  int nlevels = en.len();
+  DoubleFortranVector mu(nlevels);
+  DoubleFortranVector mu2(nlevels);
+  mu.zero();
+  mu2.zero();
+  for (auto i = 1; i <= nlevels; i++) {
+    for (auto j = 1; j <= nlevels; j++) {
+      const double den = en(i) - en(j);
+      if (fabs(den) < eps) { // First order term
+        mu(i) += real(mumat(i, j) * conj(mumat(i, j)));
+      } else { // Second order term
+        mu2(i) += real(mumat(i, j) * conj(mumat(i, j))) / den;
+      }
+    }
+  }
+  // Now calculates the temperature dependence.
+  mu *= convfact;
+  mu2 *= convfact;
+  for (size_t iT = 0; iT < nData; iT++) {
+    double expfact;
+    double Z = 0.;
+    double U = 0.;
+    const double beta = 1 / (k_B * xValues[iT]);
+    for (auto i = 1; i <= nlevels; i++) {
+      expfact = exp(-beta * en(i));
+      Z += expfact;
+      U += ((mu(i) * beta) - (2 * mu2(i))) * expfact;
+    }
+    out[iT] = U / Z;
+  }
+}
+
+// Calculate powder average - Mpowder = (Mx + My + Mz)/3
+void calculate_powder(double *out, const double *xValues, const size_t nData,
+                      const DoubleFortranVector &en,
+                      const ComplexFortranMatrix &wf, const int nre,
+                      const double convfact) {
+  for (size_t j = 0; j < nData; j++) {
+    out[j] = 0.;
+  }
+  // Loop over the x, y, z directions
+  std::vector<double> H;
+  std::vector<double> tmp(nData, 0.);
+  for (int i = 0; i < 3; i++) {
+    H.assign(3, 0.);
+    H[i] = 1.;
+    calculate(&tmp[0], xValues, nData, en, wf, nre, H, convfact);
+    for (size_t j = 0; j < nData; j++) {
+      out[j] += tmp[j];
+    }
+  }
+  for (size_t j = 0; j < nData; j++) {
+    out[j] /= 3.;
+  }
+}
+}
+
+DECLARE_FUNCTION(CrystalFieldSusceptibility)
+
+CrystalFieldSusceptibility::CrystalFieldSusceptibility()
+    : CrystalFieldPeaksBase(), API::IFunction1D(), m_setDirect(false) {
+  declareAttribute("Hdir", Attribute(std::vector<double>{0., 0., 1.}));
+  declareAttribute("Unit", Attribute("cgs"));
+  declareAttribute("inverse", Attribute(false));
+  declareAttribute("powder", Attribute(false));
+  declareAttribute("ScaleFactor", Attribute(1.0)); // Only for multi-site use
+  declareParameter("Lambda", 0.0, "Effective exchange interaction");
+}
+
+// Sets the eigenvectors / values directly
+void CrystalFieldSusceptibility::setEigensystem(const DoubleFortranVector &en,
+                                                const ComplexFortranMatrix &wf,
+                                                const int nre) {
+  m_setDirect = true;
+  m_en = en;
+  m_wf = wf;
+  m_nre = nre;
+}
+
+void CrystalFieldSusceptibility::function1D(double *out, const double *xValues,
+                                            const size_t nData) const {
+  auto H = getAttribute("Hdir").asVector();
+  if (H.size() != 3) {
+    throw std::invalid_argument("Hdir must be a three-element vector.");
+  }
+  auto powder = getAttribute("powder").asBool();
+  double Hnorm = sqrt(H[0] * H[0] + H[1] * H[1] + H[2] * H[2]);
+  if (fabs(Hnorm) > 1.e-6) {
+    for (auto i = 0; i < 3; i++) {
+      H[i] /= Hnorm;
+    }
+  }
+  // Get the unit conversion factor.
+  auto unit = getAttribute("Unit").asString();
+  const double NAMUB2cgs = 0.03232776; // N_A * muB(erg/G) * muB(meV/G)
+  // The constant above is in strange units because we need the output
+  // to be in erg/G^2/mol==cm^3/mol, but in the calculation all energies
+  // are in meV and the expression for chi has a energy denominator.
+  const double NAMUB2si = 4.062426e-7; // N_A * muB(J/T) * muB(meV/T) * mu0
+  // Again, for SI units, we need to have one of the muB in meV not J.
+  // The additional factor of mu0 is due to the different definitions of
+  // the magnetisation, B- and H-fields in the SI and cgs systems.
+  double convfact = boost::iequals(unit, "bohr")
+                        ? 0.057883818
+                        : (boost::iequals(unit, "SI") ? NAMUB2si : NAMUB2cgs);
+  // Note the constant for "bohr" is the bohr magneton in meV/T, this will
+  // give the susceptibility in "atomic" units of uB/T/ion.
+  // Note that chi_SI = (4pi*10^-6)chi_cgs
+  // Default unit is cgs (cm^3/mol).
+  if (!m_setDirect) {
+    // Because this method is const, we can't change the stored en / wf
+    // Use temporary variables instead.
+    DoubleFortranVector en;
+    ComplexFortranMatrix wf;
+    int nre = 0;
+    calculateEigenSystem(en, wf, nre);
+    if (powder) {
+      calculate_powder(out, xValues, nData, en, wf, nre, convfact);
+    } else {
+      calculate(out, xValues, nData, en, wf, nre, H, convfact);
+    }
+  } else {
+    // Use stored values
+    if (powder) {
+      calculate_powder(out, xValues, nData, m_en, m_wf, m_nre, convfact);
+    } else {
+      calculate(out, xValues, nData, m_en, m_wf, m_nre, H, convfact);
+    }
+  }
+  if (getAttribute("inverse").asBool()) {
+    for (size_t i = 0; i < nData; i++) {
+      out[i] = 1. / out[i];
+    }
+  }
+  auto fact = getAttribute("ScaleFactor").asDouble();
+  if (fact != 1.0) {
+    for (size_t i = 0; i < nData; i++) {
+      out[i] *= fact;
+    }
+  }
+  const double lambda = getParameter("Lambda");
+  if (fabs(lambda) > 1.e-6) {
+    for (size_t i = 0; i < nData; i++) {
+      out[i] /= (1. - lambda * out[i]); // chi = chi0/(1 - lambda.chi0)
+    }
+  }
+}
+
+} // namespace Functions
+} // namespace CurveFitting
+} // namespace Mantid
diff --git a/Framework/CurveFitting/src/Functions/DeltaFunction.cpp b/Framework/CurveFitting/src/Functions/DeltaFunction.cpp
index baab6b8cd5aa9b8978e41bdf41bf156fdda3a685..3640a821ff0c52f38d33fea71c0dd55fe4b80198 100644
--- a/Framework/CurveFitting/src/Functions/DeltaFunction.cpp
+++ b/Framework/CurveFitting/src/Functions/DeltaFunction.cpp
@@ -17,7 +17,7 @@ using namespace API;
 
 DECLARE_FUNCTION(DeltaFunction)
 
-DeltaFunction::DeltaFunction() {
+DeltaFunction::DeltaFunction() : IPeakFunction() {
   declareParameter("Height", 1.0,
                    "Scaling factor to be applied to the resolution.");
   declareParameter("Centre", 0.0,
diff --git a/Framework/CurveFitting/src/Functions/DynamicKuboToyabe.cpp b/Framework/CurveFitting/src/Functions/DynamicKuboToyabe.cpp
index 514424fc0f21c449a68658dc3afd1d0c201f3918..14e55390b02533f6bc422f1eb8aea58da8ef61cb 100644
--- a/Framework/CurveFitting/src/Functions/DynamicKuboToyabe.cpp
+++ b/Framework/CurveFitting/src/Functions/DynamicKuboToyabe.cpp
@@ -1,11 +1,11 @@
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidCurveFitting/Functions/DynamicKuboToyabe.h"
 #include "MantidAPI/Jacobian.h"
 #include "MantidAPI/FunctionFactory.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidKernel/PhysicalConstants.h"
+
+#include <iomanip>
+#include <sstream>
 #include <vector>
 
 namespace Mantid {
diff --git a/Framework/CurveFitting/src/Functions/ElasticDiffRotDiscreteCircle.cpp b/Framework/CurveFitting/src/Functions/ElasticDiffRotDiscreteCircle.cpp
index 227711029bae7d9f78fc1ec34fea220f8396679b..b7253b234e9559ae9aa5c938306de6d28a698ed5 100644
--- a/Framework/CurveFitting/src/Functions/ElasticDiffRotDiscreteCircle.cpp
+++ b/Framework/CurveFitting/src/Functions/ElasticDiffRotDiscreteCircle.cpp
@@ -6,6 +6,7 @@
 // Mantid headers from other projects
 #include "MantidAPI/FunctionFactory.h"
 #include "MantidAPI/IFunction.h"
+#include "MantidKernel/make_unique.h"
 // 3rd party library headers (N/A)
 // standard library headers
 #include <cmath>
@@ -39,13 +40,13 @@ ElasticDiffRotDiscreteCircle::ElasticDiffRotDiscreteCircle() {
  */
 void ElasticDiffRotDiscreteCircle::init() {
   // Ensure positive values for Height and Radius
-  auto HeightConstraint = new BConstraint(
+  auto HeightConstraint = Kernel::make_unique<BConstraint>(
       this, "Height", std::numeric_limits<double>::epsilon(), true);
-  this->addConstraint(HeightConstraint);
+  this->addConstraint(std::move(HeightConstraint));
 
-  auto RadiusConstraint = new BConstraint(
+  auto RadiusConstraint = Kernel::make_unique<BConstraint>(
       this, "Radius", std::numeric_limits<double>::epsilon(), true);
-  this->addConstraint(RadiusConstraint);
+  this->addConstraint(std::move(RadiusConstraint));
 }
 
 /**
diff --git a/Framework/CurveFitting/src/Functions/ElasticDiffSphere.cpp b/Framework/CurveFitting/src/Functions/ElasticDiffSphere.cpp
index 1e9f984430ee6bcccc6c51b4406f0d47f633f579..7443422d7ddcd9e38c3ff56941a10e5fcff7913f 100644
--- a/Framework/CurveFitting/src/Functions/ElasticDiffSphere.cpp
+++ b/Framework/CurveFitting/src/Functions/ElasticDiffSphere.cpp
@@ -6,6 +6,7 @@
 // Mantid headers from other projects
 #include "MantidAPI/FunctionFactory.h"
 #include "MantidAPI/IFunction.h"
+#include "MantidKernel/make_unique.h"
 // third party library headers
 #include <boost/math/special_functions/bessel.hpp>
 // standard library headers
@@ -39,13 +40,13 @@ ElasticDiffSphere::ElasticDiffSphere() {
  */
 void ElasticDiffSphere::init() {
   // Ensure positive values for Height and Radius
-  auto HeightConstraint = new BConstraint(
+  auto HeightConstraint = Kernel::make_unique<BConstraint>(
       this, "Height", std::numeric_limits<double>::epsilon(), true);
-  this->addConstraint(HeightConstraint);
+  this->addConstraint(std::move(HeightConstraint));
 
-  auto RadiusConstraint = new BConstraint(
+  auto RadiusConstraint = Kernel::make_unique<BConstraint>(
       this, "Radius", std::numeric_limits<double>::epsilon(), true);
-  this->addConstraint(RadiusConstraint);
+  this->addConstraint(std::move(RadiusConstraint));
 }
 
 /**
diff --git a/Framework/CurveFitting/src/Functions/ElasticIsoRotDiff.cpp b/Framework/CurveFitting/src/Functions/ElasticIsoRotDiff.cpp
index 78cbc5eccc06d50e6fab78ecd4e5061635fa9ec3..1aa64ba8b1ab8c649899234f077a070dc073f37a 100644
--- a/Framework/CurveFitting/src/Functions/ElasticIsoRotDiff.cpp
+++ b/Framework/CurveFitting/src/Functions/ElasticIsoRotDiff.cpp
@@ -6,6 +6,7 @@
 // Mantid headers from other projects
 #include "MantidAPI/FunctionFactory.h"
 #include "MantidAPI/IFunction.h"
+#include "MantidKernel/make_unique.h"
 // third party library headers
 #include <boost/math/special_functions/bessel.hpp>
 // standard library headers
@@ -39,13 +40,13 @@ ElasticIsoRotDiff::ElasticIsoRotDiff() {
  */
 void ElasticIsoRotDiff::init() {
   // Ensure positive values for Height and Radius
-  auto HeightConstraint = new BConstraint(
+  auto HeightConstraint = Kernel::make_unique<BConstraint>(
       this, "Height", std::numeric_limits<double>::epsilon(), true);
-  this->addConstraint(HeightConstraint);
+  this->addConstraint(std::move(HeightConstraint));
 
-  auto RadiusConstraint = new BConstraint(
+  auto RadiusConstraint = Kernel::make_unique<BConstraint>(
       this, "Radius", std::numeric_limits<double>::epsilon(), true);
-  this->addConstraint(RadiusConstraint);
+  this->addConstraint(std::move(RadiusConstraint));
 }
 
 /**
diff --git a/Framework/CurveFitting/src/Functions/FunctionGenerator.cpp b/Framework/CurveFitting/src/Functions/FunctionGenerator.cpp
index 1d47b5ff0f9f0ebb100ad2e653e360649e7fd86e..f8f4458efcac912f39009b8177e3991bec29fca7 100644
--- a/Framework/CurveFitting/src/Functions/FunctionGenerator.cpp
+++ b/Framework/CurveFitting/src/Functions/FunctionGenerator.cpp
@@ -19,6 +19,7 @@ FunctionGenerator::FunctionGenerator(API::IFunction_sptr source)
     throw std::logic_error(
         "FunctionGenerator initialised with null source function.");
   }
+  declareAttribute("NumDeriv", Attribute(false));
 }
 
 void FunctionGenerator::init() {}
@@ -157,23 +158,26 @@ void FunctionGenerator::unfix(size_t i) {
 /// Return parameter index from a parameter reference.
 size_t
 FunctionGenerator::getParameterIndex(const ParameterReference &ref) const {
-  auto index = m_source->getParameterIndex(ref);
-  if (index < m_nOwnParams) {
-    return index;
+  if (ref.getFunction() == this) {
+    auto index = ref.getIndex();
+    auto np = nParams();
+    if (index < np) {
+      return index;
+    }
+    return np;
   }
   checkTargetFunction();
   return m_target->getParameterIndex(ref) + m_nOwnParams;
 }
 
 /// Tie a parameter to other parameters (or a constant)
-API::ParameterTie *FunctionGenerator::tie(const std::string &parName,
-                                          const std::string &expr,
-                                          bool isDefault) {
+void FunctionGenerator::tie(const std::string &parName, const std::string &expr,
+                            bool isDefault) {
   if (isSourceName(parName)) {
-    return m_source->tie(parName, expr, isDefault);
+    m_source->tie(parName, expr, isDefault);
   } else {
     checkTargetFunction();
-    return m_target->tie(parName, expr, isDefault);
+    m_target->tie(parName, expr, isDefault);
   }
 }
 
@@ -215,15 +219,15 @@ ParameterTie *FunctionGenerator::getTie(size_t i) const {
 }
 
 /// Add a constraint to function
-void FunctionGenerator::addConstraint(API::IConstraint *ic) {
+void FunctionGenerator::addConstraint(std::unique_ptr<API::IConstraint> ic) {
   auto i = ic->getIndex();
   if (i < m_nOwnParams) {
     ic->reset(m_source.get(), i);
-    m_source->addConstraint(ic);
+    m_source->addConstraint(std::move(ic));
   } else {
     checkTargetFunction();
     ic->reset(m_target.get(), i - m_nOwnParams);
-    m_target->addConstraint(ic);
+    m_target->addConstraint(std::move(ic));
   }
 }
 
@@ -258,13 +262,15 @@ void FunctionGenerator::declareParameter(const std::string &, double,
 }
 
 /// Add a new tie. Derived classes must provide storage for ties
-void FunctionGenerator::addTie(API::ParameterTie *tie) {
+void FunctionGenerator::addTie(std::unique_ptr<API::ParameterTie> tie) {
   size_t i = getParameterIndex(*tie);
   if (i < m_nOwnParams) {
-    m_source->addTie(tie);
+    m_source->addTie(std::move(tie));
   } else {
     checkTargetFunction();
-    m_target->addTie(tie);
+    tie->reset(m_target.get(), tie->getIndex() - m_nOwnParams,
+               tie->isDefault());
+    m_target->addTie(std::move(tie));
   }
 }
 
@@ -291,9 +297,6 @@ API::IFunction::Attribute
 FunctionGenerator::getAttribute(const std::string &attName) const {
   if (IFunction::hasAttribute(attName)) {
     return IFunction::getAttribute(attName);
-  } else if (attName == "NumDeriv") {
-    checkTargetFunction();
-    return m_target->getAttribute(attName);
   } else if (isSourceName(attName)) {
     return m_source->getAttribute(attName);
   } else {
@@ -309,8 +312,6 @@ void FunctionGenerator::setAttribute(const std::string &attName,
     IFunction::setAttribute(attName, att);
     m_dirty = true;
     m_target.reset();
-  } else if (attName == "NumDeriv") {
-    m_target->setAttribute(attName, att);
   } else if (isSourceName(attName)) {
     m_source->setAttribute(attName, att);
     m_dirty = true;
@@ -322,7 +323,7 @@ void FunctionGenerator::setAttribute(const std::string &attName,
 
 /// Check if attribute attName exists
 bool FunctionGenerator::hasAttribute(const std::string &attName) const {
-  if (attName == "NumDeriv" || IFunction::hasAttribute(attName)) {
+  if (IFunction::hasAttribute(attName)) {
     return true;
   }
   if (isSourceName(attName)) {
diff --git a/Framework/CurveFitting/src/Functions/FunctionQDepends.cpp b/Framework/CurveFitting/src/Functions/FunctionQDepends.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..22490bfb7ed19ccba574e5fa44114baba1a51a16
--- /dev/null
+++ b/Framework/CurveFitting/src/Functions/FunctionQDepends.cpp
@@ -0,0 +1,157 @@
+// Mantid Coding standars <http://www.mantidproject.org/Coding_Standards>
+
+// Main Module Header
+#include "MantidCurveFitting/Functions/FunctionQDepends.h"
+// Mantid Headers from the same project
+// N/A
+// Mantid headers from other projects
+#include "MantidAPI/MatrixWorkspace.h"
+#include "MantidAPI/NumericAxis.h"
+#include "MantidKernel/UnitConversion.h"
+#include "MantidAPI/SpectrumInfo.h"
+// third party libraries
+// N/A
+// standard library
+// N/A
+
+using Attr = Mantid::API::IFunction::Attribute;
+
+namespace {
+Mantid::Kernel::Logger g_log("FunctionQDepends");
+}
+
+namespace Mantid {
+namespace CurveFitting {
+namespace Functions {
+
+/* ===========
+   Public
+   ===========*/
+
+/**
+ * @brief declare commonattributes Q and WorkspaceIndex.
+ * Subclasses containing additional attributes should override this method by
+ * declaring the additional
+ * attributes and then calling the parent (this) method to declare Q and
+ * WorkspaceIndex.
+ */
+void FunctionQDepends::declareAttributes() {
+  this->declareAttribute("Q", Attr(EMPTY_DBL()));
+  this->declareAttribute("WorkspaceIndex", Attr(EMPTY_INT()));
+}
+
+/**
+ * @brief Update attributes WorkspaceIndex and Q according to certain precedence
+ *rules.
+ * Subclasses featuring additional attributes should override and insert a call
+ *to
+ * this method within the overriding setAttribute function.
+ * There are two ways to update Q: (i) loading the value from the spectrum, and
+ *(ii) manual
+ * input from the user. Therefore, rules of precedence must be set to prevent
+ *conflict. The
+ * priority is to accept Q from the spectrum, if a Q value can be derived from
+ *such. In
+ * this case the existing Q value will be overwritten, irrespective of the
+ *mannier in which
+ * the old Q value was set.
+ *
+ * @param attName name of the attribute
+ * @param attValue  value of the attribute
+ */
+void FunctionQDepends::setAttribute(const std::string &attName,
+                                    const Attr &attValue) {
+  // Q value is tied to WorkspaceIndex if we have a list of Q values
+  if (attName == "WorkspaceIndex") {
+    size_t wi{static_cast<size_t>(
+        attValue.asInt())}; // ah!, the "joys" of C++ strong typing.
+    if (!m_vQ.empty() && wi < m_vQ.size()) {
+      Mantid::API::IFunction::setAttribute(attName, attValue);
+      Mantid::API::IFunction::setAttribute("Q", Attribute(m_vQ.at(wi)));
+    }
+  }
+  // Q can be manually changed by user only if list of Q values is empty
+  else if (attName == "Q") {
+    if (m_vQ.empty()) {
+      Mantid::API::IFunction::setAttribute(attName, attValue);
+    }
+  } else {
+    Mantid::API::IFunction::setAttribute(attName, attValue);
+  }
+}
+
+/**
+ * @brief Learn the Q values from the workspace, if possible, and update
+ * attribute Q accordingly.
+ * @param workspace Matrix workspace
+ * @param wi selected spectrum to initialize attributes
+ * @param startX unused
+ * @param endX unused
+ */
+void FunctionQDepends::setMatrixWorkspace(
+    boost::shared_ptr<const Mantid::API::MatrixWorkspace> workspace, size_t wi,
+    double startX, double endX) {
+  UNUSED_ARG(startX);
+  UNUSED_ARG(endX);
+  // reset attributes if new workspace is passed
+  if (!m_vQ.empty()) {
+    Mantid::API::IFunction::setAttribute("WorkspaceIndex", Attr(EMPTY_INT()));
+    Mantid::API::IFunction::setAttribute("Q", Attr(EMPTY_DBL()));
+  }
+  // Obtain Q values from the passed workspace, if possible. m_vQ will be
+  // cleared if unsuccessful.
+  if (workspace) {
+    m_vQ = this->extractQValues(*workspace);
+  }
+  if (!m_vQ.empty()) {
+    this->setAttribute("WorkspaceIndex", Attr(static_cast<int>(wi)));
+  }
+}
+
+/* ===========
+   Private
+   ===========*/
+
+/**
+ * @brief Extract Q values from vertical dimension of the workspace, or compute
+ * them.
+ * @param workspace workspace possibly containing Q values.
+ */
+std::vector<double> FunctionQDepends::extractQValues(
+    const Mantid::API::MatrixWorkspace &workspace) {
+  std::vector<double> qs;
+  // Check if the vertical axis has units of momentum transfer, then extract Q
+  // values...
+  auto axis_ptr =
+      dynamic_cast<Mantid::API::NumericAxis *>(workspace.getAxis(1));
+  if (axis_ptr) {
+    const boost::shared_ptr<Kernel::Unit> &unit_ptr = axis_ptr->unit();
+    if (unit_ptr->unitID() == "MomentumTransfer") {
+      qs = axis_ptr->getValues();
+    }
+  }
+  // ...otherwise, compute the momentum transfer for each spectrum, if possible
+  else {
+    const auto &spectrumInfo = workspace.spectrumInfo();
+    size_t numHist = workspace.getNumberHistograms();
+    for (size_t wi = 0; wi < numHist; wi++) {
+      try {
+        Mantid::Geometry::IDetector_const_sptr detector;
+        detector = workspace.getDetector(wi);
+        double efixed = workspace.getEFixed(detector);
+        double usignTheta = 0.5 * spectrumInfo.twoTheta(wi);
+        double q = Mantid::Kernel::UnitConversion::run(usignTheta, efixed);
+        qs.push_back(q);
+      } catch (Kernel::Exception::NotFoundError &) {
+        g_log.debug("Cannot populate Q values from workspace");
+        qs.clear();
+        break;
+      }
+    }
+  }
+  return qs;
+}
+
+} // namespace Functions
+} // namespace CurveFitting
+} // namespace Mantid
\ No newline at end of file
diff --git a/Framework/CurveFitting/src/Functions/Gaussian.cpp b/Framework/CurveFitting/src/Functions/Gaussian.cpp
index e4e7060c07643b66287d07b7195a617110a51e21..c3308e094e617165874b59e961e65550551b5e0f 100644
--- a/Framework/CurveFitting/src/Functions/Gaussian.cpp
+++ b/Framework/CurveFitting/src/Functions/Gaussian.cpp
@@ -114,7 +114,7 @@ void Gaussian::unfixCentre() { unfixParameter("PeakCentre"); }
 void Gaussian::fixIntensity() {
   std::string formula =
       std::to_string(intensity() / sqrt(2.0 * M_PI)) + "/Sigma";
-  tie("Height", formula);
+  tie("Height", formula, true);
 }
 
 void Gaussian::unfixIntensity() { removeTie("Height"); }
diff --git a/Framework/CurveFitting/src/Functions/IkedaCarpenterPV.cpp b/Framework/CurveFitting/src/Functions/IkedaCarpenterPV.cpp
index ab44b09e234523102e4c725b4139ac73d2fd6fd0..1fce22558c9cb3fe1358d98efa37e464629891b9 100644
--- a/Framework/CurveFitting/src/Functions/IkedaCarpenterPV.cpp
+++ b/Framework/CurveFitting/src/Functions/IkedaCarpenterPV.cpp
@@ -6,6 +6,7 @@
 #include "MantidCurveFitting/SpecialFunctionSupport.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/FunctionFactory.h"
+#include "MantidAPI/PeakFunctionIntegrator.h"
 #include "MantidKernel/UnitFactory.h"
 #include <cmath>
 #include <gsl/gsl_math.h>
@@ -373,6 +374,21 @@ void IkedaCarpenterPV::functionDeriv(const API::FunctionDomain &domain,
   calNumericalDeriv(domain, jacobian);
 }
 
+/// Returns the integral intensity of the peak
+double IkedaCarpenterPV::intensity() const {
+  auto interval = getDomainInterval(1e-2);
+
+  API::PeakFunctionIntegrator integrator;
+  API::IntegrationResult result =
+      integrator.integrate(*this, interval.first, interval.second);
+
+  if (!result.success) {
+    return 0.0;
+  }
+
+  return result.result;
+}
+
 } // namespace Functions
 } // namespace CurveFitting
 } // namespace Mantid
diff --git a/Framework/CurveFitting/src/Functions/InelasticDiffRotDiscreteCircle.cpp b/Framework/CurveFitting/src/Functions/InelasticDiffRotDiscreteCircle.cpp
index c7e6c5c8500935852094e83056e00a126c80b9cc..45bb0978e90478a7767c2f09c385532b4661c4f2 100644
--- a/Framework/CurveFitting/src/Functions/InelasticDiffRotDiscreteCircle.cpp
+++ b/Framework/CurveFitting/src/Functions/InelasticDiffRotDiscreteCircle.cpp
@@ -9,11 +9,13 @@
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidGeometry/IDetector.h"
 #include "MantidKernel/Exception.h"
+#include "MantidKernel/make_unique.h"
 #include "MantidKernel/UnitConversion.h"
 // 3rd party library headers (N/A)
 // standard library headers
 #include <cmath>
 #include <limits>
+#include <sstream>
 
 using BConstraint = Mantid::CurveFitting::Constraints::BoundaryConstraint;
 
@@ -50,17 +52,17 @@ InelasticDiffRotDiscreteCircle::InelasticDiffRotDiscreteCircle()
  */
 void InelasticDiffRotDiscreteCircle::init() {
   // Ensure positive values for Intensity, Radius, and decay
-  auto IntensityConstraint = new BConstraint(
+  auto IntensityConstraint = Kernel::make_unique<BConstraint>(
       this, "Intensity", std::numeric_limits<double>::epsilon(), true);
-  this->addConstraint(IntensityConstraint);
+  this->addConstraint(std::move(IntensityConstraint));
 
-  auto RadiusConstraint = new BConstraint(
+  auto RadiusConstraint = Kernel::make_unique<BConstraint>(
       this, "Radius", std::numeric_limits<double>::epsilon(), true);
-  this->addConstraint(RadiusConstraint);
+  this->addConstraint(std::move(RadiusConstraint));
 
-  auto DecayConstraint = new BConstraint(
+  auto DecayConstraint = Kernel::make_unique<BConstraint>(
       this, "Decay", std::numeric_limits<double>::epsilon(), true);
-  this->addConstraint(DecayConstraint);
+  this->addConstraint(std::move(DecayConstraint));
 }
 
 /**
diff --git a/Framework/CurveFitting/src/Functions/InelasticIsoRotDiff.cpp b/Framework/CurveFitting/src/Functions/InelasticIsoRotDiff.cpp
index 3dbb20ca9b0603c8c9bc25b0aa9ed4e49b0fbda3..e5dbb894d1ac8e7fb6721cc207a3c1560b2429c7 100644
--- a/Framework/CurveFitting/src/Functions/InelasticIsoRotDiff.cpp
+++ b/Framework/CurveFitting/src/Functions/InelasticIsoRotDiff.cpp
@@ -6,6 +6,7 @@
 // Mantid headers from other projects
 #include "MantidAPI/FunctionFactory.h"
 #include "MantidAPI/IFunction.h"
+#include "MantidKernel/make_unique.h"
 // third party library headers
 #include <boost/math/special_functions/bessel.hpp>
 // standard library headers
@@ -44,15 +45,15 @@ InelasticIsoRotDiff::InelasticIsoRotDiff() {
  */
 void InelasticIsoRotDiff::init() {
   // Ensure positive values for Height, Radius, and Diffusion constant
-  auto HeightConstraint = new BConstraint(
+  auto HeightConstraint = Kernel::make_unique<BConstraint>(
       this, "Height", std::numeric_limits<double>::epsilon(), true);
-  this->addConstraint(HeightConstraint);
-  auto RadiusConstraint = new BConstraint(
+  this->addConstraint(std::move(HeightConstraint));
+  auto RadiusConstraint = Kernel::make_unique<BConstraint>(
       this, "Radius", std::numeric_limits<double>::epsilon(), true);
-  this->addConstraint(RadiusConstraint);
-  auto DiffusionConstraint = new BConstraint(
+  this->addConstraint(std::move(RadiusConstraint));
+  auto DiffusionConstraint = Kernel::make_unique<BConstraint>(
       this, "Tau", std::numeric_limits<double>::epsilon(), true);
-  this->addConstraint(DiffusionConstraint);
+  this->addConstraint(std::move(DiffusionConstraint));
 }
 
 /**
diff --git a/Framework/CurveFitting/src/Functions/Lorentzian1D.cpp b/Framework/CurveFitting/src/Functions/Lorentzian1D.cpp
deleted file mode 100644
index 1c19669665cef0be1ff816dc5d58c0074c2a8465..0000000000000000000000000000000000000000
--- a/Framework/CurveFitting/src/Functions/Lorentzian1D.cpp
+++ /dev/null
@@ -1,77 +0,0 @@
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
-#include "MantidCurveFitting/Functions/Lorentzian1D.h"
-#include <gsl/gsl_sf_erf.h>
-#include <gsl/gsl_multifit_nlin.h>
-#include "MantidKernel/BoundedValidator.h"
-
-namespace Mantid {
-namespace CurveFitting {
-namespace Functions {
-
-using namespace CurveFitting;
-using API::Jacobian;
-
-// Register the class into the algorithm factory
-DECLARE_ALGORITHM(Lorentzian1D)
-
-using namespace Kernel;
-
-void Lorentzian1D::declareParameters() {
-  declareProperty("BG0", 0.0, "Constant background value (default 0)",
-                  Direction::InOut);
-  declareProperty("BG1", 0.0,
-                  "Linear background modelling parameter (default 0)",
-                  Direction::InOut);
-  declareProperty("Height", 0.0, "height of peak (not the height may be "
-                                 "refined to a negative value to fit a dipped "
-                                 "curve)",
-                  Direction::InOut);
-  declareProperty("PeakCentre", 0.0, "Centre of peak (default 0)",
-                  Direction::InOut);
-
-  auto positiveDouble = boost::make_shared<BoundedValidator<double>>();
-  positiveDouble->setLower(std::numeric_limits<double>::min());
-
-  declareProperty("HWHM", 1.0, positiveDouble,
-                  "half-width at half-maximum (default 1)", Direction::InOut);
-}
-
-void Lorentzian1D::function(const double *in, double *out,
-                            const double *xValues, const size_t nData) {
-  const double bg0 = in[0];
-  const double bg1 = in[1];
-  const double height = in[2];
-  const double peakCentre = in[3];
-  const double hwhm = in[4];
-
-  for (size_t i = 0; i < nData; i++) {
-    double diff = xValues[i] - peakCentre;
-    out[i] = height * (hwhm * hwhm / (diff * diff + hwhm * hwhm)) + bg0 +
-             bg1 * xValues[i];
-  }
-}
-
-void Lorentzian1D::functionDeriv(const double *in, Jacobian *out,
-                                 const double *xValues, const size_t nData) {
-  const double height = in[2];
-  const double peakCentre = in[3];
-  const double hwhm = in[4];
-
-  for (size_t i = 0; i < nData; i++) {
-    double diff = xValues[i] - peakCentre;
-    double invDenominator = 1 / ((diff * diff + hwhm * hwhm));
-    out->set(i, 0, 1);
-    out->set(i, 1, xValues[i]);
-    out->set(i, 2, hwhm * hwhm * invDenominator);
-    out->set(i, 3, 2.0 * height * diff * hwhm * hwhm * invDenominator *
-                       invDenominator);
-    out->set(i, 4, height * (-hwhm * hwhm * invDenominator + 1) * 2.0 * hwhm *
-                       invDenominator);
-  }
-}
-
-} // namespace Functions
-} // namespace CurveFitting
-} // namespace Mantid
diff --git a/Framework/CurveFitting/src/Functions/PawleyFunction.cpp b/Framework/CurveFitting/src/Functions/PawleyFunction.cpp
index d6aadb2c80f820283eeee25b6d7ccc487cfc90f4..24ff27897047b4fe79acbdd3d4e7370e7bb87c6b 100644
--- a/Framework/CurveFitting/src/Functions/PawleyFunction.cpp
+++ b/Framework/CurveFitting/src/Functions/PawleyFunction.cpp
@@ -6,6 +6,8 @@
 
 #include "MantidCurveFitting/Constraints/BoundaryConstraint.h"
 
+#include "MantidKernel/ConfigService.h"
+#include "MantidKernel/make_unique.h"
 #include "MantidKernel/UnitConversion.h"
 #include "MantidKernel/UnitFactory.h"
 
@@ -283,19 +285,19 @@ void PawleyParameterFunction::createLatticeSystemParameters(
 /// Adds a default constraint so that cell edge lengths can not be less than 0.
 void PawleyParameterFunction::addLengthConstraint(
     const std::string &parameterName) {
-  BoundaryConstraint *cellEdgeConstraint =
-      new BoundaryConstraint(this, parameterName, 0.0, true);
+  auto cellEdgeConstraint =
+      Kernel::make_unique<BoundaryConstraint>(this, parameterName, 0.0, true);
   cellEdgeConstraint->setPenaltyFactor(1e12);
-  addConstraint(cellEdgeConstraint);
+  addConstraint(std::move(cellEdgeConstraint));
 }
 
 /// Adds a default constraint so cell angles are in the range 0 to 180.
 void PawleyParameterFunction::addAngleConstraint(
     const std::string &parameterName) {
-  BoundaryConstraint *cellAngleConstraint =
-      new BoundaryConstraint(this, parameterName, 0.0, 180.0, true);
+  auto cellAngleConstraint = Kernel::make_unique<BoundaryConstraint>(
+      this, parameterName, 0.0, 180.0, true);
   cellAngleConstraint->setPenaltyFactor(1e12);
-  addConstraint(cellAngleConstraint);
+  addConstraint(std::move(cellAngleConstraint));
 }
 
 /// Tries to extract and store the center parameter name from the function.
diff --git a/Framework/CurveFitting/src/Functions/ProcessBackground.cpp b/Framework/CurveFitting/src/Functions/ProcessBackground.cpp
index 26f472a8e3a05dd35019170c62ef278d2b4bcb13..08545d6b91e0bf885ba1dd4cba5f4cd33ab7a69e 100644
--- a/Framework/CurveFitting/src/Functions/ProcessBackground.cpp
+++ b/Framework/CurveFitting/src/Functions/ProcessBackground.cpp
@@ -456,8 +456,7 @@ void ProcessBackground::selectBkgdPoints() {
   // explicitly
   string outbkgdparwsname =
       getPropertyValue("OutputBackgroundParameterWorkspace");
-  if (outbkgdparwsname.size() > 0 &&
-      outbkgdparwsname.compare("_dummy02") != 0) {
+  if (!outbkgdparwsname.empty() && outbkgdparwsname.compare("_dummy02") != 0) {
     // Will fit the selected background
     string bkgdfunctype = getPropertyValue("OutputBackgroundType");
     fitBackgroundFunction(bkgdfunctype);
@@ -692,7 +691,7 @@ ProcessBackground::filterForBackground(BackgroundFunction_sptr bkgdfunction) {
 
   // Optional output
   string userbkgdwsname = getPropertyValue("UserBackgroundWorkspace");
-  if (userbkgdwsname.size() == 0)
+  if (userbkgdwsname.empty())
     throw runtime_error("In mode SelectBackgroundPoints, "
                         "UserBackgroundWorkspace must be given!");
 
diff --git a/Framework/CurveFitting/src/Functions/PseudoVoigt.cpp b/Framework/CurveFitting/src/Functions/PseudoVoigt.cpp
index 2bdc38191001bb7dd8a8c8529e9ee90bc939c09b..6ec9d10d424876de8b5072ce22ca6df35d24daae 100644
--- a/Framework/CurveFitting/src/Functions/PseudoVoigt.cpp
+++ b/Framework/CurveFitting/src/Functions/PseudoVoigt.cpp
@@ -1,6 +1,7 @@
 #include "MantidCurveFitting/Functions/PseudoVoigt.h"
 #include "MantidAPI/FunctionFactory.h"
 #include "MantidCurveFitting/Constraints/BoundaryConstraint.h"
+#include "MantidKernel/make_unique.h"
 
 #include <cmath>
 
@@ -80,11 +81,11 @@ void PseudoVoigt::init() {
   declareParameter("PeakCentre");
   declareParameter("FWHM");
 
-  BoundaryConstraint *mixingConstraint =
-      new BoundaryConstraint(this, "Mixing", 0.0, 1.0, true);
+  auto mixingConstraint =
+      Kernel::make_unique<BoundaryConstraint>(this, "Mixing", 0.0, 1.0, true);
   mixingConstraint->setPenaltyFactor(1e9);
 
-  addConstraint(mixingConstraint);
+  addConstraint(std::move(mixingConstraint));
 }
 
 } // namespace Functions
diff --git a/Framework/CurveFitting/src/Functions/TabulatedFunction.cpp b/Framework/CurveFitting/src/Functions/TabulatedFunction.cpp
index 97f44caeebb6be70ba1b9a501552044fe15e279b..f22656250454621a79ed6d0579f693db267428b1 100644
--- a/Framework/CurveFitting/src/Functions/TabulatedFunction.cpp
+++ b/Framework/CurveFitting/src/Functions/TabulatedFunction.cpp
@@ -258,7 +258,7 @@ void TabulatedFunction::setupData() const {
 
   size_t index = static_cast<size_t>(getAttribute("WorkspaceIndex").asInt());
 
-  g_log.debug() << "Setting up " << m_workspace->name() << " index " << index
+  g_log.debug() << "Setting up " << m_workspace->getName() << " index " << index
                 << '\n';
 
   const auto &xData = m_workspace->points(index);
diff --git a/Framework/CurveFitting/src/Functions/TeixeiraWaterSQE.cpp b/Framework/CurveFitting/src/Functions/TeixeiraWaterSQE.cpp
index e7c313ee21a9541e655cde1d60470b34a8a628bb..892975442cd8664b297fe9fb19ea3d4d27c6456a 100644
--- a/Framework/CurveFitting/src/Functions/TeixeiraWaterSQE.cpp
+++ b/Framework/CurveFitting/src/Functions/TeixeiraWaterSQE.cpp
@@ -2,17 +2,17 @@
 // Main Module Header
 #include "MantidCurveFitting/Functions/TeixeiraWaterSQE.h"
 // Mantid Headers from the same project
-#include "MantidCurveFitting/Constraints/BoundaryConstraint.h"
+// N/A
 // Mantid headers from other projects
 #include "MantidAPI/FunctionFactory.h"
+#include "MantidAPI/Jacobian.h"
 #include "MantidAPI/IFunction.h"
 // third party library headers
+// N/A
 // standard library headers
 #include <cmath>
 #include <limits>
 
-using BConstraint = Mantid::CurveFitting::Constraints::BoundaryConstraint;
-
 namespace {
 Mantid::Kernel::Logger g_log("TeixeiraWaterSQE");
 }
@@ -24,32 +24,14 @@ namespace Functions {
 DECLARE_FUNCTION(TeixeiraWaterSQE)
 
 /**
- * @brief Constructor where parameters and attributes are declared
+ * @brief function parameters and impose constraints
  */
-TeixeiraWaterSQE::TeixeiraWaterSQE() {
+void TeixeiraWaterSQE::declareParameters() {
   this->declareParameter("Height", 1.0, "scaling factor");
   this->declareParameter("DiffCoeff", 2.3,
                          "Diffusion coefficient (10^(-5)cm^2/s)");
   this->declareParameter("Tau", 1.25, "Residence time (ps)");
   this->declareParameter("Centre", 0.0, "Shift along the X-axis");
-  // Momentum transfer Q, an attribute (not a fitting parameter)
-  this->declareAttribute("Q", API::IFunction::Attribute(0.3));
-}
-
-/**
- * @brief Set constraints on fitting parameters
- */
-void TeixeiraWaterSQE::init() {
-  // Ensure positive values for Height, Length, and Tau
-  auto HeightConstraint = new BConstraint(
-      this, "Height", std::numeric_limits<double>::epsilon(), true);
-  this->addConstraint(HeightConstraint);
-  auto DiffCoeffConstraint = new BConstraint(
-      this, "DiffCoeff", std::numeric_limits<double>::epsilon(), true);
-  this->addConstraint(DiffCoeffConstraint);
-  auto TauConstraint = new BConstraint(
-      this, "Tau", std::numeric_limits<double>::epsilon(), true);
-  this->addConstraint(TauConstraint);
 }
 
 /**
@@ -88,6 +70,57 @@ void TeixeiraWaterSQE::function1D(double *out, const double *xValues,
   }
 }
 
+/**
+ * @brief analytical/numerical derivative with respect to fitting parameters
+ * We carry out analytical derivative for parameter Height and numerical
+ * derivatives for parameters
+ * DiffCoeff, Tau, and Centre, selecting sensible steps.
+ */
+void TeixeiraWaterSQE::functionDeriv1D(Mantid::API::Jacobian *jacobian,
+                                       const double *xValues,
+                                       const size_t nData) {
+  const double deltaF{0.1}; // increase parameter by this fraction
+  const size_t nParam = this->nParams();
+  // cutoff defines the smallest change in the parameter when calculating the
+  // numerical derivative
+  std::map<std::string, double> cutoff;
+  cutoff["DiffCoeff"] = 0.2; // 0.2x10^(-5)cm^2/s
+  cutoff["Tau"] = 0.2;       // 0.2ps
+  cutoff["Centre"] = 0.0001; // 0.1micro-eV
+  std::vector<double> out(nData);
+  this->applyTies();
+  this->function1D(out.data(), xValues, nData);
+
+  for (size_t iP = 0; iP < nParam; iP++) {
+    std::vector<double> derivative(nData);
+    if (this->isActive(iP)) {
+      const double pVal = this->activeParameter(iP);
+      const std::string pName = this->parameterName(iP);
+      if (pName == "Height") {
+        // exact derivative
+        this->setActiveParameter(iP, 1.0);
+        this->applyTies();
+        this->function1D(derivative.data(), xValues, nData);
+      } else {
+        // numerical derivative
+        double delta =
+            cutoff[pName] > fabs(pVal * deltaF) ? cutoff[pName] : pVal * deltaF;
+        this->setActiveParameter(iP, pVal + delta);
+        this->applyTies();
+        this->function1D(derivative.data(), xValues, nData);
+        for (size_t i = 0; i < nData; i++) {
+          derivative[i] = (derivative[i] - out[i]) / delta;
+        }
+      }
+      this->setActiveParameter(iP, pVal); // restore the value of the parameter
+      // fill the jacobian for this parameter
+      for (size_t i = 0; i < nData; i++) {
+        jacobian->set(i, iP, derivative[i]);
+      }
+    }
+  }
+}
+
 } // namespace Functions
 } // namespace CurveFitting
 } // namespace Mantid
diff --git a/Framework/CurveFitting/src/Functions/Voigt.cpp b/Framework/CurveFitting/src/Functions/Voigt.cpp
index 3228667bdc3e9c67644d05855aec7d74830b4185..5f2cfb84f84d0aa1ef6e65baaa6ee38d75f992ed 100644
--- a/Framework/CurveFitting/src/Functions/Voigt.cpp
+++ b/Framework/CurveFitting/src/Functions/Voigt.cpp
@@ -6,6 +6,7 @@
 #include "MantidAPI/FunctionFactory.h"
 
 #include <cmath>
+#include <limits>
 
 namespace Mantid {
 namespace CurveFitting {
@@ -132,7 +133,16 @@ double Voigt::centre() const { return getParameter(LORENTZ_POS); }
  * Return the value of the "LorentzAmp" parameter
  * @return value of height of peak
  */
-double Voigt::height() const { return 2.0 * getParameter(LORENTZ_AMP) / 3.0; }
+double Voigt::height() const {
+  if (getParameter(LORENTZ_AMP) == 0.0 || getParameter(LORENTZ_FWHM) == 0.0 ||
+      getParameter(GAUSSIAN_FWHM) == 0.0) {
+    return 0.0;
+  }
+  double pos = getParameter(LORENTZ_POS);
+  double h;
+  functionLocal(&h, &pos, 1);
+  return h;
+}
 
 /**
  * Gives the FWHM of the peak. This is estimated as
@@ -156,7 +166,22 @@ void Voigt::setCentre(const double value) {
  * @param value :: The new value for the centre of the peak
  */
 void Voigt::setHeight(const double value) {
-  this->setParameter(LORENTZ_AMP, 1.5 * value);
+  auto lorentzFwhm = getParameter(LORENTZ_FWHM);
+  if (lorentzFwhm == 0.0) {
+    lorentzFwhm = std::numeric_limits<double>::epsilon();
+    setParameter(LORENTZ_FWHM, lorentzFwhm);
+  }
+  auto lorentzAmp = getParameter(LORENTZ_AMP);
+  if (lorentzAmp == 0.0) {
+    lorentzAmp = std::numeric_limits<double>::epsilon();
+    setParameter(LORENTZ_AMP, lorentzAmp);
+  }
+  auto gaussFwhm = getParameter(GAUSSIAN_FWHM);
+  if (gaussFwhm == 0.0) {
+    setParameter(GAUSSIAN_FWHM, std::numeric_limits<double>::epsilon());
+  }
+  auto h = height();
+  this->setParameter(LORENTZ_AMP, lorentzAmp * value / h);
 }
 
 /**
@@ -164,8 +189,44 @@ void Voigt::setHeight(const double value) {
  * @param value :: The new value for the FWHM of the peak
  */
 void Voigt::setFwhm(const double value) {
-  this->setParameter(LORENTZ_FWHM, 0.5 * value);
-  this->setParameter(GAUSSIAN_FWHM, 0.5 * value);
+  auto lorentzFwhm = getParameter(LORENTZ_FWHM);
+  if (lorentzFwhm == 0.0) {
+    lorentzFwhm = std::numeric_limits<double>::epsilon();
+  }
+  auto gaussFwhm = getParameter(GAUSSIAN_FWHM);
+  if (gaussFwhm == 0.0) {
+    gaussFwhm = std::numeric_limits<double>::epsilon();
+  }
+  auto ratio = lorentzFwhm / (lorentzFwhm + gaussFwhm);
+  this->setParameter(LORENTZ_FWHM, ratio * value);
+  this->setParameter(GAUSSIAN_FWHM, (1.0 - ratio) * value);
+}
+
+/**
+ * Returns the integral intensity of the peak
+ */
+double Voigt::intensity() const {
+  if (getParameter(GAUSSIAN_FWHM) == 0.0) {
+    return 0.0;
+  }
+  return M_PI * getParameter(LORENTZ_AMP) * getParameter(LORENTZ_FWHM) / 2.0;
+}
+
+/**
+ * Sets the integral intensity of the peak
+ * @param value :: The new value for the intensity.
+ */
+void Voigt::setIntensity(const double value) {
+  auto lorentzFWHM = getParameter(LORENTZ_FWHM);
+  if (lorentzFWHM == 0.0) {
+    lorentzFWHM = std::numeric_limits<double>::epsilon();
+    setParameter(LORENTZ_FWHM, lorentzFWHM);
+  }
+  auto gaussFwhm = getParameter(GAUSSIAN_FWHM);
+  if (gaussFwhm == 0.0) {
+    setParameter(GAUSSIAN_FWHM, std::numeric_limits<double>::epsilon());
+  }
+  setParameter(LORENTZ_AMP, 2.0 * value / (M_PI * lorentzFWHM));
 }
 
 } // namespace Functions
diff --git a/Framework/CurveFitting/src/IFittingAlgorithm.cpp b/Framework/CurveFitting/src/IFittingAlgorithm.cpp
index 2d3889bf4655cb848cca6ff2edfa0e9ecb32b139..c228967f6ff1402b4bb75d0fa7d7aedae21eb9ca 100644
--- a/Framework/CurveFitting/src/IFittingAlgorithm.cpp
+++ b/Framework/CurveFitting/src/IFittingAlgorithm.cpp
@@ -1,5 +1,6 @@
 #include "MantidCurveFitting/IFittingAlgorithm.h"
 
+#include "MantidCurveFitting/CostFunctions/CostFuncFitting.h"
 #include "MantidCurveFitting/FitMW.h"
 #include "MantidCurveFitting/GeneralDomainCreator.h"
 #include "MantidCurveFitting/HistogramDomainCreator.h"
@@ -7,6 +8,7 @@
 #include "MantidCurveFitting/MultiDomainCreator.h"
 #include "MantidCurveFitting/SeqDomainSpectrumCreator.h"
 
+#include "MantidAPI/CostFunctionFactory.h"
 #include "MantidAPI/FunctionProperty.h"
 #include "MantidAPI/IFunction1DSpectrum.h"
 #include "MantidAPI/IFunctionGeneral.h"
@@ -91,6 +93,14 @@ void IFittingAlgorithm::init() {
                   "centre of each bin. If it is \"Histogram\" then function is "
                   "integrated within the bin and the integrals returned.",
                   Kernel::Direction::Input);
+  declareProperty("PeakRadius", 0,
+                  "A value of the peak radius the peak functions should use. A "
+                  "peak radius defines an interval on the x axis around the "
+                  "centre of the peak where its values are calculated. Values "
+                  "outside the interval are not calculated and assumed zeros."
+                  "Numerically the radius is a whole number of peak widths "
+                  "(FWHM) that fit into the interval on each side from the "
+                  "centre. The default value of 0 means the whole x axis.");
 
   initConcrete();
 }
@@ -260,6 +270,68 @@ void IFittingAlgorithm::addWorkspaces() {
     m_workspacePropertyNames.clear();
   }
 }
+
+/// Return names of registered cost function for CostFuncFitting
+/// dynamic type.
+std::vector<std::string> IFittingAlgorithm::getCostFunctionNames() const {
+  std::vector<std::string> out;
+  auto &factory = CostFunctionFactory::Instance();
+  auto names = factory.getKeys();
+  out.reserve(names.size());
+  for (auto &name : names) {
+    if (boost::dynamic_pointer_cast<CostFunctions::CostFuncFitting>(
+            factory.create(name))) {
+      out.push_back(name);
+    }
+  }
+  return out;
+}
+
+/// Declare a "CostFunction" property.
+void IFittingAlgorithm::declareCostFunctionProperty() {
+  Kernel::IValidator_sptr costFuncValidator =
+      boost::make_shared<Kernel::ListValidator<std::string>>(
+          getCostFunctionNames());
+  declareProperty(
+      "CostFunction", "Least squares", costFuncValidator,
+      "The cost function to be used for the fit, default is Least squares",
+      Kernel::Direction::InOut);
+}
+
+/// Create a cost function from the "CostFunction" property
+/// and make it ready for evaluation.
+boost::shared_ptr<CostFunctions::CostFuncFitting>
+IFittingAlgorithm::getCostFunctionInitialized() const {
+  // Function may need some preparation.
+  m_function->setUpForFit();
+
+  API::FunctionDomain_sptr domain;
+  API::FunctionValues_sptr values;
+  m_domainCreator->createDomain(domain, values);
+
+  // Set peak radius to the values which will be passed to
+  // all IPeakFunctions
+  int peakRadius = getProperty("PeakRadius");
+  if (auto d1d = dynamic_cast<API::FunctionDomain1D *>(domain.get())) {
+    if (peakRadius != 0) {
+      d1d->setPeakRadius(peakRadius);
+    }
+  }
+
+  // Do something with the function which may depend on workspace.
+  m_domainCreator->initFunction(m_function);
+
+  // get the cost function which must be a CostFuncFitting
+  auto costFunction =
+      boost::dynamic_pointer_cast<CostFunctions::CostFuncFitting>(
+          API::CostFunctionFactory::Instance().create(
+              getPropertyValue("CostFunction")));
+
+  costFunction->setFittingFunction(m_function, domain, values);
+
+  return costFunction;
+}
+
 //----------------------------------------------------------------------------------------------
 /// Execute the algorithm.
 void IFittingAlgorithm::exec() {
diff --git a/Framework/CurveFitting/src/IMWDomainCreator.cpp b/Framework/CurveFitting/src/IMWDomainCreator.cpp
index 8fdae2a503f3ede20f5294bb19d794d54b5e92ab..47b9d64e202db17500efccbc1faa6f71f512f278 100644
--- a/Framework/CurveFitting/src/IMWDomainCreator.cpp
+++ b/Framework/CurveFitting/src/IMWDomainCreator.cpp
@@ -322,7 +322,11 @@ boost::shared_ptr<API::Workspace> IMWDomainCreator::createOutputWorkspace(
   auto &Diff = ws->mutableY(2);
   const size_t nData = values->size();
   for (size_t i = 0; i < nData; ++i) {
-    Diff[i] = values->getFitData(i) - Ycal[i];
+    if (values->getFitWeight(i) != 0.0) {
+      Diff[i] = values->getFitData(i) - Ycal[i];
+    } else {
+      Diff[i] = 0.0;
+    }
   }
 
   if (!outputWorkspacePropertyName.empty()) {
diff --git a/Framework/CurveFitting/src/SeqDomainSpectrumCreator.cpp b/Framework/CurveFitting/src/SeqDomainSpectrumCreator.cpp
index af4421e5631b2a27577971f8d1cb2281f4f8f9c5..8b42f51d7bf34b3668b6b8845fcadd2c33d93a62 100644
--- a/Framework/CurveFitting/src/SeqDomainSpectrumCreator.cpp
+++ b/Framework/CurveFitting/src/SeqDomainSpectrumCreator.cpp
@@ -3,6 +3,7 @@
 #include "MantidCurveFitting/Jacobian.h"
 #include "MantidCurveFitting/SeqDomain.h"
 #include "MantidAPI/IEventWorkspace.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidAPI/Workspace.h"
 #include "MantidAPI/WorkspaceOpOverloads.h"
 #include "MantidAPI/WorkspaceProperty.h"
@@ -218,17 +219,12 @@ bool SeqDomainSpectrumCreator::histogramIsUsable(size_t i) const {
     throw std::invalid_argument("No matrix workspace assigned.");
   }
 
-  try {
-    Geometry::IDetector_const_sptr detector = m_matrixWorkspace->getDetector(i);
+  const auto &spectrumInfo = m_matrixWorkspace->spectrumInfo();
 
-    if (!detector) {
-      return true;
-    }
-
-    return !detector->isMasked();
-  } catch (const Kernel::Exception::NotFoundError &) {
+  if (!spectrumInfo.hasDetectors(i)) {
     return true;
   }
+  return !spectrumInfo.isMasked(i);
 }
 
 } // namespace CurveFitting
diff --git a/Framework/CurveFitting/test/Algorithms/CalculateChiSquaredTest.h b/Framework/CurveFitting/test/Algorithms/CalculateChiSquaredTest.h
index 718c447c1ee2dfcc556b95d53dcd4edf813dc558..768635bc158d94029799ec024a8471fd2797b9db 100644
--- a/Framework/CurveFitting/test/Algorithms/CalculateChiSquaredTest.h
+++ b/Framework/CurveFitting/test/Algorithms/CalculateChiSquaredTest.h
@@ -4,6 +4,7 @@
 #include <cxxtest/TestSuite.h>
 
 #include "MantidCurveFitting/Algorithms/CalculateChiSquared.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Column.h"
 #include "MantidAPI/FunctionDomain1D.h"
 #include "MantidAPI/FunctionFactory.h"
diff --git a/Framework/CurveFitting/test/Algorithms/CalculateCostFunctionTest.h b/Framework/CurveFitting/test/Algorithms/CalculateCostFunctionTest.h
new file mode 100644
index 0000000000000000000000000000000000000000..c7140f747032d46a8faba68d49db6b6fdf4f672b
--- /dev/null
+++ b/Framework/CurveFitting/test/Algorithms/CalculateCostFunctionTest.h
@@ -0,0 +1,94 @@
+#ifndef MANTID_CURVEFITTING_CALCULATECOSTFUNCTIONTEST_H_
+#define MANTID_CURVEFITTING_CALCULATECOSTFUNCTIONTEST_H_
+
+#include <cxxtest/TestSuite.h>
+
+#include "MantidCurveFitting/Algorithms/CalculateCostFunction.h"
+#include "MantidTestHelpers/WorkspaceCreationHelper.h"
+#include <numeric>
+
+using Mantid::CurveFitting::Algorithms::CalculateCostFunction;
+using namespace Mantid;
+using namespace Mantid::API;
+
+class CalculateCostFunctionTest : public CxxTest::TestSuite {
+public:
+  // This pair of boilerplate methods prevent the suite being created statically
+  // This means the constructor isn't called when running other tests
+  static CalculateCostFunctionTest *createSuite() {
+    return new CalculateCostFunctionTest();
+  }
+  static void destroySuite(CalculateCostFunctionTest *suite) {
+    AnalysisDataService::Instance().clear();
+    delete suite;
+  }
+
+  void test_init() {
+    CalculateCostFunction alg;
+    TS_ASSERT_THROWS_NOTHING(alg.initialize())
+    TS_ASSERT(alg.isInitialized())
+  }
+
+  void test_calculate() {
+    CalculateCostFunction alg;
+    alg.initialize();
+    auto ws = WorkspaceCreationHelper::create2DWorkspaceFromFunction(
+        [](double, int) { return 0.0; }, 1, 0.0, 1.0, 0.1);
+    alg.setPropertyValue("Function", "name=UserFunction,Formula=a*x,a=1");
+    alg.setProperty("InputWorkspace", ws);
+    alg.execute();
+    TS_ASSERT(alg.isExecuted());
+    double value = alg.getProperty("Value");
+    auto sum = std::accumulate(ws->x(0).begin(), ws->x(0).end(), 0.0,
+                               [](double s, double a) { return s + a * a; });
+    TS_ASSERT_DELTA(value, sum / 2, 1e-15);
+  }
+
+  void test_calculate_weighted() {
+    CalculateCostFunction alg;
+    alg.initialize();
+    auto ws = WorkspaceCreationHelper::create2DWorkspaceFromFunction(
+        [](double, int) { return 0.0; }, 1, 0.0, 1.0, 0.1);
+    double w = 0.0;
+    std::generate(ws->dataE(0).begin(), ws->dataE(0).end(), [&w] {
+      w += 1.0;
+      return w;
+    });
+    alg.setPropertyValue("Function", "name=UserFunction,Formula=a*x,a=1");
+    alg.setProperty("InputWorkspace", ws);
+    alg.execute();
+    TS_ASSERT(alg.isExecuted());
+    double value = alg.getProperty("Value");
+    w = 0.0;
+    auto sum = std::accumulate(ws->x(0).begin(), ws->x(0).end(), 0.0,
+                               [&w](double s, double a) {
+                                 w += 1.0;
+                                 return s + a * a / (w * w);
+                               });
+    TS_ASSERT_DELTA(value, sum / 2, 1e-15);
+  }
+
+  void test_calculate_weighted_unweighted() {
+    CalculateCostFunction alg;
+    alg.initialize();
+    auto ws = WorkspaceCreationHelper::create2DWorkspaceFromFunction(
+        [](double, int) { return 1.0; }, 1, 0.0, 1.0, 0.1);
+    double w = 0.0;
+    std::generate(ws->dataE(0).begin(), ws->dataE(0).end(), [&w] {
+      w += 1.0;
+      return w;
+    });
+    alg.setPropertyValue("Function", "name=UserFunction,Formula=a*x,a=1");
+    alg.setProperty("InputWorkspace", ws);
+    alg.setProperty("CostFunction", "Unweighted least squares");
+    alg.execute();
+    TS_ASSERT(alg.isExecuted());
+    double value = alg.getProperty("Value");
+    auto sum = std::accumulate(
+        ws->x(0).begin(), ws->x(0).end(), 0.0,
+        [](double s, double a) { return s + (a - 1.0) * (a - 1.0); });
+    TS_ASSERT_DELTA(value, sum / 2, 1e-15);
+  }
+};
+
+#endif /* MANTID_CURVEFITTING_CALCULATECOSTFUNCTIONTEST_H_ */
diff --git a/Framework/CurveFitting/test/Algorithms/ConvertToYSpaceTest.h b/Framework/CurveFitting/test/Algorithms/ConvertToYSpaceTest.h
index 3dbfccc88a5773ca386155d141e64cfb905dca0a..98b982cf3774a54de6aa4feb0305356a7d84874b 100644
--- a/Framework/CurveFitting/test/Algorithms/ConvertToYSpaceTest.h
+++ b/Framework/CurveFitting/test/Algorithms/ConvertToYSpaceTest.h
@@ -104,7 +104,7 @@ public:
 
   void test_Input_Workspace_Not_In_TOF_Throws_Error() {
     auto alg = createAlgorithm();
-    auto testWS = WorkspaceCreationHelper::Create2DWorkspace123(1, 10);
+    auto testWS = WorkspaceCreationHelper::create2DWorkspace123(1, 10);
     testWS->getAxis(0)->setUnit("Wavelength");
 
     TS_ASSERT_THROWS(alg->setProperty("InputWorkspace", testWS),
@@ -113,7 +113,7 @@ public:
 
   void test_Input_Workspace_In_TOF_Without_Instrument_Throws_Error() {
     auto alg = createAlgorithm();
-    auto testWS = WorkspaceCreationHelper::Create2DWorkspace123(1, 10);
+    auto testWS = WorkspaceCreationHelper::create2DWorkspace123(1, 10);
     testWS->getAxis(0)->setUnit("TOF");
 
     TS_ASSERT_THROWS(alg->setProperty("InputWorkspace", testWS),
diff --git a/Framework/CurveFitting/test/Algorithms/ConvolveWorkspacesTest.h b/Framework/CurveFitting/test/Algorithms/ConvolveWorkspacesTest.h
index 9343daa70f29d0ea1604572c77a4cc0ff407f154..d273fe70a65d08a319c5dc5e14db2b6b034c1bc1 100644
--- a/Framework/CurveFitting/test/Algorithms/ConvolveWorkspacesTest.h
+++ b/Framework/CurveFitting/test/Algorithms/ConvolveWorkspacesTest.h
@@ -48,10 +48,10 @@ public:
     // Convolution of normalized Gaussians should have sigma =
     // sqrt(sig1^2+sig2^2)
     Workspace2D_sptr ws1 =
-        WorkspaceCreationHelper::Create2DWorkspaceFromFunction(
+        WorkspaceCreationHelper::create2DWorkspaceFromFunction(
             NormGaussianFunc1(), 1, -2.0, 2.0, 0.01, false);
     Workspace2D_sptr ws2 =
-        WorkspaceCreationHelper::Create2DWorkspaceFromFunction(
+        WorkspaceCreationHelper::create2DWorkspaceFromFunction(
             NormGaussianFunc2(), 1, -2.0, 2.0, 0.01, false);
     TS_ASSERT_THROWS_NOTHING(
         AnalysisDataService::Instance().addOrReplace("wksp1", ws1));
@@ -101,9 +101,9 @@ public:
   ConvolveWorkspacesTestPerformance() { FrameworkManager::Instance(); }
 
   void setUp() override {
-    ws1 = WorkspaceCreationHelper::Create2DWorkspaceFromFunction(
+    ws1 = WorkspaceCreationHelper::create2DWorkspaceFromFunction(
         NormGaussianFunc1(), 1000, -5.0, 5.0, 0.005, false);
-    ws2 = WorkspaceCreationHelper::Create2DWorkspaceFromFunction(
+    ws2 = WorkspaceCreationHelper::create2DWorkspaceFromFunction(
         NormGaussianFunc2(), 1000, -5.0, 5.0, 0.005, false);
     AnalysisDataService::Instance().addOrReplace("wksp1", ws1);
     AnalysisDataService::Instance().addOrReplace("wksp2", ws2);
diff --git a/Framework/CurveFitting/test/Algorithms/EstimateFitParametersTest.h b/Framework/CurveFitting/test/Algorithms/EstimateFitParametersTest.h
new file mode 100644
index 0000000000000000000000000000000000000000..0e25179a7808241e5b7a39bfd6c1fd55190e61ca
--- /dev/null
+++ b/Framework/CurveFitting/test/Algorithms/EstimateFitParametersTest.h
@@ -0,0 +1,283 @@
+#ifndef MANTID_CURVEFITTING_ESTIMATEFITPARAMETERSTEST_H_
+#define MANTID_CURVEFITTING_ESTIMATEFITPARAMETERSTEST_H_
+
+#include <cxxtest/TestSuite.h>
+
+#include "MantidCurveFitting/Algorithms/EstimateFitParameters.h"
+#include "MantidCurveFitting/Algorithms/CalculateCostFunction.h"
+#include "MantidAPI/IFunction.h"
+#include "MantidKernel/MersenneTwister.h"
+#include "MantidTestHelpers/WorkspaceCreationHelper.h"
+
+using Mantid::CurveFitting::Algorithms::CalculateCostFunction;
+using Mantid::CurveFitting::Algorithms::EstimateFitParameters;
+using namespace Mantid;
+using namespace Mantid::API;
+
+class EstimateFitParametersTest : public CxxTest::TestSuite {
+public:
+  // This pair of boilerplate methods prevent the suite being created statically
+  // This means the constructor isn't called when running other tests
+  static EstimateFitParametersTest *createSuite() {
+    return new EstimateFitParametersTest();
+  }
+  static void destroySuite(EstimateFitParametersTest *suite) {
+    AnalysisDataService::Instance().clear();
+    delete suite;
+  }
+
+  void test_init() {
+    EstimateFitParameters alg;
+    TS_ASSERT_THROWS_NOTHING(alg.initialize())
+    TS_ASSERT(alg.isInitialized())
+  }
+
+  void test_no_constraints() {
+    auto ws = WorkspaceCreationHelper::create2DWorkspaceFromFunction(
+        [](double, int) { return 0.0; }, 1, 0, 1, 0.1);
+
+    EstimateFitParameters alg;
+    alg.initialize();
+    alg.setRethrows(true);
+    alg.setPropertyValue("Function",
+                         "name=UserFunction,Formula=a*x+b,a=1,ties=(b=0)");
+    alg.setProperty("InputWorkspace", ws);
+    TS_ASSERT_THROWS(alg.execute(), std::runtime_error);
+  }
+
+  void test_no_lower_bound() {
+    auto ws = WorkspaceCreationHelper::create2DWorkspaceFromFunction(
+        [](double x, int) { return 2.0 + 3.0 * x; }, 1, 0, 1, 0.1);
+
+    EstimateFitParameters alg;
+    alg.initialize();
+    alg.setRethrows(true);
+    alg.setPropertyValue(
+        "Function", "name=UserFunction,Formula=a*x+b,constraints=(a<4, b<4)");
+    alg.setProperty("InputWorkspace", ws);
+    TS_ASSERT_THROWS(alg.execute(), std::runtime_error);
+  }
+
+  void test_no_upper_bound() {
+    auto ws = WorkspaceCreationHelper::create2DWorkspaceFromFunction(
+        [](double x, int) { return 2.0 + 3.0 * x; }, 1, 0, 1, 0.1);
+
+    EstimateFitParameters alg;
+    alg.initialize();
+    alg.setRethrows(true);
+    alg.setPropertyValue(
+        "Function", "name=UserFunction,Formula=a*x+b,constraints=(a>4, b>4)");
+    alg.setProperty("InputWorkspace", ws);
+    TS_ASSERT_THROWS(alg.execute(), std::runtime_error);
+  }
+
+  void test_all_free() {
+    auto ws = WorkspaceCreationHelper::create2DWorkspaceFromFunction(
+        [](double x, int) { return 2.0 + 3.0 * x; }, 1, 0, 1, 0.1);
+
+    std::string funStr(
+        "name=UserFunction,Formula=a*x+b,a=0,b=0,constraints=(1<a<4, 0<b<4)");
+    CalculateCostFunction calc;
+    calc.initialize();
+    calc.setPropertyValue("Function", funStr);
+    calc.setProperty("InputWorkspace", ws);
+    calc.execute();
+    double value = calc.getProperty("Value");
+
+    EstimateFitParameters alg;
+    alg.initialize();
+    alg.setRethrows(true);
+    alg.setPropertyValue("Function", funStr);
+    alg.setProperty("InputWorkspace", ws);
+    alg.setProperty("NIterations", 1000);
+    alg.execute();
+    IFunction_sptr fun = alg.getProperty("Function");
+
+    CalculateCostFunction calc1;
+    calc1.initialize();
+    calc1.setProperty("Function", fun);
+    calc1.setProperty("InputWorkspace", ws);
+    calc1.execute();
+    double value1 = calc1.getProperty("Value");
+    TS_ASSERT(value1 < value);
+  }
+
+  void test_fixed() {
+    auto ws = WorkspaceCreationHelper::create2DWorkspaceFromFunction(
+        [](double x, int) { return 2.0 + 3.0 * x; }, 1, 0, 1, 0.1);
+
+    std::string funStr(
+        "name=UserFunction,Formula=a*x+b,a=0,ties=(b=1.9),constraints=(1<a<4)");
+    CalculateCostFunction calc;
+    calc.initialize();
+    calc.setPropertyValue("Function", funStr);
+    calc.setProperty("InputWorkspace", ws);
+    calc.execute();
+    double value = calc.getProperty("Value");
+
+    EstimateFitParameters alg;
+    alg.initialize();
+    alg.setRethrows(true);
+    alg.setPropertyValue("Function", funStr);
+    alg.setProperty("InputWorkspace", ws);
+    alg.execute();
+    IFunction_sptr fun = alg.getProperty("Function");
+
+    CalculateCostFunction calc1;
+    calc1.initialize();
+    calc1.setProperty("Function", fun);
+    calc1.setProperty("InputWorkspace", ws);
+    calc1.execute();
+    double value1 = calc1.getProperty("Value");
+    TS_ASSERT(value1 < value);
+  }
+
+  void test_tied() {
+    auto ws = WorkspaceCreationHelper::create2DWorkspaceFromFunction(
+        [](double x, int) { return 2.0 + 3.0 * x; }, 1, 0, 1, 0.1);
+
+    std::string funStr(
+        "name=UserFunction,Formula=a*x+b,a=0,ties=(b=a-1),constraints=(1<a<4)");
+    CalculateCostFunction calc;
+    calc.initialize();
+    calc.setPropertyValue("Function", funStr);
+    calc.setProperty("InputWorkspace", ws);
+    calc.execute();
+    double value = calc.getProperty("Value");
+
+    EstimateFitParameters alg;
+    alg.initialize();
+    alg.setRethrows(true);
+    alg.setPropertyValue("Function", funStr);
+    alg.setProperty("InputWorkspace", ws);
+    alg.setProperty("NIterations", 1000);
+    alg.execute();
+    IFunction_sptr fun = alg.getProperty("Function");
+    double a = fun->getParameter("a");
+    double b = fun->getParameter("b");
+    TS_ASSERT_EQUALS(b, a - 1.0);
+
+    CalculateCostFunction calc1;
+    calc1.initialize();
+    calc1.setProperty("Function", fun);
+    calc1.setProperty("InputWorkspace", ws);
+    calc1.execute();
+    double value1 = calc1.getProperty("Value");
+    TS_ASSERT(value1 < value);
+  }
+
+  void test_fix_bad_parameters() {
+    auto ws = WorkspaceCreationHelper::create2DWorkspaceFromFunction(
+        [](double x, int) { return exp(-x * x / 4.0); }, 1, -8.5, 8.5, 1.0);
+
+    std::string funStr("name=BackToBackExponential,S=1.1,constraints=(0.01<I<"
+                       "200,0.001<A<300,0.001<B<300,-5<X0<5,0.001<S<4)");
+
+    EstimateFitParameters alg;
+    alg.initialize();
+    alg.setRethrows(true);
+    alg.setPropertyValue("Function", funStr);
+    alg.setProperty("InputWorkspace", ws);
+    alg.setProperty("NSamples", 100);
+    alg.setProperty("Selection", 10);
+    alg.setProperty("NIterations", 10);
+    alg.setProperty("Type", "Cross Entropy");
+    alg.setProperty("FixBadParameters", true);
+    alg.setProperty("Seed", 11);
+    alg.execute();
+    IFunction_sptr fun = alg.getProperty("Function");
+#ifdef _WIN32
+    double A = fun->getParameter("A");
+    double B = fun->getParameter("B");
+    double I = fun->getParameter("I");
+    double S = fun->getParameter("S");
+    TS_ASSERT_DELTA(A, 199.3392, 1e-4);
+    TS_ASSERT_DELTA(B, 130.9085, 1e-4);
+    TS_ASSERT_DELTA(I, 3.5418, 1e-4);
+    TS_ASSERT_DELTA(S, 1.4130, 1e-4);
+#endif
+    TS_ASSERT(fun->isFixed(fun->parameterIndex("A")));
+    TS_ASSERT(fun->isFixed(fun->parameterIndex("B")));
+    TS_ASSERT(!fun->isFixed(fun->parameterIndex("I")));
+    TS_ASSERT(!fun->isFixed(fun->parameterIndex("S")));
+  }
+
+  void test_fix_bad_parameters_doesnt_change_values() {
+    auto ws = WorkspaceCreationHelper::create2DWorkspaceFromFunction(
+        [](double x, int) { return exp(-x * x / 4.0); }, 1, -8.5, 8.5, 1.0);
+
+    std::string funStr("name=BackToBackExponential,S=1.1,constraints=(0.01<I<"
+                       "200,0.001<A<300,0.001<B<300,-5<X0<5,0.001<S<4)");
+
+    EstimateFitParameters alg;
+    alg.initialize();
+    alg.setRethrows(true);
+    alg.setPropertyValue("Function", funStr);
+    alg.setProperty("InputWorkspace", ws);
+    alg.setProperty("NSamples", 100);
+    alg.setProperty("Selection", 10);
+    alg.setProperty("NIterations", 10);
+    alg.setProperty("Type", "Cross Entropy");
+    alg.setProperty("FixBadParameters", false);
+    alg.setProperty("Seed", 11);
+    alg.execute();
+    IFunction_sptr fun = alg.getProperty("Function");
+#ifdef _WIN32
+    double A = fun->getParameter("A");
+    double B = fun->getParameter("B");
+    double I = fun->getParameter("I");
+    double S = fun->getParameter("S");
+    TS_ASSERT_DELTA(A, 199.3392, 1e-4);
+    TS_ASSERT_DELTA(B, 130.9085, 1e-4);
+    TS_ASSERT_DELTA(I, 3.5418, 1e-4);
+    TS_ASSERT_DELTA(S, 1.4130, 1e-4);
+#endif
+    TS_ASSERT(!fun->isFixed(fun->parameterIndex("A")));
+    TS_ASSERT(!fun->isFixed(fun->parameterIndex("B")));
+    TS_ASSERT(!fun->isFixed(fun->parameterIndex("I")));
+    TS_ASSERT(!fun->isFixed(fun->parameterIndex("S")));
+  }
+
+  void test_output() {
+    auto ws = WorkspaceCreationHelper::create2DWorkspaceFromFunction(
+        [](double x, int) { return 2.0 + 3.0 * x; }, 1, 0, 1, 0.1);
+
+    std::string funStr(
+        "name=UserFunction,Formula=a*x+b,a=0,b=0,constraints=(1<a<4, 0<b<4)");
+    EstimateFitParameters alg;
+    alg.initialize();
+    alg.setRethrows(true);
+    alg.setPropertyValue("Function", funStr);
+    alg.setProperty("InputWorkspace", ws);
+    alg.setProperty("OutputWorkspace", "out");
+    alg.execute();
+    IFunction_sptr fun = alg.getProperty("Function");
+    auto params =
+        AnalysisDataService::Instance().retrieveWS<ITableWorkspace>("out");
+    TS_ASSERT(params);
+    TS_ASSERT_EQUALS(params->rowCount(), 2);
+    TS_ASSERT_EQUALS(params->columnCount(), 11);
+
+    double costValue = 0.0;
+    auto names = params->getColumn(0);
+    for (size_t col = 1; col < params->columnCount(); ++col) {
+      auto column = params->getColumn(col);
+      for (size_t row = 0; row < column->size(); ++row) {
+        fun->setParameter(names->cell<std::string>(row),
+                          column->cell<double>(row));
+      }
+      CalculateCostFunction calc;
+      calc.initialize();
+      calc.setProperty("Function", fun);
+      calc.setProperty("InputWorkspace", ws);
+      calc.execute();
+      double value = calc.getProperty("Value");
+      TSM_ASSERT_LESS_THAN(
+          "Parameter sets aren't sorted by cost function value.", costValue,
+          value);
+    }
+    AnalysisDataService::Instance().clear();
+  }
+};
+
+#endif /* MANTID_CURVEFITTING_ESTIMATEFITPARAMETERSTEST_H_ */
diff --git a/Framework/CurveFitting/test/Algorithms/EstimatePeakErrorsTest.h b/Framework/CurveFitting/test/Algorithms/EstimatePeakErrorsTest.h
index b38019f242745343b5e6af70aec35363dce7f015..17ebd69ae348f7b4bf9ca060eff278228895bdf7 100644
--- a/Framework/CurveFitting/test/Algorithms/EstimatePeakErrorsTest.h
+++ b/Framework/CurveFitting/test/Algorithms/EstimatePeakErrorsTest.h
@@ -148,14 +148,14 @@ public:
     TS_ASSERT_EQUALS(res->cell<std::string>(3, 0), "f0.Intensity");
 
     TS_ASSERT_DELTA(res->cell<double>(0, 1), -3.9865, 1e-4);
-    TS_ASSERT_DELTA(res->cell<double>(1, 1), 3.1881, 1e-4);
-    TS_ASSERT_DELTA(res->cell<double>(2, 1), 2.0011, 1e-4);
-    TS_ASSERT_DELTA(res->cell<double>(3, 1), 10.0218, 1e-4);
+    TS_ASSERT_DELTA(res->cell<double>(1, 1), 3.1883, 1e-4);
+    TS_ASSERT_DELTA(res->cell<double>(2, 1), 2.0007, 1e-4);
+    TS_ASSERT_DELTA(res->cell<double>(3, 1), 10.0200, 1e-4);
 
     TS_ASSERT_DELTA(res->cell<double>(0, 2), 0.1764, 1e-4);
-    TS_ASSERT_DELTA(res->cell<double>(1, 2), 0.5690, 1e-4);
-    TS_ASSERT_DELTA(res->cell<double>(2, 2), 0.5968, 1e-4);
-    TS_ASSERT_DELTA(res->cell<double>(3, 2), 2.6126, 1e-4);
+    TS_ASSERT_DELTA(res->cell<double>(1, 2), 0.5684, 1e-4);
+    TS_ASSERT_DELTA(res->cell<double>(2, 2), 0.6063, 1e-4);
+    TS_ASSERT_DELTA(res->cell<double>(3, 2), 2.6687, 1e-4);
 
     TS_ASSERT_EQUALS(res->cell<std::string>(4, 0), "f1.Centre");
     TS_ASSERT_EQUALS(res->cell<std::string>(5, 0), "f1.Height");
@@ -165,12 +165,12 @@ public:
     TS_ASSERT_DELTA(res->cell<double>(4, 1), 3.0064, 1e-4);
     TS_ASSERT_DELTA(res->cell<double>(5, 1), 2.1327, 1e-4);
     TS_ASSERT_DELTA(res->cell<double>(6, 1), 2.9908, 1e-4);
-    TS_ASSERT_DELTA(res->cell<double>(7, 1), 10.0196, 1e-4);
+    TS_ASSERT_DELTA(res->cell<double>(7, 1), 10.0188, 1e-4);
 
-    TS_ASSERT_DELTA(res->cell<double>(4, 2), 0.3234, 1e-4);
-    TS_ASSERT_DELTA(res->cell<double>(5, 2), 0.4756, 1e-4);
-    TS_ASSERT_DELTA(res->cell<double>(6, 2), 1.2002, 1e-4);
-    TS_ASSERT_DELTA(res->cell<double>(7, 2), 3.7937, 1e-4);
+    TS_ASSERT_DELTA(res->cell<double>(4, 2), 0.3232, 1e-4);
+    TS_ASSERT_DELTA(res->cell<double>(5, 2), 0.4771, 1e-4);
+    TS_ASSERT_DELTA(res->cell<double>(6, 2), 1.2008, 1e-4);
+    TS_ASSERT_DELTA(res->cell<double>(7, 2), 3.8074, 1e-4);
 
     AnalysisDataService::Instance().clear();
   }
@@ -206,13 +206,13 @@ public:
 
     TS_ASSERT_DELTA(res->cell<double>(0, 1), -4.0000, 1e-4);
     TS_ASSERT_DELTA(res->cell<double>(1, 1), 3.1878, 1e-4);
-    TS_ASSERT_DELTA(res->cell<double>(2, 1), 2.0012, 1e-4);
-    TS_ASSERT_DELTA(res->cell<double>(3, 1), 10.0207, 1e-4);
+    TS_ASSERT_DELTA(res->cell<double>(2, 1), 2.0006, 1e-4);
+    TS_ASSERT_DELTA(res->cell<double>(3, 1), 10.0181, 1e-4);
 
     TS_ASSERT_DELTA(res->cell<double>(0, 2), 0.0000, 1e-4);
-    TS_ASSERT_DELTA(res->cell<double>(1, 2), 0.5609, 1e-4);
-    TS_ASSERT_DELTA(res->cell<double>(2, 2), 0.5797, 1e-4);
-    TS_ASSERT_DELTA(res->cell<double>(3, 2), 2.4090, 1e-4);
+    TS_ASSERT_DELTA(res->cell<double>(1, 2), 0.5605, 1e-4);
+    TS_ASSERT_DELTA(res->cell<double>(2, 2), 0.5872, 1e-4);
+    TS_ASSERT_DELTA(res->cell<double>(3, 2), 2.4510, 1e-4);
 
     TS_ASSERT_EQUALS(res->cell<std::string>(4, 0), "f1.Centre");
     TS_ASSERT_EQUALS(res->cell<std::string>(5, 0), "f1.Height");
@@ -221,12 +221,12 @@ public:
 
     TS_ASSERT_DELTA(res->cell<double>(4, 1), 3.0056, 1e-4);
     TS_ASSERT_DELTA(res->cell<double>(5, 1), 2.1320, 1e-4);
-    TS_ASSERT_DELTA(res->cell<double>(6, 1), 2.9921, 1e-4);
-    TS_ASSERT_DELTA(res->cell<double>(7, 1), 10.0207, 1e-4);
+    TS_ASSERT_DELTA(res->cell<double>(6, 1), 2.9915, 1e-4);
+    TS_ASSERT_DELTA(res->cell<double>(7, 1), 10.0181, 1e-4);
 
-    TS_ASSERT_DELTA(res->cell<double>(4, 2), 0.3231, 1e-4);
-    TS_ASSERT_DELTA(res->cell<double>(5, 2), 0.4668, 1e-4);
-    TS_ASSERT_DELTA(res->cell<double>(6, 2), 0.6551, 1e-4);
+    TS_ASSERT_DELTA(res->cell<double>(4, 2), 0.3229, 1e-4);
+    TS_ASSERT_DELTA(res->cell<double>(5, 2), 0.4677, 1e-4);
+    TS_ASSERT_DELTA(res->cell<double>(6, 2), 0.6563, 1e-4);
     TS_ASSERT_DELTA(res->cell<double>(7, 2), 0.0000, 1e-4);
 
     AnalysisDataService::Instance().clear();
diff --git a/Framework/CurveFitting/test/Algorithms/FitPowderDiffPeaksTest.h b/Framework/CurveFitting/test/Algorithms/FitPowderDiffPeaksTest.h
index 8457ed5ae95ef5a3979dd35affcc7768ecb6de92..7887e58ccde20ff30d0e7c7ed58ef11948a59bdb 100644
--- a/Framework/CurveFitting/test/Algorithms/FitPowderDiffPeaksTest.h
+++ b/Framework/CurveFitting/test/Algorithms/FitPowderDiffPeaksTest.h
@@ -4,7 +4,8 @@
 #include <cxxtest/TestSuite.h>
 
 #include "MantidCurveFitting/Algorithms/FitPowderDiffPeaks.h"
-#include "MantidDataHandling/LoadAscii.h"
+#include "MantidDataHandling/LoadAscii2.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidDataObjects/Workspace2D.h"
 #include "MantidDataObjects/TableWorkspace.h"
@@ -28,7 +29,7 @@ namespace {
 */
 void importDataFromColumnFile(string filename, string datawsname) {
   // 1. Call LoadAscii
-  DataHandling::LoadAscii loader;
+  DataHandling::LoadAscii2 loader;
   loader.initialize();
 
   loader.setProperty("FileName", filename);
diff --git a/Framework/CurveFitting/test/Algorithms/FitTest.h b/Framework/CurveFitting/test/Algorithms/FitTest.h
index 30950a9230a87544ea2030fd0737ec6642dd7180..822660ba5bdf26cf9f240a060b3bd20c0f966387 100644
--- a/Framework/CurveFitting/test/Algorithms/FitTest.h
+++ b/Framework/CurveFitting/test/Algorithms/FitTest.h
@@ -23,6 +23,7 @@
 #include <Poco/File.h>
 
 using namespace Mantid;
+using namespace Mantid::Kernel;
 using namespace Mantid::API;
 using namespace Mantid::CurveFitting;
 using namespace Mantid::CurveFitting::Algorithms;
@@ -830,24 +831,40 @@ public:
     auto &y = data->dataY(0);
     auto &e = data->dataE(0);
 
-    y = {0, -1.77636e-16, -1.77636e-16, 0, -1.77636e-16, -8.88178e-17,
-         -1.33227e-16, 0, 0, 8.88178e-17, 3.33067e-17, 1.11022e-17, 1.27676e-16,
-         6.66134e-17, 8.32667e-17, 3.88578e-17, 9.4369e-17, 1.44329e-16,
-         2.66454e-16, 5.10703e-15, 9.80105e-14, 1.63027e-12, 2.31485e-11,
-         2.80779e-10, 2.91067e-09, 2.58027e-08, 1.9575e-07, 1.27204e-06,
-         7.08849e-06, 3.39231e-05, 0.000139678, 0.000496012, 0.00152387,
-         0.0040672, 0.00948273, 0.0194574, 0.0354878, 0.0583005, 0.0877657,
-         0.123662, 0.167048, 0.221547, 0.293962, 0.393859, 0.531629, 0.714256,
-         0.938713, 1.18531, 1.41603, 1.58257, 1.64355, 1.58257, 1.41603,
-         1.18531, 0.938713, 0.714256, 0.531629, 0.393859, 0.293962, 0.221547,
-         0.167048, 0.123662, 0.0877657, 0.0583005, 0.0354878, 0.0194574,
-         0.00948273, 0.0040672, 0.00152387, 0.000496012, 0.000139678,
-         3.39231e-05, 7.08849e-06, 1.27204e-06, 1.9575e-07, 2.58027e-08,
-         2.91067e-09, 2.80779e-10, 2.31486e-11, 1.63033e-12, 9.80771e-14,
-         5.09592e-15, 2.77556e-16, 3.88578e-17, 2.22045e-17, -1.66533e-17,
-         -1.11022e-17, 0, -7.21645e-17, -8.88178e-17, -1.11022e-16,
-         -1.33227e-16, -4.44089e-17, -1.77636e-16, -1.33227e-16, -8.88178e-17,
-         -3.55271e-16, -8.88178e-17, -1.77636e-16, -1.77636e-16};
+    y = {0.00679397551246448, 0.00684266083126313, 0.00698285916556982,
+         0.00719965548825388, 0.00747519954546736, 0.00779445649068509,
+         0.00814796531751759, 0.0085316132498512,  0.00894499942724,
+         0.00938983058044737, 0.0098689280357672,  0.0103857911674609,
+         0.0109444805899566,  0.0115496436468315,  0.0122065986210473,
+         0.0129214505517302,  0.0137012349575442,  0.0145540939647495,
+         0.0154894928726603,  0.0165184880798197,  0.0176540608380039,
+         0.01891153608981,    0.0203091122610038,  0.021868537134057,
+         0.0236159780401305,  0.0255831534292171,  0.0278088202944704,
+         0.0303407524938984,  0.0332384060776671,  0.0365765613911014,
+         0.0404503783689891,  0.0449825362752094,  0.0503335145708212,
+         0.0567167210280417,  0.0644212970503862,  0.0738474209204705,
+         0.085562497139828,   0.10039290319273,    0.119576178650528,
+         0.145011665152563,   0.17965292804199,    0.228047317644744,
+         0.296874083423821,   0.394987350612542,   0.532006328704948,
+         0.714364415633021,   0.938739703160756,   1.18531948194073,
+         1.41603503739802,    1.58257225395956,    1.64354644127685,
+         1.58257225395956,    1.41603503739802,    1.18531948194073,
+         0.938739703160756,   0.714364415633021,   0.532006328704948,
+         0.394987350612542,   0.296874083423821,   0.228047317644743,
+         0.17965292804199,    0.145011665152563,   0.119576178650528,
+         0.10039290319273,    0.085562497139828,   0.0738474209204706,
+         0.0644212970503863,  0.0567167210280418,  0.0503335145708214,
+         0.0449825362752095,  0.0404503783689893,  0.0365765613911016,
+         0.0332384060776675,  0.0303407524938988,  0.0278088202944705,
+         0.0255831534292172,  0.0236159780401305,  0.0218685371340571,
+         0.0203091122610038,  0.0189115360898101,  0.0176540608380039,
+         0.0165184880798196,  0.0154894928726603,  0.0145540939647495,
+         0.0137012349575443,  0.0129214505517302,  0.0122065986210471,
+         0.0115496436468314,  0.0109444805899566,  0.0103857911674609,
+         0.00986892803576708, 0.00938983058044717, 0.00894499942723977,
+         0.00853161324985108, 0.0081479653175175,  0.00779445649068496,
+         0.00747519954546727, 0.00719965548825406, 0.00698285916556974,
+         0.00684266083126313};
 
     x = {-10,  -9.8, -9.6, -9.4, -9.2, -9,   -8.8, -8.6, -8.4, -8.2, -8,   -7.8,
          -7.6, -7.4, -7.2, -7,   -6.8, -6.6, -6.4, -6.2, -6,   -5.8, -5.6, -5.4,
@@ -1969,6 +1986,49 @@ public:
     TS_ASSERT_DELTA(out->getParameter("A2"), 1.0, 0.0001);
   }
 
+  void test_PeakRadius() {
+    size_t nbins = 100;
+    auto ws =
+        WorkspaceFactory::Instance().create("Workspace2D", 1, nbins, nbins);
+    FunctionDomain1DVector x(-10, 10, nbins);
+    ws->dataX(0) = x.toVector();
+    {
+      Fit fit;
+      fit.initialize();
+      fit.setProperty("Function", "name=Lorentzian,Amplitude=5,FWHM=1");
+      fit.setProperty("InputWorkspace", ws);
+      fit.setProperty("MaxIterations", 0);
+      fit.setProperty("Output", "out");
+      fit.execute();
+      auto res = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(
+          "out_Workspace");
+      auto y = res->y(1);
+      TS_ASSERT_DIFFERS(y.front(), 0.0);
+      TS_ASSERT_DIFFERS(y.back(), 0.0);
+    }
+    {
+      Fit fit;
+      fit.initialize();
+      fit.setProperty("Function", "name=Lorentzian,Amplitude=5,FWHM=1");
+      fit.setProperty("InputWorkspace", ws);
+      fit.setProperty("PeakRadius", 5);
+      fit.setProperty("MaxIterations", 0);
+      fit.setProperty("Output", "out");
+      fit.execute();
+      auto res = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(
+          "out_Workspace");
+      auto y = res->y(1);
+      for (size_t i = 0; i < 25; ++i) {
+        TS_ASSERT_EQUALS(y[i], 0.0);
+        TS_ASSERT_EQUALS(y[nbins - i - 1], 0.0);
+      }
+      TS_ASSERT_DIFFERS(y[26], 0.0);
+      TS_ASSERT_DIFFERS(y[26], 0.0);
+    }
+
+    AnalysisDataService::Instance().clear();
+  }
+
 private:
   /// build test input workspaces for the Pawley function Fit tests
   MatrixWorkspace_sptr getWorkspacePawley(const std::string &functionString,
@@ -2042,7 +2102,8 @@ public:
   }
 
   void test_fit_peaks_Damping() {
-    runFitAlgorithm(m_onePeakWS, FitTestHelpers::SingleB2BPeak, "Damping");
+    runFitAlgorithm(m_onePeakWS, FitTestHelpers::SingleB2BPeak,
+                    "Damped GaussNewton");
   }
 
   void test_fit_peaks_SteepestDescent() {
@@ -2085,7 +2146,8 @@ public:
   }
 
   void test_fit_smooth_Damping() {
-    runFitAlgorithm(m_smoothWS, FitTestHelpers::SmoothishGaussians, "Damping");
+    runFitAlgorithm(m_smoothWS, FitTestHelpers::SmoothishGaussians,
+                    "Damped GaussNewton");
   }
 
   // disabled: too slow: ~17s
diff --git a/Framework/CurveFitting/test/Algorithms/LeBailFitTest.h b/Framework/CurveFitting/test/Algorithms/LeBailFitTest.h
index 8484a8d0fbcaf7e69b3ab183eb6d26f1322e6e27..a4be0cfda13e3705effbad3793ad1ada735edaa5 100644
--- a/Framework/CurveFitting/test/Algorithms/LeBailFitTest.h
+++ b/Framework/CurveFitting/test/Algorithms/LeBailFitTest.h
@@ -7,7 +7,7 @@
 #include "MantidAPI/TableRow.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidCurveFitting/Algorithms/LeBailFit.h"
-#include "MantidDataHandling/LoadAscii.h"
+#include "MantidDataHandling/LoadAscii2.h"
 #include "MantidDataObjects/TableWorkspace.h"
 #include "MantidHistogramData/Counts.h"
 #include "MantidHistogramData/CountStandardDeviations.h"
@@ -423,7 +423,7 @@ API::MatrixWorkspace_sptr generateArgSiPeak220() {
 /** Import data from a column data file
  */
 void importDataFromColumnFile(std::string filename, std::string wsname) {
-  DataHandling::LoadAscii load;
+  DataHandling::LoadAscii2 load;
   load.initialize();
 
   load.setProperty("FileName", filename);
diff --git a/Framework/CurveFitting/test/Algorithms/PlotPeakByLogValueTest.h b/Framework/CurveFitting/test/Algorithms/PlotPeakByLogValueTest.h
index 06b7b715f2782a49c9e251e89821c2225aa99997..de2bc59b44bcd82d1aee0559ec75719bcf30d10e 100644
--- a/Framework/CurveFitting/test/Algorithms/PlotPeakByLogValueTest.h
+++ b/Framework/CurveFitting/test/Algorithms/PlotPeakByLogValueTest.h
@@ -16,6 +16,8 @@
 #include "MantidAPI/FunctionFactory.h"
 #include "MantidAPI/WorkspaceGroup.h"
 #include "MantidAPI/BinEdgeAxis.h"
+#include "MantidAPI/WorkspaceHistory.h"
+#include "MantidKernel/PropertyHistory.h"
 #include "MantidKernel/TimeSeriesProperty.h"
 #include "MantidKernel/UnitFactory.h"
 
@@ -281,7 +283,7 @@ public:
   }
 
   void test_passWorkspaceIndexToFunction() {
-    auto ws = WorkspaceCreationHelper::Create2DWorkspaceFromFunction(
+    auto ws = WorkspaceCreationHelper::create2DWorkspaceFromFunction(
         Fun(), 3, -5.0, 5.0, 0.1, false);
     AnalysisDataService::Instance().add("PLOTPEAKBYLOGVALUETEST_WS", ws);
     PlotPeakByLogValue alg;
@@ -308,7 +310,7 @@ public:
   }
 
   void test_dont_passWorkspaceIndexToFunction() {
-    auto ws = WorkspaceCreationHelper::Create2DWorkspaceFromFunction(
+    auto ws = WorkspaceCreationHelper::create2DWorkspaceFromFunction(
         Fun(), 3, -5.0, 5.0, 0.1, false);
     AnalysisDataService::Instance().add("PLOTPEAKBYLOGVALUETEST_WS", ws);
     PlotPeakByLogValue alg;
@@ -337,7 +339,7 @@ public:
   }
 
   void test_passWorkspaceIndexToFunction_composit_function_case() {
-    auto ws = WorkspaceCreationHelper::Create2DWorkspaceFromFunction(
+    auto ws = WorkspaceCreationHelper::create2DWorkspaceFromFunction(
         Fun(), 3, -5.0, 5.0, 0.1, false);
     AnalysisDataService::Instance().add("PLOTPEAKBYLOGVALUETEST_WS", ws);
     PlotPeakByLogValue alg;
@@ -366,7 +368,7 @@ public:
   }
 
   void test_createOutputOption() {
-    auto ws = WorkspaceCreationHelper::Create2DWorkspaceFromFunction(
+    auto ws = WorkspaceCreationHelper::create2DWorkspaceFromFunction(
         Fun(), 3, -5.0, 5.0, 0.1, false);
     AnalysisDataService::Instance().add("PLOTPEAKBYLOGVALUETEST_WS", ws);
     PlotPeakByLogValue alg;
@@ -623,7 +625,7 @@ private:
     AnalysisDataService::Instance().add("PlotPeakGroup", m_wsg);
     const int N = 3;
     for (int iWS = 0; iWS < N; ++iWS) {
-      auto ws = WorkspaceCreationHelper::Create2DWorkspaceFromFunction(
+      auto ws = WorkspaceCreationHelper::create2DWorkspaceFromFunction(
           PlotPeak_Expression(iWS), 3, 0, 10, 0.005, hist);
       for (int i = 0; i < 3; ++i) {
         ws->getSpectrum(i).setSpectrumNo(0);
diff --git a/Framework/CurveFitting/test/Algorithms/RefinePowderInstrumentParameters3Test.h b/Framework/CurveFitting/test/Algorithms/RefinePowderInstrumentParameters3Test.h
index 71b6f5ebea22bf68727b88fa0e598288bce90881..e22e29d045a82c6e2064471890d6fb0ab73acac3 100644
--- a/Framework/CurveFitting/test/Algorithms/RefinePowderInstrumentParameters3Test.h
+++ b/Framework/CurveFitting/test/Algorithms/RefinePowderInstrumentParameters3Test.h
@@ -5,6 +5,7 @@
 
 #include "MantidCurveFitting/Algorithms/RefinePowderInstrumentParameters3.h"
 
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/TableRow.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidDataObjects/TableWorkspace.h"
diff --git a/Framework/CurveFitting/test/Algorithms/RefinePowderInstrumentParametersTest.h b/Framework/CurveFitting/test/Algorithms/RefinePowderInstrumentParametersTest.h
index bdb436ab2f70eda5b738b8d4381d68f417146595..233c1a20055e57a6afc44f54949e3f49375657cd 100644
--- a/Framework/CurveFitting/test/Algorithms/RefinePowderInstrumentParametersTest.h
+++ b/Framework/CurveFitting/test/Algorithms/RefinePowderInstrumentParametersTest.h
@@ -4,11 +4,13 @@
 #include <cxxtest/TestSuite.h>
 
 #include "MantidCurveFitting/Algorithms/RefinePowderInstrumentParameters.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidDataObjects/Workspace2D.h"
 #include "MantidDataObjects/TableWorkspace.h"
 #include "MantidAPI/TableRow.h"
 #include <fstream>
+#include <iomanip>
 
 using Mantid::CurveFitting::Algorithms::RefinePowderInstrumentParameters;
 using namespace Mantid;
diff --git a/Framework/CurveFitting/test/Algorithms/SeqDomainSpectrumCreatorTest.h b/Framework/CurveFitting/test/Algorithms/SeqDomainSpectrumCreatorTest.h
index c233a1b147bd51d1ba4eddfb71c2ec884713c994..0c95cad7690a1ec730e7c0542258bd40064aab51 100644
--- a/Framework/CurveFitting/test/Algorithms/SeqDomainSpectrumCreatorTest.h
+++ b/Framework/CurveFitting/test/Algorithms/SeqDomainSpectrumCreatorTest.h
@@ -17,6 +17,7 @@
 
 #include "MantidAPI/FrameworkManager.h"
 #include "MantidAPI/AlgorithmManager.h"
+#include "MantidAPI/SpectrumInfo.h"
 
 #include "MantidTestHelpers/HistogramDataTestHelper.h"
 
@@ -51,7 +52,7 @@ public:
   void testSetMatrixWorkspace() {
     TestableSeqDomainSpectrumCreator creator(NULL, "");
     TS_ASSERT_THROWS_NOTHING(creator.setMatrixWorkspace(
-        WorkspaceCreationHelper::Create2DWorkspace(5, 5)));
+        WorkspaceCreationHelper::create2DWorkspace(5, 5)));
 
     TS_ASSERT_EQUALS(creator.m_matrixWorkspace->getNumberHistograms(), 5);
 
@@ -62,7 +63,7 @@ public:
   void testGetDomainSize() {
     TestableSeqDomainSpectrumCreator creator(NULL, "");
     creator.setMatrixWorkspace(
-        WorkspaceCreationHelper::Create2DWorkspace123(4, 12));
+        WorkspaceCreationHelper::create2DWorkspace123(4, 12));
 
     FunctionDomain_sptr domain;
     FunctionValues_sptr values;
@@ -86,14 +87,14 @@ public:
     std::set<int64_t> masked;
     masked.insert(0);
     creator.setMatrixWorkspace(
-        WorkspaceCreationHelper::Create2DWorkspace123(2, 12, false, masked));
+        WorkspaceCreationHelper::create2DWorkspace123(2, 12, false, masked));
 
     TS_ASSERT(!creator.histogramIsUsable(0));
     TS_ASSERT(creator.histogramIsUsable(1));
 
     // No instrument
     creator.setMatrixWorkspace(
-        WorkspaceCreationHelper::Create2DWorkspace123(2, 12));
+        WorkspaceCreationHelper::create2DWorkspace123(2, 12));
     TS_ASSERT(creator.histogramIsUsable(0));
     TS_ASSERT(creator.histogramIsUsable(1));
   }
@@ -101,7 +102,7 @@ public:
   void testCreateDomain() {
     TestableSeqDomainSpectrumCreator creator(NULL, "");
     creator.setMatrixWorkspace(
-        WorkspaceCreationHelper::Create2DWorkspace123(4, 12, true));
+        WorkspaceCreationHelper::create2DWorkspace123(4, 12, true));
 
     FunctionDomain_sptr domain;
     FunctionValues_sptr values;
@@ -133,7 +134,7 @@ public:
     std::set<int64_t> masked;
     masked.insert(2);
     creator.setMatrixWorkspace(
-        WorkspaceCreationHelper::Create2DWorkspace123(4, 12, true, masked));
+        WorkspaceCreationHelper::create2DWorkspace123(4, 12, true, masked));
 
     FunctionDomain_sptr domain;
     FunctionValues_sptr values;
@@ -168,7 +169,7 @@ public:
 
     // TODO is the workspace created with the wrong values here
     MatrixWorkspace_sptr matrixWs =
-        WorkspaceCreationHelper::Create2DWorkspace123(4, 12);
+        WorkspaceCreationHelper::create2DWorkspace123(4, 12);
 
     TestableSeqDomainSpectrumCreator creator(NULL, "");
     creator.setMatrixWorkspace(matrixWs);
@@ -213,7 +214,7 @@ public:
     std::set<int64_t> masked;
     masked.insert(2);
     MatrixWorkspace_sptr matrixWs =
-        WorkspaceCreationHelper::Create2DWorkspace123(4, 12, false, masked);
+        WorkspaceCreationHelper::create2DWorkspace123(4, 12, false, masked);
 
     TestableSeqDomainSpectrumCreator creator(NULL, "");
     creator.setMatrixWorkspace(matrixWs);
@@ -245,9 +246,10 @@ public:
       const auto &y = outputWsMatrix->y(i);
 
       TS_ASSERT_EQUALS(x, matrixWs->x(i));
+      const auto &spectrumInfo = outputWsMatrix->spectrumInfo();
       for (size_t j = 0; j < x.size(); ++j) {
         // If detector is not masked, there should be values, otherwise 0.
-        if (!outputWsMatrix->getDetector(i)->isMasked()) {
+        if (!spectrumInfo.isMasked(i)) {
           TS_ASSERT_EQUALS(y[j], static_cast<double>(i) + slope * x[j]);
         } else {
           TS_ASSERT_EQUALS(y[j], 0.0);
@@ -259,7 +261,7 @@ public:
   void testCreateOutputWorkspaceWithDistributionAsInput() {
     // Arrange
     MatrixWorkspace_sptr matrixWs =
-        WorkspaceCreationHelper::Create2DWorkspace123(4, 12, true);
+        WorkspaceCreationHelper::create2DWorkspace123(4, 12, true);
     Mantid::API::WorkspaceHelpers::makeDistribution(matrixWs);
 
     TestableSeqDomainSpectrumCreator creator(NULL, "");
@@ -288,7 +290,7 @@ public:
     double slope = 2.0;
 
     MatrixWorkspace_sptr matrixWs =
-        WorkspaceCreationHelper::Create2DWorkspace123(400, 500);
+        WorkspaceCreationHelper::create2DWorkspace123(400, 500);
     for (size_t i = 0; i < matrixWs->getNumberHistograms(); ++i) {
       auto &x = matrixWs->mutableX(i);
       auto &y = matrixWs->mutableY(i);
@@ -331,7 +333,7 @@ public:
     }
 
     MatrixWorkspace_sptr matrixWs =
-        WorkspaceCreationHelper::Create2DWorkspace123(400, 50);
+        WorkspaceCreationHelper::create2DWorkspace123(400, 50);
     for (size_t i = 0; i < matrixWs->getNumberHistograms(); ++i) {
       auto &x = matrixWs->mutableX(i);
       auto &y = matrixWs->mutableY(i);
diff --git a/Framework/CurveFitting/test/Algorithms/SplineBackgroundTest.h b/Framework/CurveFitting/test/Algorithms/SplineBackgroundTest.h
index f198a379cbdc7283cc23163b24abcd61376fe317..2ab8d823a3a4970b07bfccf528ef354398361ca3 100644
--- a/Framework/CurveFitting/test/Algorithms/SplineBackgroundTest.h
+++ b/Framework/CurveFitting/test/Algorithms/SplineBackgroundTest.h
@@ -23,7 +23,7 @@ private:
 
 public:
   void testIt() {
-    auto ws = WorkspaceCreationHelper::Create2DWorkspaceFromFunction(
+    auto ws = WorkspaceCreationHelper::create2DWorkspaceFromFunction(
         SinFunction(), 1, 0.1, 10.1, 0.1, true);
     WorkspaceCreationHelper::addNoise(ws, 0.1);
     // Mask some bins out to test that functionality
@@ -66,7 +66,7 @@ public:
     constexpr double xRangeEnd = 2500.1;
     constexpr double xRangeStep = 0.1;
 
-    ws = WorkspaceCreationHelper::Create2DWorkspaceFromFunction(
+    ws = WorkspaceCreationHelper::create2DWorkspaceFromFunction(
         SinFunction(), nspec, xRangeStart, xRangeEnd, xRangeStep, true);
     WorkspaceCreationHelper::addNoise(ws, 0.1);
     // Mask some bins out to test that functionality
diff --git a/Framework/CurveFitting/test/Algorithms/SplineInterpolationTest.h b/Framework/CurveFitting/test/Algorithms/SplineInterpolationTest.h
index 1718ced8660f37cfdc31e0b2d7a2de0ad041ceca..abffe7f19eb8ddc150e0912e0f376946e9271583 100644
--- a/Framework/CurveFitting/test/Algorithms/SplineInterpolationTest.h
+++ b/Framework/CurveFitting/test/Algorithms/SplineInterpolationTest.h
@@ -7,6 +7,7 @@
 #include "MantidTestHelpers/WorkspaceCreationHelper.h"
 #include "MantidAPI/NumericAxis.h"
 #include "MantidAPI/TextAxis.h"
+#include "MantidAPI/WorkspaceGroup.h"
 
 using Mantid::CurveFitting::Algorithms::SplineInterpolation;
 using namespace Mantid::API;
@@ -36,10 +37,10 @@ public:
 
     // create binned workspaces
     MatrixWorkspace_sptr mws =
-        WorkspaceCreationHelper::Create2DWorkspaceFromFunction(SplineFunc(), 1,
+        WorkspaceCreationHelper::create2DWorkspaceFromFunction(SplineFunc(), 1,
                                                                0, 20, 1, false);
     MatrixWorkspace_sptr iws =
-        WorkspaceCreationHelper::Create2DWorkspaceFromFunction(
+        WorkspaceCreationHelper::create2DWorkspaceFromFunction(
             SplineFunc(), spectra, 0, 20, 0.1, false);
 
     SplineInterpolation alg;
@@ -52,10 +53,10 @@ public:
 
     // create binned workspaces
     MatrixWorkspace_sptr mws =
-        WorkspaceCreationHelper::Create2DWorkspaceFromFunction(SplineFunc(), 1,
+        WorkspaceCreationHelper::create2DWorkspaceFromFunction(SplineFunc(), 1,
                                                                0, 20, 1, true);
     MatrixWorkspace_sptr iws =
-        WorkspaceCreationHelper::Create2DWorkspaceFromFunction(
+        WorkspaceCreationHelper::create2DWorkspaceFromFunction(
             SplineFunc(), spectra, 0, 20, 1, true);
 
     SplineInterpolation alg;
@@ -68,10 +69,10 @@ public:
 
     // create binned workspaces
     MatrixWorkspace_sptr mws =
-        WorkspaceCreationHelper::Create2DWorkspaceFromFunction(SplineFunc(), 1,
+        WorkspaceCreationHelper::create2DWorkspaceFromFunction(SplineFunc(), 1,
                                                                0, 20, 1, true);
     MatrixWorkspace_sptr iws =
-        WorkspaceCreationHelper::Create2DWorkspaceFromFunction(
+        WorkspaceCreationHelper::create2DWorkspaceFromFunction(
             SplineFunc(), spectra, 0, 20, 1, true);
 
     SplineInterpolation alg;
@@ -84,10 +85,10 @@ public:
 
     // create binned workspaces
     MatrixWorkspace_sptr mws =
-        WorkspaceCreationHelper::Create2DWorkspaceFromFunction(SplineFunc(), 1,
+        WorkspaceCreationHelper::create2DWorkspaceFromFunction(SplineFunc(), 1,
                                                                0, 20, 1, true);
     MatrixWorkspace_sptr iws =
-        WorkspaceCreationHelper::Create2DWorkspaceFromFunction(
+        WorkspaceCreationHelper::create2DWorkspaceFromFunction(
             SplineFunc(), spectra, 0, 20, 1, true);
 
     // Add an axis
@@ -171,11 +172,11 @@ public:
     constexpr int xStepVal(1);
 
     MatrixWorkspace_sptr matWs =
-        WorkspaceCreationHelper::Create2DWorkspaceFromFunction(
+        WorkspaceCreationHelper::create2DWorkspaceFromFunction(
             SplineFunc(), spectra, xStartVal, xEndVal, xStepVal, false);
 
     MatrixWorkspace_sptr inWs =
-        WorkspaceCreationHelper::Create2DWorkspaceFromFunction(
+        WorkspaceCreationHelper::create2DWorkspaceFromFunction(
             SplineFunc(), spectra, xStartVal, xEndVal, (xStepVal * 0.1), false);
 
     inputWs = inWs;
diff --git a/Framework/CurveFitting/test/Algorithms/SplineSmoothingTest.h b/Framework/CurveFitting/test/Algorithms/SplineSmoothingTest.h
index fa82e66115db858040112abb75d3528cef173c78..7ef1ad3b8a3a111ad64a59c8b94c42636df3e6cb 100644
--- a/Framework/CurveFitting/test/Algorithms/SplineSmoothingTest.h
+++ b/Framework/CurveFitting/test/Algorithms/SplineSmoothingTest.h
@@ -5,6 +5,7 @@
 
 #include "MantidTestHelpers/WorkspaceCreationHelper.h"
 #include "MantidCurveFitting/Algorithms/SplineSmoothing.h"
+#include "MantidAPI/WorkspaceGroup.h"
 
 using Mantid::CurveFitting::Algorithms::SplineSmoothing;
 
@@ -36,7 +37,7 @@ public:
 
     // create a binned workspace
     MatrixWorkspace_sptr inputWorkspace =
-        WorkspaceCreationHelper::Create2DWorkspaceFromFunction(
+        WorkspaceCreationHelper::create2DWorkspaceFromFunction(
             SplineFunc(), spectra, 0, 5, 0.02, false);
 
     // setup algorithm
@@ -53,7 +54,7 @@ public:
 
     // create a binned workspace
     MatrixWorkspace_sptr inputWorkspace =
-        WorkspaceCreationHelper::Create2DWorkspaceFromFunction(
+        WorkspaceCreationHelper::create2DWorkspaceFromFunction(
             SplineFunc(), spectra, 0, 5, 0.02, true);
 
     SplineSmoothing alg;
@@ -69,7 +70,7 @@ public:
 
     // create a binned workspace
     MatrixWorkspace_sptr inputWorkspace =
-        WorkspaceCreationHelper::Create2DWorkspaceFromFunction(
+        WorkspaceCreationHelper::create2DWorkspaceFromFunction(
             SplineFunc(), spectra, 0, 5, 0.02, true);
 
     SplineSmoothing alg;
diff --git a/Framework/CurveFitting/test/Algorithms/VesuvioCalculateMSTest.h b/Framework/CurveFitting/test/Algorithms/VesuvioCalculateMSTest.h
index b2ef11f7fb01113aae60a78313b308858b4eb47a..b4768449294f950efca2a91d6862c5f32dceddc8 100644
--- a/Framework/CurveFitting/test/Algorithms/VesuvioCalculateMSTest.h
+++ b/Framework/CurveFitting/test/Algorithms/VesuvioCalculateMSTest.h
@@ -199,7 +199,7 @@ public:
     VesuvioCalculateMS alg;
     alg.initialize();
 
-    auto testWS = WorkspaceCreationHelper::Create2DWorkspace(1, 1);
+    auto testWS = WorkspaceCreationHelper::create2DWorkspace(1, 1);
     TS_ASSERT_THROWS(alg.setProperty("InputWorkspace", testWS),
                      std::invalid_argument);
   }
@@ -208,7 +208,7 @@ public:
     VesuvioCalculateMS alg;
     alg.initialize();
 
-    auto testWS = WorkspaceCreationHelper::Create2DWorkspace(1, 1);
+    auto testWS = WorkspaceCreationHelper::create2DWorkspace(1, 1);
     testWS->getAxis(0)->setUnit("TOF");
     TS_ASSERT_THROWS(alg.setProperty("InputWorkspace", testWS),
                      std::invalid_argument);
diff --git a/Framework/CurveFitting/test/CMakeLists.txt b/Framework/CurveFitting/test/CMakeLists.txt
index 3ed8ddfae88a10b485c2018462ff96decd6ceceb..e559640e6619c1f7ec79d587e9ac232226bd9de0 100644
--- a/Framework/CurveFitting/test/CMakeLists.txt
+++ b/Framework/CurveFitting/test/CMakeLists.txt
@@ -19,6 +19,7 @@ if ( CXXTEST_FOUND )
             DataObjects
             Geometry
             HistogramData
+            Indexing
             Kernel
             ${GSL_LIBRARIES}
             ${Boost_LIBRARIES}
diff --git a/Framework/CurveFitting/test/CompositeFunctionTest.h b/Framework/CurveFitting/test/CompositeFunctionTest.h
index e6893283c435b902b1d376fe5a198215ce8a8000..15433437e8e287e06da2459340885d0293c70ff7 100644
--- a/Framework/CurveFitting/test/CompositeFunctionTest.h
+++ b/Framework/CurveFitting/test/CompositeFunctionTest.h
@@ -183,7 +183,7 @@ public:
     TS_ASSERT_EQUALS(mfun->getParameter(6), 1.1);
     TS_ASSERT_EQUALS(mfun->getParameter(7), 1.0);
 
-    auto ws = WorkspaceCreationHelper::Create2DWorkspaceFromFunction(
+    auto ws = WorkspaceCreationHelper::create2DWorkspaceFromFunction(
         TestFunction(), 1, 0.0, 10.0, 0.1);
     WorkspaceCreationHelper::addNoise(ws, 0.1);
     WorkspaceCreationHelper::storeWS("mfun", ws);
diff --git a/Framework/CurveFitting/test/Constraints/BoundaryConstraintTest.h b/Framework/CurveFitting/test/Constraints/BoundaryConstraintTest.h
index 6e340def5735e36eb437735f2ef22b333dbe501e..fb4e27623588072a569982443cc31493c2f98ba3 100644
--- a/Framework/CurveFitting/test/Constraints/BoundaryConstraintTest.h
+++ b/Framework/CurveFitting/test/Constraints/BoundaryConstraintTest.h
@@ -6,6 +6,7 @@
 #include "MantidCurveFitting/Constraints/BoundaryConstraint.h"
 #include "MantidCurveFitting/Functions/Gaussian.h"
 #include "MantidCurveFitting/Functions/Lorentzian.h"
+#include "MantidKernel/make_unique.h"
 #include "MantidKernel/UnitFactory.h"
 #include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/WorkspaceFactory.h"
@@ -13,6 +14,7 @@
 #include "MantidAPI/Algorithm.h"
 #include "MantidAPI/Expression.h"
 
+using namespace Mantid;
 using namespace Mantid::API;
 using namespace Mantid::CurveFitting;
 using namespace Mantid::CurveFitting::Functions;
@@ -139,23 +141,25 @@ public:
   void testAsString() {
     Gaussian gaus;
     gaus.initialize();
-    BoundaryConstraint *bc = new BoundaryConstraint;
-    Expression expr;
-    expr.parse("Sigma<20");
-    bc->initialize(&gaus, expr, false);
+    {
+      auto bc = Kernel::make_unique<BoundaryConstraint>();
+      Expression expr;
+      expr.parse("Sigma<20");
+      bc->initialize(&gaus, expr, false);
+
+      TS_ASSERT_EQUALS(bc->getParameterName(), "Sigma");
+      TS_ASSERT_DELTA(bc->upper(), 20, 0.0001);
+      TS_ASSERT(!bc->hasLower());
+      gaus.addConstraint(std::move(bc));
+    }
 
-    TS_ASSERT_EQUALS(bc->getParameterName(), "Sigma");
-    TS_ASSERT_DELTA(bc->upper(), 20, 0.0001);
-    TS_ASSERT(!bc->hasLower());
-
-    gaus.addConstraint(bc);
     IFunction_sptr fun =
         FunctionFactory::Instance().createInitialized(gaus.asString());
     TS_ASSERT(fun);
 
     IConstraint *c = fun->getConstraint(2);
     TS_ASSERT(c);
-    bc = dynamic_cast<BoundaryConstraint *>(c);
+    auto bc = dynamic_cast<BoundaryConstraint *>(c);
     TS_ASSERT(bc);
 
     TS_ASSERT_EQUALS(bc->getParameterName(), "Sigma");
@@ -167,17 +171,17 @@ public:
     Gaussian gaus;
     gaus.initialize();
 
-    BoundaryConstraint *bcSigma = new BoundaryConstraint;
+    auto bcSigma = Kernel::make_unique<BoundaryConstraint>();
     Expression exprSigma;
     exprSigma.parse("Sigma<20");
     bcSigma->initialize(&gaus, exprSigma, false);
-    gaus.addConstraint(bcSigma);
+    gaus.addConstraint(std::move(bcSigma));
 
-    BoundaryConstraint *bcHeight = new BoundaryConstraint;
+    auto bcHeight = Kernel::make_unique<BoundaryConstraint>();
     Expression exprHeight;
     exprHeight.parse("1.3<Height<3.4");
     bcHeight->initialize(&gaus, exprHeight, false);
-    gaus.addConstraint(bcHeight);
+    gaus.addConstraint(std::move(bcHeight));
 
     IFunction_sptr fun =
         FunctionFactory::Instance().createInitialized(gaus.asString());
diff --git a/Framework/CurveFitting/test/FitMWTest.h b/Framework/CurveFitting/test/FitMWTest.h
index 9b0ecc08b525f6f4a76e20f332450db5840b7628..3dfa3645ea0875c07f3867f1ab2c82b405f275a0 100644
--- a/Framework/CurveFitting/test/FitMWTest.h
+++ b/Framework/CurveFitting/test/FitMWTest.h
@@ -1,30 +1,31 @@
 #ifndef CURVEFITTING_FITMWTEST_H_
 #define CURVEFITTING_FITMWTEST_H_
 
-#include <cxxtest/TestSuite.h>
 #include "MantidTestHelpers/FakeObjects.h"
+#include "MantidTestHelpers/WorkspaceCreationHelper.h"
+#include <cxxtest/TestSuite.h>
 
-#include "MantidCurveFitting/FitMW.h"
 #include "MantidCurveFitting/Algorithms/Fit.h"
-#include "MantidCurveFitting/SeqDomain.h"
-#include "MantidCurveFitting/Functions/UserFunction.h"
-#include "MantidCurveFitting/Functions/ExpDecay.h"
+#include "MantidCurveFitting/FitMW.h"
 #include "MantidCurveFitting/Functions/Convolution.h"
+#include "MantidCurveFitting/Functions/ExpDecay.h"
 #include "MantidCurveFitting/Functions/Gaussian.h"
 #include "MantidCurveFitting/Functions/Polynomial.h"
+#include "MantidCurveFitting/Functions/UserFunction.h"
+#include "MantidCurveFitting/SeqDomain.h"
 
+#include "MantidAPI/AlgorithmManager.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/CompositeFunction.h"
 #include "MantidAPI/FrameworkManager.h"
-#include "MantidAPI/AlgorithmManager.h"
-#include "MantidAPI/ITableWorkspace.h"
 #include "MantidAPI/FunctionDomain1D.h"
-#include "MantidAPI/WorkspaceProperty.h"
-#include "MantidAPI/AnalysisDataService.h"
+#include "MantidAPI/ITableWorkspace.h"
 #include "MantidAPI/WorkspaceOpOverloads.h"
+#include "MantidAPI/WorkspaceProperty.h"
 
-#include "MantidKernel/PropertyManager.h"
 #include "MantidGeometry/Instrument.h"
 #include "MantidGeometry/Instrument/Detector.h"
+#include "MantidKernel/PropertyManager.h"
 
 #include <sstream>
 
@@ -205,7 +206,10 @@ public:
   // This pair of boilerplate methods prevent the suite being created statically
   // This means the constructor isn't called when running other tests
   static FitMWTest *createSuite() { return new FitMWTest(); }
-  static void destroySuite(FitMWTest *suite) { delete suite; }
+  static void destroySuite(FitMWTest *suite) {
+    AnalysisDataService::Instance().clear();
+    delete suite;
+  }
 
   FitMWTest() {
     // need to have DataObjects loaded
@@ -808,6 +812,484 @@ public:
   void test_convolve_members_option_with_background() {
     do_test_convolve_members_option(true);
   }
+
+  void test_exclude() {
+    auto ws = WorkspaceCreationHelper::create2DWorkspaceFromFunction(
+        [](double x, int) {
+          if (x >= 1.0 && x <= 2.0)
+            return 2.0;
+          return 1.0;
+        },
+        1, 0.0, 3., 0.5);
+
+    std::vector<double> exclude{1.0, 2.0};
+    Fit fit;
+    fit.initialize();
+    fit.setProperty("Function", "name=FlatBackground");
+    fit.setProperty("InputWorkspace", ws);
+    fit.setProperty("Exclude", exclude);
+
+    FunctionDomain_sptr domain;
+    FunctionValues_sptr values;
+
+    FitMW fitmw(&fit, "InputWorkspace");
+    fitmw.declareDatasetProperties("", false);
+    fitmw.createDomain(domain, values);
+
+    TS_ASSERT_EQUALS(values->getFitWeight(0), 1);
+    TS_ASSERT_EQUALS(values->getFitWeight(1), 1);
+    TS_ASSERT_EQUALS(values->getFitWeight(2), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(3), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(4), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(5), 1);
+    TS_ASSERT_EQUALS(values->getFitWeight(6), 1);
+
+    fit.execute();
+
+    IFunction_sptr fun = fit.getProperty("Function");
+    TS_ASSERT_EQUALS(fun->getParameter("A0"), 1);
+  }
+
+  void test_exclude_1() {
+    auto ws = WorkspaceCreationHelper::create2DWorkspaceFromFunction(
+        [](double x, int) {
+          if (x >= 1.0 && x <= 2.0)
+            return 2.0;
+          return 1.0;
+        },
+        1, 0.0, 3., 0.5);
+
+    std::vector<double> exclude{-2.0, -1.0};
+    Fit fit;
+    fit.initialize();
+    fit.setProperty("Function", "name=FlatBackground");
+    fit.setProperty("InputWorkspace", ws);
+    fit.setProperty("Exclude", exclude);
+
+    FunctionDomain_sptr domain;
+    FunctionValues_sptr values;
+
+    FitMW fitmw(&fit, "InputWorkspace");
+    fitmw.declareDatasetProperties("", false);
+    fitmw.createDomain(domain, values);
+
+    TS_ASSERT_EQUALS(values->getFitWeight(0), 1);
+    TS_ASSERT_EQUALS(values->getFitWeight(1), 1);
+    TS_ASSERT_EQUALS(values->getFitWeight(2), 1);
+    TS_ASSERT_EQUALS(values->getFitWeight(3), 1);
+    TS_ASSERT_EQUALS(values->getFitWeight(4), 1);
+    TS_ASSERT_EQUALS(values->getFitWeight(5), 1);
+    TS_ASSERT_EQUALS(values->getFitWeight(6), 1);
+
+    fit.execute();
+
+    IFunction_sptr fun = fit.getProperty("Function");
+    TS_ASSERT_DELTA(fun->getParameter("A0"), 1.4285, 1e-4);
+  }
+
+  void test_exclude_2() {
+    auto ws = WorkspaceCreationHelper::create2DWorkspaceFromFunction(
+        [](double x, int) {
+          if (x >= 1.0 && x <= 2.0)
+            return 2.0;
+          return 1.0;
+        },
+        1, 0.0, 3., 0.5);
+
+    std::vector<double> exclude{4.0, 5.0};
+    Fit fit;
+    fit.initialize();
+    fit.setProperty("Function", "name=FlatBackground");
+    fit.setProperty("InputWorkspace", ws);
+    fit.setProperty("Exclude", exclude);
+
+    FunctionDomain_sptr domain;
+    FunctionValues_sptr values;
+
+    FitMW fitmw(&fit, "InputWorkspace");
+    fitmw.declareDatasetProperties("", false);
+    fitmw.createDomain(domain, values);
+
+    TS_ASSERT_EQUALS(values->getFitWeight(0), 1);
+    TS_ASSERT_EQUALS(values->getFitWeight(1), 1);
+    TS_ASSERT_EQUALS(values->getFitWeight(2), 1);
+    TS_ASSERT_EQUALS(values->getFitWeight(3), 1);
+    TS_ASSERT_EQUALS(values->getFitWeight(4), 1);
+    TS_ASSERT_EQUALS(values->getFitWeight(5), 1);
+    TS_ASSERT_EQUALS(values->getFitWeight(6), 1);
+
+    fit.execute();
+
+    IFunction_sptr fun = fit.getProperty("Function");
+    TS_ASSERT_DELTA(fun->getParameter("A0"), 1.4285, 1e-4);
+  }
+
+  void test_exclude_3() {
+    auto ws = WorkspaceCreationHelper::create2DWorkspaceFromFunction(
+        [](double x, int) {
+          if (x >= 1.0 && x <= 2.0)
+            return 2.0;
+          return 1.0;
+        },
+        1, 0.0, 3., 0.5);
+
+    std::vector<double> exclude{-2.0, -1.0, 4.0, 5.0};
+    Fit fit;
+    fit.initialize();
+    fit.setProperty("Function", "name=FlatBackground");
+    fit.setProperty("InputWorkspace", ws);
+    fit.setProperty("Exclude", exclude);
+
+    FunctionDomain_sptr domain;
+    FunctionValues_sptr values;
+
+    FitMW fitmw(&fit, "InputWorkspace");
+    fitmw.declareDatasetProperties("", false);
+    fitmw.createDomain(domain, values);
+
+    TS_ASSERT_EQUALS(values->getFitWeight(0), 1);
+    TS_ASSERT_EQUALS(values->getFitWeight(1), 1);
+    TS_ASSERT_EQUALS(values->getFitWeight(2), 1);
+    TS_ASSERT_EQUALS(values->getFitWeight(3), 1);
+    TS_ASSERT_EQUALS(values->getFitWeight(4), 1);
+    TS_ASSERT_EQUALS(values->getFitWeight(5), 1);
+    TS_ASSERT_EQUALS(values->getFitWeight(6), 1);
+
+    fit.execute();
+
+    IFunction_sptr fun = fit.getProperty("Function");
+    TS_ASSERT_DELTA(fun->getParameter("A0"), 1.4285, 1e-4);
+  }
+
+  void test_exclude_4() {
+    auto ws = WorkspaceCreationHelper::create2DWorkspaceFromFunction(
+        [](double x, int) {
+          if (x >= 0.0 && x <= 1.0)
+            return 2.0;
+          if (x >= 4.0 && x <= 6.0)
+            return 3.0;
+          if (x >= 9.0 && x <= 10.0)
+            return 4.0;
+          return 1.0;
+        },
+        1, 0.0, 10., 1.0);
+
+    std::vector<double> exclude{-1.0, 1.0, 4.0, 6.5, 9.0, 11.0};
+    Fit fit;
+    fit.initialize();
+    fit.setProperty("Function", "name=FlatBackground");
+    fit.setProperty("InputWorkspace", ws);
+    fit.setProperty("Exclude", exclude);
+    fit.setProperty("Output", "out");
+
+    FunctionDomain_sptr domain;
+    FunctionValues_sptr values;
+
+    FitMW fitmw(&fit, "InputWorkspace");
+    fitmw.declareDatasetProperties("", false);
+    fitmw.createDomain(domain, values);
+
+    TS_ASSERT_EQUALS(values->getFitWeight(0), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(1), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(2), 1);
+    TS_ASSERT_EQUALS(values->getFitWeight(3), 1);
+    TS_ASSERT_EQUALS(values->getFitWeight(4), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(5), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(6), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(7), 1);
+    TS_ASSERT_EQUALS(values->getFitWeight(8), 1);
+    TS_ASSERT_EQUALS(values->getFitWeight(9), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(10), 0);
+
+    fit.execute();
+    IFunction_sptr fun = fit.getProperty("Function");
+    TS_ASSERT_EQUALS(fun->getParameter("A0"), 1);
+
+    auto out = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(
+        "out_Workspace");
+    TS_ASSERT(out);
+    if (!out)
+      return;
+
+    auto &diff = out->y(2);
+    for (size_t i = 0; i < diff.size(); ++i) {
+      TS_ASSERT_EQUALS(diff[i], 0.0);
+    }
+  }
+
+  void test_exclude_odd_number() {
+    auto ws = WorkspaceCreationHelper::create2DWorkspaceFromFunction(
+        [](double, int) { return 1.0; }, 1, 0.0, 3., 0.5);
+
+    std::vector<double> exclude{-2.0, -1.0, 4.0};
+    Fit fit;
+    fit.initialize();
+    fit.setProperty("Function", "name=FlatBackground");
+    fit.setProperty("InputWorkspace", ws);
+    TS_ASSERT_THROWS(fit.setProperty("Exclude", exclude),
+                     std::invalid_argument);
+  }
+
+  void test_exclude_unordered() {
+    auto ws = WorkspaceCreationHelper::create2DWorkspaceFromFunction(
+        [](double, int) { return 1.0; }, 1, 0.0, 3., 0.5);
+
+    std::vector<double> exclude{-2.0, -1.0, 4.0, 2.0};
+    Fit fit;
+    fit.initialize();
+    fit.setProperty("Function", "name=FlatBackground");
+    fit.setProperty("InputWorkspace", ws);
+    TS_ASSERT_THROWS(fit.setProperty("Exclude", exclude),
+                     std::invalid_argument);
+  }
+
+  void test_exclude_overlapped() {
+    auto ws = WorkspaceCreationHelper::create2DWorkspaceFromFunction(
+        [](double, int) { return 0.0; }, 1, 0.0, 10., 1.0);
+
+    std::vector<double> exclude{-1.0, 1.0, 0.0, 1.0, 9.0, 11.0, 7.5, 9.0};
+    Fit fit;
+    fit.initialize();
+    fit.setProperty("Function", "name=FlatBackground");
+    fit.setProperty("InputWorkspace", ws);
+    fit.setProperty("Exclude", exclude);
+
+    FunctionDomain_sptr domain;
+    FunctionValues_sptr values;
+
+    FitMW fitmw(&fit, "InputWorkspace");
+    fitmw.declareDatasetProperties("", false);
+    fitmw.createDomain(domain, values);
+
+    TS_ASSERT_EQUALS(values->getFitWeight(0), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(1), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(2), 1);
+    TS_ASSERT_EQUALS(values->getFitWeight(3), 1);
+    TS_ASSERT_EQUALS(values->getFitWeight(4), 1);
+    TS_ASSERT_EQUALS(values->getFitWeight(5), 1);
+    TS_ASSERT_EQUALS(values->getFitWeight(6), 1);
+    TS_ASSERT_EQUALS(values->getFitWeight(7), 1);
+    TS_ASSERT_EQUALS(values->getFitWeight(8), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(9), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(10), 0);
+  }
+
+  void test_exclude_overlapped_1() {
+    auto ws = WorkspaceCreationHelper::create2DWorkspaceFromFunction(
+        [](double, int) { return 0.0; }, 1, 0.0, 10., 1.0);
+
+    std::vector<double> exclude{6.0, 8.1, 2.1, 4.3, 4.2, 6.7};
+    Fit fit;
+    fit.initialize();
+    fit.setProperty("Function", "name=FlatBackground");
+    fit.setProperty("InputWorkspace", ws);
+    fit.setProperty("Exclude", exclude);
+
+    FunctionDomain_sptr domain;
+    FunctionValues_sptr values;
+
+    FitMW fitmw(&fit, "InputWorkspace");
+    fitmw.declareDatasetProperties("", false);
+    fitmw.createDomain(domain, values);
+
+    TS_ASSERT_EQUALS(values->getFitWeight(0), 1);
+    TS_ASSERT_EQUALS(values->getFitWeight(1), 1);
+    TS_ASSERT_EQUALS(values->getFitWeight(2), 1);
+    TS_ASSERT_EQUALS(values->getFitWeight(3), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(4), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(5), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(6), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(7), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(8), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(9), 1);
+    TS_ASSERT_EQUALS(values->getFitWeight(10), 1);
+  }
+
+  void test_exclude_overlapped_2() {
+    auto ws = WorkspaceCreationHelper::create2DWorkspaceFromFunction(
+        [](double, int) { return 0.0; }, 1, 0.0, 10., 1.0);
+
+    std::vector<double> exclude{0.0, 2.0, 2.0, 4.0};
+    Fit fit;
+    fit.initialize();
+    fit.setProperty("Function", "name=FlatBackground");
+    fit.setProperty("InputWorkspace", ws);
+    fit.setProperty("Exclude", exclude);
+
+    FunctionDomain_sptr domain;
+    FunctionValues_sptr values;
+
+    FitMW fitmw(&fit, "InputWorkspace");
+    fitmw.declareDatasetProperties("", false);
+    fitmw.createDomain(domain, values);
+
+    TS_ASSERT_EQUALS(values->getFitWeight(0), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(1), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(2), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(3), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(4), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(5), 1);
+    TS_ASSERT_EQUALS(values->getFitWeight(6), 1);
+    TS_ASSERT_EQUALS(values->getFitWeight(7), 1);
+    TS_ASSERT_EQUALS(values->getFitWeight(8), 1);
+    TS_ASSERT_EQUALS(values->getFitWeight(9), 1);
+    TS_ASSERT_EQUALS(values->getFitWeight(10), 1);
+  }
+
+  void test_exclude_jump_into_excluded() {
+    auto ws = WorkspaceCreationHelper::create2DWorkspaceFromFunction(
+        [](double, int) { return 0.0; }, 1, 0.0, 10., 1.0);
+
+    std::vector<double> exclude{0.0, 4.1, 4.3, 11.0};
+    Fit fit;
+    fit.initialize();
+    fit.setProperty("Function", "name=FlatBackground");
+    fit.setProperty("InputWorkspace", ws);
+    fit.setProperty("Exclude", exclude);
+
+    FunctionDomain_sptr domain;
+    FunctionValues_sptr values;
+
+    FitMW fitmw(&fit, "InputWorkspace");
+    fitmw.declareDatasetProperties("", false);
+    fitmw.createDomain(domain, values);
+
+    TS_ASSERT_EQUALS(values->getFitWeight(0), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(1), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(2), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(3), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(4), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(5), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(6), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(7), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(8), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(9), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(10), 0);
+  }
+
+  void test_exclude_jump_over_few_ranges() {
+    auto ws = WorkspaceCreationHelper::create2DWorkspaceFromFunction(
+        [](double, int) { return 0.0; }, 1, 0.0, 10., 1.0);
+
+    std::vector<double> exclude{0.0, 4.1, 4.2, 4.3, 4.4, 4.5, 6.0, 11.0};
+    Fit fit;
+    fit.initialize();
+    fit.setProperty("Function", "name=FlatBackground");
+    fit.setProperty("InputWorkspace", ws);
+    fit.setProperty("Exclude", exclude);
+
+    FunctionDomain_sptr domain;
+    FunctionValues_sptr values;
+
+    FitMW fitmw(&fit, "InputWorkspace");
+    fitmw.declareDatasetProperties("", false);
+    fitmw.createDomain(domain, values);
+
+    TS_ASSERT_EQUALS(values->getFitWeight(0), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(1), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(2), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(3), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(4), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(5), 1);
+    TS_ASSERT_EQUALS(values->getFitWeight(6), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(7), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(8), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(9), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(10), 0);
+  }
+
+  void test_exclude_jump_over_few_ranges_into_excluded() {
+    auto ws = WorkspaceCreationHelper::create2DWorkspaceFromFunction(
+        [](double, int) { return 0.0; }, 1, 0.0, 10., 1.0);
+
+    std::vector<double> exclude{0.0, 4.1, 4.2, 4.3, 4.4, 4.5, 4.9, 11.0};
+    Fit fit;
+    fit.initialize();
+    fit.setProperty("Function", "name=FlatBackground");
+    fit.setProperty("InputWorkspace", ws);
+    fit.setProperty("Exclude", exclude);
+
+    FunctionDomain_sptr domain;
+    FunctionValues_sptr values;
+
+    FitMW fitmw(&fit, "InputWorkspace");
+    fitmw.declareDatasetProperties("", false);
+    fitmw.createDomain(domain, values);
+
+    TS_ASSERT_EQUALS(values->getFitWeight(0), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(1), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(2), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(3), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(4), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(5), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(6), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(7), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(8), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(9), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(10), 0);
+  }
+
+  void test_exclude_almost_empty_range() {
+    auto ws = WorkspaceCreationHelper::create2DWorkspaceFromFunction(
+        [](double, int) { return 0.0; }, 1, 0.0, 10., 1.0);
+
+    std::vector<double> exclude{0.0, 4.1, 5.0, 5.0, 8.0, 10.0};
+    Fit fit;
+    fit.initialize();
+    fit.setProperty("Function", "name=FlatBackground");
+    fit.setProperty("InputWorkspace", ws);
+    fit.setProperty("Exclude", exclude);
+
+    FunctionDomain_sptr domain;
+    FunctionValues_sptr values;
+
+    FitMW fitmw(&fit, "InputWorkspace");
+    fitmw.declareDatasetProperties("", false);
+    fitmw.createDomain(domain, values);
+
+    TS_ASSERT_EQUALS(values->getFitWeight(0), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(1), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(2), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(3), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(4), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(5), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(6), 1);
+    TS_ASSERT_EQUALS(values->getFitWeight(7), 1);
+    TS_ASSERT_EQUALS(values->getFitWeight(8), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(9), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(10), 0);
+  }
+
+  void test_exclude_almost_empty_range_1() {
+    auto ws = WorkspaceCreationHelper::create2DWorkspaceFromFunction(
+        [](double, int) { return 0.0; }, 1, 0.0, 10., 1.0);
+
+    std::vector<double> exclude{0.0, 4.1, 5.0, 5.0};
+    Fit fit;
+    fit.initialize();
+    fit.setProperty("Function", "name=FlatBackground");
+    fit.setProperty("InputWorkspace", ws);
+    fit.setProperty("Exclude", exclude);
+
+    FunctionDomain_sptr domain;
+    FunctionValues_sptr values;
+
+    FitMW fitmw(&fit, "InputWorkspace");
+    fitmw.declareDatasetProperties("", false);
+    fitmw.createDomain(domain, values);
+
+    TS_ASSERT_EQUALS(values->getFitWeight(0), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(1), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(2), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(3), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(4), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(5), 0);
+    TS_ASSERT_EQUALS(values->getFitWeight(6), 1);
+    TS_ASSERT_EQUALS(values->getFitWeight(7), 1);
+    TS_ASSERT_EQUALS(values->getFitWeight(8), 1);
+    TS_ASSERT_EQUALS(values->getFitWeight(9), 1);
+    TS_ASSERT_EQUALS(values->getFitWeight(10), 1);
+  }
 };
 
 class FitMWTestPerformance : public CxxTest::TestSuite {
diff --git a/Framework/CurveFitting/test/FuncMinimizers/DampingMinimizerTest.h b/Framework/CurveFitting/test/FuncMinimizers/DampedGaussNewtonMinimizerTest.h
similarity index 94%
rename from Framework/CurveFitting/test/FuncMinimizers/DampingMinimizerTest.h
rename to Framework/CurveFitting/test/FuncMinimizers/DampedGaussNewtonMinimizerTest.h
index 260c0f58f68658826f4cdbe22325ec2b5d87621c..167850d5c42d12c12f18f8a0a8eae0f253d8286d 100644
--- a/Framework/CurveFitting/test/FuncMinimizers/DampingMinimizerTest.h
+++ b/Framework/CurveFitting/test/FuncMinimizers/DampedGaussNewtonMinimizerTest.h
@@ -1,10 +1,10 @@
-#ifndef CURVEFITTING_DAMPINGTEST_H_
-#define CURVEFITTING_DAMPINGTEST_H_
+#ifndef CURVEFITTING_DAMPEDGAUSSNEWTONTEST_H_
+#define CURVEFITTING_DAMPEDGAUSSNEWTONTEST_H_
 
 #include <cxxtest/TestSuite.h>
 
 #include "MantidCurveFitting/CostFunctions/CostFuncLeastSquares.h"
-#include "MantidCurveFitting/FuncMinimizers/DampingMinimizer.h"
+#include "MantidCurveFitting/FuncMinimizers/DampedGaussNewtonMinimizer.h"
 #include "MantidCurveFitting/Functions/UserFunction.h"
 #include "MantidAPI/FunctionDomain1D.h"
 #include "MantidAPI/FunctionValues.h"
@@ -20,7 +20,7 @@ using namespace Mantid::CurveFitting::Constraints;
 using namespace Mantid::CurveFitting::Functions;
 using namespace Mantid::API;
 
-class DampingMinimizerTest : public CxxTest::TestSuite {
+class DampedGaussNewtonMinimizerTest : public CxxTest::TestSuite {
 public:
   void test_Gaussian() {
     API::FunctionDomain1D_sptr domain(
@@ -49,7 +49,7 @@ public:
         boost::make_shared<CostFuncLeastSquares>();
     costFun->setFittingFunction(fun, domain, values);
 
-    DampingMinimizer s;
+    DampedGaussNewtonMinimizer s;
     s.initialize(costFun);
     TS_ASSERT(s.existsProperty("Damping"));
     double damping = s.getProperty("Damping");
@@ -91,7 +91,7 @@ public:
         boost::make_shared<CostFuncLeastSquares>();
     costFun->setFittingFunction(fun, domain, values);
 
-    DampingMinimizer s;
+    DampedGaussNewtonMinimizer s;
     s.initialize(costFun);
     s.setProperty("Damping", 100.0);
     double damping = s.getProperty("Damping");
@@ -135,7 +135,7 @@ public:
     costFun->setFittingFunction(fun, domain, values);
     TS_ASSERT_EQUALS(costFun->nParams(), 3);
 
-    DampingMinimizer s;
+    DampedGaussNewtonMinimizer s;
     s.initialize(costFun);
     TS_ASSERT(s.minimize());
     TS_ASSERT_DELTA(costFun->val(), 0.2, 0.01);
@@ -175,7 +175,7 @@ public:
     costFun->setFittingFunction(fun, domain, values);
     TS_ASSERT_EQUALS(costFun->nParams(), 3);
 
-    DampingMinimizer s;
+    DampedGaussNewtonMinimizer s;
     s.initialize(costFun);
     TS_ASSERT(s.minimize());
     TS_ASSERT_DELTA(costFun->val(), 0.2, 0.01);
@@ -215,7 +215,7 @@ public:
     costFun->setFittingFunction(fun, domain, values);
     TS_ASSERT_EQUALS(costFun->nParams(), 3);
 
-    DampingMinimizer s;
+    DampedGaussNewtonMinimizer s;
     s.initialize(costFun);
     TS_ASSERT(s.minimize());
     TS_ASSERT_DELTA(costFun->val(), 0.002, 0.01);
@@ -246,17 +246,15 @@ public:
     fun->setParameter("a", 1.);
     fun->setParameter("b", 2.);
 
-    BoundaryConstraint *constraint =
-        new BoundaryConstraint(fun.get(), "a", 0, 0.5);
-
-    fun->addConstraint(constraint);
+    fun->addConstraint(
+        Kernel::make_unique<BoundaryConstraint>(fun.get(), "a", 0, 0.5));
 
     boost::shared_ptr<CostFuncLeastSquares> costFun =
         boost::make_shared<CostFuncLeastSquares>();
     costFun->setFittingFunction(fun, domain, values);
     TS_ASSERT_EQUALS(costFun->nParams(), 2);
 
-    DampingMinimizer s;
+    DampedGaussNewtonMinimizer s;
     s.initialize(costFun);
     TS_ASSERT(s.minimize());
 
@@ -266,4 +264,4 @@ public:
   }
 };
 
-#endif /*CURVEFITTING_DAMPINGTEST_H_*/
+#endif /*CURVEFITTING_DAMPEDGAUSSNEWTONTEST_H_*/
diff --git a/Framework/CurveFitting/test/FuncMinimizers/FABADAMinimizerTest.h b/Framework/CurveFitting/test/FuncMinimizers/FABADAMinimizerTest.h
index 2c61271703237c63d3e0a939bbd523ca9ea3cdf9..a0b922512b962a8609ad6a688df8ec10634ca5f8 100644
--- a/Framework/CurveFitting/test/FuncMinimizers/FABADAMinimizerTest.h
+++ b/Framework/CurveFitting/test/FuncMinimizers/FABADAMinimizerTest.h
@@ -7,6 +7,7 @@
 
 #include "MantidCurveFitting/Algorithms/Fit.h"
 #include "MantidAPI/AlgorithmManager.h"
+#include "MantidAPI/AnalysisDataService.h"
 
 #include "MantidCurveFitting/Functions/ExpDecay.h"
 #include "MantidKernel/PropertyManager.h"
diff --git a/Framework/CurveFitting/test/FuncMinimizers/LevenbergMarquardtMDTest.h b/Framework/CurveFitting/test/FuncMinimizers/LevenbergMarquardtMDTest.h
index 025207624b2fd3ac94d634be7c2447a73c55b0c6..a461030889860d7702624e46ebdf3c7c908d25d7 100644
--- a/Framework/CurveFitting/test/FuncMinimizers/LevenbergMarquardtMDTest.h
+++ b/Framework/CurveFitting/test/FuncMinimizers/LevenbergMarquardtMDTest.h
@@ -210,10 +210,8 @@ public:
     fun->setParameter("a", 1.);
     fun->setParameter("b", 2.);
 
-    BoundaryConstraint *constraint =
-        new BoundaryConstraint(fun.get(), "a", 0, 0.5);
-
-    fun->addConstraint(constraint);
+    fun->addConstraint(
+        Kernel::make_unique<BoundaryConstraint>(fun.get(), "a", 0, 0.5));
 
     boost::shared_ptr<CostFuncLeastSquares> costFun =
         boost::make_shared<CostFuncLeastSquares>();
@@ -250,9 +248,8 @@ public:
 
     // lower bound is made > 0 because function's derivative over "a" at a=0 is
     // 0
-    BoundaryConstraint *constraint =
-        new BoundaryConstraint(fun.get(), "a", 0.001, 2.0);
-    fun->addConstraint(constraint);
+    fun->addConstraint(
+        Kernel::make_unique<BoundaryConstraint>(fun.get(), "a", 0.001, 2.0));
 
     boost::shared_ptr<CostFuncLeastSquares> costFun =
         boost::make_shared<CostFuncLeastSquares>();
diff --git a/Framework/CurveFitting/test/FuncMinimizers/LevenbergMarquardtTest.h b/Framework/CurveFitting/test/FuncMinimizers/LevenbergMarquardtTest.h
index 8bd02b865de4019d819e676a8afd1ab41a7afdee..9815ceebd4394afd5fa3ed6a7941ed8061255ea1 100644
--- a/Framework/CurveFitting/test/FuncMinimizers/LevenbergMarquardtTest.h
+++ b/Framework/CurveFitting/test/FuncMinimizers/LevenbergMarquardtTest.h
@@ -243,10 +243,8 @@ public:
     fun->setParameter("a", 1.);
     fun->setParameter("b", 2.);
 
-    BoundaryConstraint *constraint =
-        new BoundaryConstraint(fun.get(), "a", 0, 0.5);
-
-    fun->addConstraint(constraint);
+    fun->addConstraint(
+        Kernel::make_unique<BoundaryConstraint>(fun.get(), "a", 0, 0.5));
 
     boost::shared_ptr<CostFuncLeastSquares> costFun =
         boost::make_shared<CostFuncLeastSquares>();
@@ -283,9 +281,8 @@ public:
 
     // lower bound is made > 0 because function's derivative over "a" at a=0 is
     // 0
-    BoundaryConstraint *constraint =
-        new BoundaryConstraint(fun.get(), "a", 0.001, 2.0);
-    fun->addConstraint(constraint);
+    fun->addConstraint(
+        Kernel::make_unique<BoundaryConstraint>(fun.get(), "a", 0.001, 2.0));
 
     boost::shared_ptr<CostFuncLeastSquares> costFun =
         boost::make_shared<CostFuncLeastSquares>();
diff --git a/Framework/CurveFitting/test/FunctionDomain1DSpectrumCreatorTest.h b/Framework/CurveFitting/test/FunctionDomain1DSpectrumCreatorTest.h
index 4a7ca5b4c232878898be04eadc7f901275966757..82a877ce301905e96e5f170108944109a590bb03 100644
--- a/Framework/CurveFitting/test/FunctionDomain1DSpectrumCreatorTest.h
+++ b/Framework/CurveFitting/test/FunctionDomain1DSpectrumCreatorTest.h
@@ -54,7 +54,7 @@ public:
     TestableFunctionDomain1DSpectrumCreator creator;
 
     MatrixWorkspace_sptr matrixWs =
-        WorkspaceCreationHelper::Create2DWorkspace123(10, 15);
+        WorkspaceCreationHelper::create2DWorkspace123(10, 15);
     creator.setMatrixWorkspace(matrixWs);
 
     TS_ASSERT_EQUALS(creator.m_matrixWorkspace->getNumberHistograms(), 10);
@@ -70,7 +70,7 @@ public:
     TS_ASSERT_THROWS(creator.throwIfWorkspaceInvalid(), std::invalid_argument);
 
     creator.setMatrixWorkspace(
-        WorkspaceCreationHelper::Create2DWorkspace123(10, 15));
+        WorkspaceCreationHelper::create2DWorkspace123(10, 15));
     // still throws, since workspace index has not been set explicitly.
     TS_ASSERT_THROWS(creator.throwIfWorkspaceInvalid(), std::invalid_argument);
 
@@ -85,13 +85,13 @@ public:
   void testGetDomainSize() {
     FunctionDomain1DSpectrumCreator creator;
     creator.setMatrixWorkspace(
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(1, 5, 0.0, 1.0));
+        WorkspaceCreationHelper::create2DWorkspaceBinned(1, 5, 0.0, 1.0));
     creator.setWorkspaceIndex(0);
 
     TS_ASSERT_EQUALS(creator.getDomainSize(), 5);
 
     creator.setMatrixWorkspace(
-        WorkspaceCreationHelper::Create2DWorkspace123(1, 15));
+        WorkspaceCreationHelper::create2DWorkspace123(1, 15));
 
     TS_ASSERT_EQUALS(creator.getDomainSize(), 15);
   }
@@ -99,7 +99,7 @@ public:
   void testCreateDomain() {
     TestableFunctionDomain1DSpectrumCreator creator;
     creator.setMatrixWorkspace(
-        WorkspaceCreationHelper::Create2DWorkspace123(1, 5));
+        WorkspaceCreationHelper::create2DWorkspace123(1, 5));
     creator.setWorkspaceIndex(0);
 
     FunctionDomain_sptr domain;
@@ -130,4 +130,4 @@ private:
   };
 };
 
-#endif /* MANTID_CURVEFITTING_FUNCTIONDOMAIN1DSPECTRUMCREATORTEST_H_ */
\ No newline at end of file
+#endif /* MANTID_CURVEFITTING_FUNCTIONDOMAIN1DSPECTRUMCREATORTEST_H_ */
diff --git a/Framework/CurveFitting/test/FunctionFactoryConstraintTest.h b/Framework/CurveFitting/test/FunctionFactoryConstraintTest.h
index 6b77e7d3e525db951bc15317f66585cabc308379..1a2aba36b775eb8a2fff21c66474ec01cc68aab8 100644
--- a/Framework/CurveFitting/test/FunctionFactoryConstraintTest.h
+++ b/Framework/CurveFitting/test/FunctionFactoryConstraintTest.h
@@ -330,22 +330,27 @@ public:
     IFunction_sptr fun1 =
         FunctionFactory::Instance().createInitialized(fun->asString());
 
-    fun1->setParameter(0, 0.);
-    fun1->setParameter(1, 0.);
+    fun1->setParameter(0, 1.);
+    fun1->setParameter(1, 2.);
     fun1->setParameter(2, 0.);
     fun1->setParameter(3, 789);
 
-    TS_ASSERT_EQUALS(fun1->getParameter(0), 0.);
-    TS_ASSERT_EQUALS(fun1->getParameter(1), 0.);
+    TS_ASSERT_EQUALS(fun1->getParameter(0), 1.);
+    TS_ASSERT_EQUALS(fun1->getParameter(1), 2.);
     TS_ASSERT_EQUALS(fun1->getParameter(2), 0.);
     TS_ASSERT_EQUALS(fun1->getParameter(3), 789);
 
     fun1->applyTies();
 
-    TS_ASSERT_EQUALS(fun1->getParameter(0), 14.);
-    TS_ASSERT_EQUALS(fun1->getParameter(1), 14.);
-    TS_ASSERT_EQUALS(fun1->getParameter(2), 28.);
+    TS_ASSERT_EQUALS(fun1->getParameter(0), 1.);
+    TS_ASSERT_EQUALS(fun1->getParameter(1), 2.);
+    TS_ASSERT_EQUALS(fun1->getParameter(2), 3.);
     TS_ASSERT_EQUALS(fun1->getParameter(3), 789);
+
+    TS_ASSERT(fun1->isFixed(0));
+    TS_ASSERT(fun1->isFixed(1));
+    TS_ASSERT(fun1->isFixed(2));
+    TS_ASSERT(!fun1->isFixed(3));
   }
 };
 
diff --git a/Framework/CurveFitting/test/FunctionParameterDecoratorFitTest.h b/Framework/CurveFitting/test/FunctionParameterDecoratorFitTest.h
index 6588d3fd3592b8dee328318757db78144c1092b4..375f273bd9dc14bd7e0ee11cc0afccb29d840e2d 100644
--- a/Framework/CurveFitting/test/FunctionParameterDecoratorFitTest.h
+++ b/Framework/CurveFitting/test/FunctionParameterDecoratorFitTest.h
@@ -75,7 +75,7 @@ public:
 
   void testFit() {
     Workspace2D_sptr ws =
-        WorkspaceCreationHelper::Create1DWorkspaceConstant(20, 1.5, 0.5);
+        WorkspaceCreationHelper::create1DWorkspaceConstant(20, 1.5, 0.5);
 
     FunctionParameterDecorator_sptr fn =
         boost::make_shared<SimpleFunctionParameterDecorator>();
diff --git a/Framework/CurveFitting/test/Functions/ChebyshevTest.h b/Framework/CurveFitting/test/Functions/ChebyshevTest.h
index 68db7ff0238679b5e0df9572ad44d1da5517907a..8e388b4896b9d12d7e209d5a847b7fce5addec96 100644
--- a/Framework/CurveFitting/test/Functions/ChebyshevTest.h
+++ b/Framework/CurveFitting/test/Functions/ChebyshevTest.h
@@ -7,6 +7,8 @@
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/WorkspaceFactory.h"
 
+#include <array>
+
 using namespace Mantid::API;
 using Mantid::CurveFitting::Functions::Chebyshev;
 
diff --git a/Framework/CurveFitting/test/Functions/ComptonProfileTestHelpers.h b/Framework/CurveFitting/test/Functions/ComptonProfileTestHelpers.h
index 35385f787049f61aa2c3a2c6c6b9ff6649e06cf6..2504e8eadf6bb2b4112bc22cd14c804f98e2694e 100644
--- a/Framework/CurveFitting/test/Functions/ComptonProfileTestHelpers.h
+++ b/Framework/CurveFitting/test/Functions/ComptonProfileTestHelpers.h
@@ -4,6 +4,7 @@
 #include "MantidAPI/Axis.h"
 #include "MantidGeometry/Instrument/Detector.h"
 #include "MantidGeometry/Objects/ShapeFactory.h"
+#include "MantidIndexing/IndexInfo.h"
 #include "MantidKernel/MersenneTwister.h"
 
 #include "MantidTestHelpers/ComponentCreationHelper.h"
@@ -41,7 +42,7 @@ createTestWorkspace(const size_t nhist, const double x0, const double x1,
                     const double dx, const bool singleMassSpectrum,
                     const bool addFoilChanger) {
   bool isHist(false);
-  auto ws2d = WorkspaceCreationHelper::Create2DWorkspaceFromFunction(
+  auto ws2d = WorkspaceCreationHelper::create2DWorkspaceFromFunction(
       ones(), static_cast<int>(nhist), x0, x1, dx, isHist);
   ws2d->getAxis(0)->setUnit("TOF");
   if (singleMassSpectrum) {
@@ -85,13 +86,10 @@ createTestWorkspace(const size_t nhist, const double x0, const double x1,
   }
 
   // Link workspace with detector
-  for (size_t i = 0; i < nhist; ++i) {
-    const Mantid::specnum_t specID = static_cast<Mantid::specnum_t>(id + i);
-    auto &spec = ws2d->getSpectrum(i);
-    spec.setSpectrumNo(specID);
-    spec.clearDetectorIDs();
-    spec.addDetectorID(id);
-  }
+  Mantid::Indexing::IndexInfo indexInfo(nhist);
+  indexInfo.setDetectorIDs(std::vector<Mantid::detid_t>(nhist, id));
+  ws2d->setIndexInfo(indexInfo);
+
   return ws2d;
 }
 
diff --git a/Framework/CurveFitting/test/Functions/CrystalFieldHeatCapacityTest.h b/Framework/CurveFitting/test/Functions/CrystalFieldHeatCapacityTest.h
new file mode 100644
index 0000000000000000000000000000000000000000..d78f5edce30e2f601d2f3f984266361c3be2f7cd
--- /dev/null
+++ b/Framework/CurveFitting/test/Functions/CrystalFieldHeatCapacityTest.h
@@ -0,0 +1,80 @@
+#ifndef CRYSTALFIELDHEATCAPACITYTEST_H_
+#define CRYSTALFIELDHEATCAPACITYTEST_H_
+
+#include <cxxtest/TestSuite.h>
+
+#include "MantidAPI/FunctionDomain1D.h"
+#include "MantidAPI/FunctionValues.h"
+#include "MantidAPI/FunctionFactory.h"
+#include "MantidAPI/ParameterTie.h"
+#include "MantidCurveFitting/Functions/CrystalFieldHeatCapacity.h"
+
+using namespace Mantid;
+using namespace Mantid::API;
+using namespace Mantid::CurveFitting;
+using namespace Mantid::CurveFitting::Functions;
+
+class CrystalFieldHeatCapacityTest : public CxxTest::TestSuite {
+public:
+  void test_evaluate() {
+    CrystalFieldHeatCapacity fun;
+    fun.setParameter("B20", 0.37737);
+    fun.setParameter("B22", 3.9770);
+    fun.setParameter("B40", -0.031787);
+    fun.setParameter("B42", -0.11611);
+    fun.setParameter("B44", -0.12544);
+    fun.setAttributeValue("Ion", "Ce");
+    FunctionDomain1DVector x(1.0, 300.0, 100);
+    FunctionValues y(x);
+    fun.function(x, y);
+
+    // Test function values obtained from McPhase, interpolated by two cubics
+    auto testFun1 = FunctionFactory::Instance().createInitialized(
+        "name=UserFunction,Formula=a*x*x*x+b*x*x+c*x+d,"
+        "a=6.1504e-6,b=2.4075e-5,c=-7.9692e-3,d=5.9915e-2");
+    FunctionValues t1(x);
+    testFun1->function(x, t1);
+    auto testFun2 = FunctionFactory::Instance().createInitialized(
+        "name=UserFunction,Formula=a*x*x*x+b*x*x+c*x+d,"
+        "a=1.6632e-6,b=-1.1572e-3,c=0.24439,d=-10.351");
+    FunctionValues t2(x);
+    testFun2->function(x, t2);
+
+    for (size_t i = 0; i < x.size(); ++i) {
+      // Below 80K use polynomial 1, above use polynomial 2
+      TS_ASSERT_DELTA(y[i], (x[i] < 80) ? t1[i] : t2[i], 0.2);
+    }
+  }
+
+  void test_factory() {
+    std::string funDef =
+        "name=CrystalFieldHeatCapacity,Ion=Ce,Symmetry=C2v,"
+        "B20=0.37,B22=3.9, B40=-0.03,B42=-0.1,B44=-0.12, "
+        "ties=(BmolX=0,BmolY=0,BmolZ=0,BextX=0,BextY=0,BextZ=BextX)";
+    auto fun = FunctionFactory::Instance().createInitialized(funDef);
+    TS_ASSERT(fun);
+    TS_ASSERT_EQUALS(fun->name(), "CrystalFieldHeatCapacity");
+    TS_ASSERT_EQUALS(fun->getAttribute("Ion").asString(), "Ce");
+    TS_ASSERT_EQUALS(fun->getAttribute("Symmetry").asString(), "C2v");
+    TS_ASSERT_EQUALS(fun->getParameter("B20"), 0.37);
+    TS_ASSERT_EQUALS(fun->getParameter("B42"), -0.1);
+
+    auto i = fun->parameterIndex("BextZ");
+    auto tie = fun->getTie(i);
+    TS_ASSERT(tie);
+    if (tie) {
+      TS_ASSERT_EQUALS(tie->asString(), "BextZ=BextX");
+    }
+
+    size_t nTies = 0;
+    for (size_t i = 0; i < fun->nParams(); ++i) {
+      auto tie = fun->getTie(i);
+      if (tie) {
+        ++nTies;
+      }
+    }
+    TS_ASSERT_EQUALS(nTies, 1); // Fixed values not ties.
+  }
+};
+
+#endif /*CRYSTALFIELDHEATCAPACITYTEST_H_*/
diff --git a/Framework/CurveFitting/test/Functions/CrystalFieldMagnetisationTest.h b/Framework/CurveFitting/test/Functions/CrystalFieldMagnetisationTest.h
new file mode 100644
index 0000000000000000000000000000000000000000..52a04f00ac9a8b8c98bd1ae46f85a1b6af514d1c
--- /dev/null
+++ b/Framework/CurveFitting/test/Functions/CrystalFieldMagnetisationTest.h
@@ -0,0 +1,77 @@
+#ifndef CRYSTALFIELDMAGNETISATIONTEST_H_
+#define CRYSTALFIELDMAGNETISATIONTEST_H_
+
+#include <cxxtest/TestSuite.h>
+
+#include "MantidAPI/FunctionDomain1D.h"
+#include "MantidAPI/FunctionValues.h"
+#include "MantidAPI/FunctionFactory.h"
+#include "MantidAPI/ParameterTie.h"
+#include "MantidCurveFitting/Functions/CrystalFieldMagnetisation.h"
+
+using namespace Mantid;
+using namespace Mantid::API;
+using namespace Mantid::CurveFitting;
+using namespace Mantid::CurveFitting::Functions;
+
+class CrystalFieldMagnetisationTest : public CxxTest::TestSuite {
+public:
+  void test_evaluate() {
+    CrystalFieldMagnetisation fun;
+    fun.setParameter("B20", 0.37737);
+    fun.setParameter("B22", 3.9770);
+    fun.setParameter("B40", -0.031787);
+    fun.setParameter("B42", -0.11611);
+    fun.setParameter("B44", -0.12544);
+    fun.setAttributeValue("Ion", "Ce");
+    fun.setAttributeValue("Unit", "bohr");
+    fun.setAttributeValue("Hdir", std::vector<double>{1., 1., 1.});
+    fun.setAttributeValue("Temperature", 10.);
+    FunctionDomain1DVector x(0.0, 30.0, 100);
+    FunctionValues y(x);
+    fun.function(x, y);
+
+    // Test values obtained from McPhase, interpolated by a polynomial
+    auto testFun1 = FunctionFactory::Instance().createInitialized(
+        "name=UserFunction,Formula=a*x*x*x+b*x*x+c*x+d,"
+        "a=4.75436e-5,b=-4.10695e-3,c=0.12358,d=-2.2236e-2");
+    FunctionValues t(x);
+    testFun1->function(x, t);
+
+    for (size_t i = 0; i < x.size(); ++i) {
+      TS_ASSERT_DELTA(y[i], t[i], 0.05);
+    }
+  }
+
+  void test_factory() {
+    std::string funDef =
+        "name=CrystalFieldMagnetisation,Ion=Nd,Symmetry=C2v,"
+        "Unit=bohr,Hdir=(1,-1,2),Temperature=11.5,powder=1,"
+        "B20=0.37,B22=3.9, B40=-0.03,B42=-0.1,B44=-0.12, "
+        "ties=(BmolX=0,BmolY=0,BmolZ=0,BextX=0,BextY=0,BextZ=0)";
+    auto fun = FunctionFactory::Instance().createInitialized(funDef);
+    TS_ASSERT(fun);
+    TS_ASSERT_EQUALS(fun->name(), "CrystalFieldMagnetisation");
+    TS_ASSERT_EQUALS(fun->getAttribute("Ion").asString(), "Nd");
+    TS_ASSERT_EQUALS(fun->getAttribute("Symmetry").asString(), "C2v");
+    TS_ASSERT_EQUALS(fun->getAttribute("Temperature").asDouble(), 11.5);
+    TS_ASSERT_EQUALS(fun->getAttribute("Unit").asString(), "bohr");
+    auto Hdir = fun->getAttribute("Hdir").asVector();
+    TS_ASSERT_EQUALS(Hdir[0], 1);
+    TS_ASSERT_EQUALS(Hdir[1], -1);
+    TS_ASSERT_EQUALS(Hdir[2], 2);
+    TS_ASSERT_EQUALS(fun->getAttribute("powder").asBool(), true);
+    TS_ASSERT_EQUALS(fun->getParameter("B20"), 0.37);
+
+    size_t nTies = 0;
+    for (size_t i = 0; i < fun->nParams(); ++i) {
+      auto tie = fun->getTie(i);
+      if (tie) {
+        ++nTies;
+      }
+    }
+    TS_ASSERT_EQUALS(nTies, 0);
+  }
+};
+
+#endif /*CRYSTALFIELDMAGNETISATIONTEST_H_*/
diff --git a/Framework/CurveFitting/test/Functions/CrystalFieldMomentTest.h b/Framework/CurveFitting/test/Functions/CrystalFieldMomentTest.h
new file mode 100644
index 0000000000000000000000000000000000000000..ed7bfc2371473ddb5cb1565aa850a00494766891
--- /dev/null
+++ b/Framework/CurveFitting/test/Functions/CrystalFieldMomentTest.h
@@ -0,0 +1,80 @@
+#ifndef CRYSTALFIELDMOMENTTEST_H_
+#define CRYSTALFIELDMOMENTTEST_H_
+
+#include <cxxtest/TestSuite.h>
+
+#include "MantidAPI/FunctionDomain1D.h"
+#include "MantidAPI/FunctionValues.h"
+#include "MantidAPI/FunctionFactory.h"
+#include "MantidAPI/ParameterTie.h"
+#include "MantidCurveFitting/Functions/CrystalFieldMoment.h"
+
+using namespace Mantid;
+using namespace Mantid::API;
+using namespace Mantid::CurveFitting;
+using namespace Mantid::CurveFitting::Functions;
+
+class CrystalFieldMomentTest : public CxxTest::TestSuite {
+public:
+  void test_evaluate() {
+    CrystalFieldMoment fun;
+    fun.setParameter("B20", 0.37737);
+    fun.setParameter("B22", 3.9770);
+    fun.setParameter("B40", -0.031787);
+    fun.setParameter("B42", -0.11611);
+    fun.setParameter("B44", -0.12544);
+    fun.setAttributeValue("Ion", "Ce");
+    fun.setAttributeValue("Unit", "cgs");
+    fun.setAttributeValue("Hdir", std::vector<double>{1., 1., 1.});
+    fun.setAttributeValue("Hmag", 1.);
+    fun.setAttributeValue("inverse", true);
+    FunctionDomain1DVector x(10.0, 300.0, 100);
+    FunctionValues y(x);
+    fun.function(x, y);
+
+    // Test values obtained from McPhase, interpolated by a polynomial
+    auto testFun1 = FunctionFactory::Instance().createInitialized(
+        "name=UserFunction,Formula=a*x*x*x+b*x*x+c*x+d,"
+        "a=2.22169e-6,b=-1.310952e-3,c=0.90995,d=1.61086");
+    FunctionValues t(x);
+    testFun1->function(x, t);
+
+    for (size_t i = 0; i < x.size(); ++i) {
+      // Units is cgs, McPhase calculations in bohr magnetons.
+      TS_ASSERT_DELTA(y[i] * 0.55849 / t[i], 1, 0.1);
+    }
+  }
+
+  void test_factory() {
+    std::string funDef =
+        "name=CrystalFieldMoment,Ion=Pr,Symmetry=C2v,"
+        "Unit=cgs,Hmag=10,Hdir=(1,0,-1),"
+        "B20=0.37,B22=3.9, B40=-0.03,B42=-0.1,B44=-0.12, "
+        "ties=(BmolX=0,BmolY=0,BmolZ=0,BextX=0,BextY=0,BextZ=0)";
+    auto fun = FunctionFactory::Instance().createInitialized(funDef);
+    TS_ASSERT(fun);
+    TS_ASSERT_EQUALS(fun->name(), "CrystalFieldMoment");
+    TS_ASSERT_EQUALS(fun->getAttribute("Ion").asString(), "Pr");
+    TS_ASSERT_EQUALS(fun->getAttribute("Symmetry").asString(), "C2v");
+    TS_ASSERT_EQUALS(fun->getAttribute("Unit").asString(), "cgs");
+    TS_ASSERT_EQUALS(fun->getAttribute("Hmag").asDouble(), 10.);
+    auto Hdir = fun->getAttribute("Hdir").asVector();
+    TS_ASSERT_EQUALS(Hdir[0], 1);
+    TS_ASSERT_EQUALS(Hdir[1], 0);
+    TS_ASSERT_EQUALS(Hdir[2], -1);
+    TS_ASSERT_EQUALS(fun->getAttribute("inverse").asBool(), false);
+    TS_ASSERT_EQUALS(fun->getAttribute("powder").asBool(), false);
+    TS_ASSERT_EQUALS(fun->getParameter("B20"), 0.37);
+
+    size_t nTies = 0;
+    for (size_t i = 0; i < fun->nParams(); ++i) {
+      auto tie = fun->getTie(i);
+      if (tie) {
+        ++nTies;
+      }
+    }
+    TS_ASSERT_EQUALS(nTies, 0);
+  }
+};
+
+#endif /*CRYSTALFIELDMOMENTTEST_H_*/
diff --git a/Framework/CurveFitting/test/Functions/CrystalFieldMultiSpectrumTest.h b/Framework/CurveFitting/test/Functions/CrystalFieldMultiSpectrumTest.h
index a9dae687882382ad017703b9d1b897d2edeb1193..5a8fff0339917e708fdec74900e29803172e996d 100644
--- a/Framework/CurveFitting/test/Functions/CrystalFieldMultiSpectrumTest.h
+++ b/Framework/CurveFitting/test/Functions/CrystalFieldMultiSpectrumTest.h
@@ -9,6 +9,7 @@
 #include "MantidAPI/FunctionFactory.h"
 #include "MantidAPI/FunctionValues.h"
 #include "MantidAPI/IConstraint.h"
+#include "MantidAPI/JointDomain.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/ParameterTie.h"
 #include "MantidAPI/WorkspaceFactory.h"
@@ -145,16 +146,81 @@ public:
         "Workspace_0");
     TS_ASSERT(out);
     TS_ASSERT_EQUALS(out->getNumberHistograms(), 3);
-    TS_ASSERT_DELTA(out->readY(1)[0], 1.094 * 2.0 * c_mbsr, 0.001 * c_mbsr);
-    TS_ASSERT_DELTA(out->readY(1)[1], 0.738 * 2.0 * c_mbsr, 0.001 * c_mbsr);
-    TS_ASSERT_DELTA(out->readY(1)[2], 0.373 * 2.0 * c_mbsr, 0.001 * c_mbsr);
+    TS_ASSERT_DELTA(out->readY(1)[0], 1.094 * 2.0 * c_mbsr, 0.002 * c_mbsr);
+    TS_ASSERT_DELTA(out->readY(1)[1], 0.738 * 2.0 * c_mbsr, 0.002 * c_mbsr);
+    TS_ASSERT_DELTA(out->readY(1)[2], 0.373 * 2.0 * c_mbsr, 0.002 * c_mbsr);
     out = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(
         "Workspace_1");
     TS_ASSERT(out);
     TS_ASSERT_EQUALS(out->getNumberHistograms(), 3);
-    TS_ASSERT_DELTA(out->readY(1)[0], 1.094 * 3.3 * c_mbsr, 0.001 * c_mbsr);
-    TS_ASSERT_DELTA(out->readY(1)[1], 0.738 * 3.3 * c_mbsr, 0.001 * c_mbsr);
-    TS_ASSERT_DELTA(out->readY(1)[2], 0.3734 * 3.3 * c_mbsr, 0.001 * c_mbsr);
+    TS_ASSERT_DELTA(out->readY(1)[0], 1.094 * 3.3 * c_mbsr, 0.003 * c_mbsr);
+    TS_ASSERT_DELTA(out->readY(1)[1], 0.738 * 3.3 * c_mbsr, 0.003 * c_mbsr);
+    TS_ASSERT_DELTA(out->readY(1)[2], 0.373 * 3.3 * c_mbsr, 0.003 * c_mbsr);
+    AnalysisDataService::Instance().clear();
+  }
+
+  void test_evaluate_physprops() {
+    auto funStr = "name=CrystalFieldMultiSpectrum,Ion=Ce,Temperatures=(44,"
+                  "50,1,10,1),ToleranceIntensity=0.001,B20=0.37737,B22=3.9770,"
+                  "B40=-0.031787,B42=-0.11611,B44=-0.12544,"
+                  "PhysicalProperties=(0,1,2,3,4)," // INS, Cp, chi, M(H), M(T)
+                  "Hdir3=(1,1,1), Hmag4=1, Unit4=cgs, Lambda2=0.0000001,"
+                  "f0.f1.FWHM=1.6,f0.f2.FWHM=2.0,f0.f3.FWHM=2.3";
+    auto ws = createWorkspace();
+    auto alg = AlgorithmFactory::Instance().create("EvaluateFunction", -1);
+    alg->initialize();
+    alg->setPropertyValue("Function", funStr);
+    alg->setProperty("InputWorkspace", ws);
+    alg->setProperty("InputWorkspace_1", ws);
+    alg->setProperty("InputWorkspace_2", ws);
+    alg->setProperty("InputWorkspace_3", ws);
+    alg->setProperty("InputWorkspace_4", ws);
+    alg->setProperty("OutputWorkspace", "out");
+    alg->execute();
+
+    // Test the INS spectrum
+    auto out0 = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(
+        "Workspace_0");
+    TS_ASSERT(out0);
+    TS_ASSERT_EQUALS(out0->getNumberHistograms(), 3);
+    TS_ASSERT_DELTA(out0->readY(1)[0], 1.094 * c_mbsr, 0.001 * c_mbsr);
+    TS_ASSERT_DELTA(out0->readY(1)[1], 0.738 * c_mbsr, 0.001 * c_mbsr);
+    TS_ASSERT_DELTA(out0->readY(1)[2], 0.373 * c_mbsr, 0.001 * c_mbsr);
+    // Test the heat capacity calculation
+    auto out1 = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(
+        "Workspace_1");
+    TS_ASSERT(out1);
+    TS_ASSERT_EQUALS(out1->getNumberHistograms(), 3);
+    TS_ASSERT_DELTA(out1->readY(1)[50], 0.006, 0.001);
+    TS_ASSERT_DELTA(out1->readY(1)[60], 0.032, 0.001);
+    TS_ASSERT_DELTA(out1->readY(1)[70], 0.103, 0.001);
+    // Test the susceptibility calculation
+    auto out2 = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(
+        "Workspace_2");
+    TS_ASSERT(out2);
+    TS_ASSERT_EQUALS(out2->getNumberHistograms(), 3);
+    // Susceptibility default outputs in cgs units.
+    TS_ASSERT_DELTA(out2->readY(1)[50], 0.00236231, 0.0000001);
+    TS_ASSERT_DELTA(out2->readY(1)[60], 0.00233006, 0.0000001);
+    TS_ASSERT_DELTA(out2->readY(1)[70], 0.00230932, 0.0000001);
+    // Test the magnetisation calculation
+    auto out3 = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(
+        "Workspace_3");
+    TS_ASSERT(out3);
+    TS_ASSERT_EQUALS(out3->getNumberHistograms(), 3);
+    TS_ASSERT_DELTA(out3->readY(1)[1], 0.05754, 0.0001);
+    TS_ASSERT_DELTA(out3->readY(1)[5], 0.28307, 0.0001);
+    TS_ASSERT_DELTA(out3->readY(1)[10], 0.53932, 0.0001);
+    // Test the moment vs temperature calculation
+    auto out4 = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(
+        "Workspace_4");
+    TS_ASSERT(out4);
+    TS_ASSERT_EQUALS(out4->getNumberHistograms(), 3);
+    // SI and cgs susceptibility differ by factor of 10.
+    // Dataset 2 in cgs, dataset 4 in SI.
+    TS_ASSERT_DELTA(out4->readY(1)[51], out2->readY(1)[51], 1e-4);
+    TS_ASSERT_DELTA(out4->readY(1)[61], out2->readY(1)[61], 1e-4);
+    TS_ASSERT_DELTA(out4->readY(1)[71], out2->readY(1)[71], 1e-4);
     AnalysisDataService::Instance().clear();
   }
 
@@ -328,6 +394,91 @@ public:
     TS_ASSERT_THROWS_NOTHING(fun.buildTargetFunction());
   }
 
+  void test_monte_carlo() {
+    CrystalFieldMultiSpectrum fun;
+    fun.setParameter("B20", 0.37737);
+    fun.setParameter("B22", 3.9770);
+    fun.setParameter("B40", -0.031787);
+    fun.setParameter("B42", -0.11611);
+    fun.setParameter("B44", -0.12544);
+    fun.setAttributeValue("Ion", "Ce");
+    fun.setAttributeValue("Temperatures", std::vector<double>{44.0, 50.0});
+    fun.setAttributeValue("FWHMs", std::vector<double>{1.0, 1.5});
+    auto ws = createWorkspace(fun, 0, 50, 100);
+
+    auto mc = AlgorithmFactory::Instance().create("EstimateFitParameters", -1);
+    mc->initialize();
+    mc->setRethrows(true);
+    mc->setPropertyValue(
+        "Function",
+        "name=CrystalFieldMultiSpectrum,Ion=Ce,FixAllPeaks=1,"
+        "Symmetry=C2v,Temperatures=(44.0, 50.0),FWHMs=(1.0, 1.0),NPeaks=3,"
+        "constraints=(0<B20<0.5,3<B22<4,-0.1<B40<0.0,-0.1<B42<0.0,-0.1<B44<0."
+        "0)");
+    mc->setProperty("InputWorkspace", ws);
+    mc->setProperty("WorkspaceIndex", 0);
+    mc->setProperty("InputWorkspace_1", ws);
+    mc->setProperty("WorkspaceIndex_1", 1);
+    mc->setProperty("NSamples", 1000);
+    mc->setProperty("Constraints", "0<f0.f2.PeakCentre<50,0<f0.f3.PeakCentre<"
+                                   "50,0<f1.f2.PeakCentre<50,0<f1.f3."
+                                   "PeakCentre<50");
+    mc->execute();
+    IFunction_sptr func = mc->getProperty("Function");
+    auto fit = AlgorithmFactory::Instance().create("Fit", -1);
+    fit->initialize();
+    fit->setProperty("Function", func);
+    fit->setProperty("InputWorkspace", ws);
+    fit->setProperty("WorkspaceIndex", 0);
+    fit->setProperty("InputWorkspace_1", ws);
+    fit->setProperty("WorkspaceIndex_1", 1);
+    fit->execute();
+    double chi2 = fit->getProperty("OutputChi2overDoF");
+    TS_ASSERT_LESS_THAN(chi2, 100.0);
+  }
+
+  void test_ties_in_composite_function() {
+    std::string funDef =
+        "name=CrystalFieldMultiSpectrum,Ion=Ce,Symmetry=C2v,Temperatures=(44.0,"
+        "50),FWHMs=(1.1,0.9),B44=-0.115325956893,B40=0.0844136192563,B42=-0."
+        "459507287606,B22=4.36779676967;name=CrystalFieldMultiSpectrum,Ion=Pr,"
+        "Symmetry=C2v,Temperatures=(44.0,50),FWHMs=(1.1,0.9),B44=-0."
+        "115325956893,B40=0.0844136192563,B42=-0.459507287606,B22=4."
+        "36779676967;ties=(f1.IntensityScaling0=2.0*f0.IntensityScaling0,f1."
+        "IntensityScaling1=2.0*f0.IntensityScaling1,f0.f0.f1.FWHM=f1.f0.f1."
+        "FWHM/2)";
+    auto fun = FunctionFactory::Instance().createInitialized(funDef);
+    {
+      auto index = fun->parameterIndex("f1.IntensityScaling0");
+      auto tie = fun->getTie(index);
+      TS_ASSERT(tie);
+      if (!tie) {
+        return;
+      }
+      TS_ASSERT_EQUALS(tie->asString(),
+                       "f1.IntensityScaling0=2.0*f0.IntensityScaling0");
+    }
+    {
+      auto index = fun->parameterIndex("f1.IntensityScaling1");
+      auto tie = fun->getTie(index);
+      TS_ASSERT(tie);
+      if (!tie) {
+        return;
+      }
+      TS_ASSERT_EQUALS(tie->asString(),
+                       "f1.IntensityScaling1=2.0*f0.IntensityScaling1");
+    }
+    {
+      auto index = fun->parameterIndex("f0.f0.f1.FWHM");
+      auto tie = fun->getTie(index);
+      TS_ASSERT(tie);
+      if (!tie) {
+        return;
+      }
+      TS_ASSERT_EQUALS(tie->asString(), "f0.f0.f1.FWHM=f1.f0.f1.FWHM/2");
+    }
+  }
+
 private:
   Workspace_sptr createWorkspace() {
     auto ws = WorkspaceFactory::Instance().create("Workspace2D", 1, 100, 100);
@@ -352,6 +503,28 @@ private:
     }
     return std::make_pair(bc->lower(), bc->upper());
   }
+
+  MatrixWorkspace_sptr createWorkspace(const IFunction &fun, double x0,
+                                       double x1, size_t nbins) {
+    auto nSpec = fun.getNumberDomains();
+    auto ws =
+        WorkspaceFactory::Instance().create("Workspace2D", nSpec, nbins, nbins);
+    JointDomain domain;
+    for (size_t i = 0; i < nSpec; ++i) {
+      auto x = FunctionDomain_sptr(new FunctionDomain1DVector(x0, x1, nbins));
+      domain.addDomain(x);
+    }
+    FunctionValues y(domain);
+    fun.function(domain, y);
+    for (size_t i = 0; i < nSpec; ++i) {
+      auto x = static_cast<const FunctionDomain1DVector &>(domain.getDomain(i));
+      ws->dataX(i) = x.toVector();
+      auto n = x.size();
+      auto from = y.getPointerToCalculated(i * n);
+      ws->dataY(i).assign(from, from + n);
+    }
+    return ws;
+  }
 };
 
 #endif /*CRYSTALFIELDMULTISPECTRUMTEST_H_*/
diff --git a/Framework/CurveFitting/test/Functions/CrystalFieldSpectrumTest.h b/Framework/CurveFitting/test/Functions/CrystalFieldSpectrumTest.h
index 53e8f6ab150cbc6baeab9f4974a2c68563f5b6b5..abd7a8ae4ca724728a458eb254a483aaa208ba94 100644
--- a/Framework/CurveFitting/test/Functions/CrystalFieldSpectrumTest.h
+++ b/Framework/CurveFitting/test/Functions/CrystalFieldSpectrumTest.h
@@ -9,11 +9,13 @@
 #include "MantidAPI/FunctionValues.h"
 #include "MantidAPI/FunctionFactory.h"
 #include "MantidAPI/IConstraint.h"
+#include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/ParameterTie.h"
 #include "MantidCurveFitting/Constraints/BoundaryConstraint.h"
 #include "MantidCurveFitting/Functions/CrystalFieldSpectrum.h"
 #include "MantidCurveFitting/Functions/Gaussian.h"
 #include "MantidCurveFitting/Functions/SimpleChebfun.h"
+#include "MantidTestHelpers/WorkspaceCreationHelper.h"
 
 using namespace Mantid;
 using namespace Mantid::API;
@@ -178,22 +180,19 @@ public:
 
     auto i = fun->parameterIndex("f2.FWHM");
     auto tie = fun->getTie(i);
-    TS_ASSERT(tie);
-    if (tie) {
-      TS_ASSERT_EQUALS(tie->asString(), "f2.FWHM=2.1")
-    }
+    TS_ASSERT(!tie);
+    TS_ASSERT(fun->isFixed(i));
+    TS_ASSERT_EQUALS(fun->getParameter(i), 2.1);
     i = fun->parameterIndex("B60");
     tie = fun->getTie(i);
-    TS_ASSERT(tie);
-    if (tie) {
-      TS_ASSERT_EQUALS(tie->asString(), "B60=0")
-    }
+    TS_ASSERT(!tie);
+    TS_ASSERT(fun->isFixed(i));
+    TS_ASSERT_EQUALS(fun->getParameter(i), 0);
     i = fun->parameterIndex("BmolY");
     tie = fun->getTie(i);
-    TS_ASSERT(tie);
-    if (tie) {
-      TS_ASSERT_EQUALS(tie->asString(), "BmolY=0")
-    }
+    TS_ASSERT(!tie);
+    TS_ASSERT(fun->isFixed(i));
+    TS_ASSERT_EQUALS(fun->getParameter(i), 0);
 
     size_t nTies = 0;
     for (size_t i = 0; i < fun->nParams(); ++i) {
@@ -202,7 +201,7 @@ public:
         ++nTies;
       }
     }
-    TS_ASSERT_EQUALS(nTies, 11);
+    TS_ASSERT_EQUALS(nTies, 0);
   }
 
   void test_constraints() {
@@ -577,6 +576,112 @@ public:
     }
   }
 
+  void test_monte_carlo() {
+    CrystalFieldSpectrum fun;
+    fun.setParameter("B20", 0.37737);
+    fun.setParameter("B22", 3.9770);
+    fun.setParameter("B40", -0.031787);
+    fun.setParameter("B42", -0.11611);
+    fun.setParameter("B44", -0.12544);
+    fun.setAttributeValue("Ion", "Ce");
+    fun.setAttributeValue("Temperature", 44.0);
+    fun.setAttributeValue("FWHM", 1.0);
+    auto ws = createWorkspace(fun, 0, 50, 100);
+    auto mc = AlgorithmFactory::Instance().create("EstimateFitParameters", -1);
+    mc->initialize();
+    mc->setRethrows(true);
+    mc->setPropertyValue(
+        "Function",
+        "name=CrystalFieldSpectrum,Ion=Ce,"
+        "Symmetry=C2v,Temperature=44.0,FWHM=1.0,NPeaks=3,FixAllPeaks=1,"
+        "constraints=(0<B20<2,1<B22<4,-0.1<B40<0.1,-0.1<B42<0.1,-0.1<B44<0.1)");
+    mc->setProperty("InputWorkspace", ws);
+    mc->setProperty("NSamples", 1000);
+    mc->setProperty("Constraints", "0<f2.PeakCentre<50");
+    mc->execute();
+    IFunction_sptr func = mc->getProperty("Function");
+
+    auto fit = AlgorithmFactory::Instance().create("Fit", -1);
+    fit->initialize();
+    fit->setProperty("Function", func);
+    fit->setProperty("InputWorkspace", ws);
+    fit->execute();
+    double chi2 = fit->getProperty("OutputChi2overDoF");
+    TS_ASSERT_LESS_THAN(chi2, 100.0);
+  }
+
+  void test_change_number_of_fixed_params() {
+
+    std::string funDef =
+        "name=CrystalFieldSpectrum,Ion=Ce,Symmetry=C2v,"
+        "Temperature=44,FWHM=1.0,B20=0.37737,B22=3.977,"
+        "B40=-0.031787,B42=-0.11611,B44=-0.12544, "
+        "ties=(B60=0,B62=0,B64=0,B66=0,BmolX=0,BmolY=0,BmolZ=0,"
+        "BextX=0,BextY=0,BextZ=0,f2.FWHM=2.1);"
+        "name=CrystalFieldSpectrum,Ion=Pr,Symmetry=C2v,"
+        "Temperature=44,FWHM=1.0,B20=0.37737,B22=3.977,"
+        "B40=-0.031787,B42=-0.11611,B44=-0.12544, "
+        "ties=(B60=0,B62=0,B64=0,B66=0,BmolX=0,BmolY=0,BmolZ=0,"
+        "BextX=0,BextY=0,BextZ=0)";
+    auto fun = FunctionFactory::Instance().createInitialized(funDef);
+    auto ws = createWorkspace(*fun, -20, 170, 100);
+
+    funDef = "name=CrystalFieldSpectrum,Ion=Ce,Symmetry=C2v,Temperature=44.0,"
+             "ToleranceEnergy=1e-10,ToleranceIntensity=0.1,PeakShape="
+             "Lorentzian,FWHM=1.1,B44=-0.125,B40=-0.03,B42=-0.116,ties=(IB63="
+             "0,IB62=0,IB61=0,IB66=0,IB65=0,IB64=0,IB41=0,IB43=0,IB42=0,IB44="
+             "0,B22=3.977,B21=0,B20=0.37737,IB22=0,IB21=0,BextX=0,BextY=0,"
+             "BextZ=0,B66=0,B63=0,B62=0,B61=0,B60=0,B41=0,B43=0,B65=0,B64=0,"
+             "BmolZ=0,BmolY=0,BmolX=0);name=CrystalFieldSpectrum,Ion=Pr,"
+             "Symmetry=C2v,Temperature=44.0,ToleranceEnergy=1.0,"
+             "ToleranceIntensity=6.0,PeakShape=Lorentzian,FWHM=1.1,B44=-0."
+             "125,B40=-0.03,B42=-0.116,ties=(IB63=0,IB62=0,IB61=0,IB66=0,"
+             "IB65=0,IB64=0,IB41=0,IB43=0,IB42=0,IB44=0,B22=3.977,B21=0,B20="
+             "0.37737,IB22=0,IB21=0,BextX=0,BextY=0,BextZ=0,B66=0,B63=0,B62="
+             "0,B61=0,B60=0,B41=0,B43=0,B65=0,B64=0,BmolZ=0,BmolY=0,BmolX=0)";
+    fun = FunctionFactory::Instance().createInitialized(funDef);
+    auto fit = AlgorithmFactory::Instance().create("Fit", -1);
+    fit->setRethrows(true);
+    fit->initialize();
+    fit->setProperty("Function", fun);
+    fit->setProperty("InputWorkspace", ws);
+    fit->setProperty("Output", "out");
+    TS_ASSERT_THROWS_NOTHING(fit->execute());
+  }
+
+  void test_ties_in_composite_function() {
+    std::string funDef =
+        "name=CrystalFieldSpectrum,Ion=Ce,Symmetry=C2v,Temperature=44.0,"
+        "ToleranceEnergy=1e-10,ToleranceIntensity=0.1,FixAllPeaks=False,"
+        "PeakShape=Lorentzian,FWHM=1.1,B44=-0.12544,B20=0.37737,B22=3.977,B40=-"
+        "0.031787,B42=-0.11611;name=CrystalFieldSpectrum,Ion=Pr,Symmetry=C2v,"
+        "Temperature="
+        "44.0,ToleranceEnergy=1e-10,ToleranceIntensity=0.1,FixAllPeaks=False,"
+        "PeakShape=Lorentzian,FWHM=1.1,B44=-0.12544,B20=0.37737,B22=3.977,B40=-"
+        "0.031787,B42=-0.11611;ties=(f1.IntensityScaling=2.0*f0."
+        "IntensityScaling,f0.f1.FWHM=f1.f2.FWHM/2)";
+    auto fun = FunctionFactory::Instance().createInitialized(funDef);
+    {
+      auto index = fun->parameterIndex("f1.IntensityScaling");
+      auto tie = fun->getTie(index);
+      TS_ASSERT(tie);
+      if (!tie) {
+        return;
+      }
+      TS_ASSERT_EQUALS(tie->asString(),
+                       "f1.IntensityScaling=2.0*f0.IntensityScaling");
+    }
+    {
+      auto index = fun->parameterIndex("f0.f1.FWHM");
+      auto tie = fun->getTie(index);
+      TS_ASSERT(tie);
+      if (!tie) {
+        return;
+      }
+      TS_ASSERT_EQUALS(tie->asString(), "f0.f1.FWHM=f1.f2.FWHM/2");
+    }
+  }
+
 private:
   std::pair<double, double> getBounds(API::IFunction &fun,
                                       const std::string &parName) {
@@ -592,6 +697,18 @@ private:
     }
     return std::make_pair(bc->lower(), bc->upper());
   }
+
+  MatrixWorkspace_sptr createWorkspace(const IFunction &fun, double x0,
+                                       double x1, size_t nbins) {
+    auto ws =
+        WorkspaceFactory::Instance().create("Workspace2D", 1, nbins, nbins);
+    FunctionDomain1DVector x(x0, x1, nbins);
+    FunctionValues y(x);
+    fun.function(x, y);
+    ws->dataX(0) = x.toVector();
+    ws->dataY(0) = y.toVector();
+    return ws;
+  }
 };
 
 #endif /*CRYSTALFIELDSPECTRUMTEST_H_*/
diff --git a/Framework/CurveFitting/test/Functions/CrystalFieldSusceptibilityTest.h b/Framework/CurveFitting/test/Functions/CrystalFieldSusceptibilityTest.h
new file mode 100644
index 0000000000000000000000000000000000000000..04ba3061b85cffc7f066a43ee215cc6dfaf12fbc
--- /dev/null
+++ b/Framework/CurveFitting/test/Functions/CrystalFieldSusceptibilityTest.h
@@ -0,0 +1,77 @@
+#ifndef CRYSTALFIELDSUSCEPTIBILITYTEST_H_
+#define CRYSTALFIELDSUSCEPTIBILITYTEST_H_
+
+#include <cxxtest/TestSuite.h>
+
+#include "MantidAPI/FunctionDomain1D.h"
+#include "MantidAPI/FunctionValues.h"
+#include "MantidAPI/FunctionFactory.h"
+#include "MantidAPI/ParameterTie.h"
+#include "MantidCurveFitting/Functions/CrystalFieldSusceptibility.h"
+
+using namespace Mantid;
+using namespace Mantid::API;
+using namespace Mantid::CurveFitting;
+using namespace Mantid::CurveFitting::Functions;
+
+class CrystalFieldSusceptibilityTest : public CxxTest::TestSuite {
+public:
+  void test_evaluate() {
+    CrystalFieldSusceptibility fun;
+    fun.setParameter("B20", 0.37737);
+    fun.setParameter("B22", 3.9770);
+    fun.setParameter("B40", -0.031787);
+    fun.setParameter("B42", -0.11611);
+    fun.setParameter("B44", -0.12544);
+    fun.setAttributeValue("Ion", "Ce");
+    fun.setAttributeValue("Unit", "bohr");
+    fun.setAttributeValue("Hdir", std::vector<double>{1., 1., 1.});
+    fun.setAttributeValue("inverse", true);
+    FunctionDomain1DVector x(10.0, 300.0, 100);
+    FunctionValues y(x);
+    fun.function(x, y);
+
+    // Test values obtained from McPhase, interpolated by a polynomial
+    auto testFun1 = FunctionFactory::Instance().createInitialized(
+        "name=UserFunction,Formula=a*x*x*x+b*x*x+c*x+d,"
+        "a=2.22169e-6,b=-1.310952e-3,c=0.90995,d=1.61086");
+    FunctionValues t(x);
+    testFun1->function(x, t);
+
+    for (size_t i = 0; i < x.size(); ++i) {
+      TS_ASSERT_DELTA(y[i] / t[i], 1, 0.1);
+    }
+  }
+
+  void test_factory() {
+    std::string funDef =
+        "name=CrystalFieldSusceptibility,Ion=Pr,Symmetry=C2v,"
+        "Unit=SI,Hdir=(1,2,0),inverse=1,"
+        "B20=0.37,B22=3.9, B40=-0.03,B42=-0.1,B44=-0.12,Lambda=-0.2, "
+        "ties=(BmolX=0,BmolY=0,BmolZ=0,BextX=0,BextY=0,BextZ=0)";
+    auto fun = FunctionFactory::Instance().createInitialized(funDef);
+    TS_ASSERT(fun);
+    TS_ASSERT_EQUALS(fun->name(), "CrystalFieldSusceptibility");
+    TS_ASSERT_EQUALS(fun->getAttribute("Ion").asString(), "Pr");
+    TS_ASSERT_EQUALS(fun->getAttribute("Symmetry").asString(), "C2v");
+    TS_ASSERT_EQUALS(fun->getAttribute("Unit").asString(), "SI");
+    auto Hdir = fun->getAttribute("Hdir").asVector();
+    TS_ASSERT_EQUALS(Hdir[0], 1);
+    TS_ASSERT_EQUALS(Hdir[1], 2);
+    TS_ASSERT_EQUALS(Hdir[2], 0);
+    TS_ASSERT_EQUALS(fun->getAttribute("inverse").asBool(), true);
+    TS_ASSERT_EQUALS(fun->getParameter("B20"), 0.37);
+    TS_ASSERT_EQUALS(fun->getParameter("Lambda"), -0.2);
+
+    size_t nTies = 0;
+    for (size_t i = 0; i < fun->nParams(); ++i) {
+      auto tie = fun->getTie(i);
+      if (tie) {
+        ++nTies;
+      }
+    }
+    TS_ASSERT_EQUALS(nTies, 0);
+  }
+};
+
+#endif /*CRYSTALFIELDSUSCEPTIBILITYTEST_H_*/
diff --git a/Framework/CurveFitting/test/Functions/CrystalFieldTest.h b/Framework/CurveFitting/test/Functions/CrystalFieldTest.h
index 741a45e39e18f9104eac98bd1754927cb89cb3a7..684f16b782fac480b4e8102303d9613a5e725ce1 100644
--- a/Framework/CurveFitting/test/Functions/CrystalFieldTest.h
+++ b/Framework/CurveFitting/test/Functions/CrystalFieldTest.h
@@ -75,7 +75,12 @@ public:
     ComplexFortranMatrix bkq(0, 6, 0, 6);
     zeroAllEntries(bmol, bext, bkq);
 
-    bmol(1) = 10.;
+    // The internal (molecular) field is not rotated. So we leave it at zero
+    // else in the rotated case (en2) it will be in a different [physical]
+    // direction and so give a different splitting. The external field
+    // is rotated in the code, so we set it to some value to check the
+    // rotation works.
+    bext(1) = 10.;
     bkq(2, 0) = 0.3365;
     bkq(2, 2) = 7.4851;
     bkq(4, 0) = 0.4062;
@@ -102,7 +107,7 @@ public:
       en2 = en;
     }
     for (size_t i = 1; i < en1.size(); ++i) {
-      TS_ASSERT_LESS_THAN(1.0, fabs(en1.get(i) - en2.get(i)));
+      TS_ASSERT_DELTA(en1.get(i), en2.get(i), 1e-6);
     }
   }
 
diff --git a/Framework/CurveFitting/test/Functions/DeltaFunctionTest.h b/Framework/CurveFitting/test/Functions/DeltaFunctionTest.h
index a6873994c0fb319cb6d6ca47ebaa538cccb3f681..164f9feb4f1b3be27c0f8da146a4f522b0afd5ac 100644
--- a/Framework/CurveFitting/test/Functions/DeltaFunctionTest.h
+++ b/Framework/CurveFitting/test/Functions/DeltaFunctionTest.h
@@ -127,7 +127,6 @@ public:
   }
 
   void test_delta_with_shift() {
-    IPeakFunction::setPeakRadius(1000);
     auto res = IPeakFunction_sptr(new DeltaFunctionTest_Gauss());
     double a = 0.13;
     double ha = 1.0 / sqrt(M_PI * a);
@@ -169,7 +168,6 @@ public:
   }
 
   void test_two_deltas_with_shifts() {
-    IPeakFunction::setPeakRadius(1000);
     auto res = IPeakFunction_sptr(new DeltaFunctionTest_Gauss());
     double a = 0.13;
     double ha = 1.0 / sqrt(M_PI * a);
diff --git a/Framework/CurveFitting/test/Functions/DiffRotDiscreteCircleTest.h b/Framework/CurveFitting/test/Functions/DiffRotDiscreteCircleTest.h
index c667c12d27acf784194a5e24758e921897973ae5..1c6ce5f34b47d67c7cbd278e10e9b7c5631e771f 100644
--- a/Framework/CurveFitting/test/Functions/DiffRotDiscreteCircleTest.h
+++ b/Framework/CurveFitting/test/Functions/DiffRotDiscreteCircleTest.h
@@ -431,7 +431,7 @@ private:
     const size_t M = xView.size();
     // create temporaray workspace.
     auto temp_ws =
-        WorkspaceCreationHelper::Create2DWorkspace(1, static_cast<int>(M));
+        WorkspaceCreationHelper::create2DWorkspace(1, static_cast<int>(M));
     for (size_t i = 0; i < M; i++) {
       temp_ws->dataX(0)[i] = xView[i];
       temp_ws->dataY(0)[i] = dataYvalues.getCalculated(i);
@@ -484,7 +484,7 @@ private:
       dataX[i] = (static_cast<double>(i) - M / 2) * dw;
 
     // create the workspace
-    auto ws = WorkspaceCreationHelper::Create2DWorkspace(1, M);
+    auto ws = WorkspaceCreationHelper::create2DWorkspace(1, M);
     double fractional_error = 0.01; // error taken as a percent of the signal
     for (size_t i = 0; i < M; i++) {
       double bin_boundary =
@@ -541,7 +541,7 @@ private:
     fitalg_function->function(dataXview, dataYvalues);
 
     // Create the workspace
-    auto ws = WorkspaceCreationHelper::Create2DWorkspace(1, M);
+    auto ws = WorkspaceCreationHelper::create2DWorkspace(1, M);
 
     // Create the instrument
     boost::shared_ptr<Instrument> inst =
diff --git a/Framework/CurveFitting/test/Functions/DiffSphereTest.h b/Framework/CurveFitting/test/Functions/DiffSphereTest.h
index 1023e8c8a0701625648d60ba5b9c16f257d6715e..91b4019a44516ff37cace8bfbab256f87b08468b 100644
--- a/Framework/CurveFitting/test/Functions/DiffSphereTest.h
+++ b/Framework/CurveFitting/test/Functions/DiffSphereTest.h
@@ -73,6 +73,7 @@ public:
     fitalg.setProperty("Function", funtion_string);
     fitalg.setProperty("InputWorkspace", data_workspace);
     fitalg.setPropertyValue("WorkspaceIndex", "0");
+    fitalg.setProperty("IgnoreInvalidData", true);
     TS_ASSERT_THROWS_NOTHING(TS_ASSERT(fitalg.execute()));
     TS_ASSERT(fitalg.isExecuted());
 
@@ -475,7 +476,7 @@ private:
     fitalg_function->function(dataXview, dataYvalues);
 
     // Create the workspace
-    auto ws = WorkspaceCreationHelper::Create2DWorkspace(1, M);
+    auto ws = WorkspaceCreationHelper::create2DWorkspace(1, M);
 
     // Create the instrument
     boost::shared_ptr<Instrument> inst =
diff --git a/Framework/CurveFitting/test/Functions/FunctionQDependsTest.h b/Framework/CurveFitting/test/Functions/FunctionQDependsTest.h
new file mode 100644
index 0000000000000000000000000000000000000000..1860a032320980e32c2fbd7df29003145ed6ae2d
--- /dev/null
+++ b/Framework/CurveFitting/test/Functions/FunctionQDependsTest.h
@@ -0,0 +1,173 @@
+#ifndef MANTID_CURVEFITTING_FUNCTIONQDEPENDSTEST_H
+#define MANTID_CURVEFITTING_FUNCTIONQDEPENDSTEST_H
+
+// Mantid Coding standars <http://www.mantidproject.org/Coding_Standards>
+
+// Mantid Headers from the same project
+#include "MantidCurveFitting/Functions/FunctionQDepends.h"
+// Mantid headers from other projects
+#include "MantidAPI/IFunction.h"
+#include "MantidAPI/ParamFunction.h"
+#include "MantidAPI/NumericAxis.h"
+#include "MantidAPI/MatrixWorkspace.h"
+#include "MantidDataObjects/Workspace2D.h"
+#include "MantidTestHelpers/WorkspaceCreationHelper.h"
+#include "MantidKernel/EmptyValues.h"
+#include "MantidDataHandling/LoadNexus.h"
+// 3rd party library headers
+#include <cxxtest/TestSuite.h>
+// Standard library
+// N/A
+
+using Attr = Mantid::API::IFunction::Attribute;
+
+namespace {
+class ImplementsFunctionQDepends
+    : public Mantid::CurveFitting::Functions::FunctionQDepends {
+
+public:
+  std::string name() const override { return "ImplementsFunctionQDepends"; }
+
+  void function1D(double *out, const double *xValues,
+                  const size_t nData) const override {
+    double Q = this->getAttribute("Q").asDouble();
+    for (size_t i = 0; i < nData; i++) {
+      out[i] = Q * xValues[i];
+    }
+  }
+};
+} // end of namespace
+
+class FunctionQDependsTest : public CxxTest::TestSuite {
+
+public:
+  // This pair of boilerplate methods prevent the suite being created statically
+  // This means the constructor isn't called when running other tests
+  static FunctionQDependsTest *createSuite() {
+    return new FunctionQDependsTest();
+  }
+  static void destroySuite(FunctionQDependsTest *suite) { delete suite; }
+
+  void testConstruction() {
+    TS_ASSERT_THROWS_NOTHING(ImplementsFunctionQDepends f);
+  }
+
+  void testInitialization() {
+    ImplementsFunctionQDepends f;
+    TS_ASSERT_THROWS_NOTHING(f.initialize());
+  }
+
+  void testSetWorkspace() {
+    double startX{0.0}, endX{1.0};
+    ImplementsFunctionQDepends f;
+    f.initialize(); // declare attributes
+    // test with an non matrix workspace
+    TS_ASSERT_THROWS_NOTHING(
+        f.setMatrixWorkspace(this->unsuitableWS(), 0, startX, endX));
+    // test with a non-suitable matrix workspace
+    TS_ASSERT_THROWS_NOTHING(
+        f.setMatrixWorkspace(this->withoutQ(), 0, startX, endX));
+    // test with a workspace containing Q values in the vertical axis
+    TS_ASSERT_THROWS_NOTHING(
+        f.setMatrixWorkspace(this->withQonVerticalAxis(), 0, startX, endX));
+    // test with a workspace containing detectors for calculation of Q values
+    TS_ASSERT_THROWS_NOTHING(
+        f.setMatrixWorkspace(this->withDetectors(), 0, startX, endX));
+  }
+
+  void testQAttribute() {
+    double startX{0.0}, endX{1.0};
+    ImplementsFunctionQDepends f;
+    f.initialize(); // declare attributes
+    auto Q = f.getAttribute("Q").asDouble();
+    TS_ASSERT_EQUALS(Q, Mantid::EMPTY_DBL());
+    f.setMatrixWorkspace(this->unsuitableWS(), 0, startX, endX);
+    TS_ASSERT_EQUALS(Q, Mantid::EMPTY_DBL());
+    f.setMatrixWorkspace(this->withoutQ(), 0, startX, endX);
+    TS_ASSERT_EQUALS(Q, Mantid::EMPTY_DBL());
+    // test assigning Q when no matrix workspace has been set
+    f.setAttribute("Q", Attr(0.18));
+    TS_ASSERT_EQUALS(f.getAttribute("Q").asDouble(), 0.18);
+    // test assigning Q when a workspace has been set
+    f.setMatrixWorkspace(this->withQonVerticalAxis(), 1, startX, endX);
+    TS_ASSERT_EQUALS(f.getAttribute("Q").asDouble(), 0.5); // Q overwritten
+    f.setAttribute("Q", Attr(0.18));
+    TS_ASSERT_EQUALS(f.getAttribute("Q").asDouble(), 0.5); // Q not overwritten
+  }
+
+  void testWorkspaceIndexAttribute() {
+    double startX{0.0}, endX{1.0};
+    ImplementsFunctionQDepends f;
+    f.initialize(); // declare attributes
+    auto wi = f.getAttribute("WorkspaceIndex").asInt();
+    TS_ASSERT_EQUALS(wi, Mantid::EMPTY_INT());
+    f.setMatrixWorkspace(this->unsuitableWS(), 0, startX, endX);
+    TS_ASSERT_EQUALS(wi, Mantid::EMPTY_INT());
+    f.setMatrixWorkspace(this->withoutQ(), 0, startX, endX);
+    TS_ASSERT_EQUALS(wi, Mantid::EMPTY_INT());
+    // test assigning wi when no matrix workspace has been set
+    f.setAttribute("WorkspaceIndex", Attr(1));
+    TS_ASSERT_EQUALS(f.getAttribute("WorkspaceIndex").asInt(),
+                     Mantid::EMPTY_INT()); // not overwritten
+    // test assigning wi when a workspace has been set
+    f.setMatrixWorkspace(this->withQonVerticalAxis(), 1, startX, endX);
+    TS_ASSERT_EQUALS(f.getAttribute("WorkspaceIndex").asInt(), 1);
+    f.setAttribute("WorkspaceIndex", Attr(0));
+    TS_ASSERT_EQUALS(f.getAttribute("WorkspaceIndex").asInt(),
+                     0); // WorkspaceIndex overwritten
+  }
+
+  void testWorkspaceIndexTiesQ() {
+    double startX{0.0}, endX{1.0};
+    ImplementsFunctionQDepends f;
+    f.initialize(); // declare attributes
+    f.setMatrixWorkspace(this->withQonVerticalAxis(), 1, startX, endX);
+    TS_ASSERT_EQUALS(f.getAttribute("Q").asDouble(), 0.5); // Q overwritten
+    f.setAttribute("WorkspaceIndex", Attr(0));
+    TS_ASSERT_EQUALS(f.getAttribute("Q").asDouble(), 0.3); // Q overwritten
+    f.setMatrixWorkspace(this->withDetectors(), 9, startX, endX);
+    TS_ASSERT_DELTA(f.getAttribute("Q").asDouble(), 1.82,
+                    0.01); // Q overwritten
+    Mantid::API::AnalysisDataService::Instance().clear();
+  }
+
+private:
+  // return a MatrixWorkspace with Q values on the vertical axis
+  Mantid::DataObjects::Workspace2D_sptr withQonVerticalAxis() {
+    int nhist{4}, nbins{9};
+    // create an axis of Q-values
+    std::vector<double> qvalues{
+        0.3, 0.5, 0.5, 0.9}; // as many elements as the value of variable nhist
+    auto momenta = new Mantid::API::NumericAxis(qvalues);
+    momenta->setUnit("MomentumTransfer");
+    // create the matrix workspace
+    auto ws = WorkspaceCreationHelper::create2DWorkspaceBinned(nhist, nbins);
+    ws->replaceAxis(1, momenta);
+    return ws;
+  }
+
+  // return a MatrixWorkspace with detectors allowing computations of Q values
+  Mantid::API::MatrixWorkspace_sptr withDetectors() {
+    Mantid::DataHandling::LoadNexus loader;
+    loader.initialize();
+    loader.setPropertyValue("Filename", "irs26173_graphite002_red");
+    loader.setPropertyValue("OutputWorkspace", "irs26173");
+    TS_ASSERT_THROWS_NOTHING(loader.execute());
+    TS_ASSERT(loader.isExecuted());
+    return Mantid::API::AnalysisDataService::Instance()
+        .retrieveWS<Mantid::API::MatrixWorkspace>("irs26173");
+  }
+
+  // return a MatrixWorkspace without Q values
+  Mantid::DataObjects::Workspace2D_sptr withoutQ() {
+    int nhist{3}, nbins{9};
+    return WorkspaceCreationHelper::create2DWorkspaceBinned(nhist, nbins);
+  }
+
+  // return a Workspace not of MatrixWorkspace type
+  Mantid::DataObjects::EventWorkspace_sptr unsuitableWS() {
+    return WorkspaceCreationHelper::createEventWorkspace();
+  }
+};
+
+#endif /* MANTID_API_FUNCTIONQDEPENDSTEST_H */
diff --git a/Framework/CurveFitting/test/Functions/GaussianTest.h b/Framework/CurveFitting/test/Functions/GaussianTest.h
index ff6fa75caf03aabbda42c7e17b6c09b43f0a04d6..dedc9f2642e832ce337ec066c6eeb4d8af97f2db 100644
--- a/Framework/CurveFitting/test/Functions/GaussianTest.h
+++ b/Framework/CurveFitting/test/Functions/GaussianTest.h
@@ -79,10 +79,8 @@ public:
     fn->setParameter("PeakCentre", 79450.0);
     fn->setParameter("Height", 200.0);
     fn->setParameter("Sigma", 300.0);
-    BoundaryConstraint *bc =
-        new BoundaryConstraint(fn.get(), "Sigma", 20.0, 100.0);
-    // bc->setPenaltyFactor(1000.001);
-    fn->addConstraint(bc);
+    fn->addConstraint(Kernel::make_unique<BoundaryConstraint>(fn.get(), "Sigma",
+                                                              20.0, 100.0));
 
     fnWithBk->addFunction(bk);
     fnWithBk->addFunction(fn);
diff --git a/Framework/CurveFitting/test/Functions/IkedaCarpenterPVTest.h b/Framework/CurveFitting/test/Functions/IkedaCarpenterPVTest.h
index 5ef06fa8236207d4497cf6154e477670faa9d2da..6285adf379bafde31d3faa212ef52e2567bae6ee 100644
--- a/Framework/CurveFitting/test/Functions/IkedaCarpenterPVTest.h
+++ b/Framework/CurveFitting/test/Functions/IkedaCarpenterPVTest.h
@@ -56,6 +56,20 @@ public:
     TS_ASSERT_DELTA(y[13], 77.7493, 1e-4);
     TS_ASSERT_DELTA(y[14], 53.8871, 1e-4);
   }
+
+  void test_intensity() {
+    IkedaCarpenterPV fn;
+    fn.initialize();
+    fn.setParameter("I", 67.2548);
+    fn.setParameter("Alpha0", 1.6);
+    fn.setParameter("Alpha1", 1.5);
+    fn.setParameter("Beta0", 31.9);
+    fn.setParameter("Kappa", 46.0);
+    fn.setParameter("SigmaSquared", 0.00281776);
+    fn.setParameter("Gamma", 0.125);
+    fn.setParameter("X0", 0);
+    TS_ASSERT_DELTA(fn.intensity(), 810.7256, 1e-4);
+  }
 };
 
 #endif /*IKEDACARPENTERPVTEST_H_*/
diff --git a/Framework/CurveFitting/test/Functions/Lorentzian1DTest.h b/Framework/CurveFitting/test/Functions/Lorentzian1DTest.h
deleted file mode 100644
index d56d87abe45f2cf3e6dd7bb6b2719c5e6b4f8a67..0000000000000000000000000000000000000000
--- a/Framework/CurveFitting/test/Functions/Lorentzian1DTest.h
+++ /dev/null
@@ -1,120 +0,0 @@
-#ifndef LORENTZIAN1DTEST_H_
-#define LORENTZIAN1DTEST_H_
-
-#include <cxxtest/TestSuite.h>
-
-#include "MantidCurveFitting/Functions/Lorentzian1D.h"
-#include "MantidKernel/UnitFactory.h"
-#include "MantidAPI/AnalysisDataService.h"
-#include "MantidAPI/WorkspaceFactory.h"
-#include "MantidAPI/Algorithm.h"
-#include "MantidDataObjects/Workspace2D.h"
-
-using namespace Mantid::Kernel;
-using namespace Mantid::API;
-using Mantid::CurveFitting::Functions::Lorentzian1D;
-using namespace Mantid::DataObjects;
-
-class Lorentzian1DTest : public CxxTest::TestSuite {
-public:
-  void testInit() {
-    TS_ASSERT_THROWS_NOTHING(alg.initialize());
-    TS_ASSERT(alg.isInitialized());
-  }
-
-  void testAgainstMockData() {
-    Lorentzian1D alg2;
-    TS_ASSERT_THROWS_NOTHING(alg2.initialize());
-    TS_ASSERT(alg2.isInitialized());
-
-    // create mock data to test against
-    std::string wsName = "LorentzianMockData";
-    int histogramNumber = 1;
-    int timechannels = 20;
-    Workspace_sptr ws = WorkspaceFactory::Instance().create(
-        "Workspace2D", histogramNumber, timechannels, timechannels);
-    Workspace2D_sptr ws2D = boost::dynamic_pointer_cast<Workspace2D>(ws);
-    for (int i = 0; i < 20; i++)
-      ws2D->dataX(0)[i] = i + 1;
-    Mantid::MantidVec &y = ws2D->dataY(0); // y-values (counts)
-    y[0] = 4.1733;
-    y[1] = 4.3729;
-    y[2] = 4.8150;
-    y[3] = 5.3402;
-    y[4] = 6.0909;
-    y[5] = 7.3389;
-    y[6] = 9.4883;
-    y[7] = 13.6309;
-    y[8] = 23.1555;
-    y[9] = 48.9471;
-    y[10] = 100.4982;
-    y[11] = 68.8164;
-    y[12] = 30.3590;
-    y[13] = 16.4184;
-    y[14] = 10.7455;
-    y[15] = 8.0570;
-    y[16] = 6.5158;
-    y[17] = 5.5496;
-    y[18] = 5.0087;
-    y[19] = 4.5027;
-    Mantid::MantidVec &e = ws2D->dataE(0); // error values of counts
-    e[0] = 2.0429;
-    e[1] = 2.0911;
-    e[2] = 2.1943;
-    e[3] = 2.3109;
-    e[4] = 2.4680;
-    e[5] = 2.7090;
-    e[6] = 3.0803;
-    e[7] = 3.6920;
-    e[8] = 4.8120;
-    e[9] = 6.9962;
-    e[10] = 10.0249;
-    e[11] = 8.2956;
-    e[12] = 5.5099;
-    e[13] = 4.0520;
-    e[14] = 3.2780;
-    e[15] = 2.8385;
-    e[16] = 2.5526;
-    e[17] = 2.3558;
-    e[18] = 2.2380;
-    e[19] = 2.1220;
-
-    // put this workspace in the data service
-    TS_ASSERT_THROWS_NOTHING(AnalysisDataService::Instance().add(wsName, ws2D));
-
-    // Set which spectrum to fit against and initial starting values
-    alg2.setPropertyValue("InputWorkspace", wsName);
-    alg2.setPropertyValue("WorkspaceIndex", "1");
-    alg2.setPropertyValue("StartX", "0");
-    alg2.setPropertyValue("EndX", "20");
-    alg2.setPropertyValue("BG0", "2.0");
-    alg2.setPropertyValue("BG1", "0.0");
-    alg2.setPropertyValue("Height", "105.7");
-    alg2.setPropertyValue("PeakCentre", "13.5");
-    alg2.setPropertyValue("HWHM", "1.2");
-
-    // execute fit
-    TS_ASSERT_THROWS_NOTHING(TS_ASSERT(alg2.execute()))
-
-    TS_ASSERT(alg2.isExecuted());
-
-    // test the output from fit is what you expect
-    double dummy = alg2.getProperty("OutputChi2overDoF");
-    TS_ASSERT_DELTA(dummy, 0.0002, 0.0005);
-    dummy = alg2.getProperty("BG0");
-    TS_ASSERT_DELTA(dummy, 3.017, 0.002);
-    dummy = alg2.getProperty("BG1");
-    TS_ASSERT_DELTA(dummy, 0.0, 0.005);
-    dummy = alg2.getProperty("Height");
-    TS_ASSERT_DELTA(dummy, 100.69, 0.01);
-    dummy = alg2.getProperty("PeakCentre");
-    TS_ASSERT_DELTA(dummy, 11.20, 0.01);
-    dummy = alg2.getProperty("HWHM");
-    TS_ASSERT_DELTA(dummy, 1.10, 0.01);
-  }
-
-private:
-  Lorentzian1D alg;
-};
-
-#endif /*LORENTZIAN1DTEST_H_*/
diff --git a/Framework/CurveFitting/test/Functions/ProcessBackgroundTest.h b/Framework/CurveFitting/test/Functions/ProcessBackgroundTest.h
index a89fdc30a80bc54c8a5cdf2a2f8afe622c83af6c..acd2ddcd4f044a5c4198e43c6ddb1cb46d45ec57 100644
--- a/Framework/CurveFitting/test/Functions/ProcessBackgroundTest.h
+++ b/Framework/CurveFitting/test/Functions/ProcessBackgroundTest.h
@@ -6,6 +6,7 @@
 #include "MantidCurveFitting/Functions/ProcessBackground.h"
 #include "MantidDataObjects/Workspace2D.h"
 #include "MantidDataObjects/TableWorkspace.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidAPI/TableRow.h"
 #include "MantidKernel/MersenneTwister.h"
diff --git a/Framework/CurveFitting/test/Functions/ResolutionTest.h b/Framework/CurveFitting/test/Functions/ResolutionTest.h
index e247c61288866ab23c568449889a54023f142848..ff124dd187f4fd3ec3d4aefd4180ef6ca3084e22 100644
--- a/Framework/CurveFitting/test/Functions/ResolutionTest.h
+++ b/Framework/CurveFitting/test/Functions/ResolutionTest.h
@@ -4,6 +4,7 @@
 #include <cxxtest/TestSuite.h>
 
 #include "MantidCurveFitting/Functions/Resolution.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/IPeakFunction.h"
 #include "MantidAPI/FunctionFactory.h"
 #include "MantidAPI/MatrixWorkspace.h"
diff --git a/Framework/CurveFitting/test/Functions/TabulatedFunctionTest.h b/Framework/CurveFitting/test/Functions/TabulatedFunctionTest.h
index 79b9ff4ad5e27c4531c8d324558d1f788ebde352..7211061ef362c52ffec2a05207e7893090ebef59 100644
--- a/Framework/CurveFitting/test/Functions/TabulatedFunctionTest.h
+++ b/Framework/CurveFitting/test/Functions/TabulatedFunctionTest.h
@@ -123,7 +123,7 @@ public:
   }
 
   void test_loadWorkspace() {
-    auto ws = WorkspaceCreationHelper::Create2DWorkspaceFromFunction(
+    auto ws = WorkspaceCreationHelper::create2DWorkspaceFromFunction(
         Fun(), 1, -5.0, 5.0, 0.1, false);
     AnalysisDataService::Instance().add("TABULATEDFUNCTIONTEST_WS", ws);
     TabulatedFunction fun;
@@ -144,7 +144,7 @@ public:
   }
 
   void test_loadWorkspace_nondefault_index() {
-    auto ws = WorkspaceCreationHelper::Create2DWorkspaceFromFunction(
+    auto ws = WorkspaceCreationHelper::create2DWorkspaceFromFunction(
         Fun(), 3, -5.0, 5.0, 0.1, false);
     AnalysisDataService::Instance().add("TABULATEDFUNCTIONTEST_WS", ws);
     TabulatedFunction fun;
@@ -168,7 +168,7 @@ public:
   }
 
   void test_loadWorkspace_nondefault_wrong_index() {
-    auto ws = WorkspaceCreationHelper::Create2DWorkspaceFromFunction(
+    auto ws = WorkspaceCreationHelper::create2DWorkspaceFromFunction(
         Fun(), 3, -5.0, 5.0, 0.1, false);
     AnalysisDataService::Instance().add("TABULATEDFUNCTIONTEST_WS", ws);
     TabulatedFunction fun;
@@ -187,7 +187,7 @@ public:
   }
 
   void test_Derivatives() {
-    auto ws = WorkspaceCreationHelper::Create2DWorkspaceFromFunction(
+    auto ws = WorkspaceCreationHelper::create2DWorkspaceFromFunction(
         Fun(), 1, -5.0, 5.0, 0.1, false);
     AnalysisDataService::Instance().add("TABULATEDFUNCTIONTEST_WS", ws);
     TabulatedFunction fun;
@@ -244,7 +244,7 @@ public:
   }
 
   void test_factory_create_from_workspace() {
-    auto ws = WorkspaceCreationHelper::Create2DWorkspaceFromFunction(
+    auto ws = WorkspaceCreationHelper::create2DWorkspaceFromFunction(
         Fun(), 1, -5.0, 5.0, 0.1, false);
     AnalysisDataService::Instance().add("TABULATEDFUNCTIONTEST_WS", ws);
     std::string inif = "name=TabulatedFunction,Workspace=TABULATEDFUNCTIONTEST_"
diff --git a/Framework/CurveFitting/test/Functions/VoigtTest.h b/Framework/CurveFitting/test/Functions/VoigtTest.h
index 74c76e0aa518baa8c9d7ed76c45d70b2b04ea523..34d940fac854c525e2a8d2d8ec4f1a5b5d0ad6b1 100644
--- a/Framework/CurveFitting/test/Functions/VoigtTest.h
+++ b/Framework/CurveFitting/test/Functions/VoigtTest.h
@@ -14,6 +14,7 @@
 
 using Mantid::CurveFitting::Functions::Voigt;
 using Mantid::API::IFunction;
+using Mantid::API::IPeakFunction;
 
 class VoigtTest : public CxxTest::TestSuite {
 public:
@@ -104,7 +105,7 @@ public:
         boost::dynamic_pointer_cast<Mantid::API::IPeakFunction>(voigtFn);
 
     TS_ASSERT_DELTA(peakFn->centre(), pos, 1e-12);
-    TS_ASSERT_DELTA(peakFn->height(), 2.0 * a_L / 3.0, 1e-12);
+    TS_ASSERT_DELTA(peakFn->height(), 4.9570, 1e-4);
     TS_ASSERT_DELTA(peakFn->fwhm(), (gamma_L + gamma_G), 1e-12);
   }
 
@@ -128,16 +129,150 @@ public:
     TS_ASSERT_DELTA(peakFn->fwhm(), (gamma_L + gamma_G), 1e-12);
   }
 
+  void test_height() {
+    {
+      auto voigt = createFunction(0, 0, 0, 0);
+      TS_ASSERT_EQUALS(voigt->height(), 0.0);
+      voigt->setHeight(3.0);
+      TS_ASSERT_DELTA(voigt->height(), 3.0, 1e-10);
+      TS_ASSERT_DELTA(voigt->fwhm(), 0, 1e-10);
+      TS_ASSERT_DELTA(voigt->intensity(), 0, 1e-10);
+    }
+    {
+      auto voigt = createFunction(1, 0, 0, 0);
+      TS_ASSERT_EQUALS(voigt->height(), 0.0);
+      voigt->setHeight(3.0);
+      TS_ASSERT_DELTA(voigt->height(), 3.0, 1e-10);
+      TS_ASSERT_DELTA(voigt->fwhm(), 0, 1e-10);
+      TS_ASSERT_DELTA(voigt->intensity(), 0, 1e-10);
+    }
+    {
+      auto voigt = createFunction(1, 0, 1, 0);
+      TS_ASSERT_EQUALS(voigt->height(), 0.0);
+      voigt->setHeight(3.0);
+      TS_ASSERT_DELTA(voigt->height(), 3.0, 1e-10);
+      TS_ASSERT_DELTA(voigt->fwhm(), 1, 1e-10);
+      TS_ASSERT_DELTA(voigt->intensity(), 4.7123, 1e-4);
+    }
+    {
+      auto voigt = createFunction(1, 0, 0, 1);
+      TS_ASSERT_EQUALS(voigt->height(), 0.0);
+      voigt->setHeight(3.0);
+      TS_ASSERT_DELTA(voigt->height(), 3.0, 1e-10);
+      TS_ASSERT_DELTA(voigt->fwhm(), 1, 1e-10);
+      TS_ASSERT_DELTA(voigt->intensity(), 3.1933, 1e-4);
+    }
+    {
+      auto voigt = createFunction(0, 0, 1, 1);
+      TS_ASSERT_EQUALS(voigt->height(), 0.0);
+      voigt->setHeight(3.0);
+      TS_ASSERT_DELTA(voigt->height(), 3.0, 1e-10);
+      TS_ASSERT_DELTA(voigt->fwhm(), 2, 1e-10);
+      TS_ASSERT_DELTA(voigt->intensity(), 6.6795, 1e-4);
+    }
+    {
+      auto voigt = createFunction(4, 0, 2, 3);
+      TS_ASSERT_DELTA(voigt->height(), 2.3159, 1e-4);
+      voigt->setHeight(3.0);
+      TS_ASSERT_DELTA(voigt->height(), 3.0, 1e-10);
+      TS_ASSERT_DELTA(voigt->fwhm(), 5, 1e-10);
+      TS_ASSERT_DELTA(voigt->intensity(), 16.2778, 1e-4);
+    }
+  }
+
+  void test_intensity() {
+    {
+      auto voigt = createFunction(0, 0, 0, 0);
+      TS_ASSERT_EQUALS(voigt->intensity(), 0.0);
+      voigt->setIntensity(3.0);
+      TS_ASSERT_DELTA(voigt->height(), 6068115080134125.22, 1e10);
+      TS_ASSERT_DELTA(voigt->fwhm(), 0, 1e-10);
+      TS_ASSERT_DELTA(voigt->intensity(), 3.0, 1e-10);
+    }
+    {
+      auto voigt = createFunction(1, 0, 0, 0);
+      TS_ASSERT_EQUALS(voigt->intensity(), 0.0);
+      voigt->setIntensity(3.0);
+      TS_ASSERT_DELTA(voigt->height(), 6068115080134125.22, 1e10);
+      TS_ASSERT_DELTA(voigt->fwhm(), 0, 1e-10);
+      TS_ASSERT_DELTA(voigt->intensity(), 3.0, 1e-10);
+    }
+    {
+      auto voigt = createFunction(1, 0, 0, 1);
+      TS_ASSERT_EQUALS(voigt->intensity(), 0.0);
+      voigt->setIntensity(3.0);
+      TS_ASSERT_DELTA(voigt->height(), 2.8183, 1e-4);
+      TS_ASSERT_DELTA(voigt->fwhm(), 1, 1e-10);
+      TS_ASSERT_DELTA(voigt->intensity(), 3.0, 1e-10);
+    }
+    {
+      auto voigt = createFunction(1, 0, 1, 0);
+      TS_ASSERT_EQUALS(voigt->intensity(), 0.0);
+      voigt->setIntensity(3.0);
+      TS_ASSERT_DELTA(voigt->height(), 1.9098, 1e-4);
+      TS_ASSERT_DELTA(voigt->fwhm(), 1, 1e-10);
+      TS_ASSERT_DELTA(voigt->intensity(), 3.0, 1e-10);
+    }
+    {
+      auto voigt = createFunction(4, 0, 2, 3);
+      TS_ASSERT_DELTA(voigt->intensity(), 12.5663, 1e-4);
+      voigt->setIntensity(3.0);
+      TS_ASSERT_DELTA(voigt->height(), 0.5528, 1e-4);
+      TS_ASSERT_DELTA(voigt->fwhm(), 5, 1e-10);
+      TS_ASSERT_DELTA(voigt->intensity(), 3.0, 1e-10);
+      TS_ASSERT_DELTA(voigt->IPeakFunction::intensity(), 3.0, 1e-2);
+    }
+  }
+
+  void test_fwhm() {
+    {
+      auto voigt = createFunction(0, 0, 0, 0);
+      TS_ASSERT_EQUALS(voigt->fwhm(), 0.0);
+      voigt->setFwhm(3.0);
+      TS_ASSERT_DELTA(voigt->height(), 0, 1e-10);
+      TS_ASSERT_DELTA(voigt->fwhm(), 3, 1e-10);
+      TS_ASSERT_DELTA(voigt->intensity(), 0.0, 1e-10);
+      TS_ASSERT_DELTA(voigt->getParameter("LorentzFWHM"), 1.5, 1e-10);
+      TS_ASSERT_DELTA(voigt->getParameter("GaussianFWHM"), 1.5, 1e-10);
+    }
+    {
+      auto voigt = createFunction(0, 0, 1, 0);
+      TS_ASSERT_EQUALS(voigt->fwhm(), 1.0);
+      voigt->setFwhm(3.0);
+      TS_ASSERT_DELTA(voigt->height(), 0, 1e-10);
+      TS_ASSERT_DELTA(voigt->fwhm(), 3, 1e-10);
+      TS_ASSERT_DELTA(voigt->intensity(), 0.0, 1e-10);
+      TS_ASSERT_DELTA(voigt->getParameter("LorentzFWHM"), 3.0, 1e-10);
+      TS_ASSERT_DELTA(voigt->getParameter("GaussianFWHM"), 0.0, 1e-10);
+    }
+    {
+      auto voigt = createFunction(0, 0, 0, 1);
+      TS_ASSERT_EQUALS(voigt->fwhm(), 1.0);
+      voigt->setFwhm(3.0);
+      TS_ASSERT_DELTA(voigt->height(), 0, 1e-10);
+      TS_ASSERT_DELTA(voigt->fwhm(), 3, 1e-10);
+      TS_ASSERT_DELTA(voigt->intensity(), 0.0, 1e-10);
+      TS_ASSERT_DELTA(voigt->getParameter("LorentzFWHM"), 0.0, 1e-10);
+      TS_ASSERT_DELTA(voigt->getParameter("GaussianFWHM"), 3.0, 1e-10);
+    }
+    {
+      auto voigt = createFunction(2, 0, 2, 1);
+      TS_ASSERT_EQUALS(voigt->fwhm(), 3.0);
+      voigt->setFwhm(5.5);
+      TS_ASSERT_DELTA(voigt->fwhm(), 5.5, 1e-10);
+      TS_ASSERT_DELTA(voigt->intensity(), 11.5191, 1e-4);
+      TS_ASSERT_DELTA(voigt->getParameter("LorentzFWHM"), 3.6666, 1e-4);
+      TS_ASSERT_DELTA(voigt->getParameter("GaussianFWHM"), 1.8333, 1e-4);
+    }
+  }
+
 private:
-  boost::shared_ptr<IFunction> createFunction(const double a_L,
-                                              const double pos,
-                                              const double gamma_L,
-                                              const double gamma_G) {
+  boost::shared_ptr<Mantid::API::IPeakFunction>
+  createFunction(const double a_L, const double pos, const double gamma_L,
+                 const double gamma_G) {
     boost::shared_ptr<IFunction> voigtFn = boost::make_shared<Voigt>();
     auto peakFn =
         boost::dynamic_pointer_cast<Mantid::API::IPeakFunction>(voigtFn);
-    // Set a fairly wide radius for simple tests
-    peakFn->setPeakRadius(10);
     voigtFn->initialize();
 
     voigtFn->setParameter("LorentzAmp", a_L);
@@ -145,7 +280,7 @@ private:
     voigtFn->setParameter("LorentzFWHM", gamma_L);
     voigtFn->setParameter("GaussianFWHM", gamma_G);
 
-    return voigtFn;
+    return peakFn;
   }
 
   enum { g_domainSize = 10 };
diff --git a/Framework/CurveFitting/test/MultiDomainCreatorTest.h b/Framework/CurveFitting/test/MultiDomainCreatorTest.h
index 5cd23175905ea0f1deb7c21375c6e67e4592a0a2..a64bfa9f5b7b86206b4be24d4f2c6d76e8dcadcf 100644
--- a/Framework/CurveFitting/test/MultiDomainCreatorTest.h
+++ b/Framework/CurveFitting/test/MultiDomainCreatorTest.h
@@ -22,6 +22,7 @@
 #include <algorithm>
 
 using namespace Mantid;
+using namespace Mantid::Kernel;
 using namespace Mantid::API;
 using namespace Mantid::CurveFitting;
 using namespace Mantid::CurveFitting::Functions;
@@ -232,11 +233,11 @@ public:
 
     WorkspaceGroup_sptr outWS = manager.getProperty("OUT_WS");
     TS_ASSERT(outWS);
-    TS_ASSERT_EQUALS(outWS->getItem(0)->name(), "out_Workspace_0");
-    TS_ASSERT_EQUALS(outWS->getItem(1)->name(), "out_Workspace_1");
-    TS_ASSERT_EQUALS(outWS->getItem(2)->name(), "out_Workspace_2");
+    TS_ASSERT_EQUALS(outWS->getItem(0)->getName(), "out_Workspace_0");
+    TS_ASSERT_EQUALS(outWS->getItem(1)->getName(), "out_Workspace_1");
+    TS_ASSERT_EQUALS(outWS->getItem(2)->getName(), "out_Workspace_2");
     manager.store("OUT_WS");
-    TS_ASSERT_EQUALS(outWS->name(), "out_Workspaces");
+    TS_ASSERT_EQUALS(outWS->getName(), "out_Workspaces");
     AnalysisDataService::Instance().clear();
   }
 
diff --git a/Framework/CurveFitting/test/SpecialFunctionSupportTest.h b/Framework/CurveFitting/test/SpecialFunctionSupportTest.h
index 60cef0c51dcc6e96a18cd04a3ae6d78e49cb90e0..01c4b8142f1a3a1363cdd10e84b36aa62cf13979 100644
--- a/Framework/CurveFitting/test/SpecialFunctionSupportTest.h
+++ b/Framework/CurveFitting/test/SpecialFunctionSupportTest.h
@@ -5,7 +5,6 @@
 #include <complex>
 #include "MantidCurveFitting/SpecialFunctionSupport.h"
 
-#include "MantidCurveFitting/Functions/Lorentzian1D.h"
 #include "MantidKernel/UnitFactory.h"
 #include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/WorkspaceFactory.h"
diff --git a/Framework/DataHandling/CMakeLists.txt b/Framework/DataHandling/CMakeLists.txt
index 59a5748cd597bfb883f8a9129f8355ea2085abb8..91a6d41ba66e3edc33e20f61dde2335cb1cadf4d 100644
--- a/Framework/DataHandling/CMakeLists.txt
+++ b/Framework/DataHandling/CMakeLists.txt
@@ -45,7 +45,6 @@ set ( SRC_FILES
 	src/LoadEventNexus.cpp
 	src/ProcessBankData.cpp
 	src/BankPulseTimes.cpp
-	src/LoadEventPreNexus.cpp
 	src/LoadEventPreNexus2.cpp
 	src/LoadFITS.cpp
 	src/LoadFullprofResolution.cpp
@@ -53,9 +52,10 @@ set ( SRC_FILES
 	src/LoadGSS.cpp
 	src/LoadHelper.cpp
 	src/LoadIDFFromNexus.cpp
-	src/LoadILL.cpp
 	src/LoadILLIndirect.cpp
+        src/LoadILLIndirect2.cpp
 	src/LoadILLTOF.cpp
+	src/LoadILLTOF2.cpp
 	src/LoadILLReflectometry.cpp
 	src/LoadILLSANS.cpp
 	src/LoadISISNexus2.cpp
@@ -65,7 +65,6 @@ set ( SRC_FILES
 	src/LoadIsawDetCal.cpp
 	src/LoadLLB.cpp
 	src/LoadLog.cpp
-	src/LoadLogsForSNSPulsedMagnet.cpp
 	src/LoadMLZ.cpp
 	src/LoadMappingTable.cpp
 	src/LoadMask.cpp
@@ -119,7 +118,6 @@ set ( SRC_FILES
 	src/NexusTester.cpp
 	src/PDLoadCharacterizations.cpp
 	src/PatchBBY.cpp
-	src/ProcessDasNexusLog.cpp
 	src/RawFileInfo.cpp
 	src/RemoveLogs.cpp
 	src/RenameLog.cpp
@@ -223,7 +221,6 @@ set ( INC_FILES
 	inc/MantidDataHandling/LoadEventNexus.h
 	inc/MantidDataHandling/ProcessBankData.h
 	inc/MantidDataHandling/BankPulseTimes.h
-	inc/MantidDataHandling/LoadEventPreNexus.h
 	inc/MantidDataHandling/LoadEventPreNexus2.h
 	inc/MantidDataHandling/LoadFITS.h
 	inc/MantidDataHandling/LoadFullprofResolution.h
@@ -231,9 +228,10 @@ set ( INC_FILES
 	inc/MantidDataHandling/LoadGSS.h
 	inc/MantidDataHandling/LoadHelper.h
 	inc/MantidDataHandling/LoadIDFFromNexus.h
-	inc/MantidDataHandling/LoadILL.h
 	inc/MantidDataHandling/LoadILLIndirect.h
+        inc/MantidDataHandling/LoadILLIndirect2.h
 	inc/MantidDataHandling/LoadILLTOF.h
+	inc/MantidDataHandling/LoadILLTOF2.h
 	inc/MantidDataHandling/LoadILLReflectometry.h
 	inc/MantidDataHandling/LoadILLSANS.h
 	inc/MantidDataHandling/LoadISISNexus2.h
@@ -243,7 +241,6 @@ set ( INC_FILES
 	inc/MantidDataHandling/LoadIsawDetCal.h
 	inc/MantidDataHandling/LoadLLB.h
 	inc/MantidDataHandling/LoadLog.h
-	inc/MantidDataHandling/LoadLogsForSNSPulsedMagnet.h
 	inc/MantidDataHandling/LoadMLZ.h
 	inc/MantidDataHandling/LoadMappingTable.h
 	inc/MantidDataHandling/LoadMask.h
@@ -293,7 +290,6 @@ set ( INC_FILES
 	inc/MantidDataHandling/NexusTester.h
 	inc/MantidDataHandling/PDLoadCharacterizations.h
 	inc/MantidDataHandling/PatchBBY.h
-	inc/MantidDataHandling/ProcessDasNexusLog.h
 	inc/MantidDataHandling/RawFileInfo.h
 	inc/MantidDataHandling/RemoveLogs.h
 	inc/MantidDataHandling/RenameLog.h
@@ -384,8 +380,8 @@ set ( TEST_FILES
 	ISISDataArchiveTest.h
 	ImggAggregateWavelengthsTest.h
 	InstrumentRayTracerTest.h
-	LoadAscii2Test.h
 	LoadAsciiTest.h
+	LoadAscii2Test.h
 	LoadBBYTest.h
 	LoadCalFileTest.h
 	LoadCanSAS1dTest.h
@@ -397,17 +393,19 @@ set ( TEST_FILES
 	LoadEmptyInstrumentTest.h
 	LoadEventNexusTest.h
 	LoadEventPreNexus2Test.h
-	LoadEventPreNexusTest.h
 	LoadFITSTest.h
 	LoadFullprofResolutionTest.h
 	LoadGSASInstrumentFileTest.h
 	LoadGSSTest.h
 	LoadIDFFromNexusTest.h
 	LoadILLIndirectTest.h
+        LoadILLIndirect2Test.h
 	LoadILLTOFTest.h
+	LoadILLTOF2Test.h
 	LoadILLReflectometryTest.h
 	LoadILLSANSTest.h
 	LoadISISNexusTest.h
+        LoadInstrumentFromNexusTest.h
 	LoadInstrumentFromRawTest.h
 	LoadInstrumentTest.h
 	LoadIsawDetCalTest.h
@@ -441,6 +439,7 @@ set ( TEST_FILES
 	LoadSINQFocusTest.h
 	LoadSNSspecTest.h
 	LoadSPETest.h
+        LoadSampleDetailsFromRawTest.h
 	LoadSassenaTest.h
 	LoadSaveAsciiTest.h
 	LoadSavuTomoConfigTest.h
@@ -458,7 +457,6 @@ set ( TEST_FILES
 	MoveInstrumentComponentTest.h
 	NexusTesterTest.h
 	PDLoadCharacterizationsTest.h
-	ProcessDasNexusLogTest.h
 	RawFileInfoTest.h
 	RemoveLogsTest.h
 	RenameLogTest.h
diff --git a/Framework/DataHandling/inc/MantidDataHandling/AsciiPointBase.h b/Framework/DataHandling/inc/MantidDataHandling/AsciiPointBase.h
index c230162717ffa03d7f72712f568c48fcd5857c86..cd5c6c13436e8de031849dab69c963abfe115028 100644
--- a/Framework/DataHandling/inc/MantidDataHandling/AsciiPointBase.h
+++ b/Framework/DataHandling/inc/MantidDataHandling/AsciiPointBase.h
@@ -68,11 +68,13 @@ private:
   virtual std::vector<double> header(std::ofstream &file);
 
 protected:
-  /// Return the separator character
-  virtual char sep() { return '\t'; }
   /// write the main content of the data
   virtual void data(std::ofstream &file, const std::vector<double> &XData,
                     bool exportDeltaQ = true);
+  /// Retrieves the separator property
+  virtual void appendSeparatorProperty();
+  /// The separator character
+  char m_sep;
   double m_qres = 0.0;
   size_t m_xlength = 0;
 
diff --git a/Framework/DataHandling/inc/MantidDataHandling/FindDetectorsPar.h b/Framework/DataHandling/inc/MantidDataHandling/FindDetectorsPar.h
index a52e0228e636f460cf989695e433277e08dd8b52..41560c23e033de7e9f0a6bb5182171fd9e1ba7c3 100644
--- a/Framework/DataHandling/inc/MantidDataHandling/FindDetectorsPar.h
+++ b/Framework/DataHandling/inc/MantidDataHandling/FindDetectorsPar.h
@@ -187,8 +187,8 @@ private:
   std::vector<size_t> detID;
 
   // calculate generic detectors parameters:
-  void calcDetPar(const Geometry::IDetector_const_sptr &spDet,
-                  const Kernel::V3D &Observer, DetParameters &Detector);
+  void calcDetPar(const Geometry::IDetector &det, const Kernel::V3D &Observer,
+                  DetParameters &Detector);
 
   /// if ASCII file is selected as the datasource, this structure describes the
   /// type of this file.
@@ -264,8 +264,7 @@ public:
         m_PolarBase(0), m_useSphericalSizes(false), m_AzimMin(FLT_MAX),
         m_PolarMin(FLT_MAX), m_AzimMax(-FLT_MAX), m_PolarMax(-FLT_MAX),
         m_nComponents(0) {}
-  void addDetInfo(const Geometry::IDetector_const_sptr &spDet,
-                  const Kernel::V3D &Observer);
+  void addDetInfo(const Geometry::IDetector &det, const Kernel::V3D &Observer);
   void returnAvrgDetPar(DetParameters &avrgDet);
 
   void setUseSpherical(bool shouldWe = true) { m_useSphericalSizes = shouldWe; }
diff --git a/Framework/DataHandling/inc/MantidDataHandling/GroupDetectors2.h b/Framework/DataHandling/inc/MantidDataHandling/GroupDetectors2.h
index 617cc786e77f0c42ddb9884e1c8dff09cb54f91a..a0fb1ea9053758fdc00dde82be7cb1762359074b 100644
--- a/Framework/DataHandling/inc/MantidDataHandling/GroupDetectors2.h
+++ b/Framework/DataHandling/inc/MantidDataHandling/GroupDetectors2.h
@@ -1,12 +1,10 @@
 #ifndef MANTID_DATAHANDLING_GROUPDETECTORS2_H_
 #define MANTID_DATAHANDLING_GROUPDETECTORS2_H_
 
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidAPI/Algorithm.h"
 #include "MantidDataObjects/EventWorkspace.h"
 #include "MantidDataObjects/GroupingWorkspace.h"
+#include "MantidKernel/StringTokenizer.h"
 
 #include <map>
 
diff --git a/Framework/DataHandling/inc/MantidDataHandling/Load.h b/Framework/DataHandling/inc/MantidDataHandling/Load.h
index faafaf643896e5ce7315dab94ccf69db535dbb3d..a36f9aac772a09f484429e4653270a06cd9cc4b3 100644
--- a/Framework/DataHandling/inc/MantidDataHandling/Load.h
+++ b/Framework/DataHandling/inc/MantidDataHandling/Load.h
@@ -1,10 +1,8 @@
 #ifndef MANTID_DATAHANDLING_LOAD_H_
 #define MANTID_DATAHANDLING_LOAD_H_
 
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidAPI/Algorithm.h"
+#include "MantidAPI/WorkspaceGroup_fwd.h"
 #include <mutex>
 
 namespace Mantid {
diff --git a/Framework/DataHandling/inc/MantidDataHandling/LoadAscii.h b/Framework/DataHandling/inc/MantidDataHandling/LoadAscii.h
index 8a8729c7f29139e547f09e38afe0ee7ac6b6f9ab..767e6dca67844889e019eb39b0021760da673075 100644
--- a/Framework/DataHandling/inc/MantidDataHandling/LoadAscii.h
+++ b/Framework/DataHandling/inc/MantidDataHandling/LoadAscii.h
@@ -1,12 +1,11 @@
 #ifndef MANTID_DATAHANDLING_LOADASCII_H_
 #define MANTID_DATAHANDLING_LOADASCII_H_
 
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidAPI/IFileLoader.h"
 #include "MantidAPI/DeprecatedAlgorithm.h"
 
+#include <list>
+
 namespace Mantid {
 namespace DataHandling {
 /**
@@ -99,4 +98,4 @@ private:
 } // namespace DataHandling
 } // namespace Mantid
 
-#endif /*  MANTID_DATAHANDLING_LOADASCII_H_  */
+#endif /*  MANTID_DATAHANDLING_LOADASCII_H_  */
\ No newline at end of file
diff --git a/Framework/DataHandling/inc/MantidDataHandling/LoadAscii2.h b/Framework/DataHandling/inc/MantidDataHandling/LoadAscii2.h
index 944c23c96662642f280e13280701611d688eea17..db7c394e41301412bb1f427fdc0142cba2925968 100644
--- a/Framework/DataHandling/inc/MantidDataHandling/LoadAscii2.h
+++ b/Framework/DataHandling/inc/MantidDataHandling/LoadAscii2.h
@@ -1,13 +1,12 @@
 #ifndef MANTID_DATAHANDLING_LoadAscii2_H_
 #define MANTID_DATAHANDLING_LoadAscii2_H_
 
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidAPI/IFileLoader.h"
 #include "MantidDataObjects/Histogram1D.h"
 #include "MantidAPI/MatrixWorkspace_fwd.h"
 
+#include <list>
+
 namespace Mantid {
 namespace DataHandling {
 /**
diff --git a/Framework/DataHandling/inc/MantidDataHandling/LoadCanSAS1D.h b/Framework/DataHandling/inc/MantidDataHandling/LoadCanSAS1D.h
index 26a1f6b3aeba9a7465bbed7098b05704a905b881..2c1fc7c64621e2fb95246bbe2daa6c02df5b016e 100644
--- a/Framework/DataHandling/inc/MantidDataHandling/LoadCanSAS1D.h
+++ b/Framework/DataHandling/inc/MantidDataHandling/LoadCanSAS1D.h
@@ -1,14 +1,11 @@
 #ifndef MANTID_DATAHANDLING_LoadCanSAS1D_H
 #define MANTID_DATAHANDLING_LoadCanSAS1D_H
 
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidAPI/IFileLoader.h"
+#include "MantidAPI/WorkspaceGroup_fwd.h"
 #include "MantidDataObjects/Workspace2D.h"
 #include <Poco/DOM/Element.h>
 #include <Poco/DOM/Node.h>
-//----------------------------------------------------------------------
 
 namespace Poco {
 namespace XML {
diff --git a/Framework/DataHandling/inc/MantidDataHandling/LoadDetectorInfo.h b/Framework/DataHandling/inc/MantidDataHandling/LoadDetectorInfo.h
index 8af99cb034f6b54d0b1688a8cd0c78991e4f3730..fd3441dc44804374b3b2db8bbd66aebee087ce4d 100644
--- a/Framework/DataHandling/inc/MantidDataHandling/LoadDetectorInfo.h
+++ b/Framework/DataHandling/inc/MantidDataHandling/LoadDetectorInfo.h
@@ -79,8 +79,8 @@ private:
 
   /// Update the parameter map with the new values for the given detector
   void updateParameterMap(Geometry::ParameterMap &pmap,
-                          const Geometry::IDetector_const_sptr &det,
-                          const double l2, const double theta, const double phi,
+                          const Geometry::IDetector &det, const double l2,
+                          const double theta, const double phi,
                           const double delay, const double pressure,
                           const double thickness) const;
 
diff --git a/Framework/DataHandling/inc/MantidDataHandling/LoadEventPreNexus.h b/Framework/DataHandling/inc/MantidDataHandling/LoadEventPreNexus.h
deleted file mode 100644
index 09dfd3ebdd57c5c9dbe441b665d66d6da6acb248..0000000000000000000000000000000000000000
--- a/Framework/DataHandling/inc/MantidDataHandling/LoadEventPreNexus.h
+++ /dev/null
@@ -1,198 +0,0 @@
-#ifndef LOADEVENTPRENEXUS_H_
-#define LOADEVENTPRENEXUS_H_
-
-#include <fstream>
-#include <string>
-#include <vector>
-#include "MantidAPI/IFileLoader.h"
-#include "MantidAPI/DeprecatedAlgorithm.h"
-#include "MantidKernel/BinaryFile.h"
-#include "MantidDataObjects/EventWorkspace.h"
-#include "MantidDataObjects/Events.h"
-
-namespace Mantid {
-namespace DataHandling {
-/** @class Mantid::DataHandling::LoadEventPreNexus
-
-    A data loading routine for SNS pre-nexus event files
-
-    Copyright &copy; 2010-11 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>
-*/
-
-/// This define is used to quickly turn parallel code on or off.
-#undef LOADEVENTPRENEXUS_ALLOW_PARALLEL
-
-/// Make the code clearer by having this an explicit type
-typedef int PixelType;
-
-/// Type for the DAS time of flight (data file)
-typedef int DasTofType;
-
-/// Structure that matches the form in the binary event list.
-#pragma pack(push, 4) // Make sure the structure is 8 bytes.
-struct DasEvent {
-  /// Time of flight.
-  DasTofType tof;
-  /// Pixel identifier as published by the DAS/DAE/DAQ.
-  PixelType pid;
-};
-#pragma pack(pop)
-
-/// Structure used as an intermediate for parallel processing of events
-#pragma pack(push, 4) // Make sure the structure is 8 bytes.
-struct IntermediateEvent {
-  /// Time of flight.
-  DasTofType tof;
-  /// Pixel identifier as published by the DAS/DAE/DAQ.
-  PixelType pid;
-  /// Frame index (pulse # of this event)
-  size_t frame_index;
-  /// Period of the event (not really used at this time)
-  uint32_t period;
-};
-#pragma pack(pop)
-
-/// Structure that matches the form in the new pulseid files.
-#pragma pack(push, 4) // Make sure the structure is 16 bytes.
-struct Pulse {
-  /// The number of nanoseconds since the seconds field. This is not necessarily
-  /// less than one second.
-  uint32_t nanoseconds;
-
-  /// The number of seconds since January 1, 1990.
-  uint32_t seconds;
-
-  /// The index of the first event for this pulse.
-  uint64_t event_index;
-
-  /// The proton charge for the pulse.
-  double pCurrent;
-};
-#pragma pack(pop)
-
-class DLLExport LoadEventPreNexus
-    : public API::IFileLoader<Kernel::FileDescriptor>,
-      public API::DeprecatedAlgorithm {
-public:
-  /// Constructor
-  LoadEventPreNexus();
-  /// Virtual destructor
-  ~LoadEventPreNexus() override;
-  /// Algorithm's name
-  const std::string name() const override { return "LoadEventPreNexus"; }
-  /// Summary of algorithms purpose
-  const std::string summary() const override {
-    return "Loads SNS raw neutron event data format and stores it in a "
-           "workspace (EventWorkspace class).";
-  }
-
-  /// Algorithm's version
-  int version() const override { return (1); }
-  /// Algorithm's category for identification
-  const std::string category() const override {
-    return "DataHandling\\PreNexus";
-  }
-  /// Algorithm's aliases
-  const std::string alias() const override { return "LoadEventPreNeXus"; }
-
-  /// Returns a confidence value that this algorithm can load a file
-  int confidence(Kernel::FileDescriptor &descriptor) const override;
-
-private:
-  /// Initialisation code
-  void init() override;
-  /// Execution code
-  void exec() override;
-
-  Mantid::API::Progress *prog;
-
-  std::vector<int64_t> spectra_list; ///<the list of Spectra
-
-  /// The times for each pulse.
-  std::vector<Kernel::DateAndTime> pulsetimes;
-  /// The index of the first event in each pulse.
-  std::vector<uint64_t> event_indices;
-  /// The proton charge on a pulse by pulse basis.
-  std::vector<double> proton_charge;
-  /// The total proton charge for the run.
-  double proton_charge_tot;
-  /// The value of the vector is the workspace index. The index into it is the
-  /// pixel ID from DAS
-  std::vector<std::size_t> pixel_to_wkspindex;
-  /// Map between the DAS pixel IDs and our pixel IDs, used while loading.
-  std::vector<PixelType> pixelmap;
-
-  /// The maximum detector ID possible
-  Mantid::detid_t detid_max;
-
-  /// Handles loading from the event file
-  Mantid::Kernel::BinaryFile<DasEvent> *eventfile;
-  std::size_t num_events; ///< The number of events in the file
-  std::size_t num_pulses; ///<the number of pulses
-  uint32_t numpixel;      ///<the number of pixels
-
-  std::size_t num_good_events;  ///< The number of good events loaded
-  std::size_t num_error_events; ///< The number of error events encountered
-  /// the number of events that were ignored (not loaded) because, e.g. of only
-  /// loading some spectra.
-  std::size_t num_ignored_events;
-  std::size_t first_event; ///< The first event to load (count from zero)
-  std::size_t max_events;  ///< Number of events to load
-
-  /// Set to true if a valid Mapping file was provided.
-  bool using_mapping_file;
-
-  /// For loading only some spectra
-  bool loadOnlySomeSpectra;
-  /// Handle to the loaded spectra map
-  std::map<int64_t, bool> spectraLoadMap;
-
-  /// Longest TOF limit
-  double longest_tof;
-  /// Shortest TOF limit
-  double shortest_tof;
-
-  /// Flag to allow for parallel loading
-  bool parallelProcessing;
-
-  void loadPixelMap(const std::string &filename);
-
-  void openEventFile(const std::string &filename);
-
-  void readPulseidFile(const std::string &filename, const bool throwError);
-
-  void runLoadInstrument(const std::string &eventfilename,
-                         API::MatrixWorkspace_sptr localWorkspace);
-
-  inline void fixPixelId(PixelType &pixel, uint32_t &period) const;
-
-  void procEvents(DataObjects::EventWorkspace_sptr &workspace);
-
-  void procEventsLinear(DataObjects::EventWorkspace_sptr &workspace,
-                        std::vector<DataObjects::TofEvent> **arrayOfVectors,
-                        DasEvent *event_buffer,
-                        size_t current_event_buffer_size, size_t fileOffset);
-
-  void setProtonCharge(DataObjects::EventWorkspace_sptr &workspace);
-};
-}
-}
-#endif /*LOADEVENTPRENEXUS_H_*/
diff --git a/Framework/DataHandling/inc/MantidDataHandling/LoadILL.h b/Framework/DataHandling/inc/MantidDataHandling/LoadILL.h
deleted file mode 100644
index 9c6ea8f5227030fda4fc2bf751f1fa647befce5c..0000000000000000000000000000000000000000
--- a/Framework/DataHandling/inc/MantidDataHandling/LoadILL.h
+++ /dev/null
@@ -1,49 +0,0 @@
-#ifndef MANTID_DATAHANDLING_LOADILL_H_
-#define MANTID_DATAHANDLING_LOADILL_H_
-
-#include "MantidAPI/IFileLoader.h"
-#include "MantidNexus/NexusClasses.h"
-#include "MantidDataHandling/LoadHelper.h"
-#include "MantidAPI/DeprecatedAlgorithm.h"
-#include "MantidDataHandling/LoadILLTOF.h"
-
-namespace Mantid {
-namespace DataHandling {
-/**
- Loads an ILL IN4/5/6 nexus file into a Mantid workspace.
-
- Copyright &copy; 2016 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>
- */
-class DLLExport LoadILL : public LoadILLTOF, public API::DeprecatedAlgorithm {
-public:
-  /// Constructor
-  LoadILL();
-  /// Algorithm's name
-  const std::string name() const override { return "LoadILL"; }
-  /// Returns a confidence value that this algorithm can load a file
-  int confidence(Kernel::NexusDescriptor &descriptor) const override;
-};
-
-} // namespace DataHandling
-} // namespace Mantid
-
-#endif /*MANTID_DATAHANDLING_LoadILL_H_*/
diff --git a/Framework/DataHandling/inc/MantidDataHandling/LoadILLIndirect2.h b/Framework/DataHandling/inc/MantidDataHandling/LoadILLIndirect2.h
new file mode 100644
index 0000000000000000000000000000000000000000..ab552a992cfc4fa8c3796a33d27141aa011305a3
--- /dev/null
+++ b/Framework/DataHandling/inc/MantidDataHandling/LoadILLIndirect2.h
@@ -0,0 +1,95 @@
+#ifndef MANTID_DATAHANDLING_LOADILLINDIRECT2_H_
+#define MANTID_DATAHANDLING_LOADILLINDIRECT2_H_
+
+#include "MantidAPI/IFileLoader.h"
+#include "MantidDataHandling/LoadHelper.h"
+#include "MantidNexus/NexusClasses.h"
+
+namespace Mantid {
+namespace DataHandling {
+
+/**
+  Loads an ILL IN16B nexus file into a Mantid workspace.
+
+  Copyright &copy; 2014 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>
+*/
+class DLLExport LoadILLIndirect2
+    : public API::IFileLoader<Kernel::NexusDescriptor> {
+public:
+  LoadILLIndirect2();
+  /// Returns a confidence value that this algorithm can load a file
+  int confidence(Kernel::NexusDescriptor &descriptor) const override;
+
+  /// Algorithm's version for identification. @see Algorithm::version
+  int version() const override { return 2; }
+
+  const std::string name() const override;
+  /// Summary of algorithms purpose
+  const std::string summary() const override {
+    return "Loads a ILL/IN16B nexus file.";
+  }
+  const std::string category() const override;
+
+private:
+  void init() override;
+  void exec() override;
+
+  void loadDataDetails(NeXus::NXEntry &entry);
+  void initWorkSpace(NeXus::NXEntry &entry,
+                     std::vector<std::vector<int>> monitorsData);
+  void setInstrumentName(const NeXus::NXEntry &firstEntry,
+                         const std::string &instrumentNamePath);
+  void loadNexusEntriesIntoProperties(std::string nexusfilename);
+  void loadDataIntoTheWorkSpace(NeXus::NXEntry &entry,
+                                std::vector<std::vector<int>> monitorsData);
+  std::vector<std::vector<int>> loadMonitors(NeXus::NXEntry &entry);
+
+  void runLoadInstrument();
+
+  /// Calculate error for y
+  static double calculateError(double in) { return sqrt(in); }
+
+  void moveComponent(const std::string &, double);
+  void moveSingleDetectors(NeXus::NXEntry &entry);
+
+  API::MatrixWorkspace_sptr m_localWorkspace;
+
+  std::string m_instrumentName; ///< Name of the instrument
+
+  // Variables describing the data in the detector
+  size_t m_numberOfTubes;           // number of tubes - X
+  size_t m_numberOfPixelsPerTube;   // number of pixels per tube - Y
+  size_t m_numberOfChannels;        // time channels - Z
+  size_t m_numberOfSimpleDetectors; // number of simple detector
+  size_t m_numberOfHistograms;      // number of spectra
+  size_t m_numberOfMonitors;        // number of monitor spectra
+  std::set<int> m_activeSDIndices;  // set of Single Detector indices,
+                                    // that were actually active
+
+  std::vector<std::string> m_supportedInstruments;
+  LoadHelper m_loader;
+};
+
+} // namespace DataHandling
+} // namespace Mantid
+
+#endif /* MANTID_DATAHANDLING_LOADILLINDIRECT2_H_ */
diff --git a/Framework/DataHandling/inc/MantidDataHandling/LoadILLTOF.h b/Framework/DataHandling/inc/MantidDataHandling/LoadILLTOF.h
index c20363e1bc7961d61b8a97bb028447bd99b8509e..9c53bb11b9cce438561162c4209a54a77437c263 100644
--- a/Framework/DataHandling/inc/MantidDataHandling/LoadILLTOF.h
+++ b/Framework/DataHandling/inc/MantidDataHandling/LoadILLTOF.h
@@ -8,6 +8,7 @@
 #include "MantidNexus/NexusClasses.h"
 #include "MantidDataHandling/LoadHelper.h"
 #include "MantidGeometry/IDTypes.h"
+#include "MantidAPI/DeprecatedAlgorithm.h"
 #include "MantidAPI/Progress.h"
 
 namespace Mantid {
@@ -36,7 +37,8 @@ namespace DataHandling {
  File change history is stored at: <https://github.com/mantidproject/mantid>
  Code Documentation is available at: <http://doxygen.mantidproject.org>
  */
-class DLLExport LoadILLTOF : public API::IFileLoader<Kernel::NexusDescriptor> {
+class DLLExport LoadILLTOF : public API::IFileLoader<Kernel::NexusDescriptor>,
+                             public API::DeprecatedAlgorithm {
 public:
   /// Constructor
   LoadILLTOF();
diff --git a/Framework/DataHandling/inc/MantidDataHandling/LoadILLTOF2.h b/Framework/DataHandling/inc/MantidDataHandling/LoadILLTOF2.h
new file mode 100644
index 0000000000000000000000000000000000000000..abff769124b80d295dc7ea146f97d81c4f9ad0f9
--- /dev/null
+++ b/Framework/DataHandling/inc/MantidDataHandling/LoadILLTOF2.h
@@ -0,0 +1,107 @@
+#ifndef MANTID_DATAHANDLING_LOADILLTOF2_H_
+#define MANTID_DATAHANDLING_LOADILLTOF2_H_
+
+#include "MantidAPI/IFileLoader.h"
+#include "MantidNexus/NexusClasses.h"
+#include "MantidDataHandling/LoadHelper.h"
+#include "MantidGeometry/IDTypes.h"
+
+namespace Mantid {
+namespace DataHandling {
+/**
+ Loads an ILL IN4/5/6 nexus file into a Mantid workspace.
+
+ Copyright &copy; 2016 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>
+ */
+class DLLExport LoadILLTOF2 : public API::IFileLoader<Kernel::NexusDescriptor> {
+public:
+  /// Constructor
+  LoadILLTOF2();
+  /// Algorithm's name
+  const std::string name() const override { return "LoadILLTOF"; }
+  /// Summary of algorithms purpose
+  const std::string summary() const override {
+    return "Loads an ILL TOF NeXus file.";
+  }
+
+  /// Algorithm's version
+  int version() const override { return 2; }
+  /// Algorithm's category for identification
+  const std::string category() const override { return "DataHandling\\Nexus"; }
+
+  /// Returns a confidence value that this algorithm can load a file
+  int confidence(Kernel::NexusDescriptor &descriptor) const override;
+
+private:
+  const static std::vector<std::string> SUPPORTED_INSTRUMENTS;
+
+  // Initialisation code
+  void init() override;
+  // Execution code
+  void exec() override;
+
+  void loadInstrumentDetails(NeXus::NXEntry &);
+  std::vector<std::vector<int>> getMonitorInfo(NeXus::NXEntry &firstEntry);
+  void initWorkSpace(NeXus::NXEntry &entry,
+                     const std::vector<std::vector<int>> &);
+  void initInstrumentSpecific();
+  void addAllNexusFieldsAsProperties(const std::string &filename);
+  void addEnergyToRun();
+  void addFacility();
+  void addPulseInterval();
+
+  void loadTimeDetails(NeXus::NXEntry &entry);
+  void loadDataIntoTheWorkSpace(NeXus::NXEntry &entry,
+                                const std::vector<std::vector<int>> &);
+  void loadSpectra(size_t &spec, const size_t numberOfMonitors,
+                   const size_t numberOfTubes,
+                   const std::vector<Mantid::detid_t> &detectorIDs,
+                   NeXus::NXInt data, Mantid::API::Progress progress);
+
+  void runLoadInstrument();
+
+  /// Calculate error for y
+  static double calculateError(double in) { return sqrt(in); }
+
+  API::MatrixWorkspace_sptr m_localWorkspace;
+
+  std::string m_instrumentName = ""; ///< Name of the instrument
+  std::string m_instrumentPath = ""; ///< Name of the instrument path
+
+  // Variables describing the data in the detector
+  size_t m_numberOfTubes = 0;         // number of tubes - X
+  size_t m_numberOfPixelsPerTube = 0; // number of pixels per tube - Y
+  size_t m_numberOfChannels = 0;      // time channels - Z
+  size_t m_numberOfHistograms = 0;
+
+  /* Values parsed from the nexus file */
+  double m_wavelength = 0;
+  double m_channelWidth = 0;
+  double m_timeOfFlightDelay = 0;
+
+  LoadHelper m_loader;
+};
+
+} // namespace DataHandling
+} // namespace Mantid
+
+#endif /*MANTID_DATAHANDLING_LOADILLTOF2_H_*/
diff --git a/Framework/DataHandling/inc/MantidDataHandling/LoadLogsForSNSPulsedMagnet.h b/Framework/DataHandling/inc/MantidDataHandling/LoadLogsForSNSPulsedMagnet.h
deleted file mode 100644
index 5858426957c96b1b23271194f783a25b99907805..0000000000000000000000000000000000000000
--- a/Framework/DataHandling/inc/MantidDataHandling/LoadLogsForSNSPulsedMagnet.h
+++ /dev/null
@@ -1,70 +0,0 @@
-#ifndef MANTID_DATAHANDLING_LOADLOGSFORSNSPULSEDMAGNET_H_
-#define MANTID_DATAHANDLING_LOADLOGSFORSNSPULSEDMAGNET_H_
-
-#include "MantidKernel/System.h"
-#include "MantidAPI/Algorithm.h"
-#include "MantidKernel/DateAndTime.h"
-#include "MantidKernel/TimeSeriesProperty.h"
-
-#include <vector>
-
-namespace Mantid {
-namespace DataHandling {
-
-/** LoadLogsForSNSPulsedMagnet : TODO: DESCRIPTION
- *
- * @author
- * @date 2011-06-07
- */
-class DLLExport LoadLogsForSNSPulsedMagnet : public API::Algorithm {
-public:
-  LoadLogsForSNSPulsedMagnet();
-  ~LoadLogsForSNSPulsedMagnet() override;
-
-  /// Algorithm's name for identification
-  const std::string name() const override {
-    return "LoadLogsForSNSPulsedMagnet";
-  };
-  /// Summary of algorithms purpose
-  const std::string summary() const override {
-    return "Both log files are in binary format";
-  }
-
-  /// Algorithm's version for identification
-  int version() const override { return 1; };
-  /// Algorithm's category for identification
-  const std::string category() const override { return "DataHandling\\Logs"; }
-
-private:
-  /// Initialise the properties
-  void init() override;
-  /// Run the algorithm
-  void exec() override;
-
-  /// Parse DelayTime log file
-  void ParseDelayTimeLogFile();
-
-  /// Parse PulseID log file
-  void ParsePulseIDLogFile();
-
-  /// Integrate to TimeSeriesProperty
-  void addProperty();
-
-  std::string m_delaytimefilename;
-  std::string m_pulseidfilename;
-
-  bool m_delayfileinoldformat;
-
-  std::size_t m_numpulses;
-  int m_numchoppers;
-  unsigned int **m_delaytimes;
-  std::vector<uint32_t> m_pulseidseconds;
-  std::vector<uint32_t> m_pulseidnanoseconds;
-
-  API::MatrixWorkspace_sptr WS;
-};
-
-} // namespace Mantid
-} // namespace DataHandling
-
-#endif /* MANTID_DATAHANDLING_LOADLOGSFORSNSPULSEDMAGNET_H_ */
diff --git a/Framework/DataHandling/inc/MantidDataHandling/LoadNexusMonitors.h b/Framework/DataHandling/inc/MantidDataHandling/LoadNexusMonitors.h
index 32454e84b3920f2956cae62b0d202c1cc19427c2..8b284a2c647a715b113d51a9873101461f9189bd 100644
--- a/Framework/DataHandling/inc/MantidDataHandling/LoadNexusMonitors.h
+++ b/Framework/DataHandling/inc/MantidDataHandling/LoadNexusMonitors.h
@@ -2,6 +2,7 @@
 #define MANTID_DATAHANDLING_LOADNEXUSMONITORS_H_
 
 #include "MantidAPI/Algorithm.h"
+#include "MantidAPI/DeprecatedAlgorithm.h"
 
 namespace Mantid {
 namespace DataHandling {
@@ -40,8 +41,12 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 File change history is stored at: <https://github.com/mantidproject/mantid>
 */
-class DLLExport LoadNexusMonitors : public API::Algorithm {
+class DLLExport LoadNexusMonitors : public API::Algorithm,
+                                    public API::DeprecatedAlgorithm {
 public:
+  /// Constructor
+  LoadNexusMonitors() { this->useAlgorithm("LoadNexusMonitors", 2); }
+
   /// Algorithm's name for identification overriding a virtual method
   const std::string name() const override { return "LoadNexusMonitors"; }
 
diff --git a/Framework/DataHandling/inc/MantidDataHandling/LoadNexusMonitors2.h b/Framework/DataHandling/inc/MantidDataHandling/LoadNexusMonitors2.h
index fe074f92b010928a700deef80939c5736594e9c8..39157303eacc33ed780b58057992f4ad4703d680 100644
--- a/Framework/DataHandling/inc/MantidDataHandling/LoadNexusMonitors2.h
+++ b/Framework/DataHandling/inc/MantidDataHandling/LoadNexusMonitors2.h
@@ -5,8 +5,8 @@
 #include "MantidAPI/MatrixWorkspace_fwd.h"
 #include "MantidGeometry/IDTypes.h"
 #include <boost/scoped_array.hpp>
-#include <nexus/NeXusException.hpp>
 #include <nexus/NeXusFile.hpp>
+#include <nexus/NeXusException.hpp>
 
 namespace Mantid {
 namespace DataHandling {
diff --git a/Framework/DataHandling/inc/MantidDataHandling/LoadRawHelper.h b/Framework/DataHandling/inc/MantidDataHandling/LoadRawHelper.h
index 51293d676c6db9d1f2a1b80b873528030fcbfc6a..6d2faee4ef1d5cdc776e808e015554a003efb367 100644
--- a/Framework/DataHandling/inc/MantidDataHandling/LoadRawHelper.h
+++ b/Framework/DataHandling/inc/MantidDataHandling/LoadRawHelper.h
@@ -5,12 +5,10 @@
 #include "MantidDataObjects/Workspace2D.h"
 #include "MantidDataHandling/ISISRunLogs.h"
 #include "MantidAPI/Run.h"
+#include "MantidAPI/WorkspaceGroup_fwd.h"
 #include <boost/scoped_ptr.hpp>
 #include <climits>
 
-//----------------------------------------------------------------------
-// Forward declaration
-//----------------------------------------------------------------------
 class ISISRAW;
 class ISISRAW2;
 
diff --git a/Framework/DataHandling/inc/MantidDataHandling/LoadSpice2D.h b/Framework/DataHandling/inc/MantidDataHandling/LoadSpice2D.h
index 473849ed9418813a9debc5999d0b31332b9925c2..3908d455a4337d8b1dfca2c637b94689857d9ed0 100644
--- a/Framework/DataHandling/inc/MantidDataHandling/LoadSpice2D.h
+++ b/Framework/DataHandling/inc/MantidDataHandling/LoadSpice2D.h
@@ -1,9 +1,7 @@
 #ifndef MANTID_DATAHANDLING_LoadSpice2D_H
 #define MANTID_DATAHANDLING_LoadSpice2D_H
 
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
+#include "MantidKernel/DateAndTime.h"
 #include "MantidAPI/IFileLoader.h"
 #include "MantidDataObjects/Workspace2D.h"
 #include "MantidDataHandling/XmlHandler.h"
@@ -12,8 +10,6 @@
 #include <vector>
 #include <utility>
 
-//----------------------------------------------------------------------
-
 namespace Poco {
 namespace XML {
 class Element;
diff --git a/Framework/DataHandling/inc/MantidDataHandling/LoadSpiceXML2DDet.h b/Framework/DataHandling/inc/MantidDataHandling/LoadSpiceXML2DDet.h
index 2ca875626e948a142d4c34efaaea40519c43973e..ea13c77dc54ee1c22a7ff1b516503051e6121ad9 100644
--- a/Framework/DataHandling/inc/MantidDataHandling/LoadSpiceXML2DDet.h
+++ b/Framework/DataHandling/inc/MantidDataHandling/LoadSpiceXML2DDet.h
@@ -133,6 +133,9 @@ private:
   std::string m_idfFileName;
   /// User specified wave length
   double m_userSpecifiedWaveLength;
+  /// shift of detector on X and Y direction
+  double m_detXShift;
+  double m_detYShift;
 };
 
 } // namespace DataHandling
diff --git a/Framework/DataHandling/inc/MantidDataHandling/MaskDetectors.h b/Framework/DataHandling/inc/MantidDataHandling/MaskDetectors.h
index 0009d23a3e6bd671de9b5f1295a51b919bf90d00..dfcdfd76c8e2b227d7541ecc5bc6fac4dd5f1b7f 100644
--- a/Framework/DataHandling/inc/MantidDataHandling/MaskDetectors.h
+++ b/Framework/DataHandling/inc/MantidDataHandling/MaskDetectors.h
@@ -69,6 +69,9 @@ public:
   const std::string category() const override { return "Transforms\\Masking"; }
 
 private:
+  // create type for range information
+  using RangeInfo = std::tuple<size_t, size_t, bool>;
+
   const std::string workspaceMethodName() const override {
     return "maskDetectors";
   }
@@ -79,16 +82,40 @@ private:
   // Implement abstract Algorithm methods
   void init() override;
   void exec() override;
-  void execPeaks(DataObjects::PeaksWorkspace_sptr WS);
+
+  /// Choose how to mask given that we have a mask workspace
   void
-  fillIndexListFromSpectra(std::vector<size_t> &indexList,
-                           const std::vector<specnum_t> &spectraList,
-                           const API::MatrixWorkspace_sptr WS,
-                           const std::tuple<size_t, size_t, bool> &range_info);
+  handleMaskByMaskWorkspace(const DataObjects::MaskWorkspace_const_sptr maskWs,
+                            const API::MatrixWorkspace_const_sptr WS,
+                            std::vector<detid_t> &detectorList,
+                            std::vector<size_t> &indexList,
+                            const RangeInfo &rangeInfo);
+
+  /// Choose how to mask given that we have a matrix workspace
+  void handleMaskByMatrixWorkspace(const API::MatrixWorkspace_const_sptr maskWs,
+                                   const API::MatrixWorkspace_const_sptr WS,
+                                   std::vector<detid_t> &detectorList,
+                                   std::vector<size_t> &indexList,
+                                   const RangeInfo &rangeInfo);
+
+  void execPeaks(DataObjects::PeaksWorkspace_sptr WS);
+  void fillIndexListFromSpectra(std::vector<size_t> &indexList,
+                                const std::vector<specnum_t> &spectraList,
+                                const API::MatrixWorkspace_sptr WS,
+                                const RangeInfo &range_info);
+  void appendToDetectorListFromComponentList(
+      std::vector<detid_t> &detectorList,
+      const std::vector<std::string> &componentList,
+      const API::MatrixWorkspace_const_sptr WS);
   void
   appendToIndexListFromWS(std::vector<size_t> &indexList,
-                          const API::MatrixWorkspace_sptr maskedWorkspace,
-                          const std::tuple<size_t, size_t, bool> &range_info);
+                          const API::MatrixWorkspace_const_sptr maskedWorkspace,
+                          const RangeInfo &range_info);
+  void appendToDetectorListFromWS(
+      std::vector<detid_t> &detectorList,
+      const API::MatrixWorkspace_const_sptr inputWs,
+      const API::MatrixWorkspace_const_sptr maskWs,
+      const std::tuple<size_t, size_t, bool> &range_info);
   void appendToIndexListFromMaskWS(
       std::vector<size_t> &indexList,
       const DataObjects::MaskWorkspace_const_sptr maskedWorkspace,
@@ -96,12 +123,10 @@ private:
   void
   extractMaskedWSDetIDs(std::vector<detid_t> &detectorList,
                         const DataObjects::MaskWorkspace_const_sptr &maskWS);
-  void
-  constrainMaskedIndexes(std::vector<size_t> &indexList,
-                         const std::tuple<size_t, size_t, bool> &range_info);
+  void constrainMaskedIndexes(std::vector<size_t> &indexList,
+                              const RangeInfo &range_info);
 
-  std::tuple<size_t, size_t, bool>
-  getRanges(const API::MatrixWorkspace_sptr &targWS);
+  RangeInfo getRanges(const API::MatrixWorkspace_sptr &targWS);
 };
 
 } // namespace DataHandling
diff --git a/Framework/DataHandling/inc/MantidDataHandling/PDLoadCharacterizations.h b/Framework/DataHandling/inc/MantidDataHandling/PDLoadCharacterizations.h
index 9bf73f272bbd84dfbbfc92448c63878ea936f1d1..7e0b8e11fce5300c8547c11f03cbcde637975b9a 100644
--- a/Framework/DataHandling/inc/MantidDataHandling/PDLoadCharacterizations.h
+++ b/Framework/DataHandling/inc/MantidDataHandling/PDLoadCharacterizations.h
@@ -47,8 +47,13 @@ public:
 private:
   void init() override;
   void exec() override;
+  std::vector<std::string> getFilenames();
   void readFocusInfo(std::ifstream &file);
   void readCharInfo(std::ifstream &file, API::ITableWorkspace_sptr &wksp);
+  void readVersion0(const std::string &filename,
+                    API::ITableWorkspace_sptr &wksp);
+  void readVersion1(const std::string &filename,
+                    API::ITableWorkspace_sptr &wksp);
   void readExpIni(const std::string &filename, API::ITableWorkspace_sptr &wksp);
 };
 
diff --git a/Framework/DataHandling/inc/MantidDataHandling/ProcessDasNexusLog.h b/Framework/DataHandling/inc/MantidDataHandling/ProcessDasNexusLog.h
deleted file mode 100644
index 5b8c473abcd5888297e48d9a32755ed5e164a7c7..0000000000000000000000000000000000000000
--- a/Framework/DataHandling/inc/MantidDataHandling/ProcessDasNexusLog.h
+++ /dev/null
@@ -1,79 +0,0 @@
-#ifndef MANTID_DATAHANDLING_PROCESSDASNEXUSLOG_H_
-#define MANTID_DATAHANDLING_PROCESSDASNEXUSLOG_H_
-
-#include "MantidKernel/System.h"
-#include "MantidAPI/Algorithm.h"
-#include "MantidAPI/DeprecatedAlgorithm.h"
-
-namespace Mantid {
-namespace DataHandling {
-
-/** ProcessDasNexusLog : TODO: DESCRIPTION
-
-  @date 2012-01-23
-
-  Copyright &copy; 2012 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>
-*/
-class DLLExport ProcessDasNexusLog : public API::Algorithm,
-                                     public API::DeprecatedAlgorithm {
-public:
-  ProcessDasNexusLog();
-  const std::string name() const override { return "ProcessDasNexusLog"; };
-  /// Summary of algorithms purpose
-  const std::string summary() const override {
-    return "Very specialized algorithm to fix certain SNS DAS logs that cannot "
-           "be used directly.";
-  }
-
-  int version() const override { return 1; };
-  const std::string category() const override { return "DataHandling\\Logs"; };
-
-private:
-  void init() override;
-  void exec() override;
-
-  void convertToAbsoluteTime(API::MatrixWorkspace_sptr ws, std::string logname,
-                             std::vector<Kernel::DateAndTime> &abstimevec,
-                             std::vector<double> &orderedtofs);
-
-  void writeLogtoFile(API::MatrixWorkspace_sptr ws, std::string logname,
-                      size_t numentriesoutput, std::string outputfilename);
-
-  void addLog(API::MatrixWorkspace_sptr ws,
-              std::vector<Kernel::DateAndTime> timevec, double unifylogvalue,
-              std::string logname, std::vector<Kernel::DateAndTime> pulsetimes,
-              std::vector<double> orderedtofs, bool);
-
-  void checkLog(API::MatrixWorkspace_sptr ws, std::string logname);
-
-  void calDistributions(std::vector<Kernel::DateAndTime>, double dts);
-
-  void exportErrorLog(API::MatrixWorkspace_sptr ws,
-                      std::vector<Kernel::DateAndTime> abstimevec,
-                      std::vector<Kernel::DateAndTime> pulsetimes,
-                      std::vector<double> orderedtofs, double dts);
-};
-
-} // namespace DataHandling
-} // namespace Mantid
-
-#endif /* MANTID_DATAHANDLING_PROCESSDASNEXUSLOG_H_ */
diff --git a/Framework/DataHandling/inc/MantidDataHandling/SaveANSTOAscii.h b/Framework/DataHandling/inc/MantidDataHandling/SaveANSTOAscii.h
index 3da2d33c37c3b854228b05d7529648d8537d4e42..5cd322be4f189b2b2f01a79de3c335f98e4e34de 100644
--- a/Framework/DataHandling/inc/MantidDataHandling/SaveANSTOAscii.h
+++ b/Framework/DataHandling/inc/MantidDataHandling/SaveANSTOAscii.h
@@ -54,8 +54,8 @@ private:
   std::string ext() override { return ".txt"; }
   /// return if the line should start with a separator
   bool leadingSep() override { return false; }
-  /// no extra properties required so override blank
-  void extraProps() override {}
+  /// only separator property required, nothing else
+  void extraProps() override { appendSeparatorProperty(); }
   /// no extra information required so override blank
   void extraHeaders(std::ofstream &file) override;
 };
diff --git a/Framework/DataHandling/inc/MantidDataHandling/SaveISISNexus.h b/Framework/DataHandling/inc/MantidDataHandling/SaveISISNexus.h
index ad4e8fa3a1ef783075c3a895bca1b4216a6a89a2..4c070da9edc4d139633ecc9e8cd16f6220f3f9a9 100644
--- a/Framework/DataHandling/inc/MantidDataHandling/SaveISISNexus.h
+++ b/Framework/DataHandling/inc/MantidDataHandling/SaveISISNexus.h
@@ -1,16 +1,12 @@
 #ifndef MANTID_DATAHANDLING_SAVEISISNEXUS_H_
 #define MANTID_DATAHANDLING_SAVEISISNEXUS_H_
 
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidAPI/Algorithm.h"
 
+#include <nexus/NeXusFile.hpp>
+
 #include <climits>
 
-//----------------------------------------------------------------------
-// Forward declaration
-//----------------------------------------------------------------------
 class ISISRAW2;
 
 namespace Mantid {
diff --git a/Framework/DataHandling/inc/MantidDataHandling/SetSample.h b/Framework/DataHandling/inc/MantidDataHandling/SetSample.h
index cafbf459fffb8ffec00a93504c4229b9f4135918..6769bd955b1d072b382907e536ddbc38b0c71856 100644
--- a/Framework/DataHandling/inc/MantidDataHandling/SetSample.h
+++ b/Framework/DataHandling/inc/MantidDataHandling/SetSample.h
@@ -7,6 +7,7 @@
 
 namespace Mantid {
 namespace Geometry {
+class ReferenceFrame;
 class SampleEnvironment;
 }
 namespace DataHandling {
@@ -49,13 +50,18 @@ private:
 
   const Geometry::SampleEnvironment *
   setSampleEnvironment(API::MatrixWorkspace_sptr &workspace,
-                       const Kernel::PropertyManager &args);
+                       const Kernel::PropertyManager_const_sptr &args);
   void setSampleShape(API::MatrixWorkspace_sptr &workspace,
-                      const Kernel::PropertyManager_sptr &args,
+                      const Kernel::PropertyManager_const_sptr &args,
                       const Geometry::SampleEnvironment *sampleEnv);
-  std::string tryCreateXMLFromArgsOnly(const Kernel::PropertyManager_sptr args);
-  std::string createFlatPlateXML(const Kernel::PropertyManager &args) const;
+  std::string
+  tryCreateXMLFromArgsOnly(const Kernel::PropertyManager &args,
+                           const Geometry::ReferenceFrame &refFrame);
+  std::string
+  createFlatPlateXML(const Kernel::PropertyManager &args,
+                     const Geometry::ReferenceFrame &refFrame) const;
   std::string createCylinderLikeXML(const Kernel::PropertyManager &args,
+                                    const Geometry::ReferenceFrame &refFrame,
                                     bool hollow) const;
 
   void runSetSampleShape(API::MatrixWorkspace_sptr &workspace,
diff --git a/Framework/DataHandling/inc/MantidDataHandling/UpdateInstrumentFromFile.h b/Framework/DataHandling/inc/MantidDataHandling/UpdateInstrumentFromFile.h
index 22924d2b24010e15f3ef87efabba614a38a808f6..fe6ea44c31f297cf73e3335ec0e3a729331624c9 100644
--- a/Framework/DataHandling/inc/MantidDataHandling/UpdateInstrumentFromFile.h
+++ b/Framework/DataHandling/inc/MantidDataHandling/UpdateInstrumentFromFile.h
@@ -1,20 +1,17 @@
 #ifndef MANTID_DATAHANDLING_UPDATEINSTRUMENTFROMFILE_H_
 #define MANTID_DATAHANDLING_UPDATEINSTRUMENTFROMFILE_H_
 
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidAPI/Algorithm.h"
 #include "MantidGeometry/IDetector.h"
 #include <nexus/NeXusFile.hpp>
 
 namespace Mantid {
-//----------------------------------------------------------------------
-// Forward declarations
-//----------------------------------------------------------------------
 namespace Geometry {
 class Instrument;
 }
+namespace API {
+class DetectorInfo;
+}
 
 namespace DataHandling {
 /**
@@ -109,16 +106,13 @@ private:
 
   /// Parse the header and fill the headerInfo struct
   bool parseAsciiHeader(AsciiFileHeader &headerInfo);
-  /// Set a new detector parameter
-  void setDetectorParameter(const Geometry::IDetector_const_sptr &det,
-                            const std::string &name, double value);
   /// Set the new detector positions
   void setDetectorPositions(const std::vector<int32_t> &detID,
                             const std::vector<float> &l2,
                             const std::vector<float> &theta,
                             const std::vector<float> &phi);
   /// Set the new detector position for a single det ID
-  void setDetectorPosition(const Geometry::IDetector_const_sptr &det,
+  void setDetectorPosition(API::DetectorInfo &detectorInfo, const size_t index,
                            const float l2, const float theta, const float phi);
 
   /// The input workspace to modify
diff --git a/Framework/DataHandling/src/AsciiPointBase.cpp b/Framework/DataHandling/src/AsciiPointBase.cpp
index 30e72e1dc2af2cc513d1b5c6decf80ffd4194f90..9d919bd677c1d96d1fac3aefdd986a708bbbff4b 100644
--- a/Framework/DataHandling/src/AsciiPointBase.cpp
+++ b/Framework/DataHandling/src/AsciiPointBase.cpp
@@ -4,15 +4,15 @@ SaveILLCosmosAscii and SaveANSTOAscii export-only Acii-based save formats. It is
 based on a python script by Maximilian Skoda, written for the ISIS Reflectometry
 GUI
 */
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidDataHandling/AsciiPointBase.h"
 #include "MantidAPI/FileProperty.h"
 #include "MantidAPI/MatrixWorkspace.h"
+#include "MantidKernel/ListValidator.h"
 
+#include <boost/lexical_cast.hpp>
 #include <boost/tokenizer.hpp>
 #include <boost/regex.hpp>
+#include <boost/make_shared.hpp>
 #include <cmath>
 #include <fstream>
 
@@ -30,6 +30,7 @@ void AsciiPointBase::init() {
   declareProperty(Kernel::make_unique<FileProperty>("Filename", "",
                                                     FileProperty::Save, ext()),
                   "The filename of the output file.");
+
   extraProps();
 }
 
@@ -46,7 +47,14 @@ void AsciiPointBase::exec() {
   }
   m_ws = getProperty("InputWorkspace");
   g_log.information("FILENAME: " + filename);
-
+  std::string sepOption = getProperty("Separator");
+  if (sepOption == "comma") {
+    m_sep = ',';
+  } else if (sepOption == "space") {
+    m_sep = ' ';
+  } else {
+    m_sep = '\t';
+  }
   std::vector<double> XData = header(file);
   extraHeaders(file);
   data(file, XData);
@@ -114,7 +122,7 @@ void AsciiPointBase::outputval(double val, std::ofstream &file,
   bool nancheck = std::isnan(val);
   bool infcheck = std::isinf(val);
   if (leadingSep) {
-    file << sep();
+    file << m_sep;
   }
   if (!nancheck && !infcheck) {
     file << val;
@@ -127,5 +135,16 @@ void AsciiPointBase::outputval(double val, std::ofstream &file,
   }
 }
 
+/** appends the separator property to the algorithm
+ */
+void AsciiPointBase::appendSeparatorProperty() {
+  std::vector<std::string> propOptions;
+  propOptions.push_back("comma");
+  propOptions.push_back("space");
+  propOptions.push_back("tab");
+  declareProperty("Separator", "tab",
+                  boost::make_shared<StringListValidator>(propOptions),
+                  "The separator used for splitting data columns.");
+}
 } // namespace DataHandling
 } // namespace Mantid
diff --git a/Framework/DataHandling/src/CheckMantidVersion.cpp b/Framework/DataHandling/src/CheckMantidVersion.cpp
index 4f9929c48c692a132382cb2ad569c68f1688ade4..c5b1c4b9e581409a29b0839f70d0a8b728e38b5f 100644
--- a/Framework/DataHandling/src/CheckMantidVersion.cpp
+++ b/Framework/DataHandling/src/CheckMantidVersion.cpp
@@ -1,4 +1,5 @@
 #include "MantidDataHandling/CheckMantidVersion.h"
+#include "MantidKernel/ConfigService.h"
 #include "MantidKernel/GitHubApiHelper.h"
 #include "MantidKernel/MantidVersion.h"
 #include "MantidKernel/Strings.h"
@@ -22,8 +23,6 @@ using Mantid::API::WorkspaceProperty;
 // Register the algorithm into the AlgorithmFactory
 DECLARE_ALGORITHM(CheckMantidVersion)
 
-//----------------------------------------------------------------------------------------------
-
 /// Algorithms name for identification. @see Algorithm::name
 const std::string CheckMantidVersion::name() const {
   return "CheckMantidVersion";
@@ -43,7 +42,6 @@ const std::string CheckMantidVersion::summary() const {
          "the Github API";
 }
 
-//----------------------------------------------------------------------------------------------
 /** Initialize the algorithm's properties.
  */
 void CheckMantidVersion::init() {
@@ -54,7 +52,6 @@ void CheckMantidVersion::init() {
                   Direction::Output);
 }
 
-//----------------------------------------------------------------------------------------------
 /** Execute the algorithm.
  */
 void CheckMantidVersion::exec() {
@@ -248,4 +245,4 @@ std::string CheckMantidVersion::getCurrentVersion() const {
 }
 
 } // namespace DataHandling
-} // namespace Mantid
\ No newline at end of file
+} // namespace Mantid
diff --git a/Framework/DataHandling/src/CompressEvents.cpp b/Framework/DataHandling/src/CompressEvents.cpp
index e656c82baebb59cc78502d57cfb35e4abacac4fb..0c3a8e14b7d5e8587894b7d0782d5e9d99a91e7b 100644
--- a/Framework/DataHandling/src/CompressEvents.cpp
+++ b/Framework/DataHandling/src/CompressEvents.cpp
@@ -58,7 +58,7 @@ void CompressEvents::exec() {
         API::WorkspaceFactory::Instance().create(
             "EventWorkspace", inputWS->getNumberHistograms(), 2, 1));
     // Copy geometry over.
-    API::WorkspaceFactory::Instance().initializeFromParent(inputWS, outputWS,
+    API::WorkspaceFactory::Instance().initializeFromParent(*inputWS, *outputWS,
                                                            false);
     // We DONT copy the data though
 
diff --git a/Framework/DataHandling/src/CreateSimulationWorkspace.cpp b/Framework/DataHandling/src/CreateSimulationWorkspace.cpp
index 909b236e5004127f1a37ff8aef8ce2f52609ed12..fd3f4a929521219bcce38a07e143844eccda3a1a 100644
--- a/Framework/DataHandling/src/CreateSimulationWorkspace.cpp
+++ b/Framework/DataHandling/src/CreateSimulationWorkspace.cpp
@@ -21,6 +21,8 @@
 
 #include <Poco/File.h>
 
+#include <boost/algorithm/string/predicate.hpp>
+
 namespace {
 
 struct StartAndEndTime {
diff --git a/Framework/DataHandling/src/DefineGaugeVolume.cpp b/Framework/DataHandling/src/DefineGaugeVolume.cpp
index da5db7396bd9c29d52e97e356cff9e2c350e7bcd..7c08358fa9d0858850eb3cb2156b59ca1557fb58 100644
--- a/Framework/DataHandling/src/DefineGaugeVolume.cpp
+++ b/Framework/DataHandling/src/DefineGaugeVolume.cpp
@@ -1,4 +1,5 @@
 #include "MantidDataHandling/DefineGaugeVolume.h"
+#include "MantidGeometry/Objects/Object.h"
 #include "MantidGeometry/Objects/ShapeFactory.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/Run.h"
diff --git a/Framework/DataHandling/src/DownloadInstrument.cpp b/Framework/DataHandling/src/DownloadInstrument.cpp
index 23b7aeb1a17a2a29c6e9b73d6b6c5bc705f60096..5bd0af84487f294cd50e03b5147aa47a95407ef7 100644
--- a/Framework/DataHandling/src/DownloadInstrument.cpp
+++ b/Framework/DataHandling/src/DownloadInstrument.cpp
@@ -3,6 +3,9 @@
 #include "MantidKernel/ConfigService.h"
 #include "MantidKernel/GitHubApiHelper.h"
 
+// boost
+#include <boost/algorithm/string/predicate.hpp>
+
 // Poco
 #include <Poco/DateTimeFormat.h>
 #include <Poco/DateTimeFormatter.h>
@@ -109,6 +112,10 @@ void DownloadInstrument::exec() {
   for (auto &itMap : fileMap) {
     // download a file
     doDownloadFile(itMap.first, itMap.second);
+    if (boost::algorithm::ends_with(itMap.second, "Facilities.xml")) {
+      g_log.notice("A new Facilities.xml file has been downloaded, this will "
+                   "take effect next time Mantid is started.");
+    }
   }
 
   setProperty("FileDownloadCount", static_cast<int>(fileMap.size()));
diff --git a/Framework/DataHandling/src/EventWorkspaceCollection.cpp b/Framework/DataHandling/src/EventWorkspaceCollection.cpp
index cea0c44416d6ddeb08099486aa7a63cf0bafc635..1105d777d43129ac157fb38323f93063bd92374d 100644
--- a/Framework/DataHandling/src/EventWorkspaceCollection.cpp
+++ b/Framework/DataHandling/src/EventWorkspaceCollection.cpp
@@ -226,7 +226,7 @@ size_t EventWorkspaceCollection::getNumberEvents() const {
 void EventWorkspaceCollection::resizeTo(const size_t size) {
   for (auto &ws : m_WsVec) {
     auto tmp = createWorkspace<DataObjects::EventWorkspace>(size, 2, 1);
-    WorkspaceFactory::Instance().initializeFromParent(ws, tmp, true);
+    WorkspaceFactory::Instance().initializeFromParent(*ws, *tmp, true);
     ws = std::move(tmp);
     for (size_t i = 0; i < ws->getNumberHistograms(); ++i)
       ws->getSpectrum(i).setSpectrumNo(static_cast<specnum_t>(i + 1));
diff --git a/Framework/DataHandling/src/FilterEventsByLogValuePreNexus.cpp b/Framework/DataHandling/src/FilterEventsByLogValuePreNexus.cpp
index f7838b15a0bf108cf869b5e68d621994c70847dc..e829bc94401b3ef6dc7c87866d93df3704592af4 100644
--- a/Framework/DataHandling/src/FilterEventsByLogValuePreNexus.cpp
+++ b/Framework/DataHandling/src/FilterEventsByLogValuePreNexus.cpp
@@ -1,5 +1,6 @@
 #include "MantidDataHandling/FilterEventsByLogValuePreNexus.h"
 #include "MantidAPI/Axis.h"
+#include "MantidAPI/DetectorInfo.h"
 #include "MantidAPI/FileFinder.h"
 #include "MantidAPI/FileProperty.h"
 #include "MantidAPI/RegisterFileLoader.h"
@@ -590,7 +591,7 @@ FilterEventsByLogValuePreNexus::setupOutputEventWorkspace() {
   if (!this->m_spectraList.empty())
     nSpec = this->m_spectraList.size();
   auto ws = createWorkspace<EventWorkspace>(nSpec, 2, 1);
-  WorkspaceFactory::Instance().initializeFromParent(tempworkspace, ws, true);
+  WorkspaceFactory::Instance().initializeFromParent(*tempworkspace, *ws, true);
 
   return ws;
 }
@@ -817,15 +818,14 @@ void FilterEventsByLogValuePreNexus::procEvents(
   // Set up instrument related parameters such as detector map and etc.
   // We want to pad out empty pixels.
   //--------------------------------------------------------------------
-  detid2det_map detector_map;
-  workspace->getInstrument()->getDetectors(detector_map);
+  const auto &detectorInfo = workspace->detectorInfo();
+  const auto &detIDs = detectorInfo.detectorIDs();
 
   // Determine maximum pixel id
-  detid2det_map::iterator it;
   m_detid_max = 0; // seems like a safe lower bound
-  for (it = detector_map.begin(); it != detector_map.end(); it++)
-    if (it->first > m_detid_max)
-      m_detid_max = it->first;
+  for (const auto detID : detIDs)
+    if (detID > m_detid_max)
+      m_detid_max = detID;
 
   // Pad all the pixels
   m_prog->report("Padding Pixels");
@@ -835,20 +835,20 @@ void FilterEventsByLogValuePreNexus::procEvents(
   this->m_pixelToWkspindex.assign(m_detid_max + 1, 0);
   size_t workspaceIndex = 0;
   specnum_t spectrumNumber = 1;
-  for (it = detector_map.begin(); it != detector_map.end(); it++) {
-    if (!it->second->isMonitor()) {
+  for (size_t i = 0; i < detectorInfo.size(); ++i) {
+    if (!detectorInfo.isMonitor(i)) {
       if (!m_loadOnlySomeSpectra ||
-          (spectraLoadMap.find(it->first) != spectraLoadMap.end())) {
+          (spectraLoadMap.find(detIDs[i]) != spectraLoadMap.end())) {
         // Add non-monitor detector ID
-        this->m_pixelToWkspindex[it->first] = workspaceIndex;
+        this->m_pixelToWkspindex[detIDs[i]] = workspaceIndex;
         EventList &spec = workspace->getSpectrum(workspaceIndex);
-        spec.addDetectorID(it->first);
+        spec.addDetectorID(detIDs[i]);
         // Start the spectrum number at 1
         spec.setSpectrumNo(spectrumNumber);
         workspaceIndex += 1;
         ++workspaceIndex;
       } else {
-        this->m_pixelToWkspindex[it->first] = -1;
+        this->m_pixelToWkspindex[detIDs[i]] = -1;
       }
       ++spectrumNumber;
     }
@@ -873,7 +873,7 @@ void FilterEventsByLogValuePreNexus::procEvents(
     // second, e.g. 7 million events more per seconds).
     // compared to a setup time/merging time of about 10 seconds per million
     // detectors.
-    double setUpTime = double(detector_map.size()) * 10e-6;
+    double setUpTime = double(detectorInfo.size()) * 10e-6;
     m_parallelProcessing = ((double(m_maxNumEvents) / 7e6) > setUpTime);
     g_log.information() << (m_parallelProcessing ? "Using" : "Not using")
                         << " parallel processing."
@@ -2109,16 +2109,14 @@ void FilterEventsByLogValuePreNexus::filterEventsLinear(
   */
 size_t FilterEventsByLogValuePreNexus::padOutEmptyPixels(
     DataObjects::EventWorkspace_sptr eventws) {
-  // Obtain detector map
-  detid2det_map detector_map;
-  eventws->getInstrument()->getDetectors(detector_map);
+  const auto &detectorInfo = eventws->detectorInfo();
+  const auto &detIDs = detectorInfo.detectorIDs();
 
   // Determine maximum pixel id
-  detid2det_map::iterator it;
   m_detid_max = 0; // seems like a safe lower bound
-  for (it = detector_map.begin(); it != detector_map.end(); it++)
-    if (it->first > m_detid_max)
-      m_detid_max = it->first;
+  for (const auto detID : detIDs)
+    if (detID > m_detid_max)
+      m_detid_max = detID;
 
   // Pad all the pixels
   m_prog->report("Padding Pixels of workspace");
@@ -2129,19 +2127,19 @@ size_t FilterEventsByLogValuePreNexus::padOutEmptyPixels(
 
   // Set up the map between workspace index and pixel ID
   size_t workspaceIndex = 0;
-  for (it = detector_map.begin(); it != detector_map.end(); it++) {
-    if (!it->second->isMonitor()) {
+  for (size_t i = 0; i < detectorInfo.size(); ++i) {
+    if (!detectorInfo.isMonitor(i)) {
       if (!m_loadOnlySomeSpectra ||
-          (spectraLoadMap.find(it->first) != spectraLoadMap.end())) {
-        this->m_pixelToWkspindex[it->first] = workspaceIndex;
+          (spectraLoadMap.find(detIDs[i]) != spectraLoadMap.end())) {
+        this->m_pixelToWkspindex[detIDs[i]] = workspaceIndex;
         ++workspaceIndex;
       } else {
-        this->m_pixelToWkspindex[it->first] = -1;
+        this->m_pixelToWkspindex[detIDs[i]] = -1;
       }
     }
   }
 
-  return detector_map.size();
+  return detectorInfo.size();
 }
 
 //----------------------------------------------------------------------------------------------
@@ -2151,20 +2149,19 @@ size_t FilterEventsByLogValuePreNexus::padOutEmptyPixels(
   */
 void FilterEventsByLogValuePreNexus::setupPixelSpectrumMap(
     DataObjects::EventWorkspace_sptr eventws) {
-  // Obtain detector map
-  detid2det_map detector_map;
-  eventws->getInstrument()->getDetectors(detector_map);
+  const auto &detectorInfo = eventws->detectorInfo();
+  const auto &detIDs = detectorInfo.detectorIDs();
 
   // Set up
   specnum_t spectrumNumber = 1;
-  for (auto &det : detector_map) {
-    if (!det.second->isMonitor()) {
+  for (size_t i = 0; i < detectorInfo.size(); ++i) {
+    if (!detectorInfo.isMonitor(i)) {
       if (!m_loadOnlySomeSpectra ||
-          (spectraLoadMap.find(det.first) != spectraLoadMap.end())) {
+          (spectraLoadMap.find(detIDs[i]) != spectraLoadMap.end())) {
         // Add non-monitor detector ID
-        size_t workspaceIndex = m_pixelToWkspindex[det.first];
+        size_t workspaceIndex = m_pixelToWkspindex[detIDs[i]];
         EventList &spec = eventws->getSpectrum(workspaceIndex);
-        spec.addDetectorID(det.first);
+        spec.addDetectorID(detIDs[i]);
         // Start the spectrum number at 1
         spec.setSpectrumNo(spectrumNumber);
       }
diff --git a/Framework/DataHandling/src/FindDetectorsInShape.cpp b/Framework/DataHandling/src/FindDetectorsInShape.cpp
index d22b07a6ac0a44b8c7d7c65d4752533b10e0428e..81f3aa7d644a457d1e5279dcb924ffe0787f5ca2 100644
--- a/Framework/DataHandling/src/FindDetectorsInShape.cpp
+++ b/Framework/DataHandling/src/FindDetectorsInShape.cpp
@@ -1,9 +1,8 @@
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidDataHandling/FindDetectorsInShape.h"
+#include "MantidGeometry/Objects/Object.h"
 #include "MantidGeometry/Objects/ShapeFactory.h"
 #include "MantidKernel/ArrayProperty.h"
+#include "MantidAPI/DetectorInfo.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidGeometry/Instrument.h"
 #include "MantidKernel/MandatoryValidator.h"
@@ -41,56 +40,35 @@ void FindDetectorsInShape::init() {
 }
 
 void FindDetectorsInShape::exec() {
-  // Get the input workspace
   const MatrixWorkspace_const_sptr WS = getProperty("Workspace");
-
   bool includeMonitors = getProperty("IncludeMonitors");
-
   std::string shapeXML = getProperty("ShapeXML");
 
   // convert into a Geometry object
   Geometry::ShapeFactory sFactory;
-  boost::shared_ptr<Geometry::Object> shape_sptr =
-      sFactory.createShape(shapeXML);
-
-  // get the instrument out of the workspace
-  Instrument_const_sptr instrument_sptr = WS->getInstrument();
+  auto shape_sptr = sFactory.createShape(shapeXML);
 
-  // To get all the detector ID's
-  detid2det_map allDetectors;
-  instrument_sptr->getDetectors(allDetectors);
+  const auto &detectorInfo = WS->detectorInfo();
+  const auto &detIDs = detectorInfo.detectorIDs();
 
   std::vector<int> foundDets;
 
   // progress
-  detid2det_map::size_type objCmptCount = allDetectors.size();
+  detid2det_map::size_type objCmptCount = detectorInfo.size();
   int iprogress_step = static_cast<int>(objCmptCount / 100);
   if (iprogress_step == 0)
     iprogress_step = 1;
   int iprogress = 0;
 
-  // Now go through all
-  detid2det_map::iterator it;
-  detid2det_map::const_iterator it_end = allDetectors.end();
-  for (it = allDetectors.begin(); it != it_end; ++it) {
-    Geometry::IDetector_const_sptr det = it->second;
-
-    // attempt to dynamic cast up to an IDetector
-    boost::shared_ptr<const Geometry::IDetector> detector_sptr =
-        boost::dynamic_pointer_cast<const Geometry::IDetector>(it->second);
-
-    if (detector_sptr) {
-      if ((includeMonitors) || (!detector_sptr->isMonitor())) {
-        // check if the centre of this item is within the user defined shape
-        if (shape_sptr->isValid(detector_sptr->getPos())) {
-          // shape encloses this objectComponent
-          g_log.debug() << "Detector contained in shape "
-                        << detector_sptr->getID() << '\n';
-          foundDets.push_back(detector_sptr->getID());
-        }
+  for (size_t i = 0; i < detectorInfo.size(); ++i) {
+    if ((includeMonitors) || (!detectorInfo.isMonitor(i))) {
+      // check if the centre of this item is within the user defined shape
+      if (shape_sptr->isValid(detectorInfo.position(i))) {
+        // shape encloses this objectComponent
+        g_log.debug() << "Detector contained in shape " << detIDs[i] << '\n';
+        foundDets.push_back(detIDs[i]);
       }
     }
-
     iprogress++;
     if (iprogress % iprogress_step == 0) {
       progress(static_cast<double>(iprogress) /
diff --git a/Framework/DataHandling/src/FindDetectorsPar.cpp b/Framework/DataHandling/src/FindDetectorsPar.cpp
index 523f03dceadbd8a51a50ed6ea0fa6e825d28cc15..e9381cbdcda6a47790445ae700edf21d77a5e9d7 100644
--- a/Framework/DataHandling/src/FindDetectorsPar.cpp
+++ b/Framework/DataHandling/src/FindDetectorsPar.cpp
@@ -5,6 +5,7 @@
 #include "MantidAPI/FileProperty.h"
 #include "MantidAPI/InstrumentValidator.h"
 #include "MantidAPI/ITableWorkspace.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidAPI/TableRow.h"
 #include "MantidAPI/WorkspaceFactory.h"
 
@@ -100,35 +101,24 @@ void FindDetectorsPar::exec() {
   Progress progress(this, 0, 1, 100);
   const int progStep = static_cast<int>(ceil(double(nHist) / 100.0));
 
+  const auto &spectrumInfo = inputWS->spectrumInfo();
+
   // define the centre of coordinates:
-  Kernel::V3D Observer = inputWS->getInstrument()->getSample()->getPos();
+  Kernel::V3D Observer = spectrumInfo.samplePosition();
 
   // Loop over the spectra
   PARALLEL_FOR_NO_WSP_CHECK()
   for (int64_t i = 0; i < nHist; i++) {
     PARALLEL_START_INTERUPT_REGION
-    Geometry::IDetector_const_sptr spDet;
-    try {
-      spDet = inputWS->getDetector(i);
-    } catch (Kernel::Exception::NotFoundError &) { // Intel compilers on MAC
-                                                   // hungs on continue here
-      // should be no problem with this if get detector implemented properly and
-      // workspace keeps ownership for the detector (I expet so)
-      spDet.reset();
-    }
-    // separate check as some compilers do not obey the standard evaluation
-    // order
-    if (!spDet)
-      continue;
     // Check that we aren't writing a monitor...
-    if (spDet->isMonitor())
+    if (!spectrumInfo.hasDetectors(i) || spectrumInfo.isMonitor(i))
       continue;
 
     // valid detector has valid detID
-    Detectors[i].detID = spDet->getID();
+    Detectors[i].detID = spectrumInfo.detector(i).getID();
 
     // calculate all parameters for current composite detector
-    calcDetPar(spDet, Observer, Detectors[i]);
+    calcDetPar(spectrumInfo.detector(i), Observer, Detectors[i]);
 
     // make regular progress reports and check for canceling the algorithm
 
@@ -209,14 +199,14 @@ double AvrgDetector::nearAngle(const double &baseAngle, const double &anAngle) {
 
 /** method to cacluate the detectors parameters and add them to the detectors
 *averages
-*@param spDet    -- shared pointer to the Mantid Detector
+*@param det      -- reference to the Mantid Detector
 *@param Observer -- sample position or the centre of the polar system of
 *coordinates to calculate detector's parameters.
 */
-void AvrgDetector::addDetInfo(const Geometry::IDetector_const_sptr &spDet,
+void AvrgDetector::addDetInfo(const Geometry::IDetector &det,
                               const Kernel::V3D &Observer) {
   m_nComponents++;
-  Kernel::V3D detPos = spDet->getPos();
+  Kernel::V3D detPos = det.getPos();
   Kernel::V3D toDet = (detPos - Observer);
 
   double dist2Det, Polar, Azimut, ringPolar, ringAzim;
@@ -261,7 +251,7 @@ void AvrgDetector::addDetInfo(const Geometry::IDetector_const_sptr &spDet,
   coord[2] = e_tg; // new z
   bbox.setBoxAlignment(ringCentre, coord);
 
-  spDet->getBoundingBox(bbox);
+  det.getBoundingBox(bbox);
 
   // linear extensions of the bounding box orientied tangentially to the equal
   // scattering angle circle
@@ -315,7 +305,7 @@ void AvrgDetector::returnAvrgDetPar(DetParameters &avrgDet) {
 }
 /** Method calculates averaged polar coordinates of the detector's group
 (which may consist of one detector)
-*@param spDet    -- shared pointer to the Mantid Detector
+*@param det    -- reference to the Mantid Detector
 *@param Observer -- sample position or the centre of the polar system of
 coordinates to calculate detector's parameters.
 
@@ -323,33 +313,29 @@ coordinates to calculate detector's parameters.
 of the detector or detector's group in
                      spherical coordinate system with centre at Observer
 */
-void FindDetectorsPar::calcDetPar(const Geometry::IDetector_const_sptr &spDet,
+void FindDetectorsPar::calcDetPar(const Geometry::IDetector &det,
                                   const Kernel::V3D &Observer,
                                   DetParameters &Detector) {
 
   // get number of basic detectors within the composit detector
-  size_t nDetectors = spDet->nDets();
+  size_t nDetectors = det.nDets();
   // define summator
   AvrgDetector detSum;
   // do we want spherical or linear box sizes?
   detSum.setUseSpherical(!m_SizesAreLinear);
 
   if (nDetectors == 1) {
-    detSum.addDetInfo(spDet, Observer);
+    detSum.addDetInfo(det, Observer);
   } else {
     // access contributing detectors;
-    Geometry::DetectorGroup_const_sptr spDetGroup =
-        boost::dynamic_pointer_cast<const Geometry::DetectorGroup>(spDet);
-    if (!spDetGroup) {
+    auto detGroup = dynamic_cast<const Geometry::DetectorGroup *>(&det);
+    if (!detGroup) {
       g_log.error() << "calc_cylDetPar: can not downcast IDetector_sptr to "
-                       "detector group for det->ID: " << spDet->getID() << '\n';
+                       "detector group for det->ID: " << det.getID() << '\n';
       throw(std::bad_cast());
     }
-    auto detectors = spDetGroup->getDetectors();
-    auto it = detectors.begin();
-    auto it_end = detectors.end();
-    for (; it != it_end; it++) {
-      detSum.addDetInfo(*it, Observer);
+    for (const auto &det : detGroup->getDetectors()) {
+      detSum.addDetInfo(*det, Observer);
     }
   }
   // calculate averages and return the detector parameters
@@ -469,24 +455,14 @@ void FindDetectorsPar::populate_values_from_file(
     }
     m_SizesAreLinear = false;
   } else {
-
-    Geometry::IComponent_const_sptr sample =
-        inputWS->getInstrument()->getSample();
+    const auto &spectrumInfo = inputWS->spectrumInfo();
     secondaryFlightpath.resize(nHist);
-    // Loop over the spectra
     for (size_t i = 0; i < nHist; i++) {
-      Geometry::IDetector_const_sptr spDet;
-      try {
-        spDet = inputWS->getDetector(i);
-      } catch (Kernel::Exception::NotFoundError &) {
-        continue;
-      }
-      // Check that we aren't writing a monitor...
-      if (spDet->isMonitor())
+      if (!spectrumInfo.hasDetectors(i) || spectrumInfo.isMonitor(i))
         continue;
       /// this is the only value, which is not defined in phx file, so we
       /// calculate it
-      secondaryFlightpath[i] = spDet->getDistance(*sample);
+      secondaryFlightpath[i] = spectrumInfo.l2(i);
     }
   }
 }
diff --git a/Framework/DataHandling/src/GroupDetectors.cpp b/Framework/DataHandling/src/GroupDetectors.cpp
index 53cb496725bea49ae8931ed0ab79277190730134..a3b22113068901de52fc3a5e4f9299570cd02ab9 100644
--- a/Framework/DataHandling/src/GroupDetectors.cpp
+++ b/Framework/DataHandling/src/GroupDetectors.cpp
@@ -59,7 +59,7 @@ void GroupDetectors::exec() {
   }
 
   // Bin boundaries need to be the same, so check if they actually are
-  if (!API::WorkspaceHelpers::commonBoundaries(WS)) {
+  if (!API::WorkspaceHelpers::commonBoundaries(*WS)) {
     g_log.error("Can only group if the histograms have common bin boundaries");
     throw std::runtime_error(
         "Can only group if the histograms have common bin boundaries");
diff --git a/Framework/DataHandling/src/GroupDetectors2.cpp b/Framework/DataHandling/src/GroupDetectors2.cpp
index a852814297b2073909fca87069fe50ceda2365c7..a69e01b834b894cef35a6829fdb5f4b31054c8e4 100644
--- a/Framework/DataHandling/src/GroupDetectors2.cpp
+++ b/Framework/DataHandling/src/GroupDetectors2.cpp
@@ -1,6 +1,3 @@
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidDataHandling/GroupDetectors2.h"
 
 #include "MantidAPI/CommonBinsValidator.h"
@@ -15,7 +12,10 @@
 #include "MantidKernel/Exception.h"
 #include "MantidKernel/ListValidator.h"
 
+#include <boost/algorithm/string/classification.hpp>
 #include <boost/regex.hpp>
+#include <boost/algorithm/string/split.hpp>
+#include <boost/algorithm/string/trim.hpp>
 
 namespace Mantid {
 namespace DataHandling {
@@ -112,7 +112,7 @@ void GroupDetectors2::exec() {
   const size_t numInHists = inputWS->getNumberHistograms();
   // Bin boundaries need to be the same, so do the full check on whether they
   // actually are
-  if (!API::WorkspaceHelpers::commonBoundaries(inputWS)) {
+  if (!API::WorkspaceHelpers::commonBoundaries(*inputWS)) {
     g_log.error()
         << "Can only group if the histograms have common bin boundaries\n";
     throw std::invalid_argument(
@@ -219,7 +219,7 @@ void GroupDetectors2::execEvent() {
           "EventWorkspace", m_GroupWsInds.size() + numUnGrouped,
           inputWS->x(0).size(), inputWS->blocksize()));
   // Copy geometry over.
-  WorkspaceFactory::Instance().initializeFromParent(inputWS, outputWS, true);
+  WorkspaceFactory::Instance().initializeFromParent(*inputWS, *outputWS, true);
 
   // prepare to move the requested histograms into groups, first estimate how
   // long for progress reporting. +1 in the demonator gets rid of any divide by
@@ -271,11 +271,11 @@ void GroupDetectors2::getGroups(API::MatrixWorkspace_const_sptr workspace,
             groupingWS_sptr);
     if (groupWS) {
       g_log.debug() << "Extracting grouping from GroupingWorkspace ("
-                    << groupWS->name() << ")\n";
+                    << groupWS->getName() << ")\n";
       processGroupingWorkspace(groupWS, workspace, unUsedSpec);
     } else {
       g_log.debug() << "Extracting grouping from MatrixWorkspace ("
-                    << groupingWS_sptr->name() << ")\n";
+                    << groupingWS_sptr->getName() << ")\n";
       processMatrixWorkspace(groupingWS_sptr, workspace, unUsedSpec);
     }
     return;
@@ -925,6 +925,7 @@ size_t GroupDetectors2::formGroups(API::MatrixWorkspace_const_sptr inputWS,
   // Only used for averaging behaviour. We may have a 1:1 map where a Divide
   // would be waste as it would be just dividing by 1
   bool requireDivide(false);
+  const auto &spectrumInfo = inputWS->spectrumInfo();
   for (storage_map::const_iterator it = m_GroupWsInds.begin();
        it != m_GroupWsInds.end(); ++it) {
     // This is the grouped spectrum
@@ -942,7 +943,6 @@ size_t GroupDetectors2::formGroups(API::MatrixWorkspace_const_sptr inputWS,
 
     // Keep track of number of detectors required for masking
     size_t nonMaskedSpectra(0);
-    const auto &spectrumInfo = inputWS->spectrumInfo();
 
     for (auto originalWI : it->second) {
       // detectors to add to firstSpecNum
@@ -1021,6 +1021,7 @@ GroupDetectors2::formGroupsEvent(DataObjects::EventWorkspace_const_sptr inputWS,
   // Only used for averaging behaviour. We may have a 1:1 map where a Divide
   // would be waste as it would be just dividing by 1
   bool requireDivide(false);
+  const auto &spectrumInfo = inputWS->spectrumInfo();
   for (storage_map::const_iterator it = m_GroupWsInds.begin();
        it != m_GroupWsInds.end(); ++it) {
     // This is the grouped spectrum
@@ -1044,12 +1045,7 @@ GroupDetectors2::formGroupsEvent(DataObjects::EventWorkspace_const_sptr inputWS,
 
       // detectors to add to the output spectrum
       outEL.addDetectorIDs(fromEL.getDetectorIDs());
-      try {
-        Geometry::IDetector_const_sptr det = inputWS->getDetector(originalWI);
-        if (!det->isMasked())
-          ++nonMaskedSpectra;
-      } catch (Exception::NotFoundError &) {
-        // If a detector cannot be found, it cannot be masked
+      if (!isMaskedDetector(spectrumInfo, originalWI)) {
         ++nonMaskedSpectra;
       }
     }
diff --git a/Framework/DataHandling/src/ImggAggregateWavelengths.cpp b/Framework/DataHandling/src/ImggAggregateWavelengths.cpp
index 3b8d5948b6ab3a4abed85ba54449baa7b25199ec..3b1bd81eb312ade75ddcdd47d3bf4540548fbe4f 100644
--- a/Framework/DataHandling/src/ImggAggregateWavelengths.cpp
+++ b/Framework/DataHandling/src/ImggAggregateWavelengths.cpp
@@ -2,6 +2,7 @@
 #include "MantidAPI/AlgorithmManager.h"
 #include "MantidAPI/FileProperty.h"
 #include "MantidAPI/MatrixWorkspace.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidKernel/BoundedValidator.h"
 #include "MantidKernel/ListValidator.h"
 #include "MantidKernel/make_unique.h"
@@ -9,6 +10,7 @@
 #include "MantidKernel/StringTokenizer.h"
 
 #include <fstream>
+#include <iomanip>
 
 #include <Poco/File.h>
 #include <Poco/DirectoryIterator.h>
@@ -558,7 +560,7 @@ ImggAggregateWavelengths::findInputSubdirs(const Poco::Path &path) {
 
     // there is at least one image file: take just the first level directory
     if (it->isFile()) {
-      const std::string name = it.name();
+      const std::string &name = it.name();
       const std::string extShort = name.substr(name.size() - 3);
       const std::string extLong = name.substr(name.size() - 4);
 
@@ -690,7 +692,7 @@ ImggAggregateWavelengths::buildOutputSubdirNamesFromUniformBands(
   std::vector<std::string> outputSubdirs;
   // get number of available images from first effective subdirectory
   std::vector<Poco::Path> images;
-  for (size_t idx = 0; idx < inputSubDirs.size() && 0 == images.size(); ++idx) {
+  for (size_t idx = 0; idx < inputSubDirs.size() && images.empty(); ++idx) {
     images = findInputImages(inputSubDirs[idx]);
   }
   auto outRanges = splitSizeIntoRanges(images.size(), bands);
@@ -741,10 +743,10 @@ bool ImggAggregateWavelengths::isSupportedExtension(
   const std::vector<std::string> formatExtensionsShort{"fit"};
   const std::vector<std::string> formatExtensionsLong{"fits"};
 
-  bool found = (formatExtensionsShort.end() !=
+  bool found = (formatExtensionsShort.cend() !=
                 std::find(formatExtensionsShort.cbegin(),
                           formatExtensionsShort.cend(), extShort)) ||
-               (formatExtensionsLong.end() !=
+               (formatExtensionsLong.cend() !=
                 std::find(formatExtensionsLong.cbegin(),
                           formatExtensionsLong.cend(), extLong));
   return found;
diff --git a/Framework/DataHandling/src/Load.cpp b/Framework/DataHandling/src/Load.cpp
index aca068f9239cdd630ec367dcc7ebc106a6f4f066..67a48fdfd187c47c0fc89b2153238408a6693553 100644
--- a/Framework/DataHandling/src/Load.cpp
+++ b/Framework/DataHandling/src/Load.cpp
@@ -1,6 +1,3 @@
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidDataHandling/Load.h"
 #include "MantidAPI/AlgorithmManager.h"
 #include "MantidAPI/FileProperty.h"
@@ -10,6 +7,7 @@
 #include "MantidAPI/ITableWorkspace.h"
 #include "MantidAPI/IWorkspaceProperty.h"
 #include "MantidAPI/MultipleFileProperty.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidKernel/ArrayProperty.h"
 #include "MantidKernel/FacilityInfo.h"
 
@@ -245,7 +243,7 @@ void Load::declareLoaderProperties(const API::IAlgorithm_sptr &loader) {
   // THIS IS A COPY as the properties are mutated as we move through them
   const std::vector<Property *> existingProps = this->getProperties();
   for (auto existingProp : existingProps) {
-    const std::string name = existingProp->name();
+    const std::string &name = existingProp->name();
     // Wipe all properties except the Load native ones
     if (m_baseProps.find(name) == m_baseProps.end()) {
       this->removeProperty(name);
diff --git a/Framework/DataHandling/src/LoadAscii.cpp b/Framework/DataHandling/src/LoadAscii.cpp
index 24e0a47913934a66585e433c9cbe5ab8329cc368..c34c5fcf89c04babfc86ea465b58f2b9d9eb3d1a 100644
--- a/Framework/DataHandling/src/LoadAscii.cpp
+++ b/Framework/DataHandling/src/LoadAscii.cpp
@@ -370,4 +370,4 @@ void LoadAscii::exec() {
 }
 
 } // namespace DataHandling
-} // namespace Mantid
+} // namespace Mantid
\ No newline at end of file
diff --git a/Framework/DataHandling/src/LoadBBY.cpp b/Framework/DataHandling/src/LoadBBY.cpp
index b109d4d6ba4a8a61ff3d597a7462df6c6a61c352..0bbe0669658b8aa6cf1640048eb1343c99d324a7 100644
--- a/Framework/DataHandling/src/LoadBBY.cpp
+++ b/Framework/DataHandling/src/LoadBBY.cpp
@@ -2,6 +2,7 @@
 #include <cstdio>
 
 #include "MantidDataHandling/LoadBBY.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Axis.h"
 #include "MantidAPI/FileProperty.h"
 #include "MantidAPI/LogManager.h"
diff --git a/Framework/DataHandling/src/LoadCalFile.cpp b/Framework/DataHandling/src/LoadCalFile.cpp
index d41a66d19ec8f33529041582b59cb2345856cb97..804decf8b19cb974817c2fc411fe8c18d215bc08 100644
--- a/Framework/DataHandling/src/LoadCalFile.cpp
+++ b/Framework/DataHandling/src/LoadCalFile.cpp
@@ -2,6 +2,7 @@
 #include "MantidAPI/FileProperty.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/ITableWorkspace.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidAPI/Run.h"
 #include "MantidDataHandling/LoadCalFile.h"
 #include "MantidDataObjects/GroupingWorkspace.h"
@@ -259,6 +260,9 @@ void LoadCalFile::readCalFile(const std::string &calFileName,
   int n, udet, select, group;
   double n_d, udet_d, offset, select_d, group_d;
 
+  SpectrumInfo *maskSpectrumInfo{nullptr};
+  if (maskWS)
+    maskSpectrumInfo = &maskWS->mutableSpectrumInfo();
   std::string str;
   while (getline(grFile, str)) {
     if (str.empty() || str[0] == '#')
@@ -309,7 +313,8 @@ void LoadCalFile::readCalFile(const std::string &calFileName,
 
         if (select <= 0) {
           // Not selected, then mask this detector
-          maskWS->maskWorkspaceIndex(wi);
+          maskWS->getSpectrum(wi).clearData();
+          maskSpectrumInfo->setMasked(wi, true);
           maskWS->mutableY(wi)[0] = 1.0;
         } else {
           // Selected, set the value to be 0
diff --git a/Framework/DataHandling/src/LoadCanSAS1D.cpp b/Framework/DataHandling/src/LoadCanSAS1D.cpp
index c38e1b5b319f6682f89cfb904f159df0e563d684..42d1a649e34b59cd4eecc9cd95441069fda42f05 100644
--- a/Framework/DataHandling/src/LoadCanSAS1D.cpp
+++ b/Framework/DataHandling/src/LoadCanSAS1D.cpp
@@ -381,26 +381,67 @@ void LoadCanSAS1D::createSampleInformation(
       sasInstrumentElement->getChildElement("SAScollimation");
   check(sasCollimationElement, "<SAScollimation>");
 
-  // Get the geometry information
-  auto geometryElement = sasCollimationElement->getChildElement("name");
-  if (geometryElement) {
-    auto geometry = geometryElement->innerText();
-    auto geometryID = getGeometryID(geometry);
-    sample.setGeometryFlag(geometryID);
+  // Since we have shipped a sligthly invalid CanSAS1D format we need to
+  // make sure that we can read those files back in again
+  bool isInValidOldFormat = true;
+  try {
+    auto name = sasCollimationElement->getChildElement("name");
+    check(name, "name");
+  } catch (Kernel::Exception::NotFoundError &) {
+    isInValidOldFormat = false;
   }
 
-  // Get the thickness information
-  auto widthElement = sasCollimationElement->getChildElement("X");
-  if (widthElement) {
-    double width = std::stod(widthElement->innerText());
-    sample.setWidth(width);
-  }
+  if (isInValidOldFormat) {
+    // Get the geometry information
+    auto geometryElement = sasCollimationElement->getChildElement("name");
+    if (geometryElement) {
+      auto geometry = geometryElement->innerText();
+      auto geometryID = getGeometryID(geometry);
+      sample.setGeometryFlag(geometryID);
+    }
 
-  // Get the thickness information
-  auto heightElement = sasCollimationElement->getChildElement("Y");
-  if (heightElement) {
-    double height = std::stod(heightElement->innerText());
-    sample.setHeight(height);
+    // Get the width information
+    auto widthElement = sasCollimationElement->getChildElement("X");
+    if (widthElement) {
+      double width = std::stod(widthElement->innerText());
+      sample.setWidth(width);
+    }
+
+    // Get the height information
+    auto heightElement = sasCollimationElement->getChildElement("Y");
+    if (heightElement) {
+      double height = std::stod(heightElement->innerText());
+      sample.setHeight(height);
+    }
+
+  } else {
+    // Get aperture
+    auto aperture = sasCollimationElement->getChildElement("aperture");
+    if (aperture) {
+      // Get geometry element
+      auto geometry = aperture->getAttribute("name");
+      if (!geometry.empty()) {
+        auto geometryID = getGeometryID(Poco::XML::fromXMLString(geometry));
+        sample.setGeometryFlag(geometryID);
+      }
+
+      // Get size
+      auto size = aperture->getChildElement("size");
+
+      // Get the width information
+      auto widthElement = size->getChildElement("x");
+      if (widthElement) {
+        double width = std::stod(widthElement->innerText());
+        sample.setWidth(width);
+      }
+
+      // Get the height information
+      auto heightElement = size->getChildElement("y");
+      if (heightElement) {
+        double height = std::stod(heightElement->innerText());
+        sample.setHeight(height);
+      }
+    }
   }
 }
 }
diff --git a/Framework/DataHandling/src/LoadDetectorInfo.cpp b/Framework/DataHandling/src/LoadDetectorInfo.cpp
index b337e626417afefdfe58308f2779c25f8c3c7164..bca700cda94e579e62d28d819bd6582807852198 100644
--- a/Framework/DataHandling/src/LoadDetectorInfo.cpp
+++ b/Framework/DataHandling/src/LoadDetectorInfo.cpp
@@ -1,4 +1,5 @@
 #include "MantidDataHandling/LoadDetectorInfo.h"
+#include "MantidAPI/DetectorInfo.h"
 #include "MantidAPI/FileProperty.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidKernel/Exception.h"
@@ -6,6 +7,7 @@
 #include "LoadRaw/isisraw2.h"
 
 #include <boost/algorithm/string/compare.hpp>
+#include <boost/algorithm/string/predicate.hpp>
 #include <nexus/NeXusFile.hpp>
 #include <Poco/Path.h>
 
@@ -122,6 +124,7 @@ void LoadDetectorInfo::loadFromDAT(const std::string &filename) {
 
   // start loop over file
   auto &pmap = m_workspace->instrumentParameters();
+  const auto &detectorInfo = m_workspace->detectorInfo();
   while (getline(datFile, line)) {
     if (line.empty() || line[0] == '#')
       continue;
@@ -135,24 +138,24 @@ void LoadDetectorInfo::loadFromDAT(const std::string &filename) {
     // offset value is be subtracted so store negative
     delta *= -1.0f;
 
-    IDetector_const_sptr det;
     try {
-      det = m_baseInstrument->getDetector(detID);
-    } catch (Exception::NotFoundError &) {
-      continue;
-    }
-    if (det->isMonitor() || code == 1)
-      continue;
+      size_t index = detectorInfo.indexOf(detID);
+      if (detectorInfo.isMonitor(index) || code == 1)
+        continue;
 
-    // drop 10 float columns
-    for (int i = 0; i < 10; ++i)
-      is >> droppedFloat;
+      // drop 10 float columns
+      for (int i = 0; i < 10; ++i)
+        is >> droppedFloat;
 
-    // pressure, wall thickness
-    float pressure(0.0), thickness(0.0);
-    is >> pressure >> thickness;
+      // pressure, wall thickness
+      float pressure(0.0), thickness(0.0);
+      is >> pressure >> thickness;
 
-    updateParameterMap(pmap, det, l2, theta, phi, delta, pressure, thickness);
+      updateParameterMap(pmap, detectorInfo.detector(index), l2, theta, phi,
+                         delta, pressure, thickness);
+    } catch (std::out_of_range &) {
+      continue;
+    }
   }
 }
 
@@ -186,32 +189,33 @@ void LoadDetectorInfo::loadFromRAW(const std::string &filename) {
 
   // Start loop over detectors
   auto &pmap = m_workspace->instrumentParameters();
+  const auto &detectorInfo = m_workspace->detectorInfo();
   for (int i = 0; i < numDets; ++i) {
     detid_t detID = static_cast<detid_t>(iraw.udet[i]);
     int code = iraw.code[i];
-    IDetector_const_sptr det;
     try {
-      det = m_baseInstrument->getDetector(detID);
-    } catch (Exception::NotFoundError &) {
+      size_t index = detectorInfo.indexOf(detID);
+      if (detectorInfo.isMonitor(index) || code == 1)
+        continue;
+
+      // Positions
+      float l2 = iraw.len2[i];
+      float theta = iraw.tthe[i];
+      float phi = (phiPresent ? iraw.ut[i] : 0.0f);
+
+      // Parameters
+      float delta = iraw.delt[i];
+      // offset value is be subtracted so store negative
+      delta *= -1.0f;
+      // pressure, wall thickness
+      float pressure = iraw.ut[i + pressureTabNum * numDets];
+      float thickness = iraw.ut[i + thicknessTabNum * numDets];
+
+      updateParameterMap(pmap, detectorInfo.detector(index), l2, theta, phi,
+                         delta, pressure, thickness);
+    } catch (std::out_of_range &) {
       continue;
     }
-    if (det->isMonitor() || code == 1)
-      continue;
-
-    // Positions
-    float l2 = iraw.len2[i];
-    float theta = iraw.tthe[i];
-    float phi = (phiPresent ? iraw.ut[i] : 0.0f);
-
-    // Parameters
-    float delta = iraw.delt[i];
-    // offset value is be subtracted so store negative
-    delta *= -1.0f;
-    // pressure, wall thickness
-    float pressure = iraw.ut[i + pressureTabNum * numDets];
-    float thickness = iraw.ut[i + thicknessTabNum * numDets];
-
-    updateParameterMap(pmap, det, l2, theta, phi, delta, pressure, thickness);
   }
 }
 
@@ -247,33 +251,34 @@ void LoadDetectorInfo::loadFromIsisNXS(const std::string &filename) {
 
   // Start loop over detectors
   auto &pmap = m_workspace->instrumentParameters();
+  const auto &detectorInfo = m_workspace->detectorInfo();
   int numDets = static_cast<int>(detInfo.ids.size());
   for (int i = 0; i < numDets; ++i) {
     detid_t detID = detInfo.ids[i];
     int code = detInfo.codes[i];
-    IDetector_const_sptr det;
     try {
-      det = m_baseInstrument->getDetector(detID);
-    } catch (Exception::NotFoundError &) {
+      size_t index = detectorInfo.indexOf(detID);
+      if (detectorInfo.isMonitor(index) || code == 1)
+        continue;
+
+      // Positions
+      double l2 = detInfo.l2[i];
+      double theta = detInfo.theta[i];
+      double phi = detInfo.phi[i];
+
+      // Parameters
+      double delta = detInfo.delays[i];
+      // offset value is be subtracted so store negative
+      delta *= -1.0;
+      // pressure, wall thickness
+      double pressure = detInfo.pressures[i];
+      double thickness = detInfo.thicknesses[i];
+
+      updateParameterMap(pmap, detectorInfo.detector(index), l2, theta, phi,
+                         delta, pressure, thickness);
+    } catch (std::out_of_range &) {
       continue;
     }
-    if (det->isMonitor() || code == 1)
-      continue;
-
-    // Positions
-    double l2 = detInfo.l2[i];
-    double theta = detInfo.theta[i];
-    double phi = detInfo.phi[i];
-
-    // Parameters
-    double delta = detInfo.delays[i];
-    // offset value is be subtracted so store negative
-    delta *= -1.0;
-    // pressure, wall thickness
-    double pressure = detInfo.pressures[i];
-    double thickness = detInfo.thicknesses[i];
-
-    updateParameterMap(pmap, det, l2, theta, phi, delta, pressure, thickness);
   }
 }
 
@@ -309,11 +314,13 @@ void LoadDetectorInfo::readLibisisNxs(::NeXus::File &nxsFile,
   nxsFile.readData<double>("gas_pressure", pressure);
   nxsFile.readData<double>("wall_thickness", thickness);
   nxsFile.closeGroup();
+  // cppcheck-suppress knownConditionTrueFalse
   if (pressure <= 0.0) {
     g_log.warning("The data file does not contain correct He3 pressure, "
                   "default value of 10 bar is used instead");
     pressure = 10.0;
   }
+  // cppcheck-suppress knownConditionTrueFalse
   if (thickness <= 0.0) {
     g_log.warning("The data file does not contain correct detector's wall "
                   "thickness, default value of 0.8mm is used instead");
@@ -385,7 +392,7 @@ void LoadDetectorInfo::readNXSDotDat(::NeXus::File &nxsFile,
 /**
  *
  * @param pmap A reference to the ParameterMap instance to update
- * @param det A pointer to the detector whose parameters should be updated
+ * @param det A reference to the detector whose parameters should be updated
  * @param l2 The new l2 value
  * @param theta The new theta value
  * @param phi The new phi value
@@ -393,17 +400,19 @@ void LoadDetectorInfo::readNXSDotDat(::NeXus::File &nxsFile,
  * @param pressure The new pressure value
  * @param thickness The new thickness value
  */
-void LoadDetectorInfo::updateParameterMap(
-    Geometry::ParameterMap &pmap, const Geometry::IDetector_const_sptr &det,
-    const double l2, const double theta, const double phi, const double delay,
-    const double pressure, const double thickness) const {
+void LoadDetectorInfo::updateParameterMap(Geometry::ParameterMap &pmap,
+                                          const Geometry::IDetector &det,
+                                          const double l2, const double theta,
+                                          const double phi, const double delay,
+                                          const double pressure,
+                                          const double thickness) const {
   // store detector params that are different to instrument level
   if (fabs(delay - m_instDelta) > 1e-06)
-    pmap.addDouble(det->getComponentID(), DELAY_PARAM, delay);
+    pmap.addDouble(det.getComponentID(), DELAY_PARAM, delay);
   if (fabs(pressure - m_instPressure) > 1e-06)
-    pmap.addDouble(det->getComponentID(), PRESSURE_PARAM, pressure);
+    pmap.addDouble(det.getComponentID(), PRESSURE_PARAM, pressure);
   if (fabs(thickness - m_instThickness) > 1e-06)
-    pmap.addDouble(det->getComponentID(), THICKNESS_PARAM, thickness);
+    pmap.addDouble(det.getComponentID(), THICKNESS_PARAM, thickness);
 
   // move
   if (m_moveDets) {
@@ -411,7 +420,7 @@ void LoadDetectorInfo::updateParameterMap(
     newPos.spherical(l2, theta, phi);
     // The sample position may not be at 0,0,0
     newPos += m_samplePos;
-    ComponentHelper::moveComponent(*det, pmap, newPos,
+    ComponentHelper::moveComponent(det, pmap, newPos,
                                    ComponentHelper::Absolute);
   }
 }
diff --git a/Framework/DataHandling/src/LoadDetectorsGroupingFile.cpp b/Framework/DataHandling/src/LoadDetectorsGroupingFile.cpp
index 7abb622b8349d2a4cdcdfcb64cded3bd28bd75c6..e7805f49f3f681fea60acf2855ce21d49d6f9f7b 100644
--- a/Framework/DataHandling/src/LoadDetectorsGroupingFile.cpp
+++ b/Framework/DataHandling/src/LoadDetectorsGroupingFile.cpp
@@ -511,9 +511,9 @@ void LoadGroupXMLFile::parseXML() {
         std::string val_value =
             this->getAttributeValueByName(pNode, "val", valfound);
         std::string finalvalue;
-        if (valfound && value.size() > 0)
+        if (valfound && !value.empty())
           finalvalue = value + ", " + val_value;
-        else if (value.size() == 0)
+        else if (value.empty())
           finalvalue = val_value;
         else
           finalvalue = value;
@@ -534,9 +534,9 @@ void LoadGroupXMLFile::parseXML() {
         std::string val_value =
             this->getAttributeValueByName(pNode, "val", valfound);
         std::string finalvalue;
-        if (valfound && value.size() > 0)
+        if (valfound && !value.empty())
           finalvalue = value + ", " + val_value;
-        else if (value.size() == 0)
+        else if (value.empty())
           finalvalue = val_value;
         else
           finalvalue = value;
@@ -559,9 +559,9 @@ void LoadGroupXMLFile::parseXML() {
         std::string val_value =
             this->getAttributeValueByName(pNode, "val", valfound);
         std::string finalvalue;
-        if (valfound && value.size() > 0)
+        if (valfound && !value.empty())
           finalvalue = value + ", " + val_value;
-        else if (value.size() == 0)
+        else if (value.empty())
           finalvalue = val_value;
         else
           finalvalue = value;
diff --git a/Framework/DataHandling/src/LoadDspacemap.cpp b/Framework/DataHandling/src/LoadDspacemap.cpp
index 39519b4353896309f31dd4d6480db944e3f14344..e71748e59cc187f6705d320ae0478ac18688aa2d 100644
--- a/Framework/DataHandling/src/LoadDspacemap.cpp
+++ b/Framework/DataHandling/src/LoadDspacemap.cpp
@@ -121,8 +121,8 @@ void LoadDspacemap::CalculateOffsetsFromDSpacemapFile(
 
     // Compute the factor
     double offset = 0.0;
-    double factor = Instrument::calcConversion(l1, beamline, beamline_norm,
-                                               samplePos, det, offset);
+    double factor = Instrument::calcConversion(
+        l1, beamline, beamline_norm, samplePos, det->getPos(), offset);
     offset = dspace[detectorID] / factor - 1.0;
     // Save in the map
     try {
diff --git a/Framework/DataHandling/src/LoadEmptyInstrument.cpp b/Framework/DataHandling/src/LoadEmptyInstrument.cpp
index 80e9b15a802b973d6bfa57dd0886e8886faf39e9..097ac82e6adbd215ae09621388fa9a324ff6c48a 100644
--- a/Framework/DataHandling/src/LoadEmptyInstrument.cpp
+++ b/Framework/DataHandling/src/LoadEmptyInstrument.cpp
@@ -1,5 +1,6 @@
 #include "MantidAPI/FileProperty.h"
 #include "MantidAPI/RegisterFileLoader.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidDataHandling/LoadEmptyInstrument.h"
 #include "MantidDataObjects/EventWorkspace.h"
@@ -124,7 +125,7 @@ void LoadEmptyInstrument::exec() {
     outWS = WorkspaceFactory::Instance().create("EventWorkspace",
                                                 number_spectra, 2, 1);
     // Copy geometry over.
-    WorkspaceFactory::Instance().initializeFromParent(ws, outWS, true);
+    WorkspaceFactory::Instance().initializeFromParent(*ws, *outWS, true);
   } else {
     // Now create the outputworkspace and copy over the instrument object
     outWS = WorkspaceFactory::Instance().create(ws, number_spectra, 2, 1);
@@ -140,9 +141,9 @@ void LoadEmptyInstrument::exec() {
     CountStandardDeviations v_e(1, detector_value);
     CountStandardDeviations v_monitor_e(1, monitor_value);
 
+    const auto &spectrumInfo = ws2D->spectrumInfo();
     for (size_t i = 0; i < ws2D->getNumberHistograms(); i++) {
-      IDetector_const_sptr det = ws2D->getDetector(i);
-      if (det->isMonitor()) {
+      if (spectrumInfo.isMonitor(i)) {
         ws2D->setCounts(i, v_monitor_y);
         ws2D->setCountStandardDeviations(i, v_monitor_e);
       } else {
diff --git a/Framework/DataHandling/src/LoadEventNexus.cpp b/Framework/DataHandling/src/LoadEventNexus.cpp
index eb8d8b5b87486c429a91d1537401502391a9f899..1be3de61847257593af8a83867a5ed15e69052ac 100644
--- a/Framework/DataHandling/src/LoadEventNexus.cpp
+++ b/Framework/DataHandling/src/LoadEventNexus.cpp
@@ -9,6 +9,7 @@
 #include "MantidAPI/Sample.h"
 #include "MantidAPI/SpectrumDetectorMapping.h"
 #include "MantidGeometry/Instrument.h"
+#include "MantidGeometry/Instrument/Goniometer.h"
 #include "MantidGeometry/Instrument/RectangularDetector.h"
 #include "MantidKernel/ArrayProperty.h"
 #include "MantidKernel/BoundedValidator.h"
@@ -864,7 +865,7 @@ void LoadEventNexus::init() {
 */
 void LoadEventNexus::setTopEntryName() {
   std::string nxentryProperty = getProperty("NXentryName");
-  if (nxentryProperty.size() > 0) {
+  if (!nxentryProperty.empty()) {
     m_top_entry_name = nxentryProperty;
     return;
   }
@@ -1940,8 +1941,7 @@ void LoadEventNexus::runLoadMonitorsAsEvents(API::Progress *const prog) {
           << "data workspace.\n";
       try {
         auto to = m_ws->getSingleHeldWorkspace();
-        auto from = dataWS;
-        copyLogs(from, to);
+        copyLogs(dataWS, to);
         g_log.information() << "Log data copied.\n";
       } catch (std::runtime_error &) {
         g_log.error()
diff --git a/Framework/DataHandling/src/LoadEventPreNexus.cpp b/Framework/DataHandling/src/LoadEventPreNexus.cpp
deleted file mode 100644
index 7f4cf0b5fbeca0847f3c2561dd748f41d68d6637..0000000000000000000000000000000000000000
--- a/Framework/DataHandling/src/LoadEventPreNexus.cpp
+++ /dev/null
@@ -1,965 +0,0 @@
-#include "MantidDataHandling/LoadEventPreNexus.h"
-#include "MantidAPI/Axis.h"
-#include "MantidAPI/FileFinder.h"
-#include "MantidAPI/RegisterFileLoader.h"
-#include "MantidAPI/Run.h"
-#include "MantidAPI/WorkspaceFactory.h"
-#include "MantidDataObjects/EventWorkspace.h"
-#include "MantidDataObjects/EventList.h"
-#include "MantidKernel/ArrayProperty.h"
-#include "MantidKernel/FileValidator.h"
-#include "MantidKernel/DateAndTime.h"
-#include "MantidKernel/Glob.h"
-#include "MantidAPI/FileProperty.h"
-#include "MantidKernel/ConfigService.h"
-#include "MantidKernel/BinaryFile.h"
-#include "MantidKernel/InstrumentInfo.h"
-#include "MantidKernel/System.h"
-#include "MantidKernel/TimeSeriesProperty.h"
-#include "MantidKernel/UnitFactory.h"
-#include "MantidKernel/DateAndTime.h"
-#include "MantidGeometry/IDetector.h"
-#include "MantidGeometry/Instrument.h"
-#include "MantidKernel/CPUTimer.h"
-#include "MantidKernel/VisibleWhenProperty.h"
-#include "MantidKernel/BoundedValidator.h"
-#include "MantidKernel/ListValidator.h"
-
-#include <algorithm>
-#include <sstream>
-#include <stdexcept>
-#include <functional>
-#include <set>
-#include <vector>
-#include <Poco/File.h>
-#include <Poco/Path.h>
-#include <boost/timer.hpp>
-
-namespace Mantid {
-namespace DataHandling {
-
-DECLARE_FILELOADER_ALGORITHM(LoadEventPreNexus)
-
-using namespace Kernel;
-using namespace API;
-using namespace Geometry;
-using boost::posix_time::ptime;
-using boost::posix_time::time_duration;
-using DataObjects::EventList;
-using DataObjects::EventWorkspace;
-using DataObjects::EventWorkspace_sptr;
-using DataObjects::TofEvent;
-using std::cout;
-using std::ifstream;
-using std::runtime_error;
-using std::stringstream;
-using std::string;
-using std::vector;
-
-// constants for locating the parameters to use in execution
-static const string EVENT_PARAM("EventFilename");
-static const string PULSEID_PARAM("PulseidFilename");
-static const string MAP_PARAM("MappingFilename");
-static const string PID_PARAM("SpectrumList");
-static const string PARALLEL_PARAM("UseParallelProcessing");
-static const string BLOCK_SIZE_PARAM("LoadingBlockSize");
-static const string OUT_PARAM("OutputWorkspace");
-
-static const string PULSE_EXT("pulseid.dat");
-static const string EVENT_EXT("event.dat");
-
-/// All pixel ids with matching this mask are errors.
-static const PixelType ERROR_PID = 0x80000000;
-/// The maximum possible tof as native type
-static const uint32_t MAX_TOF_UINT32 = std::numeric_limits<uint32_t>::max();
-
-/// Conversion factor between 100 nanoseconds and 1 microsecond.
-static const double TOF_CONVERSION = .1;
-/// Conversion factor between picoColumbs and microAmp*hours
-static const double CURRENT_CONVERSION = 1.e-6 / 3600.;
-
-LoadEventPreNexus::LoadEventPreNexus()
-    : Mantid::API::IFileLoader<Kernel::FileDescriptor>(), prog(nullptr),
-      spectra_list(), pulsetimes(), event_indices(), proton_charge(),
-      proton_charge_tot(0), pixel_to_wkspindex(), pixelmap(), detid_max(),
-      eventfile(nullptr), num_events(0), num_pulses(0), numpixel(0),
-      num_good_events(0), num_error_events(0), num_ignored_events(0),
-      first_event(0), max_events(0), using_mapping_file(false),
-      loadOnlySomeSpectra(false), spectraLoadMap(), longest_tof(0),
-      shortest_tof(0), parallelProcessing(false) {
-  this->useAlgorithm("LoadEventPreNexus", 2);
-}
-
-LoadEventPreNexus::~LoadEventPreNexus() { delete this->eventfile; }
-
-/**
- * Return the confidence with with this algorithm can load the file
- * @param descriptor A descriptor for the file
- * @returns An integer specifying the confidence level. 0 indicates it will not
- * be used
- */
-int LoadEventPreNexus::confidence(Kernel::FileDescriptor &descriptor) const {
-  if (descriptor.extension().rfind("dat") == std::string::npos)
-    return 0;
-
-  // If this looks like a binary file where the exact file length is a multiple
-  // of the DasEvent struct then we're probably okay.
-  if (descriptor.isAscii())
-    return 0;
-
-  const size_t objSize = sizeof(DasEvent);
-  auto &handle = descriptor.data();
-  // get the size of the file in bytes and reset the handle back to the
-  // beginning
-  handle.seekg(0, std::ios::end);
-  const size_t filesize = static_cast<size_t>(handle.tellg());
-  handle.seekg(0, std::ios::beg);
-
-  if (filesize % objSize == 0)
-    return 60;
-  else
-    return 0;
-}
-
-//-----------------------------------------------------------------------------
-/** Initialize the algorithm */
-void LoadEventPreNexus::init() {
-  // which files to use
-  declareProperty(
-      Kernel::make_unique<FileProperty>(EVENT_PARAM, "", FileProperty::Load,
-                                        EVENT_EXT),
-      "The name of the neutron event file to read, including its full or "
-      "relative path. The file typically ends in neutron_event.dat (N.B. case "
-      "sensitive if running on Linux).");
-  declareProperty(Kernel::make_unique<FileProperty>(
-                      PULSEID_PARAM, "", FileProperty::OptionalLoad, PULSE_EXT),
-                  "File containing the accelerator pulse information; the "
-                  "filename will be found automatically if not specified.");
-  declareProperty(
-      Kernel::make_unique<FileProperty>(MAP_PARAM, "",
-                                        FileProperty::OptionalLoad, ".dat"),
-      "File containing the pixel mapping (DAS pixels to pixel IDs) file "
-      "(typically INSTRUMENT_TS_YYYY_MM_DD.dat). The filename will be found "
-      "automatically if not specified.");
-
-  // which pixels to load
-  declareProperty(Kernel::make_unique<ArrayProperty<int64_t>>(PID_PARAM),
-                  "A list of individual spectra (pixel IDs) to read, specified "
-                  "as e.g. 10:20. Only used if set.");
-
-  auto mustBePositive = boost::make_shared<BoundedValidator<int>>();
-  mustBePositive->setLower(1);
-  declareProperty("ChunkNumber", EMPTY_INT(), mustBePositive,
-                  "If loading the file by sections ('chunks'), this is the "
-                  "section number of this execution of the algorithm.");
-  declareProperty("TotalChunks", EMPTY_INT(), mustBePositive,
-                  "If loading the file by sections ('chunks'), this is the "
-                  "total number of sections.");
-  // TotalChunks is only meaningful if ChunkNumber is set
-  // Would be nice to be able to restrict ChunkNumber to be <= TotalChunks at
-  // validation
-  setPropertySettings("TotalChunks", make_unique<VisibleWhenProperty>(
-                                         "ChunkNumber", IS_NOT_DEFAULT));
-
-  std::vector<std::string> propOptions{"Auto", "Serial", "Parallel"};
-  declareProperty("UseParallelProcessing", "Auto",
-                  boost::make_shared<StringListValidator>(propOptions),
-                  "Use multiple cores for loading the data?\n"
-                  "  Auto: Use serial loading for small data sets, parallel "
-                  "for large data sets.\n"
-                  "  Serial: Use a single core.\n"
-                  "  Parallel: Use all available cores.");
-
-  // the output workspace name
-  declareProperty(
-      Kernel::make_unique<WorkspaceProperty<IEventWorkspace>>(
-          OUT_PARAM, "", Direction::Output),
-      "The name of the workspace that will be created, filled with the read-in "
-      "data and stored in the [[Analysis Data Service]].");
-}
-
-//-----------------------------------------------------------------------------
-static string generatePulseidName(string eventfile) {
-  size_t start;
-  string ending;
-
-  // normal ending
-  ending = "neutron_event.dat";
-  start = eventfile.find(ending);
-  if (start != string::npos)
-    return eventfile.replace(start, ending.size(), "pulseid.dat");
-
-  // split up event files - yes this is copy and pasted code
-  ending = "neutron0_event.dat";
-  start = eventfile.find(ending);
-  if (start != string::npos)
-    return eventfile.replace(start, ending.size(), "pulseid0.dat");
-
-  ending = "neutron1_event.dat";
-  start = eventfile.find(ending);
-  if (start != string::npos)
-    return eventfile.replace(start, ending.size(), "pulseid1.dat");
-
-  return "";
-}
-
-//-----------------------------------------------------------------------------
-static string generateMappingfileName(EventWorkspace_sptr &wksp) { //
-  // get the name of the mapping file as set in the parameter files
-  std::vector<string> temp =
-      wksp->getInstrument()->getStringParameter("TS_mapping_file");
-  if (temp.empty())
-    return "";
-  string mapping = temp[0];
-  // Try to get it from the working directory
-  Poco::File localmap(mapping);
-  if (localmap.exists())
-    return mapping;
-
-  // Try to get it from the data directories
-  string dataversion = Mantid::API::FileFinder::Instance().getFullPath(mapping);
-  if (!dataversion.empty())
-    return dataversion;
-
-  // get a list of all proposal directories
-  string instrument = wksp->getInstrument()->getName();
-  Poco::File base("/SNS/" + instrument + "/");
-  // try short instrument name
-  if (!base.exists()) {
-    instrument =
-        Kernel::ConfigService::Instance().getInstrument(instrument).shortName();
-    base = Poco::File("/SNS/" + instrument + "/");
-    if (!base.exists())
-      return "";
-  }
-  vector<string> dirs; // poco won't let me reuse temp
-  base.list(dirs);
-
-  // check all of the proposals for the mapping file in the canonical place
-  const string CAL("_CAL");
-  const size_t CAL_LEN = CAL.length(); // cache to make life easier
-  vector<string> files;
-  for (auto &dir : dirs) {
-    if ((dir.length() > CAL_LEN) &&
-        (dir.compare(dir.length() - CAL.length(), CAL.length(), CAL) == 0)) {
-      if (Poco::File(base.path() + "/" + dir + "/calibrations/" + mapping)
-              .exists())
-        files.push_back(base.path() + "/" + dir + "/calibrations/" + mapping);
-    }
-  }
-
-  if (files.empty())
-    return "";
-  else if (files.size() == 1)
-    return files[0];
-  else // just assume that the last one is the right one, this should never be
-       // fired
-    return *(files.rbegin());
-}
-
-namespace { // anonymous namespace
-string getRunnumber(const string &filename) {
-  // start by trimming the filename
-  string runnumber(Poco::Path(filename).getBaseName());
-
-  if (runnumber.find("neutron") >= string::npos)
-    return "0";
-
-  std::size_t left = runnumber.find('_');
-  std::size_t right = runnumber.find('_', left + 1);
-
-  return runnumber.substr(left + 1, right - left - 1);
-}
-}
-
-//-----------------------------------------------------------------------------
-/** Execute the algorithm */
-void LoadEventPreNexus::exec() {
-  // Check 'chunk' properties are valid, if set
-  const int chunks = getProperty("TotalChunks");
-  if (!isEmpty(chunks) && int(getProperty("ChunkNumber")) > chunks) {
-    throw std::out_of_range("ChunkNumber cannot be larger than TotalChunks");
-  }
-
-  prog = new Progress(this, 0.0, 1.0, 100);
-
-  // what spectra (pixel ID's) to load
-  this->spectra_list = this->getProperty(PID_PARAM);
-
-  // the event file is needed in case the pulseid fileanme is empty
-  string event_filename = this->getPropertyValue(EVENT_PARAM);
-  string pulseid_filename = this->getPropertyValue(PULSEID_PARAM);
-  bool throwError = true;
-  if (pulseid_filename.empty()) {
-    pulseid_filename = generatePulseidName(event_filename);
-    if (!pulseid_filename.empty()) {
-      if (Poco::File(pulseid_filename).exists()) {
-        this->g_log.information() << "Found pulseid file " << pulseid_filename
-                                  << '\n';
-        throwError = false;
-      } else {
-        pulseid_filename = "";
-      }
-    }
-  }
-
-  prog->report("Loading Pulse ID file");
-  this->readPulseidFile(pulseid_filename, throwError);
-
-  this->openEventFile(event_filename);
-
-  prog->report("Creating output workspace");
-  // prep the output workspace
-  EventWorkspace_sptr localWorkspace =
-      EventWorkspace_sptr(new EventWorkspace());
-  // Make sure to initialize.
-  //   We can use dummy numbers for arguments, for event workspace it doesn't
-  //   matter
-  localWorkspace->initialize(1, 1, 1);
-
-  // Set the units
-  localWorkspace->getAxis(0)->unit() = UnitFactory::Instance().create("TOF");
-  localWorkspace->setYUnit("Counts");
-  // TODO localWorkspace->setTitle(title);
-
-  // Add the run_start property
-  // Use the first pulse as the run_start time.
-  if (this->num_pulses > 0) {
-    // add the start of the run as a ISO8601 date/time string. The start = the
-    // first pulse.
-    // (this is used in LoadInstrument to find the right instrument file to
-    // use).
-    localWorkspace->mutableRun().addProperty(
-        "run_start", pulsetimes[0].toISO8601String(), true);
-  }
-
-  // determine the run number and add it to the run object
-  localWorkspace->mutableRun().addProperty("run_number",
-                                           getRunnumber(event_filename));
-
-  // Get the instrument!
-  prog->report("Loading Instrument");
-  this->runLoadInstrument(event_filename, localWorkspace);
-
-  // load the mapping file
-  prog->report("Loading Mapping File");
-  string mapping_filename = this->getPropertyValue(MAP_PARAM);
-  if (mapping_filename.empty()) {
-    mapping_filename = generateMappingfileName(localWorkspace);
-    if (!mapping_filename.empty())
-      this->g_log.information() << "Found mapping file \"" << mapping_filename
-                                << "\"\n";
-  }
-  this->loadPixelMap(mapping_filename);
-
-  // Replace workspace by workspace of correct size
-  // Number of non-monitors in instrument
-  size_t nSpec = localWorkspace->getInstrument()->getDetectorIDs(true).size();
-  if (!this->spectra_list.empty())
-    nSpec = this->spectra_list.size();
-  auto tmp = createWorkspace<EventWorkspace>(nSpec, 2, 1);
-  WorkspaceFactory::Instance().initializeFromParent(localWorkspace, tmp, true);
-  localWorkspace = std::move(tmp);
-
-  // Process the events into pixels
-  this->procEvents(localWorkspace);
-
-  // Save output
-  this->setProperty<IEventWorkspace_sptr>(OUT_PARAM, localWorkspace);
-
-  // Cleanup
-  delete prog;
-}
-
-//-----------------------------------------------------------------------------
-/** Load the instrument geometry File
- *  @param eventfilename :: Used to pick the instrument.
- *  @param localWorkspace :: MatrixWorkspace in which to put the instrument
- * geometry
- */
-void LoadEventPreNexus::runLoadInstrument(const std::string &eventfilename,
-                                          MatrixWorkspace_sptr localWorkspace) {
-  // determine the instrument parameter file
-  string instrument = Poco::Path(eventfilename).getFileName();
-  size_t pos = instrument.rfind('_');   // get rid of 'event.dat'
-  pos = instrument.rfind('_', pos - 1); // get rid of 'neutron'
-  pos = instrument.rfind('_', pos - 1); // get rid of the run number
-  instrument = instrument.substr(0, pos);
-
-  // do the actual work
-  IAlgorithm_sptr loadInst = createChildAlgorithm("LoadInstrument");
-
-  // Now execute the Child Algorithm. Catch and log any error, but don't stop.
-  loadInst->setPropertyValue("InstrumentName", instrument);
-  loadInst->setProperty<MatrixWorkspace_sptr>("Workspace", localWorkspace);
-  loadInst->setProperty("RewriteSpectraMap",
-                        Mantid::Kernel::OptionalBool(false));
-  loadInst->executeAsChildAlg();
-
-  // Populate the instrument parameters in this workspace - this works around a
-  // bug
-  localWorkspace->populateInstrumentParameters();
-}
-
-//-----------------------------------------------------------------------------
-/** Turn a pixel id into a "corrected" pixelid and period.
- *
- */
-inline void LoadEventPreNexus::fixPixelId(PixelType &pixel,
-                                          uint32_t &period) const {
-  if (!this->using_mapping_file) { // nothing to do here
-    period = 0;
-    return;
-  }
-
-  PixelType unmapped_pid = pixel % this->numpixel;
-  period = (pixel - unmapped_pid) / this->numpixel;
-  pixel = this->pixelmap[unmapped_pid];
-}
-
-//-----------------------------------------------------------------------------
-/** Process the event file properly.
- * @param workspace :: EventWorkspace to write to.
- */
-void LoadEventPreNexus::procEvents(
-    DataObjects::EventWorkspace_sptr &workspace) {
-  this->num_error_events = 0;
-  this->num_good_events = 0;
-  this->num_ignored_events = 0;
-
-  // Default values in the case of no parallel
-  size_t loadBlockSize = Mantid::Kernel::DEFAULT_BLOCK_SIZE * 2;
-
-  shortest_tof = static_cast<double>(MAX_TOF_UINT32) * TOF_CONVERSION;
-  longest_tof = 0.;
-
-  // Initialize progress reporting.
-  size_t numBlocks = (max_events + loadBlockSize - 1) / loadBlockSize;
-
-  // We want to pad out empty pixels.
-  detid2det_map detector_map;
-  workspace->getInstrument()->getDetectors(detector_map);
-
-  // -------------- Determine processing mode
-  std::string procMode = getProperty("UseParallelProcessing");
-  if (procMode == "Serial")
-    parallelProcessing = false;
-  else if (procMode == "Parallel")
-    parallelProcessing = true;
-  else {
-    // Automatic determination. Loading serially (for me) is about 3 million
-    // events per second,
-    // (which is sped up by ~ x 3 with parallel processing, say 10 million per
-    // second, e.g. 7 million events more per seconds).
-    // compared to a setup time/merging time of about 10 seconds per million
-    // detectors.
-    double setUpTime = double(detector_map.size()) * 10e-6;
-    parallelProcessing = ((double(max_events) / 7e6) > setUpTime);
-    g_log.debug() << (parallelProcessing ? "Using" : "Not using")
-                  << " parallel processing.\n";
-  }
-
-  // determine maximum pixel id
-  detid2det_map::iterator it;
-  detid_max = 0; // seems like a safe lower bound
-  for (it = detector_map.begin(); it != detector_map.end(); it++)
-    if (it->first > detid_max)
-      detid_max = it->first;
-
-  // For slight speed up
-  loadOnlySomeSpectra = (!this->spectra_list.empty());
-
-  // Turn the spectra list into a map, for speed of access
-  for (auto &spectrum : spectra_list)
-    spectraLoadMap[spectrum] = true;
-
-  // Pad all the pixels
-  prog->report("Padding Pixels");
-  this->pixel_to_wkspindex.reserve(
-      detid_max + 1); // starting at zero up to and including detid_max
-  // Set to zero
-  this->pixel_to_wkspindex.assign(detid_max + 1, 0);
-  size_t workspaceIndex = 0;
-  specnum_t spectrumNumber = 1;
-  for (it = detector_map.begin(); it != detector_map.end(); it++) {
-    if (!it->second->isMonitor()) {
-      if (!loadOnlySomeSpectra ||
-          (spectraLoadMap.find(it->first) != spectraLoadMap.end())) {
-        this->pixel_to_wkspindex[it->first] = workspaceIndex;
-        EventList &spec = workspace->getSpectrum(workspaceIndex);
-        spec.setDetectorID(it->first);
-        spec.setSpectrumNo(spectrumNumber);
-        ++workspaceIndex;
-      } else {
-        this->pixel_to_wkspindex[it->first] = -1;
-      }
-      ++spectrumNumber;
-    }
-  }
-
-  CPUTimer tim;
-
-  // --------------- Create the partial workspaces
-  // ------------------------------------------
-  // Vector of partial workspaces, for parallel processing.
-  std::vector<EventWorkspace_sptr> partWorkspaces;
-  std::vector<DasEvent *> buffers;
-
-  /// Pointer to the vector of events
-  typedef std::vector<TofEvent> *EventVector_pt;
-  /// Bare array of arrays of pointers to the EventVectors
-  EventVector_pt **eventVectors;
-
-  /// How many threads will we use?
-  size_t numThreads = 1;
-  if (parallelProcessing)
-    numThreads = size_t(PARALLEL_GET_MAX_THREADS);
-
-  partWorkspaces.resize(numThreads);
-  buffers.resize(numThreads);
-  eventVectors = new EventVector_pt *[numThreads];
-
-  // cppcheck-suppress syntaxError
-  PRAGMA_OMP( parallel for if (parallelProcessing) )
-  for (int i = 0; i < int(numThreads); i++) {
-    // This is the partial workspace we are about to create (if in parallel)
-    EventWorkspace_sptr partWS;
-    if (parallelProcessing) {
-      prog->report("Creating Partial Workspace");
-      // Create a partial workspace, copy all the spectra numbers and stuff
-      // (no actual events to copy though).
-      partWS = workspace->clone();
-      // Push it in the array
-      partWorkspaces[i] = partWS;
-    } else
-      partWS = workspace;
-
-    // Allocate the buffers
-    buffers[i] = new DasEvent[loadBlockSize];
-
-    // For each partial workspace, make an array where index = detector ID and
-    // value = pointer to the events vector
-    eventVectors[i] = new EventVector_pt[detid_max + 1];
-    EventVector_pt *theseEventVectors = eventVectors[i];
-    for (detid_t j = 0; j < detid_max + 1; j++) {
-      size_t wi = pixel_to_wkspindex[j];
-      // Save a POINTER to the vector<tofEvent>
-      if (wi != static_cast<size_t>(-1))
-        theseEventVectors[j] = &partWS->getSpectrum(wi).getEvents();
-      else
-        theseEventVectors[j] = nullptr;
-    }
-  }
-
-  g_log.debug() << tim << " to create " << partWorkspaces.size()
-                << " workspaces for parallel loading.\n";
-
-  prog->resetNumSteps(numBlocks, 0.1, 0.8);
-
-  // ---------------------------------- LOAD THE DATA --------------------------
-  PRAGMA_OMP( parallel for schedule(dynamic, 1) if (parallelProcessing) )
-  for (int blockNum = 0; blockNum < int(numBlocks); blockNum++) {
-    PARALLEL_START_INTERUPT_REGION
-
-    // Find the workspace for this particular thread
-    EventWorkspace_sptr ws;
-    size_t threadNum = 0;
-    if (parallelProcessing) {
-      threadNum = PARALLEL_THREAD_NUMBER;
-      ws = partWorkspaces[threadNum];
-    } else
-      ws = workspace;
-
-    // Get the buffer (for this thread)
-    DasEvent *event_buffer = buffers[threadNum];
-
-    // Get the speeding-up array of vector<tofEvent> where index = detid.
-    EventVector_pt *theseEventVectors = eventVectors[threadNum];
-
-    // Where to start in the file?
-    size_t fileOffset = first_event + (loadBlockSize * blockNum);
-    // May need to reduce size of last (or only) block
-    size_t current_event_buffer_size =
-        (blockNum == int(numBlocks - 1))
-            ? (max_events - (numBlocks - 1) * loadBlockSize)
-            : loadBlockSize;
-
-    // Load this chunk of event data (critical block)
-    PARALLEL_CRITICAL(LoadEventPreNexus_fileAccess) {
-      current_event_buffer_size = eventfile->loadBlockAt(
-          event_buffer, fileOffset, current_event_buffer_size);
-    }
-
-    // This processes the events. Can be done in parallel!
-    procEventsLinear(ws, theseEventVectors, event_buffer,
-                     current_event_buffer_size, fileOffset);
-
-    // Report progress
-    prog->report("Load Event PreNeXus");
-
-    PARALLEL_END_INTERUPT_REGION
-  }
-  PARALLEL_CHECK_INTERUPT_REGION
-  g_log.debug() << tim << " to load the data.\n";
-
-  // ---------------------------------- MERGE WORKSPACES BACK TOGETHER
-  // --------------------------
-  if (parallelProcessing) {
-    PARALLEL_START_INTERUPT_REGION
-    prog->resetNumSteps(workspace->getNumberHistograms(), 0.8, 0.95);
-
-    // Merge all workspaces, index by index.
-    PARALLEL_FOR_NO_WSP_CHECK()
-    for (int iwi = 0; iwi < int(workspace->getNumberHistograms()); iwi++) {
-      size_t wi = size_t(iwi);
-
-      // The output event list.
-      EventList &el = workspace->getSpectrum(wi);
-      el.clear(false);
-
-      // How many events will it have?
-      size_t numEvents = 0;
-      for (size_t i = 0; i < numThreads; i++)
-        numEvents += partWorkspaces[i]->getSpectrum(wi).getNumberEvents();
-      // This will avoid too much copying.
-      el.reserve(numEvents);
-
-      // Now merge the event lists
-      for (size_t i = 0; i < numThreads; i++) {
-        EventList &partEl = partWorkspaces[i]->getSpectrum(wi);
-        el += partEl.getEvents();
-        // Free up memory as you go along.
-        partEl.clear(false);
-      }
-      prog->report("Merging Workspaces");
-    }
-    g_log.debug() << tim << " to merge workspaces together.\n";
-    PARALLEL_END_INTERUPT_REGION
-  }
-  PARALLEL_CHECK_INTERUPT_REGION
-
-  // Delete the buffers for each thread.
-  for (size_t i = 0; i < numThreads; i++) {
-    delete[] buffers[i];
-    delete[] eventVectors[i];
-  }
-  delete[] eventVectors;
-  // delete [] pulsetimes;
-
-  prog->resetNumSteps(3, 0.94, 1.00);
-
-  // finalize loading
-  prog->report("Setting proton charge");
-  this->setProtonCharge(workspace);
-  g_log.debug() << tim << " to set the proton charge log.\n";
-
-  // Make sure the MRU is cleared
-  workspace->clearMRU();
-
-  // Now, create a default X-vector for histogramming, with just 2 bins.
-  auto axis = HistogramData::BinEdges{shortest_tof - 1, longest_tof + 1};
-  workspace->setAllX(axis);
-  this->pixel_to_wkspindex.clear();
-
-  g_log.information() << "Read " << this->num_good_events << " events + "
-                      << this->num_error_events << " errors"
-                      << ". Shortest TOF: " << shortest_tof
-                      << " microsec; longest TOF: " << longest_tof
-                      << " microsec.\n";
-}
-
-//-----------------------------------------------------------------------------
-/** Linear-version of the procedure to process the event file properly.
- * @param workspace :: EventWorkspace to write to.
- * @param arrayOfVectors :: For speed up: this is an array, of size detid_max+1,
- * where the
- *        index is a pixel ID, and the value is a pointer to the
- * vector<tofEvent> in the given EventList.
- * @param event_buffer :: The buffer containing the DAS events
- * @param current_event_buffer_size :: The length of the given DAS buffer
- * @param fileOffset :: Value for an offset into the binary file
- */
-void LoadEventPreNexus::procEventsLinear(
-    DataObjects::EventWorkspace_sptr & /*workspace*/,
-    std::vector<TofEvent> **arrayOfVectors, DasEvent *event_buffer,
-    size_t current_event_buffer_size, size_t fileOffset) {
-  // Starting pulse time
-  DateAndTime pulsetime;
-  int64_t pulse_i = 0;
-  int64_t numPulses = static_cast<int64_t>(num_pulses);
-  if (event_indices.size() < num_pulses) {
-    g_log.warning()
-        << "Event_indices vector is smaller than the pulsetimes array.\n";
-    numPulses = static_cast<int64_t>(event_indices.size());
-  }
-
-  size_t local_num_error_events = 0;
-  size_t local_num_ignored_events = 0;
-  size_t local_num_good_events = 0;
-  double local_shortest_tof =
-      static_cast<double>(MAX_TOF_UINT32) * TOF_CONVERSION;
-  double local_longest_tof = 0.;
-
-  // process the individual events
-  for (size_t i = 0; i < current_event_buffer_size; i++) {
-    DasEvent &temp = *(event_buffer + i);
-    PixelType pid = temp.pid;
-
-    if ((pid & ERROR_PID) == ERROR_PID) // marked as bad
-    {
-      local_num_error_events++;
-      continue;
-    }
-
-    // Covert the pixel ID from DAS pixel to our pixel ID
-    if (this->using_mapping_file) {
-      PixelType unmapped_pid = pid % this->numpixel;
-      pid = this->pixelmap[unmapped_pid];
-    }
-
-    // Avoid segfaults for wrong pixel IDs
-    if (pid > static_cast<PixelType>(detid_max)) {
-      local_num_error_events++;
-      continue;
-    }
-
-    // Now check if this pid we want to load.
-    if (loadOnlySomeSpectra) {
-      std::map<int64_t, bool>::iterator it;
-      it = spectraLoadMap.find(pid);
-      if (it == spectraLoadMap.end()) {
-        // Pixel ID was not found, so the event is being ignored.
-        local_num_ignored_events++;
-        continue;
-      }
-    }
-
-    // work with the good guys
-
-    // Find the pulse time for this event index
-    if (pulse_i < numPulses - 1) {
-      // This is the total offset into the file
-      size_t total_i = i + fileOffset;
-      // Go through event_index until you find where the index increases to
-      // encompass the current index. Your pulse = the one before.
-      while (!((total_i >= event_indices[pulse_i]) &&
-               (total_i < event_indices[pulse_i + 1]))) {
-        pulse_i++;
-        if (pulse_i >= (numPulses - 1))
-          break;
-      }
-
-      // if (pulsetimes[pulse_i] != pulsetime)    std::cout << pulse_i << " at "
-      // << pulsetimes[pulse_i] << "\n";
-
-      // Save the pulse time at this index for creating those events
-      pulsetime = pulsetimes[pulse_i];
-    }
-
-    double tof = static_cast<double>(temp.tof) * TOF_CONVERSION;
-    TofEvent event(tof, pulsetime);
-
-    // Find the overall max/min tof
-    if (tof < local_shortest_tof)
-      local_shortest_tof = tof;
-    if (tof > local_longest_tof)
-      local_longest_tof = tof;
-
-    // The addEventQuickly method does not clear the cache, making things
-    // slightly faster.
-    // workspace->getSpectrum(this->pixel_to_wkspindex[pid]).addEventQuickly(event);
-
-    // This is equivalent to
-    // workspace->getSpectrum(this->pixel_to_wkspindex[pid]).addEventQuickly(event);
-    // But should be faster as a bunch of these calls were cached.
-    arrayOfVectors[pid]->push_back(event);
-
-    // TODO work with period
-    local_num_good_events++;
-
-  } // for each event
-
-  PARALLEL_CRITICAL(LoadEventPreNexus_global_statistics) {
-    this->num_good_events += local_num_good_events;
-    this->num_ignored_events += local_num_ignored_events;
-    this->num_error_events += local_num_error_events;
-    if (local_shortest_tof < shortest_tof)
-      shortest_tof = local_shortest_tof;
-    if (local_longest_tof > longest_tof)
-      longest_tof = local_longest_tof;
-  }
-}
-
-//-----------------------------------------------------------------------------
-/// Comparator for sorting dasevent lists
-bool intermediatePixelIDComp(IntermediateEvent x, IntermediateEvent y) {
-  return (x.pid < y.pid);
-}
-
-//-----------------------------------------------------------------------------
-/**
- * Add a sample environment log for the proton chage (charge of the pulse in
- *picoCoulombs)
- * and set the scalar value (total proton charge, microAmps*hours, on the
- *sample)
- *
- * @param workspace :: Event workspace to set the proton charge on
- */
-void LoadEventPreNexus::setProtonCharge(
-    DataObjects::EventWorkspace_sptr &workspace) {
-  if (this->proton_charge.empty()) // nothing to do
-    return;
-
-  Run &run = workspace->mutableRun();
-
-  // Add the proton charge entries.
-  TimeSeriesProperty<double> *log =
-      new TimeSeriesProperty<double>("proton_charge");
-  log->setUnits("picoCoulombs");
-
-  // Add the time and associated charge to the log
-  log->addValues(this->pulsetimes, this->proton_charge);
-
-  /// TODO set the units for the log
-  run.addLogData(log);
-  // Force re-integration
-  run.integrateProtonCharge();
-  double integ = run.getProtonCharge();
-  this->g_log.information() << "Total proton charge of " << integ
-                            << " microAmp*hours found by integrating.\n";
-}
-
-//-----------------------------------------------------------------------------
-/** Load a pixel mapping file
- * @param filename :: Path to file.
- */
-void LoadEventPreNexus::loadPixelMap(const std::string &filename) {
-  this->using_mapping_file = false;
-
-  // check that there is a mapping file
-  if (filename.empty()) {
-    this->g_log.information("NOT using a mapping file");
-    return;
-  }
-
-  // actually deal with the file
-  this->g_log.debug("Using mapping file \"" + filename + "\"");
-
-  // Open the file; will throw if there is any problem
-  BinaryFile<PixelType> pixelmapFile(filename);
-  PixelType max_pid = static_cast<PixelType>(pixelmapFile.getNumElements());
-  // Load all the data
-  this->pixelmap = pixelmapFile.loadAllIntoVector();
-
-  // Check for funky file
-  if (std::find_if(pixelmap.begin(), pixelmap.end(),
-                   std::bind2nd(std::greater<PixelType>(), max_pid)) !=
-      pixelmap.end()) {
-    this->g_log.warning("Pixel id in mapping file was out of bounds. Loading "
-                        "without mapping file");
-    this->numpixel = 0;
-    this->pixelmap.clear();
-    this->using_mapping_file = false;
-    return;
-  }
-
-  // If we got here, the mapping file was loaded correctly and we'll use it
-  this->using_mapping_file = true;
-  // Let's assume that the # of pixels in the instrument matches the mapping
-  // file length.
-  this->numpixel = static_cast<uint32_t>(pixelmapFile.getNumElements());
-}
-
-//-----------------------------------------------------------------------------
-/** Open an event file
- * @param filename :: file to open.
- */
-void LoadEventPreNexus::openEventFile(const std::string &filename) {
-  // Open the file
-  eventfile = new BinaryFile<DasEvent>(filename);
-  num_events = eventfile->getNumElements();
-  g_log.debug() << "File contains " << num_events << " event records.\n";
-
-  // Check if we are only loading part of the event file
-  const int chunk = getProperty("ChunkNumber");
-  if (isEmpty(chunk)) // We are loading the whole file
-  {
-    first_event = 0;
-    max_events = num_events;
-  } else // We are loading part - work out the event number range
-  {
-    const int totalChunks = getProperty("TotalChunks");
-    max_events = num_events / totalChunks;
-    first_event = (chunk - 1) * max_events;
-    // Need to add any remainder to the final chunk
-    if (chunk == totalChunks)
-      max_events += num_events % totalChunks;
-  }
-
-  g_log.information() << "Reading " << max_events << " event records\n";
-}
-
-//-----------------------------------------------------------------------------
-/** Read a pulse ID file
- * @param filename :: file to load.
- * @param throwError :: Flag to trigger error throwing instead of just logging
- */
-void LoadEventPreNexus::readPulseidFile(const std::string &filename,
-                                        const bool throwError) {
-  this->proton_charge_tot = 0.;
-  this->num_pulses = 0;
-
-  // jump out early if there isn't a filename
-  if (filename.empty()) {
-    this->g_log.information("NOT using a pulseid file");
-    return;
-  }
-
-  std::vector<Pulse> pulses;
-
-  // set up for reading
-  // Open the file; will throw if there is any problem
-  try {
-    BinaryFile<Pulse> pulseFile(filename);
-
-    // Get the # of pulse
-    this->num_pulses = pulseFile.getNumElements();
-    this->g_log.information() << "Using pulseid file \"" << filename
-                              << "\", with " << num_pulses << " pulses.\n";
-
-    // Load all the data
-    pulses = pulseFile.loadAll();
-  } catch (runtime_error &e) {
-    if (throwError) {
-      throw;
-    } else {
-      this->g_log.information()
-          << "Encountered error in pulseidfile (ignoring file): " << e.what()
-          << "\n";
-      return;
-    }
-  }
-
-  double temp;
-
-  if (num_pulses > 0) {
-    this->pulsetimes.reserve(num_pulses);
-    for (const auto &pulse : pulses) {
-      this->pulsetimes.emplace_back(static_cast<int64_t>(pulse.seconds),
-                                    static_cast<int64_t>(pulse.nanoseconds));
-      this->event_indices.push_back(pulse.event_index);
-
-      temp = pulse.pCurrent;
-      this->proton_charge.push_back(temp);
-      if (temp < 0.)
-        this->g_log.warning("Individual proton charge < 0 being ignored");
-      else
-        this->proton_charge_tot += temp;
-    }
-  }
-
-  this->proton_charge_tot = this->proton_charge_tot * CURRENT_CONVERSION;
-}
-
-} // namespace DataHandling
-} // namespace Mantid
diff --git a/Framework/DataHandling/src/LoadEventPreNexus2.cpp b/Framework/DataHandling/src/LoadEventPreNexus2.cpp
index ab5a9953405d983c24ac830f95c853faee28685d..9d756994ae1c98c1f4839c939b1a9fa6d15f0e00 100644
--- a/Framework/DataHandling/src/LoadEventPreNexus2.cpp
+++ b/Framework/DataHandling/src/LoadEventPreNexus2.cpp
@@ -1,5 +1,6 @@
 #include "MantidDataHandling/LoadEventPreNexus2.h"
 #include "MantidAPI/Axis.h"
+#include "MantidAPI/DetectorInfo.h"
 #include "MantidAPI/FileFinder.h"
 #include "MantidAPI/RegisterFileLoader.h"
 #include "MantidAPI/Run.h"
@@ -451,7 +452,8 @@ void LoadEventPreNexus2::createOutputWorkspace(
   if (!this->spectra_list.empty())
     nSpec = this->spectra_list.size();
   auto tmp = createWorkspace<EventWorkspace>(nSpec, 2, 1);
-  WorkspaceFactory::Instance().initializeFromParent(localWorkspace, tmp, true);
+  WorkspaceFactory::Instance().initializeFromParent(*localWorkspace, *tmp,
+                                                    true);
   localWorkspace = std::move(tmp);
 }
 
@@ -669,8 +671,8 @@ void LoadEventPreNexus2::procEvents(
   size_t numBlocks = (max_events + loadBlockSize - 1) / loadBlockSize;
 
   // We want to pad out empty pixels.
-  detid2det_map detector_map;
-  workspace->getInstrument()->getDetectors(detector_map);
+  const auto &detectorInfo = workspace->detectorInfo();
+  const auto &detIDs = detectorInfo.detectorIDs();
 
   // Determine processing mode
   std::string procMode = getProperty("UseParallelProcessing");
@@ -685,18 +687,17 @@ void LoadEventPreNexus2::procEvents(
     // second, e.g. 7 million events more per seconds).
     // compared to a setup time/merging time of about 10 seconds per million
     // detectors.
-    double setUpTime = double(detector_map.size()) * 10e-6;
+    double setUpTime = double(detectorInfo.size()) * 10e-6;
     parallelProcessing = ((double(max_events) / 7e6) > setUpTime);
     g_log.debug() << (parallelProcessing ? "Using" : "Not using")
                   << " parallel processing.\n";
   }
 
   // determine maximum pixel id
-  detid2det_map::iterator it;
   detid_max = 0; // seems like a safe lower bound
-  for (it = detector_map.begin(); it != detector_map.end(); it++)
-    if (it->first > detid_max)
-      detid_max = it->first;
+  for (const auto detID : detIDs)
+    if (detID > detid_max)
+      detid_max = detID;
 
   // For slight speed up
   loadOnlySomeSpectra = (!this->spectra_list.empty());
@@ -713,17 +714,17 @@ void LoadEventPreNexus2::procEvents(
   this->pixel_to_wkspindex.assign(detid_max + 1, 0);
   size_t workspaceIndex = 0;
   specnum_t spectrumNumber = 1;
-  for (it = detector_map.begin(); it != detector_map.end(); it++) {
-    if (!it->second->isMonitor()) {
+  for (size_t i = 0; i < detectorInfo.size(); ++i) {
+    if (!detectorInfo.isMonitor(i)) {
       if (!loadOnlySomeSpectra ||
-          (spectraLoadMap.find(it->first) != spectraLoadMap.end())) {
-        this->pixel_to_wkspindex[it->first] = workspaceIndex;
+          (spectraLoadMap.find(detIDs[i]) != spectraLoadMap.end())) {
+        this->pixel_to_wkspindex[detIDs[i]] = workspaceIndex;
         EventList &spec = workspace->getSpectrum(workspaceIndex);
-        spec.setDetectorID(it->first);
+        spec.setDetectorID(detIDs[i]);
         spec.setSpectrumNo(spectrumNumber);
         ++workspaceIndex;
       } else {
-        this->pixel_to_wkspindex[it->first] = -1;
+        this->pixel_to_wkspindex[detIDs[i]] = -1;
       }
       ++spectrumNumber;
     }
diff --git a/Framework/DataHandling/src/LoadFITS.cpp b/Framework/DataHandling/src/LoadFITS.cpp
index a941b625844d24513927862af2808607bd8c7576..f8ed6a97fd9dbdfe18e10a69c48d537a53898f60 100644
--- a/Framework/DataHandling/src/LoadFITS.cpp
+++ b/Framework/DataHandling/src/LoadFITS.cpp
@@ -4,6 +4,7 @@
 #include "MantidAPI/RegisterFileLoader.h"
 #include "MantidAPI/Run.h"
 #include "MantidAPI/WorkspaceFactory.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidDataHandling/LoadFITS.h"
 #include "MantidDataObjects/Workspace2D.h"
 #include "MantidKernel/BoundedValidator.h"
@@ -472,19 +473,17 @@ void LoadFITS::doLoadFiles(const std::vector<std::string> &paths,
 
   // Create a group for these new workspaces, if the group already exists, add
   // to it.
-  std::string groupName = outWSName;
-
   size_t fileNumberInGroup = 0;
   WorkspaceGroup_sptr wsGroup;
 
-  if (!AnalysisDataService::Instance().doesExist(groupName)) {
-    wsGroup = WorkspaceGroup_sptr(new WorkspaceGroup());
-    wsGroup->setTitle(groupName);
+  if (!AnalysisDataService::Instance().doesExist(outWSName)) {
+    wsGroup = boost::make_shared<WorkspaceGroup>();
+    wsGroup->setTitle(outWSName);
   } else {
     // Get the name of the latest file in group to start numbering from
-    if (AnalysisDataService::Instance().doesExist(groupName))
+    if (AnalysisDataService::Instance().doesExist(outWSName))
       wsGroup =
-          AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>(groupName);
+          AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>(outWSName);
 
     std::string latestName = wsGroup->getNames().back();
     // Set next file number
@@ -860,10 +859,10 @@ void LoadFITS::readDataToWorkspace(const FITSInfo &fileInfo, double cmpp,
 
   PARALLEL_FOR_NO_WSP_CHECK()
   for (int i = 0; i < static_cast<int>(nrows); ++i) {
-    auto &dataX = ws->dataX(i);
-    auto &dataY = ws->dataY(i);
-    auto &dataE = ws->dataE(i);
-    std::fill(dataX.begin(), dataX.end(), static_cast<double>(i) * cmpp);
+    auto &xVals = ws->mutableX(i);
+    auto &yVals = ws->mutableY(i);
+    auto &eVals = ws->mutableE(i);
+    xVals = static_cast<double>(i) * cmpp;
 
     for (size_t j = 0; j < ncols; ++j) {
       // Map from 2D->1D index
@@ -890,8 +889,8 @@ void LoadFITS::readDataToWorkspace(const FITSInfo &fileInfo, double cmpp,
       }
 
       val = fileInfo.scale * val - fileInfo.offset;
-      dataY[j] = val;
-      dataE[j] = sqrt(val);
+      yVals[j] = val;
+      eVals[j] = sqrt(val);
     }
   }
 }
diff --git a/Framework/DataHandling/src/LoadFullprofResolution.cpp b/Framework/DataHandling/src/LoadFullprofResolution.cpp
index 223b9c06882d84d3db837bc5703c7f96e2d9b10d..e2e3e810de2117f6d97e7ce20333189a4ff0edb5 100644
--- a/Framework/DataHandling/src/LoadFullprofResolution.cpp
+++ b/Framework/DataHandling/src/LoadFullprofResolution.cpp
@@ -3,6 +3,7 @@
 #include "MantidAPI/InstrumentDataService.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/TableRow.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidAPI/WorkspaceProperty.h"
 #include "MantidGeometry/Instrument.h"
 #include "MantidGeometry/Instrument/InstrumentDefinitionParser.h"
@@ -17,6 +18,7 @@
 #include <Poco/DOM/DOMWriter.h>
 #include <Poco/DOM/Element.h>
 #include <Poco/DOM/AutoPtr.h>
+#include <Poco/XML/XMLWriter.h>
 
 #include <fstream>
 
@@ -252,7 +254,7 @@ void LoadFullprofResolution::loadFile(string filename, vector<string> &lines) {
 
       // display the line we gathered:
       boost::algorithm::trim(line);
-      if (line.size() > 0)
+      if (!line.empty())
         lines.push_back(line);
     }
 
@@ -651,7 +653,7 @@ void LoadFullprofResolution::parseBankLine(string line, double &cwl,
                     << "'" << v[i] << "'\n";
       string candidate = v[i];
       boost::algorithm::trim(candidate);
-      if (candidate.size() > 0) {
+      if (!candidate.empty()) {
         cwl = atof(candidate.c_str());
         break;
       }
diff --git a/Framework/DataHandling/src/LoadGSASInstrumentFile.cpp b/Framework/DataHandling/src/LoadGSASInstrumentFile.cpp
index 74e8997744b26a8be6c2d3fb3d3108c872fd7066..239ea187ff49047152f221f36e53d16d585be4f9 100644
--- a/Framework/DataHandling/src/LoadGSASInstrumentFile.cpp
+++ b/Framework/DataHandling/src/LoadGSASInstrumentFile.cpp
@@ -3,6 +3,7 @@
 #include "MantidAPI/InstrumentDataService.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/TableRow.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidAPI/WorkspaceProperty.h"
 #include "MantidGeometry/Instrument.h"
 #include "MantidGeometry/Instrument/InstrumentDefinitionParser.h"
@@ -225,7 +226,7 @@ void LoadGSASInstrumentFile::loadFile(string filename, vector<string> &lines) {
 
       // display the line we gathered:
       boost::algorithm::trim(line);
-      if (line.size() > 0)
+      if (!line.empty())
         lines.push_back(line);
     }
 
diff --git a/Framework/DataHandling/src/LoadGSS.cpp b/Framework/DataHandling/src/LoadGSS.cpp
index c0568da204a1044a4ba54258e5b060fb7af40106..cca84ae9e67e0ccd021055d506dcb499f8daf465 100644
--- a/Framework/DataHandling/src/LoadGSS.cpp
+++ b/Framework/DataHandling/src/LoadGSS.cpp
@@ -22,6 +22,7 @@
 
 using namespace Mantid::DataHandling;
 using namespace Mantid::API;
+using namespace Mantid::HistogramData;
 using namespace Mantid::Kernel;
 
 namespace Mantid {
@@ -113,7 +114,10 @@ API::MatrixWorkspace_sptr LoadGSS::loadGSASFile(const std::string &filename,
   std::vector<int> detectorIDs;
 
   // Vectors to store data
-  std::vector<std::vector<double>> gsasDataX, gsasDataY, gsasDataE;
+  std::vector<HistogramData::BinEdges> gsasDataX;
+  std::vector<HistogramData::Counts> gsasDataY;
+  std::vector<HistogramData::CountStandardDeviations> gsasDataE;
+
   std::vector<double> vecX, vecY, vecE;
 
   // progress
@@ -251,16 +255,12 @@ API::MatrixWorkspace_sptr LoadGSS::loadGSASFile(const std::string &filename,
       // Line start with Bank including file format, X0 information and etc.
       isOutOfHead = true;
 
-      // If there is, Save the previous to array and initialze new MantiVec for
+      // If there is, Save the previous to array and initialize new MantiVec for
       // (X, Y, E)
       if (!vecX.empty()) {
-        std::vector<double> storeX = vecX;
-        std::vector<double> storeY = vecY;
-        std::vector<double> storeE = vecE;
-
-        gsasDataX.push_back(storeX);
-        gsasDataY.push_back(storeY);
-        gsasDataE.push_back(storeE);
+        gsasDataX.emplace_back(std::move(vecX));
+        gsasDataY.emplace_back(std::move(vecY));
+        gsasDataE.emplace_back(std::move(vecE));
         vecX.clear();
         vecY.clear();
         vecE.clear();
@@ -387,20 +387,26 @@ API::MatrixWorkspace_sptr LoadGSS::loadGSASFile(const std::string &filename,
       }
 
       // store read in data (x, y, e) to vector
-      vecX.push_back(xValue);
-      vecY.push_back(yValue);
-      vecE.push_back(eValue);
+      vecX.push_back(std::move(xValue));
+      vecY.push_back(std::move(yValue));
+      vecE.push_back(std::move(eValue));
     } // Date Line
     else {
       g_log.warning() << "Line not defined: " << currentLine << '\n';
     }
-  } // ENDWHILE of readling all lines
+  } // ENDWHILE of reading all lines
+
+  // Get the sizes before using std::move
+  int nHist(static_cast<int>(gsasDataX.size()));
+  int xWidth(static_cast<int>(vecX.size()));
+  int yWidth(static_cast<int>(vecY.size()));
 
   // Push the vectors (X, Y, E) of the last bank to gsasData
   if (!vecX.empty()) { // Put final spectra into data
-    gsasDataX.push_back(vecX);
-    gsasDataY.push_back(vecY);
-    gsasDataE.push_back(vecE);
+    gsasDataX.emplace_back(std::move(vecX));
+    gsasDataY.emplace_back(std::move(vecY));
+    gsasDataE.emplace_back(std::move(vecE));
+    ++nHist;
   }
   input.close();
 
@@ -409,9 +415,6 @@ API::MatrixWorkspace_sptr LoadGSS::loadGSASFile(const std::string &filename,
   //********************************************************************************************
 
   // Create workspace & GSS Files data is always in TOF
-  int nHist(static_cast<int>(gsasDataX.size()));
-  int xWidth(static_cast<int>(vecX.size()));
-  int yWidth(static_cast<int>(vecY.size()));
 
   MatrixWorkspace_sptr outputWorkspace =
       boost::dynamic_pointer_cast<MatrixWorkspace>(
@@ -425,7 +428,7 @@ API::MatrixWorkspace_sptr LoadGSS::loadGSASFile(const std::string &filename,
   else
     outputWorkspace->setTitle(slogTitle);
 
-  // put data from MatidVec's into outputWorkspace
+  // put data from constructed histograms into outputWorkspace
   if (detectorIDs.size() != static_cast<size_t>(nHist)) {
     // File error is found
     std::ostringstream mess("");
@@ -436,9 +439,9 @@ API::MatrixWorkspace_sptr LoadGSS::loadGSASFile(const std::string &filename,
 
   for (int i = 0; i < nHist; ++i) {
     // Move data across
-    outputWorkspace->dataX(i) = gsasDataX[i];
-    outputWorkspace->dataY(i) = gsasDataY[i];
-    outputWorkspace->dataE(i) = gsasDataE[i];
+    outputWorkspace->setHistogram(
+        i, BinEdges(std::move(gsasDataX[i])), Counts(std::move(gsasDataY[i])),
+        CountStandardDeviations(std::move(gsasDataE[i])));
 
     // Reset spectrum number if
     if (useBankAsSpectrum) {
@@ -506,7 +509,6 @@ void LoadGSS::createInstrumentGeometry(
   // Create a new instrument and set its name
   Geometry::Instrument_sptr instrument(
       new Geometry::Instrument(instrumentname));
-  workspace->setInstrument(instrument);
 
   // Add dummy source and samplepos to instrument
   Geometry::ObjComponent *samplepos =
@@ -554,6 +556,7 @@ void LoadGSS::createInstrumentGeometry(
     instrument->markAsDetector(detector);
 
   } // ENDFOR (i: spectrum)
+  workspace->setInstrument(instrument);
 }
 
 } // namespace
diff --git a/Framework/DataHandling/src/LoadHelper.cpp b/Framework/DataHandling/src/LoadHelper.cpp
index fc456db0ed416202d873c91264a429d94464ca8c..2b7a2dfe2fd6be5694e4432e8e19f4f1293518b0 100644
--- a/Framework/DataHandling/src/LoadHelper.cpp
+++ b/Framework/DataHandling/src/LoadHelper.cpp
@@ -6,6 +6,7 @@
 
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidGeometry/Instrument/ComponentHelper.h"
+#include "MantidKernel/PhysicalConstants.h"
 
 #include <nexus/napi.h>
 
diff --git a/Framework/DataHandling/src/LoadIDFFromNexus.cpp b/Framework/DataHandling/src/LoadIDFFromNexus.cpp
index 1cfc6d102c0e1e583a973f316f16be829f9be6be..ab9e7484b49498243529d3d619b5460b246b2643 100644
--- a/Framework/DataHandling/src/LoadIDFFromNexus.cpp
+++ b/Framework/DataHandling/src/LoadIDFFromNexus.cpp
@@ -1,11 +1,9 @@
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidDataHandling/LoadIDFFromNexus.h"
 #include "MantidAPI/FileProperty.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidGeometry/Instrument.h"
 #include "MantidKernel/ConfigService.h"
+#include "MantidKernel/Strings.h"
 
 #include <Poco/DOM/Document.h>
 #include <Poco/DOM/DOMParser.h>
diff --git a/Framework/DataHandling/src/LoadILL.cpp b/Framework/DataHandling/src/LoadILL.cpp
deleted file mode 100644
index 10544792be1eb34b7dbe9b81d8bd006edc8d63c6..0000000000000000000000000000000000000000
--- a/Framework/DataHandling/src/LoadILL.cpp
+++ /dev/null
@@ -1,29 +0,0 @@
-//---------------------------------------------------
-// Includes
-//---------------------------------------------------
-#include "MantidDataHandling/LoadILL.h"
-#include "MantidAPI/RegisterFileLoader.h"
-
-namespace Mantid {
-namespace DataHandling {
-
-DECLARE_NEXUS_FILELOADER_ALGORITHM(LoadILL)
-
-/// Constructor
-LoadILL::LoadILL() : LoadILLTOF() { this->useAlgorithm("LoadILLTOF", 1); }
-
-/**
- * Return the confidence with with this algorithm can load the file
- * @param descriptor A descriptor for the file
- * @returns An integer specifying the confidence level. 0 indicates it will not
- * be used
- */
-int LoadILL::confidence(Kernel::NexusDescriptor &descriptor) const {
-  // Suppress unused warning
-  (void)descriptor;
-  // Deprecated, always return 0
-  return 0;
-}
-
-} // namespace DataHandling
-} // namespace Mantid
diff --git a/Framework/DataHandling/src/LoadILLIndirect.cpp b/Framework/DataHandling/src/LoadILLIndirect.cpp
index b651948cf026ca70b4465d649ff4f7defec2ecdb..2c9a6fae6ff4343a411ade44d4ef7f1ab019c3b3 100644
--- a/Framework/DataHandling/src/LoadILLIndirect.cpp
+++ b/Framework/DataHandling/src/LoadILLIndirect.cpp
@@ -4,12 +4,14 @@
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/RegisterFileLoader.h"
 #include "MantidAPI/WorkspaceFactory.h"
+#include "MantidHistogramData/LinearGenerator.h"
 #include "MantidKernel/UnitFactory.h"
 #include "MantidGeometry/Instrument/ComponentHelper.h"
 
 #include <boost/algorithm/string.hpp>
 
 #include <nexus/napi.h>
+#include <numeric>
 
 namespace Mantid {
 namespace DataHandling {
@@ -46,7 +48,7 @@ const std::string LoadILLIndirect::category() const {
 //----------------------------------------------------------------------------------------------
 
 /**
-* Return the confidence with with this algorithm can load the file
+* Return the confidence with this algorithm can load the file
 * @param descriptor A descriptor for the file
 * @returns An integer specifying the confidence level. 0 indicates it will not
 * be used
@@ -64,7 +66,7 @@ int LoadILLIndirect::confidence(Kernel::NexusDescriptor &descriptor) const {
        (descriptor.pathExists("/entry0/instrument/Doppler/doppler_frequency") &&
         descriptor.pathExists("/entry0/dataSD/dataSD")) // IN16B old
        )) {
-    return 80;
+    return 70;
   } else {
     return 0;
   }
@@ -239,10 +241,6 @@ void LoadILLIndirect::loadDataIntoTheWorkSpace(
   // load the counts from the file into memory
   dataSD.load();
 
-  // Assign calculated bins to first X axis
-  ////  m_localWorkspace->dataX(0).assign(detectorTofBins.begin(),
-  /// detectorTofBins.end());
-
   size_t spec = 0;
   size_t nb_monitors = monitorsData.size();
   size_t nb_SD_detectors = dataSD.dim0();
@@ -250,22 +248,17 @@ void LoadILLIndirect::loadDataIntoTheWorkSpace(
   Progress progress(this, 0, 1, m_numberOfTubes * m_numberOfPixelsPerTube +
                                     nb_monitors + nb_SD_detectors);
 
-  // Assign fake values to first X axis <<to be completed>>
-  for (size_t i = 0; i <= m_numberOfChannels; ++i) {
-    m_localWorkspace->dataX(0)[i] = double(i);
-  }
+  // Assign fake values to first X axis
+  const HistogramData::BinEdges histoBinEdges(
+      m_numberOfChannels + 1, HistogramData::LinearGenerator(1.0, 1.0));
 
   // First, Monitor
   for (size_t im = 0; im < nb_monitors; im++) {
 
-    if (im > 0) {
-      m_localWorkspace->dataX(im) = m_localWorkspace->readX(0);
-    }
-
-    // Assign Y
     int *monitor_p = monitorsData[im].data();
-    m_localWorkspace->dataY(im)
-        .assign(monitor_p, monitor_p + m_numberOfChannels);
+    const HistogramData::Counts histoCounts(monitor_p,
+                                            monitor_p + m_numberOfChannels);
+    m_localWorkspace->setHistogram(im, histoBinEdges, std::move(histoCounts));
 
     progress.report();
   }
@@ -274,18 +267,12 @@ void LoadILLIndirect::loadDataIntoTheWorkSpace(
   for (size_t i = 0; i < m_numberOfTubes; ++i) {
     for (size_t j = 0; j < m_numberOfPixelsPerTube; ++j) {
 
-      // just copy the time binning axis to every spectra
-      m_localWorkspace->dataX(spec + nb_monitors) = m_localWorkspace->readX(0);
-
       // Assign Y
       int *data_p = &data(static_cast<int>(i), static_cast<int>(j), 0);
-      m_localWorkspace->dataY(spec + nb_monitors)
-          .assign(data_p, data_p + m_numberOfChannels);
-
-      // Assign Error
-      MantidVec &E = m_localWorkspace->dataE(spec + nb_monitors);
-      std::transform(data_p, data_p + m_numberOfChannels, E.begin(),
-                     LoadILLIndirect::calculateError);
+      const HistogramData::Counts histoCounts(data_p,
+                                              data_p + m_numberOfChannels);
+      m_localWorkspace->setHistogram((spec + nb_monitors), histoBinEdges,
+                                     std::move(histoCounts));
 
       ++spec;
       progress.report();
@@ -295,15 +282,16 @@ void LoadILLIndirect::loadDataIntoTheWorkSpace(
   // Then add Simple Detector (SD)
   for (int i = 0; i < dataSD.dim0(); ++i) {
 
-    // just copy again the time binning axis to every spectra
-    m_localWorkspace->dataX(spec + nb_monitors + i) =
-        m_localWorkspace->readX(0);
-
     // Assign Y
     int *dataSD_p = &dataSD(i, 0, 0);
-    m_localWorkspace->dataY(spec + nb_monitors + i)
-        .assign(dataSD_p, dataSD_p + m_numberOfChannels);
-
+    const HistogramData::Counts histoCounts(dataSD_p,
+                                            dataSD_p + m_numberOfChannels);
+    const HistogramData::CountStandardDeviations histoErrors(m_numberOfChannels,
+                                                             0.0);
+
+    m_localWorkspace->setHistogram((spec + nb_monitors + i), histoBinEdges,
+                                   std::move(histoCounts),
+                                   std::move(histoErrors));
     progress.report();
   }
 
diff --git a/Framework/DataHandling/src/LoadILLIndirect2.cpp b/Framework/DataHandling/src/LoadILLIndirect2.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..525d8f6a0be2690b2ddbf525c3b3eeb1429a54d0
--- /dev/null
+++ b/Framework/DataHandling/src/LoadILLIndirect2.cpp
@@ -0,0 +1,447 @@
+#include "MantidDataHandling/LoadILLIndirect2.h"
+#include "MantidAPI/Axis.h"
+#include "MantidAPI/FileProperty.h"
+#include "MantidAPI/MatrixWorkspace.h"
+#include "MantidAPI/RegisterFileLoader.h"
+#include "MantidAPI/WorkspaceFactory.h"
+#include "MantidGeometry/Instrument/ComponentHelper.h"
+#include "MantidKernel/UnitFactory.h"
+
+#include <boost/algorithm/string.hpp>
+#include <boost/format.hpp>
+
+#include <nexus/napi.h>
+
+namespace Mantid {
+namespace DataHandling {
+
+using namespace Kernel;
+using namespace API;
+using namespace NeXus;
+
+// Register the algorithm into the AlgorithmFactory
+DECLARE_NEXUS_FILELOADER_ALGORITHM(LoadILLIndirect2)
+
+//----------------------------------------------------------------------------------------------
+/** Constructor
+ */
+LoadILLIndirect2::LoadILLIndirect2()
+    : API::IFileLoader<Kernel::NexusDescriptor>(), m_numberOfTubes(0),
+      m_numberOfPixelsPerTube(0), m_numberOfChannels(0),
+      m_numberOfSimpleDetectors(0), m_numberOfHistograms(0),
+      m_numberOfMonitors(0) {
+  m_supportedInstruments.emplace_back("IN16B");
+}
+
+//----------------------------------------------------------------------------------------------
+/// Algorithm's name for identification. @see Algorithm::name
+const std::string LoadILLIndirect2::name() const { return "LoadILLIndirect"; }
+
+/// Algorithm's category for identification. @see Algorithm::category
+const std::string LoadILLIndirect2::category() const {
+  return "DataHandling\\Nexus";
+}
+
+//----------------------------------------------------------------------------------------------
+
+/**
+* Return the confidence with with this algorithm can load the file
+* @param descriptor A descriptor for the file
+* @returns An integer specifying the confidence level. 0 indicates it will not
+* be used
+*/
+int LoadILLIndirect2::confidence(Kernel::NexusDescriptor &descriptor) const {
+
+  // fields existent only at the ILL
+  if (descriptor.pathExists("/entry0/wavelength")               // ILL
+      && descriptor.pathExists("/entry0/experiment_identifier") // ILL
+      && descriptor.pathExists("/entry0/mode")                  // ILL
+      &&
+      ((descriptor.pathExists("/entry0/instrument/Doppler/mirror_sense") &&
+        descriptor.pathExists("/entry0/dataSD/SingleD_data")) // IN16B new
+       ||
+       (descriptor.pathExists("/entry0/instrument/Doppler/doppler_frequency") &&
+        descriptor.pathExists("/entry0/dataSD/dataSD")) // IN16B old
+       )) {
+    return 80;
+  } else {
+    return 0;
+  }
+}
+
+//----------------------------------------------------------------------------------------------
+/** Initialize the algorithm's properties.
+ */
+void LoadILLIndirect2::init() {
+  declareProperty(
+      make_unique<FileProperty>("Filename", "", FileProperty::Load, ".nxs"),
+      "File path of the Data file to load");
+
+  declareProperty(make_unique<WorkspaceProperty<>>("OutputWorkspace", "",
+                                                   Direction::Output),
+                  "The name to use for the output workspace");
+}
+
+//----------------------------------------------------------------------------------------------
+/** Execute the algorithm.
+ */
+void LoadILLIndirect2::exec() {
+
+  // Retrieve filename
+  std::string filenameData = getPropertyValue("Filename");
+
+  // open the root node
+  NeXus::NXRoot dataRoot(filenameData);
+  NXEntry firstEntry = dataRoot.openFirstEntry();
+
+  // Load Monitor details: n. monitors x monitor contents
+  std::vector<std::vector<int>> monitorsData = loadMonitors(firstEntry);
+
+  // Load Data details (number of tubes, channels, etc)
+  loadDataDetails(firstEntry);
+
+  std::string instrumentPath = m_loader.findInstrumentNexusPath(firstEntry);
+  setInstrumentName(firstEntry, instrumentPath);
+
+  initWorkSpace(firstEntry, monitorsData);
+
+  g_log.debug("Building properties...");
+  loadNexusEntriesIntoProperties(filenameData);
+
+  g_log.debug("Loading data...");
+  loadDataIntoTheWorkSpace(firstEntry, monitorsData);
+
+  // load the instrument from the IDF if it exists
+  g_log.debug("Loading instrument definition...");
+  runLoadInstrument();
+
+  g_log.debug("Movind SDs...");
+  moveSingleDetectors(firstEntry);
+
+  // Set the output workspace property
+  setProperty("OutputWorkspace", m_localWorkspace);
+}
+
+/**
+* Set member variable with the instrument name
+*/
+void LoadILLIndirect2::setInstrumentName(
+    const NeXus::NXEntry &firstEntry, const std::string &instrumentNamePath) {
+
+  if (instrumentNamePath == "") {
+    std::string message("Cannot set the instrument name from the Nexus file!");
+    g_log.error(message);
+    throw std::runtime_error(message);
+  }
+  m_instrumentName =
+      m_loader.getStringFromNexusPath(firstEntry, instrumentNamePath + "/name");
+  boost::to_upper(m_instrumentName); // "IN16b" in file, keep it upper case.
+  g_log.debug() << "Instrument name set to: " + m_instrumentName << '\n';
+}
+
+/**
+* Load Data details (number of tubes, channels, etc)
+* @param entry First entry of nexus file
+*/
+void LoadILLIndirect2::loadDataDetails(NeXus::NXEntry &entry) {
+  // read in the data
+  NXData dataGroup = entry.openNXData("data");
+  NXInt data = dataGroup.openIntData();
+
+  m_numberOfTubes = static_cast<size_t>(data.dim0());
+  m_numberOfPixelsPerTube = static_cast<size_t>(data.dim1());
+  m_numberOfChannels = static_cast<size_t>(data.dim2());
+
+  // check which single detectors are enabled, and store their indices
+  NXData dataSDGroup = entry.openNXData("dataSD");
+  NXInt dataSD = dataSDGroup.openIntData();
+
+  for (int i = 1; i <= dataSD.dim0(); ++i) {
+    try {
+      std::string entryNameFlagSD =
+          boost::str(boost::format("instrument/SingleD/tubes%i_function") % i);
+      NXFloat flagSD = entry.openNXFloat(entryNameFlagSD);
+      flagSD.load();
+
+      if (flagSD[0] == 1.0) // is enabled
+      {
+        m_activeSDIndices.insert(i);
+      }
+    } catch (...) {
+      // if the flags are not present in the file (e.g. old format), load all
+      m_activeSDIndices.insert(i);
+    }
+  }
+
+  m_numberOfSimpleDetectors = m_activeSDIndices.size();
+
+  g_log.information() << "Number of activated single detectors is: "
+                      << m_numberOfSimpleDetectors << std::endl;
+}
+
+/**
+   * Load monitors data found in nexus file
+   *
+   * @param entry :: The Nexus entry
+   *
+   */
+std::vector<std::vector<int>>
+LoadILLIndirect2::loadMonitors(NeXus::NXEntry &entry) {
+  // read in the data
+  g_log.debug("Fetching monitor data...");
+
+  NXData dataGroup = entry.openNXData("monitor/data");
+  NXInt data = dataGroup.openIntData();
+  // load the counts from the file into memory
+  data.load();
+
+  // For the moment, we are aware of only one monitor entry, but we keep the
+  // generalized case of n monitors
+
+  std::vector<std::vector<int>> monitors(1);
+  std::vector<int> monitor(data(), data() + data.size());
+  monitors[0].swap(monitor);
+  m_numberOfMonitors = monitors.size();
+  return monitors;
+}
+
+/**
+   * Creates the workspace and initialises member variables with
+   * the corresponding values
+   *
+   * @param entry :: The Nexus entry
+   * @param monitorsData :: Monitors data already loaded
+   *
+   */
+void LoadILLIndirect2::initWorkSpace(
+    NeXus::NXEntry & /*entry*/, std::vector<std::vector<int>> monitorsData) {
+
+  // dim0 * m_numberOfPixelsPerTube is the total number of detectors
+  m_numberOfHistograms = m_numberOfTubes * m_numberOfPixelsPerTube;
+
+  g_log.debug() << "NumberOfTubes: " << m_numberOfTubes << '\n';
+  g_log.debug() << "NumberOfPixelsPerTube: " << m_numberOfPixelsPerTube << '\n';
+  g_log.debug() << "NumberOfChannels: " << m_numberOfChannels << '\n';
+  g_log.debug() << "NumberOfSimpleDetectors: " << m_numberOfSimpleDetectors
+                << '\n';
+  g_log.debug() << "Monitors: " << monitorsData.size() << '\n';
+  g_log.debug() << "Monitors[0]: " << monitorsData[0].size() << '\n';
+
+  // Now create the output workspace
+
+  m_localWorkspace = WorkspaceFactory::Instance().create(
+      "Workspace2D",
+      m_numberOfHistograms + monitorsData.size() + m_numberOfSimpleDetectors,
+      m_numberOfChannels + 1, m_numberOfChannels);
+
+  m_localWorkspace->getAxis(0)->unit() =
+      UnitFactory::Instance().create("Empty");
+
+  m_localWorkspace->setYUnitLabel("Counts");
+}
+
+/**
+   * Load data found in nexus file
+   *
+   * @param entry :: The Nexus entry
+   * @param monitorsData :: Monitors data already loaded
+   *
+   */
+void LoadILLIndirect2::loadDataIntoTheWorkSpace(
+    NeXus::NXEntry &entry, std::vector<std::vector<int>> monitorsData) {
+
+  // read in the data
+  NXData dataGroup = entry.openNXData("data");
+  NXInt data = dataGroup.openIntData();
+  // load the counts from the file into memory
+  data.load();
+
+  // Same for Simple Detectors
+  NXData dataSDGroup = entry.openNXData("dataSD");
+  NXInt dataSD = dataSDGroup.openIntData();
+  // load the counts from the file into memory
+  dataSD.load();
+
+  // Assign calculated bins to first X axis
+  ////  m_localWorkspace->dataX(0).assign(detectorTofBins.begin(),
+  /// detectorTofBins.end());
+
+  size_t spec = 0;
+
+  Progress progress(this, 0, 1, m_numberOfTubes * m_numberOfPixelsPerTube +
+                                    m_numberOfMonitors +
+                                    m_numberOfSimpleDetectors);
+
+  // Assign fake values to first X axis <<to be completed>>
+  for (size_t i = 0; i <= m_numberOfChannels; ++i) {
+    m_localWorkspace->dataX(0)[i] = double(i);
+  }
+
+  // First, Monitor
+  for (size_t im = 0; im < m_numberOfMonitors; im++) {
+
+    if (im > 0) {
+      m_localWorkspace->dataX(im) = m_localWorkspace->readX(0);
+    }
+
+    // Assign Y
+    int *monitor_p = monitorsData[im].data();
+    m_localWorkspace->dataY(im)
+        .assign(monitor_p, monitor_p + m_numberOfChannels);
+
+    // Assign Error
+    MantidVec &E = m_localWorkspace->dataE(im);
+    std::transform(monitor_p, monitor_p + m_numberOfChannels, E.begin(),
+                   LoadILLIndirect2::calculateError);
+
+    progress.report();
+  }
+
+  // Then Tubes
+  for (size_t i = 0; i < m_numberOfTubes; ++i) {
+    for (size_t j = 0; j < m_numberOfPixelsPerTube; ++j) {
+
+      // just copy the time binning axis to every spectra
+      m_localWorkspace->dataX(spec + m_numberOfMonitors) =
+          m_localWorkspace->readX(0);
+
+      // Assign Y
+      int *data_p = &data(static_cast<int>(i), static_cast<int>(j), 0);
+      m_localWorkspace->dataY(spec + m_numberOfMonitors)
+          .assign(data_p, data_p + m_numberOfChannels);
+
+      // Assign Error
+      MantidVec &E = m_localWorkspace->dataE(spec + m_numberOfMonitors);
+      std::transform(data_p, data_p + m_numberOfChannels, E.begin(),
+                     LoadILLIndirect2::calculateError);
+
+      ++spec;
+      progress.report();
+    }
+  } // for m_numberOfTubes
+
+  // Then add Simple Detector (SD)
+  size_t offset = 0;
+  for (auto &index : m_activeSDIndices) {
+    // just copy again the time binning axis to every spectra
+    m_localWorkspace->dataX(spec + m_numberOfMonitors + offset) =
+        m_localWorkspace->readX(0);
+
+    // Assign Y, note that index starts from 1
+    int *dataSD_p = &dataSD(index - 1, 0, 0);
+    m_localWorkspace->dataY(spec + m_numberOfMonitors + offset)
+        .assign(dataSD_p, dataSD_p + m_numberOfChannels);
+
+    // Assign Error
+    MantidVec &E = m_localWorkspace->dataE(spec + m_numberOfMonitors + offset);
+    std::transform(dataSD_p, dataSD_p + m_numberOfChannels, E.begin(),
+                   LoadILLIndirect2::calculateError);
+
+    progress.report();
+    ++offset;
+  }
+
+} // LoadILLIndirect::loadDataIntoTheWorkSpace
+
+void LoadILLIndirect2::loadNexusEntriesIntoProperties(
+    std::string nexusfilename) {
+
+  API::Run &runDetails = m_localWorkspace->mutableRun();
+
+  // Open NeXus file
+  NXhandle nxfileID;
+  NXstatus stat = NXopen(nexusfilename.c_str(), NXACC_READ, &nxfileID);
+
+  if (stat == NX_ERROR) {
+    g_log.debug() << "convertNexusToProperties: Error loading "
+                  << nexusfilename;
+    throw Kernel::Exception::FileError("Unable to open File:", nexusfilename);
+  }
+  m_loader.addNexusFieldsToWsRun(nxfileID, runDetails);
+
+  // Add also "Facility", as asked
+  runDetails.addProperty("Facility", std::string("ILL"));
+
+  stat = NXclose(&nxfileID);
+}
+
+/**
+   * Run the Child Algorithm LoadInstrument.
+   */
+void LoadILLIndirect2::runLoadInstrument() {
+
+  IAlgorithm_sptr loadInst = createChildAlgorithm("LoadInstrument");
+
+  // Now execute the Child Algorithm. Catch and log any error, but don't stop.
+  try {
+    loadInst->setPropertyValue("InstrumentName", m_instrumentName);
+    loadInst->setProperty<MatrixWorkspace_sptr>("Workspace", m_localWorkspace);
+    loadInst->setProperty("RewriteSpectraMap",
+                          Mantid::Kernel::OptionalBool(true));
+    loadInst->execute();
+
+  } catch (...) {
+    g_log.information("Cannot load the instrument definition.");
+  }
+}
+
+void LoadILLIndirect2::moveComponent(const std::string &componentName,
+                                     double twoTheta) {
+
+  try {
+
+    Geometry::Instrument_const_sptr instrument =
+        m_localWorkspace->getInstrument();
+    Geometry::IComponent_const_sptr component =
+        instrument->getComponentByName(componentName);
+
+    double r, theta, phi;
+    V3D oldPos = component->getPos();
+    oldPos.getSpherical(r, theta, phi);
+
+    V3D newPos;
+    newPos.spherical(r, twoTheta, phi);
+
+    g_log.debug() << componentName << " : t = " << theta
+                  << " ==> t = " << twoTheta << "\n";
+    Geometry::ParameterMap &pmap = m_localWorkspace->instrumentParameters();
+    Geometry::ComponentHelper::moveComponent(
+        *component, pmap, newPos, Geometry::ComponentHelper::Absolute);
+
+  } catch (Mantid::Kernel::Exception::NotFoundError &) {
+    throw std::runtime_error("Error when trying to move the " + componentName +
+                             " : NotFoundError");
+  } catch (std::runtime_error &) {
+    throw std::runtime_error("Error when trying to move the " + componentName +
+                             " : runtime_error");
+  }
+}
+
+/**
+ * IN16B has a few single detectors that are place around the sample.
+ * They are moved according to some values in the nexus file.
+ */
+void LoadILLIndirect2::moveSingleDetectors(NeXus::NXEntry &entry) {
+
+  std::string prefix("single_tube_");
+
+  int index = 1;
+
+  for (auto i : m_activeSDIndices) {
+
+    std::string angleEntry =
+        boost::str(boost::format("instrument/SingleD/SD%i angle") % i);
+
+    NXFloat angleSD = entry.openNXFloat(angleEntry);
+
+    angleSD.load();
+
+    g_log.debug("Moving single detector " + std::to_string(i) + " to t=" +
+                std::to_string(angleSD[0]));
+    moveComponent(prefix + std::to_string(index), angleSD[0]);
+    index++;
+  }
+}
+
+} // namespace DataHandling
+} // namespace Mantid
diff --git a/Framework/DataHandling/src/LoadILLReflectometry.cpp b/Framework/DataHandling/src/LoadILLReflectometry.cpp
index 764704f022cec96af309759aaadb7a01f5ff4ee0..b41993fa16422c1b0ae64f52e68b3c16179834c2 100644
--- a/Framework/DataHandling/src/LoadILLReflectometry.cpp
+++ b/Framework/DataHandling/src/LoadILLReflectometry.cpp
@@ -52,7 +52,7 @@ const std::string LoadILLReflectometry::category() const {
 }
 
 /**
- * Return the confidence with with this algorithm can load the file
+ * Return the confidence with this algorithm can load the file
  * @param descriptor A descriptor for the file
  * @returns An integer specifying the confidence level. 0 indicates it will not
  * be used
@@ -285,10 +285,6 @@ void LoadILLReflectometry::loadDataIntoTheWorkSpace(
   // load the counts from the file into memory
   data.load();
 
-  // Assign calculated bins to first X axis
-  ////  m_localWorkspace->dataX(0).assign(detectorTofBins.begin(),
-  /// detectorTofBins.end());
-
   size_t spec = 0;
   size_t nb_monitors = monitorsData.size();
 
@@ -368,50 +364,44 @@ void LoadILLReflectometry::loadDataIntoTheWorkSpace(
   }
   g_log.debug() << "t_TOF2: " << t_TOF2 << '\n';
 
+  std::vector<double> tofVals;
+  tofVals.reserve(m_localWorkspace->x(0).size());
+
   // 2) Compute tof values
   for (size_t timechannelnumber = 0; timechannelnumber <= m_numberOfChannels;
        ++timechannelnumber) {
     double t_TOF1 =
         (static_cast<int>(timechannelnumber) + 0.5) * m_channelWidth +
         tof_delay;
-    m_localWorkspace->dataX(0)[timechannelnumber] = t_TOF1 + t_TOF2;
+    tofVals.push_back(t_TOF1 + t_TOF2);
   }
 
+  HistogramData::BinEdges binEdges(tofVals);
+
   // Load monitors
   for (size_t im = 0; im < nb_monitors; im++) {
-    if (im > 0) {
-      m_localWorkspace->dataX(im) = m_localWorkspace->readX(0);
-    }
-
-    // Assign Y
     int *monitor_p = monitorsData[im].data();
-    m_localWorkspace->dataY(im)
-        .assign(monitor_p, monitor_p + m_numberOfChannels);
+    const HistogramData::Counts histoCounts(monitor_p,
+                                            monitor_p + m_numberOfChannels);
+    const HistogramData::CountStandardDeviations histoBlankError(
+        monitorsData[im].size(), 0.0);
+    m_localWorkspace->setHistogram(im, binEdges, std::move(histoCounts),
+                                   std::move(histoBlankError));
 
     progress.report();
   }
 
-  // Then Tubes
   for (size_t i = 0; i < m_numberOfTubes; ++i) {
     for (size_t j = 0; j < m_numberOfPixelsPerTube; ++j) {
-
-      // just copy the time binning axis to every spectra
-      m_localWorkspace->dataX(spec + nb_monitors) = m_localWorkspace->readX(0);
-
-      //// Assign Y
       int *data_p = &data(static_cast<int>(i), static_cast<int>(j), 0);
-      m_localWorkspace->dataY(spec + nb_monitors)
-          .assign(data_p, data_p + m_numberOfChannels);
-
-      // Assign Error
-      MantidVec &E = m_localWorkspace->dataE(spec + nb_monitors);
-      std::transform(data_p, data_p + m_numberOfChannels, E.begin(),
-                     LoadHelper::calculateStandardError);
-
+      const HistogramData::Counts histoCounts(data_p,
+                                              data_p + m_numberOfChannels);
+      m_localWorkspace->setHistogram((spec + nb_monitors), binEdges,
+                                     std::move(histoCounts));
       ++spec;
       progress.report();
     }
-  } // for m_numberOfTubes
+  }
 
 } // LoadILLIndirect::loadDataIntoTheWorkSpace
 
diff --git a/Framework/DataHandling/src/LoadILLSANS.cpp b/Framework/DataHandling/src/LoadILLSANS.cpp
index d3f787b171862dacf76e1cd38f8c36269851ddc8..92442adb891539eb30e0aee63a37abf52e3a5db3 100644
--- a/Framework/DataHandling/src/LoadILLSANS.cpp
+++ b/Framework/DataHandling/src/LoadILLSANS.cpp
@@ -3,7 +3,9 @@
 #include "MantidAPI/FileProperty.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/RegisterFileLoader.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidAPI/WorkspaceFactory.h"
+#include "MantidHistogramData/LinearGenerator.h"
 #include "MantidGeometry/Instrument.h"
 #include "MantidGeometry/IDetector.h"
 #include "MantidKernel/UnitFactory.h"
@@ -252,18 +254,12 @@ LoadILLSANS::loadDataIntoWorkspaceFromMonitors(NeXus::NXEntry &firstEntry,
       std::vector<double> positionsBinning;
       positionsBinning.reserve(vectorSize);
 
-      for (size_t i = 0; i < vectorSize; i++)
-        positionsBinning.push_back(static_cast<double>(i));
+      const HistogramData::BinEdges histoBinEdges(
+          vectorSize, HistogramData::LinearGenerator(0.0, 1.0));
+      const HistogramData::Counts histoCounts(data(), data() + data.dim2());
 
-      // Assign X
-      m_localWorkspace->dataX(firstIndex)
-          .assign(positionsBinning.begin(), positionsBinning.end());
-      // Assign Y
-      m_localWorkspace->dataY(firstIndex).assign(data(), data() + data.dim2());
-      // Assign Error
-      MantidVec &E = m_localWorkspace->dataE(firstIndex);
-      std::transform(data(), data() + data.dim2(), E.begin(),
-                     LoadHelper::calculateStandardError);
+      m_localWorkspace->setHistogram(firstIndex, std::move(histoBinEdges),
+                                     std::move(histoCounts));
 
       // Add average monitor counts to a property:
       double averageMonitorCounts =
@@ -298,30 +294,20 @@ size_t LoadILLSANS::loadDataIntoWorkspaceFromHorizontalTubes(
                 << "First bin = " << timeBinning[0] << '\n';
 
   // Workaround to get the number of tubes / pixels
-  size_t numberOfTubes = data.dim1();
-  size_t numberOfPixelsPerTube = data.dim0();
+  const size_t numberOfTubes = data.dim1();
+  const size_t numberOfPixelsPerTube = data.dim0();
 
   Progress progress(this, 0, 1, data.dim0() * data.dim1());
 
-  m_localWorkspace->dataX(firstIndex)
-      .assign(timeBinning.begin(), timeBinning.end());
-
   size_t spec = firstIndex;
-  for (size_t i = 0; i < numberOfTubes; ++i) { // iterate tubes
-    for (size_t j = 0; j < numberOfPixelsPerTube;
-         ++j) { // iterate pixels in the tube 256
-      if (spec > firstIndex) {
-        // just copy the time binning axis to every spectra
-        m_localWorkspace->dataX(spec) = m_localWorkspace->readX(firstIndex);
-      }
-      // Assign Y
-      int *data_p = &data(static_cast<int>(j), static_cast<int>(i), 0);
-      m_localWorkspace->dataY(spec).assign(data_p, data_p + data.dim2());
 
-      // Assign Error
-      MantidVec &E = m_localWorkspace->dataE(spec);
-      std::transform(data_p, data_p + data.dim2(), E.begin(),
-                     LoadHelper::calculateStandardError);
+  const HistogramData::BinEdges binEdges(timeBinning);
+
+  for (size_t i = 0; i < numberOfTubes; ++i) {
+    for (size_t j = 0; j < numberOfPixelsPerTube; ++j) {
+      int *data_p = &data(static_cast<int>(j), static_cast<int>(i), 0);
+      const HistogramData::Counts histoCounts(data_p, data_p + data.dim2());
+      m_localWorkspace->setHistogram(spec, binEdges, std::move(histoCounts));
 
       ++spec;
       progress.report();
@@ -350,31 +336,20 @@ size_t LoadILLSANS::loadDataIntoWorkspaceFromVerticalTubes(
                 << "First bin = " << timeBinning[0] << '\n';
 
   // Workaround to get the number of tubes / pixels
-  size_t numberOfTubes = data.dim0();
-  size_t numberOfPixelsPerTube = data.dim1();
+  const size_t numberOfTubes = data.dim0();
+  const size_t numberOfPixelsPerTube = data.dim1();
 
   Progress progress(this, 0, 1, data.dim0() * data.dim1());
 
-  m_localWorkspace->dataX(firstIndex)
-      .assign(timeBinning.begin(), timeBinning.end());
-
+  const HistogramData::BinEdges binEdges(timeBinning);
   size_t spec = firstIndex;
-  for (size_t i = 0; i < numberOfTubes; ++i) { // iterate tubes
-    for (size_t j = 0; j < numberOfPixelsPerTube;
-         ++j) { // iterate pixels in the tube 256
-      if (spec > firstIndex) {
-        // just copy the time binning axis to every spectra
-        m_localWorkspace->dataX(spec) = m_localWorkspace->readX(firstIndex);
-      }
-      // Assign Y
-      int *data_p = &data(static_cast<int>(i), static_cast<int>(j), 0);
-      m_localWorkspace->dataY(spec).assign(data_p, data_p + data.dim2());
 
-      // Assign Error
-      MantidVec &E = m_localWorkspace->dataE(spec);
-      std::transform(data_p, data_p + data.dim2(), E.begin(),
-                     LoadHelper::calculateStandardError);
+  for (size_t i = 0; i < numberOfTubes; ++i) {
+    for (size_t j = 0; j < numberOfPixelsPerTube; ++j) {
+      int *data_p = &data(static_cast<int>(i), static_cast<int>(j), 0);
+      const HistogramData::Counts histoCounts(data_p, data_p + data.dim2());
 
+      m_localWorkspace->setHistogram(spec, binEdges, std::move(histoCounts));
       ++spec;
       progress.report();
     }
@@ -570,14 +545,6 @@ void LoadILLSANS::loadMetaData(const NeXus::NXEntry &entry,
     m_defaultBinning[0] = wavelength - wavelengthRes * wavelength * 0.01 / 2;
     m_defaultBinning[1] = wavelength + wavelengthRes * wavelength * 0.01 / 2;
   }
-
-  // Put the detector distances:
-  //	std::string detectorPath(instrumentNamePath + "/detector");
-  //	// Just for Sample - RearDetector
-  //	double sampleDetectorDistance =
-  // m_loader.getDoubleFromNexusPath(entry,detectorPath + "/det2_calc");
-  //	runDetails.addProperty("sample_detector_distance",
-  // sampleDetectorDistance);
 }
 
 /**
@@ -594,18 +561,15 @@ std::pair<double, double> LoadILLSANS::calculateQMaxQMin() {
          max = std::numeric_limits<double>::min();
   g_log.debug("Calculating Qmin Qmax...");
   std::size_t nHist = m_localWorkspace->getNumberHistograms();
+  const auto &spectrumInfo = m_localWorkspace->spectrumInfo();
   for (std::size_t i = 0; i < nHist; ++i) {
-    Geometry::IDetector_const_sptr det = m_localWorkspace->getDetector(i);
-    if (!det->isMonitor()) {
-      const MantidVec &lambdaBinning = m_localWorkspace->readX(i);
-      Kernel::V3D detPos = det->getPos();
+    if (!spectrumInfo.isMonitor(i)) {
+      const auto &lambdaBinning = m_localWorkspace->x(i);
+      Kernel::V3D detPos = spectrumInfo.position(i);
       double r, theta, phi;
       detPos.getSpherical(r, theta, phi);
       double v1 = calculateQ(*(lambdaBinning.begin()), theta);
       double v2 = calculateQ(*(lambdaBinning.end() - 1), theta);
-      // std::cout << "i=" << i << " theta="<<theta << " lambda_i=" <<
-      // *(lambdaBinning.begin()) << " lambda_f=" << *(lambdaBinning.end()-1) <<
-      // " v1=" << v1 << " v2=" << v2 << '\n';
       if (i == 0) {
         min = v1;
         max = v1;
@@ -623,7 +587,8 @@ std::pair<double, double> LoadILLSANS::calculateQMaxQMin() {
         max = v2;
       }
     } else
-      g_log.debug() << "Detector " << i << " is a Monitor : " << det->getID()
+      g_log.debug() << "Detector " << i
+                    << " is a Monitor : " << spectrumInfo.detector(i).getID()
                     << '\n';
   }
 
diff --git a/Framework/DataHandling/src/LoadILLTOF.cpp b/Framework/DataHandling/src/LoadILLTOF.cpp
index f4206f45d1f72738fa10094dcd9965e126dec556..a9c2ab8386e30c0ff4f07cd7577fac077a016167 100644
--- a/Framework/DataHandling/src/LoadILLTOF.cpp
+++ b/Framework/DataHandling/src/LoadILLTOF.cpp
@@ -1,6 +1,3 @@
-//---------------------------------------------------
-// Includes
-//---------------------------------------------------
 #include "MantidDataHandling/LoadILLTOF.h"
 
 #include "MantidAPI/Axis.h"
@@ -11,6 +8,8 @@
 #include "MantidGeometry/Instrument.h"
 #include "MantidKernel/UnitFactory.h"
 
+#include <boost/algorithm/string/predicate.hpp>
+
 namespace Mantid {
 namespace DataHandling {
 
@@ -21,10 +20,6 @@ using namespace HistogramData;
 
 DECLARE_NEXUS_FILELOADER_ALGORITHM(LoadILLTOF)
 
-//---------------------------------------------------
-// Private member functions
-//---------------------------------------------------
-
 /**
  * Return the confidence with with this algorithm can load the file
  * @param descriptor A descriptor for the file
@@ -32,25 +27,13 @@ DECLARE_NEXUS_FILELOADER_ALGORITHM(LoadILLTOF)
  * be used
  */
 int LoadILLTOF::confidence(Kernel::NexusDescriptor &descriptor) const {
-
-  // fields existent only at the ILL
-  if (descriptor.pathExists("/entry0/wavelength") &&
-      descriptor.pathExists("/entry0/experiment_identifier") &&
-      descriptor.pathExists("/entry0/mode") &&
-      !descriptor.pathExists(
-          "/entry0/dataSD") // This one is for LoadILLIndirect
-      &&
-      !descriptor.pathExists(
-          "/entry0/instrument/VirtualChopper") // This one is for
-                                               // LoadILLReflectometry
-      ) {
-    return 80;
-  } else {
-    return 0;
-  }
+  UNUSED_ARG(descriptor)
+  // This loader is deprecated.
+  return 0;
 }
 
 LoadILLTOF::LoadILLTOF() : API::IFileLoader<Kernel::NexusDescriptor>() {
+  useAlgorithm("LoadILLTOF", 2);
   m_instrumentName = "";
   m_wavelength = 0;
   m_channelWidth = 0;
diff --git a/Framework/DataHandling/src/LoadILLTOF2.cpp b/Framework/DataHandling/src/LoadILLTOF2.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b033803f6ecf454183203260ae8d68fa35af7d4c
--- /dev/null
+++ b/Framework/DataHandling/src/LoadILLTOF2.cpp
@@ -0,0 +1,446 @@
+#include "MantidDataHandling/LoadILLTOF2.h"
+
+#include "MantidAPI/Axis.h"
+#include "MantidAPI/FileProperty.h"
+#include "MantidAPI/MatrixWorkspace.h"
+#include "MantidAPI/RegisterFileLoader.h"
+#include "MantidAPI/WorkspaceFactory.h"
+#include "MantidGeometry/Instrument.h"
+#include "MantidKernel/UnitFactory.h"
+
+#include <boost/algorithm/string/predicate.hpp>
+
+namespace Mantid {
+namespace DataHandling {
+
+using namespace Kernel;
+using namespace API;
+using namespace NeXus;
+using namespace HistogramData;
+
+DECLARE_NEXUS_FILELOADER_ALGORITHM(LoadILLTOF2)
+
+/// A vector containing the supported instrument names
+const std::vector<std::string> LoadILLTOF2::SUPPORTED_INSTRUMENTS = {
+    "IN4", "IN5", "IN6"};
+
+/**
+ * Return the confidence with with this algorithm can load the file
+ *
+ * @param descriptor A descriptor for the file
+ *
+ * @return An integer specifying the confidence level. 0 indicates it will not
+ * be used
+ */
+int LoadILLTOF2::confidence(Kernel::NexusDescriptor &descriptor) const {
+
+  // fields existent only at the ILL
+  if (descriptor.pathExists("/entry0/wavelength") &&
+      descriptor.pathExists("/entry0/experiment_identifier") &&
+      descriptor.pathExists("/entry0/mode") &&
+      !descriptor.pathExists(
+          "/entry0/dataSD") // This one is for LoadILLIndirect
+      &&
+      !descriptor.pathExists(
+          "/entry0/instrument/VirtualChopper") // This one is for
+                                               // LoadILLReflectometry
+      ) {
+    return 80;
+  } else {
+    return 0;
+  }
+}
+
+LoadILLTOF2::LoadILLTOF2() : API::IFileLoader<Kernel::NexusDescriptor>() {}
+
+/**
+ * Initialises the algorithm
+ */
+void LoadILLTOF2::init() {
+  declareProperty(
+      make_unique<FileProperty>("Filename", "", FileProperty::Load, ".nxs"),
+      "File path of the Data file to load");
+
+  declareProperty(make_unique<WorkspaceProperty<>>("OutputWorkspace", "",
+                                                   Direction::Output),
+                  "The name to use for the output workspace");
+}
+
+/**
+ * Executes the algorithm
+ */
+void LoadILLTOF2::exec() {
+  // Retrieve filename
+  const std::string filenameData = getPropertyValue("Filename");
+
+  // open the root node
+  NeXus::NXRoot dataRoot(filenameData);
+  NXEntry dataFirstEntry = dataRoot.openFirstEntry();
+
+  loadInstrumentDetails(dataFirstEntry);
+  loadTimeDetails(dataFirstEntry);
+
+  const auto monitors = getMonitorInfo(dataFirstEntry);
+
+  initWorkSpace(dataFirstEntry, monitors);
+
+  addAllNexusFieldsAsProperties(filenameData);
+  addFacility();
+
+  runLoadInstrument(); // just to get IDF contents
+
+  loadDataIntoTheWorkSpace(dataFirstEntry, monitors);
+
+  addEnergyToRun();
+  addPulseInterval();
+
+  // load the instrument from the IDF if it exists
+  runLoadInstrument();
+
+  // Set the output workspace property
+  setProperty("OutputWorkspace", m_localWorkspace);
+}
+
+/**
+ * Loads Monitor data into an vector of monitor data
+ *
+ * @param firstEntry The NeXus entry
+ *
+ * @return List of monitor data
+ */
+std::vector<std::vector<int>>
+LoadILLTOF2::getMonitorInfo(NeXus::NXEntry &firstEntry) {
+
+  std::vector<std::vector<int>> monitorList;
+
+  for (std::vector<NXClassInfo>::const_iterator it =
+           firstEntry.groups().begin();
+       it != firstEntry.groups().end(); ++it) {
+
+    if (it->nxclass == "NXmonitor" ||
+        boost::starts_with(it->nxname, "monitor")) {
+
+      g_log.debug() << "Load monitor data from " + it->nxname;
+
+      NXData dataGroup = firstEntry.openNXData(it->nxname + "/data");
+      NXInt data = dataGroup.openIntData();
+      // load the counts from the file into memory
+      data.load();
+
+      std::vector<int> thisMonitor(data(), data() + data.size());
+      monitorList.push_back(thisMonitor);
+    }
+  }
+  return monitorList;
+}
+
+/**
+ * Sets the instrument name along with its path in the nexus file
+ *
+ * @param firstEntry The NeXus entry
+ */
+void LoadILLTOF2::loadInstrumentDetails(NeXus::NXEntry &firstEntry) {
+
+  m_instrumentPath = m_loader.findInstrumentNexusPath(firstEntry);
+
+  if (m_instrumentPath == "") {
+    throw std::runtime_error(
+        "Cannot set the instrument name from the Nexus file!");
+  }
+
+  m_instrumentName =
+      m_loader.getStringFromNexusPath(firstEntry, m_instrumentPath + "/name");
+
+  if (std::find(SUPPORTED_INSTRUMENTS.begin(), SUPPORTED_INSTRUMENTS.end(),
+                m_instrumentName) == SUPPORTED_INSTRUMENTS.end()) {
+    std::string message =
+        "The instrument " + m_instrumentName + " is not valid for this loader!";
+    throw std::runtime_error(message);
+  }
+
+  g_log.debug() << "Instrument name set to: " + m_instrumentName << '\n';
+}
+
+/**
+ * Creates the workspace and initialises member variables with
+ * the corresponding values
+ *
+ * @param entry The NeXus entry
+ * @param monitors List of monitor data
+ */
+void LoadILLTOF2::initWorkSpace(NeXus::NXEntry &entry,
+                                const std::vector<std::vector<int>> &monitors) {
+
+  // read in the data
+  NXData dataGroup = entry.openNXData("data");
+  NXInt data = dataGroup.openIntData();
+
+  m_numberOfTubes = static_cast<size_t>(data.dim0());
+  m_numberOfPixelsPerTube = static_cast<size_t>(data.dim1());
+  m_numberOfChannels = static_cast<size_t>(data.dim2());
+  const size_t numberOfMonitors = monitors.size();
+
+  /**
+   * IN4 : Rosace detector is in a different field.
+   */
+  size_t numberOfTubesInRosace = 0;
+  if (m_instrumentName == "IN4") {
+    NXData dataGroupRosace =
+        entry.openNXData("instrument/Detector_Rosace/data");
+    NXInt dataRosace = dataGroupRosace.openIntData();
+    numberOfTubesInRosace += static_cast<size_t>(dataRosace.dim0());
+  }
+
+  // dim0 * m_numberOfPixelsPerTube is the total number of detectors
+  m_numberOfHistograms =
+      (m_numberOfTubes + numberOfTubesInRosace) * m_numberOfPixelsPerTube;
+
+  g_log.debug() << "NumberOfTubes: " << m_numberOfTubes << '\n';
+  g_log.debug() << "NumberOfPixelsPerTube: " << m_numberOfPixelsPerTube << '\n';
+  g_log.debug() << "NumberOfChannels: " << m_numberOfChannels << '\n';
+
+  // Now create the output workspace
+  // total number of spectra + number of monitors,
+  // bin boundaries = m_numberOfChannels + 1
+  // Z/time dimension
+  m_localWorkspace = WorkspaceFactory::Instance().create(
+      "Workspace2D", m_numberOfHistograms + numberOfMonitors,
+      m_numberOfChannels + 1, m_numberOfChannels);
+  m_localWorkspace->getAxis(0)->unit() = UnitFactory::Instance().create("TOF");
+  m_localWorkspace->setYUnitLabel("Counts");
+}
+
+/**
+ * Load the time details from the nexus file.
+ *
+ * @param entry :: The Nexus entry
+ */
+void LoadILLTOF2::loadTimeDetails(NeXus::NXEntry &entry) {
+
+  m_wavelength = entry.getFloat("wavelength");
+
+  // Monitor can be monitor (IN5) or monitor1 (IN6)
+  std::string monitorName;
+  if (entry.containsGroup("monitor"))
+    monitorName = "monitor";
+  else if (entry.containsGroup("monitor1"))
+    monitorName = "monitor1";
+  else {
+    std::string message("Cannot find monitor[1] in the Nexus file!");
+    g_log.error(message);
+    throw std::runtime_error(message);
+  }
+
+  NXFloat time_of_flight_data =
+      entry.openNXFloat(monitorName + "/time_of_flight");
+  time_of_flight_data.load();
+
+  // The entry "monitor/time_of_flight", has 3 fields:
+  // channel width , number of channels, Time of flight delay
+  m_channelWidth = time_of_flight_data[0];
+  m_timeOfFlightDelay = time_of_flight_data[2];
+
+  g_log.debug("Nexus Data:");
+  g_log.debug() << " ChannelWidth: " << m_channelWidth << '\n';
+  g_log.debug() << " TimeOfFlightDealy: " << m_timeOfFlightDelay << '\n';
+  g_log.debug() << " Wavelength: " << m_wavelength << '\n';
+}
+
+/**
+ * Goes through all the fields of the NeXus file and adds them
+ * as parameters in the workspace
+ *
+ * @param filename The NeXus file
+ */
+void LoadILLTOF2::addAllNexusFieldsAsProperties(const std::string &filename) {
+
+  API::Run &runDetails = m_localWorkspace->mutableRun();
+
+  // Open NeXus file
+  NXhandle nxfileID;
+  NXstatus stat = NXopen(filename.c_str(), NXACC_READ, &nxfileID);
+
+  g_log.debug() << "Starting parsing properties from : " << filename << '\n';
+  if (stat == NX_ERROR) {
+    g_log.debug() << "convertNexusToProperties: Error loading " << filename;
+    throw Kernel::Exception::FileError("Unable to open File:", filename);
+  }
+  m_loader.addNexusFieldsToWsRun(nxfileID, runDetails);
+
+  g_log.debug() << "End parsing properties from : " << filename << '\n';
+}
+
+/**
+ * Calculates the incident energy from the wavelength and adds
+ * it as sample log 'Ei'
+ */
+void LoadILLTOF2::addEnergyToRun() {
+
+  API::Run &runDetails = m_localWorkspace->mutableRun();
+  const double ei = m_loader.calculateEnergy(m_wavelength);
+  runDetails.addProperty<double>("Ei", ei, true); // overwrite
+}
+
+/**
+ * Adds facility info to the sample logs
+ */
+void LoadILLTOF2::addFacility() {
+  API::Run &runDetails = m_localWorkspace->mutableRun();
+  runDetails.addProperty("Facility", std::string("ILL"));
+}
+
+/**
+ * Calculates and adds the pulse intervals for the run
+ */
+void LoadILLTOF2::addPulseInterval() {
+  API::Run &runDetails = m_localWorkspace->mutableRun();
+  double n_pulses = -1;
+  double fermiChopperSpeed = -1;
+
+  if (m_instrumentName == "IN4") {
+    fermiChopperSpeed =
+        runDetails.getPropertyAsSingleValue("FC.rotation_speed");
+    const double bkgChopper1Speed =
+        runDetails.getPropertyAsSingleValue("BC1.rotation_speed");
+    const double bkgChopper2Speed =
+        runDetails.getPropertyAsSingleValue("BC2.rotation_speed");
+
+    if (std::abs(bkgChopper1Speed - bkgChopper2Speed) > 1) {
+      throw std::invalid_argument(
+          "Background choppers 1 and 2 have different speeds");
+    }
+
+    n_pulses = fermiChopperSpeed / bkgChopper1Speed / 4;
+  } else if (m_instrumentName == "IN6") {
+    fermiChopperSpeed =
+        runDetails.getPropertyAsSingleValue("Fermi.rotation_speed");
+    const double suppressorSpeed =
+        runDetails.getPropertyAsSingleValue("Suppressor.rotation_speed");
+
+    n_pulses = fermiChopperSpeed / suppressorSpeed;
+  } else {
+    return;
+  }
+
+  const double pulseInterval = 60.0 / (2 * fermiChopperSpeed) * n_pulses;
+  runDetails.addProperty<double>("pulse_interval", pulseInterval);
+}
+
+/**
+ * Loads all the spectra into the workspace, including that from the monitor
+ *
+ * @param entry The Nexus entry
+ * @param monitors List of monitor data
+ */
+void LoadILLTOF2::loadDataIntoTheWorkSpace(
+    NeXus::NXEntry &entry, const std::vector<std::vector<int>> &monitors) {
+
+  g_log.debug() << "Loading data into the workspace...\n";
+  // read in the data
+  NXData dataGroup = entry.openNXData("data");
+  NXInt data = dataGroup.openIntData();
+  // load the counts from the file into memory
+  data.load();
+
+  // Put tof in an array
+  auto &X0 = m_localWorkspace->mutableX(0);
+  for (size_t i = 0; i < m_numberOfChannels + 1; ++i) {
+    X0[i] = m_timeOfFlightDelay + m_channelWidth * static_cast<double>(i) -
+            m_channelWidth / 2; // to make sure the bin centre is correct
+  }
+
+  // The binning for monitors is considered the same as for detectors
+  size_t spec = 0;
+
+  auto const &instrument = m_localWorkspace->getInstrument();
+
+  const auto monitorIDs = instrument->getMonitors();
+
+  for (const auto &monitor : monitors) {
+    m_localWorkspace->setHistogram(spec, m_localWorkspace->binEdges(0),
+                                   Counts(monitor.begin(), monitor.end()));
+    m_localWorkspace->getSpectrum(spec).setDetectorID(monitorIDs[spec]);
+    spec++;
+  }
+
+  const std::vector<detid_t> detectorIDs = instrument->getDetectorIDs(true);
+  const size_t numberOfMonitors = monitors.size();
+
+  Progress progress(this, 0, 1, m_numberOfTubes * m_numberOfPixelsPerTube);
+
+  loadSpectra(spec, numberOfMonitors, m_numberOfTubes, detectorIDs, data,
+              progress);
+
+  g_log.debug() << "Loading data into the workspace: DONE!\n";
+
+  /**
+   * IN4 Rosace detectors are in a different NeXus entry
+   */
+  if (m_instrumentName == "IN4") {
+    g_log.debug() << "Loading data into the workspace: IN4 Rosace!\n";
+    // read in the data
+    NXData dataGroupRosace =
+        entry.openNXData("instrument/Detector_Rosace/data");
+    NXInt dataRosace = dataGroupRosace.openIntData();
+    auto numberOfTubes = static_cast<size_t>(dataRosace.dim0());
+    // load the counts from the file into memory
+    dataRosace.load();
+
+    Progress progressRosace(this, 0, 1,
+                            numberOfTubes * m_numberOfPixelsPerTube);
+
+    loadSpectra(spec, numberOfMonitors, numberOfTubes, detectorIDs, dataRosace,
+                progressRosace);
+  }
+}
+
+/**
+ * Loops over all the pixels and loads the correct spectra. Called for each set
+ * of detector types in the workspace.
+ *
+ * @param spec The current spectrum id
+ * @param numberOfMonitors The number of monitors in the workspace
+ * @param numberOfTubes The number of detector tubes in the workspace
+ * @param detectorIDs A list of all of the detector IDs
+ * @param data The NeXus data to load into the workspace
+ * @param progress The progress monitor
+ */
+void LoadILLTOF2::loadSpectra(size_t &spec, const size_t numberOfMonitors,
+                              const size_t numberOfTubes,
+                              const std::vector<detid_t> &detectorIDs,
+                              NXInt data, Progress progress) {
+  for (size_t i = 0; i < numberOfTubes; ++i) {
+    for (size_t j = 0; j < m_numberOfPixelsPerTube; ++j) {
+      int *data_p = &data(static_cast<int>(i), static_cast<int>(j), 0);
+      m_localWorkspace->setHistogram(
+          spec, m_localWorkspace->binEdges(0),
+          Counts(data_p, data_p + m_numberOfChannels));
+      m_localWorkspace->getSpectrum(spec)
+          .setDetectorID(detectorIDs[spec - numberOfMonitors]);
+      spec++;
+      progress.report();
+    }
+  }
+}
+
+/**
+ * Runs LoadInstrument to attach the instrument to the workspace
+ */
+void LoadILLTOF2::runLoadInstrument() {
+
+  IAlgorithm_sptr loadInst = createChildAlgorithm("LoadInstrument");
+
+  // Execute the child algorithm. Catch and log any error, but don't stop.
+  try {
+    loadInst->setPropertyValue("InstrumentName", m_instrumentName);
+    loadInst->setProperty<MatrixWorkspace_sptr>("Workspace", m_localWorkspace);
+    loadInst->setProperty("RewriteSpectraMap",
+                          Mantid::Kernel::OptionalBool(false));
+    loadInst->execute();
+  } catch (...) {
+    g_log.information("Cannot load the instrument definition.");
+  }
+}
+
+} // namespace DataHandling
+} // namespace Mantid
diff --git a/Framework/DataHandling/src/LoadInstrument.cpp b/Framework/DataHandling/src/LoadInstrument.cpp
index 62d8c1a9269838bdc7002780b97177b273a5ef8f..3353a6d762e21731dd96ae0fcecf8476a4d438cd 100644
--- a/Framework/DataHandling/src/LoadInstrument.cpp
+++ b/Framework/DataHandling/src/LoadInstrument.cpp
@@ -1,6 +1,3 @@
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidAPI/FileProperty.h"
 #include "MantidAPI/InstrumentDataService.h"
 #include "MantidAPI/MatrixWorkspace.h"
@@ -11,6 +8,7 @@
 #include "MantidKernel/ConfigService.h"
 #include "MantidKernel/OptionalBool.h"
 #include "MantidKernel/MandatoryValidator.h"
+#include "MantidKernel/Strings.h"
 
 #include <Poco/DOM/DOMParser.h>
 #include <Poco/DOM/Document.h>
@@ -270,7 +268,7 @@ std::string LoadInstrument::getFullPathParamIDF(std::string directoryName) {
   directoryPath.makeDirectory();
   // Remove the path from the filename
   Poco::Path filePath(m_filename);
-  std::string instrumentFile = filePath.getFileName();
+  const std::string &instrumentFile = filePath.getFileName();
 
   // First check whether there is a parameter file whose name is the same as the
   // IDF file,
diff --git a/Framework/DataHandling/src/LoadInstrumentFromRaw.cpp b/Framework/DataHandling/src/LoadInstrumentFromRaw.cpp
index 72e363e248c09da685244ca13a30f388efcee8ef..6d75d43314794c25d770365b1fb30c1398f5077e 100644
--- a/Framework/DataHandling/src/LoadInstrumentFromRaw.cpp
+++ b/Framework/DataHandling/src/LoadInstrumentFromRaw.cpp
@@ -67,7 +67,6 @@ void LoadInstrumentFromRaw::exec() {
 
   // Create a new Instrument with the right name and add it to the workspace
   Geometry::Instrument_sptr instrument(new Instrument(iraw.i_inst));
-  localWorkspace->setInstrument(instrument);
 
   // Add dummy source and samplepos to instrument
   // The L2 and 2-theta values from Raw file assumed to be relative to sample
@@ -146,6 +145,7 @@ void LoadInstrumentFromRaw::exec() {
     prog += (0.5 / numDetector);
     progress(prog);
   }
+  localWorkspace->setInstrument(instrument);
 
   std::vector<detid_t> monitorList = instrument->getMonitors();
   setProperty("MonitorList", monitorList);
diff --git a/Framework/DataHandling/src/LoadIsawDetCal.cpp b/Framework/DataHandling/src/LoadIsawDetCal.cpp
index 696b8feb3c7861d50178f1f6ea38e40ad3979121..cdd51572f8afcaf56665255b62bdcbd96e3e55b4 100644
--- a/Framework/DataHandling/src/LoadIsawDetCal.cpp
+++ b/Framework/DataHandling/src/LoadIsawDetCal.cpp
@@ -13,9 +13,11 @@
 #include "MantidGeometry/Instrument/ObjCompAssembly.h"
 #include "MantidGeometry/Instrument/ComponentHelper.h"
 
+#include "MantidKernel/Strings.h"
 #include "MantidKernel/V3D.h"
 
 #include <Poco/File.h>
+#include <boost/algorithm/string/trim.hpp>
 #include <sstream>
 #include <iostream>
 #include <fstream>
diff --git a/Framework/DataHandling/src/LoadLog.cpp b/Framework/DataHandling/src/LoadLog.cpp
index 62a2025aa429f27917d783c779a82b9eb0f478be..96e1840d73f7309fd9c3e15b01b8495660373a34 100644
--- a/Framework/DataHandling/src/LoadLog.cpp
+++ b/Framework/DataHandling/src/LoadLog.cpp
@@ -357,7 +357,7 @@ bool LoadLog::LoadSNSText() {
   // Go back to start
   inLogFile.seekg(0);
   while (Mantid::Kernel::Strings::extractToEOL(inLogFile, aLine)) {
-    if (aLine.size() == 0)
+    if (aLine.empty())
       break;
 
     if (SNSTextFormatColumns(aLine, cols)) {
diff --git a/Framework/DataHandling/src/LoadLogsForSNSPulsedMagnet.cpp b/Framework/DataHandling/src/LoadLogsForSNSPulsedMagnet.cpp
deleted file mode 100644
index caf291169effae73cdc9c4a6ab4d2e8b6a45d13a..0000000000000000000000000000000000000000
--- a/Framework/DataHandling/src/LoadLogsForSNSPulsedMagnet.cpp
+++ /dev/null
@@ -1,251 +0,0 @@
-#include "MantidDataHandling/LoadLogsForSNSPulsedMagnet.h"
-#include "MantidAPI/FileProperty.h"
-#include "MantidAPI/MatrixWorkspace.h"
-#include "MantidAPI/Run.h"
-#include "MantidKernel/BinaryFile.h"
-#include "MantidKernel/ConfigService.h"
-#include "MantidKernel/System.h"
-
-#include <fstream>
-#include <sstream>
-#include <sys/stat.h>
-
-using std::size_t;
-using std::vector;
-
-namespace Mantid {
-namespace DataHandling {
-
-// Register the algorithm into the AlgorithmFactory
-DECLARE_ALGORITHM(LoadLogsForSNSPulsedMagnet)
-
-using namespace Mantid::Kernel;
-using namespace Mantid::API;
-
-/** Constructor
- */
-LoadLogsForSNSPulsedMagnet::LoadLogsForSNSPulsedMagnet()
-    : m_delaytimefilename(""), m_pulseidfilename(""),
-      m_delayfileinoldformat(false), m_numpulses(0), m_numchoppers(0),
-      m_delaytimes(nullptr), m_pulseidseconds(), m_pulseidnanoseconds(), WS() {}
-
-/** Destructor
- */
-LoadLogsForSNSPulsedMagnet::~LoadLogsForSNSPulsedMagnet() {
-  for (unsigned int i = 0; i < m_numpulses; i++)
-    delete[] m_delaytimes[i];
-  delete[] m_delaytimes;
-}
-
-/** Initialize the algorithm's properties.
- */
-void LoadLogsForSNSPulsedMagnet::init() {
-
-  declareProperty(make_unique<WorkspaceProperty<MatrixWorkspace>>(
-                      "Workspace", "Anonymous", Direction::InOut),
-                  "The name of the workspace in which to attach the pulsed "
-                  "magnet log information.");
-
-  declareProperty(
-      make_unique<FileProperty>("DelayTimeFilename", "", FileProperty::Load,
-                                ".dat"),
-      "The name (including its full or relative path) of the log file to\n"
-      "attempt to load the pulsed magnet log. The file extension must either "
-      "be\n"
-      ".dat or .DAT");
-
-  declareProperty(
-      make_unique<FileProperty>("PulseIDFilename", "", FileProperty::Load,
-                                ".dat"),
-      "The name (including its full or relative path) of the log file to\n"
-      "attempt to load the PulseID. The file extension must either be\n"
-      ".dat or .DAT");
-
-  declareProperty(make_unique<PropertyWithValue<bool>>("OldFormat", false,
-                                                       Direction::Input),
-                  "Delay time file have an old format");
-
-  declareProperty(
-      make_unique<PropertyWithValue<int64_t>>("NumberOfChoppers", 4,
-                                              Direction::Input),
-      "Number of choppers used in data acquisition.  It is not required for "
-      "new format Delay time file.");
-
-  m_numpulses = 0;
-  m_numchoppers = 4;
-  m_delayfileinoldformat = false;
-}
-
-//----------------------------------------------------------------------------------------------
-/** Execute the algorithm.
- */
-void LoadLogsForSNSPulsedMagnet::exec() {
-
-  // 1. Retrieve the information from input data file (binary)
-  m_delaytimefilename = getPropertyValue("DelayTimeFileName");
-  m_pulseidfilename = getPropertyValue("PulseIDFileName");
-  m_delayfileinoldformat = getProperty("OldFormat");
-  if (m_delayfileinoldformat)
-    m_numchoppers = getProperty("NumberOfChoppers");
-
-  // 1 b) check input
-  if (m_numchoppers < 1) {
-    throw std::invalid_argument(
-        "Number of choppers cannot be smaller than 1. ");
-  }
-
-  WS = getProperty("Workspace");
-
-  g_log.information() << "Input Files: " << m_delaytimefilename << " , "
-                      << m_pulseidfilename << '\n';
-
-  // 2. Parse delaytime file
-  ParseDelayTimeLogFile();
-
-  // 3. Parse pulse ID file
-  ParsePulseIDLogFile();
-
-  // 4. Integrate answer
-  addProperty();
-}
-
-void LoadLogsForSNSPulsedMagnet::ParseDelayTimeLogFile() {
-  char *logfilename = &m_delaytimefilename[0];
-
-  // 1. Determine length of file
-  struct stat results;
-  size_t filesize;
-  if (stat(logfilename, &results) == 0) {
-    filesize = static_cast<size_t>(results.st_size);
-    g_log.debug() << "File Size = " << filesize << "\n";
-  } else {
-    g_log.error() << "File Error!  Cannot Read File Size"
-                  << "\n";
-    return;
-  }
-
-  // 2. Determine number of magnetic pulses
-  size_t numpulses;
-  if (m_delayfileinoldformat) {
-    numpulses = filesize / sizeof(double) / m_numchoppers;
-  } else {
-    numpulses = filesize / (4 + 4) / m_numchoppers;
-  }
-  g_log.debug() << "Number of Pulses = " << numpulses
-                << " Old format = " << m_delayfileinoldformat << '\n';
-
-  // 3. Build data structure
-  auto delaytimes = new unsigned int *[numpulses];
-  for (unsigned int i = 0; i < numpulses; i++)
-    delaytimes[i] = new unsigned int[m_numchoppers];
-
-  // 4. Parse
-  std::ifstream logFile(logfilename, std::ios::in | std::ios::binary);
-  size_t index = 0;
-  unsigned int localdelaytimes[4];
-  for (size_t p = 0; p < numpulses; p++) {
-    for (size_t i = 0; i < static_cast<size_t>(m_numchoppers); i++) {
-      unsigned int chopperindex;
-      unsigned int delaytime;
-      double dtime;
-      if (m_delayfileinoldformat) {
-        // Old format
-        logFile.read(reinterpret_cast<char *>(&dtime), sizeof(double));
-
-        chopperindex = static_cast<unsigned int>(i + 1);
-        delaytime = static_cast<unsigned int>(dtime * 1000);
-
-      } else {
-        // New format
-        logFile.read(reinterpret_cast<char *>(&chopperindex),
-                     sizeof(unsigned int));
-        logFile.read(reinterpret_cast<char *>(&delaytime),
-                     sizeof(unsigned int));
-      }
-      if (delaytime != 0) {
-        g_log.debug() << "Pulse Index =  " << index
-                      << "  Chopper = " << chopperindex
-                      << "   Delay Time = " << delaytime << '\n';
-      }
-      localdelaytimes[i] = delaytime;
-    }
-
-    // Load
-    for (int i = 0; i < 4; i++) {
-      delaytimes[p][i] = localdelaytimes[i];
-    }
-
-    index++;
-  }
-  logFile.close();
-
-  m_numpulses = numpulses;
-  m_delaytimes = delaytimes;
-}
-
-#pragma pack(push, 4) // Make sure the structure is 16 bytes.
-struct Pulse {
-  /// The number of nanoseconds since the seconds field. This is not necessarily
-  /// less than one second.
-  uint32_t nanoseconds;
-
-  /// The number of seconds since January 1, 1990.
-  uint32_t seconds;
-
-  /// The index of the first event for this pulse.
-  // cppcheck-suppress unusedStructMember
-  uint64_t event_index;
-
-  /// The proton charge for the pulse.
-  // cppcheck-suppress unusedStructMember
-  double pCurrent;
-};
-#pragma pack(pop)
-
-void LoadLogsForSNSPulsedMagnet::ParsePulseIDLogFile() {
-  std::vector<Pulse> pulses;
-  BinaryFile<Pulse> pulseFile(m_pulseidfilename);
-  this->m_numpulses = pulseFile.getNumElements();
-  pulses = pulseFile.loadAll();
-  for (const auto &pulse : pulses) {
-    this->m_pulseidseconds.push_back(pulse.seconds);
-    this->m_pulseidnanoseconds.push_back(pulse.nanoseconds);
-  }
-}
-
-void LoadLogsForSNSPulsedMagnet::addProperty() {
-  //    DateAndTime epoc(int64_t(m_pulseidhighs[0]),
-  //    int64_t(m_pulseidhighs[0]));
-  // create values to put into the property
-  //    std::vector<double> times;
-  //    std::vector<double> values;*/
-
-  auto property = new TimeSeriesProperty<double> *[4];
-  for (int i = 0; i < 4; i++) {
-    std::stringstream namess;
-    namess << "PulsedMagnetDelay" << i;
-    std::string tempname = namess.str();
-    property[i] = new TimeSeriesProperty<double>(tempname);
-    property[i]->setUnits("nanoseconds");
-  }
-
-  for (size_t pulse_index = 0; pulse_index < m_numpulses; pulse_index++) {
-    DateAndTime dt(static_cast<int32_t>(m_pulseidseconds[pulse_index]),
-                   static_cast<int32_t>(m_pulseidnanoseconds[pulse_index]));
-    for (int i = 0; i < 4; i++) {
-      property[i]->addValue(dt,
-                            static_cast<double>(m_delaytimes[pulse_index][i]));
-    }
-  }
-
-  for (int i = 0; i < 4; i++)
-    WS->mutableRun().addProperty(property[i], false);
-
-  g_log.debug() << "Integration is Over!\n";
-
-  // Clean memory
-  delete[] property;
-}
-
-} // namespace Mantid
-} // namespace DataHandling
diff --git a/Framework/DataHandling/src/LoadMLZ.cpp b/Framework/DataHandling/src/LoadMLZ.cpp
index cead7cb1e2dea549cb67ab19d832cf333abebef2..8a574397602efdf3dba67348a6e7c497a057ee54 100644
--- a/Framework/DataHandling/src/LoadMLZ.cpp
+++ b/Framework/DataHandling/src/LoadMLZ.cpp
@@ -1,9 +1,7 @@
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidDataHandling/LoadMLZ.h"
 #include "MantidDataHandling/LoadHelper.h"
 #include "MantidAPI/Axis.h"
+#include "MantidAPI/DetectorInfo.h"
 #include "MantidAPI/FileProperty.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/Progress.h"
@@ -18,7 +16,6 @@
 #include <cmath>
 #include <limits>
 #include <vector>
-//-----------------------------------------------------------------------
 
 namespace Mantid {
 namespace DataHandling {
@@ -30,7 +27,6 @@ using namespace NeXus;
 // Register the algorithm into the AlgorithmFactory
 DECLARE_NEXUS_FILELOADER_ALGORITHM(LoadMLZ)
 
-//----------------------------------------------------------------------------------------------
 /** Constructor
  */
 LoadMLZ::LoadMLZ()
@@ -40,7 +36,6 @@ LoadMLZ::LoadMLZ()
       m_monitorCounts{0}, m_chopper_speed{0.0}, m_chopper_ratio{0}, m_l1{0.0},
       m_l2{0.0}, m_t1{0.0}, m_supportedInstruments{"TOFTOF", "DNS"} {}
 
-//---------------------------------------------------------------------------
 /// Algorithm's name for identification. @see Algorithm::name
 const std::string LoadMLZ::name() const { return "LoadMLZ"; }
 
@@ -50,7 +45,6 @@ int LoadMLZ::version() const { return 1; }
 /// Algorithm's category for identification. @see Algorithm::category
 const std::string LoadMLZ::category() const { return "DataHandling\\Nexus"; }
 
-//---------------------------------------------------------------------------
 /** Initialize the algorithm's properties.
  */
 void LoadMLZ::init() {
@@ -64,7 +58,6 @@ void LoadMLZ::init() {
                   "The name to use for the output workspace");
 }
 
-//---------------------------------------------------------------------------
 /** Execute the algorithm.
  */
 void LoadMLZ::exec() {
@@ -126,34 +119,23 @@ void LoadMLZ::maskDetectors(NeXus::NXEntry &entry) {
   g_log.debug() << "Number of masked detectors: " << masked_detectors.size()
                 << '\n';
 
+  auto &detInfo = m_localWorkspace->mutableDetectorInfo();
+  std::vector<size_t> indicesToMask;
   for (auto masked_detector : masked_detectors) {
     g_log.debug() << "List of masked detectors: ";
     g_log.debug() << masked_detector;
     g_log.debug() << ", ";
+    try {
+      indicesToMask.push_back(detInfo.indexOf(masked_detector));
+    } catch (std::out_of_range &) {
+      g_log.warning() << "Invalid detector ID " << masked_detector
+                      << ". Found while running LoadMLZ\n";
+    }
   }
   g_log.debug() << '\n';
 
-  // Need to get hold of the parameter map
-  Geometry::ParameterMap &pmap = m_localWorkspace->instrumentParameters();
-
-  // If explicitly given a list of detectors to mask, just mark those.
-  // Otherwise, mask all detectors pointing to the requested spectra in
-  // indexlist loop below
-  std::vector<detid_t>::const_iterator it;
-  Geometry::Instrument_const_sptr instrument =
-      m_localWorkspace->getInstrument();
-  if (!masked_detectors.empty()) {
-    for (it = masked_detectors.begin(); it != masked_detectors.end(); ++it) {
-      try {
-        if (const Geometry::ComponentID det =
-                instrument->getDetector(*it)->getComponentID()) {
-          pmap.addBool(det, "masked", true);
-        }
-      } catch (Kernel::Exception::NotFoundError &e) {
-        g_log.warning() << e.what() << " Found while running MaskDetectors\n";
-      }
-    }
-  }
+  for (const auto index : indicesToMask)
+    detInfo.setMasked(index, true);
 }
 
 /**
diff --git a/Framework/DataHandling/src/LoadMask.cpp b/Framework/DataHandling/src/LoadMask.cpp
index 36f8d26745769b678c90e77f34c21fd8803becdc..8710f55f6a3dfdad3249ea64ecdcc4449e1494ad 100644
--- a/Framework/DataHandling/src/LoadMask.cpp
+++ b/Framework/DataHandling/src/LoadMask.cpp
@@ -164,7 +164,7 @@ void parseISISStringToVector(const std::string &ins,
       temps.insert(temps.begin() + 1, "-");
       splitstrings.erase(splitstrings.begin() + index);
       for (size_t ic = 0; ic < 3; ic++) {
-        if (temps[ic].size() > 0) {
+        if (!temps[ic].empty()) {
           splitstrings.insert(splitstrings.begin() + index, temps[ic]);
           index++;
         }
diff --git a/Framework/DataHandling/src/LoadMuonNexus1.cpp b/Framework/DataHandling/src/LoadMuonNexus1.cpp
index f8c27b233e3cf921c3fe0356a4f964674e2fd3e6..025dbdac56ea1825da749c34d52b5b80dbcd2cb2 100644
--- a/Framework/DataHandling/src/LoadMuonNexus1.cpp
+++ b/Framework/DataHandling/src/LoadMuonNexus1.cpp
@@ -8,6 +8,7 @@
 #include "MantidAPI/SpectrumDetectorMapping.h"
 #include "MantidAPI/TableRow.h"
 #include "MantidAPI/WorkspaceFactory.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidDataHandling/ISISRunLogs.h"
 #include "MantidDataObjects/TableWorkspace.h"
 #include "MantidDataObjects/Workspace2D.h"
diff --git a/Framework/DataHandling/src/LoadMuonNexus2.cpp b/Framework/DataHandling/src/LoadMuonNexus2.cpp
index 16a8a2b54779676f01244345ca992cbc2475d697..f50c4f38723f7434adfd079adb418ba5a97328b1 100644
--- a/Framework/DataHandling/src/LoadMuonNexus2.cpp
+++ b/Framework/DataHandling/src/LoadMuonNexus2.cpp
@@ -6,6 +6,7 @@
 #include "MantidAPI/RegisterFileLoader.h"
 #include "MantidAPI/Run.h"
 #include "MantidAPI/WorkspaceFactory.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidGeometry/Instrument/Detector.h"
 #include "MantidKernel/TimeSeriesProperty.h"
 #include "MantidKernel/UnitFactory.h"
diff --git a/Framework/DataHandling/src/LoadNXSPE.cpp b/Framework/DataHandling/src/LoadNXSPE.cpp
index 0dc488aa121cccc62cd513f2c6deacaa85d8f278..fb9ed5a8cabd553c6e8cd8d7f7b3cabfc2a5e17d 100644
--- a/Framework/DataHandling/src/LoadNXSPE.cpp
+++ b/Framework/DataHandling/src/LoadNXSPE.cpp
@@ -7,6 +7,7 @@
 #include "MantidAPI/RegisterFileLoader.h"
 #include "MantidAPI/Run.h"
 #include "MantidAPI/SpectraAxis.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidAPI/WorkspaceFactory.h"
 
 #include <nexus/NeXusFile.hpp>
@@ -264,7 +265,6 @@ void LoadNXSPE::exec() {
   // generate instrument
   Geometry::Instrument_sptr instrument(new Geometry::Instrument(
       instrument_name.empty() ? "NXSPE" : instrument_name));
-  outputWS->setInstrument(instrument);
 
   Geometry::ObjComponent *source = new Geometry::ObjComponent("source");
   source->setPos(0.0, 0.0, -10.);
@@ -293,10 +293,11 @@ void LoadNXSPE::exec() {
     instrument->add(det);
     instrument->markAsDetector(det);
   }
+  outputWS->setInstrument(instrument);
 
-  Geometry::ParameterMap &pmap = outputWS->instrumentParameters();
   std::vector<double>::iterator itdata = data.begin(), iterror = error.begin(),
                                 itdataend, iterrorend;
+  auto &spectrumInfo = outputWS->mutableSpectrumInfo();
   API::Progress prog = API::Progress(this, 0.0, 0.9, numSpectra);
   for (std::size_t i = 0; i < numSpectra; ++i) {
     itdataend = itdata + numBins;
@@ -304,9 +305,7 @@ void LoadNXSPE::exec() {
     outputWS->dataX(i) = energies;
     if ((!std::isfinite(*itdata)) || (*itdata <= -1e10)) // masked bin
     {
-      outputWS->dataY(i) = std::vector<double>(numBins, 0);
-      outputWS->dataE(i) = std::vector<double>(numBins, 0);
-      pmap.addBool(outputWS->getDetector(i)->getComponentID(), "masked", true);
+      spectrumInfo.setMasked(i, true);
     } else {
       outputWS->dataY(i) = std::vector<double>(itdata, itdataend);
       outputWS->dataE(i) = std::vector<double>(iterror, iterrorend);
diff --git a/Framework/DataHandling/src/LoadNXcanSAS.cpp b/Framework/DataHandling/src/LoadNXcanSAS.cpp
index 993bb6f8a0ac9ff2c25f7531249e9b99174e30fe..dbfabd47a5a98d333f06bad186a48d14ebe1c9b7 100644
--- a/Framework/DataHandling/src/LoadNXcanSAS.cpp
+++ b/Framework/DataHandling/src/LoadNXcanSAS.cpp
@@ -1,4 +1,5 @@
 #include "MantidAPI/AlgorithmManager.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Axis.h"
 #include "MantidAPI/Progress.h"
 #include "MantidAPI/RegisterFileLoader.h"
@@ -131,7 +132,7 @@ std::string extractIdfFileOnCurrentSystem(std::string idf) {
 
   // Get the specified IDF name
   Poco::Path path(idf);
-  auto fileName = path.getFileName();
+  const auto &fileName = path.getFileName();
 
   // Compare against all available IDFs
   const std::vector<std::string> &directoryNames =
diff --git a/Framework/DataHandling/src/LoadNexusLogs.cpp b/Framework/DataHandling/src/LoadNexusLogs.cpp
index 60b408c9c49bacfcb32778b1ae424cfaeab13f85..339c3b467ca006a7ea9b5a34f3e3e38ab3e4814e 100644
--- a/Framework/DataHandling/src/LoadNexusLogs.cpp
+++ b/Framework/DataHandling/src/LoadNexusLogs.cpp
@@ -69,6 +69,29 @@ bool loadAndApplyMeasurementInfo(::NeXus::File *const file,
   }
   return successfullyApplied;
 }
+
+/**
+* @brief loadAndApplyRunTitle
+* @param file : Nexus::File pointer
+* @param workspace : Pointer to the workspace to set logs on
+* @return True only if reading and execution successful.
+*/
+bool loadAndApplyRunTitle(::NeXus::File *const file,
+                          API::MatrixWorkspace &workspace) {
+
+  bool successfullyApplied = false;
+  try {
+    file->openData("title");
+    workspace.mutableRun().addLogData(
+        new Mantid::Kernel::PropertyWithValue<std::string>("run_title",
+                                                           file->getStrData()));
+    file->closeData();
+    successfullyApplied = true;
+  } catch (::NeXus::Exception &) {
+    successfullyApplied = false;
+  }
+  return successfullyApplied;
+}
 }
 
 /// Empty default constructor
@@ -175,6 +198,8 @@ void LoadNexusLogs::exec() {
 
   // If there's measurement information, load that info as logs.
   loadAndApplyMeasurementInfo(&file, *workspace);
+  // If there's title information, load that info as logs.
+  loadAndApplyRunTitle(&file, *workspace);
 
   // Freddie Akeroyd 12/10/2011
   // current ISIS implementation contains an additional indirection between
@@ -366,9 +391,6 @@ void LoadNexusLogs::loadLogs(
       loadNXLog(file, itr->first, log_class, workspace);
     } else if (log_class == "IXseblock") {
       loadSELog(file, itr->first, workspace);
-    } else if (log_class == "NXcollection") {
-      int jj = 0;
-      ++jj;
     }
   }
   loadVetoPulses(file, workspace);
diff --git a/Framework/DataHandling/src/LoadNexusProcessed.cpp b/Framework/DataHandling/src/LoadNexusProcessed.cpp
index 518fbd67fe6c3146e8a52e8b7eba99fef50caa62..f11fa22ae7cf40cefe2c7b55fedf0664492a9765 100644
--- a/Framework/DataHandling/src/LoadNexusProcessed.cpp
+++ b/Framework/DataHandling/src/LoadNexusProcessed.cpp
@@ -8,6 +8,7 @@
 #include "MantidAPI/Run.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidAPI/WorkspaceGroup.h"
+#include "MantidAPI/WorkspaceHistory.h"
 #include "MantidDataHandling/LoadNexusProcessed.h"
 #include "MantidDataObjects/EventWorkspace.h"
 #include "MantidDataObjects/RebinnedOutput.h"
diff --git a/Framework/DataHandling/src/LoadPDFgetNFile.cpp b/Framework/DataHandling/src/LoadPDFgetNFile.cpp
index 524ea6463cbd0fc8e8cca0d73a7bcbf2c80d4f11..ffaca18040e9a7a37ed8a0f2cdfcf8a4d35bde4e 100644
--- a/Framework/DataHandling/src/LoadPDFgetNFile.cpp
+++ b/Framework/DataHandling/src/LoadPDFgetNFile.cpp
@@ -8,6 +8,7 @@
 #include "MantidKernel/UnitFactory.h"
 
 #include <fstream>
+#include <iomanip>
 #include <boost/algorithm/string.hpp>
 #include <boost/algorithm/string/split.hpp>
 #include <boost/algorithm/string/trim.hpp>
diff --git a/Framework/DataHandling/src/LoadParameterFile.cpp b/Framework/DataHandling/src/LoadParameterFile.cpp
index 9075c9c841656477dea6db6f45be7f5ead260a71..bf8c811d7705ca062596bdfb1524249868b9c953 100644
--- a/Framework/DataHandling/src/LoadParameterFile.cpp
+++ b/Framework/DataHandling/src/LoadParameterFile.cpp
@@ -1,6 +1,3 @@
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidDataHandling/LoadParameterFile.h"
 #include "MantidAPI/FileProperty.h"
 #include "MantidAPI/MatrixWorkspace.h"
@@ -8,6 +5,7 @@
 #include "MantidGeometry/Instrument.h"
 #include "MantidGeometry/Instrument/Component.h"
 #include "MantidGeometry/Instrument/InstrumentDefinitionParser.h"
+#include "MantidKernel/ConfigService.h"
 
 #include <Poco/DOM/DOMParser.h>
 #include <Poco/DOM/Document.h>
diff --git a/Framework/DataHandling/src/LoadQKK.cpp b/Framework/DataHandling/src/LoadQKK.cpp
index 88a220ba15d822f908a0dd48d1b9a92a3ed8911a..7463ec3de93cec7ba96fe7566593e4d3923e599a 100644
--- a/Framework/DataHandling/src/LoadQKK.cpp
+++ b/Framework/DataHandling/src/LoadQKK.cpp
@@ -132,7 +132,6 @@ void LoadQKK::exec() {
   std::string instrumentname = "QUOKKA";
   Geometry::Instrument_sptr instrument(
       new Geometry::Instrument(instrumentname));
-  outputWorkspace->setInstrument(instrument);
 
   // Add dummy source and samplepos to instrument
 
@@ -210,6 +209,8 @@ void LoadQKK::exec() {
   // Position the detector so the z axis goes through its centre
   bank->setPos(-width / 2, -height / 2, 0);
 
+  outputWorkspace->setInstrument(instrument);
+
   // Set the workspace title
   outputWorkspace->setTitle(entry.getString("experiment/title"));
   // Attach the created workspace to the OutputWorkspace property. The workspace
diff --git a/Framework/DataHandling/src/LoadRawHelper.cpp b/Framework/DataHandling/src/LoadRawHelper.cpp
index 9aa49ef2b95339cbc2ca1385dcc1b65fb28bb500..f5e0720dc93bbae210db32e7d8bc8bef929943d4 100644
--- a/Framework/DataHandling/src/LoadRawHelper.cpp
+++ b/Framework/DataHandling/src/LoadRawHelper.cpp
@@ -4,6 +4,7 @@
 #include "MantidAPI/FileProperty.h"
 #include "MantidAPI/SpectrumDetectorMapping.h"
 #include "MantidAPI/WorkspaceFactory.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidDataObjects/Workspace2D.h"
 #include "MantidGeometry/Instrument.h"
 #include "MantidKernel/ArrayProperty.h"
@@ -13,7 +14,6 @@
 #include "MantidKernel/Strings.h"
 #include "MantidKernel/TimeSeriesProperty.h"
 #include "MantidKernel/UnitFactory.h"
-#include "MantidDataHandling/LoadAscii.h"
 #include "MantidDataHandling/LoadLog.h"
 #include "MantidDataHandling/RawFileInfo.h"
 
diff --git a/Framework/DataHandling/src/LoadSassena.cpp b/Framework/DataHandling/src/LoadSassena.cpp
index 785472d7a1053611bc14d117794f021840c0b5d3..c2a4f2c2315452fa606fd068621a789816b37db8 100644
--- a/Framework/DataHandling/src/LoadSassena.cpp
+++ b/Framework/DataHandling/src/LoadSassena.cpp
@@ -6,6 +6,7 @@
 #include "MantidAPI/NumericAxis.h"
 #include "MantidAPI/RegisterFileLoader.h"
 #include "MantidAPI/WorkspaceFactory.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidDataObjects/Workspace2D.h"
 #include "MantidKernel/Exception.h"
 #include "MantidKernel/Unit.h"
@@ -372,9 +373,9 @@ void LoadSassena::exec() {
 
   API::WorkspaceGroup_sptr gws =
       boost::dynamic_pointer_cast<API::WorkspaceGroup>(ows);
-  if (gws && API::AnalysisDataService::Instance().doesExist(gws->name())) {
+  if (gws && API::AnalysisDataService::Instance().doesExist(gws->getName())) {
     // gws->deepRemoveAll(); // remove workspace members
-    API::AnalysisDataService::Instance().deepRemoveGroup(gws->name());
+    API::AnalysisDataService::Instance().deepRemoveGroup(gws->getName());
   } else {
     gws = boost::make_shared<API::WorkspaceGroup>();
     setProperty("OutputWorkspace",
diff --git a/Framework/DataHandling/src/LoadSpice2D.cpp b/Framework/DataHandling/src/LoadSpice2D.cpp
index cb80cf1a500f0be0a62ff1190e39f81e251d91c8..be29746f24a4f4ddcc95dc8d0ca0bc573a4f9b6c 100644
--- a/Framework/DataHandling/src/LoadSpice2D.cpp
+++ b/Framework/DataHandling/src/LoadSpice2D.cpp
@@ -541,6 +541,8 @@ void LoadSpice2D::setMetadataAsRunProperties(
 
   addRunProperty<double>("wavelength", m_wavelength, "Angstrom");
   addRunProperty<double>("wavelength-spread", m_dwavelength, "Angstrom");
+  addRunProperty<double>("wavelength-spread-ratio",
+                         m_dwavelength / m_wavelength);
 
   addRunProperty<double>(metadata, "Counters/monitor", "monitor", "");
   addRunProperty<double>(metadata, "Counters/time", "timer", "sec");
diff --git a/Framework/DataHandling/src/LoadSpiceAscii.cpp b/Framework/DataHandling/src/LoadSpiceAscii.cpp
index b627d8292452dab5ba1850ef6cd955ed9f5ac40e..d0124230bb1eca10da4c2b6cd6f8ebd94d7b4eaa 100644
--- a/Framework/DataHandling/src/LoadSpiceAscii.cpp
+++ b/Framework/DataHandling/src/LoadSpiceAscii.cpp
@@ -236,7 +236,7 @@ void LoadSpiceAscii::parseSPICEAscii(
     // Strip
     boost::trim(line);
     // skip for empyt line
-    if (line.size() == 0)
+    if (line.empty())
       continue;
 
     // Comment line for run information
diff --git a/Framework/DataHandling/src/LoadSpiceXML2DDet.cpp b/Framework/DataHandling/src/LoadSpiceXML2DDet.cpp
index 67dec0804108200b2f81732527c4fda3a2a470a7..a0381cf324144ee9596c980b18c3d9858f528fe9 100644
--- a/Framework/DataHandling/src/LoadSpiceXML2DDet.cpp
+++ b/Framework/DataHandling/src/LoadSpiceXML2DDet.cpp
@@ -68,24 +68,24 @@ void SpiceXMLNode::setParameters(const std::string &nodetype,
   }
 
   // unit
-  if (nodeunit.size() > 0) {
+  if (!nodeunit.empty()) {
     m_unit = nodeunit;
   }
 
   // description
-  if (nodedescription.size() > 0)
+  if (!nodedescription.empty())
     m_description = nodedescription;
 }
 
 /** Check whether XML has unit set
  */
-bool SpiceXMLNode::hasUnit() const { return (m_unit.size() > 0); }
+bool SpiceXMLNode::hasUnit() const { return (!m_unit.empty()); }
 
 /** Check whether XML node has value set
  * @brief SpiceXMLNode::hasValue
  * @return
  */
-bool SpiceXMLNode::hasValue() const { return (m_value.size() > 0); }
+bool SpiceXMLNode::hasValue() const { return (!m_value.empty()); }
 
 /** Is this node of string type?
  * @brief SpiceXMLNode::isString
@@ -201,15 +201,23 @@ void LoadSpiceXML2DDet::init() {
   declareProperty("PtNumber", 0,
                   "Pt. value for the row to get sample log from. ");
 
+  declareProperty("UserSpecifiedWaveLength", EMPTY_DBL(),
+                  "User can specify the wave length of the instrument if it is "
+                  "drifted from the designed value."
+                  "It happens often.");
+
   declareProperty(
       "ShiftedDetectorDistance", 0.,
       "Amount of shift of the distance between source and detector centre."
       "It is used to apply instrument calibration.");
 
-  declareProperty("UserSpecifiedWaveLength", EMPTY_DBL(),
-                  "User can specify the wave length of the instrument if it is "
-                  "drifted from the designed value."
-                  "It haappens often.");
+  declareProperty("DetectorCenterXShift", 0.0, "The amount of shift of "
+                                               "detector center along X "
+                                               "direction in the unit meter.");
+
+  declareProperty("DetectorCenterYShift", 0.0, "The amount of shift of "
+                                               "detector center along Y "
+                                               "direction in the unit meter.");
 }
 
 /** Process inputs arguments
@@ -232,7 +240,7 @@ void LoadSpiceXML2DDet::processInputs() {
 
   // Retreive sample environment data from SPICE scan table workspace
   std::string spicetablewsname = getPropertyValue("SpiceTableWorkspace");
-  if (spicetablewsname.size() > 0)
+  if (!spicetablewsname.empty())
     m_hasScanTable = true;
   else
     m_hasScanTable = false;
@@ -240,6 +248,9 @@ void LoadSpiceXML2DDet::processInputs() {
   m_ptNumber4Log = getProperty("PtNumber");
 
   m_userSpecifiedWaveLength = getProperty("UserSpecifiedWaveLength");
+
+  m_detXShift = getProperty("DetectorCenterXShift");
+  m_detYShift = getProperty("DetectorCenterYShift");
 }
 
 /** Set up sample logs especially 2theta and diffr for loading instrument
@@ -254,12 +265,13 @@ bool LoadSpiceXML2DDet::setupSampleLogs(API::MatrixWorkspace_sptr outws) {
     setupSampleLogFromSpiceTable(outws, spicetablews, m_ptNumber4Log);
   }
 
+  Kernel::DateAndTime anytime(1000);
+
   // Process 2theta
   bool return_true = true;
   if (!outws->run().hasProperty("2theta") &&
       outws->run().hasProperty("_2theta")) {
     // Set up 2theta if it is not set up yet
-    Kernel::DateAndTime anytime(1000);
     double logvalue =
         atof(outws->run().getProperty("_2theta")->value().c_str());
     TimeSeriesProperty<double> *newlogproperty =
@@ -275,8 +287,16 @@ bool LoadSpiceXML2DDet::setupSampleLogs(API::MatrixWorkspace_sptr outws) {
     return_true = false;
   }
 
+  // set up the caibrated detector center to beam
+  TimeSeriesProperty<double> *det_dx = new TimeSeriesProperty<double>("deltax");
+  det_dx->addValue(anytime, m_detXShift);
+  outws->mutableRun().addProperty(det_dx);
+
+  TimeSeriesProperty<double> *det_dy = new TimeSeriesProperty<double>("deltay");
+  det_dy->addValue(anytime, m_detYShift);
+  outws->mutableRun().addProperty(det_dy);
+
   // set up Sample-detetor distance calibration
-  Kernel::DateAndTime anytime(1000);
   double sampledetdistance = m_detSampleDistanceShift;
   TimeSeriesProperty<double> *distproperty =
       new TimeSeriesProperty<double>("diffr");
@@ -465,20 +485,20 @@ MatrixWorkspace_sptr LoadSpiceXML2DDet::createMatrixWorkspace(
                     << "\n";
 
       // XML file records data in the order of column-major
-      size_t icol = 0;
+      size_t i_col = 0;
       for (size_t i = 0; i < vecLines.size(); ++i) {
         std::string &line = vecLines[i];
 
         // Skip empty line
-        if (line.size() == 0) {
+        if (line.empty()) {
           g_log.debug() << "\tFound empty Line at " << i << "\n";
           continue;
         }
 
         // Check whether it exceeds boundary
-        if (icol == numpixelx) {
+        if (i_col == numpixelx) {
           std::stringstream errss;
-          errss << "Number of non-empty rows (" << icol + 1
+          errss << "Number of non-empty rows (" << i_col + 1
                 << ") in detector data "
                 << "exceeds user defined geometry size " << numpixelx << ".";
           throw std::runtime_error(errss.str());
@@ -492,18 +512,20 @@ MatrixWorkspace_sptr LoadSpiceXML2DDet::createMatrixWorkspace(
         // in Y direction
         if (veccounts.size() != numpixely) {
           std::stringstream errss;
-          errss << "Row " << icol << " contains " << veccounts.size()
+          errss << "Row " << i_col << " contains " << veccounts.size()
                 << " items other than " << numpixely
                 << " counts specified by user.";
           throw std::runtime_error(errss.str());
         }
 
-        // scan per row
+        // scan per column
         for (size_t j_row = 0; j_row < veccounts.size(); ++j_row) {
           double counts = atof(veccounts[j_row].c_str());
 
           if (loadinstrument) {
-            size_t wsindex = j_row * numpixely + icol;
+            // the detector ID and ws index are set up in column-major too!
+            size_t wsindex = i_col * numpixelx + j_row;
+            //  size_t wsindex = j_row * numpixely + icol;
             // size_t wsindex = icol * numpixelx + j_row;
             outws->dataX(wsindex)[0] = static_cast<double>(wsindex);
             outws->dataY(wsindex)[0] = counts;
@@ -513,12 +535,12 @@ MatrixWorkspace_sptr LoadSpiceXML2DDet::createMatrixWorkspace(
               outws->dataE(wsindex)[0] = 1.0;
 
           } else {
-            outws->dataX(j_row)[icol] = static_cast<double>(j_row);
-            outws->dataY(j_row)[icol] = counts;
+            outws->dataX(j_row)[i_col] = static_cast<double>(j_row);
+            outws->dataY(j_row)[i_col] = counts;
             if (counts > 0)
-              outws->dataE(j_row)[icol] = sqrt(counts);
+              outws->dataE(j_row)[i_col] = sqrt(counts);
             else
-              outws->dataE(j_row)[icol] = 1.0;
+              outws->dataE(j_row)[i_col] = 1.0;
           }
 
           // record max count
@@ -527,8 +549,8 @@ MatrixWorkspace_sptr LoadSpiceXML2DDet::createMatrixWorkspace(
           }
         }
 
-        // Update irow
-        icol += 1;
+        // Update column index (i.e., column number)
+        i_col += 1;
       } // END-FOR (i-vec line)
 
       // Set flag
@@ -709,7 +731,7 @@ void LoadSpiceXML2DDet::loadInstrument(API::MatrixWorkspace_sptr matrixws,
   API::IAlgorithm_sptr loadinst = createChildAlgorithm("LoadInstrument");
   loadinst->initialize();
   loadinst->setProperty("Workspace", matrixws);
-  if (idffilename.size() > 0) {
+  if (!idffilename.empty()) {
     loadinst->setProperty("Filename", idffilename);
   } else
     loadinst->setProperty("InstrumentName", "HB3A");
diff --git a/Framework/DataHandling/src/LoadTBL.cpp b/Framework/DataHandling/src/LoadTBL.cpp
index 2e357abae9691e5b50dac6a0eeda7107c6bf7feb..0bb459acbb7bca0bcc31f1bf1ae2d3d14ebc0537 100644
--- a/Framework/DataHandling/src/LoadTBL.cpp
+++ b/Framework/DataHandling/src/LoadTBL.cpp
@@ -130,7 +130,6 @@ void LoadTBL::csvParse(std::string line, std::vector<std::string> &cols,
                        std::vector<std::vector<size_t>> &quoteBounds,
                        size_t expectedCommas) const {
   size_t pairID = 0;
-  size_t valsFound = 0;
   size_t lastComma = 0;
   size_t pos = 0;
   bool firstCheck = true;
@@ -153,7 +152,6 @@ void LoadTBL::csvParse(std::string line, std::vector<std::string> &cols,
                                      quoteBounds.at(pairID).at(1) -
                                          (quoteBounds.at(pairID).at(0) + 1)));
           ++pairID;
-          ++valsFound;
         }
       } else {
         if (firstCell) {
@@ -163,7 +161,6 @@ void LoadTBL::csvParse(std::string line, std::vector<std::string> &cols,
           auto colVal = line.substr(lastComma + 1, pos - (lastComma + 1));
           cols.push_back(line.substr(lastComma + 1, pos - (lastComma + 1)));
         }
-        ++valsFound;
       }
       lastComma = pos;
     } else {
diff --git a/Framework/DataHandling/src/LoadTOFRawNexus.cpp b/Framework/DataHandling/src/LoadTOFRawNexus.cpp
index 064855fe9d38f8c30bc7c2ee75a5918ac977e1fd..3acf135a655ca8fa4d04fa929fb91daa52d9fbdb 100644
--- a/Framework/DataHandling/src/LoadTOFRawNexus.cpp
+++ b/Framework/DataHandling/src/LoadTOFRawNexus.cpp
@@ -8,6 +8,7 @@
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidKernel/ArrayProperty.h"
 #include "MantidKernel/BoundedValidator.h"
+#include "MantidKernel/Strings.h"
 #include "MantidKernel/cow_ptr.h"
 #include <nexus/NeXusFile.hpp>
 
diff --git a/Framework/DataHandling/src/LoadVulcanCalFile.cpp b/Framework/DataHandling/src/LoadVulcanCalFile.cpp
index 7a66d7defd77d85ade19b6b82c064026dc9bdee3..5e9bfe7d1d85eeab8a49d924d950eaaffdc0ccb5 100644
--- a/Framework/DataHandling/src/LoadVulcanCalFile.cpp
+++ b/Framework/DataHandling/src/LoadVulcanCalFile.cpp
@@ -2,6 +2,7 @@
 #include "MantidAPI/Algorithm.h"
 #include "MantidAPI/FileProperty.h"
 #include "MantidAPI/MatrixWorkspace.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidAPI/Run.h"
 #include "MantidDataObjects/GroupingWorkspace.h"
 #include "MantidDataObjects/MaskWorkspace.h"
@@ -255,7 +256,7 @@ void LoadVulcanCalFile::setupGroupingWorkspace() {
 void LoadVulcanCalFile::setupMaskWorkspace() {
 
   // Skip if bad pixel file is not given
-  if (m_badPixFilename.size() == 0)
+  if (m_badPixFilename.empty())
     return;
 
   // Open file
@@ -288,9 +289,11 @@ void LoadVulcanCalFile::setupMaskWorkspace() {
 
   // Mask workspace index
   std::ostringstream msg;
+  auto &spectrumInfo = m_maskWS->mutableSpectrumInfo();
   for (size_t i = 0; i < m_maskWS->getNumberHistograms(); ++i) {
     if (m_maskWS->readY(i)[0] > 0.5) {
-      m_maskWS->maskWorkspaceIndex(i);
+      m_maskWS->getSpectrum(i).clearData();
+      spectrumInfo.setMasked(i, true);
       m_maskWS->dataY(i)[0] = 1.0;
       msg << "Spectrum " << i << " is masked. DataY = " << m_maskWS->readY(i)[0]
           << "\n";
@@ -628,6 +631,9 @@ void LoadVulcanCalFile::readCalFile(const std::string &calFileName,
   int n, udet, select, group;
   double n_d, udet_d, offset, select_d, group_d;
 
+  SpectrumInfo *maskSpectrumInfo{nullptr};
+  if (maskWS)
+    maskSpectrumInfo = &maskWS->mutableSpectrumInfo();
   std::string str;
   while (getline(grFile, str)) {
     if (str.empty() || str[0] == '#')
@@ -674,7 +680,8 @@ void LoadVulcanCalFile::readCalFile(const std::string &calFileName,
 
         if (select <= 0) {
           // Not selected, then mask this detector
-          maskWS->maskWorkspaceIndex(wi);
+          maskWS->getSpectrum(wi).clearData();
+          maskSpectrumInfo->setMasked(wi, true);
           maskWS->dataY(wi)[0] = 1.0;
         } else {
           // Selected, set the value to be 0
diff --git a/Framework/DataHandling/src/MaskDetectors.cpp b/Framework/DataHandling/src/MaskDetectors.cpp
index 87c9e673c5d3bb6bb29913e6334a70bafa68d786..7ffcbb0625785febc015450fbb1a9b2b5d33d836 100644
--- a/Framework/DataHandling/src/MaskDetectors.cpp
+++ b/Framework/DataHandling/src/MaskDetectors.cpp
@@ -1,11 +1,10 @@
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidDataHandling/MaskDetectors.h"
 
 #include "MantidDataObjects/EventWorkspace.h"
 #include "MantidDataObjects/MaskWorkspace.h"
 
+#include "MantidAPI/DetectorInfo.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidKernel/ArrayProperty.h"
 #include "MantidKernel/BoundedValidator.h"
 #include "MantidKernel/EnabledWhenProperty.h"
@@ -39,12 +38,10 @@ namespace DataHandling {
 // Register the algorithm into the algorithm factory
 DECLARE_ALGORITHM(MaskDetectors)
 
-using namespace Kernel;
 using namespace API;
+using namespace Kernel;
 using namespace DataObjects;
-using Geometry::Instrument_const_sptr;
-using Geometry::IDetector_const_sptr;
-using namespace DataObjects;
+using namespace Geometry;
 
 /*
  * Define input arguments
@@ -94,6 +91,9 @@ void MaskDetectors::init() {
       "Default is number of histograms in target workspace if other masks are"
       " present "
       "or ignored if not.");
+  declareProperty(
+      make_unique<ArrayProperty<std::string>>("ComponentList"),
+      "An ArrayProperty containing a list of component names to mask");
 }
 
 /*
@@ -120,6 +120,10 @@ void MaskDetectors::exec() {
   std::vector<size_t> indexList = getProperty("WorkspaceIndexList");
   std::vector<specnum_t> spectraList = getProperty("SpectraList");
   std::vector<detid_t> detectorList = getProperty("DetectorList");
+  std::vector<std::string> componentList = getProperty("ComponentList");
+  if (!componentList.empty()) {
+    appendToDetectorListFromComponentList(detectorList, componentList, WS);
+  }
   const MatrixWorkspace_sptr prevMasking = getProperty("MaskedWorkspace");
 
   auto ranges_info = getRanges(WS);
@@ -148,38 +152,13 @@ void MaskDetectors::exec() {
     std::iota(indexList.begin(), indexList.end(), std::get<0>(ranges_info));
   }
 
-  if (prevMasking) {
-    DataObjects::MaskWorkspace_const_sptr maskWS =
-        boost::dynamic_pointer_cast<DataObjects::MaskWorkspace>(prevMasking);
-    if (maskWS) {
-      if (maskWS->getInstrument()->getDetectorIDs().size() !=
-          WS->getInstrument()->getDetectorIDs().size()) {
-        throw std::runtime_error("Instrument's detector numbers mismatch "
-                                 "between input Workspace and MaskWorkspace");
-      }
-
-      g_log.debug() << "Extracting mask from MaskWorkspace (" << maskWS->name()
-                    << ")\n";
-      bool forceDetIDs = getProperty("ForceInstrumentMasking");
-      if (prevMasking->getNumberHistograms() != WS->getNumberHistograms() ||
-          forceDetIDs) {
-        extractMaskedWSDetIDs(detectorList, maskWS);
-      } else {
-        appendToIndexListFromMaskWS(indexList, maskWS, ranges_info);
-      }
-    } else { // not mask workspace
-      // Check the provided workspace has the same number of spectra as the
-      // input
-      if (prevMasking->getNumberHistograms() > WS->getNumberHistograms()) {
-        g_log.error() << "Input workspace has " << WS->getNumberHistograms()
-                      << " histograms   vs. "
-                      << "Input masking workspace has "
-                      << prevMasking->getNumberHistograms()
-                      << " histograms. \n";
-        throw std::runtime_error("Size mismatch between two input workspaces.");
-      }
-      appendToIndexListFromWS(indexList, prevMasking, ranges_info);
-    }
+  auto maskWS =
+      boost::dynamic_pointer_cast<DataObjects::MaskWorkspace>(prevMasking);
+  if (maskWS && prevMasking) { // is a mask workspace
+    handleMaskByMaskWorkspace(maskWS, WS, detectorList, indexList, ranges_info);
+  } else if (prevMasking) { // is not a mask workspace
+    handleMaskByMatrixWorkspace(prevMasking, WS, detectorList, indexList,
+                                ranges_info);
   }
 
   // If the spectraList property has been set, need to loop over the workspace
@@ -211,10 +190,12 @@ void MaskDetectors::exec() {
   }
 
   // Get a reference to the spectra-detector map to get hold of detector ID's
+  auto &spectrumInfo = WS->mutableSpectrumInfo();
   double prog = 0.0;
-  std::vector<size_t>::const_iterator wit;
-  for (wit = indexList.begin(); wit != indexList.end(); ++wit) {
-    WS->maskWorkspaceIndex(*wit);
+  for (const auto i : indexList) {
+    WS->getSpectrum(i).clearData();
+    if (spectrumInfo.hasDetectors(i))
+      spectrumInfo.setMasked(i, true);
 
     // Progress
     prog += (1.0 / static_cast<int>(indexList.size()));
@@ -236,6 +217,92 @@ void MaskDetectors::exec() {
     setProperty("Workspace", ws);
   }
 }
+
+/** Handle masking a workspace using a MaskWorkspace.
+ *
+ * This will choose the strategy to mask the input workspace with based on
+ * information about the mask workspace.
+ *
+ * @param maskWs :: pointer to the mask workspace to use.
+ * @param WS :: pointer to the workspace to be masked.
+ * @param detectorList :: list of detectors to be masked.
+ * @param indexList :: list of workspace indicies to be masked.
+ * @param rangeInfo :: information about the spectrum range to use when masking
+ */
+void MaskDetectors::handleMaskByMaskWorkspace(
+    const MaskWorkspace_const_sptr maskWs,
+    const API::MatrixWorkspace_const_sptr WS,
+    std::vector<detid_t> &detectorList, std::vector<size_t> &indexList,
+    const RangeInfo &rangeInfo) {
+
+  if (maskWs->getInstrument()->getDetectorIDs().size() !=
+      WS->getInstrument()->getDetectorIDs().size()) {
+    throw std::runtime_error("Instrument's detector numbers mismatch "
+                             "between input Workspace and MaskWorkspace");
+  }
+
+  g_log.debug() << "Extracting mask from MaskWorkspace (" << maskWs->getName()
+                << ")\n";
+  bool forceDetIDs = getProperty("ForceInstrumentMasking");
+  if (maskWs->getNumberHistograms() != WS->getNumberHistograms() ||
+      forceDetIDs) {
+    g_log.notice("Masking using detectors IDs");
+    extractMaskedWSDetIDs(detectorList, maskWs);
+  } else {
+    g_log.notice("Masking using workspace indicies");
+    appendToIndexListFromMaskWS(indexList, maskWs, rangeInfo);
+  }
+}
+
+/** Handle masking a workspace using a MatrixWorkspace.
+ *
+ * This will choose the strategy to mask the input workspace with based on
+ * information about the matrix workspace passed as a mask workspace.
+ *
+ * @param maskWs :: pointer to the workspace to use as a mask.
+ * @param WS :: pointer to the workspace to be masked.
+ * @param detectorList :: list of detectors to be masked.
+ * @param indexList :: list of workspace indicies to be masked.
+ * @param rangeInfo :: information about the spectrum range to use when masking
+ */
+void MaskDetectors::handleMaskByMatrixWorkspace(
+    const API::MatrixWorkspace_const_sptr maskWs,
+    const API::MatrixWorkspace_const_sptr WS,
+    std::vector<detid_t> &detectorList, std::vector<size_t> &indexList,
+    const RangeInfo &rangeInfo) {
+
+  const auto nHist = maskWs->getNumberHistograms();
+  auto instrument = WS->getInstrument();
+  auto maskInstrument = maskWs->getInstrument();
+
+  // Check the provided workspace has the same number of spectra as the
+  // input, if so assume index list
+  if (nHist == WS->getNumberHistograms()) {
+    g_log.notice("Masking using workspace indicies");
+    appendToIndexListFromWS(indexList, maskWs, rangeInfo);
+    // Check they both have instrument and then use detector based masking
+  } else if (instrument && maskInstrument) {
+    const auto inputDetCount = instrument->getNumberDetectors();
+    const auto maskDetCount = maskInstrument->getNumberDetectors();
+
+    g_log.notice("Masking using detectors IDs");
+
+    if (inputDetCount != maskDetCount)
+      g_log.warning() << "Number of detectors does not match between "
+                         "mask workspace and input workspace";
+
+    if (instrument->getName() != maskInstrument->getName())
+      g_log.warning() << "Mask is from a different instrument to the input "
+                         "workspace. ";
+
+    appendToDetectorListFromWS(detectorList, WS, maskWs, rangeInfo);
+    // Not an index list and there's no instrument, so give up.
+  } else {
+    throw std::runtime_error(
+        "Input or mask workspace does not have an instrument.");
+  }
+}
+
 /* Verifies input ranges are defined and returns these ranges if they are.
 *
 * @return tuple containing min/max ranges provided to algorithm
@@ -335,61 +402,39 @@ void MaskDetectors::execPeaks(PeaksWorkspace_sptr WS) {
     return;
   }
 
-  // Need to get hold of the parameter map and instrument
-  Geometry::ParameterMap &pmap = WS->instrumentParameters();
-  Instrument_const_sptr instrument = WS->getInstrument();
+  auto &detInfo = WS->mutableDetectorInfo();
+  std::vector<size_t> indicesToMask;
+  for (const auto &detID : detectorList) {
+    try {
+      indicesToMask.push_back(detInfo.indexOf(detID));
+    } catch (std::out_of_range &) {
+      g_log.warning() << "Invalid detector ID " << detID
+                      << ". Found while running MaskDetectors\n";
+    }
+  }
 
   // If we have a workspace that could contain masking,copy that in too
-
   if (prevMasking) {
     DataObjects::MaskWorkspace_sptr maskWS =
         boost::dynamic_pointer_cast<DataObjects::MaskWorkspace>(prevMasking);
     if (maskWS) {
-      const auto &maskPmap = maskWS->constInstrumentParameters();
-      Instrument_const_sptr maskInstrument = maskWS->getInstrument();
-      if (maskInstrument->getDetectorIDs().size() !=
-          WS->getInstrument()->getDetectorIDs().size()) {
+      const auto &maskDetInfo = maskWS->detectorInfo();
+      if (detInfo.size() != maskDetInfo.size()) {
         throw std::runtime_error(
             "Size mismatch between input Workspace and MaskWorkspace");
       }
 
-      g_log.debug() << "Extracting mask from MaskWorkspace (" << maskWS->name()
-                    << ")\n";
-      std::vector<detid_t> detectorIDs = maskInstrument->getDetectorIDs();
-      std::vector<detid_t>::const_iterator it;
-      for (it = detectorIDs.begin(); it != detectorIDs.end(); ++it) {
-        try {
-          if (const Geometry::ComponentID det =
-                  maskInstrument->getDetector(*it)->getComponentID()) {
-            Geometry::Parameter_sptr maskedParam = maskPmap.get(det, "masked");
-            int detID =
-                static_cast<int>(maskInstrument->getDetector(*it)->getID());
-            if (maskedParam)
-              detectorList.push_back(detID);
-          }
-        } catch (Kernel::Exception::NotFoundError &e) {
-          g_log.warning() << e.what() << " Found while running MaskDetectors\n";
-        }
-      }
-    }
-  }
+      g_log.debug() << "Extracting mask from MaskWorkspace ("
+                    << maskWS->getName() << ")\n";
 
-  // If explicitly given a list of detectors to mask, just mark those.
-  // Otherwise, mask all detectors pointing to the requested spectra in
-  // index list loop below
-  std::vector<detid_t>::const_iterator it;
-  if (!detectorList.empty()) {
-    for (it = detectorList.begin(); it != detectorList.end(); ++it) {
-      try {
-        if (const Geometry::ComponentID det =
-                instrument->getDetector(*it)->getComponentID()) {
-          pmap.addBool(det, "masked", true);
-        }
-      } catch (Kernel::Exception::NotFoundError &e) {
-        g_log.warning() << e.what() << " Found while running MaskDetectors\n";
-      }
+      for (size_t i = 0; i < maskDetInfo.size(); ++i)
+        if (maskDetInfo.isMasked(i))
+          indicesToMask.push_back(i);
     }
   }
+
+  for (const auto index : indicesToMask)
+    detInfo.setMasked(index, true);
 }
 
 /* Convert a list of spectra numbers into the corresponding workspace indices.
@@ -442,7 +487,7 @@ void MaskDetectors::fillIndexListFromSpectra(
  *                            Boolean indicating if these ranges are defined
 */
 void MaskDetectors::appendToIndexListFromWS(
-    std::vector<size_t> &indexList, const MatrixWorkspace_sptr sourceWS,
+    std::vector<size_t> &indexList, const MatrixWorkspace_const_sptr sourceWS,
     const std::tuple<size_t, size_t, bool> &range_info) {
 
   std::vector<size_t> tmp_index;
@@ -450,40 +495,59 @@ void MaskDetectors::appendToIndexListFromWS(
   size_t endIndex = std::get<1>(range_info);
   bool range_constrained = std::get<2>(range_info);
 
+  const auto &spectrumInfo = sourceWS->spectrumInfo();
   if (range_constrained) {
     constrainIndexInRange(indexList, tmp_index, startIndex, endIndex);
 
     for (size_t i = startIndex; i <= endIndex; ++i) {
-      IDetector_const_sptr det;
-      try {
-        det = sourceWS->getDetector(i);
-      } catch (Exception::NotFoundError &) {
-        continue;
-      }
-      if (det->isMasked()) {
+      if (spectrumInfo.hasDetectors(i) && spectrumInfo.isMasked(i)) {
         tmp_index.push_back(i);
       }
     }
-
   } else {
     tmp_index.swap(indexList);
 
     endIndex = sourceWS->getNumberHistograms();
     for (size_t i = 0; i < endIndex; ++i) {
-      IDetector_const_sptr det;
-      try {
-        det = sourceWS->getDetector(i);
-      } catch (Exception::NotFoundError &) {
-        continue;
-      }
-      if (det->isMasked()) {
+      if (spectrumInfo.hasDetectors(i) && spectrumInfo.isMasked(i)) {
         tmp_index.push_back(i);
       }
     }
   }
   tmp_index.swap(indexList);
+}
 
-} // appendToIndexListFromWS
+/**
+* Append the indices of a workspace corresponding to detector IDs to the
+* given list
+*
+* @param detectorList :: An existing list of detector IDs
+* @param inputWs :: A workspace to mask detectors in
+* @param maskWs :: A workspace with masked spectra
+* @param range_info    :: tuple containing the information on
+*                      if copied indexes are constrained by ranges and if yes
+*                       -- the range of indexes to topy
+*/
+void MaskDetectors::appendToDetectorListFromWS(
+    std::vector<detid_t> &detectorList,
+    const MatrixWorkspace_const_sptr inputWs,
+    const MatrixWorkspace_const_sptr maskWs,
+    const std::tuple<size_t, size_t, bool> &range_info) {
+  const auto startIndex = std::get<0>(range_info);
+  const auto endIndex = std::get<1>(range_info);
+  const auto &detMap = inputWs->getDetectorIDToWorkspaceIndexMap();
+  detectorList.reserve(maskWs->getNumberHistograms());
+
+  for (size_t i = 0; i < maskWs->getNumberHistograms(); ++i) {
+    if (maskWs->y(i)[0] == 0) {
+      const auto &spec = maskWs->getSpectrum(i);
+      for (const auto &id : spec.getDetectorIDs()) {
+        if (detMap.at(id) >= startIndex && detMap.at(id) <= endIndex)
+          detectorList.push_back(id);
+      }
+    }
+  }
+}
 
 /**
 * Append the indices of the masked spectra from the given workspace list to the
@@ -528,5 +592,47 @@ void MaskDetectors::appendToIndexListFromMaskWS(
   tmp_index.swap(indexList);
 } // appendToIndexListFromWS
 
+/**
+ * Append the detector IDs of detectors found recursively in the list of
+ * components.
+ *
+ * @param detectorList :: An existing list of detector IDs
+ * @param componentList :: List of component names
+ * @param WS :: Workspace instrument of which to use
+ */
+void MaskDetectors::appendToDetectorListFromComponentList(
+    std::vector<detid_t> &detectorList,
+    const std::vector<std::string> &componentList,
+    const API::MatrixWorkspace_const_sptr WS) {
+  const auto instrument = WS->getInstrument();
+  if (!instrument) {
+    g_log.error()
+        << "No instrument in input workspace. Ignoring ComponentList\n";
+    return;
+  }
+  std::set<detid_t> detectorIDs;
+  for (const auto &compName : componentList) {
+    std::vector<IDetector_const_sptr> dets;
+    instrument->getDetectorsInBank(dets, compName);
+    if (dets.empty()) {
+      const auto component = instrument->getComponentByName(compName);
+      const auto det = boost::dynamic_pointer_cast<const IDetector>(component);
+      if (!det) {
+        g_log.warning() << "No detectors found in component '" << compName
+                        << "'\n";
+        continue;
+      }
+      dets.emplace_back(det);
+    }
+    for (const auto &det : dets) {
+      detectorIDs.emplace(det->getID());
+    }
+  }
+  const auto oldSize = detectorList.size();
+  detectorList.resize(detectorList.size() + detectorIDs.size());
+  auto appendBegin = detectorList.begin() + oldSize;
+  std::copy(detectorIDs.cbegin(), detectorIDs.cend(), appendBegin);
+} // appendToDetectorListFromComponentList
+
 } // namespace DataHandling
 } // namespace Mantid
diff --git a/Framework/DataHandling/src/MergeLogs.cpp b/Framework/DataHandling/src/MergeLogs.cpp
index 6ec1beea82d23f2b02327fe10d09271554079ef4..b371ac206b0b5f977f42ab066075d46e7bf69bf0 100644
--- a/Framework/DataHandling/src/MergeLogs.cpp
+++ b/Framework/DataHandling/src/MergeLogs.cpp
@@ -39,7 +39,7 @@ void Merge2WorkspaceLogs::exec() {
   double logvalue2 = this->getProperty("LogValue2");
 
   // 2. Check
-  if (logname1.size() == 0 || logname2.size() == 0 || mlogname.size() == 0) {
+  if (logname1.empty() || logname2.empty() || mlogname.empty()) {
     g_log.error() << "One or more than one log name is not given!\n";
     throw std::invalid_argument("One or more than one log name is not give");
   }
diff --git a/Framework/DataHandling/src/ModifyDetectorDotDatFile.cpp b/Framework/DataHandling/src/ModifyDetectorDotDatFile.cpp
index 76c392072aebc8f0259735ed0b03c33a67569e43..21f440fdd907d42d45e5cf254d065254b18a4c2b 100644
--- a/Framework/DataHandling/src/ModifyDetectorDotDatFile.cpp
+++ b/Framework/DataHandling/src/ModifyDetectorDotDatFile.cpp
@@ -1,3 +1,4 @@
+#include "MantidAPI/DetectorInfo.h"
 #include "MantidAPI/FileProperty.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidDataHandling/ModifyDetectorDotDatFile.h"
@@ -99,9 +100,6 @@ void ModifyDetectorDotDatFile::exec() {
   // Copy column title line
   getline(in, str);
   out << str << "\n";
-
-  int i = 0;
-
   // Format details
   int pOffset = 3; // Precision of Offset
   int pOther = 5;  // Precision of Other floats
@@ -111,6 +109,8 @@ void ModifyDetectorDotDatFile::exec() {
   int wCode = 6;   // Field width of Code
   int wAng = 12;   // Field width of angles
 
+  const auto &detectorInfo = ws->detectorInfo();
+
   // Read input file line by line, modify line as necessary and put line into
   // output file
   while (getline(in, str)) {
@@ -135,11 +135,9 @@ void ModifyDetectorDotDatFile::exec() {
       istr >> dump; // get phi
 
     if (code == 3) {
-      // This is detector will look for it in workspace and if found use its
-      // position
-      Geometry::IDetector_const_sptr det = ws->getDetectorByID(detID);
-      if (det) {
-        V3D pos = det->getPos();
+      try {
+        // indexOf throws for invalided detID
+        V3D pos = detectorInfo.position(detectorInfo.indexOf(detID));
         double l2;
         double theta;
         double phi;
@@ -158,8 +156,7 @@ void ModifyDetectorDotDatFile::exec() {
         std::string prefix = oss.str();
         std::string suffix = str.substr(width, std::string::npos);
         out << prefix << suffix << "\n";
-        i++;
-      } else { // Detector not found, don't modify
+      } catch (std::out_of_range &) { // Detector not found, don't modify
         out << str << "\n";
       }
     } else {
diff --git a/Framework/DataHandling/src/PDLoadCharacterizations.cpp b/Framework/DataHandling/src/PDLoadCharacterizations.cpp
index c10ec5e890a407b62c12fcb51dae30c56870aff7..13a815e78fbc1091c5c62aaf6a42261cbd522e8f 100644
--- a/Framework/DataHandling/src/PDLoadCharacterizations.cpp
+++ b/Framework/DataHandling/src/PDLoadCharacterizations.cpp
@@ -1,13 +1,18 @@
 #include "MantidDataHandling/PDLoadCharacterizations.h"
 #include "MantidAPI/FileProperty.h"
+#include "MantidAPI/MultipleFileProperty.h"
 #include "MantidAPI/ITableWorkspace.h"
 #include "MantidAPI/TableRow.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidKernel/ArrayProperty.h"
 #include "MantidKernel/Property.h"
 #include "MantidKernel/Strings.h"
+#include "MantidKernel/StringTokenizer.h"
 #include <boost/algorithm/string.hpp>
+#include <boost/regex.hpp>
 #include <fstream>
+#include <set>
+#include <iostream>
 
 using namespace Mantid::API;
 using namespace Mantid::Kernel;
@@ -26,6 +31,61 @@ static const std::string ZERO("0.");
 static const std::string EXP_INI_VAN_KEY("Vana");
 static const std::string EXP_INI_EMPTY_KEY("VanaBg");
 static const std::string EXP_INI_CAN_KEY("MTc");
+// in the filenames vector, each index has a unique location
+static const int F_INDEX_V0 = 0;
+static const int F_INDEX_V1 = 1;
+static const int F_INDEX_EXPINI = 2;
+static const int F_INDEX_SIZE = 3;
+/// matches the header line for the columns in the version=1 style file
+const boost::regex V1_TABLE_REG_EXP{"^freq.*\\s+w.*l.*\\s+"
+                                    "van\\s+van_back\\s+"
+                                    "mt_env\\s+mt_instr(.+)"};
+const boost::regex VERSION_REG_EXP{"^version=([0-9]+)"};
+
+/**
+ * Use the files to determine if there is any "extra" columns that need to be
+ * added to the output TableWorkspace.
+ */
+std::vector<std::string>
+extra_columns(const std::vector<std::string> &filenames) {
+  // only version1 files generate extra columns
+  if (filenames[F_INDEX_V1].empty())
+    return std::vector<std::string>();
+
+  std::set<std::string> columnSet;
+
+  // parse the version1 file
+  std::ifstream file(filenames[F_INDEX_V1].c_str());
+  if (!file) {
+    throw Exception::FileError("Unable to open file", filenames[F_INDEX_V1]);
+  }
+
+  for (std::string line = Strings::getLine(file); !file.eof();
+       Strings::getLine(file, line)) {
+    boost::smatch result;
+    // all instances of table headers
+    if (boost::regex_search(line, result, V1_TABLE_REG_EXP)) {
+      if (result.size() == 2) {
+        line = Strings::strip(result[1]);
+        Kernel::StringTokenizer tokenizer(
+            line, " ", Kernel::StringTokenizer::TOK_IGNORE_EMPTY);
+        for (const auto &token : tokenizer) {
+          columnSet.insert(token);
+        }
+      }
+    }
+    // TODO need to get the "extras" line
+  }
+  file.close();
+
+  // convert the result to a sorted vector
+  std::vector<std::string> columnnames;
+  std::copy(columnSet.begin(), columnSet.end(),
+            std::back_inserter(columnnames));
+  std::sort(columnnames.begin(), columnnames.end());
+
+  return columnnames;
+}
 }
 
 //----------------------------------------------------------------------------------------------
@@ -46,9 +106,9 @@ const std::string PDLoadCharacterizations::category() const {
 /** Initialize the algorithm's properties.
  */
 void PDLoadCharacterizations::init() {
-  declareProperty(
-      make_unique<FileProperty>("Filename", "", FileProperty::Load, ".txt"),
-      "Characterizations file");
+  const auto exts = std::vector<std::string>({".txt"});
+  declareProperty(Kernel::make_unique<MultipleFileProperty>("Filename", exts),
+                  "Characterizations file");
   declareProperty(make_unique<FileProperty>("ExpIniFilename", "",
                                             FileProperty::OptionalLoad, "ini"),
                   "(Optional) exp.ini file used at NOMAD");
@@ -86,46 +146,106 @@ void PDLoadCharacterizations::init() {
 /** Execute the algorithm.
  */
 void PDLoadCharacterizations::exec() {
-  // open the file for reading
-  std::string filename = this->getProperty("Filename");
-  std::ifstream file(filename.c_str());
-  if (!file) {
-    throw Exception::FileError("Unable to open file", filename);
-  }
+  auto filenames = this->getFilenames();
+  const std::vector<std::string> canColumnNames = extra_columns(filenames);
 
-  // read the first line and decide what to do
-  std::string firstLine = Strings::getLine(file);
-  if (firstLine.substr(0, IPARM_KEY.size()) == IPARM_KEY) {
-    firstLine = Strings::strip(firstLine.substr(IPARM_KEY.size()));
-    this->setProperty("IParmFilename", firstLine);
-    this->readFocusInfo(file);
-  } else {
-    // things expect the L1 to be zero if it isn't set
-    this->setProperty("PrimaryFlightPath", 0.);
-  }
-
-  // now the rest of the file
   // setup the default table workspace for the characterization runs
   ITableWorkspace_sptr wksp = WorkspaceFactory::Instance().createTable();
   wksp->addColumn("double", "frequency");
   wksp->addColumn("double", "wavelength");
   wksp->addColumn("int", "bank");
   wksp->addColumn("str", "vanadium");
+  wksp->addColumn("str", "vanadium_background");
   wksp->addColumn("str", "container");
-  wksp->addColumn("str", "empty");
+  wksp->addColumn("str", "empty_environment");
+  wksp->addColumn("str", "empty_instrument");
   wksp->addColumn("str", "d_min"); // b/c it is an array for NOMAD
   wksp->addColumn("str", "d_max"); // b/c it is an array for NOMAD
   wksp->addColumn("double", "tof_min");
   wksp->addColumn("double", "tof_max");
-  this->readCharInfo(file, wksp);
+  wksp->addColumn("double", "wavelength_min");
+  wksp->addColumn("double", "wavelength_max");
+  for (const auto &name : canColumnNames) {
+    wksp->addColumn("str", name); // all will be strings
+  }
+
+  // first file is assumed to be version 0
+  this->readVersion0(filenames[F_INDEX_V0], wksp);
+
+  // optional second file has container dependent information
+  this->readVersion1(filenames[F_INDEX_V1], wksp);
+
+  // optional exp.ini file for NOMAD
+  this->readExpIni(filenames[F_INDEX_EXPINI], wksp);
+
+  this->setProperty("OutputWorkspace", wksp);
+}
+
+int getVersion(const std::string &filename) {
+  std::ifstream file(filename.c_str());
+  if (!file) {
+    throw Exception::FileError("Unable to open file", filename);
+  }
+  // first line must be version string
+  std::string line = Strings::getLine(file);
+
+  boost::smatch result;
+  if (boost::regex_search(line, result, VERSION_REG_EXP) &&
+      result.size() == 2) {
+    return boost::lexical_cast<int>(result[1]);
+  }
+  file.close();
+
+  // otherwise it is a version=0
+  return 0;
+}
+
+/**
+ * This ignores the traditional interpretation of
+ * Mantid::API::MultipleFileProperty
+ * and flattens the array into a simple list of filenames.
+ */
+std::vector<std::string> PDLoadCharacterizations::getFilenames() {
+  // get the values from the "Filename" property
+  std::vector<std::string> filenamesFromPropertyUnraveld;
+  std::vector<std::vector<std::string>> filenamesFromProperty =
+      this->getProperty("Filename");
+  for (auto outer : filenamesFromProperty) {
+    for (auto inner : outer) {
+      filenamesFromPropertyUnraveld.push_back(inner);
+    }
+  }
+  // error check that something sensible was supplied
+  if (filenamesFromPropertyUnraveld.size() > 2) {
+    throw std::runtime_error("Can only specify up to 2 characterization files");
+  }
+
+  // sort out which file is which
+  int v0_index = -1;
+  int v1_index = -1;
+  for (size_t i = 0; i < filenamesFromPropertyUnraveld.size(); ++i) {
+    const int version = getVersion(filenamesFromPropertyUnraveld[i]);
+    g_log.debug() << "Found version " << version << " in \""
+                  << filenamesFromPropertyUnraveld[i] << "\"\n";
+    if (version == 0)
+      v0_index = static_cast<int>(i);
+    else if (version == 1)
+      v1_index = static_cast<int>(i);
+  }
+
+  // fill the output array
+  std::vector<std::string> filenames(F_INDEX_SIZE);
+  if (v0_index >= 0)
+    filenames[F_INDEX_V0] = filenamesFromPropertyUnraveld[v0_index];
+  if (v1_index >= 0)
+    filenames[F_INDEX_V1] = filenamesFromPropertyUnraveld[v1_index];
 
   // optional exp.ini file for NOMAD
   std::string iniFilename = this->getProperty("ExpIniFilename");
   if (!iniFilename.empty()) {
-    this->readExpIni(iniFilename, wksp);
+    filenames[F_INDEX_EXPINI] = iniFilename;
   }
-
-  this->setProperty("OutputWorkspace", wksp);
+  return filenames;
 }
 
 /**
@@ -144,7 +264,7 @@ void PDLoadCharacterizations::readFocusInfo(std::ifstream &file) {
 
   // parse the file
   for (std::string line = Strings::getLine(file); !file.eof();
-       line = Strings::getLine(file)) {
+       Strings::getLine(file, line)) {
     line = Strings::strip(line);
     // skip empty lines and "comments"
     if (line.empty())
@@ -192,11 +312,12 @@ void PDLoadCharacterizations::readCharInfo(std::ifstream &file,
   if (file.eof())
     return;
 
+  const size_t num_of_columns = wksp->columnCount();
+
   // parse the file
   for (std::string line = Strings::getLine(file); !file.eof();
-       line = Strings::getLine(file)) {
+       Strings::getLine(file, line)) {
     line = Strings::strip(line);
-
     // skip empty lines and "comments"
     if (line.empty())
       continue;
@@ -207,7 +328,7 @@ void PDLoadCharacterizations::readCharInfo(std::ifstream &file,
     std::vector<std::string> splitted;
     boost::split(splitted, line, boost::is_any_of("\t "),
                  boost::token_compress_on);
-    while (splitted.size() < 10)
+    while (splitted.size() < 12)
       splitted.push_back(ZERO); // extra values default to zero
 
     // add the row
@@ -216,13 +337,182 @@ void PDLoadCharacterizations::readCharInfo(std::ifstream &file,
     row << boost::lexical_cast<double>(splitted[1]);  // wavelength
     row << boost::lexical_cast<int32_t>(splitted[2]); // bank
     row << splitted[3];                               // vanadium
+    row << splitted[5];                               // vanadium_background
     row << splitted[4];                               // container
-    row << splitted[5];                               // empty
+    row << "0";                                       // empty_environment
+    row << "0";                                       // empty_instrument
     row << splitted[6];                               // d_min
     row << splitted[7];                               // d_max
     row << boost::lexical_cast<double>(splitted[8]);  // tof_min
     row << boost::lexical_cast<double>(splitted[9]);  // tof_max
+    row << boost::lexical_cast<double>(splitted[10]); // wavelength_min
+    row << boost::lexical_cast<double>(splitted[11]); // wavelength_max
+
+    // pad all extras with empty string - the 14 required columns have
+    // already been added to the row
+    for (size_t i = 14; i < num_of_columns; ++i) {
+      row << "0";
+    }
+  }
+}
+
+void PDLoadCharacterizations::readVersion0(const std::string &filename,
+                                           API::ITableWorkspace_sptr &wksp) {
+  // don't bother if there isn't a filename
+  if (filename.empty())
+    return;
+
+  std::ifstream file(filename.c_str());
+  if (!file) {
+    throw Exception::FileError("Unable to open file", filename);
+  }
+
+  // read the first line and decide what to do
+  std::string firstLine = Strings::getLine(file);
+  if (firstLine.substr(0, IPARM_KEY.size()) == IPARM_KEY) {
+    firstLine = Strings::strip(firstLine.substr(IPARM_KEY.size()));
+    this->setProperty("IParmFilename", firstLine);
+    this->readFocusInfo(file);
+  } else {
+    // things expect the L1 to be zero if it isn't set
+    this->setProperty("PrimaryFlightPath", 0.);
+  }
+
+  // now the rest of the file
+  this->readCharInfo(file, wksp);
+
+  file.close();
+}
+
+bool closeEnough(const double left, const double right) {
+  // the same value
+  const double diff = fabs(left - right);
+  if (diff == 0.)
+    return true;
+
+  // same within 5%
+  const double relativeDiff = diff * 2 / (left + right);
+  return relativeDiff < .05;
+}
+
+int findRow(API::ITableWorkspace_sptr &wksp,
+            const std::vector<std::string> &values) {
+  const double frequency = boost::lexical_cast<double>(values[0]);
+  const double wavelength = boost::lexical_cast<double>(values[1]);
+
+  // find the correct row
+  const size_t numRows = wksp->rowCount();
+  for (size_t i = 0; i < numRows; ++i) {
+    const double frequencyRow = wksp->getRef<double>("frequency", i);
+    const double wavelengthRow = wksp->getRef<double>("wavelength", i);
+    if (closeEnough(frequency, frequencyRow) &&
+        closeEnough(wavelength, wavelengthRow)) {
+      return static_cast<int>(i);
+    }
+  }
+  // fall through behavior is -1
+  return -1;
+}
+
+void updateRow(API::ITableWorkspace_sptr &wksp, const size_t rowNum,
+               const std::vector<std::string> &names,
+               const std::vector<std::string> &values) {
+  wksp->getRef<std::string>("vanadium", rowNum) = values[2];
+  wksp->getRef<std::string>("vanadium_background", rowNum) = values[3];
+  wksp->getRef<std::string>("empty_environment", rowNum) = values[4];
+  wksp->getRef<std::string>("empty_instrument", rowNum) = values[5];
+  for (size_t i = 0; i < names.size(); ++i) {
+    const auto name = names[i];
+    wksp->getRef<std::string>(name, rowNum) = values[i + 6];
+  }
+}
+
+void PDLoadCharacterizations::readVersion1(const std::string &filename,
+                                           API::ITableWorkspace_sptr &wksp) {
+  // don't bother if there isn't a filename
+  if (filename.empty())
+    return;
+
+  g_log.information() << "Opening \"" << filename << "\" as a version 1 file\n";
+  std::ifstream file(filename.c_str());
+  if (!file) {
+    throw Exception::FileError("Unable to open file", filename);
+  }
+
+  // first line must be version string
+  std::string line = Strings::getLine(file);
+  boost::smatch result;
+  if (boost::regex_search(line, result, VERSION_REG_EXP) &&
+      result.size() == 2) {
+    g_log.debug() << "Found version " << result[1] << "\n";
+  } else {
+    file.close();
+    throw std::runtime_error("file must have \"version=1\" as the first line");
   }
+
+  // store the names of the columns in order
+  std::vector<std::string> columnNames;
+  for (Strings::getLine(file, line); !file.eof();
+       Strings::getLine(file, line)) {
+    if (line.empty())
+      continue;
+    if (line.substr(0, 1) == "#")
+      continue;
+
+    boost::smatch result;
+    // all instances of table headers
+    if (boost::regex_search(line, result, V1_TABLE_REG_EXP)) {
+      if (result.size() == 2) {
+        line = Strings::strip(result[1]);
+        Kernel::StringTokenizer tokenizer(
+            line, " ", Kernel::StringTokenizer::TOK_IGNORE_EMPTY);
+        for (const auto &token : tokenizer) {
+          columnNames.push_back(token);
+        }
+      }
+    } else {
+      if (columnNames.empty()) // should never happen
+        throw std::runtime_error("file missing column names");
+
+      line = Strings::strip(line);
+      Kernel::StringTokenizer tokenizer(
+          line, " ", Kernel::StringTokenizer::TOK_IGNORE_EMPTY);
+      std::vector<std::string> valuesAsStr;
+      for (const auto &token : tokenizer) {
+        valuesAsStr.push_back(token);
+      }
+
+      const int row = findRow(wksp, valuesAsStr);
+
+      if (row >= 0) {
+        updateRow(wksp, static_cast<size_t>(row), columnNames, valuesAsStr);
+      } else {
+        // add the row
+        API::TableRow row = wksp->appendRow();
+        row << boost::lexical_cast<double>(valuesAsStr[0]); // frequency
+        row << boost::lexical_cast<double>(valuesAsStr[1]); // wavelength
+        row << boost::lexical_cast<int32_t>(1);             // bank
+        row << valuesAsStr[2];                              // vanadium
+        row << valuesAsStr[3]; // vanadium_background
+        row << "0";            // container
+        row << valuesAsStr[4]; // empty_environment
+        row << valuesAsStr[5]; // empty_instrument
+        row << "0";            // d_min
+        row << "0";            // d_max
+        row << 0.;             // tof_min
+        row << 0.;             // tof_max
+        row << 0.;             // wavelength_min
+        row << 0.;             // wavelength_max
+        // insert all the extras
+        for (size_t i = 6; i < valuesAsStr.size(); ++i) {
+          row << valuesAsStr[i];
+        }
+      }
+    }
+    // TODO need to get the extras line
+  }
+
+  file.close();
 }
 
 /**
@@ -232,6 +522,11 @@ void PDLoadCharacterizations::readCharInfo(std::ifstream &file,
  */
 void PDLoadCharacterizations::readExpIni(const std::string &filename,
                                          API::ITableWorkspace_sptr &wksp) {
+  // don't bother if there isn't a filename
+  if (filename.empty())
+    return;
+
+  std::cout << "readExpIni(" << filename << ")" << std::endl;
   if (wksp->rowCount() == 0)
     throw std::runtime_error("Characterizations file does not have any "
                              "characterizations information");
@@ -243,7 +538,7 @@ void PDLoadCharacterizations::readExpIni(const std::string &filename,
 
   // parse the file
   for (std::string line = Strings::getLine(file); !file.eof();
-       line = Strings::getLine(file)) {
+       Strings::getLine(file, line)) {
     line = Strings::strip(line);
     // skip empty lines and "comments"
     if (line.empty())
@@ -262,9 +557,9 @@ void PDLoadCharacterizations::readExpIni(const std::string &filename,
     if (splitted[0] == EXP_INI_VAN_KEY) {
       wksp->getRef<std::string>("vanadium", 0) = splitted[1];
     } else if (splitted[0] == EXP_INI_EMPTY_KEY) {
-      wksp->getRef<std::string>("container", 0) = splitted[1];
+      wksp->getRef<std::string>("vanadium_background", 0) = splitted[1];
     } else if (splitted[0] == EXP_INI_CAN_KEY) {
-      wksp->getRef<std::string>("empty", 0) = splitted[1];
+      wksp->getRef<std::string>("container", 0) = splitted[1];
     }
   }
 }
diff --git a/Framework/DataHandling/src/PatchBBY.cpp b/Framework/DataHandling/src/PatchBBY.cpp
index 8f3887424421e9e0439ab89077cb6fc8bb5da805..5f177a346cec5cb4c761b7b18f7a3da3836786c1 100644
--- a/Framework/DataHandling/src/PatchBBY.cpp
+++ b/Framework/DataHandling/src/PatchBBY.cpp
@@ -301,7 +301,7 @@ void PatchBBY::exec() {
   }
 
   std::string logContentNew = logContentNewBuffer.str();
-  if (logContentNew.size() == 0)
+  if (logContentNew.empty())
     throw std::invalid_argument("nothing to patch");
 
   // merge log content
diff --git a/Framework/DataHandling/src/ProcessDasNexusLog.cpp b/Framework/DataHandling/src/ProcessDasNexusLog.cpp
deleted file mode 100644
index a87966368c30d79d52d00b863b18ae107ff6ae68..0000000000000000000000000000000000000000
--- a/Framework/DataHandling/src/ProcessDasNexusLog.cpp
+++ /dev/null
@@ -1,484 +0,0 @@
-#include "MantidDataHandling/ProcessDasNexusLog.h"
-#include "MantidKernel/System.h"
-#include "MantidKernel/MandatoryValidator.h"
-#include "MantidAPI/MatrixWorkspace.h"
-#include "MantidAPI/Run.h"
-#include "MantidAPI/WorkspaceProperty.h"
-#include "MantidKernel/TimeSeriesProperty.h"
-#include "MantidKernel/Property.h"
-#include "MantidKernel/DateAndTime.h"
-#include "MantidAPI/FileProperty.h"
-
-#include <fstream>
-
-using namespace Mantid::Kernel;
-using namespace Mantid::API;
-
-namespace Mantid {
-namespace DataHandling {
-
-DECLARE_ALGORITHM(ProcessDasNexusLog)
-
-/** Constructor
- */
-ProcessDasNexusLog::ProcessDasNexusLog() : Algorithm(), DeprecatedAlgorithm() {}
-
-void ProcessDasNexusLog::init() {
-  this->declareProperty(
-      make_unique<API::WorkspaceProperty<API::MatrixWorkspace>>(
-          "InputWorkspace", "", Direction::InOut),
-      "The name of the [[EventWorkspace]] to filter events from.");
-  this->declareProperty("LogToProcess", "",
-                        boost::make_shared<MandatoryValidator<std::string>>(),
-                        "The name of sample log to process.");
-  this->declareProperty(
-      "ProcessedLog", "", boost::make_shared<MandatoryValidator<std::string>>(),
-      "The name of the new sample log processed from DAS log.");
-  this->declareProperty(
-      make_unique<API::FileProperty>("OutputDirectory", "",
-                                     API::FileProperty::Directory),
-      "The directory for some other examination files to be written to.");
-  this->declareProperty(
-      "NumberOfOutputs", 4000,
-      "Number of log entries to be written to a file for examination.");
-  this->declareProperty(
-      make_unique<API::FileProperty>("OutputLogFile", "",
-                                     API::FileProperty::OptionalSave),
-      "The file name for the output data file. ");
-}
-
-void ProcessDasNexusLog::exec() {
-  // 1. Get input
-  API::MatrixWorkspace_sptr inWS = getProperty("InputWorkspace");
-  std::string inlogname = getProperty("LogToProcess");
-  std::string outlogname = getProperty("ProcessedLog");
-  int numentriesoutput = getProperty("NumberOfOutputs");
-  std::string outputfilename = getProperty("OutputLogFile");
-
-  // 2. Check Input
-  // 1. Get log
-  Kernel::Property *log(nullptr);
-  try {
-    log = inWS->run().getProperty(inlogname);
-  } catch (Exception::NotFoundError &) {
-    // Will trigger non-existent log message below
-  }
-  if (!log) {
-    g_log.error() << "Log " << inlogname << " does not exist!\n";
-    throw std::invalid_argument("Non-existent log name");
-  }
-  Kernel::TimeSeriesProperty<double> *tslog =
-      dynamic_cast<Kernel::TimeSeriesProperty<double> *>(log);
-  if (!tslog) {
-    g_log.error() << "Log " << inlogname << " is not time series log\n";
-    throw std::invalid_argument("Log type error!");
-  }
-
-  // 3. Do some check for log statistic
-  checkLog(inWS, inlogname);
-
-  // 3. Convert Das log to log for absolute time
-  std::vector<Kernel::DateAndTime> abstimevec;
-  std::vector<double> orderedtofs;
-  convertToAbsoluteTime(inWS, inlogname, abstimevec, orderedtofs);
-
-  // 4. Add vector to log
-  addLog(inWS, abstimevec, 1.0, outlogname, tslog->timesAsVector(), orderedtofs,
-         false);
-
-  // 5. Optionally write out log to
-  if (numentriesoutput > 0) {
-    this->writeLogtoFile(inWS, inlogname, static_cast<size_t>(numentriesoutput),
-                         outputfilename);
-  }
-}
-
-/*
- * Add and check log from processed absolute time stamps
- */
-void ProcessDasNexusLog::addLog(API::MatrixWorkspace_sptr ws,
-                                std::vector<Kernel::DateAndTime> timevec,
-                                double unifylogvalue, std::string logname,
-                                std::vector<Kernel::DateAndTime> pulsetimes,
-                                std::vector<double> orderedtofs, bool docheck) {
-  // 1. Do some static
-  g_log.notice() << "Vector size = " << timevec.size() << '\n';
-  double sum1dtms = 0.0; // sum(dt^2)
-  double sum2dtms = 0.0; // sum(dt^2)
-  size_t numinvert = 0;
-  size_t numsame = 0;
-  size_t numnormal = 0;
-  double maxdtms = 0;
-  double mindtms = 1.0E20;
-  size_t numdtabove10p = 0;
-  size_t numdtbelow10p = 0;
-
-  double sampledtms = 0.00832646 * 1.0E6;
-  double dtmsA10p = sampledtms * 1.1;
-  double dtmsB10p = sampledtms / 1.0;
-
-  for (size_t i = 1; i < timevec.size(); i++) {
-    int64_t dtns =
-        timevec[i].totalNanoseconds() - timevec[i - 1].totalNanoseconds();
-    double dtms = static_cast<double>(dtns) * 1.0E-3;
-
-    sum1dtms += dtms;
-    sum2dtms += dtms * dtms;
-    if (dtns == 0)
-      numsame++;
-    else if (dtns < 0)
-      numinvert++;
-    else
-      numnormal++;
-
-    if (dtms > maxdtms)
-      maxdtms = dtms;
-    if (dtms < mindtms)
-      mindtms = dtms;
-
-    if (dtms > dtmsA10p)
-      numdtabove10p++;
-    else if (dtms < dtmsB10p)
-      numdtbelow10p++;
-
-  } // ENDFOR
-
-  double dt = sum1dtms / static_cast<double>(timevec.size()) * 1.0E-6;
-  double stddt =
-      sqrt(sum2dtms / static_cast<double>(timevec.size()) * 1.0E-12 - dt * dt);
-
-  g_log.notice() << "Normal   dt = " << numnormal << '\n';
-  g_log.notice() << "Zero     dt = " << numsame << '\n';
-  g_log.notice() << "Negative dt = " << numinvert << '\n';
-  g_log.notice() << "Avg d(T) = " << dt << " seconds +/- " << stddt
-                 << ",  Frequency = " << 1.0 / dt << '\n';
-  g_log.notice() << "d(T) (unit ms) is in range [" << mindtms << ", " << maxdtms
-                 << "]\n";
-  g_log.notice() << "Number of d(T) 10% larger than average  = "
-                 << numdtabove10p << '\n';
-  g_log.notice() << "Number of d(T) 10% smaller than average = "
-                 << numdtbelow10p << '\n';
-
-  g_log.notice() << "Size of timevec, pulsestimes, orderedtofs = "
-                 << timevec.size() << ", " << pulsetimes.size() << ", "
-                 << orderedtofs.size() << '\n';
-
-  if (docheck) {
-    exportErrorLog(ws, timevec, pulsetimes, orderedtofs, 1 / (0.5 * 240.1));
-    calDistributions(timevec, 1 / (0.5 * 240.1));
-  }
-
-  // 2. Add log
-  auto newlog = new Kernel::TimeSeriesProperty<double>(logname);
-  for (auto &time : timevec) {
-    newlog->addValue(time, unifylogvalue);
-  }
-  ws->mutableRun().addProperty(newlog, true);
-}
-
-/*
- * Export time stamps looking erroreous
- */
-void ProcessDasNexusLog::exportErrorLog(
-    API::MatrixWorkspace_sptr ws, std::vector<Kernel::DateAndTime> abstimevec,
-    std::vector<Kernel::DateAndTime> pulsetimes,
-    std::vector<double> orderedtofs, double dts) {
-  std::string outputdir = getProperty("OutputDirectory");
-  if (outputdir.back() != '/')
-    outputdir += "/";
-
-  std::string ofilename = outputdir + "errordeltatime.txt";
-  g_log.notice() << ofilename << '\n';
-  std::ofstream ofs;
-  ofs.open(ofilename.c_str(), std::ios::out);
-
-  size_t numbaddt = 0;
-  Kernel::DateAndTime t0(ws->run().getProperty("run_start")->value());
-
-  for (size_t i = 1; i < abstimevec.size(); i++) {
-    double tempdts = static_cast<double>(abstimevec[i].totalNanoseconds() -
-                                         abstimevec[i - 1].totalNanoseconds()) *
-                     1.0E-9;
-    double dev = (tempdts - dts) / dts;
-    bool baddt = false;
-    if (fabs(dev) > 0.5)
-      baddt = true;
-
-    if (baddt) {
-      numbaddt++;
-      double deltapulsetimeSec1 =
-          static_cast<double>(pulsetimes[i - 1].totalNanoseconds() -
-                              t0.totalNanoseconds()) *
-          1.0E-9;
-      double deltapulsetimeSec2 =
-          static_cast<double>(pulsetimes[i].totalNanoseconds() -
-                              t0.totalNanoseconds()) *
-          1.0E-9;
-      int index1 = static_cast<int>(deltapulsetimeSec1 * 60);
-      int index2 = static_cast<int>(deltapulsetimeSec2 * 60);
-
-      ofs << "Error d(T) = " << tempdts << "   vs   Correct d(T) = " << dts
-          << '\n';
-      ofs << index1 << "\t\t" << pulsetimes[i - 1].totalNanoseconds() << "\t\t"
-          << orderedtofs[i - 1] << '\n';
-      ofs << index2 << "\t\t" << pulsetimes[i].totalNanoseconds() << "\t\t"
-          << orderedtofs[i] << '\n';
-    }
-  }
-
-  ofs.close();
-}
-
-/*
- * Output distributions in order for a better understanding of the log
- * @param dts: d(T) in second
- */
-void ProcessDasNexusLog::calDistributions(
-    std::vector<Kernel::DateAndTime> timevec, double dts) {
-  // 1. Calculate percent deviation vs. number of cases
-  std::vector<double> x1, y1;
-  for (int i = -99; i < 100; i++) {
-    x1.push_back(static_cast<double>(i));
-    y1.push_back(0);
-  }
-
-  for (size_t i = 1; i < timevec.size(); i++) {
-    double tempdts = static_cast<double>(timevec[i].totalNanoseconds() -
-                                         timevec[i - 1].totalNanoseconds()) *
-                     1.0E-9;
-    int index = static_cast<int>((tempdts - dts) / dts * 100) + 99;
-    if (index < 0)
-      index = 0;
-    else if (index > 199)
-      index = 19;
-    y1[static_cast<size_t>(index)]++;
-  }
-
-  /* Skip output */
-  for (size_t i = 0; i < x1.size(); i++)
-    g_log.notice() << i << "\t\t" << x1[i] << "\t\t" << y1[i] << '\n';
-  /**/
-
-  // 2. Calculate space distribution on error cases
-  std::vector<double> x2s;
-  std::vector<size_t> y2;
-
-  size_t numperiods = 100;
-  int64_t spanns =
-      timevec.back().totalNanoseconds() - timevec.front().totalNanoseconds();
-  double timestepsec =
-      static_cast<double>(spanns) * 1.0E-9 / static_cast<double>(numperiods);
-
-  for (size_t i = 0; i < numperiods; i++) {
-    x2s.push_back(static_cast<double>(i) * timestepsec);
-    y2.push_back(0);
-  }
-
-  size_t numbaddt = 0;
-  for (size_t i = 1; i < timevec.size(); i++) {
-    double tempdts = static_cast<double>(timevec[i].totalNanoseconds() -
-                                         timevec[i - 1].totalNanoseconds()) *
-                     1.0E-9;
-    double dev = (tempdts - dts) / dts;
-    bool baddt = false;
-    if (fabs(dev) > 0.5)
-      baddt = true;
-
-    if (baddt) {
-      numbaddt++;
-      int index =
-          static_cast<int>(static_cast<double>(timevec[i].totalNanoseconds() -
-                                               timevec[0].totalNanoseconds()) *
-                           1.0E-9 / timestepsec);
-      if (index < 0)
-        throw std::runtime_error("Impossible to have index less than 0");
-      if (index >= static_cast<int>(numperiods)) {
-        g_log.error() << "Logic error X\n";
-        index = static_cast<int>(numperiods) - 1;
-      }
-      y2[static_cast<size_t>(index)]++;
-    }
-  } // ENDFOR
-
-  /* Skip
-  for (size_t i = 0; i < x2s.size(); i ++)
-    g_log.notice() << i << "\t\t" << x2s[i] << "\t\t" << y2[i] << '\n';
-    */
-  g_log.notice() << "total number of wrong dt = " << numbaddt << '\n';
-}
-
-/*
- * Check log in workspace
- */
-void ProcessDasNexusLog::checkLog(API::MatrixWorkspace_sptr ws,
-                                  std::string logname) {
-  // 1. Get log
-  Kernel::Property *log = ws->run().getProperty(logname);
-  if (!log) {
-    g_log.error() << "Log " << logname << " does not exist!\n";
-    throw std::invalid_argument("Non-exising log name");
-  }
-  Kernel::TimeSeriesProperty<double> *tslog =
-      dynamic_cast<Kernel::TimeSeriesProperty<double> *>(log);
-  if (!tslog) {
-    g_log.error() << "Log " << logname << " is not time series log\n";
-    throw std::invalid_argument("Log type error!");
-  }
-
-  // 2. Survey
-  std::vector<Kernel::DateAndTime> times = tslog->timesAsVector();
-  g_log.information() << "Entries of times = " << times.size() << '\n';
-  size_t countsame = 0;
-  size_t countinverse = 0;
-  for (size_t i = 1; i < times.size(); i++) {
-    Kernel::DateAndTime tprev = times[i - 1];
-    Kernel::DateAndTime tpres = times[i];
-    if (tprev == tpres)
-      countsame++;
-    else if (tprev > tpres)
-      countinverse++;
-  }
-
-  // 3. Output
-  Kernel::DateAndTime t0(ws->run().getProperty("run_start")->value());
-  Kernel::time_duration dts = times.front() - t0;
-  Kernel::time_duration dtf = times.back() - t0;
-  size_t f = times.size() - 1;
-
-  g_log.information() << "Number of Equal Time Stamps    = " << countsame
-                      << '\n';
-  g_log.information() << "Number of Inverted Time Stamps = " << countinverse
-                      << '\n';
-  g_log.information() << "Run Start = " << t0.totalNanoseconds() << '\n';
-  g_log.information() << "First Log (Absolute Time, Relative Time): "
-                      << times[0].totalNanoseconds() << ", "
-                      << Kernel::DateAndTime::nanosecondsFromDuration(dts)
-                      << '\n';
-  g_log.information() << "Last  Log (Absolute Time, Relative Time): "
-                      << times[f].totalNanoseconds() << ", "
-                      << Kernel::DateAndTime::nanosecondsFromDuration(dtf)
-                      << '\n';
-}
-
-/*
- * Convert DAS log to a vector of absolute time
- * @param  orderedtofs: tofs with abstimevec
- */
-void ProcessDasNexusLog::convertToAbsoluteTime(
-    API::MatrixWorkspace_sptr ws, std::string logname,
-    std::vector<Kernel::DateAndTime> &abstimevec,
-    std::vector<double> &orderedtofs) {
-  // 1. Get log
-  Kernel::Property *log = ws->run().getProperty(logname);
-  Kernel::TimeSeriesProperty<double> *tslog =
-      dynamic_cast<Kernel::TimeSeriesProperty<double> *>(log);
-  if (!tslog)
-    throw std::runtime_error("Invalid time series log: it could not be cast "
-                             "(interpreted) as a time series property");
-  std::vector<Kernel::DateAndTime> times = tslog->timesAsVector();
-  std::vector<double> values = tslog->valuesAsVector();
-
-  // 2. Get converted
-  size_t numsamepulses = 0;
-  std::vector<double> tofs;
-  Kernel::DateAndTime prevtime(0);
-
-  for (size_t i = 0; i < times.size(); i++) {
-    Kernel::DateAndTime tnow = times[i];
-    if (tnow > prevtime) {
-      // (a) Process previous logs
-      std::sort(tofs.begin(), tofs.end());
-      for (double tof : tofs) {
-        Kernel::DateAndTime temptime =
-            prevtime + static_cast<int64_t>(tof * 100);
-        abstimevec.push_back(temptime);
-        orderedtofs.push_back(tof);
-      }
-      // (b) Clear
-      tofs.clear();
-      // (c) Update time
-      prevtime = tnow;
-    } else {
-      numsamepulses++;
-    }
-    // (d) Push the current value
-    tofs.push_back(values[i]);
-  } // ENDFOR
-  // Clear the last
-  if (!tofs.empty()) {
-    // (a) Process previous logs: note value is in unit of 100 nano-second
-    std::sort(tofs.begin(), tofs.end());
-    for (double tof : tofs) {
-      Kernel::DateAndTime temptime = prevtime + static_cast<int64_t>(tof * 100);
-      abstimevec.push_back(temptime);
-      orderedtofs.push_back(tof);
-    }
-  } else {
-    throw std::runtime_error("Impossible for this to happen!");
-  }
-} // END Function
-
-/*
- * Write a certain number of log entries (from beginning) to file
- */
-void ProcessDasNexusLog::writeLogtoFile(API::MatrixWorkspace_sptr ws,
-                                        std::string logname,
-                                        size_t numentriesoutput,
-                                        std::string outputfilename) {
-  // 1. Get log
-  Kernel::Property *log = ws->run().getProperty(logname);
-  Kernel::TimeSeriesProperty<double> *tslog =
-      dynamic_cast<Kernel::TimeSeriesProperty<double> *>(log);
-  if (!tslog)
-    throw std::runtime_error("Invalid time series log: it could not be cast "
-                             "(interpreted) as a time series property");
-  std::vector<Kernel::DateAndTime> times = tslog->timesAsVector();
-  std::vector<double> values = tslog->valuesAsVector();
-
-  // 2. Write out
-  std::ofstream ofs;
-  ofs.open(outputfilename.c_str(), std::ios::out);
-  ofs << "# Absolute Time (nanosecond)\tPulse Time (nanosecond)\tTOF (ms)\n";
-
-  Kernel::DateAndTime prevtime(0);
-  std::vector<double> tofs;
-
-  for (size_t i = 0; i < numentriesoutput; i++) {
-    Kernel::DateAndTime tnow = times[i];
-
-    if (tnow > prevtime) {
-      // (a) Process previous logs
-      std::sort(tofs.begin(), tofs.end());
-      for (double tof : tofs) {
-        Kernel::DateAndTime temptime =
-            prevtime + static_cast<int64_t>(tof * 100);
-        ofs << temptime.totalNanoseconds() << "\t" << tnow.totalNanoseconds()
-            << "\t" << tof * 0.1 << '\n';
-      }
-      // (b) Clear
-      tofs.clear();
-      // (c) Update time
-      prevtime = tnow;
-    }
-
-    // (d) Push the current value
-    tofs.push_back(values[i]);
-  } // ENDFOR
-  // Clear the last
-  if (!tofs.empty()) {
-    // (a) Process previous logs: note value is in unit of 100 nano-second
-    std::sort(tofs.begin(), tofs.end());
-    for (double tof : tofs) {
-      Kernel::DateAndTime temptime = prevtime + static_cast<int64_t>(tof * 100);
-      ofs << temptime.totalNanoseconds() << "\t" << prevtime.totalNanoseconds()
-          << "\t" << tof * 0.1 << '\n';
-    }
-  } else {
-    throw std::runtime_error("Impossible for this to happen!");
-  }
-
-  ofs.close();
-} // END Function
-
-} // namespace Mantid
-} // namespace DataHandling
diff --git a/Framework/DataHandling/src/SaveAscii2.cpp b/Framework/DataHandling/src/SaveAscii2.cpp
index bd5d594f1bcb694298de522a5b93a8a4fccfd0c6..7e63abebc5582afc6d2258a555199ef2769c33c0 100644
--- a/Framework/DataHandling/src/SaveAscii2.cpp
+++ b/Framework/DataHandling/src/SaveAscii2.cpp
@@ -1,12 +1,10 @@
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include <set>
 #include <fstream>
 
 #include "MantidDataHandling/SaveAscii2.h"
 #include "MantidAPI/FileProperty.h"
 #include "MantidAPI/MatrixWorkspace.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidGeometry/Instrument.h"
 #include "MantidKernel/ArrayProperty.h"
 #include "MantidKernel/BoundedValidator.h"
@@ -129,7 +127,7 @@ void SaveAscii2::exec() {
   m_isCommonBins = m_ws->isCommonBins(); // checking for ragged workspace
   m_writeID = getProperty("WriteSpectrumID");
   std::string metaDataString = getPropertyValue("SpectrumMetaData");
-  if (metaDataString.size() != 0) {
+  if (!metaDataString.empty()) {
     m_metaData = stringListToVector(metaDataString);
     auto containsSpectrumNumber =
         findElementInUnorderedStringVector(m_metaData, "spectrumnumber");
@@ -256,7 +254,7 @@ void SaveAscii2::exec() {
     file << '\n';
   }
   // populate the meta data map
-  if (m_metaData.size() > 0) {
+  if (!m_metaData.empty()) {
     populateAllMetaData();
   }
   if (idx.empty()) {
@@ -399,24 +397,26 @@ SaveAscii2::stringListToVector(std::string &inputString) {
 void SaveAscii2::populateQMetaData() {
   std::vector<std::string> qValues;
   const auto nHist = m_ws->getNumberHistograms();
+  const auto &spectrumInfo = m_ws->spectrumInfo();
   for (size_t i = 0; i < nHist; i++) {
     const auto specNo = m_ws->getSpectrum(i).getSpectrumNo();
     const auto workspaceIndex = m_specToIndexMap[specNo];
-    const auto detector = m_ws->getDetector(workspaceIndex);
-    double twoTheta(0.0), efixed(0.0);
-    if (!detector->isMonitor()) {
-      twoTheta = 0.5 * m_ws->detectorTwoTheta(*detector);
+    double theta(0.0), efixed(0.0);
+    if (!spectrumInfo.isMonitor(workspaceIndex)) {
+      theta = 0.5 * spectrumInfo.twoTheta(workspaceIndex);
       try {
+        boost::shared_ptr<const Geometry::IDetector> detector(
+            &spectrumInfo.detector(workspaceIndex), NoDeleting());
         efixed = m_ws->getEFixed(detector);
       } catch (std::runtime_error) {
         throw;
       }
     } else {
-      twoTheta = 0.0;
+      theta = 0.0;
       efixed = DBL_MIN;
     }
     // Convert to MomentumTransfer
-    auto qValue = Kernel::UnitConversion::run(twoTheta, efixed);
+    auto qValue = Kernel::UnitConversion::run(theta, efixed);
     auto qValueStr = boost::lexical_cast<std::string>(qValue);
     qValues.push_back(qValueStr);
   }
diff --git a/Framework/DataHandling/src/SaveCSV.cpp b/Framework/DataHandling/src/SaveCSV.cpp
index 72edec787aad196f00e8a92ef108709c091b78ea..d4ec94836026b51923a0731bc7b5deb90494071a 100644
--- a/Framework/DataHandling/src/SaveCSV.cpp
+++ b/Framework/DataHandling/src/SaveCSV.cpp
@@ -19,14 +19,12 @@
  File change history is stored at: <https://github.com/mantidproject/mantid>
  */
 
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidDataHandling/SaveCSV.h"
 #include "MantidDataObjects/Workspace2D.h"
 #include "MantidAPI/FileProperty.h"
 
 #include <fstream> // used to get ofstream
+#include <iomanip>
 
 /* @class SaveCSV
 
diff --git a/Framework/DataHandling/src/SaveCalFile.cpp b/Framework/DataHandling/src/SaveCalFile.cpp
index 117dd7e38cf6cb9008295600c76ffe74bd904a4f..7baa585f620ebeac83d80495ea880fbbe16e4552 100644
--- a/Framework/DataHandling/src/SaveCalFile.cpp
+++ b/Framework/DataHandling/src/SaveCalFile.cpp
@@ -95,7 +95,7 @@ void SaveCalFile::saveCalFile(const std::string &calFileName,
     doMask = true;
     inst = maskWS->getInstrument();
     if (!inst)
-      g_log.warning() << "Mask workspace " << maskWS->name()
+      g_log.warning() << "Mask workspace " << maskWS->getName()
                       << " has no instrument associated with."
                       << "\n";
   }
diff --git a/Framework/DataHandling/src/SaveCanSAS1D.cpp b/Framework/DataHandling/src/SaveCanSAS1D.cpp
index 04915a0708262b9a1dfde19c621cdbb8e376d6dd..a5c568833fb8d526c7dab603080b011e6ce2fca8 100644
--- a/Framework/DataHandling/src/SaveCanSAS1D.cpp
+++ b/Framework/DataHandling/src/SaveCanSAS1D.cpp
@@ -1,6 +1,3 @@
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidDataHandling/SaveCanSAS1D.h"
 
 #include "MantidAPI/FileProperty.h"
@@ -16,8 +13,9 @@
 #include "MantidKernel/ListValidator.h"
 
 #include <boost/shared_ptr.hpp>
+#include <boost/algorithm/string/split.hpp>
+#include <boost/algorithm/string/trim.hpp>
 
-//-----------------------------------------------------------------------------
 namespace {
 void encode(std::string &data) {
   std::string buffer;
@@ -578,7 +576,7 @@ void SaveCanSAS1D::createSASDetectorElement(std::string &sasDet) {
     } else {
       g_log.notice() << "Detector with name " << detectorName
                      << " does not exist in the instrument of the workspace: "
-                     << m_workspace->name() << '\n';
+                     << m_workspace->getName() << '\n';
     }
   }
 }
@@ -640,10 +638,28 @@ void SaveCanSAS1D::createSASProcessElement(std::string &sasProcess) {
 }
 
 /** This method creates an XML element named "SASinstrument"
+ *
+ * The structure for required(r) parts of the SASinstrument and the parts
+ * we want to add is:
+ *
+ * SASinstrument
+ *   name(r)
+ *   SASsource(r)
+ *     radiation(r)
+ *   SAScollimation(r)
+ *     aperature[name]
+ *       size
+ *         x[units]
+ *         y[units]
+ *   SASdetector
+ *     name
+ *
 *  @param sasInstrument :: string for sasinstrument element in the xml
 */
 void SaveCanSAS1D::createSASInstrument(std::string &sasInstrument) {
   sasInstrument = "\n\t\t<SASinstrument>";
+
+  // Set name(r)
   std::string sasInstrName = "\n\t\t\t<name>";
   std::string instrname = m_workspace->getInstrument()->getName();
   // look for xml special characters and replace with entity refrence
@@ -652,10 +668,12 @@ void SaveCanSAS1D::createSASInstrument(std::string &sasInstrument) {
   sasInstrName += "</name>";
   sasInstrument += sasInstrName;
 
+  // Set SASsource(r)
   std::string sasSource;
   createSASSourceElement(sasSource);
   sasInstrument += sasSource;
 
+  // Set SAScollimation(r)
   // Add the collimation. We add the collimation information if
   // either the width of the height is different from 0
   double collimationHeight = getProperty("SampleHeight");
@@ -663,19 +681,29 @@ void SaveCanSAS1D::createSASInstrument(std::string &sasInstrument) {
   std::string sasCollimation = "\n\t\t\t<SAScollimation/>";
   if (collimationHeight > 0 || collimationWidth > 0) {
     sasCollimation = "\n\t\t\t<SAScollimation>";
-    // Geometry
+
+    // aperture with name
     std::string collimationGeometry = getProperty("Geometry");
-    sasCollimation += "\n\t\t\t\t<name>" + collimationGeometry + "</name>";
-    // Width
     sasCollimation +=
-        "\n\t\t\t\t<X unit=\"mm\">" + std::to_string(collimationWidth) + "</X>";
+        "\n\t\t\t\t<aperture name=\"" + collimationGeometry + "\">";
+
+    // size
+    sasCollimation += "\n\t\t\t\t\t<size>";
+
+    // Width
+    sasCollimation += "\n\t\t\t\t\t\t<x unit=\"mm\">" +
+                      std::to_string(collimationWidth) + "</x>";
     // Height
-    sasCollimation += "\n\t\t\t\t<Y unit=\"mm\">" +
-                      std::to_string(collimationHeight) + "</Y>";
+    sasCollimation += "\n\t\t\t\t\t\t<y unit=\"mm\">" +
+                      std::to_string(collimationHeight) + "</y>";
+
+    sasCollimation += "\n\t\t\t\t\t</size>";
+    sasCollimation += "\n\t\t\t\t</aperture>";
     sasCollimation += "\n\t\t\t</SAScollimation>";
   }
   sasInstrument += sasCollimation;
 
+  // Set SASdetector
   std::string sasDet;
   createSASDetectorElement(sasDet);
   sasInstrument += sasDet;
diff --git a/Framework/DataHandling/src/SaveDiffFittingAscii.cpp b/Framework/DataHandling/src/SaveDiffFittingAscii.cpp
index f0422f8941b6ca02c2c9933e4668109cb8e90124..b9c75fdd93de58cf5a69a6dc2771e69ff1b57c40 100644
--- a/Framework/DataHandling/src/SaveDiffFittingAscii.cpp
+++ b/Framework/DataHandling/src/SaveDiffFittingAscii.cpp
@@ -1,10 +1,8 @@
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidDataHandling/SaveDiffFittingAscii.h"
 
 #include "MantidAPI/FileProperty.h"
 #include "MantidAPI/TableRow.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidDataObjects/TableWorkspace.h"
 #include "MantidKernel/ListValidator.h"
 #include "MantidKernel/MandatoryValidator.h"
diff --git a/Framework/DataHandling/src/SaveDspacemap.cpp b/Framework/DataHandling/src/SaveDspacemap.cpp
index 34d8e59ddcfe26f2ea847221934b17984f681ce1..92352c01a35ae5051c37b8b0e2ca419bc389d8f5 100644
--- a/Framework/DataHandling/src/SaveDspacemap.cpp
+++ b/Framework/DataHandling/src/SaveDspacemap.cpp
@@ -86,9 +86,9 @@ void SaveDspacemap::CalculateDspaceFromCal(
     it = allDetectors.find(i);
     if (it != allDetectors.end()) {
       det = it->second;
-      factor =
-          Instrument::calcConversion(l1, beamline, beamline_norm, samplePos,
-                                     det, offsetsWS->getValue(i, 0.0));
+      factor = Instrument::calcConversion(l1, beamline, beamline_norm,
+                                          samplePos, det->getPos(),
+                                          offsetsWS->getValue(i, 0.0));
       // Factor of 10 between ISAW and Mantid
       factor *= 0.1;
       if (factor < 0)
diff --git a/Framework/DataHandling/src/SaveFITS.cpp b/Framework/DataHandling/src/SaveFITS.cpp
index aee2911ddbb392259e72612c4ece6e041c6cf7d3..2a8c458c504f2afb6155947486e4d7a96b21ca7a 100644
--- a/Framework/DataHandling/src/SaveFITS.cpp
+++ b/Framework/DataHandling/src/SaveFITS.cpp
@@ -7,6 +7,7 @@
 #include "MantidKernel/make_unique.h"
 
 #include <fstream>
+#include <iomanip>
 
 #include <boost/pointer_cast.hpp>
 
diff --git a/Framework/DataHandling/src/SaveFullprofResolution.cpp b/Framework/DataHandling/src/SaveFullprofResolution.cpp
index 39047131ac7bba532d80a25fc3023fcdb0b64708..0e508d349dcd80f9910cd4bd3486162629a7ee36 100644
--- a/Framework/DataHandling/src/SaveFullprofResolution.cpp
+++ b/Framework/DataHandling/src/SaveFullprofResolution.cpp
@@ -9,6 +9,7 @@
 #include <Poco/File.h>
 
 #include <fstream>
+#include <iomanip>
 
 using namespace Mantid;
 using namespace Mantid::API;
@@ -117,7 +118,7 @@ void SaveFullprofResolution::processProperties() {
 
   // Output file and operation
   m_outIrfFilename = getPropertyValue("OutputFilename");
-  if (m_outIrfFilename.size() == 0)
+  if (m_outIrfFilename.empty())
     throw runtime_error("Input file name invalid. ");
   m_append = getProperty("Append");
   if (m_append) {
diff --git a/Framework/DataHandling/src/SaveGSASInstrumentFile.cpp b/Framework/DataHandling/src/SaveGSASInstrumentFile.cpp
index 812f2b15f9a284ab468843dd9f69dd012bb21522..8c98bf1e5ee7453d4890e8c9bee6ab544966af5a 100644
--- a/Framework/DataHandling/src/SaveGSASInstrumentFile.cpp
+++ b/Framework/DataHandling/src/SaveGSASInstrumentFile.cpp
@@ -6,7 +6,11 @@
 #include "MantidKernel/BoundedValidator.h"
 #include "MantidAPI/TableRow.h"
 
+#include <boost/algorithm/string/classification.hpp>
+#include <boost/algorithm/string/split.hpp>
+
 #include <cstdio>
+#include <iomanip>
 
 using namespace Mantid;
 using namespace Mantid::API;
@@ -230,7 +234,7 @@ ChopperConfiguration::parseStringDbl(const string &instring) const {
 
   vector<double> vecdouble;
   for (auto &str : strs) {
-    if (str.size() > 0) {
+    if (!str.empty()) {
       double item = atof(str.c_str());
       vecdouble.push_back(item);
       // cout << "[C] |" << strs[i] << "|" << item << "\n";
@@ -253,7 +257,7 @@ ChopperConfiguration::parseStringUnsignedInt(const string &instring) const {
 
   vector<unsigned int> vecinteger;
   for (auto &str : strs) {
-    if (str.size() > 0) {
+    if (!str.empty()) {
       int item = atoi(str.c_str());
       if (item < 0) {
         throw runtime_error(
diff --git a/Framework/DataHandling/src/SaveGSS.cpp b/Framework/DataHandling/src/SaveGSS.cpp
index fa9c252fb9e2e7dc7b8e0bd1b9b5f747dfd3daaa..c338cb5e684b01bb1c590e2ae57979d409890e03 100644
--- a/Framework/DataHandling/src/SaveGSS.cpp
+++ b/Framework/DataHandling/src/SaveGSS.cpp
@@ -3,6 +3,8 @@
 #include "MantidAPI/AlgorithmHistory.h"
 #include "MantidAPI/FileProperty.h"
 #include "MantidAPI/Run.h"
+#include "MantidAPI/SpectrumInfo.h"
+#include "MantidAPI/WorkspaceHistory.h"
 #include "MantidAPI/WorkspaceUnitValidator.h"
 #include "MantidGeometry/Instrument.h"
 #include "MantidKernel/TimeSeriesProperty.h"
@@ -112,7 +114,7 @@ void getFocusedPos(MatrixWorkspace_const_sptr wksp, const int spectrum,
   Geometry::IDetector_const_sptr det = wksp->getDetector(spectrum);
   if (!det) {
     std::stringstream errss;
-    errss << "Workspace " << wksp->name()
+    errss << "Workspace " << wksp->getName()
           << " does not have detector with spectrum " << spectrum;
     throw std::runtime_error(errss.str());
   }
@@ -160,8 +162,7 @@ void SaveGSS::exec() {
 
   // Check whether append or not
   if (!split) {
-    const std::string file(filename);
-    Poco::File fileobj(file);
+    Poco::File fileobj(filename);
     if (fileobj.exists() && !append) {
       // Non-append mode and will be overwritten
       g_log.warning() << "Target GSAS file " << filename
@@ -208,19 +209,17 @@ void SaveGSS::writeGSASFile(const std::string &outfilename, bool append,
   int nHist = static_cast<int>(inputWS->getNumberHistograms());
   Progress p(this, 0.0, 1.0, nHist);
 
+  const auto &spectrumInfo = inputWS->spectrumInfo();
   for (int iws = 0; iws < nHist; iws++) {
     // Determine whether to skip the spectrum due to being masked
     if (has_instrument) {
-      try {
-        Geometry::IDetector_const_sptr det =
-            inputWS->getDetector(static_cast<size_t>(iws));
-        if (det->isMasked())
-          continue;
-      } catch (const Kernel::Exception::NotFoundError &) {
+      if (!spectrumInfo.hasDetectors(iws)) {
         has_instrument = false;
         g_log.warning() << "There is no detector associated with spectrum "
                         << iws
                         << ". Workspace is treated as NO-INSTRUMENT case. \n";
+      } else if (spectrumInfo.isMasked(iws)) {
+        continue;
       }
     }
 
diff --git a/Framework/DataHandling/src/SaveILLCosmosAscii.cpp b/Framework/DataHandling/src/SaveILLCosmosAscii.cpp
index 90168b7fc8c1daff24307f474ce62db530d20b15..14dc26d624879c976a0759dd9f6eaeb6727ebabb 100644
--- a/Framework/DataHandling/src/SaveILLCosmosAscii.cpp
+++ b/Framework/DataHandling/src/SaveILLCosmosAscii.cpp
@@ -21,6 +21,7 @@ void SaveILLCosmosAscii::extraProps() {
   declareProperty("UserContact", "",
                   "Text to be written to the User-local contact field");
   declareProperty("Title", "", "Text to be written to the Title field");
+  appendSeparatorProperty();
 }
 
 /** virtual method to add information to the file before the data
@@ -74,10 +75,10 @@ void SaveILLCosmosAscii::extraHeaders(std::ofstream &file) {
   }
 
   file << "Number of file format: 2\n";
-  file << "Number of data points:" << sep() << m_xlength << '\n';
+  file << "Number of data points:" << m_sep << m_xlength << '\n';
   file << '\n';
 
-  file << sep() << "q" << sep() << "refl" << sep() << "refl_err" << sep()
+  file << m_sep << "q" << m_sep << "refl" << m_sep << "refl_err" << m_sep
        << "q_res\n";
 }
 } // namespace DataHandling
diff --git a/Framework/DataHandling/src/SaveIsawDetCal.cpp b/Framework/DataHandling/src/SaveIsawDetCal.cpp
index b00ab53fe8926898fbad359552196344fea87467..ce10be85d4aa9d9781cb462365f84e1fbed0f2df 100644
--- a/Framework/DataHandling/src/SaveIsawDetCal.cpp
+++ b/Framework/DataHandling/src/SaveIsawDetCal.cpp
@@ -5,11 +5,14 @@
 #include "MantidGeometry/Instrument.h"
 #include "MantidGeometry/Instrument/RectangularDetector.h"
 #include "MantidKernel/ArrayProperty.h"
+#include "MantidKernel/Strings.h"
 #include "MantidKernel/System.h"
-#include <fstream>
 #include "MantidAPI/Workspace.h"
 #include "MantidAPI/ExperimentInfo.h"
+
 #include <Poco/File.h>
+#include <boost/algorithm/string/trim.hpp>
+#include <fstream>
 
 using namespace Mantid::Kernel;
 using namespace Mantid::API;
diff --git a/Framework/DataHandling/src/SaveNXSPE.cpp b/Framework/DataHandling/src/SaveNXSPE.cpp
index 7a6105a7e85efa9f9eef28c811008f58b66da8ab..d5a6521d4e93df13073904f206151d04fe3fb012 100644
--- a/Framework/DataHandling/src/SaveNXSPE.cpp
+++ b/Framework/DataHandling/src/SaveNXSPE.cpp
@@ -3,13 +3,13 @@
 #include "MantidAPI/FileProperty.h"
 #include "MantidAPI/CommonBinsValidator.h"
 #include "MantidAPI/HistogramValidator.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidAPI/Run.h"
 #include "MantidAPI/WorkspaceUnitValidator.h"
 #include "MantidAPI/WorkspaceOpOverloads.h"
 
 #include "MantidDataHandling/FindDetectorsPar.h"
 #include "MantidGeometry/Instrument.h"
-#include "MantidGeometry/Instrument/Detector.h"
 
 #include "MantidKernel/CompositeValidator.h"
 #include "MantidKernel/MantidVersion.h"
@@ -82,7 +82,7 @@ void SaveNXSPE::exec() {
   MatrixWorkspace_sptr inputWS = getProperty("InputWorkspace");
 
   // Do the full check for common binning
-  if (!WorkspaceHelpers::commonBoundaries(inputWS)) {
+  if (!WorkspaceHelpers::commonBoundaries(*inputWS)) {
     g_log.error("The input workspace must have common bins");
     throw std::invalid_argument("The input workspace must have common bins");
   }
@@ -228,20 +228,15 @@ void SaveNXSPE::exec() {
   // Write the data
   Progress progress(this, 0, 1, nHist);
   int64_t bufferCounter(0);
+  const auto &spectrumInfo = inputWS->spectrumInfo();
   for (int64_t i = 0; i < nHist; ++i) {
     progress.report();
 
-    Geometry::IDetector_const_sptr det;
-    try { // detector exist
-      det = inputWS->getDetector(i);
-    } catch (Exception::NotFoundError &) {
-    }
-
     double *signalBufferStart = signalBuffer.get() + bufferCounter * nBins;
     double *errorBufferStart = errorBuffer.get() + bufferCounter * nBins;
-    if (det && !det->isMonitor()) {
+    if (spectrumInfo.hasDetectors(i) && !spectrumInfo.isMonitor(i)) {
       // a detector but not a monitor
-      if (!det->isMasked()) {
+      if (!spectrumInfo.isMasked(i)) {
         const auto &inY = inputWS->readY(i);
         std::copy(inY.begin(), inY.end(), signalBufferStart);
         const auto &inE = inputWS->readE(i);
diff --git a/Framework/DataHandling/src/SaveNXTomo.cpp b/Framework/DataHandling/src/SaveNXTomo.cpp
index 730d4f25162480b69591aba54cafa26db12ff700..ea46a1b95e3a54c1c45a3aee4643c5bea7514a88 100644
--- a/Framework/DataHandling/src/SaveNXTomo.cpp
+++ b/Framework/DataHandling/src/SaveNXTomo.cpp
@@ -4,6 +4,7 @@
 #include "MantidAPI/CommonBinsValidator.h"
 #include "MantidAPI/HistogramValidator.h"
 #include "MantidAPI/Run.h"
+#include "MantidAPI/WorkspaceGroup.h"
 
 #include "MantidDataHandling/FindDetectorsPar.h"
 
@@ -368,9 +369,6 @@ void SaveNXTomo::writeSingleWorkspace(const Workspace2D_sptr workspace,
   writeLogValues(workspace, nxFile, numFiles);
   writeIntensityValue(workspace, nxFile, numFiles);
   writeImageKeyValue(workspace, nxFile, numFiles);
-
-  ++numFiles;
-
   delete[] dataArr;
 }
 
diff --git a/Framework/DataHandling/src/SaveNXcanSAS.cpp b/Framework/DataHandling/src/SaveNXcanSAS.cpp
index 93e757a5bcc47865e5e755167728155ef473a2f9..dfa527692cdd5eb737ef7359351e482f8ef8ff5c 100644
--- a/Framework/DataHandling/src/SaveNXcanSAS.cpp
+++ b/Framework/DataHandling/src/SaveNXcanSAS.cpp
@@ -19,6 +19,7 @@
 #include <H5Cpp.h>
 #include <boost/make_shared.hpp>
 #include <boost/regex.hpp>
+#include <boost/algorithm/string/trim.hpp>
 
 #include <Poco/File.h>
 #include <Poco/Path.h>
@@ -752,7 +753,7 @@ std::map<std::string, std::string> SaveNXcanSAS::validateInputs() {
   }
 
   // Don't allow ragged workspaces for now
-  if (!API::WorkspaceHelpers::commonBoundaries(workspace)) {
+  if (!API::WorkspaceHelpers::commonBoundaries(*workspace)) {
     result.emplace("InputWorkspace",
                    "The InputWorkspace cannot be a ragged workspace.");
   }
diff --git a/Framework/DataHandling/src/SaveNexus.cpp b/Framework/DataHandling/src/SaveNexus.cpp
index 90631e8c9df5d5ecf74827521b58fb948727dc1f..c2b74e2a5ea9102fe4a68aae6846b71c6bce26a9 100644
--- a/Framework/DataHandling/src/SaveNexus.cpp
+++ b/Framework/DataHandling/src/SaveNexus.cpp
@@ -1,13 +1,11 @@
 // SaveNeXus
 // @author Freddie Akeroyd, STFC ISIS Faility
 // @author Ronald Fowler, STFC eScience. Modified to fit with SaveNexusProcessed
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidDataHandling/SaveNexus.h"
 #include "MantidDataObjects/Workspace2D.h"
 #include "MantidKernel/ArrayProperty.h"
 #include "MantidAPI/FileProperty.h"
+#include "MantidAPI/WorkspaceHistory.h"
 #include "MantidKernel/BoundedValidator.h"
 
 #include <cmath>
diff --git a/Framework/DataHandling/src/SaveNexusProcessed.cpp b/Framework/DataHandling/src/SaveNexusProcessed.cpp
index 3a5d8114f0342da090adc9d7885c8e75070fd1ff..f69accd921644586de57350139e3ff76fa29c7a5 100644
--- a/Framework/DataHandling/src/SaveNexusProcessed.cpp
+++ b/Framework/DataHandling/src/SaveNexusProcessed.cpp
@@ -4,6 +4,7 @@
 #include "MantidAPI/FileProperty.h"
 #include "MantidAPI/IMDEventWorkspace.h"
 #include "MantidAPI/IMDHistoWorkspace.h"
+#include "MantidAPI/WorkspaceHistory.h"
 #include "MantidAPI/WorkspaceOpOverloads.h"
 #include "MantidDataHandling/SaveNexusProcessed.h"
 #include "MantidDataObjects/EventWorkspace.h"
@@ -239,7 +240,7 @@ void SaveNexusProcessed::doExec(Workspace_sptr inputWorkspace,
 
     // check if all X() are in fact the same array
     const bool uniformSpectra =
-        API::WorkspaceHelpers::commonBoundaries(matrixWorkspace);
+        API::WorkspaceHelpers::commonBoundaries(*matrixWorkspace);
 
     // Retrieve the workspace indices (from params)
     std::vector<int> spec;
diff --git a/Framework/DataHandling/src/SaveReflCustomAscii.cpp b/Framework/DataHandling/src/SaveReflCustomAscii.cpp
index 8ccc780c31cf3cef3aa9b27fe6e3b5a51fb51b90..6b9a61892c157d851e748b78045e009ac348ee3d 100644
--- a/Framework/DataHandling/src/SaveReflCustomAscii.cpp
+++ b/Framework/DataHandling/src/SaveReflCustomAscii.cpp
@@ -22,6 +22,7 @@ void SaveReflCustomAscii::extraProps() {
       "WriteDeltaQ", false,
       "If true, the error on DeltaQ will be written as the fourth column.");
   declareProperty("Subtitle", false, "If true, subtitle added to header.");
+  appendSeparatorProperty();
 }
 
 /** virtual method to add information to the file before the data
diff --git a/Framework/DataHandling/src/SaveReflThreeColumnAscii.cpp b/Framework/DataHandling/src/SaveReflThreeColumnAscii.cpp
index faa993c0663e641f0aff28018b629ef0c513f96d..29b9218c24ea1de02e57c71e0e2a5321bb4d0467 100644
--- a/Framework/DataHandling/src/SaveReflThreeColumnAscii.cpp
+++ b/Framework/DataHandling/src/SaveReflThreeColumnAscii.cpp
@@ -18,6 +18,7 @@ void SaveReflThreeColumnAscii::extraProps() {
   declareProperty("Title", "", "Text to be written to the Title field");
   declareProperty(make_unique<ArrayProperty<std::string>>("LogList"),
                   "List of logs to write to file.");
+  appendSeparatorProperty();
 }
 
 /** virtual method to add information to the file before the data
diff --git a/Framework/DataHandling/src/SaveSPE.cpp b/Framework/DataHandling/src/SaveSPE.cpp
index c50cf911d68239daff5d23f96342c7f914bdce4c..6bd6409c2b73e4ad2868de4f75d9dfc5dd427ba9 100644
--- a/Framework/DataHandling/src/SaveSPE.cpp
+++ b/Framework/DataHandling/src/SaveSPE.cpp
@@ -3,6 +3,7 @@
 #include "MantidAPI/CommonBinsValidator.h"
 #include "MantidAPI/FileProperty.h"
 #include "MantidAPI/HistogramValidator.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidAPI/WorkspaceOpOverloads.h"
 #include "MantidGeometry/Instrument.h"
 #include "MantidGeometry/IDetector.h"
@@ -106,7 +107,7 @@ void SaveSPE::exec() {
   const MatrixWorkspace_const_sptr inputWS = getProperty("InputWorkspace");
 
   // Do the full check for common binning
-  if (!WorkspaceHelpers::commonBoundaries(inputWS)) {
+  if (!WorkspaceHelpers::commonBoundaries(*inputWS)) {
     throw std::invalid_argument("The input workspace must have common binning");
   }
 
@@ -223,11 +224,11 @@ void SaveSPE::writeHists(const API::MatrixWorkspace_const_sptr WS,
   std::vector<int> spuriousSpectra;
   // used only for debugging
   int nMasked = 0;
+  const auto &spectrumInfo = WS->spectrumInfo();
   // Loop over the spectra, writing out Y and then E values for each
   for (int i = 0; i < static_cast<int>(nHist); i++) {
-    try { // need to check if _all_ the detectors for the spectrum are masked,
-          // as we don't have output values for those
-      if (isNumericAxis || !WS->getDetector(i)->isMasked()) {
+    if (spectrumInfo.hasDetectors(i)) {
+      if (isNumericAxis || !spectrumInfo.isMasked(i)) {
         // there's no masking, write the data
         writeHist(WS, outFile, i);
       } else { // all the detectors are masked, write the masking value from the
@@ -236,11 +237,8 @@ void SaveSPE::writeHists(const API::MatrixWorkspace_const_sptr WS,
         writeMaskFlags(outFile);
         nMasked++;
       }
-    } catch (Exception::NotFoundError &) { // WS->getDetector(i) throws this if
-                                           // the detector isn't in the
-                                           // instrument definition file, write
-                                           // mask values and prepare to log
-                                           // what happened
+    } else { // if the detector isn't in the instrument definition file, write
+             // mask values and prepare to log what happened
       spuriousSpectra.push_back(i);
       writeMaskFlags(outFile);
     }
diff --git a/Framework/DataHandling/src/SaveSavuTomoConfig.cpp b/Framework/DataHandling/src/SaveSavuTomoConfig.cpp
index e88e6eccd8676266df10dfe83fc99d282d212cae..80c331018d6b4dc1161f1283b76857dca07f7ffb 100644
--- a/Framework/DataHandling/src/SaveSavuTomoConfig.cpp
+++ b/Framework/DataHandling/src/SaveSavuTomoConfig.cpp
@@ -1,3 +1,4 @@
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/FileProperty.h"
 #include "MantidAPI/ITableWorkspace.h"
 #include "MantidDataHandling/SaveSavuTomoConfig.h"
diff --git a/Framework/DataHandling/src/SaveToSNSHistogramNexus.cpp b/Framework/DataHandling/src/SaveToSNSHistogramNexus.cpp
index 67c9dc75f64d03b59e4ebf2609ffffa4499230d1..5cc7dd9dbd6e5188705b1cc5956d436352ee761e 100644
--- a/Framework/DataHandling/src/SaveToSNSHistogramNexus.cpp
+++ b/Framework/DataHandling/src/SaveToSNSHistogramNexus.cpp
@@ -647,7 +647,7 @@ int SaveToSNSHistogramNexus::WriteGroup(int is_definition) {
 int SaveToSNSHistogramNexus::WriteAttributes(int is_definition) {
   (void)is_definition;
 
-  int status, i, attrLen, attrType;
+  int status, attrLen, attrType;
 #ifndef NEXUS43
   int rank;
   int dims[4];
@@ -655,7 +655,6 @@ int SaveToSNSHistogramNexus::WriteAttributes(int is_definition) {
   NXname attrName;
   void *attrBuffer;
 
-  i = 0;
   do {
 #ifdef NEXUS43
     status = NXgetnextattr(inId, attrName, &attrLen, &attrType);
@@ -684,7 +683,6 @@ int SaveToSNSHistogramNexus::WriteAttributes(int is_definition) {
         if (NXfree(&attrBuffer) != NX_OK)
           return NX_ERROR;
       }
-      i++;
     }
   } while (status != NX_EOD);
   return NX_OK;
diff --git a/Framework/DataHandling/src/SetSample.cpp b/Framework/DataHandling/src/SetSample.cpp
index b216716c00bc089f516d3caeeffc6b51bb67b350..38e268798773c3250b6504c01d4ab888e363ef86 100644
--- a/Framework/DataHandling/src/SetSample.cpp
+++ b/Framework/DataHandling/src/SetSample.cpp
@@ -3,12 +3,15 @@
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/Sample.h"
 #include "MantidGeometry/Instrument.h"
+#include "MantidGeometry/Instrument/Goniometer.h"
+#include "MantidGeometry/Instrument/ReferenceFrame.h"
 #include "MantidGeometry/Instrument/SampleEnvironmentFactory.h"
 #include "MantidKernel/ConfigService.h"
 #include "MantidKernel/FacilityInfo.h"
 #include "MantidKernel/InstrumentInfo.h"
 #include "MantidKernel/Logger.h"
 #include "MantidKernel/Material.h"
+#include "MantidKernel/Matrix.h"
 #include "MantidKernel/PropertyManager.h"
 #include "MantidKernel/PropertyManagerProperty.h"
 
@@ -19,32 +22,63 @@
 namespace Mantid {
 namespace DataHandling {
 
+using Geometry::Goniometer;
+using Geometry::ReferenceFrame;
 using Geometry::SampleEnvironment;
 using Kernel::Logger;
+using Kernel::PropertyWithValue;
+using Kernel::Quat;
 using Kernel::V3D;
 
 namespace {
+/// Private namespace storing property name strings
+namespace PropertyNames {
+/// Input workspace property name
+const std::string INPUT_WORKSPACE("InputWorkspace");
+/// Geometry property name
+const std::string GEOMETRY("Geometry");
+/// Material property name
+const std::string MATERIAL("Material");
+/// Environment property name
+const std::string ENVIRONMENT("Environment");
+}
+/// Private namespace storing sample environment args
+namespace SEArgs {
+/// Static Name string
+const std::string NAME("Name");
+/// Static Container string
+const std::string CONTAINER("Container");
+}
+/// Provate namespace storing geometry args
+namespace GeometryArgs {
+/// Static Shape string
+const std::string SHAPE("Shape");
+}
 
-/**
- * Retrieve "Axis" property value. The most commmon use case is calling
- * this algorithm from Python where Axis is input as a C long. The
- * definition of long varies across platforms and long v = args.getProperty()
- * is currently unable to cope so we go via the long route to retrieve
- * the value.
- * @param args Dictionary-type containing the argument
- */
-long getAxisIndex(const Kernel::PropertyManager &args) {
-  using Kernel::Property;
-  using Kernel::PropertyWithValue;
-  long axisIdx(1);
-  if (args.existsProperty("Axis")) {
-    Kernel::Property *axisProp = args.getProperty("Axis");
-    axisIdx = static_cast<PropertyWithValue<long> *>(axisProp)->operator()();
-    if (axisIdx < 0 || axisIdx > 2)
-      throw std::invalid_argument(
-          "Geometry.Axis value must be either 0,1,2 (X,Y,Z)");
-  }
-  return axisIdx;
+/// Private namespace storing sample environment args
+namespace ShapeArgs {
+/// Static FlatPlate string
+const std::string FLAT_PLATE("FlatPlate");
+/// Static Cylinder string
+const std::string CYLINDER("Cylinder");
+/// Static HollowCylinder string
+const std::string HOLLOW_CYLINDER("HollowCylinder");
+/// Static CSG string
+const std::string CSG("CSG");
+/// Static Width string
+const std::string WIDTH("Width");
+/// Static Height string
+const std::string HEIGHT("Height");
+/// Static Thick string
+const std::string THICK("Thick");
+/// Static Center string
+const std::string CENTER("Center");
+/// Static Radius string
+const std::string RADIUS("Radius");
+/// Static InnerRadius string
+const std::string INNER_RADIUS("InnerRadius");
+/// Static OuterRadius string
+const std::string OUTER_RADIUS("OuterRadius");
 }
 
 /**
@@ -55,7 +89,7 @@ long getAxisIndex(const Kernel::PropertyManager &args) {
   * @param axis The index of the height-axis of the cylinder
   */
 V3D cylBaseCentre(const std::vector<double> &cylCentre, double height,
-                  long axisIdx) {
+                  unsigned axisIdx) {
   const V3D halfHeight = [&]() {
     switch (axisIdx) {
     case 0:
@@ -76,7 +110,7 @@ V3D cylBaseCentre(const std::vector<double> &cylCentre, double height,
  * @param axisIdx Index 0,1,2 for the axis of a cylinder
  * @return A string containing the axis tag for this index
  */
-std::string axisXML(long axisIdx) {
+std::string axisXML(unsigned axisIdx) {
   switch (axisIdx) {
   case 0:
     return "<axis x=\"1\" y=\"0\" z=\"0\" />";
@@ -109,28 +143,58 @@ const std::string SetSample::summary() const {
 
 /// Validate the inputs against each other @see Algorithm::validateInputs
 std::map<std::string, std::string> SetSample::validateInputs() {
-  using Kernel::PropertyManager_sptr;
+  using Kernel::PropertyManager;
+  using Kernel::PropertyManager_const_sptr;
   std::map<std::string, std::string> errors;
 
+  auto existsAndNotEmptyString =
+      [](const PropertyManager &pm, const std::string &name) {
+        if (pm.existsProperty(name)) {
+          const auto value = pm.getPropertyValue(name);
+          return !value.empty();
+        }
+        return false;
+      };
+
+  auto existsAndNegative =
+      [](const PropertyManager &pm, const std::string &name) {
+        if (pm.existsProperty(name)) {
+          const double value = pm.getProperty(name);
+          if (value < 0.0) {
+            return true;
+          }
+        }
+        return false;
+      };
+
   // Validate Environment
-  PropertyManager_sptr environArgs = getProperty("Environment");
+  const PropertyManager_const_sptr environArgs =
+      getProperty(PropertyNames::ENVIRONMENT);
   if (environArgs) {
-    if (!environArgs->existsProperty("Name")) {
-      errors["Environment"] = "Environment flags must contain a 'Name' entry.";
-    } else {
-      std::string name = environArgs->getPropertyValue("Name");
-      if (name.empty()) {
-        errors["Environment"] = "Environment 'Name' flag is an empty string!";
-      }
+    if (!existsAndNotEmptyString(*environArgs, SEArgs::NAME)) {
+      errors[PropertyNames::ENVIRONMENT] =
+          "Environment flags require a non-empty 'Name' entry.";
     }
 
-    if (!environArgs->existsProperty("Container")) {
-      errors["Environment"] =
-          "Environment flags must contain a 'Container' entry.";
-    } else {
-      std::string name = environArgs->getPropertyValue("Container");
-      if (name.empty()) {
-        errors["Environment"] = "Environment 'Can' flag is an empty string!";
+    if (!existsAndNotEmptyString(*environArgs, SEArgs::CONTAINER)) {
+      errors[PropertyNames::ENVIRONMENT] =
+          "Environment flags require a non-empty 'Container' entry.";
+    }
+  }
+
+  // Validate as much of the shape information as possible
+  const PropertyManager_const_sptr geomArgs =
+      getProperty(PropertyNames::GEOMETRY);
+  if (geomArgs) {
+    if (existsAndNotEmptyString(*geomArgs, GeometryArgs::SHAPE)) {
+      const std::array<const std::string *, 6> positiveValues = {
+          {&ShapeArgs::HEIGHT, &ShapeArgs::WIDTH, &ShapeArgs::THICK,
+           &ShapeArgs::RADIUS, &ShapeArgs::INNER_RADIUS,
+           &ShapeArgs::OUTER_RADIUS}};
+      for (const auto &arg : positiveValues) {
+        if (existsAndNegative(*geomArgs, *arg)) {
+          errors[PropertyNames::GEOMETRY] = *arg + " argument < 0.0";
+        }
       }
     }
   }
@@ -147,18 +211,18 @@ void SetSample::init() {
   using Kernel::PropertyManagerProperty;
 
   // Inputs
-  declareProperty(Kernel::make_unique<WorkspaceProperty<>>("InputWorkspace", "",
-                                                           Direction::InOut),
+  declareProperty(Kernel::make_unique<WorkspaceProperty<>>(
+                      PropertyNames::INPUT_WORKSPACE, "", Direction::InOut),
                   "A workspace whose sample properties will be updated");
   declareProperty(Kernel::make_unique<PropertyManagerProperty>(
-                      "Geometry", Direction::Input),
+                      PropertyNames::GEOMETRY, Direction::Input),
                   "A dictionary of geometry parameters for the sample.");
   declareProperty(Kernel::make_unique<PropertyManagerProperty>(
-                      "Material", Direction::Input),
+                      PropertyNames::MATERIAL, Direction::Input),
                   "A dictionary of material parameters for the sample. See "
                   "SetSampleMaterial for all accepted parameters");
   declareProperty(
-      Kernel::make_unique<PropertyManagerProperty>("Environment",
+      Kernel::make_unique<PropertyManagerProperty>(PropertyNames::ENVIRONMENT,
                                                    Direction::Input),
       "A dictionary of parameters to configure the sample environment");
 }
@@ -170,17 +234,17 @@ void SetSample::exec() {
   using API::MatrixWorkspace_sptr;
   using Kernel::PropertyManager_sptr;
 
-  MatrixWorkspace_sptr workspace = getProperty("InputWorkspace");
-  PropertyManager_sptr environArgs = getProperty("Environment");
-  PropertyManager_sptr geometryArgs = getProperty("Geometry");
-  PropertyManager_sptr materialArgs = getProperty("Material");
+  MatrixWorkspace_sptr workspace = getProperty(PropertyNames::INPUT_WORKSPACE);
+  PropertyManager_sptr environArgs = getProperty(PropertyNames::ENVIRONMENT);
+  PropertyManager_sptr geometryArgs = getProperty(PropertyNames::GEOMETRY);
+  PropertyManager_sptr materialArgs = getProperty(PropertyNames::MATERIAL);
 
   // The order here is important. Se the environment first. If this
   // defines a sample geometry then we can process the Geometry flags
   // combined with this
   const SampleEnvironment *sampleEnviron(nullptr);
   if (environArgs) {
-    sampleEnviron = setSampleEnvironment(workspace, *environArgs);
+    sampleEnviron = setSampleEnvironment(workspace, environArgs);
   }
 
   if (geometryArgs || sampleEnviron) {
@@ -199,15 +263,15 @@ void SetSample::exec() {
  * @param args The dictionary of flags for the environment
  * @return A pointer to the new sample environment
  */
-const Geometry::SampleEnvironment *
-SetSample::setSampleEnvironment(API::MatrixWorkspace_sptr &workspace,
-                                const Kernel::PropertyManager &args) {
+const Geometry::SampleEnvironment *SetSample::setSampleEnvironment(
+    API::MatrixWorkspace_sptr &workspace,
+    const Kernel::PropertyManager_const_sptr &args) {
   using Geometry::SampleEnvironmentSpecFileFinder;
   using Geometry::SampleEnvironmentFactory;
   using Kernel::ConfigService;
 
-  const std::string envName = args.getPropertyValue("Name");
-  const std::string canName = args.getPropertyValue("Container");
+  const std::string envName = args->getPropertyValue(SEArgs::NAME);
+  const std::string canName = args->getPropertyValue(SEArgs::CONTAINER);
   // The specifications need to be qualified by the facility and instrument.
   // Check instrument for name and then lookup facility if facility
   // is unknown then set to default facility & instrument.
@@ -248,7 +312,7 @@ SetSample::setSampleEnvironment(API::MatrixWorkspace_sptr &workspace,
  * @return A string containing the XML definition of the shape
  */
 void SetSample::setSampleShape(API::MatrixWorkspace_sptr &workspace,
-                               const Kernel::PropertyManager_sptr &args,
+                               const Kernel::PropertyManager_const_sptr &args,
                                const Geometry::SampleEnvironment *sampleEnv) {
   using Geometry::Container;
   /* The sample geometry can be specified in two ways:
@@ -258,10 +322,13 @@ void SetSample::setSampleShape(API::MatrixWorkspace_sptr &workspace,
   */
 
   // Try known shapes or CSG first if supplied
-  const auto xml = tryCreateXMLFromArgsOnly(args);
-  if (!xml.empty()) {
-    runSetSampleShape(workspace, xml);
-    return;
+  if (args) {
+    const auto refFrame = workspace->getInstrument()->getReferenceFrame();
+    const auto xml = tryCreateXMLFromArgsOnly(*args, *refFrame);
+    if (!xml.empty()) {
+      runSetSampleShape(workspace, xml);
+      return;
+    }
   }
   // Any arguments in the args dict are assumed to be values that should
   // override the default set by the sampleEnv samplegeometry if it exists
@@ -300,23 +367,26 @@ void SetSample::setSampleShape(API::MatrixWorkspace_sptr &workspace,
 /**
  * Create the required XML for a given shape type plus its arguments
  * @param args A dict of flags defining the shape
+ * @param refFrame Defines the reference frame for the shape
  * @return A string containing the XML if possible or an empty string
  */
 std::string
-SetSample::tryCreateXMLFromArgsOnly(const Kernel::PropertyManager_sptr args) {
+SetSample::tryCreateXMLFromArgsOnly(const Kernel::PropertyManager &args,
+                                    const Geometry::ReferenceFrame &refFrame) {
   std::string result;
-  if (!args || !args->existsProperty("Shape")) {
+  if (!args.existsProperty(GeometryArgs::SHAPE)) {
     return result;
   }
 
-  const auto shape = args->getPropertyValue("Shape");
-  if (shape == "CSG") {
-    result = args->getPropertyValue("Value");
-  } else if (shape == "FlatPlate") {
-    result = createFlatPlateXML(*args);
-  } else if (boost::algorithm::ends_with(shape, "Cylinder")) {
+  const auto shape = args.getPropertyValue(GeometryArgs::SHAPE);
+  if (shape == ShapeArgs::CSG) {
+    result = args.getPropertyValue("Value");
+  } else if (shape == ShapeArgs::FLAT_PLATE) {
+    result = createFlatPlateXML(args, refFrame);
+  } else if (boost::algorithm::ends_with(shape, ShapeArgs::CYLINDER)) {
     result = createCylinderLikeXML(
-        *args, boost::algorithm::starts_with(shape, "Hollow"));
+        args, refFrame,
+        boost::algorithm::equals(shape, ShapeArgs::HOLLOW_CYLINDER));
   } else {
     throw std::invalid_argument(
         "Unknown 'Shape' argument provided in "
@@ -332,61 +402,85 @@ SetSample::tryCreateXMLFromArgsOnly(const Kernel::PropertyManager_sptr args) {
 /**
  * Create the XML required to define a flat plate from the given args
  * @param args A user-supplied dict of args
+ * @param refFrame Defines the reference frame for the shape
  * @return The XML definition string
  */
 std::string
-SetSample::createFlatPlateXML(const Kernel::PropertyManager &args) const {
-  // X
-  double widthInCM = args.getProperty("Width");
-  // Y
-  double heightInCM = args.getProperty("Height");
-  // Z
-  double thickInCM = args.getProperty("Thick");
-  std::vector<double> center = args.getProperty("Center");
-  // convert to metres
-  std::transform(center.begin(), center.end(), center.begin(),
-                 [](double val) { return val *= 0.01; });
-
-  // Half lengths in metres (*0.01*0.5)
+SetSample::createFlatPlateXML(const Kernel::PropertyManager &args,
+                              const Geometry::ReferenceFrame &refFrame) const {
+  // Helper to take 3 coordinates and turn them to a V3D respecting the
+  // current reference frame
+  auto makeV3D = [&refFrame](double x, double y, double z) {
+    V3D v;
+    v[refFrame.pointingHorizontal()] = x;
+    v[refFrame.pointingUp()] = y;
+    v[refFrame.pointingAlongBeam()] = z;
+    return v;
+  };
+  const double widthInCM = args.getProperty(ShapeArgs::WIDTH);
+  const double heightInCM = args.getProperty(ShapeArgs::HEIGHT);
+  const double thickInCM = args.getProperty(ShapeArgs::THICK);
+  // Convert to half-"width" in metres
   const double szX = (widthInCM * 5e-3);
   const double szY = (heightInCM * 5e-3);
   const double szZ = (thickInCM * 5e-3);
+  // Contruct cuboid corners. Define points about origin, rotate and then
+  // translate to final center position
+  auto lfb = makeV3D(szX, -szY, -szZ);
+  auto lft = makeV3D(szX, szY, -szZ);
+  auto lbb = makeV3D(szX, -szY, szZ);
+  auto rfb = makeV3D(-szX, -szY, -szZ);
+  // optional rotation about the center of object
+  if (args.existsProperty("Angle")) {
+    Goniometer gr;
+    const auto upAxis = makeV3D(0, 1, 0);
+    gr.pushAxis("up", upAxis.X(), upAxis.Y(), upAxis.Z(),
+                args.getProperty("Angle"), Geometry::CCW, Geometry::angDegrees);
+    auto &rotation = gr.getR();
+    lfb.rotate(rotation);
+    lft.rotate(rotation);
+    lbb.rotate(rotation);
+    rfb.rotate(rotation);
+  }
+  std::vector<double> center = args.getProperty(ShapeArgs::CENTER);
+  const V3D centrePos(center[0] * 0.01, center[1] * 0.01, center[2] * 0.01);
+  // translate to true center after rotation
+  lfb += centrePos;
+  lft += centrePos;
+  lbb += centrePos;
+  rfb += centrePos;
 
   std::ostringstream xmlShapeStream;
   xmlShapeStream << " <cuboid id=\"sample-shape\"> "
-                 << "<left-front-bottom-point x=\"" << szX + center[0]
-                 << "\" y=\"" << -szY + center[1] << "\" z=\""
-                 << -szZ + center[2] << "\"  /> "
-                 << "<left-front-top-point  x=\"" << szX + center[0]
-                 << "\" y=\"" << szY + center[1] << "\" z=\""
-                 << -szZ + center[2] << "\"  /> "
-                 << "<left-back-bottom-point  x=\"" << szX + center[0]
-                 << "\" y=\"" << -szY + center[1] << "\" z=\""
-                 << szZ + center[2] << "\"  /> "
-                 << "<right-front-bottom-point  x=\"" << -szX + center[0]
-                 << "\" y=\"" << -szY + center[1] << "\" z=\""
-                 << -szZ + center[2] << "\"  /> "
+                 << "<left-front-bottom-point x=\"" << lfb.X() << "\" y=\""
+                 << lfb.Y() << "\" z=\"" << lfb.Z() << "\"  /> "
+                 << "<left-front-top-point  x=\"" << lft.X() << "\" y=\""
+                 << lft.Y() << "\" z=\"" << lft.Z() << "\"  /> "
+                 << "<left-back-bottom-point  x=\"" << lbb.X() << "\" y=\""
+                 << lbb.Y() << "\" z=\"" << lbb.Z() << "\"  /> "
+                 << "<right-front-bottom-point  x=\"" << rfb.X() << "\" y =\""
+                 << rfb.Y() << "\" z=\"" << rfb.Z() << "\"  /> "
                  << "</cuboid>";
-
   return xmlShapeStream.str();
 }
 
 /**
  * Create the XML required to define a cylinder from the given args
  * @param args A user-supplied dict of args
+ * @param refFrame Defines the reference frame for the shape
  * @param hollow True if an annulus is to be created
  * @return The XML definition string
  */
 std::string
 SetSample::createCylinderLikeXML(const Kernel::PropertyManager &args,
+                                 const Geometry::ReferenceFrame &refFrame,
                                  bool hollow) const {
   const std::string tag = hollow ? "hollow-cylinder" : "cylinder";
-  double height = args.getProperty("Height");
-  double innerRadius = hollow ? args.getProperty("InnerRadius") : 0.0;
-  double outerRadius =
-      hollow ? args.getProperty("OuterRadius") : args.getProperty("Radius");
-  std::vector<double> centre = args.getProperty("Center");
-  long axisIdx = getAxisIndex(args);
+  double height = args.getProperty(ShapeArgs::HEIGHT);
+  double innerRadius = hollow ? args.getProperty(ShapeArgs::INNER_RADIUS) : 0.0;
+  double outerRadius = hollow ? args.getProperty(ShapeArgs::OUTER_RADIUS)
+                              : args.getProperty("Radius");
+  std::vector<double> centre = args.getProperty(ShapeArgs::CENTER);
   // convert to metres
   height *= 0.01;
   innerRadius *= 0.01;
@@ -395,6 +489,7 @@ SetSample::createCylinderLikeXML(const Kernel::PropertyManager &args,
                  [](double val) { return val *= 0.01; });
   // XML needs center position of bottom base but user specifies center of
   // cylinder
+  const unsigned axisIdx = static_cast<unsigned>(refFrame.pointingUp());
   const V3D baseCentre = cylBaseCentre(centre, height, axisIdx);
 
   std::ostringstream xmlShapeStream;
@@ -421,7 +516,7 @@ SetSample::createCylinderLikeXML(const Kernel::PropertyManager &args,
 void SetSample::runSetSampleShape(API::MatrixWorkspace_sptr &workspace,
                                   const std::string &xml) {
   auto alg = createChildAlgorithm("CreateSampleShape");
-  alg->setProperty("InputWorkspace", workspace);
+  alg->setProperty(PropertyNames::INPUT_WORKSPACE, workspace);
   alg->setProperty("ShapeXML", xml);
   alg->executeAsChildAlg();
 }
@@ -437,7 +532,7 @@ void SetSample::runChildAlgorithm(const std::string &name,
                                   API::MatrixWorkspace_sptr &workspace,
                                   const Kernel::PropertyManager &args) {
   auto alg = createChildAlgorithm(name);
-  alg->setProperty("InputWorkspace", workspace);
+  alg->setProperty(PropertyNames::INPUT_WORKSPACE, workspace);
   alg->updatePropertyValues(args);
   alg->executeAsChildAlg();
 }
diff --git a/Framework/DataHandling/src/SetSampleMaterial.cpp b/Framework/DataHandling/src/SetSampleMaterial.cpp
index 84256b5df47dd54c72a89f59118a8b770c234cef..5786e4433ad86fd5da4c106c96ea06329cd50cdf 100644
--- a/Framework/DataHandling/src/SetSampleMaterial.cpp
+++ b/Framework/DataHandling/src/SetSampleMaterial.cpp
@@ -1,6 +1,3 @@
-//--------------------------------
-// Includes
-//--------------------------------
 #include "MantidDataHandling/SetSampleMaterial.h"
 #include "MantidAPI/ExperimentInfo.h"
 #include "MantidAPI/Workspace.h"
@@ -17,6 +14,7 @@
 #include <boost/scoped_ptr.hpp>
 
 #include <cmath>
+#include <iostream>
 
 using namespace Mantid::PhysicalConstants;
 
diff --git a/Framework/DataHandling/src/SetScalingPSD.cpp b/Framework/DataHandling/src/SetScalingPSD.cpp
index 7e7a83bbbf3e5546e6a083b650e8fc6e2cddc227..090730a47695c6770c33d7f8bed9d9ed25eeba61 100644
--- a/Framework/DataHandling/src/SetScalingPSD.cpp
+++ b/Framework/DataHandling/src/SetScalingPSD.cpp
@@ -1,11 +1,8 @@
-// SetScalingPSD
 // @author Ronald Fowler
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidDataHandling/SetScalingPSD.h"
 #include "LoadRaw/isisraw.h"
 #include "MantidAPI/Axis.h"
+#include "MantidAPI/DetectorInfo.h"
 #include "MantidAPI/FileProperty.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidGeometry/Instrument/ComponentHelper.h"
@@ -87,7 +84,7 @@ bool SetScalingPSD::processScalingFile(const std::string &scalingFile,
   std::map<int, double> scaleMap;
   std::map<int, double>::iterator its;
 
-  Instrument_const_sptr instrument = m_workspace->getInstrument();
+  const auto &detectorInfo = m_workspace->detectorInfo();
   if (scalingFile.find(".sca") != std::string::npos ||
       scalingFile.find(".SCA") != std::string::npos) {
     // read a .sca text format file
@@ -140,38 +137,35 @@ bool SetScalingPSD::processScalingFile(const std::string &scalingFile,
       // use abs as correction file has -ve l2 for first few detectors
       truPos.spherical(fabs(l2), theta, phi);
       truepos.push_back(truPos);
-      //
-      Geometry::IDetector_const_sptr det;
       try {
-        det = instrument->getDetector(detIndex);
-      } catch (Kernel::Exception::NotFoundError &) {
-        continue;
-      }
-      Kernel::V3D detPos = det->getPos();
-      Kernel::V3D shift = truPos - detPos;
+        // detIndex is what Mantid usually calls detectorID
+        size_t index = detectorInfo.indexOf(detIndex);
+        Kernel::V3D detPos = detectorInfo.position(index);
+        Kernel::V3D shift = truPos - detPos;
 
-      // scaling applied to dets that are not monitors and have sequential IDs
-      if (detIdLast == detIndex - 1 && !det->isMonitor()) {
-        Kernel::V3D diffI = detPos - detPosLast;
-        Kernel::V3D diffT = truPos - truPosLast;
-        double scale = diffT.norm() / diffI.norm();
-        // Wish to store the scaling in a map, if we already have a scaling
-        // for this detector (i.e. from the other side) we average the two
-        // values. End of tube detectors only have one scaling estimate.
-        scaleMap[detIndex] = scale;
-        its = scaleMap.find(detIndex - 1);
-        if (its == scaleMap.end())
-          scaleMap[detIndex - 1] = scale;
-        else
-          its->second = 0.5 * (its->second + scale);
-        // std::cout << detIndex << scale << scaleDir << '\n';
+        // scaling applied to dets that are not monitors and have sequential IDs
+        if (detIdLast == detIndex - 1 && !detectorInfo.isMonitor(index)) {
+          Kernel::V3D diffI = detPos - detPosLast;
+          Kernel::V3D diffT = truPos - truPosLast;
+          double scale = diffT.norm() / diffI.norm();
+          // Wish to store the scaling in a map, if we already have a scaling
+          // for this detector (i.e. from the other side) we average the two
+          // values. End of tube detectors only have one scaling estimate.
+          scaleMap[detIndex] = scale;
+          its = scaleMap.find(detIndex - 1);
+          if (its == scaleMap.end())
+            scaleMap[detIndex - 1] = scale;
+          else
+            its->second = 0.5 * (its->second + scale);
+        }
+        detIdLast = detIndex;
+        detPosLast = detPos;
+        truPosLast = truPos;
+        posMap[detIndex] = shift;
+        prog.report();
+      } catch (std::out_of_range &) {
+        continue;
       }
-      detIdLast = detIndex;
-      detPosLast = detPos;
-      truPosLast = truPos;
-      posMap[detIndex] = shift;
-      //
-      prog.report();
     }
   } else if (scalingFile.find(".raw") != std::string::npos ||
              scalingFile.find(".RAW") != std::string::npos) {
@@ -189,44 +183,42 @@ bool SetScalingPSD::processScalingFile(const std::string &scalingFile,
     Progress prog(this, 0.0, 0.5, detectorCount);
     for (int i = 0; i < detectorCount; i++) {
       int detIndex = detID[i];
-      Geometry::IDetector_const_sptr det;
       try {
-        det = instrument->getDetector(detIndex);
-      } catch (Kernel::Exception::NotFoundError &) {
-        continue;
-      }
-      Kernel::V3D detPos = det->getPos();
-      Kernel::V3D shift = truepos[i] - detPos;
+        // detIndex is what Mantid usually calls detectorID
+        size_t index = detectorInfo.indexOf(detIndex);
+        Kernel::V3D detPos = detectorInfo.position(index);
+        Kernel::V3D shift = truepos[i] - detPos;
 
-      if (detIdLast == detIndex - 1 && !det->isMonitor()) {
-        Kernel::V3D diffI = detPos - detPosLast;
-        Kernel::V3D diffT = truepos[i] - truPosLast;
-        double scale = diffT.norm() / diffI.norm();
-        scaleMap[detIndex] = scale;
-        its = scaleMap.find(detIndex - 1);
-        if (its == scaleMap.end()) {
-          scaleMap[detIndex - 1] = scale;
-        } else {
-          if (m_scalingOption == 0)
-            its->second = 0.5 * (its->second + scale); // average of two
-          else if (m_scalingOption == 1) {
-            if (its->second < scale)
-              its->second = scale; // max
-          } else if (m_scalingOption == 2) {
-            if (its->second < scale)
-              its->second = scale;
-            its->second *= 1.05; // max+5%
-          } else
-            its->second = 3.0; // crazy test value
+        if (detIdLast == detIndex - 1 && !detectorInfo.isMonitor(index)) {
+          Kernel::V3D diffI = detPos - detPosLast;
+          Kernel::V3D diffT = truepos[i] - truPosLast;
+          double scale = diffT.norm() / diffI.norm();
+          scaleMap[detIndex] = scale;
+          its = scaleMap.find(detIndex - 1);
+          if (its == scaleMap.end()) {
+            scaleMap[detIndex - 1] = scale;
+          } else {
+            if (m_scalingOption == 0)
+              its->second = 0.5 * (its->second + scale); // average of two
+            else if (m_scalingOption == 1) {
+              if (its->second < scale)
+                its->second = scale; // max
+            } else if (m_scalingOption == 2) {
+              if (its->second < scale)
+                its->second = scale;
+              its->second *= 1.05; // max+5%
+            } else
+              its->second = 3.0; // crazy test value
+          }
         }
-        // std::cout << detIndex << scale << scaleDir << '\n';
+        detIdLast = detID[i];
+        detPosLast = detPos;
+        truPosLast = truepos[i];
+        posMap[detIndex] = shift;
+        prog.report();
+      } catch (std::out_of_range &) {
+        continue;
       }
-      detIdLast = detID[i];
-      detPosLast = detPos;
-      truPosLast = truepos[i];
-      posMap[detIndex] = shift;
-      //
-      prog.report();
     }
   }
   movePos(m_workspace, posMap, scaleMap);
diff --git a/Framework/DataHandling/src/UpdateInstrumentFromFile.cpp b/Framework/DataHandling/src/UpdateInstrumentFromFile.cpp
index d2a1be7b00bdecaf93af68a6ee8400205c511b58..6e357656111e43d7bed6dd649314a427ae8ab12f 100644
--- a/Framework/DataHandling/src/UpdateInstrumentFromFile.cpp
+++ b/Framework/DataHandling/src/UpdateInstrumentFromFile.cpp
@@ -1,13 +1,11 @@
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidDataHandling/UpdateInstrumentFromFile.h"
-#include "MantidDataHandling/LoadAscii.h"
 #include "MantidDataHandling/LoadEventNexus.h"
 #include "MantidDataHandling/LoadISISNexus2.h"
 #include "MantidDataHandling/LoadRawHelper.h"
+#include "MantidAPI/DetectorInfo.h"
 #include "MantidAPI/FileProperty.h"
 #include "MantidAPI/MatrixWorkspace.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidGeometry/Instrument.h"
 #include "MantidGeometry/Instrument/ComponentHelper.h"
 #include "MantidGeometry/Instrument/DetectorGroup.h"
@@ -199,7 +197,6 @@ void UpdateInstrumentFromFile::updateFromAscii(const std::string &filename) {
   AsciiFileHeader header;
   const bool isSpectrum = parseAsciiHeader(header);
 
-  Geometry::Instrument_const_sptr inst = m_workspace->getInstrument();
   // Throws for multiple detectors
   const spec2index_map specToIndex(
       m_workspace->getSpectrumToWorkspaceIndexMap());
@@ -213,6 +210,10 @@ void UpdateInstrumentFromFile::updateFromAscii(const std::string &filename) {
     ++lineCount;
   }
 
+  Geometry::ParameterMap &pmap = m_workspace->instrumentParameters();
+  auto &detectorInfo = m_workspace->mutableDetectorInfo();
+  const auto &spectrumInfo = m_workspace->spectrumInfo();
+
   std::vector<double> colValues(header.colCount - 1, 0.0);
   while (std::getline(datfile, line)) {
     boost::trim(line);
@@ -227,28 +228,50 @@ void UpdateInstrumentFromFile::updateFromAscii(const std::string &filename) {
       continue;
     }
 
-    Geometry::IDetector_const_sptr det;
-    try {
-      if (isSpectrum) {
-        auto it = specToIndex.find(detOrSpec);
-        if (it != specToIndex.end()) {
-          const size_t wsIndex = it->second;
-          det = m_workspace->getDetector(wsIndex);
+    bool skip{false};
+    size_t index = static_cast<size_t>(-1);
+    const Geometry::IDetector *det{nullptr};
+    if (isSpectrum) {
+      auto it = specToIndex.find(detOrSpec);
+      if (it != specToIndex.end()) {
+        index = it->second;
+        if (spectrumInfo.hasDetectors(index)) {
+          det = &spectrumInfo.detector(index);
         } else {
-          g_log.debug() << "Skipping \"" << line
-                        << "\". Spectrum is not in workspace.\n";
-          continue;
+          skip = true;
         }
       } else {
-        det = inst->getDetector(detOrSpec);
+        g_log.debug() << "Skipping \"" << line
+                      << "\". Spectrum is not in workspace.\n";
+        continue;
       }
-    } catch (Kernel::Exception::NotFoundError &) {
+    } else {
+      try {
+        index = detectorInfo.indexOf(detOrSpec);
+        det = &detectorInfo.detector(index);
+      } catch (std::out_of_range &) {
+        skip = true;
+      }
+    }
+    if (skip || index == static_cast<size_t>(-1)) {
       g_log.debug()
           << "Skipping \"" << line
           << "\". Spectrum in workspace but cannot find associated detector.\n";
       continue;
     }
 
+    std::vector<size_t> indices;
+    if (isSpectrum) {
+      if (auto group = dynamic_cast<const Geometry::DetectorGroup *>(det)) {
+        for (const auto detID : group->getDetectorIDs())
+          indices.push_back(detectorInfo.indexOf(detID));
+      } else {
+        indices.push_back(detectorInfo.indexOf(det->getID()));
+      }
+    } else {
+      indices.push_back(index);
+    }
+
     // Special cases for detector r,t,p. Everything else is
     // attached as an detector parameter
     double R(0.0), theta(0.0), phi(0.0);
@@ -270,7 +293,10 @@ void UpdateInstrumentFromFile::updateFromAscii(const std::string &filename) {
       else if (i == header.phiColIdx)
         phi = value;
       else if (header.detParCols.count(i) == 1) {
-        setDetectorParameter(det, header.colToName[i], value);
+        for (const auto index : indices) {
+          auto id = detectorInfo.detector(index).getComponentID();
+          pmap.addDouble(id, header.colToName[i], value);
+        }
       }
     }
     // Check stream state. stringstream::EOF should have been reached, if not
@@ -284,16 +310,20 @@ void UpdateInstrumentFromFile::updateFromAscii(const std::string &filename) {
 
     // If not supplied use current values
     double r, t, p;
-    det->getPos().getSpherical(r, t, p);
+    if (isSpectrum)
+      spectrumInfo.position(index).getSpherical(r, t, p);
+    else
+      detectorInfo.position(index).getSpherical(r, t, p);
     if (header.rColIdx == 0)
       R = r;
     if (header.thetaColIdx == 0)
       theta = t;
-    if (header.phiColIdx == 0)
+    if (header.phiColIdx == 0 || m_ignorePhi)
       phi = p;
 
-    setDetectorPosition(det, static_cast<float>(R), static_cast<float>(theta),
-                        static_cast<float>(phi));
+    for (const auto index : indices)
+      setDetectorPosition(detectorInfo, index, static_cast<float>(R),
+                          static_cast<float>(theta), static_cast<float>(phi));
   }
 }
 
@@ -350,27 +380,6 @@ bool UpdateInstrumentFromFile::parseAsciiHeader(
   return isSpectrum;
 }
 
-/**
- * Attaches a detector parameter to the given detector
- * @param det A pointer to the detector object
- * @param name The name of the parameter
- * @param value Value of the parameter
- */
-void UpdateInstrumentFromFile::setDetectorParameter(
-    const Geometry::IDetector_const_sptr &det, const std::string &name,
-    double value) {
-  Geometry::ParameterMap &pmap = m_workspace->instrumentParameters();
-  if (auto group =
-          boost::dynamic_pointer_cast<const Geometry::DetectorGroup>(det)) {
-    auto dets = group->getDetectors();
-    for (const auto &comp : dets) {
-      pmap.addDouble(comp->getComponentID(), name, value);
-    }
-  } else {
-    pmap.addDouble(det->getComponentID(), name, value);
-  }
-}
-
 /**
  * Set the detector positions given the r,theta and phi.
  * @param detID :: A vector of detector IDs
@@ -381,16 +390,23 @@ void UpdateInstrumentFromFile::setDetectorParameter(
 void UpdateInstrumentFromFile::setDetectorPositions(
     const std::vector<int32_t> &detID, const std::vector<float> &l2,
     const std::vector<float> &theta, const std::vector<float> &phi) {
-  Geometry::Instrument_const_sptr inst = m_workspace->getInstrument();
   const int numDetector = static_cast<int>(detID.size());
   g_log.information() << "Setting new positions for " << numDetector
                       << " detectors\n";
 
+  auto &detectorInfo = m_workspace->mutableDetectorInfo();
   for (int i = 0; i < numDetector; ++i) {
     try {
-      Geometry::IDetector_const_sptr det = inst->getDetector(detID[i]);
-      setDetectorPosition(det, l2[i], theta[i], phi[i]);
-    } catch (Kernel::Exception::NotFoundError &) {
+      auto index = detectorInfo.indexOf(detID[i]);
+      double p{phi[i]};
+      if (m_ignorePhi) {
+        double r, t;
+        detectorInfo.position(index).getSpherical(r, t, p);
+      }
+      setDetectorPosition(detectorInfo, index, l2[i], theta[i],
+                          static_cast<float>(p));
+    } catch (std::out_of_range &) {
+      // Invalid detID[i]
       continue;
     }
     progress(static_cast<double>(i) / numDetector,
@@ -400,37 +416,23 @@ void UpdateInstrumentFromFile::setDetectorPositions(
 
 /**
  * Set the new detector position given the r,theta and phi.
- * @param det :: A pointer to the detector
+ * @param detectorInfo :: Reference to the DetectorInfo
+ * @param index :: Index into detectorInfo
  * @param l2 :: A single l2
  * @param theta :: A single theta
  * @param phi :: A single phi
  */
-void UpdateInstrumentFromFile::setDetectorPosition(
-    const Geometry::IDetector_const_sptr &det, const float l2,
-    const float theta, const float phi) {
-  if (m_ignoreMonitors && det->isMonitor())
+void UpdateInstrumentFromFile::setDetectorPosition(DetectorInfo &detectorInfo,
+                                                   const size_t index,
+                                                   const float l2,
+                                                   const float theta,
+                                                   const float phi) {
+  if (m_ignoreMonitors && detectorInfo.isMonitor(index))
     return;
 
-  Geometry::ParameterMap &pmap = m_workspace->instrumentParameters();
   Kernel::V3D pos;
-  if (!m_ignorePhi) {
-    pos.spherical(l2, theta, phi);
-  } else {
-    double r, t, p;
-    det->getPos().getSpherical(r, t, p);
-    pos.spherical(l2, theta, p);
-  }
-  if (auto group =
-          boost::dynamic_pointer_cast<const Geometry::DetectorGroup>(det)) {
-    auto dets = group->getDetectors();
-    for (const auto &element : dets) {
-      Geometry::ComponentHelper::moveComponent(
-          *element, pmap, pos, Geometry::ComponentHelper::Absolute);
-    }
-  } else {
-    Geometry::ComponentHelper::moveComponent(
-        *det, pmap, pos, Geometry::ComponentHelper::Absolute);
-  }
+  pos.spherical(l2, theta, phi);
+  detectorInfo.setPosition(index, pos);
 }
 
 } // namespace DataHandling
diff --git a/Framework/DataHandling/test/CompressEventsTest.h b/Framework/DataHandling/test/CompressEventsTest.h
index 1516f7a8fda2f09e0b95e4dcf285a27f64661279..9d87bba6b3435e427c6c396738d5370751f868ff 100644
--- a/Framework/DataHandling/test/CompressEventsTest.h
+++ b/Framework/DataHandling/test/CompressEventsTest.h
@@ -41,7 +41,7 @@ public:
      * 200 events; two in each bin, at time 0.5, 1.5, etc.
      * PulseTime = 1 second, 2 seconds, etc.
      */
-    input = WorkspaceCreationHelper::CreateEventWorkspace(numPixels, 100, 100,
+    input = WorkspaceCreationHelper::createEventWorkspace(numPixels, 100, 100,
                                                           0.0, 1.0, 2);
     AnalysisDataService::Instance().addOrReplace(inputName, input);
     // Quick initial check
diff --git a/Framework/DataHandling/test/CreateChopperModelTest.h b/Framework/DataHandling/test/CreateChopperModelTest.h
index 26791ab88fd88c74597bbf61ff168df4c90a26f9..0ca6677ca31cad519e1824733a3dd5ebcd88e9a0 100644
--- a/Framework/DataHandling/test/CreateChopperModelTest.h
+++ b/Framework/DataHandling/test/CreateChopperModelTest.h
@@ -109,7 +109,7 @@ private:
   }
 
   Mantid::API::MatrixWorkspace_sptr createTestWorkspace() {
-    auto ws = WorkspaceCreationHelper::Create2DWorkspace(1, 10);
+    auto ws = WorkspaceCreationHelper::create2DWorkspace(1, 10);
     ws->mutableRun().addProperty("Ei", 45.0);
     ws->mutableRun().addProperty("ChopperSpeed", 150.0);
     return ws;
diff --git a/Framework/DataHandling/test/CreateChunkingFromInstrumentTest.h b/Framework/DataHandling/test/CreateChunkingFromInstrumentTest.h
index eaa50ed4042d8a3d2e3dd0c593673be0dcda1db8..0f11d5fbac794d1ecedc67d6aba9ebb6243fce74 100644
--- a/Framework/DataHandling/test/CreateChunkingFromInstrumentTest.h
+++ b/Framework/DataHandling/test/CreateChunkingFromInstrumentTest.h
@@ -3,6 +3,7 @@
 
 #include <cxxtest/TestSuite.h>
 
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/ITableWorkspace.h"
 #include "MantidDataHandling/CreateChunkingFromInstrument.h"
 
diff --git a/Framework/DataHandling/test/CreateModeratorModelTest.h b/Framework/DataHandling/test/CreateModeratorModelTest.h
index e21d49af90c8f9044e64baaf3b720309ba180c27..0c3e0393bdd7c02707f3a1ad790e27ce2fa10e98 100644
--- a/Framework/DataHandling/test/CreateModeratorModelTest.h
+++ b/Framework/DataHandling/test/CreateModeratorModelTest.h
@@ -113,7 +113,7 @@ private:
 
   Mantid::API::MatrixWorkspace_sptr createTestWorkspace() {
     using Mantid::API::MatrixWorkspace_sptr;
-    return WorkspaceCreationHelper::Create2DWorkspace(1, 10);
+    return WorkspaceCreationHelper::create2DWorkspace(1, 10);
   }
 
   const std::string m_inputName;
diff --git a/Framework/DataHandling/test/CreateSampleShapeTest.h b/Framework/DataHandling/test/CreateSampleShapeTest.h
index bf194e2b4c511ce3cf70013278ea6fdd7f1530e7..b950764814f48238a0b01e7693b00d44c172832e 100644
--- a/Framework/DataHandling/test/CreateSampleShapeTest.h
+++ b/Framework/DataHandling/test/CreateSampleShapeTest.h
@@ -57,7 +57,7 @@ public:
     using Mantid::Kernel::V3D;
     using Mantid::PhysicalConstants::getNeutronAtom;
 
-    auto inputWS = WorkspaceCreationHelper::Create2DWorkspaceBinned(1, 1);
+    auto inputWS = WorkspaceCreationHelper::create2DWorkspaceBinned(1, 1);
     auto sampleShape = ComponentCreationHelper::createSphere(0.5);
     sampleShape->setID("mysample");
     Material alum("Al", getNeutronAtom(13), 2.6989);
@@ -83,7 +83,7 @@ public:
     // Need a test workspace
     Mantid::API::AnalysisDataService::Instance().add(
         "TestWorkspace",
-        WorkspaceCreationHelper::Create2DWorkspace123(22, 10, 1));
+        WorkspaceCreationHelper::create2DWorkspace123(22, 10, 1));
 
     CreateSampleShape alg;
     TS_ASSERT_THROWS_NOTHING(alg.initialize());
diff --git a/Framework/DataHandling/test/CreateSimulationWorkspaceTest.h b/Framework/DataHandling/test/CreateSimulationWorkspaceTest.h
index c93b75abbf355ffc9d13e5656d759d27627170f1..7713089510f1016c6ee4bcb8dfac8ad771447370 100644
--- a/Framework/DataHandling/test/CreateSimulationWorkspaceTest.h
+++ b/Framework/DataHandling/test/CreateSimulationWorkspaceTest.h
@@ -4,6 +4,7 @@
 #include <cxxtest/TestSuite.h>
 
 #include "MantidDataHandling/CreateSimulationWorkspace.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Axis.h"
 #include "MantidAPI/AlgorithmManager.h"
 #include "MantidAPI/MatrixWorkspace.h"
diff --git a/Framework/DataHandling/test/DefineGaugeVolumeTest.h b/Framework/DataHandling/test/DefineGaugeVolumeTest.h
index 4cc6dcc15c9ed6fa8b279107aa8fce72aa80a636..5249777dc0aaaef183b7497b482433929625638d 100644
--- a/Framework/DataHandling/test/DefineGaugeVolumeTest.h
+++ b/Framework/DataHandling/test/DefineGaugeVolumeTest.h
@@ -4,6 +4,7 @@
 #include <cxxtest/TestSuite.h>
 #include "MantidDataHandling/DefineGaugeVolume.h"
 
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/Run.h"
 #include "MantidAPI/WorkspaceFactory.h"
diff --git a/Framework/DataHandling/test/DetermineChunkingTest.h b/Framework/DataHandling/test/DetermineChunkingTest.h
index b15a648fa30b8751bfc4dd1e4ccfe52778001314..07e8488a6c8226b44d0cd31524cdf5b3408814df 100644
--- a/Framework/DataHandling/test/DetermineChunkingTest.h
+++ b/Framework/DataHandling/test/DetermineChunkingTest.h
@@ -7,6 +7,7 @@
 
 #include "MantidDataHandling/DetermineChunking.h"
 #include "MantidDataObjects/TableWorkspace.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/TableRow.h"
 
 using namespace Mantid;
diff --git a/Framework/DataHandling/test/DownloadInstrumentTest.h b/Framework/DataHandling/test/DownloadInstrumentTest.h
index 22eb88013767523dfca8d79040591ed96c020d39..45a8dec95f9d09cc7ae2d1cb8b1faeedd475a1ad 100644
--- a/Framework/DataHandling/test/DownloadInstrumentTest.h
+++ b/Framework/DataHandling/test/DownloadInstrumentTest.h
@@ -4,6 +4,7 @@
 #include <cxxtest/TestSuite.h>
 
 #include "MantidDataHandling/DownloadInstrument.h"
+#include "MantidKernel/ConfigService.h"
 
 #include <Poco/Net/HTTPResponse.h>
 #include <Poco/Glob.h>
diff --git a/Framework/DataHandling/test/ExtractMonitorWorkspaceTest.h b/Framework/DataHandling/test/ExtractMonitorWorkspaceTest.h
index 6ddecf8e56e062c312a42f892a4f3806be6829e9..fa7a6ee512f5f098170af80857116e6b6cbd76c4 100644
--- a/Framework/DataHandling/test/ExtractMonitorWorkspaceTest.h
+++ b/Framework/DataHandling/test/ExtractMonitorWorkspaceTest.h
@@ -29,7 +29,7 @@ public:
   }
 
   void test_fails_if_no_monitor_workspace() {
-    auto inws = WorkspaceCreationHelper::Create1DWorkspaceRand(1);
+    auto inws = WorkspaceCreationHelper::create1DWorkspaceRand(1);
 
     ExtractMonitorWorkspace alg;
     TS_ASSERT_THROWS_NOTHING(alg.initialize())
@@ -77,8 +77,8 @@ public:
   }
 
   void test_2D_2D() {
-    auto inws = WorkspaceCreationHelper::Create1DWorkspaceRand(1);
-    auto monws = WorkspaceCreationHelper::Create1DWorkspaceFib(1);
+    auto inws = WorkspaceCreationHelper::create1DWorkspaceRand(1);
+    auto monws = WorkspaceCreationHelper::create1DWorkspaceFib(1);
     doTest(inws, monws);
   }
 
@@ -86,20 +86,20 @@ public:
   // type
 
   void test_2D_event() {
-    auto inws = WorkspaceCreationHelper::Create1DWorkspaceRand(1);
-    auto monws = WorkspaceCreationHelper::CreateEventWorkspace2(1, 1);
+    auto inws = WorkspaceCreationHelper::create1DWorkspaceRand(1);
+    auto monws = WorkspaceCreationHelper::createEventWorkspace2(1, 1);
     doTest(inws, monws);
   }
 
   void test_event_2D() {
-    auto inws = WorkspaceCreationHelper::CreateEventWorkspace2(1, 1);
-    auto monws = WorkspaceCreationHelper::Create1DWorkspaceRand(1);
+    auto inws = WorkspaceCreationHelper::createEventWorkspace2(1, 1);
+    auto monws = WorkspaceCreationHelper::create1DWorkspaceRand(1);
     doTest(inws, monws);
   }
 
   void test_event_event() {
-    auto inws = WorkspaceCreationHelper::CreateEventWorkspace2(1, 1);
-    auto monws = WorkspaceCreationHelper::CreateEventWorkspace2(1, 1);
+    auto inws = WorkspaceCreationHelper::createEventWorkspace2(1, 1);
+    auto monws = WorkspaceCreationHelper::createEventWorkspace2(1, 1);
     doTest(inws, monws);
   }
 
diff --git a/Framework/DataHandling/test/FindDetectorsInShapeTest.h b/Framework/DataHandling/test/FindDetectorsInShapeTest.h
index 350fa43e77e4256e60dc5b789fc2d434f0739f1e..e8918c444a31b6449c5ef0624586a2379ae6f508 100644
--- a/Framework/DataHandling/test/FindDetectorsInShapeTest.h
+++ b/Framework/DataHandling/test/FindDetectorsInShapeTest.h
@@ -5,6 +5,7 @@
 
 #include "MantidDataHandling/FindDetectorsInShape.h"
 #include "MantidDataHandling/LoadEmptyInstrument.h"
+#include "MantidAPI/AnalysisDataService.h"
 
 class FindDetectorsInShapeTest : public CxxTest::TestSuite {
 public:
diff --git a/Framework/DataHandling/test/FindDetectorsParTest.h b/Framework/DataHandling/test/FindDetectorsParTest.h
index f68e3cec6f8c10513c83d3d757e92b5a04399436..78c8e4d29cead1b2674d54f17a73a997793ee376 100644
--- a/Framework/DataHandling/test/FindDetectorsParTest.h
+++ b/Framework/DataHandling/test/FindDetectorsParTest.h
@@ -418,7 +418,7 @@ private:
   MatrixWorkspace_sptr buildUngroupedWS(const std::string &WS_Name) {
     const int NHIST = 3;
 
-    inputWS = WorkspaceCreationHelper::Create2DWorkspaceBinned(NHIST, 10, 1.0);
+    inputWS = WorkspaceCreationHelper::create2DWorkspaceBinned(NHIST, 10, 1.0);
 
     for (int j = 0; j < NHIST; ++j) {
       // Just set the spectrum number to match the index
@@ -450,7 +450,7 @@ private:
         ComponentCreationHelper::createRingOfCylindricalDetectors(4, 5, 4));
     const size_t NDET = pDet->nDets();
 
-    inputWS = WorkspaceCreationHelper::Create2DWorkspaceBinned(1, 10, 1.0);
+    inputWS = WorkspaceCreationHelper::create2DWorkspaceBinned(1, 10, 1.0);
 
     boost::shared_ptr<Geometry::Instrument> spInst(
         new Geometry::Instrument("basic_ring"));
diff --git a/Framework/DataHandling/test/GenerateGroupingPowderTest.h b/Framework/DataHandling/test/GenerateGroupingPowderTest.h
index 1567bd6da07367acd92974731e1b97837df5a1b8..9176052888fc24c19d35b03f10196e8dad2530b9 100644
--- a/Framework/DataHandling/test/GenerateGroupingPowderTest.h
+++ b/Framework/DataHandling/test/GenerateGroupingPowderTest.h
@@ -8,6 +8,7 @@
 #include "MantidDataHandling/LoadEmptyInstrument.h"
 #include "MantidDataHandling/GenerateGroupingPowder.h"
 #include "MantidDataHandling/LoadDetectorsGroupingFile.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidGeometry/Crystal/AngleUnits.h"
 
 using namespace Mantid;
diff --git a/Framework/DataHandling/test/GroupDetectors2Test.h b/Framework/DataHandling/test/GroupDetectors2Test.h
index 26bd8b3995ecf7b03579d1c7f7c0dedaeeeca0ef..434772d6e0811380e43a28dc6ac270b7121bc1a0 100644
--- a/Framework/DataHandling/test/GroupDetectors2Test.h
+++ b/Framework/DataHandling/test/GroupDetectors2Test.h
@@ -56,10 +56,6 @@ public:
       // the same for each bin
       space2D->setCounts(j, NBINS, j + 1);
       space2D->setCountStandardDeviations(j, errors);
-      space2D->getSpectrum(j).setSpectrumNo(j + 1); // spectra numbers are also
-                                                    // 1 + index_numbers
-                                                    // because this is the
-                                                    // tradition
       space2D->getSpectrum(j).setDetectorID(j);
     }
 
@@ -95,7 +91,7 @@ public:
 
   void testAveragingWithNoInstrument() {
     Workspace2D_sptr testWS =
-        WorkspaceCreationHelper::Create2DWorkspace123(3, 3, false);
+        WorkspaceCreationHelper::create2DWorkspace123(3, 3, false);
     GroupDetectors2 grouper;
     grouper.initialize();
     grouper.setChild(true);
@@ -532,7 +528,7 @@ public:
     int numPixels = 5;
     int numBins = 5;
     int numEvents = 200;
-    EventWorkspace_sptr input = WorkspaceCreationHelper::CreateEventWorkspace(
+    EventWorkspace_sptr input = WorkspaceCreationHelper::createEventWorkspace(
         numPixels, numBins, numEvents, 0, 1, 4);
     AnalysisDataService::Instance().addOrReplace("GDEvents", input);
     GroupDetectors2 alg2;
diff --git a/Framework/DataHandling/test/GroupDetectorsTest.h b/Framework/DataHandling/test/GroupDetectorsTest.h
index 4cc67d38032948633205828d9c4e8a65c7ed24c3..4ae58ace1837dfde443a8cf7587ada069b0e4068 100644
--- a/Framework/DataHandling/test/GroupDetectorsTest.h
+++ b/Framework/DataHandling/test/GroupDetectorsTest.h
@@ -5,6 +5,7 @@
 
 #include "MantidHistogramData/LinearGenerator.h"
 #include "MantidDataHandling/GroupDetectors.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Axis.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidAPI/WorkspaceProperty.h"
diff --git a/Framework/DataHandling/test/InstrumentRayTracerTest.h b/Framework/DataHandling/test/InstrumentRayTracerTest.h
index 1241629492be517f9f992eb512ecdd46bd63f89a..403a4d4f92e249a1b8cc3b372c04b51af8480c4d 100644
--- a/Framework/DataHandling/test/InstrumentRayTracerTest.h
+++ b/Framework/DataHandling/test/InstrumentRayTracerTest.h
@@ -47,7 +47,7 @@ public:
   InstrumentRayTracerTestPerformance() {
     m_inst = ComponentCreationHelper::createTestInstrumentRectangular(2, 100);
 
-    topazWS = WorkspaceCreationHelper::Create2DWorkspace(1, 2);
+    topazWS = WorkspaceCreationHelper::create2DWorkspace(1, 2);
     AnalysisDataService::Instance().add("TOPAZ_2010", topazWS);
     // Load a small test file
     FrameworkManager::Instance().exec(
diff --git a/Framework/DataHandling/test/LoadAsciiTest.h b/Framework/DataHandling/test/LoadAsciiTest.h
index 29bc2fa4e558fc2b3604873fcbf9537f825508d8..ebbb1a9f507ec265ce8ae29e29204af920f993be 100644
--- a/Framework/DataHandling/test/LoadAsciiTest.h
+++ b/Framework/DataHandling/test/LoadAsciiTest.h
@@ -307,4 +307,4 @@ private:
   }
 };
 
-#endif // LOADASCIITEST_H_
+#endif // LOADASCIITEST_H_
\ No newline at end of file
diff --git a/Framework/DataHandling/test/LoadCalFileTest.h b/Framework/DataHandling/test/LoadCalFileTest.h
index f5c96908b2384523e6132c95b100d1504ebb65cd..bd53ec47bed97c2d7cff0af781d6133e095b53dd 100644
--- a/Framework/DataHandling/test/LoadCalFileTest.h
+++ b/Framework/DataHandling/test/LoadCalFileTest.h
@@ -4,6 +4,8 @@
 #include <cxxtest/TestSuite.h>
 #include "MantidKernel/Timer.h"
 #include "MantidKernel/System.h"
+#include "MantidAPI/AnalysisDataService.h"
+#include "MantidAPI/DetectorInfo.h"
 #include "MantidAPI/Run.h"
 
 #include "MantidDataHandling/LoadCalFile.h"
@@ -89,10 +91,11 @@ public:
     TS_ASSERT_EQUALS(int(maskWS->getValue(101003)), 1);
     TS_ASSERT_EQUALS(int(maskWS->getValue(101008)), 1);
     TS_ASSERT_EQUALS(int(maskWS->getValue(715079)), 0);
-    TS_ASSERT(!maskWS->getInstrument()->getDetector(101001)->isMasked());
-    TS_ASSERT(maskWS->getInstrument()->getDetector(101003)->isMasked());
-    TS_ASSERT(maskWS->getInstrument()->getDetector(101008)->isMasked());
-    TS_ASSERT(!maskWS->getInstrument()->getDetector(715079)->isMasked());
+    const auto &detectorInfo = maskWS->detectorInfo();
+    TS_ASSERT(!detectorInfo.isMasked(detectorInfo.indexOf(101001)));
+    TS_ASSERT(detectorInfo.isMasked(detectorInfo.indexOf(101003)));
+    TS_ASSERT(detectorInfo.isMasked(detectorInfo.indexOf(101008)));
+    TS_ASSERT(!detectorInfo.isMasked(detectorInfo.indexOf(715079)));
     // Check if filename is saved
     TS_ASSERT_EQUALS(alg.getPropertyValue("CalFilename"),
                      maskWS->run().getProperty("Filename")->value());
diff --git a/Framework/DataHandling/test/LoadCanSAS1dTest.h b/Framework/DataHandling/test/LoadCanSAS1dTest.h
index 1efb62318e742a2605a76ec82c2594f8bf92da65..488e24632fefbb9252ced8cc2be08ae7ac0994eb 100644
--- a/Framework/DataHandling/test/LoadCanSAS1dTest.h
+++ b/Framework/DataHandling/test/LoadCanSAS1dTest.h
@@ -7,6 +7,7 @@
 #include "MantidDataObjects/Workspace2D.h"
 #include "MantidGeometry/Instrument.h"
 #include "MantidAPI/Run.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include <Poco/Path.h>
 
 class LoadCanSAS1dTest : public CxxTest::TestSuite {
diff --git a/Framework/DataHandling/test/LoadDetectorInfoTest.h b/Framework/DataHandling/test/LoadDetectorInfoTest.h
index b7c16c208e4f4ea631ad16b300f45f330dc1dfd4..1ade97d303c03c42ec1b09660febdb720e84c83d 100644
--- a/Framework/DataHandling/test/LoadDetectorInfoTest.h
+++ b/Framework/DataHandling/test/LoadDetectorInfoTest.h
@@ -6,6 +6,7 @@
 #include "MantidHistogramData/LinearGenerator.h"
 #include "MantidDataHandling/LoadDetectorInfo.h"
 #include "MantidDataHandling/LoadRaw3.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Axis.h"
 #include "MantidAPI/FileFinder.h"
 #include "MantidAPI/WorkspaceFactory.h"
@@ -219,12 +220,10 @@ void makeTestWorkspace(const int ndets, const int nbins,
     space2D->setCounts(j, nbins, j + 1);
     space2D->setCountStandardDeviations(j, errors);
     auto &spec = space2D->getSpectrum(j);
-    spec.setSpectrumNo(j + 1);
     spec.setDetectorID(j);
   }
 
   Instrument_sptr instr(new Instrument);
-  space2D->setInstrument(instr);
   ObjComponent *samplePos = new ObjComponent("sample-pos", instr.get());
   instr->markAsSamplePos(samplePos);
 
@@ -234,6 +233,7 @@ void makeTestWorkspace(const int ndets, const int nbins,
     Detector *d = new Detector(os.str(), i, 0);
     instr->markAsDetector(d);
   }
+  space2D->setInstrument(instr);
 
   // Register the workspace in the data service
   AnalysisDataService::Instance().add(ads_name, space2D);
diff --git a/Framework/DataHandling/test/LoadDetectorsGroupingFileTest.h b/Framework/DataHandling/test/LoadDetectorsGroupingFileTest.h
index 8b5b8b5cb54bd3057990bdacd38141c182cba5ca..9c77c21fea1a4421522bb6bd34276a7de89f0c9f 100644
--- a/Framework/DataHandling/test/LoadDetectorsGroupingFileTest.h
+++ b/Framework/DataHandling/test/LoadDetectorsGroupingFileTest.h
@@ -4,6 +4,7 @@
 #include "MantidKernel/Timer.h"
 #include "MantidKernel/System.h"
 
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Run.h"
 #include "MantidDataHandling/LoadDetectorsGroupingFile.h"
 #include "MantidDataObjects/GroupingWorkspace.h"
diff --git a/Framework/DataHandling/test/LoadDiffCalTest.h b/Framework/DataHandling/test/LoadDiffCalTest.h
index 097f6fe5b9a1d9e72e87215391d8ad07b7003ba4..733638d3d4efc1b6286062a2d4e6cdbf7a08bc6a 100644
--- a/Framework/DataHandling/test/LoadDiffCalTest.h
+++ b/Framework/DataHandling/test/LoadDiffCalTest.h
@@ -3,6 +3,7 @@
 
 #include <cxxtest/TestSuite.h>
 
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/FrameworkManager.h"
 #include "MantidDataHandling/LoadDiffCal.h"
 // reuse what another test has for creating dummy workspaces
diff --git a/Framework/DataHandling/test/LoadDspacemapTest.h b/Framework/DataHandling/test/LoadDspacemapTest.h
index d00455638b4fb0e6c1aa1a1cd2077560b1c4c5c8..436509e27c298a9ae1478dd5d06deeaa03311cde 100644
--- a/Framework/DataHandling/test/LoadDspacemapTest.h
+++ b/Framework/DataHandling/test/LoadDspacemapTest.h
@@ -4,6 +4,7 @@
 #include "MantidDataHandling/LoadDspacemap.h"
 #include "MantidDataHandling/LoadEmptyInstrument.h"
 #include "MantidDataObjects/OffsetsWorkspace.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidKernel/ConfigService.h"
 #include "MantidKernel/System.h"
 #include "MantidKernel/Timer.h"
diff --git a/Framework/DataHandling/test/LoadEventNexusTest.h b/Framework/DataHandling/test/LoadEventNexusTest.h
index c38a31c87b6b68fb92292c0d6c8a9608d128b3c4..ed806df1d14bcc8e40443403b0915fc8f64836bd 100644
--- a/Framework/DataHandling/test/LoadEventNexusTest.h
+++ b/Framework/DataHandling/test/LoadEventNexusTest.h
@@ -6,6 +6,7 @@
 #include "MantidAPI/FrameworkManager.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/Run.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidAPI/Workspace.h"
 #include "MantidDataObjects/EventWorkspace.h"
 #include "MantidKernel/Property.h"
@@ -464,12 +465,11 @@ public:
     TS_ASSERT_EQUALS(WS->dataE(0).size(), 200001);
     TS_ASSERT_DELTA(WS->dataE(0)[12], 0.0, 1e-6);
     // Check geometry for a monitor
-    IDetector_const_sptr mon = WS->getDetector(2);
-    TS_ASSERT(mon->isMonitor());
-    TS_ASSERT_EQUALS(mon->getID(), -3);
-    boost::shared_ptr<const IComponent> sample =
-        WS->getInstrument()->getSample();
-    TS_ASSERT_DELTA(mon->getDistance(*sample), 1.426, 1e-6);
+    const auto &specInfo = WS->spectrumInfo();
+    TS_ASSERT(specInfo.isMonitor(2));
+    TS_ASSERT_EQUALS(specInfo.detector(2).getID(), -3);
+    TS_ASSERT_DELTA(specInfo.samplePosition().distance(specInfo.position(2)),
+                    1.426, 1e-6);
 
     // Check monitor workspace pointer held in main workspace
     TS_ASSERT_EQUALS(WS, ads.retrieveWS<MatrixWorkspace>("cncs_compressed")
@@ -557,7 +557,7 @@ public:
     TS_ASSERT_EQUALS(inst->getValidFromDate(),
                      std::string("2011-Jul-20 17:02:48.437294000"));
     TS_ASSERT_EQUALS(inst->getNumberDetectors(), 20483);
-    TS_ASSERT_EQUALS(inst->baseInstrument()->numMonitors(), 3);
+    TS_ASSERT_EQUALS(inst->baseInstrument()->getMonitors().size(), 3);
     auto params = inst->getParameterMap();
     TS_ASSERT_EQUALS(params->size(), 49);
     TS_ASSERT_EQUALS(params->getString(inst.get(), "deltaE-mode"), "direct");
@@ -580,7 +580,7 @@ public:
                                              // file
     TS_ASSERT_EQUALS(inst->getName(), "CNCS");
     TS_ASSERT_EQUALS(inst->getNumberDetectors(), 51203);
-    TS_ASSERT_EQUALS(inst->baseInstrument()->numMonitors(), 3);
+    TS_ASSERT_EQUALS(inst->baseInstrument()->getMonitors().size(), 3);
 
     // check that CNCS_Parameters.xml has been loaded
     auto params = inst->getParameterMap();
diff --git a/Framework/DataHandling/test/LoadEventPreNexus2Test.h b/Framework/DataHandling/test/LoadEventPreNexus2Test.h
index f18db11ae8b6bc3b2bd0f23c043957c609b7f728..1b2b1a7175dd4281ad4847c9890adcc9d66cfbf7 100644
--- a/Framework/DataHandling/test/LoadEventPreNexus2Test.h
+++ b/Framework/DataHandling/test/LoadEventPreNexus2Test.h
@@ -12,6 +12,7 @@
 
 #include "MantidDataHandling/LoadEventPreNexus2.h"
 
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Axis.h"
 #include "MantidAPI/Run.h"
 #include "MantidAPI/WorkspaceFactory.h"
diff --git a/Framework/DataHandling/test/LoadEventPreNexusTest.h b/Framework/DataHandling/test/LoadEventPreNexusTest.h
deleted file mode 100644
index 59e16806de12bb8f4290b18b73265e64aeee888a..0000000000000000000000000000000000000000
--- a/Framework/DataHandling/test/LoadEventPreNexusTest.h
+++ /dev/null
@@ -1,306 +0,0 @@
-/*
- * LoadEventPreNexusTest.h
- *
- *  Created on: Jun 23, 2010
- *      Author: janik zikovsky
- */
-
-#ifndef LOADEVENTPRENEXUSTEST_H_
-#define LOADEVENTPRENEXUSTEST_H_
-
-#include <cxxtest/TestSuite.h>
-
-#include "MantidDataHandling/LoadEventPreNexus.h"
-
-#include "MantidAPI/Axis.h"
-#include "MantidAPI/Run.h"
-#include "MantidAPI/WorkspaceFactory.h"
-#include "MantidDataObjects/EventList.h"
-#include "MantidDataObjects/EventWorkspace.h"
-#include "MantidDataObjects/Workspace2D.h"
-#include "MantidGeometry/Instrument.h"
-#include "MantidKernel/DateAndTime.h"
-#include "MantidKernel/TimeSeriesProperty.h"
-
-#include <sys/stat.h>
-
-using namespace Mantid;
-using namespace Mantid::DataHandling;
-using namespace Mantid::DataObjects;
-using namespace Mantid::Kernel;
-using namespace Mantid::Kernel::Exception;
-using namespace Mantid::API;
-using namespace Mantid::Geometry;
-using Mantid::HistogramData::HistogramX;
-
-using std::runtime_error;
-using std::size_t;
-using std::vector;
-using std::cout;
-
-//==========================================================================================
-class LoadEventPreNexusTest : public CxxTest::TestSuite {
-public:
-  LoadEventPreNexus *eventLoader;
-
-  static LoadEventPreNexusTest *createSuite() {
-    return new LoadEventPreNexusTest();
-  }
-  static void destroySuite(LoadEventPreNexusTest *suite) { delete suite; }
-
-  LoadEventPreNexusTest() {}
-
-  void setUp() override {
-    eventLoader = new LoadEventPreNexus();
-    eventLoader->initialize();
-  }
-
-  void test_file_not_found() {
-    TS_ASSERT_THROWS(eventLoader->setPropertyValue(
-                         "EventFilename", "this_file_doesnt_exist.blabla.data"),
-                     std::invalid_argument);
-    // Execute fails since the properties aren't set correctly.
-    TS_ASSERT_THROWS(eventLoader->execute(), std::runtime_error);
-  }
-
-  void test_data_sizes() {
-    // Make sure the structs are the right size
-    TS_ASSERT_EQUALS(sizeof(Pulse), 24);
-    TS_ASSERT_EQUALS(sizeof(DasEvent), 8);
-  }
-
-  void checkWorkspace(std::string eventfile, std::string WSName,
-                      int numpixels_with_events) {
-    // Get the event file size
-    struct stat filestatus;
-    stat(eventfile.c_str(), &filestatus);
-
-    EventWorkspace_sptr ew =
-        AnalysisDataService::Instance().retrieveWS<EventWorkspace>(WSName);
-
-    // The # of events = size of the file / 8 bytes (per event)
-    TS_ASSERT_EQUALS(ew->getNumberEvents(), filestatus.st_size / 8);
-
-    // Only some of the pixels were loaded, because of lot of them are empty
-    TS_ASSERT_EQUALS(ew->getNumberHistograms(), numpixels_with_events);
-
-    // Mapping between workspace index and spectrum number
-    // Is the length good?
-    TS_ASSERT_EQUALS(ew->getAxis(1)->length(), numpixels_with_events);
-  }
-
-  void test_LoadPreNeXus_REFL() {
-    std::string eventfile("REF_L_32035_neutron_event.dat");
-    std::string pulsefile("REF_L_32035_pulseid.dat");
-    eventLoader->setPropertyValue("EventFilename", eventfile);
-    eventLoader->setPropertyValue("PulseidFilename", pulsefile);
-    eventLoader->setPropertyValue("MappingFilename", "REF_L_TS_2010_02_19.dat");
-    eventLoader->setPropertyValue("OutputWorkspace", "refl");
-
-    // Get the event file size
-    struct stat filestatus;
-    eventfile = eventLoader->getPropertyValue("EventFilename");
-    stat(eventfile.c_str(), &filestatus);
-
-    // no instrument definition - should fail
-    TS_ASSERT((eventLoader->execute()));
-  }
-
-  void test_LoadPreNeXus_CNCS_7860() {
-    std::string eventfile("CNCS_7860_neutron_event.dat");
-    eventLoader->setPropertyValue("EventFilename", eventfile);
-    eventLoader->setPropertyValue("MappingFilename", "CNCS_TS_2008_08_18.dat");
-    eventLoader->setPropertyValue("OutputWorkspace", "cncs");
-
-    // Get the event file size
-    struct stat filestatus;
-    stat(eventfile.c_str(), &filestatus);
-
-    // std::cout << "***** executing *****\n";
-    TS_ASSERT(eventLoader->execute());
-
-    EventWorkspace_sptr ew = boost::dynamic_pointer_cast<EventWorkspace>(
-        AnalysisDataService::Instance().retrieve("cncs"));
-
-    // Get the start time of all pulses
-    Kernel::TimeSeriesProperty<double> *log =
-        dynamic_cast<Kernel::TimeSeriesProperty<double> *>(
-            ew->mutableRun().getProperty("proton_charge"));
-    std::map<DateAndTime, double> logMap = log->valueAsMap();
-    std::map<DateAndTime, double>::iterator it, it2;
-    it = logMap.begin();
-    Kernel::DateAndTime start = it->first;
-
-    std::vector<TofEvent> events1 = ew->getSpectrum(1000).getEvents();
-    for (size_t i = 0; i < events1.size(); i++) {
-      std::cout << (events1[i].pulseTime() - start) << " sec \n";
-    }
-  }
-
-  void test_LoadPreNeXus_CNCS() { do_test_LoadPreNeXus_CNCS("Serial"); }
-
-  void test_LoadPreNeXus_CNCS_parallel() {
-    do_test_LoadPreNeXus_CNCS("Parallel");
-  }
-
-  void do_test_LoadPreNeXus_CNCS(std::string parallel) {
-    std::string eventfile("CNCS_7860_neutron_event.dat");
-    eventLoader->setPropertyValue("EventFilename", eventfile);
-    eventLoader->setPropertyValue("MappingFilename", "CNCS_TS_2008_08_18.dat");
-    eventLoader->setPropertyValue("OutputWorkspace", "cncs");
-    eventLoader->setPropertyValue("UseParallelProcessing", parallel);
-
-    // Get the event file size
-    struct stat filestatus;
-    stat(eventfile.c_str(), &filestatus);
-
-    // std::cout << "***** executing *****\n";
-    TS_ASSERT(eventLoader->execute());
-
-    EventWorkspace_sptr ew = boost::dynamic_pointer_cast<EventWorkspace>(
-        AnalysisDataService::Instance().retrieve("cncs"));
-
-    // The # of events = size of the file / 8 bytes (per event)
-    // This fails cause of errors in events
-    TS_ASSERT_EQUALS(ew->getNumberEvents(), 112266);
-
-    // We pad all pixels by default
-    int numpixels_with_events = 51200;
-    TS_ASSERT_EQUALS(ew->getNumberHistograms(), numpixels_with_events);
-
-    // Check if the instrument was loaded correctly
-    boost::shared_ptr<const Instrument> inst = ew->getInstrument();
-    TS_ASSERT_EQUALS(inst->getName(), "CNCS");
-
-    // Mapping between workspace index and spectrum number
-    // Is the length good?
-    TS_ASSERT_EQUALS(ew->getAxis(1)->length(), numpixels_with_events);
-
-    //--------------------------------------------------------
-    // Now let's test if a copy works too
-    EventWorkspace_sptr inputWS = ew;
-    TS_ASSERT_EQUALS(inputWS->getInstrument()->getName(), "CNCS");
-
-    // Create a new one
-    auto outputWS = inputWS->clone();
-
-    // Bunch of checks
-    TS_ASSERT_EQUALS(outputWS->getNumberEvents(), inputWS->getNumberEvents());
-    TS_ASSERT_EQUALS(outputWS->getNumberHistograms(),
-                     inputWS->getNumberHistograms());
-    TS_ASSERT_EQUALS(outputWS->getInstrument()->getName(), "CNCS");
-
-    std::size_t wkspIndex = 4348; // a good workspace index (with events)
-    TS_ASSERT_EQUALS(outputWS->getSpectrum(wkspIndex).getNumberEvents(), 11);
-    if (outputWS->getSpectrum(wkspIndex).getNumberEvents() != 11)
-      return;
-
-    TS_ASSERT_EQUALS(outputWS->getSpectrum(wkspIndex).getEvents()[0].tof(),
-                     inputWS->getSpectrum(wkspIndex).getEvents()[0].tof());
-    // It should be possible to change an event list and not affect the other
-    // one
-    outputWS->getSpectrum(wkspIndex).convertTof(1.5, 0.2);
-    TS_ASSERT_DIFFERS(outputWS->getSpectrum(wkspIndex).getEvents()[0].tof(),
-                      inputWS->getSpectrum(wkspIndex).getEvents()[0].tof());
-
-    // Setting X should still be possible
-    Kernel::cow_ptr<HistogramX> x;
-    TS_ASSERT_THROWS_NOTHING(outputWS->setX(0, x));
-    // Accessing Y is still possible
-    static_cast<void>(outputWS->y(0));
-
-    // Check the run_start property exists and is right.
-    Property *p = NULL;
-    TS_ASSERT(outputWS->mutableRun().hasProperty("run_start"));
-    TS_ASSERT_THROWS_NOTHING(
-        p = outputWS->mutableRun().getProperty("run_start");)
-    if (p) {
-      TS_ASSERT_EQUALS(p->value(), "2010-03-25T16:08:37.457381666");
-    }
-  }
-
-  void test_LoadPreNeXus_CNCS_SkipPixels() {
-    std::string eventfile("CNCS_7860_neutron_event.dat");
-    eventLoader->setPropertyValue("EventFilename", eventfile);
-    eventLoader->setPropertyValue("MappingFilename", "CNCS_TS_2008_08_18.dat");
-    eventLoader->setPropertyValue("OutputWorkspace", "cncs_skipped");
-    // Load just 2 pixels
-    eventLoader->setProperty("SpectrumList", "45, 110");
-
-    TS_ASSERT(eventLoader->execute());
-
-    EventWorkspace_sptr ew = boost::dynamic_pointer_cast<EventWorkspace>(
-        AnalysisDataService::Instance().retrieve("cncs_skipped"));
-
-    // Only some of the pixels weretof loaded, because of lot of them are empty
-    int numpixels = 2;
-    TS_ASSERT_EQUALS(ew->getNumberHistograms(), numpixels);
-
-    // Mapping between workspace index and spectrum number; simple
-    TS_ASSERT_EQUALS(ew->getAxis(1)->spectraNo(0), 46);
-    TS_ASSERT_EQUALS(ew->getAxis(1)->spectraNo(1), 111);
-    TS_ASSERT_EQUALS(ew->getAxis(1)->length(), 2);
-
-    // Are the pixel IDs ok?
-    TS_ASSERT_EQUALS(ew->getSpectrum(0).getSpectrumNo(), 46);
-    auto dets = ew->getSpectrum(0).getDetectorIDs();
-    TS_ASSERT_EQUALS(dets.size(), 1);
-    TS_ASSERT_EQUALS(*dets.begin(), 45);
-
-    TS_ASSERT_EQUALS(ew->getSpectrum(1).getSpectrumNo(), 111);
-    dets = ew->getSpectrum(1).getDetectorIDs();
-    TS_ASSERT_EQUALS(dets.size(), 1);
-    TS_ASSERT_EQUALS(*dets.begin(), 110);
-  }
-
-  void test_invalid_chunk_number() {
-    eventLoader->setPropertyValue("EventFilename",
-                                  "CNCS_7860_neutron_event.dat");
-    eventLoader->setPropertyValue("ChunkNumber", "3");
-    eventLoader->setPropertyValue("TotalChunks", "2");
-    TS_ASSERT_THROWS(eventLoader->execute(), std::runtime_error);
-  }
-
-  void test_loading_chunks() {
-    // Load chunk 1 of 2
-    eventLoader->setPropertyValue("EventFilename",
-                                  "CNCS_7860_neutron_event.dat");
-    eventLoader->setPropertyValue("ChunkNumber", "1");
-    eventLoader->setPropertyValue("TotalChunks", "2");
-    eventLoader->setPropertyValue("OutputWorkspace", "chunk1");
-    TS_ASSERT(eventLoader->execute());
-    EventWorkspace_sptr chunk1 = boost::dynamic_pointer_cast<EventWorkspace>(
-        AnalysisDataService::Instance().retrieve("chunk1"));
-
-    // Load chunk 2 of 2
-    eventLoader->setPropertyValue("EventFilename",
-                                  "CNCS_7860_neutron_event.dat");
-    eventLoader->setPropertyValue("ChunkNumber", "2");
-    eventLoader->setPropertyValue("TotalChunks", "2");
-    eventLoader->setPropertyValue("OutputWorkspace", "chunk2");
-    TS_ASSERT(eventLoader->execute());
-    EventWorkspace_sptr chunk2 = boost::dynamic_pointer_cast<EventWorkspace>(
-        AnalysisDataService::Instance().retrieve("chunk2"));
-
-    // The number of events should be roughly equal and the sum should be 112266
-    TS_ASSERT_EQUALS(chunk1->getNumberEvents(), 56139)
-    TS_ASSERT_EQUALS(chunk2->getNumberEvents(), 56127)
-  }
-};
-
-//------------------------------------------------------------------------------
-// Performance test
-//------------------------------------------------------------------------------
-
-class LoadEventPreNexusTestPerformance : public CxxTest::TestSuite {
-public:
-  void testDefaultLoad() {
-    LoadEventPreNexus loader;
-    loader.initialize();
-    loader.setPropertyValue("EventFilename", "CNCS_7860_neutron_event.dat");
-    loader.setPropertyValue("OutputWorkspace", "ws");
-    TS_ASSERT(loader.execute());
-  }
-};
-
-#endif /* LOADEVENTPRENEXUSTEST_H_ */
diff --git a/Framework/DataHandling/test/LoadFITSTest.h b/Framework/DataHandling/test/LoadFITSTest.h
index 875959d9bda5fad58a43485d0c9add20ea4b4bc1..c68e416ee1cd01ce3bb82c4d16fe80d17d2639d3 100644
--- a/Framework/DataHandling/test/LoadFITSTest.h
+++ b/Framework/DataHandling/test/LoadFITSTest.h
@@ -6,6 +6,7 @@
 #include "MantidAPI/AlgorithmManager.h"
 #include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Run.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidDataHandling/LoadFITS.h"
 #include <MantidAPI/FrameworkManager.h>
 
@@ -163,12 +164,12 @@ public:
 
     // Sum the two bins from the last spectra - should be 70400
     double sumY =
-        ws1->readY(g_SPECTRA_COUNT - 1)[0] + ws2->readY(g_SPECTRA_COUNT - 1)[0];
+        ws1->y(g_SPECTRA_COUNT - 1)[0] + ws2->y(g_SPECTRA_COUNT - 1)[0];
     TS_ASSERT_EQUALS(sumY, 275);
     // Check the sum of the error values for the last spectra in each file -
     // should be 375.183
     double sumE =
-        ws1->readE(g_SPECTRA_COUNT - 1)[0] + ws2->readE(g_SPECTRA_COUNT - 1)[0];
+        ws1->e(g_SPECTRA_COUNT - 1)[0] + ws2->e(g_SPECTRA_COUNT - 1)[0];
     TS_ASSERT_LESS_THAN(std::abs(sumE - 23.4489), 0.0001); // Include a small
     // tolerance check with
     // the assert - not
@@ -209,9 +210,9 @@ public:
       TS_ASSERT_EQUALS(ws->getNumberHistograms(), g_SPECTRA_COUNT);
 
       // check Y and Error
-      TS_ASSERT_EQUALS(ws->readY(g_SPECTRA_COUNT - 100)[0], expectedY[i]);
+      TS_ASSERT_EQUALS(ws->y(g_SPECTRA_COUNT - 100)[0], expectedY[i]);
       TS_ASSERT_LESS_THAN(
-          std::abs(ws->readE(g_SPECTRA_COUNT - 100)[0] - expectedE[i]), 0.0001);
+          std::abs(ws->e(g_SPECTRA_COUNT - 100)[0] - expectedE[i]), 0.0001);
     }
   }
 
@@ -347,15 +348,15 @@ public:
     size_t n = ws0->getNumberHistograms();
     TSM_ASSERT_EQUALS(
         "The value at a given spectrum and bin (first one) is not as expected",
-        ws0->readY(n - 1)[0], 137);
+        ws0->y(n - 1)[0], 137);
 
     TSM_ASSERT_EQUALS(
         "The value at a given spectrum and bin (middle one) is not as expected",
-        ws0->readY(n - 1)[g_SPECTRA_COUNT_ASRECT / 2], 159);
+        ws0->y(n - 1)[g_SPECTRA_COUNT_ASRECT / 2], 159);
 
     TSM_ASSERT_EQUALS(
         "The value at a given spectrum and bin (last one) is not as expected",
-        ws0->readY(n - 1).back(), 142);
+        ws0->y(n - 1).back(), 142);
 
     MatrixWorkspace_sptr ws1;
     TS_ASSERT_THROWS_NOTHING(
@@ -366,15 +367,15 @@ public:
                       ws1->getTitle(), g_smallFname2);
     TSM_ASSERT_EQUALS(
         "The value at a given spectrum and bin (first one) is not as expected",
-        ws1->readY(n - 1)[0], 155);
+        ws1->y(n - 1)[0], 155);
 
     TSM_ASSERT_EQUALS(
         "The value at a given spectrum and bin (middle one) is not as expected",
-        ws1->readY(n - 1)[g_SPECTRA_COUNT_ASRECT / 2], 199);
+        ws1->y(n - 1)[g_SPECTRA_COUNT_ASRECT / 2], 199);
 
     TSM_ASSERT_EQUALS(
         "The value at a given spectrum and bin (last one) is not as expected",
-        ws1->readY(n - 1).back(), 133);
+        ws1->y(n - 1).back(), 133);
   }
 
   void test_loadEmpty() {
diff --git a/Framework/DataHandling/test/LoadFullprofResolutionTest.h b/Framework/DataHandling/test/LoadFullprofResolutionTest.h
index 63d8c9537a4999e5477cccdc827c8083ee8d27e4..892f17551c5e930adf3b74a2c2b8cc0a4b21e432 100644
--- a/Framework/DataHandling/test/LoadFullprofResolutionTest.h
+++ b/Framework/DataHandling/test/LoadFullprofResolutionTest.h
@@ -7,6 +7,7 @@
 #include "MantidDataObjects/TableWorkspace.h"
 #include "MantidAPI/TableRow.h"
 #include "MantidAPI/WorkspaceFactory.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidDataHandling/LoadInstrument.h"
 #include "MantidDataObjects/Workspace2D.h"
 #include "MantidGeometry/Instrument.h"
diff --git a/Framework/DataHandling/test/LoadGSASInstrumentFileTest.h b/Framework/DataHandling/test/LoadGSASInstrumentFileTest.h
index c77d1da9fd6399c00d5005c5f6799c63d489ebb4..3d4e3add2b2ec3040e268ac302b6f6fb925079f7 100644
--- a/Framework/DataHandling/test/LoadGSASInstrumentFileTest.h
+++ b/Framework/DataHandling/test/LoadGSASInstrumentFileTest.h
@@ -7,6 +7,7 @@
 #include "MantidDataObjects/TableWorkspace.h"
 #include "MantidAPI/TableRow.h"
 #include "MantidAPI/WorkspaceFactory.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidDataHandling/LoadInstrument.h"
 #include "MantidDataObjects/Workspace2D.h"
 #include "MantidGeometry/Instrument.h"
diff --git a/Framework/DataHandling/test/LoadGSSTest.h b/Framework/DataHandling/test/LoadGSSTest.h
index 69b211b760bd3fa7f000288d7321c005d633002a..c42f27213775d8cab750e847225bce675a460719 100644
--- a/Framework/DataHandling/test/LoadGSSTest.h
+++ b/Framework/DataHandling/test/LoadGSSTest.h
@@ -4,6 +4,7 @@
 #include "cxxtest/TestSuite.h"
 #include "MantidDataHandling/LoadGSS.h"
 #include "MantidAPI/AlgorithmManager.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Axis.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidTestHelpers/ScopedFileHelper.h"
@@ -27,13 +28,14 @@ public:
   void test_load_gss_txt() {
     API::IAlgorithm_sptr loader = createAlgorithm();
     loader->setPropertyValue("Filename", "gss.txt");
-    TS_ASSERT(loader->execute())
+    loader->setRethrows(true);
+    TS_ASSERT_THROWS_NOTHING(loader->execute());
     API::MatrixWorkspace_const_sptr ws = loader->getProperty("OutputWorkspace");
     // Check a few things in the workspace
     checkWorkspace(ws, 8, 816);
-    auto x1 = ws->readX(0)[99];
-    auto x2 = ws->readX(0)[100];
-    auto y = ws->readY(0)[99];
+    auto x1 = ws->x(0)[99];
+    auto x2 = ws->x(0)[100];
+    auto y = ws->y(0)[99];
     TS_ASSERT_DELTA((x1 + x2) / 2, 40844.0625, 1e-6);
     TS_ASSERT_DELTA(y, 145304004.625, 1e-6);
   }
@@ -71,16 +73,16 @@ public:
     TS_ASSERT(loader->execute());
     TS_ASSERT_EQUALS(loader->isExecuted(), true);
     API::MatrixWorkspace_const_sptr ws = loader->getProperty("OutputWorkspace");
-    auto x1 = ws->readX(0)[0];
-    auto x2 = ws->readX(0)[1];
+    auto x1 = ws->x(0)[0];
+    auto x2 = ws->x(0)[1];
     auto dx = x2 - x1;
-    auto y = ws->readY(0)[0] * dx;
+    auto y = ws->y(0)[0] * dx;
     TS_ASSERT_DELTA((x1 + x2) / 2, 115202.20029, 1e-6);
     TS_ASSERT_DELTA(y, 123456.00000002, 1e-10);
-    x1 = ws->readX(0)[3];
-    x2 = ws->readX(0)[4];
+    x1 = ws->x(0)[3];
+    x2 = ws->x(0)[4];
     dx = x2 - x1;
-    y = ws->readY(0)[3] * dx;
+    y = ws->y(0)[3] * dx;
     TS_ASSERT_DELTA(y, 123456789.00000005, 1e-10);
 
     const auto source = ws->getInstrument()->getSource();
@@ -177,4 +179,43 @@ private:
   }
 };
 
+class LoadGSSTestPerformance : public CxxTest::TestSuite {
+public:
+  void setUp() override {
+    for (int i = 0; i < numberOfIterations; ++i) {
+      loadAlgPtrs.emplace_back(setupAlg());
+    }
+  }
+
+  void testLoadGSSPerformance() {
+    for (auto alg : loadAlgPtrs) {
+      TS_ASSERT_THROWS_NOTHING(alg->execute());
+    }
+  }
+
+  void tearDown() override {
+    for (int i = 0; i < numberOfIterations; i++) {
+      delete loadAlgPtrs[i];
+      loadAlgPtrs[i] = nullptr;
+    }
+    API::AnalysisDataService::Instance().remove(outWsName);
+  }
+
+private:
+  std::vector<LoadGSS *> loadAlgPtrs;
+  const int numberOfIterations = 100;
+  const std::string outWsName = "TestWS";
+
+  LoadGSS *setupAlg() {
+    LoadGSS *loadAlg = new LoadGSS();
+    loadAlg->initialize();
+
+    loadAlg->setPropertyValue("Filename", "gss1.txt");
+    loadAlg->setProperty("OutputWorkspace", outWsName);
+    loadAlg->setProperty("UseBankIDasSpectrumNumber", true);
+
+    loadAlg->setRethrows(true);
+    return loadAlg;
+  }
+};
 #endif // LOADGSSTEST_H_
diff --git a/Framework/DataHandling/test/LoadIDFFromNexusTest.h b/Framework/DataHandling/test/LoadIDFFromNexusTest.h
index 9745930d68d517fdcbb042de0a6ae2eaf07a6ee2..116fa0aae5a0257b28f5588a3c28e9cceb76f06a 100644
--- a/Framework/DataHandling/test/LoadIDFFromNexusTest.h
+++ b/Framework/DataHandling/test/LoadIDFFromNexusTest.h
@@ -9,6 +9,7 @@
 #include "MantidDataObjects/Workspace2D.h"
 #include "MantidAPI/AnalysisDataService.h"
 #include "MantidKernel/Exception.h"
+#include "MantidAPI/DetectorInfo.h"
 #include "MantidAPI/FrameworkManager.h"
 #include "MantidAPI/Workspace.h"
 #include "MantidAPI/Algorithm.h"
@@ -119,12 +120,13 @@ public:
     TS_ASSERT_THROWS(i->getDetector(16735), Exception::NotFoundError);
 
     // Check the monitors are correctly marked
-    TS_ASSERT(i->getDetector(1)->isMonitor())
-    TS_ASSERT(i->getDetector(2)->isMonitor())
+    const auto &detInfo = output->detectorInfo();
+    TS_ASSERT(detInfo.isMonitor(0))
+    TS_ASSERT(detInfo.isMonitor(1))
     // ...and that a normal detector isn't
-    TS_ASSERT(!i->getDetector(3)->isMonitor())
-    TS_ASSERT(!i->getDetector(300)->isMonitor())
-    TS_ASSERT(!i->getDetector(16500)->isMonitor())
+    TS_ASSERT(!detInfo.isMonitor(2))
+    TS_ASSERT(!detInfo.isMonitor(299))
+    TS_ASSERT(!detInfo.isMonitor(16499))
 
     AnalysisDataService::Instance().remove(wsName);
   }
diff --git a/Framework/DataHandling/test/LoadILLIndirect2Test.h b/Framework/DataHandling/test/LoadILLIndirect2Test.h
new file mode 100644
index 0000000000000000000000000000000000000000..560e0c76e531e7faad086021036a61029c143d6c
--- /dev/null
+++ b/Framework/DataHandling/test/LoadILLIndirect2Test.h
@@ -0,0 +1,100 @@
+#ifndef MANTID_DATAHANDLING_LOADILLINDIRECT2TEST_H_
+#define MANTID_DATAHANDLING_LOADILLINDIRECT2TEST_H_
+
+#include <cxxtest/TestSuite.h>
+
+#include "MantidAPI/AnalysisDataService.h"
+#include "MantidAPI/MatrixWorkspace.h"
+#include "MantidDataHandling/LoadILLIndirect2.h"
+
+using namespace Mantid::API;
+using Mantid::DataHandling::LoadILLIndirect2;
+
+class LoadILLIndirect2Test : public CxxTest::TestSuite {
+public:
+  // This pair of boilerplate methods prevent the suite being created statically
+  // This means the constructor isn't called when running other tests
+  static LoadILLIndirect2Test *createSuite() {
+    return new LoadILLIndirect2Test();
+  }
+  static void destroySuite(LoadILLIndirect2Test *suite) { delete suite; }
+
+  LoadILLIndirect2Test()
+      : m_dataFile2013("ILLIN16B_034745.nxs"),
+        m_dataFile2015("ILLIN16B_127500.nxs") {}
+
+  void test_Init() {
+    LoadILLIndirect2 loader;
+    TS_ASSERT_THROWS_NOTHING(loader.initialize())
+    TS_ASSERT(loader.isInitialized())
+  }
+
+  void test_Name() {
+    LoadILLIndirect2 loader;
+    TS_ASSERT_EQUALS(loader.name(), "LoadILLIndirect");
+  }
+
+  void test_Version() {
+    LoadILLIndirect2 loader;
+    TS_ASSERT_EQUALS(loader.version(), 2);
+  }
+
+  void test_Load_2013_Format() {
+    doExecTest(m_dataFile2013, 2057); // all single detectors
+  }
+
+  void test_Load_2015_Format() {
+    doExecTest(m_dataFile2015, 2051); // only 2 out of 8 single detectors
+  }
+
+  void test_Confidence_2013_Format() { doConfidenceTest(m_dataFile2013); }
+
+  void test_Confidence_2015_Format() { doConfidenceTest(m_dataFile2015); }
+
+  void doConfidenceTest(const std::string &file) {
+    LoadILLIndirect2 alg;
+    TS_ASSERT_THROWS_NOTHING(alg.initialize());
+
+    alg.setPropertyValue("Filename", file);
+    Mantid::Kernel::NexusDescriptor descr(alg.getPropertyValue("Filename"));
+    TS_ASSERT_EQUALS(alg.confidence(descr), 80);
+  }
+
+  void doExecTest(const std::string &file, int numHist) {
+    // Name of the output workspace.
+    std::string outWSName("LoadILLIndirectTest_OutputWS");
+
+    LoadILLIndirect2 loader;
+    TS_ASSERT_THROWS_NOTHING(loader.initialize())
+    TS_ASSERT(loader.isInitialized())
+    TS_ASSERT_THROWS_NOTHING(loader.setPropertyValue("Filename", file));
+    TS_ASSERT_THROWS_NOTHING(
+        loader.setPropertyValue("OutputWorkspace", outWSName));
+    TS_ASSERT_THROWS_NOTHING(loader.execute(););
+    TS_ASSERT(loader.isExecuted());
+
+    MatrixWorkspace_sptr output =
+        AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(outWSName);
+    TS_ASSERT(output);
+
+    if (!output)
+      return;
+
+    MatrixWorkspace_sptr output2D =
+        boost::dynamic_pointer_cast<MatrixWorkspace>(output);
+    TS_ASSERT_EQUALS(output2D->getNumberHistograms(), numHist);
+
+    const Mantid::API::Run &runlogs = output->run();
+    TS_ASSERT(runlogs.hasProperty("Facility"));
+    TS_ASSERT_EQUALS(runlogs.getProperty("Facility")->value(), "ILL");
+
+    // Remove workspace from the data service.
+    AnalysisDataService::Instance().clear();
+  }
+
+private:
+  std::string m_dataFile2013;
+  std::string m_dataFile2015;
+};
+
+#endif /* MANTID_DATAHANDLING_LOADILLINDIRECT2TEST_H_ */
diff --git a/Framework/DataHandling/test/LoadILLIndirectTest.h b/Framework/DataHandling/test/LoadILLIndirectTest.h
index 4c7af1051fa4c891e7a3e65e9ce92b4ab7c7bb92..85fc6cf9a30c5d6fc1fb3a68a9565bdc9efabb95 100644
--- a/Framework/DataHandling/test/LoadILLIndirectTest.h
+++ b/Framework/DataHandling/test/LoadILLIndirectTest.h
@@ -53,7 +53,7 @@ public:
 
     alg.setPropertyValue("Filename", file);
     Mantid::Kernel::NexusDescriptor descr(alg.getPropertyValue("Filename"));
-    TS_ASSERT_EQUALS(alg.confidence(descr), 80);
+    TS_ASSERT_EQUALS(alg.confidence(descr), 70);
   }
 
   void doExecTest(const std::string &file) {
@@ -89,8 +89,49 @@ public:
   }
 
 private:
-  std::string m_dataFile2013;
-  std::string m_dataFile2015;
+  const std::string m_dataFile2013;
+  const std::string m_dataFile2015;
 };
 
+class LoadILLIndirectTestPerformance : public CxxTest::TestSuite {
+public:
+  void setUp() override {
+    for (int i = 0; i < numberOfIterations; ++i) {
+      loadAlgPtrs.emplace_back(setupAlg());
+    }
+  }
+
+  void testLoadILLIndirectPerformance() {
+    for (auto alg : loadAlgPtrs) {
+      TS_ASSERT_THROWS_NOTHING(alg->execute());
+    }
+  }
+
+  void tearDown() override {
+    for (int i = 0; i < numberOfIterations; i++) {
+      delete loadAlgPtrs[i];
+      loadAlgPtrs[i] = nullptr;
+    }
+    Mantid::API::AnalysisDataService::Instance().remove(outWSName);
+  }
+
+private:
+  std::vector<LoadILLIndirect *> loadAlgPtrs;
+
+  const int numberOfIterations = 5;
+
+  const std::string inFileName = "ILLIN16B_127500.nxs";
+  const std::string outWSName = "LoadILLWsOut";
+
+  LoadILLIndirect *setupAlg() {
+    LoadILLIndirect *loader = new LoadILLIndirect;
+    loader->initialize();
+    loader->isInitialized();
+    loader->setPropertyValue("Filename", inFileName);
+    loader->setPropertyValue("OutputWorkspace", outWSName);
+
+    loader->setRethrows(true);
+    return loader;
+  }
+};
 #endif /* MANTID_DATAHANDLING_LOADILLINDIRECTTEST_H_ */
diff --git a/Framework/DataHandling/test/LoadILLSANSTest.h b/Framework/DataHandling/test/LoadILLSANSTest.h
index 1e1328d6cc4e4990d450c116d84508a407e691c9..1182d8675e2a96d40313539e7b7db13eb8b83931 100644
--- a/Framework/DataHandling/test/LoadILLSANSTest.h
+++ b/Framework/DataHandling/test/LoadILLSANSTest.h
@@ -4,6 +4,7 @@
 #include <cxxtest/TestSuite.h>
 
 #include "MantidDataHandling/LoadILLSANS.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/MatrixWorkspace.h"
 
 using Mantid::DataHandling::LoadILLSANS;
diff --git a/Framework/DataHandling/test/LoadILLTOF2Test.h b/Framework/DataHandling/test/LoadILLTOF2Test.h
new file mode 100644
index 0000000000000000000000000000000000000000..1cc81243de7d42ae22f175c4f2bdfc1ada8ac430
--- /dev/null
+++ b/Framework/DataHandling/test/LoadILLTOF2Test.h
@@ -0,0 +1,162 @@
+#ifndef LOADILLTOF2TEST_H_
+#define LOADILLTOF2TEST_H_
+
+#include <cxxtest/TestSuite.h>
+#include "MantidAPI/AnalysisDataService.h"
+#include "MantidAPI/MatrixWorkspace.h"
+#include "MantidDataHandling/LoadILLTOF2.h"
+
+using namespace Mantid::API;
+using Mantid::DataHandling::LoadILLTOF2;
+
+class LoadILLTOF2Test : public CxxTest::TestSuite {
+public:
+  // This pair of boilerplate methods prevent the suite being created statically
+  // This means the constructor isn't called when running other tests
+  static LoadILLTOF2Test *createSuite() { return new LoadILLTOF2Test(); }
+  static void destroySuite(LoadILLTOF2Test *suite) { delete suite; }
+
+  void tearDown() override { AnalysisDataService::Instance().clear(); }
+
+  void testName() {
+    LoadILLTOF2 loader;
+    TS_ASSERT_EQUALS(loader.name(), "LoadILLTOF")
+  }
+
+  void testVersion() {
+    LoadILLTOF2 loader;
+    TS_ASSERT_EQUALS(loader.version(), 2)
+  }
+
+  void testInit() {
+    LoadILLTOF2 loader;
+    loader.setRethrows(true);
+    TS_ASSERT_THROWS_NOTHING(loader.initialize())
+    TS_ASSERT(loader.isInitialized())
+  }
+
+  /*
+   * This test only loads the Sample Data
+   * The elastic peak is obtained on the fly from the sample data.
+   */
+  MatrixWorkspace_sptr loadDataFile(const std::string dataFile,
+                                    const size_t numberOfHistograms,
+                                    const size_t numberOfChannels,
+                                    const double tofDelay,
+                                    const double tofChannelWidth) {
+    LoadILLTOF2 loader;
+    loader.setRethrows(true);
+    TS_ASSERT_THROWS_NOTHING(loader.initialize())
+    TS_ASSERT_THROWS_NOTHING(loader.setPropertyValue("Filename", dataFile))
+
+    std::string outputSpace = "LoadILLTOFTest_out";
+    TS_ASSERT_THROWS_NOTHING(
+        loader.setPropertyValue("OutputWorkspace", outputSpace))
+    TS_ASSERT_THROWS_NOTHING(loader.execute())
+
+    MatrixWorkspace_sptr output =
+        AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(
+            outputSpace);
+
+    TS_ASSERT_EQUALS(output->getNumberHistograms(), numberOfHistograms)
+    for (size_t wsIndex = 0; wsIndex != output->getNumberHistograms();
+         ++wsIndex) {
+      const auto histogram = output->histogram(wsIndex);
+      TS_ASSERT_EQUALS(histogram.xMode(),
+                       Mantid::HistogramData::Histogram::XMode::BinEdges)
+      TS_ASSERT_EQUALS(histogram.yMode(),
+                       Mantid::HistogramData::Histogram::YMode::Counts)
+      TS_ASSERT_EQUALS(histogram.size(), numberOfChannels)
+      const auto &xs = histogram.x();
+      for (size_t channelIndex = 0; channelIndex != xs.size(); ++channelIndex) {
+        const double binEdge =
+            tofDelay + static_cast<double>(channelIndex) * tofChannelWidth -
+            tofChannelWidth / 2;
+        TS_ASSERT_DELTA(xs[channelIndex], binEdge, 1e-3)
+      }
+      const auto &ys = histogram.y();
+      const auto &es = histogram.e();
+      for (size_t channelIndex = 0; channelIndex != es.size(); ++channelIndex) {
+        TS_ASSERT_EQUALS(es[channelIndex], std::sqrt(ys[channelIndex]))
+      }
+    }
+
+    // Check all detectors have a defined detector ID >= 0
+    Mantid::detid2index_map detectorMap;
+    TS_ASSERT_THROWS_NOTHING(detectorMap =
+                                 output->getDetectorIDToWorkspaceIndexMap(true))
+
+    // Check all detectors have a unique detector ID
+    TS_ASSERT_EQUALS(detectorMap.size(), output->getNumberHistograms())
+
+    for (const auto value : detectorMap) {
+      TS_ASSERT(value.first >= 0)
+    }
+
+    return output;
+  }
+
+  void test_IN4_load() {
+    // From the input test file.
+    const double tofDelay = 238.34;
+    const double tofChannelWidth = 5.85;
+    const size_t channelCount = 512;
+    const size_t histogramCount = 397;
+    MatrixWorkspace_sptr ws =
+        loadDataFile("ILL/IN4/084446.nxs", histogramCount, channelCount,
+                     tofDelay, tofChannelWidth);
+
+    const double pulseInterval =
+        ws->run().getLogAsSingleValue("pulse_interval");
+    TS_ASSERT_DELTA(0.003, pulseInterval, 1e-10)
+  }
+
+  void test_IN5_load() {
+    // From the input test file.
+    const double tofDelay = 5982.856;
+    const double tofChannelWidth = 14.6349;
+    const size_t channelCount = 512;
+    const size_t histogramCount = 98305;
+    loadDataFile("ILL/IN5/104007.nxs", histogramCount, channelCount, tofDelay,
+                 tofChannelWidth);
+  }
+
+  void test_IN6_load() {
+    // From the input test file.
+    const double tofDelay = 430;
+    const double tofChannelWidth = 5.8;
+    const size_t channelCount = 1024;
+    const size_t histogramCount = 340;
+    MatrixWorkspace_sptr ws =
+        loadDataFile("ILL/IN6/164192.nxs", histogramCount, channelCount,
+                     tofDelay, tofChannelWidth);
+
+    const double pulseInterval =
+        ws->run().getLogAsSingleValue("pulse_interval");
+    TS_ASSERT_DELTA(0.0060337892, pulseInterval, 1e-10)
+  }
+};
+
+//------------------------------------------------------------------------------
+// Performance test
+//------------------------------------------------------------------------------
+
+class LoadILLTOF2TestPerformance : public CxxTest::TestSuite {
+public:
+  LoadILLTOF2TestPerformance() : m_dataFile("ILL/IN5/104007.nxs") {}
+
+  void testDefaultLoad() {
+    Mantid::DataHandling::LoadILLTOF2 loader;
+    loader.setRethrows(true);
+    TS_ASSERT_THROWS_NOTHING(loader.initialize())
+    TS_ASSERT_THROWS_NOTHING(loader.setPropertyValue("Filename", m_dataFile))
+    TS_ASSERT_THROWS_NOTHING(loader.setPropertyValue("OutputWorkspace", "ws"))
+    TS_ASSERT_THROWS_NOTHING(loader.execute())
+    TS_ASSERT(loader.isExecuted())
+  }
+
+private:
+  std::string m_dataFile;
+};
+
+#endif /*LOADILLTOF2TEST_H_*/
diff --git a/Framework/DataHandling/test/LoadInstrumentFromNexusTest.h b/Framework/DataHandling/test/LoadInstrumentFromNexusTest.h
new file mode 100644
index 0000000000000000000000000000000000000000..a4ef87012697b3b6412af46c9d6d120bbaae8649
--- /dev/null
+++ b/Framework/DataHandling/test/LoadInstrumentFromNexusTest.h
@@ -0,0 +1,82 @@
+#ifndef LOADINSTRUMENTFROMNEXUS_H_
+#define LOADINSTRUMENTFROMNEXUS_H_
+
+#include <cxxtest/TestSuite.h>
+
+#include "MantidDataHandling/LoadInstrumentFromNexus.h"
+#include "MantidGeometry/Instrument.h"
+#include "MantidTestHelpers/WorkspaceCreationHelper.h"
+
+using namespace Mantid;
+using namespace Mantid::DataHandling;
+using namespace Mantid::API;
+using namespace Mantid::Geometry;
+using Mantid::Kernel::V3D;
+
+class LoadInstrumentFromNexusTest : public CxxTest::TestSuite {
+public:
+  // This pair of boilerplate methods prevent the suite being created statically
+  // This means the constructor isn't called when running other tests
+  static LoadInstrumentFromNexusTest *createSuite() {
+    return new LoadInstrumentFromNexusTest();
+  }
+  static void destroySuite(LoadInstrumentFromNexusTest *suite) { delete suite; }
+
+  void testLoadInstrumentFromNexus() {
+    // setup and run the algorithm (includes basic checks)
+    LoadInstrumentFromNexus alg;
+    const MatrixWorkspace_sptr ws = setupAlgorithm(alg, "MUSR00015189.nxs");
+    runAlgorithm(alg);
+
+    // specific checks
+    const Instrument_const_sptr inst = ws->getInstrument();
+    TS_ASSERT(inst);
+    TS_ASSERT_EQUALS(inst->getName(), "MUSR");
+
+    const IComponent_const_sptr sample = inst->getSample();
+    const V3D samplepos = sample->getPos();
+    TS_ASSERT_EQUALS(sample->getName(), "Unknown");
+    TS_ASSERT_DELTA(samplepos.X(), 0.0, 1e-6);
+    TS_ASSERT_DELTA(samplepos.Y(), 0.0, 1e-6);
+    TS_ASSERT_DELTA(samplepos.Z(), 0.0, 1e-6);
+
+    const IComponent_const_sptr source = inst->getSource();
+    const V3D sourcepos = source->getPos();
+    TS_ASSERT_EQUALS(source->getName(), "Unknown");
+    TS_ASSERT_DELTA(sourcepos.X(), 0.0, 1e-6);
+    TS_ASSERT_DELTA(sourcepos.Y(), -10.0, 1e-6);
+    TS_ASSERT_DELTA(sourcepos.Z(), 0.0, 1e-6);
+  }
+
+private:
+  const MatrixWorkspace_sptr makeFakeWorkspace() {
+    // create the workspace
+    MatrixWorkspace_sptr ws = WorkspaceCreationHelper::create2DWorkspace(2, 10);
+    return ws;
+  }
+
+  // Initialise the algorithm and set the properties. Creates a fake
+  // workspace for the input.
+  const MatrixWorkspace_sptr setupAlgorithm(LoadInstrumentFromNexus &alg,
+                                            const std::string &filename) {
+    // create the workspace
+    const MatrixWorkspace_sptr inWS = makeFakeWorkspace();
+
+    // set up the algorithm
+    if (!alg.isInitialized())
+      alg.initialize();
+    alg.setProperty("Workspace", inWS);
+    alg.setProperty("Filename", filename);
+
+    return inWS;
+  }
+
+  // Run the algorithm and do some basic checks
+  void runAlgorithm(LoadInstrumentFromNexus &alg) {
+    // run the algorithm
+    TS_ASSERT_THROWS_NOTHING(alg.execute());
+    TS_ASSERT(alg.isExecuted());
+  }
+};
+
+#endif /*LOADINSTRUMENTFROMNEXUS_H_*/
diff --git a/Framework/DataHandling/test/LoadInstrumentFromRawTest.h b/Framework/DataHandling/test/LoadInstrumentFromRawTest.h
index c97849c6b01244b92ae2cbefb10dc2eb60991071..790592dc73693a0388354d87fcbf83718d152bf0 100644
--- a/Framework/DataHandling/test/LoadInstrumentFromRawTest.h
+++ b/Framework/DataHandling/test/LoadInstrumentFromRawTest.h
@@ -9,6 +9,7 @@
 #include "MantidDataObjects/Workspace2D.h"
 #include "MantidAPI/AnalysisDataService.h"
 #include "MantidKernel/Exception.h"
+#include "MantidAPI/DetectorInfo.h"
 #include "MantidAPI/FrameworkManager.h"
 #include "MantidAPI/Workspace.h"
 #include "MantidAPI/Algorithm.h"
@@ -106,12 +107,13 @@ public:
     TS_ASSERT_THROWS(i->getDetector(9), Exception::NotFoundError);
 
     // Check the monitors are correctly marked
-    TS_ASSERT(i->getDetector(1)->isMonitor())
-    TS_ASSERT(i->getDetector(2)->isMonitor())
+    const auto &detInfo = output->detectorInfo();
+    TS_ASSERT(detInfo.isMonitor(0))
+    TS_ASSERT(detInfo.isMonitor(1))
     // ...and that a normal detector isn't
-    TS_ASSERT(!i->getDetector(3)->isMonitor())
-    TS_ASSERT(!i->getDetector(4)->isMonitor())
-    TS_ASSERT(!i->getDetector(8)->isMonitor())
+    TS_ASSERT(!detInfo.isMonitor(2))
+    TS_ASSERT(!detInfo.isMonitor(3))
+    TS_ASSERT(!detInfo.isMonitor(7))
 
     AnalysisDataService::Instance().remove(wsName);
   }
diff --git a/Framework/DataHandling/test/LoadInstrumentTest.h b/Framework/DataHandling/test/LoadInstrumentTest.h
index 61d85995c6820d712eff1108f928d7f86caa4fe6..b5e66c754255fa84c28a75d0f9dbf9510f20d404 100644
--- a/Framework/DataHandling/test/LoadInstrumentTest.h
+++ b/Framework/DataHandling/test/LoadInstrumentTest.h
@@ -5,6 +5,7 @@
 #include "MantidAPI/Algorithm.h"
 #include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Axis.h"
+#include "MantidAPI/DetectorInfo.h"
 #include "MantidAPI/ExperimentInfo.h"
 #include "MantidAPI/FrameworkManager.h"
 #include "MantidAPI/InstrumentDataService.h"
@@ -129,8 +130,8 @@ public:
     TS_ASSERT_DELTA(cmpDistance, 2.512, 0.0001);
 
     // test if detector with det_id=603 has been marked as a monitor
-    boost::shared_ptr<const IDetector> ptrMonitor = i->getDetector(601);
-    TS_ASSERT(ptrMonitor->isMonitor());
+    TS_ASSERT(
+        output->detectorInfo().isMonitor(output->detectorInfo().indexOf(601)));
 
     // Spectra mapping has been updated
     TS_ASSERT_EQUALS(output->getAxis(1)->spectraNo(0), 1);
@@ -228,8 +229,7 @@ public:
     boost::shared_ptr<const IDetector> ptrDet = i->getDetector(101);
     TS_ASSERT_EQUALS(ptrDet->getID(), 101);
 
-    boost::shared_ptr<const IDetector> ptrMonitor = i->getDetector(1);
-    TS_ASSERT(ptrMonitor->isMonitor());
+    TS_ASSERT(output->detectorInfo().isMonitor(0));
 
     boost::shared_ptr<const IDetector> ptrDetShape = i->getDetector(102);
     TS_ASSERT(ptrDetShape->isValid(V3D(0.0, 0.0, 0.0) + ptrDetShape->getPos()));
@@ -646,7 +646,7 @@ public:
   MatrixWorkspace_sptr ws;
 
   void setUp() override {
-    ws = WorkspaceCreationHelper::Create2DWorkspace(1, 2);
+    ws = WorkspaceCreationHelper::create2DWorkspace(1, 2);
   }
 
   void doTest(std::string filename, size_t numTimes = 1) {
diff --git a/Framework/DataHandling/test/LoadLLBTest.h b/Framework/DataHandling/test/LoadLLBTest.h
index 788811a1ffec8a8d101e46a4974cd6223c77bb15..3f638dcf051512f951258c7a8e9d4ade1637e227 100644
--- a/Framework/DataHandling/test/LoadLLBTest.h
+++ b/Framework/DataHandling/test/LoadLLBTest.h
@@ -4,6 +4,7 @@
 #include <cxxtest/TestSuite.h>
 
 #include "MantidDataHandling/LoadLLB.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/MatrixWorkspace.h"
 
 using namespace Mantid::API;
diff --git a/Framework/DataHandling/test/LoadMaskTest.h b/Framework/DataHandling/test/LoadMaskTest.h
index af0b7551195de92e6f6aaaf039a9970fbee2e2b5..03405c6dbcaaf8242ccaf1ffb5cdc9adf8b5ae32 100644
--- a/Framework/DataHandling/test/LoadMaskTest.h
+++ b/Framework/DataHandling/test/LoadMaskTest.h
@@ -10,6 +10,8 @@
 #include "MantidDataObjects/MaskWorkspace.h"
 #include "MantidTestHelpers/ScopedFileHelper.h"
 #include "MantidAPI/AlgorithmManager.h"
+#include "MantidAPI/AnalysisDataService.h"
+#include "MantidAPI/SpectrumInfo.h"
 
 using namespace Mantid;
 using namespace Mantid::DataHandling;
@@ -259,9 +261,10 @@ public:
     // masked
     std::vector<detid_t> maskSourceDet, maskTargDet;
 
+    const auto &spectrumInfo = source->spectrumInfo();
     size_t n_steps = source->getNumberHistograms();
     for (size_t i = 0; i < n_steps; ++i) {
-      bool source_masked = source->getDetector(i)->isMasked();
+      bool source_masked = spectrumInfo.isMasked(i);
       if (source_masked) {
         maskSourceDet.push_back(source->getDetector(i)->getID());
       }
diff --git a/Framework/DataHandling/test/LoadMcStasNexusTest.h b/Framework/DataHandling/test/LoadMcStasNexusTest.h
index 27902f836b5a0edd69e3c372128e6d2a6e418582..36a36c38722887a2749355508b72829184dc8107 100644
--- a/Framework/DataHandling/test/LoadMcStasNexusTest.h
+++ b/Framework/DataHandling/test/LoadMcStasNexusTest.h
@@ -7,6 +7,7 @@
 #include "MantidAPI/FrameworkManager.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidAPI/AnalysisDataService.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidDataHandling/LoadMcStasNexus.h"
 // These includes seem to make the difference between initialization of the
 // workspace names (workspace2D/1D etc), instrument classes and not for this
diff --git a/Framework/DataHandling/test/LoadMcStasTest.h b/Framework/DataHandling/test/LoadMcStasTest.h
index e9ebc98da5d18a6c32ab5dd0c2035e5e3345e319..6d178168e198220bcc11faba60c5127097843f90 100644
--- a/Framework/DataHandling/test/LoadMcStasTest.h
+++ b/Framework/DataHandling/test/LoadMcStasTest.h
@@ -8,6 +8,7 @@
 #include "MantidAPI/FrameworkManager.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidAPI/AnalysisDataService.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidDataHandling/LoadMcStas.h"
 // These includes seem to make the difference between initialization of the
 // workspace names (workspace2D/1D etc), instrument classes and not for this
diff --git a/Framework/DataHandling/test/LoadMuonNexus1Test.h b/Framework/DataHandling/test/LoadMuonNexus1Test.h
index 4d936fb662567c06100d88efed3378dc5e7fc5b4..9428b1ec308fc6af0fe3e6c20b93c9c869537a87 100644
--- a/Framework/DataHandling/test/LoadMuonNexus1Test.h
+++ b/Framework/DataHandling/test/LoadMuonNexus1Test.h
@@ -20,6 +20,7 @@
 #include "MantidAPI/Sample.h"
 #include "MantidAPI/ScopedWorkspace.h"
 #include "MantidAPI/WorkspaceFactory.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidKernel/ConfigService.h"
 #include "MantidKernel/TimeSeriesProperty.h"
 #include "MantidKernel/Unit.h"
diff --git a/Framework/DataHandling/test/LoadNXSPETest.h b/Framework/DataHandling/test/LoadNXSPETest.h
index 878755526a32996dc852ff394ab75f252862a440..6557806cd91ce21e6aa6d412e119c31e7cb0046f 100644
--- a/Framework/DataHandling/test/LoadNXSPETest.h
+++ b/Framework/DataHandling/test/LoadNXSPETest.h
@@ -2,6 +2,7 @@
 #define MANTID_DATAHANDLING_LOADNXSPETEST_H_
 
 #include <cxxtest/TestSuite.h>
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidGeometry/Instrument.h"
 #include "MantidKernel/DeltaEMode.h"
diff --git a/Framework/DataHandling/test/LoadNXcanSASTest.h b/Framework/DataHandling/test/LoadNXcanSASTest.h
index a322f61cb8e7825fb448f16fa2f59418b1f8c1f3..7ff7c3ca011db961dc9877a6dbe1e4c132133fe2 100644
--- a/Framework/DataHandling/test/LoadNXcanSASTest.h
+++ b/Framework/DataHandling/test/LoadNXcanSASTest.h
@@ -4,6 +4,7 @@
 #include <cxxtest/TestSuite.h>
 
 #include "MantidAPI/AlgorithmManager.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Axis.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/Run.h"
diff --git a/Framework/DataHandling/test/LoadNexusLogsTest.h b/Framework/DataHandling/test/LoadNexusLogsTest.h
index 38b10895647caffca67aae37b40fb0a19a5ef0ed..d530d8e5641b8fb849eca30ab54267d71eaa8e2a 100644
--- a/Framework/DataHandling/test/LoadNexusLogsTest.h
+++ b/Framework/DataHandling/test/LoadNexusLogsTest.h
@@ -39,7 +39,7 @@ public:
     Run &run = ws->mutableRun();
     // Do we have all we expect
     const std::vector<Property *> &logs = run.getLogData();
-    TS_ASSERT_EQUALS(logs.size(), 74);
+    TS_ASSERT_EQUALS(logs.size(), 75);
     Property *prop;
     TimeSeriesProperty<double> *dProp;
 
@@ -84,7 +84,7 @@ public:
     const API::Run &run = testWS->run();
     const std::vector<Property *> &logs = run.getLogData();
     TS_ASSERT_EQUALS(logs.size(),
-                     34); // 33 logs in file + 1 synthetic nperiods log
+                     35); // 34 logs in file + 1 synthetic nperiods log
 
     TimeSeriesProperty<std::string> *slog =
         dynamic_cast<TimeSeriesProperty<std::string> *>(
@@ -170,6 +170,27 @@ public:
                       uniquePeriods.size());
   }
 
+  void test_extract_run_title_from_event_nexus() {
+
+    auto testWS = createTestWorkspace();
+    auto run = testWS->run();
+
+    LoadNexusLogs loader;
+    loader.setChild(true);
+    loader.initialize();
+    loader.setProperty("Workspace", testWS);
+    loader.setPropertyValue("Filename", "LARMOR00003368.nxs");
+    loader.execute();
+    run = testWS->run();
+
+    const bool hasTitle = run.hasProperty("run_title");
+    TSM_ASSERT("Should have run_title now we have run LoadNexusLogs", hasTitle);
+
+    std::string title = run.getPropertyValueAsType<std::string>("run_title");
+    TSM_ASSERT_EQUALS("Run title is not correct",
+                      "3He polariser test 0.9bar Long Polariser 0.75A", title);
+  }
+
   void test_log_non_default_entry() {
     auto testWS = createTestWorkspace();
     LoadNexusLogs loader;
diff --git a/Framework/DataHandling/test/LoadNexusMonitorsTest.h b/Framework/DataHandling/test/LoadNexusMonitorsTest.h
index 80e14001c17c9cc993593bd741258641a905c1a1..00a8312c7f3729cd7e0d308cbc2f84e664e92f5e 100644
--- a/Framework/DataHandling/test/LoadNexusMonitorsTest.h
+++ b/Framework/DataHandling/test/LoadNexusMonitorsTest.h
@@ -7,6 +7,8 @@
 #include "MantidAPI/FrameworkManager.h"
 #include "MantidAPI/Run.h"
 #include "MantidAPI/Sample.h"
+#include "MantidAPI/SpectrumInfo.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidGeometry/Instrument.h"
 #include "MantidGeometry/Instrument/Detector.h"
 #include "MantidDataObjects/EventWorkspace.h"
@@ -53,12 +55,11 @@ public:
     TS_ASSERT_EQUALS(WS->dataE(1).size(), 200001);
     TS_ASSERT_DELTA(WS->dataE(1)[3412], 14.03567, 1e-4);
     // Check geometry for a monitor
-    IDetector_const_sptr mon = WS->getDetector(2);
-    TS_ASSERT(mon->isMonitor());
-    TS_ASSERT_EQUALS(mon->getID(), -3);
-    boost::shared_ptr<const IComponent> sample =
-        WS->getInstrument()->getSample();
-    TS_ASSERT_DELTA(mon->getDistance(*sample), 1.426, 1e-6);
+    const auto &specInfo = WS->spectrumInfo();
+    TS_ASSERT(specInfo.isMonitor(2));
+    TS_ASSERT_EQUALS(specInfo.detector(2).getID(), -3);
+    TS_ASSERT_DELTA(specInfo.samplePosition().distance(specInfo.position(2)),
+                    1.426, 1e-6);
     // Check if filename is saved
     TS_ASSERT_EQUALS(ld.getPropertyValue("Filename"),
                      WS->run().getProperty("Filename")->value());
diff --git a/Framework/DataHandling/test/LoadNexusProcessedTest.h b/Framework/DataHandling/test/LoadNexusProcessedTest.h
index 02ce669e70ef7a5ee38db81b465a87f65fd03f64..e5dfe7fda6acd34c98d588c03e2516dc3a0e0529 100644
--- a/Framework/DataHandling/test/LoadNexusProcessedTest.h
+++ b/Framework/DataHandling/test/LoadNexusProcessedTest.h
@@ -7,6 +7,7 @@
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/NumericAxis.h"
 #include "MantidAPI/WorkspaceGroup.h"
+#include "MantidAPI/WorkspaceHistory.h"
 #include "MantidDataObjects/EventWorkspace.h"
 #include "MantidDataObjects/PeakShapeSpherical.h"
 #include "MantidDataObjects/Peak.h"
@@ -465,7 +466,7 @@ public:
       TS_ASSERT(ws);
       TS_ASSERT_EQUALS(ws->getNumberHistograms(), 1);
       TS_ASSERT_EQUALS(ws->blocksize(), 10);
-      TS_ASSERT_EQUALS(ws->name(), "group_" + std::to_string(i + 1));
+      TS_ASSERT_EQUALS(ws->getName(), "group_" + std::to_string(i + 1));
     }
   }
 
@@ -495,8 +496,8 @@ public:
       TS_ASSERT(ws);
       TS_ASSERT_EQUALS(ws->getNumberHistograms(), 1);
       TS_ASSERT_EQUALS(ws->blocksize(), 2);
-      TS_ASSERT_EQUALS(ws->name(), "irs55125_graphite002_to_55131_" +
-                                       std::string(suffix[i]));
+      TS_ASSERT_EQUALS(ws->getName(), "irs55125_graphite002_to_55131_" +
+                                          std::string(suffix[i]));
     }
   }
 
@@ -526,8 +527,8 @@ public:
       TS_ASSERT(ws);
       TS_ASSERT_EQUALS(ws->getNumberHistograms(), 1);
       TS_ASSERT_EQUALS(ws->blocksize(), 2);
-      TS_ASSERT_EQUALS(ws->name(), "irs55125_graphite002_to_55131_" +
-                                       std::string(suffix[i]));
+      TS_ASSERT_EQUALS(ws->getName(), "irs55125_graphite002_to_55131_" +
+                                          std::string(suffix[i]));
     }
 
     // load same file again, but to a different group
@@ -555,8 +556,8 @@ public:
       TS_ASSERT(ws);
       TS_ASSERT_EQUALS(ws->getNumberHistograms(), 1);
       TS_ASSERT_EQUALS(ws->blocksize(), 2);
-      TS_ASSERT_EQUALS(ws->name(), "irs55125_graphite002_to_55131_" +
-                                       std::string(suffix[i]) + "_1");
+      TS_ASSERT_EQUALS(ws->getName(), "irs55125_graphite002_to_55131_" +
+                                          std::string(suffix[i]) + "_1");
     }
   }
 
@@ -962,7 +963,7 @@ public:
     std::string workspaceName = "test_workspace_name";
     for (size_t index = 0; index < 2; ++index) {
       // Create a sample workspace and add it to the ADS, so it gets a name.
-      auto ws = WorkspaceCreationHelper::Create1DWorkspaceConstant(
+      auto ws = WorkspaceCreationHelper::create1DWorkspaceConstant(
           3, static_cast<double>(index), static_cast<double>(index));
       AnalysisDataService::Instance().addOrReplace(workspaceName, ws);
       alg.setProperty("InputWorkspace",
@@ -1245,7 +1246,7 @@ private:
     groups[5].push_back(20);
 
     EventWorkspace_sptr ws =
-        WorkspaceCreationHelper::CreateGroupedEventWorkspace(groups, 30, 1.0);
+        WorkspaceCreationHelper::createGroupedEventWorkspace(groups, 30, 1.0);
     ws->getSpectrum(4).clear();
 
     TS_ASSERT_EQUALS(ws->getNumberHistograms(), groups.size());
diff --git a/Framework/DataHandling/test/LoadNexusTest.h b/Framework/DataHandling/test/LoadNexusTest.h
index 8ca3c98b46f1bc9878e644b2b0a4fdc63af2843b..ef781f83fb4a483a09b21a6df8e2cefbebd71403 100644
--- a/Framework/DataHandling/test/LoadNexusTest.h
+++ b/Framework/DataHandling/test/LoadNexusTest.h
@@ -8,6 +8,7 @@
 #include "MantidAPI/FrameworkManager.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidAPI/AnalysisDataService.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidKernel/Unit.h"
 #include "MantidDataHandling/LoadNexus.h"
 // These includes seem to make the difference between initialization of the
diff --git a/Framework/DataHandling/test/LoadPDFgetNFileTest.h b/Framework/DataHandling/test/LoadPDFgetNFileTest.h
index e77c0db0cfed94c97ae35c604a0c60495bcf5fb2..d5bd74bbf2ca4e22916cf85c6a9f7e9271a6150e 100644
--- a/Framework/DataHandling/test/LoadPDFgetNFileTest.h
+++ b/Framework/DataHandling/test/LoadPDFgetNFileTest.h
@@ -5,6 +5,7 @@
 
 #include "MantidDataHandling/LoadPDFgetNFile.h"
 #include "MantidDataObjects/Workspace2D.h"
+#include "MantidAPI/AnalysisDataService.h"
 
 using Mantid::DataHandling::LoadPDFgetNFile;
 using namespace Mantid;
diff --git a/Framework/DataHandling/test/LoadPreNexusTest.h b/Framework/DataHandling/test/LoadPreNexusTest.h
index e6cb64d3ac25f84204127d6a4c53db006d896880..8a63e21ea94d66576bb43df7c06c4e7ab10a7844 100644
--- a/Framework/DataHandling/test/LoadPreNexusTest.h
+++ b/Framework/DataHandling/test/LoadPreNexusTest.h
@@ -5,6 +5,7 @@
 
 #include "MantidDataHandling/LoadPreNexus.h"
 
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidKernel/Timer.h"
 #include "MantidKernel/System.h"
diff --git a/Framework/DataHandling/test/LoadQKKTest.h b/Framework/DataHandling/test/LoadQKKTest.h
index e41eb78c3f7bd069c5c84ab64c0f1ce59446da9f..d7e2f42d50c4c648b7a215f284ff5b99a5ece15e 100644
--- a/Framework/DataHandling/test/LoadQKKTest.h
+++ b/Framework/DataHandling/test/LoadQKKTest.h
@@ -1,11 +1,9 @@
 #ifndef LOADQKKTEST_H_
 #define LOADQKKTEST_H_
 
-//-----------------
-// Includes
-//-----------------
 #include "MantidDataHandling/LoadQKK.h"
 #include "MantidDataObjects/Workspace2D.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidKernel/ConfigService.h"
 #include <cxxtest/TestSuite.h>
 #include <Poco/Path.h>
diff --git a/Framework/DataHandling/test/LoadRKHTest.h b/Framework/DataHandling/test/LoadRKHTest.h
index eed7b29b0d96e0e7f6633b88d1bcf224e0ffaf9d..c1baec0c8c4854397e2eb076d35f78ebe0d18415 100644
--- a/Framework/DataHandling/test/LoadRKHTest.h
+++ b/Framework/DataHandling/test/LoadRKHTest.h
@@ -1,10 +1,8 @@
 #ifndef LOADRKHTEST_H_
 #define LOADRKHTEST_H_
 
-//-----------------
-// Includes
-//-----------------
 #include "MantidDataHandling/LoadRKH.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Axis.h"
 #include "MantidDataObjects/Workspace2D.h"
 #include "MantidKernel/ConfigService.h"
diff --git a/Framework/DataHandling/test/LoadRaw3Test.h b/Framework/DataHandling/test/LoadRaw3Test.h
index 32bbf029c0f236db6f5b396c442fb57e9f06a785..a1bf006f2e3ad4ee3689726e355ac7c28ac8bcc8 100644
--- a/Framework/DataHandling/test/LoadRaw3Test.h
+++ b/Framework/DataHandling/test/LoadRaw3Test.h
@@ -12,6 +12,7 @@
 #include "MantidKernel/ConfigService.h"
 #include "MantidKernel/TimeSeriesProperty.h"
 #include "MantidKernel/Unit.h"
+#include <boost/lexical_cast.hpp>
 #include <cxxtest/TestSuite.h>
 
 using namespace Mantid;
@@ -1154,8 +1155,8 @@ private:
     PropertyWithValue<int> *current_period_property =
         dynamic_cast<PropertyWithValue<int> *>(prop);
     TS_ASSERT(current_period_property != NULL);
-    int actual_period;
-    Kernel::toValue<int>(current_period_property->value(), actual_period);
+    int actual_period =
+        boost::lexical_cast<int>(current_period_property->value());
     TS_ASSERT_EQUALS(expected_period, actual_period);
     // Check the period n property.
     std::stringstream stream;
diff --git a/Framework/DataHandling/test/LoadRawBin0Test.h b/Framework/DataHandling/test/LoadRawBin0Test.h
index b22a7d886d0a3b60da977a7671a339ddd3dd1b51..189d36505cc31adefc5afd929e85cf057954df0b 100644
--- a/Framework/DataHandling/test/LoadRawBin0Test.h
+++ b/Framework/DataHandling/test/LoadRawBin0Test.h
@@ -13,6 +13,7 @@
 #include "MantidKernel/Unit.h"
 #include "MantidAPI/WorkspaceGroup.h"
 #include "MantidGeometry/Instrument.h"
+#include <boost/lexical_cast.hpp>
 #include <Poco/Path.h>
 
 using namespace Mantid::API;
@@ -156,8 +157,7 @@ private:
         dynamic_cast<PropertyWithValue<int> *>(prop);
     TS_ASSERT(current_period_property != NULL);
     int actual_period;
-    Mantid::Kernel::toValue<int>(current_period_property->value(),
-                                 actual_period);
+    actual_period = boost::lexical_cast<int>(current_period_property->value());
     TS_ASSERT_EQUALS(expected_period, actual_period);
     // Check the period n property.
     std::stringstream stream;
diff --git a/Framework/DataHandling/test/LoadRawSaveNxsLoadNxsTest.h b/Framework/DataHandling/test/LoadRawSaveNxsLoadNxsTest.h
index a0eb1bed4c0cf877f2a96389e50f5b33c456ebd6..f6cf518eefa5273c3d92d5a970f648e4abf17937 100644
--- a/Framework/DataHandling/test/LoadRawSaveNxsLoadNxsTest.h
+++ b/Framework/DataHandling/test/LoadRawSaveNxsLoadNxsTest.h
@@ -13,6 +13,7 @@
 #include "MantidGeometry/Instrument.h"
 #include "MantidGeometry/Instrument/Detector.h"
 #include "MantidKernel/TimeSeriesProperty.h"
+#include "MantidKernel/Unit.h"
 #include "MantidKernel/UnitFactory.h"
 #include "MantidDataHandling/LoadMuonNexus.h"
 #include "MantidDataHandling/LoadNexus.h"
diff --git a/Framework/DataHandling/test/LoadRawSpectrum0Test.h b/Framework/DataHandling/test/LoadRawSpectrum0Test.h
index a3f831dbe4bc3c68784fd387123fc461e0eec9fa..481139c8b82073aa90ffbae27597ecb28e92d976 100644
--- a/Framework/DataHandling/test/LoadRawSpectrum0Test.h
+++ b/Framework/DataHandling/test/LoadRawSpectrum0Test.h
@@ -14,6 +14,7 @@
 #include "MantidKernel/Unit.h"
 #include "MantidGeometry/Instrument.h"
 
+#include <boost/lexical_cast.hpp>
 #include <Poco/Path.h>
 
 using namespace Mantid::API;
@@ -150,8 +151,7 @@ private:
         dynamic_cast<PropertyWithValue<int> *>(prop);
     TS_ASSERT(current_period_property != NULL);
     int actual_period;
-    Mantid::Kernel::toValue<int>(current_period_property->value(),
-                                 actual_period);
+    actual_period = boost::lexical_cast<int>(current_period_property->value());
     TS_ASSERT_EQUALS(expected_period, actual_period);
     // Check the period n property.
     std::stringstream stream;
diff --git a/Framework/DataHandling/test/LoadSINQFocusTest.h b/Framework/DataHandling/test/LoadSINQFocusTest.h
index cb1410ef5a548c1879fe5fb627837c0bc9e99411..86013e43e899d4a1bfcaf60328e1c340cce4b712 100644
--- a/Framework/DataHandling/test/LoadSINQFocusTest.h
+++ b/Framework/DataHandling/test/LoadSINQFocusTest.h
@@ -4,6 +4,7 @@
 #include <cxxtest/TestSuite.h>
 
 #include "MantidDataHandling/LoadSINQFocus.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/MatrixWorkspace.h"
 
 using namespace Mantid::API;
diff --git a/Framework/DataHandling/test/LoadSNSspecTest.h b/Framework/DataHandling/test/LoadSNSspecTest.h
index 761eefc00a237164f1d08126102b274f46d8ce40..45e1c54cc773a1cd19e11aaba43ca012afb221df 100644
--- a/Framework/DataHandling/test/LoadSNSspecTest.h
+++ b/Framework/DataHandling/test/LoadSNSspecTest.h
@@ -3,6 +3,7 @@
 
 #include <cxxtest/TestSuite.h>
 #include "MantidDataHandling/LoadSNSspec.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/MatrixWorkspace.h"
 
 using namespace Mantid::API;
diff --git a/Framework/DataHandling/test/LoadSPETest.h b/Framework/DataHandling/test/LoadSPETest.h
index 0c86b26b16037d1119d44c5b6b6d25e85bda29ec..2143a174defa2ba605e5f562583834457486e662 100644
--- a/Framework/DataHandling/test/LoadSPETest.h
+++ b/Framework/DataHandling/test/LoadSPETest.h
@@ -3,6 +3,7 @@
 
 #include <cxxtest/TestSuite.h>
 #include "MantidDataHandling/LoadSPE.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Axis.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidKernel/Unit.h"
diff --git a/Framework/DataHandling/test/LoadSampleDetailsFromRawTest.h b/Framework/DataHandling/test/LoadSampleDetailsFromRawTest.h
new file mode 100644
index 0000000000000000000000000000000000000000..8d8706741fb90295c44332ef8dbe8ea630060f00
--- /dev/null
+++ b/Framework/DataHandling/test/LoadSampleDetailsFromRawTest.h
@@ -0,0 +1,69 @@
+#ifndef LOADSAMPLEDETAILSFROMRAWTEST_H_
+#define LOADSAMPLEDETAILSFROMRAWTEST_H_
+
+#include <cxxtest/TestSuite.h>
+
+#include "MantidDataHandling/LoadSampleDetailsFromRaw.h"
+#include "MantidAPI/Sample.h"
+#include "MantidTestHelpers/WorkspaceCreationHelper.h"
+
+using namespace Mantid;
+using namespace Mantid::DataHandling;
+using namespace Mantid::API;
+
+class LoadSampleDetailsFromRawTest : public CxxTest::TestSuite {
+public:
+  // This pair of boilerplate methods prevent the suite being created statically
+  // This means the constructor isn't called when running other tests
+  static LoadSampleDetailsFromRawTest *createSuite() {
+    return new LoadSampleDetailsFromRawTest();
+  }
+  static void destroySuite(LoadSampleDetailsFromRawTest *suite) {
+    delete suite;
+  }
+
+  void testExec() {
+    // setup and run the algorithm (includes basic checks)
+    LoadSampleDetailsFromRaw alg;
+    const MatrixWorkspace_const_sptr inWS = setupAlgorithm(alg, "HRP39180.RAW");
+    runAlgorithm(alg);
+
+    // specific checks
+    TS_ASSERT_EQUALS(inWS->sample().getGeometryFlag(), 2);
+    TS_ASSERT_DELTA(inWS->sample().getHeight(), 20.0, 1e-6);
+    TS_ASSERT_DELTA(inWS->sample().getWidth(), 15.0, 1e-6);
+    TS_ASSERT_DELTA(inWS->sample().getThickness(), 11.0, 1e-6);
+  }
+
+private:
+  const MatrixWorkspace_sptr makeFakeWorkspace() {
+    // create the workspace
+    MatrixWorkspace_sptr ws = WorkspaceCreationHelper::createEventWorkspace();
+    return ws;
+  }
+
+  // Initialise the algorithm and set the properties. Creates a fake
+  // workspace for the input and returns it.
+  const MatrixWorkspace_sptr setupAlgorithm(LoadSampleDetailsFromRaw &alg,
+                                            const std::string &filename) {
+    // create the workspace
+    const MatrixWorkspace_sptr inWS = makeFakeWorkspace();
+
+    // set up the algorithm
+    if (!alg.isInitialized())
+      alg.initialize();
+    alg.setProperty("InputWorkspace", inWS);
+    alg.setProperty("Filename", filename);
+
+    return inWS;
+  }
+
+  // Run the algorithm and do some basic checks
+  void runAlgorithm(LoadSampleDetailsFromRaw &alg) {
+    // run the algorithm
+    TS_ASSERT_THROWS_NOTHING(alg.execute());
+    TS_ASSERT(alg.isExecuted());
+  }
+};
+
+#endif /*LOADSAMPLEDETAILSFROMRAWTEST_H_*/
diff --git a/Framework/DataHandling/test/LoadSassenaTest.h b/Framework/DataHandling/test/LoadSassenaTest.h
index 5fcdbe5eb4cad18ba4234ed3532bb53b2b1a662e..235e583c912c2526263399850920027904d49dae 100644
--- a/Framework/DataHandling/test/LoadSassenaTest.h
+++ b/Framework/DataHandling/test/LoadSassenaTest.h
@@ -4,6 +4,7 @@
 #include <cxxtest/TestSuite.h>
 #include "MantidDataHandling/LoadSassena.h"
 #include "MantidAPI/AnalysisDataService.h"
+#include "MantidAPI/WorkspaceGroup.h"
 
 using namespace Mantid;
 
diff --git a/Framework/DataHandling/test/LoadSaveAsciiTest.h b/Framework/DataHandling/test/LoadSaveAsciiTest.h
index 50693391e6d1e99af3a267369ecdf68b5491b2d7..1571f24f690017dca9ff62127f2f91e0513bb54c 100644
--- a/Framework/DataHandling/test/LoadSaveAsciiTest.h
+++ b/Framework/DataHandling/test/LoadSaveAsciiTest.h
@@ -6,6 +6,7 @@
 #include "MantidDataHandling/LoadAscii.h"
 #include "MantidDataHandling/SaveAscii.h"
 
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Axis.h"
 #include "MantidAPI/FrameworkManager.h"
 #include "MantidAPI/WorkspaceFactory.h"
diff --git a/Framework/DataHandling/test/LoadSpice2dTest.h b/Framework/DataHandling/test/LoadSpice2dTest.h
index 498f3a7a8543dc01ef4a461ec13d3f6a304590a9..1ebec15ccb8588e71f2383673c8c31cd4e143948 100644
--- a/Framework/DataHandling/test/LoadSpice2dTest.h
+++ b/Framework/DataHandling/test/LoadSpice2dTest.h
@@ -9,6 +9,7 @@
 #include "MantidGeometry/Instrument/ParameterMap.h"
 #include "MantidGeometry/Instrument/Parameter.h"
 #include "MantidKernel/PropertyWithValue.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Run.h"
 #include <Poco/Path.h>
 #include <vector>
diff --git a/Framework/DataHandling/test/LoadSpiceAsciiTest.h b/Framework/DataHandling/test/LoadSpiceAsciiTest.h
index d8f8c1a37e508f4151a5843c3b634db0393d2b09..d0f2137d3a0012677a3e18394b66ab29bcf8af06 100644
--- a/Framework/DataHandling/test/LoadSpiceAsciiTest.h
+++ b/Framework/DataHandling/test/LoadSpiceAsciiTest.h
@@ -4,6 +4,7 @@
 #include <cxxtest/TestSuite.h>
 #include "MantidDataHandling/LoadSpiceAscii.h"
 
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/ITableWorkspace.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/Run.h"
diff --git a/Framework/DataHandling/test/LoadSpiceXML2DDetTest.h b/Framework/DataHandling/test/LoadSpiceXML2DDetTest.h
index 1d27805f05e4b5461c70f93738aec5d403d3160b..d5ab96dc8938af0e3303ed7698a87f99b73f5eec 100644
--- a/Framework/DataHandling/test/LoadSpiceXML2DDetTest.h
+++ b/Framework/DataHandling/test/LoadSpiceXML2DDetTest.h
@@ -4,6 +4,7 @@
 #include <cxxtest/TestSuite.h>
 
 #include "MantidDataHandling/LoadSpiceXML2DDet.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/ITableWorkspace.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/Run.h"
@@ -42,9 +43,13 @@ public:
 
   //----------------------------------------------------------------------------------------------
   /** Sample test load data without instrument
-   * @brief test_LoadHB3AXML
+   * test data: HB3A_exp355_scan0001_0522
+   *   2theta = 42.70975 degree
+   * check:
+   *   sample logs: including run_start, monitor, omega, chi, phi and 2theta
+   * @brief Load data without instrument
    */
-  void test_LoadHB3AXML() {
+  void test_LoadDataNoInstrument() {
     LoadSpiceXML2DDet loader;
     loader.initialize();
 
@@ -121,13 +126,15 @@ public:
 
   //----------------------------------------------------------------------------------------------
   /** Test algorithm with loading HB3A with instrument and presense of SPICE
-   * scan table
-   *  such that it can be set to zero-2-theta position
-   * @brief test_LoadHB3AXML2InstrumentedWS
-   * Testing include
-   * 1. 2theta = 0 degree: scattering angle of all 4 corners should be same;
+   * scan table such that it will override 2theta value in the XML file
+   * Test: Set 2theta = 0
+   *  1. Detector should be symmetric along the X-axis and about the center of
+   * detector;
+   *  2. All pixels on the X-axis will have position Y value zero;
+   *  3. All pixels on the Y-axis will have position X value zero
+   * @brief test: load data with instrument whose detector's 2theta value is 0.
    */
-  void test_LoadHB3ADataZeroPosition() {
+  void test_LoadDataOverwrite2ThetaZero() {
     // Test 2theta at 0 degree
     LoadSpiceXML2DDet loader;
     loader.initialize();
@@ -142,7 +149,7 @@ public:
     loader.setProperty("DetectorGeometry", sizelist);
     loader.setProperty("LoadInstrument", true);
     loader.setProperty("SpiceTableWorkspace", scantablews);
-    loader.setProperty("PtNumber", 3);
+    loader.setProperty("PtNumber", 3); // pt number 3 has 2theta value as 0.0
     loader.setProperty("ShiftedDetectorDistance", 0.);
 
     loader.execute();
@@ -154,9 +161,11 @@ public:
     TS_ASSERT(outws);
     TS_ASSERT_EQUALS(outws->getNumberHistograms(), 256 * 256);
 
-    // Value
-    TS_ASSERT_DELTA(outws->readY(255 * 256)[0], 1.0, 0.0001);
-    TS_ASSERT_DELTA(outws->readY(9 * 256 + 253)[0], 1.0, 0.00001);
+    // test signal value on various pixels
+    // pixel at (256, 1): column 1
+    TS_ASSERT_DELTA(outws->readY(255)[0], 1.0, 0.0001);
+    // pixel at (254, 256): colun 256
+    TS_ASSERT_DELTA(outws->readY(255 * 256 + 138)[0], 2.0, 0.00001);
 
     // Instrument
     TS_ASSERT(outws->getInstrument());
@@ -167,14 +176,54 @@ public:
     // check center of the detector @ (128, 115)
     size_t center_col = 128;
     size_t center_row = 115;
-    size_t center_ws_index = (center_row - 1) * 256 + (center_col - 1);
+    size_t center_ws_index = (center_row - 1) + (center_col - 1) * 256;
     Kernel::V3D det_center = outws->getDetector(center_ws_index)->getPos();
     // distance to sample
     double dist_r = det_center.distance(sample);
     TS_ASSERT_DELTA(dist_r, 0.3750, 0.0001);
     // center of the detector must be at zero
     TS_ASSERT_DELTA(det_center.X(), 0.0, 0.0000001);
-    TS_ASSERT_DELTA(det_center.Y(), 0.0, 0.0000001)
+    TS_ASSERT_DELTA(det_center.Y(), 0.0, 0.0000001);
+
+    // check the sequence of the detector to each ws index
+    detid_t det0id = outws->getDetector(0)->getID();
+    TS_ASSERT_EQUALS(det0id, 0);
+    detid_t det1id = outws->getDetector(1)->getID();
+    TS_ASSERT_EQUALS(det1id, 1);
+    detid_t detlastid = outws->getDetector(256 * 255 + 255)->getID();
+    TS_ASSERT_EQUALS(detlastid, 255 * 256 + 255);
+    // test the whole sequence
+    for (size_t irow = 1; irow < 250; ++irow)
+      for (size_t jcol = 10; jcol < 20; ++jcol) {
+        size_t iws = irow + jcol * 256;
+        detid_t detid = outws->getDetector(iws)->getID();
+        TS_ASSERT_EQUALS(detid, static_cast<detid_t>(iws));
+      }
+
+    // test the geometry position whether det ID is from lower right corner and
+    // move along positive Y direction
+    // right most column
+    Kernel::V3D det0pos = outws->getDetector(0)->getPos();
+    TS_ASSERT_DELTA(det0pos.X(), 0.0252015625, 0.000001);
+    TS_ASSERT_DELTA(det0pos.Y(), -0.022621875, 0.000001);
+    TS_ASSERT_DELTA(det0pos.Z(), 0.375, 0.0001);
+
+    double dY = 0.0001984375;
+
+    Kernel::V3D det1pos = outws->getDetector(1)->getPos();
+    TS_ASSERT_DELTA(det1pos.X(), 0.0252015625, 0.000001);
+    TS_ASSERT_DELTA(det1pos.Y(), -0.022621875 + dY, 0.000001);
+    TS_ASSERT_DELTA(det1pos.Z(), 0.375, 0.0001);
+
+    // center is tested before
+
+    // lower left column
+    size_t i_wsll = 255 * 256 + 1;
+    double dX = -0.0001984375;
+    Kernel::V3D detllpos = outws->getDetector(i_wsll)->getPos();
+    TS_ASSERT_DELTA(detllpos.X(), 0.0252015625 + 255 * dX, 0.000001);
+    TS_ASSERT_DELTA(detllpos.Y(), -0.022621875 + dY, 0.000001);
+    TS_ASSERT_DELTA(detllpos.Z(), 0.375, 0.0001);
 
     // test the detectors with symmetric to each other
     // they should have opposite X or Y
@@ -182,22 +231,22 @@ public:
     // ll: low-left, lr: low-right, ul: upper-left; ur: upper-right
     size_t row_ll = 0;
     size_t col_ll = 2;
-    size_t ws_index_ll = row_ll * 256 + col_ll;
+    size_t ws_index_ll = row_ll + col_ll * 256;
     Kernel::V3D det_ll_pos = outws->getDetector(ws_index_ll)->getPos();
 
     size_t row_lr = 0;
     size_t col_lr = 2 * 127 - 2;
-    size_t ws_index_lr = row_lr * 256 + col_lr;
+    size_t ws_index_lr = row_lr + col_lr * 256;
     Kernel::V3D det_lr_pos = outws->getDetector(ws_index_lr)->getPos();
 
     size_t row_ul = 114 * 2;
     size_t col_ul = 2;
-    size_t ws_index_ul = row_ul * 256 + col_ul;
+    size_t ws_index_ul = row_ul + col_ul * 256;
     Kernel::V3D det_ul_pos = outws->getDetector(ws_index_ul)->getPos();
 
     size_t row_ur = 114 * 2;
     size_t col_ur = 2 * 127 - 2;
-    size_t ws_index_ur = row_ur * 256 + col_ur;
+    size_t ws_index_ur = row_ur + col_ur * 256;
     Kernel::V3D det_ur_pos = outws->getDetector(ws_index_ur)->getPos();
 
     double det_size = 0.0508; // meter
@@ -221,12 +270,16 @@ public:
   }
 
   //----------------------------------------------------------------------------------------------
-  /** Test with loading instrument but without Spice scan Table.
-   *  Other tests include check the positions of detectors
-   *  2-theta = 42.797
-   * @brief test_LoadHB3AXMLInstrumentNoTable
+  /** Test with loading instrument without Spice scan Table, while the 2theta
+   * value is from sample
+   *    sample log
+   *  Testing includes:
+   *  1. Load the instrument without Spice Table;
+   *  2. Check the positions of detectors.
+   *    (a) at center pixel, 2-theta = 42.797
+   * @brief Load data and instrument with sample log value
    */
-  void test_LoadHB3AXMLInstrumentNoTable() {
+  void test_loadDataUsingSampleLogValue() {
     // initialize the algorithm
     LoadSpiceXML2DDet loader;
     loader.initialize();
@@ -253,8 +306,11 @@ public:
     TS_ASSERT_EQUALS(outws->getNumberHistograms(), 256 * 256);
 
     // Value
-    TS_ASSERT_DELTA(outws->readY(255 * 256)[0], 1.0, 0.0001);
-    TS_ASSERT_DELTA(outws->readY(9 * 256 + 253)[0], 1.0, 0.00001);
+    // test signal value on various pixels
+    // pixel at (256, 1): column 1
+    TS_ASSERT_DELTA(outws->readY(255)[0], 1.0, 0.0001);
+    // pixel at (254, 256): colun 256
+    TS_ASSERT_DELTA(outws->readY(255 * 256 + 138)[0], 2.0, 0.00001);
 
     // Instrument
     TS_ASSERT(outws->getInstrument());
@@ -279,7 +335,7 @@ public:
     // check the center position
     size_t center_row = 115 - 1;
     size_t center_col = 128 - 1;
-    size_t center_ws_index = 256 * center_row + center_col;
+    size_t center_ws_index = 256 * center_col + center_row;
     Kernel::V3D center_det_pos = outws->getDetector(center_ws_index)->getPos();
     TS_ASSERT_DELTA(center_det_pos.Y(), 0., 0.00000001);
     double sample_center_distance = sample.distance(center_det_pos);
@@ -294,7 +350,7 @@ public:
     double ll_sample_r = sample.distance(ll_det_pos);
     TS_ASSERT_DELTA(ll_sample_r, 0.37597, 0.001);
 
-    size_t lu_ws_index = 255 * 256; // row = 255, col = 1
+    size_t lu_ws_index = 255; // row = 255, col = 1
     Kernel::V3D lu_det_pos = outws->getDetector(lu_ws_index)->getPos();
     double lu_sample_r = sample.distance(lu_det_pos);
     TS_ASSERT_DELTA(lu_sample_r, 0.37689, 0.001);
@@ -344,8 +400,11 @@ public:
     TS_ASSERT_EQUALS(outws->getNumberHistograms(), 256 * 256);
 
     // Value
-    TS_ASSERT_DELTA(outws->readY(255 * 256)[0], 1.0, 0.0001);
-    TS_ASSERT_DELTA(outws->readY(9 * 256 + 253)[0], 1.0, 0.00001);
+    // test signal value on various pixels
+    // pixel at (256, 1): column 1
+    TS_ASSERT_DELTA(outws->readY(255)[0], 1.0, 0.0001);
+    // pixel at (254, 256): colun 256
+    TS_ASSERT_DELTA(outws->readY(255 * 256 + 138)[0], 2.0, 0.00001);
 
     // Instrument
     TS_ASSERT(outws->getInstrument());
@@ -357,7 +416,7 @@ public:
     // check center of the detector @ (128, 115)
     size_t center_col = 128;
     size_t center_row = 115;
-    size_t center_ws_index = (center_row - 1) * 256 + (center_col - 1);
+    size_t center_ws_index = (center_row - 1) + (center_col - 1) * 256;
     Kernel::V3D center_det_pos = outws->getDetector(center_ws_index)->getPos();
     // distance to sample
     double dist_r = center_det_pos.distance(sample);
@@ -373,22 +432,22 @@ public:
     // ll: low-left, lr: low-right, ul: upper-left; ur: upper-right
     size_t row_ll = 0;
     size_t col_ll = 2;
-    size_t ws_index_ll = row_ll * 256 + col_ll;
+    size_t ws_index_ll = row_ll + col_ll * 256;
     Kernel::V3D det_ll_pos = outws->getDetector(ws_index_ll)->getPos();
 
     size_t row_lr = 0;
     size_t col_lr = 2 * 127 - 2;
-    size_t ws_index_lr = row_lr * 256 + col_lr;
+    size_t ws_index_lr = row_lr + col_lr * 256;
     Kernel::V3D det_lr_pos = outws->getDetector(ws_index_lr)->getPos();
 
     size_t row_ul = 114 * 2;
     size_t col_ul = 2;
-    size_t ws_index_ul = row_ul * 256 + col_ul;
+    size_t ws_index_ul = row_ul + col_ul * 256;
     Kernel::V3D det_ul_pos = outws->getDetector(ws_index_ul)->getPos();
 
     size_t row_ur = 114 * 2;
     size_t col_ur = 2 * 127 - 2;
-    size_t ws_index_ur = row_ur * 256 + col_ur;
+    size_t ws_index_ur = row_ur + col_ur * 256;
     Kernel::V3D det_ur_pos = outws->getDetector(ws_index_ur)->getPos();
 
     // Check symmetry
@@ -403,6 +462,131 @@ public:
     AnalysisDataService::Instance().remove("Exp0335_S0038D");
   }
 
+  //----------------------------------------------------------------------------------------------
+  /** Test with loading instrument without Spice scan Table and detector is
+   *shifted from original
+   *  center
+   *
+   *  Testing includes:
+   *  1. Load the instrument without Spice Table;
+   *  2. Check the positions of shifted detector: from (115, 128) to (127,137)
+   *    (a) at center pixel, 2-theta = 42.797 and pixel ID
+   *  3. Check the symmetry of the peak positions
+   * @brief Load data and instrument with sample log value
+   */
+  void test_loadDataShiftDetectorCenter() {
+    // initialize the algorithm
+    LoadSpiceXML2DDet loader;
+    loader.initialize();
+
+    // calculate shift of the detector center from (115, 128) to (127, 127)
+    double det_step_x = -0.0001984375;
+    double shift_x = static_cast<double>(137 - 128) * det_step_x *
+                     -1.; // shift x comes from column
+    double det_step_y = 0.0001984375;
+    double shift_y = static_cast<double>(127 - 115) * det_step_y *
+                     -1; // shift y comes from row
+
+    // set up properties
+    const std::string filename("HB3A_exp355_scan0001_0522.xml");
+    TS_ASSERT_THROWS_NOTHING(loader.setProperty("Filename", filename));
+    TS_ASSERT_THROWS_NOTHING(
+        loader.setProperty("OutputWorkspace", "Exp0335_S0038C"));
+    std::vector<size_t> sizelist(2);
+    sizelist[0] = 256;
+    sizelist[1] = 256;
+    loader.setProperty("DetectorGeometry", sizelist);
+    loader.setProperty("LoadInstrument", true);
+    loader.setProperty("ShiftedDetectorDistance", 0.);
+    loader.setProperty("DetectorCenterXShift", shift_x);
+    loader.setProperty("DetectorCenterYShift", shift_y);
+
+    loader.execute();
+    TS_ASSERT(loader.isExecuted());
+
+    // Get data
+    MatrixWorkspace_sptr outws = boost::dynamic_pointer_cast<MatrixWorkspace>(
+        AnalysisDataService::Instance().retrieve("Exp0335_S0038C"));
+    TS_ASSERT(outws);
+    TS_ASSERT_EQUALS(outws->getNumberHistograms(), 256 * 256);
+
+    // Value
+    // test signal value on various pixels
+    // pixel at (256, 1): column 1
+    TS_ASSERT_DELTA(outws->readY(255)[0], 1.0, 0.0001);
+    // pixel at (254, 256): column 256
+    TS_ASSERT_DELTA(outws->readY(255 * 256 + 138)[0], 2.0, 0.00001);
+
+    // Instrument
+    TS_ASSERT(outws->getInstrument());
+
+    // get 2theta from workspace
+    double twotheta_raw =
+        atof(outws->run().getProperty("_2theta")->value().c_str());
+
+    Kernel::Property *raw_property = outws->run().getProperty("2theta");
+    Kernel::TimeSeriesProperty<double> *twotheta_property =
+        dynamic_cast<Kernel::TimeSeriesProperty<double> *>(raw_property);
+    TS_ASSERT(twotheta_property);
+    double twotheta_log = twotheta_property->valuesAsVector()[0];
+    TS_ASSERT_DELTA(twotheta_log, 42.70975, 0.0001);
+
+    TS_ASSERT_EQUALS(twotheta_raw, twotheta_log);
+
+    // check the center of the detector
+    Kernel::V3D source = outws->getInstrument()->getSource()->getPos();
+    Kernel::V3D sample = outws->getInstrument()->getSample()->getPos();
+
+    // check the center position
+    size_t center_row = 127 - 1;
+    size_t center_col = 137 - 1;
+    size_t center_ws_index = 256 * center_col + center_row;
+    // y should be 0. in the Z-Y plane
+    Kernel::V3D center_det_pos = outws->getDetector(center_ws_index)->getPos();
+    TS_ASSERT_DELTA(center_det_pos.Y(), 0., 0.00000001);
+    double sample_center_distance = sample.distance(center_det_pos);
+    // distance
+    std::cout << "Sample center distance: " << sample_center_distance << "\n";
+    TS_ASSERT_DELTA(sample_center_distance, 0.3750, 0.0000001);
+    // 2-theta angle
+    double sample_center_angle =
+        (sample - source).angle(center_det_pos - sample);
+    TS_ASSERT_DELTA(sample_center_angle * 180. / M_PI, twotheta_log, 0.0001);
+
+    // symmetry from now on!
+    size_t ws_d_row = 10;
+    size_t ws_d_col = 15;
+
+    size_t ll_ws_index =
+        (center_row - ws_d_row) + (center_col - ws_d_col) * 256;
+    Kernel::V3D ll_det_pos = outws->getDetector(ll_ws_index)->getPos();
+    double ll_sample_r = sample.distance(ll_det_pos);
+
+    size_t lr_ws_index =
+        (center_row + ws_d_row) + (center_col - ws_d_col) * 256;
+    Kernel::V3D lr_det_pos = outws->getDetector(lr_ws_index)->getPos();
+    double lr_sample_r = sample.distance(lr_det_pos);
+
+    TS_ASSERT_DELTA(ll_sample_r, lr_sample_r, 0.0000001);
+
+    size_t ur_ws_index =
+        (center_row + ws_d_row) + (center_col + ws_d_col) * 256;
+    Kernel::V3D ur_det_pos = outws->getDetector(ur_ws_index)->getPos();
+    double ur_sample_r = sample.distance(ur_det_pos);
+
+    TS_ASSERT_DELTA(ll_sample_r, ur_sample_r, 0.0000001);
+
+    size_t ul_ws_index =
+        (center_row - ws_d_row) + (center_col + ws_d_col) * 256;
+    Kernel::V3D ul_det_pos = outws->getDetector(ul_ws_index)->getPos();
+    double ul_sample_r = sample.distance(ul_det_pos);
+
+    TS_ASSERT_DELTA(ul_sample_r, ur_sample_r, 0.0000001);
+
+    // Clean
+    AnalysisDataService::Instance().remove("Exp0335_S0038C");
+  }
+
   /** Create SPICE scan table workspace
    * @brief createSpiceScanTable
    * @return
diff --git a/Framework/DataHandling/test/LoadVulcanCalFileTest.h b/Framework/DataHandling/test/LoadVulcanCalFileTest.h
index 55ec9327339d4b29b653698d8c2ec310d692c6d8..a1fd723afebe0aeaca0d9eb4fe788accf78ef750 100644
--- a/Framework/DataHandling/test/LoadVulcanCalFileTest.h
+++ b/Framework/DataHandling/test/LoadVulcanCalFileTest.h
@@ -4,7 +4,9 @@
 #include <cxxtest/TestSuite.h>
 #include "MantidKernel/Timer.h"
 #include "MantidKernel/System.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Run.h"
+#include "MantidAPI/SpectrumInfo.h"
 
 #include "MantidDataHandling/LoadVulcanCalFile.h"
 #include "MantidDataObjects/GroupingWorkspace.h"
@@ -144,11 +146,12 @@ public:
     if (!maskWS)
       return;
 
+    const auto &spectrumInfo = maskWS->spectrumInfo();
     size_t nummasked = 0;
     for (size_t i = 0; i < maskWS->getNumberHistograms(); ++i) {
       if (maskWS->readY(i)[0] > 0.5) {
         ++nummasked;
-        TS_ASSERT(maskWS->getDetector(i)->isMasked());
+        TS_ASSERT(spectrumInfo.isMasked(i));
       }
     }
 
diff --git a/Framework/DataHandling/test/MaskDetectorsInShapeTest.h b/Framework/DataHandling/test/MaskDetectorsInShapeTest.h
index 97797a41e912bd5a456d5117192b3647d53422ef..8ef1fc33059fca35fb2c442b6af77269a961748e 100644
--- a/Framework/DataHandling/test/MaskDetectorsInShapeTest.h
+++ b/Framework/DataHandling/test/MaskDetectorsInShapeTest.h
@@ -7,6 +7,8 @@
 #include "MantidDataHandling/LoadEmptyInstrument.h"
 #include "MantidGeometry/Instrument.h"
 #include "MantidKernel/ArrayProperty.h"
+#include "MantidAPI/AnalysisDataService.h"
+#include "MantidAPI/DetectorInfo.h"
 #include "MantidAPI/FrameworkManager.h"
 
 using namespace Mantid::API;
@@ -81,10 +83,9 @@ public:
     // check that the detectors have actually been marked dead
     std::vector<int> expectedDetectorArray =
         convertStringToVector(expectedHits);
-    Mantid::Geometry::Instrument_const_sptr i = outWS->getInstrument();
-    for (std::vector<int>::iterator it = expectedDetectorArray.begin();
-         it != expectedDetectorArray.end(); ++it) {
-      TS_ASSERT(i->getDetector((*it))->isMasked())
+    const auto &detectorInfo = outWS->detectorInfo();
+    for (const auto detID : expectedDetectorArray) {
+      TS_ASSERT(detectorInfo.isMasked(detectorInfo.indexOf(detID)));
     }
   }
 
diff --git a/Framework/DataHandling/test/MaskDetectorsTest.h b/Framework/DataHandling/test/MaskDetectorsTest.h
index cdd82dfc4e78547a7b036607750db4c8681fad93..2553fd4fe8c97058a47c1190d24bfc07e07a5fd0 100644
--- a/Framework/DataHandling/test/MaskDetectorsTest.h
+++ b/Framework/DataHandling/test/MaskDetectorsTest.h
@@ -5,6 +5,8 @@
 
 #include "MantidHistogramData/LinearGenerator.h"
 #include "MantidDataHandling/MaskDetectors.h"
+#include "MantidAPI/AnalysisDataService.h"
+#include "MantidAPI/DetectorInfo.h"
 #include "MantidAPI/WorkspaceProperty.h"
 #include "MantidKernel/ArrayProperty.h"
 #include "MantidDataObjects/Workspace2D.h"
@@ -14,7 +16,9 @@
 #include "MantidAPI/FrameworkManager.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidAPI/AlgorithmManager.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidTestHelpers/ComponentCreationHelper.h"
+#include "MantidTestHelpers/WorkspaceCreationHelper.h"
 #include "MantidGeometry/IDetector.h"
 
 using namespace Mantid::DataHandling;
@@ -35,7 +39,7 @@ public:
   static MaskDetectorsTest *createSuite() { return new MaskDetectorsTest(); }
   static void destroySuite(MaskDetectorsTest *suite) { delete suite; }
 
-  MaskDetectorsTest() {}
+  MaskDetectorsTest() = default;
 
   void testName() { TS_ASSERT_EQUALS(marker.name(), "MaskDetectors"); }
 
@@ -84,11 +88,11 @@ public:
       BinEdges x(6, LinearGenerator(10.0, 1.0));
       Counts y(5, 1.0);
       CountStandardDeviations e(5, 1.0);
-      for (int j = 0; j < numspec; ++j) {
+      for (size_t j = 0; j < space2D->getNumberHistograms(); ++j) {
         space2D->setBinEdges(j, x);
         space2D->setCounts(j, y);
         space2D->setCountStandardDeviations(j, e);
-        space2D->getSpectrum(j).setSpectrumNo(j + 1);
+        space2D->getSpectrum(j).setSpectrumNo(static_cast<int>(j + 1));
         auto id = space2D->getDetector(j)->getID();
         space2D->getSpectrum(j).setDetectorID(id);
       }
@@ -120,7 +124,7 @@ public:
     TS_ASSERT(mdd.isInitialized());
 
     std::vector<Property *> props = mdd.getProperties();
-    TS_ASSERT_EQUALS(static_cast<int>(props.size()), 8);
+    TS_ASSERT_EQUALS(static_cast<int>(props.size()), 9);
 
     TS_ASSERT_EQUALS(props[0]->name(), "Workspace");
     TS_ASSERT(props[0]->isDefault());
@@ -141,6 +145,19 @@ public:
     TS_ASSERT_EQUALS(props[4]->name(), "MaskedWorkspace");
     TS_ASSERT(props[4]->isDefault());
     TS_ASSERT(dynamic_cast<WorkspaceProperty<> *>(props[4]));
+
+    TS_ASSERT_EQUALS(props[5]->name(), "ForceInstrumentMasking");
+    TS_ASSERT(props[5]->isDefault());
+
+    TS_ASSERT_EQUALS(props[6]->name(), "StartWorkspaceIndex");
+    TS_ASSERT(props[6]->isDefault());
+
+    TS_ASSERT_EQUALS(props[7]->name(), "EndWorkspaceIndex");
+    TS_ASSERT(props[7]->isDefault());
+
+    TS_ASSERT_EQUALS(props[8]->name(), "ComponentList");
+    TS_ASSERT(props[8]->isDefault());
+    TS_ASSERT(dynamic_cast<ArrayProperty<std::string> *>(props[8]));
   }
 
   //---------------------------------------------------------------------------------------------
@@ -170,11 +187,12 @@ public:
     TS_ASSERT_EQUALS(outputWS->dataE(3)[0], zeroes);
     TS_ASSERT_EQUALS(outputWS->dataY(4)[0], ones);
     TS_ASSERT_EQUALS(outputWS->dataE(4)[0], ones);
-    TS_ASSERT(outputWS->getDetector(0)->isMasked());
-    TS_ASSERT(!outputWS->getDetector(1)->isMasked());
-    TS_ASSERT(outputWS->getDetector(2)->isMasked());
-    TS_ASSERT(outputWS->getDetector(3)->isMasked());
-    TS_ASSERT(!outputWS->getDetector(4)->isMasked());
+    const auto &spectrumInfo = outputWS->spectrumInfo();
+    TS_ASSERT(spectrumInfo.isMasked(0));
+    TS_ASSERT(!spectrumInfo.isMasked(1));
+    TS_ASSERT(spectrumInfo.isMasked(2));
+    TS_ASSERT(spectrumInfo.isMasked(3));
+    TS_ASSERT(!spectrumInfo.isMasked(4));
   }
 
   //---------------------------------------------------------------------------------------------
@@ -235,6 +253,61 @@ public:
     AnalysisDataService::Instance().remove("testSpace");
   }
 
+  void test_Mask_Specific_Components() {
+    const int numBanks = 3;
+    const int numSpec = 9 * numBanks;
+    setUpWS(false, "testSpace", false, numSpec);
+    MaskDetectors masker;
+    masker.setRethrows(true);
+    TS_ASSERT_THROWS_NOTHING(masker.initialize())
+    TS_ASSERT(masker.isInitialized())
+    TS_ASSERT_THROWS_NOTHING(masker.setProperty("Workspace", "testSpace"))
+    TS_ASSERT_THROWS_NOTHING(masker.setProperty(
+        "ComponentList", "bank1/pixel-(0;1), bank3/pixel-(1;1)"))
+    const detid_t maskedPixel1 = 7;
+    const detid_t maskedPixel2 = 26;
+    TS_ASSERT_THROWS_NOTHING(masker.execute())
+    TS_ASSERT(masker.isExecuted())
+    MatrixWorkspace_const_sptr outputWS =
+        AnalysisDataService::Instance().retrieveWS<const MatrixWorkspace>(
+            "testSpace");
+    const auto &spectrumInfo = outputWS->spectrumInfo();
+    for (size_t i = 0; i < numSpec; ++i) {
+      if (i == maskedPixel1 || i == maskedPixel2) {
+        TS_ASSERT(spectrumInfo.isMasked(i))
+      } else {
+        TS_ASSERT(!spectrumInfo.isMasked(i))
+      }
+    }
+    AnalysisDataService::Instance().remove("testSpace");
+  }
+
+  void test_Mask_Components_Recursively() {
+    const int numBanks = 3;
+    const int numSpec = 9 * numBanks;
+    setUpWS(false, "testSpace", false, numSpec);
+    MaskDetectors masker;
+    masker.setRethrows(true);
+    TS_ASSERT_THROWS_NOTHING(masker.initialize())
+    TS_ASSERT(masker.isInitialized())
+    TS_ASSERT_THROWS_NOTHING(masker.setProperty("Workspace", "testSpace"))
+    TS_ASSERT_THROWS_NOTHING(masker.setProperty("ComponentList", "bank2"))
+    TS_ASSERT_THROWS_NOTHING(masker.execute())
+    TS_ASSERT(masker.isExecuted())
+    MatrixWorkspace_const_sptr outputWS =
+        AnalysisDataService::Instance().retrieveWS<const MatrixWorkspace>(
+            "testSpace");
+    const auto &spectrumInfo = outputWS->spectrumInfo();
+    for (size_t i = 0; i < numSpec; ++i) {
+      if (i >= 9 && i < 18) {
+        TS_ASSERT(spectrumInfo.isMasked(i))
+      } else {
+        TS_ASSERT(!spectrumInfo.isMasked(i))
+      }
+    }
+    AnalysisDataService::Instance().remove("testSpace");
+  }
+
   //---------------------------------------------------------------------------------------------
   void test_That_Giving_A_Workspace_Containing_Masks_Copies_These_Masks_Over() {
     // Create 2 workspaces
@@ -251,15 +324,10 @@ public:
     masked_indices.insert(3);
     masked_indices.insert(4);
 
-    ParameterMap &pmap = existingMask->instrumentParameters();
-    for (int i = 0; i < static_cast<int>(existingMask->getNumberHistograms());
-         ++i) {
-      if (masked_indices.count(i) == 1) {
-        IDetector_const_sptr det;
-        TS_ASSERT_THROWS_NOTHING(det = existingMask->getDetector(i));
-        pmap.addBool(det.get(), "masked", true);
-      }
-    }
+    auto &detInfo = existingMask->mutableDetectorInfo();
+    for (int i = 0; i < static_cast<int>(detInfo.size()); ++i)
+      if (masked_indices.count(i) == 1)
+        detInfo.setMasked(i, true);
 
     MaskDetectors masker;
     TS_ASSERT_THROWS_NOTHING(masker.initialize());
@@ -279,15 +347,15 @@ public:
     TS_ASSERT(originalWS);
     if (!originalWS)
       return;
+    const auto &spectrumInfo = originalWS->spectrumInfo();
     for (int i = 0; i < static_cast<int>(originalWS->getNumberHistograms());
          ++i) {
-      IDetector_const_sptr det;
-      TS_ASSERT_THROWS_NOTHING(det = originalWS->getDetector(i));
+      TS_ASSERT(spectrumInfo.hasDetectors(i));
       if (masked_indices.count(i) == 1) {
-        TS_ASSERT_EQUALS(det->isMasked(), true);
+        TS_ASSERT_EQUALS(spectrumInfo.isMasked(i), true);
         TS_ASSERT_EQUALS(originalWS->readY(i)[0], 0.0);
       } else {
-        TS_ASSERT_EQUALS(det->isMasked(), false);
+        TS_ASSERT_EQUALS(spectrumInfo.isMasked(i), false);
         TS_ASSERT_EQUALS(originalWS->readY(i)[0], 1.0);
       }
     }
@@ -343,15 +411,15 @@ public:
     if (!originalWS)
       return;
 
+    const auto &spectrumInfo = originalWS->spectrumInfo();
     for (int i = 0; i < static_cast<int>(originalWS->getNumberHistograms() - 1);
          ++i) {
-      IDetector_const_sptr det;
-      TS_ASSERT_THROWS_NOTHING(det = originalWS->getDetector(i));
+      TS_ASSERT(spectrumInfo.hasDetectors(i));
       if (masked_indices.count(i) == 1) {
-        TS_ASSERT_EQUALS(det->isMasked(), true);
+        TS_ASSERT_EQUALS(spectrumInfo.isMasked(i), true);
         TS_ASSERT_EQUALS(originalWS->readY(i)[0], 0.0);
       } else {
-        TS_ASSERT_EQUALS(det->isMasked(), false);
+        TS_ASSERT_EQUALS(spectrumInfo.isMasked(i), false);
         TS_ASSERT_EQUALS(originalWS->readY(i)[0], 1.0);
       }
     }
@@ -394,13 +462,13 @@ public:
         inputWSName);
 
     // Check masking
+    const auto &spectrumInfo = inputWS->spectrumInfo();
     for (int i = 0; i < numInputSpec; ++i) {
-      IDetector_const_sptr det;
-      TS_ASSERT_THROWS_NOTHING(det = inputWS->getDetector(i));
+      TS_ASSERT(spectrumInfo.hasDetectors(i));
       if (i == 3 || i == 4) {
-        TS_ASSERT_EQUALS(det->isMasked(), true);
+        TS_ASSERT_EQUALS(spectrumInfo.isMasked(i), true);
       } else {
-        TS_ASSERT_EQUALS(det->isMasked(), false);
+        TS_ASSERT_EQUALS(spectrumInfo.isMasked(i), false);
       }
     }
 
@@ -425,13 +493,13 @@ public:
         inputWSName);
 
     // Check masking
+    const auto &spectrumInfo = inputWS->spectrumInfo();
     for (int i = 0; i < numInputSpec; ++i) {
-      IDetector_const_sptr det;
-      TS_ASSERT_THROWS_NOTHING(det = inputWS->getDetector(i));
+      TS_ASSERT(spectrumInfo.hasDetectors(i));
       if (i == 3 || i == 4 || i == 5) {
-        TS_ASSERT_EQUALS(det->isMasked(), true);
+        TS_ASSERT_EQUALS(spectrumInfo.isMasked(i), true);
       } else {
-        TS_ASSERT_EQUALS(det->isMasked(), false);
+        TS_ASSERT_EQUALS(spectrumInfo.isMasked(i), false);
       }
     }
 
@@ -489,21 +557,23 @@ public:
         inputWSName);
 
     // Check masking
+    const auto &spectrumInfo = inputWS->spectrumInfo();
     for (size_t i = 0; i < inputWS->getNumberHistograms(); ++i) {
       IDetector_const_sptr det;
       TS_ASSERT_THROWS_NOTHING(det = inputWS->getDetector(i));
+      TS_ASSERT(spectrumInfo.hasDetectors(i));
       if (i == 0 || i == 2 || i == 5) {
         TSM_ASSERT_EQUALS("Detector with id: " +
                               boost::lexical_cast<std::string>(det->getID()) +
                               "; Spectra N: " +
                               boost::lexical_cast<std::string>(i),
-                          det->isMasked(), true);
+                          spectrumInfo.isMasked(i), true);
       } else {
         TSM_ASSERT_EQUALS("Detector with id: " +
                               boost::lexical_cast<std::string>(det->getID()) +
                               "; Spectra N: " +
                               boost::lexical_cast<std::string>(i),
-                          det->isMasked(), false);
+                          spectrumInfo.isMasked(i), false);
       }
     }
 
@@ -554,21 +624,23 @@ public:
         inputWSName);
 
     // Check masking
+    const auto &spectrumInfo = inputWS->spectrumInfo();
     for (size_t i = 0; i < inputWS->getNumberHistograms(); ++i) {
       IDetector_const_sptr det;
       TS_ASSERT_THROWS_NOTHING(det = inputWS->getDetector(i));
+      TS_ASSERT(spectrumInfo.hasDetectors(i));
       if (i == 1 || i == 2 || i == 5) {
         TSM_ASSERT_EQUALS("Detector with id: " +
                               boost::lexical_cast<std::string>(det->getID()) +
                               "; Spectra N: " +
                               boost::lexical_cast<std::string>(i),
-                          det->isMasked(), true);
+                          spectrumInfo.isMasked(i), true);
       } else {
         TSM_ASSERT_EQUALS("Detector with id: " +
                               boost::lexical_cast<std::string>(det->getID()) +
                               "; Spectra N: " +
                               boost::lexical_cast<std::string>(i),
-                          det->isMasked(), false);
+                          spectrumInfo.isMasked(i), false);
       }
     }
 
@@ -576,6 +648,144 @@ public:
     AnalysisDataService::Instance().remove(existingMaskName);
   }
 
+  void test_MaskWithWorkspaceWithDetectorIDs() {
+    auto &ads = AnalysisDataService::Instance();
+    const std::string inputWSName("inputWS"), existingMaskName("existingMask");
+    const int numInputSpec(90);
+
+    setUpWS(false, inputWSName, false, numInputSpec);
+
+    auto inputWS = ads.retrieveWS<MatrixWorkspace>(inputWSName);
+
+    // group spectra into 10
+    auto grouper = AlgorithmManager::Instance().create("GroupDetectors");
+    grouper->initialize();
+    grouper->setProperty("InputWorkspace", inputWSName);
+    grouper->setPropertyValue("OutputWorkspace", inputWSName);
+    grouper->setPropertyValue(
+        "GroupingPattern",
+        "0-9,10-19,20-29,30-39,40-49,50-59,60-69,70-79,80-89");
+    grouper->execute();
+
+    TS_ASSERT(grouper->isExecuted());
+
+    inputWS = ads.retrieveWS<MatrixWorkspace>(inputWSName);
+    TS_ASSERT(inputWS);
+
+    // Make workspace to act as mask
+    const auto numMaskWSSpec = inputWS->getInstrument()->getNumberDetectors();
+    auto maskWs = WorkspaceCreationHelper::create2DWorkspaceBinned(
+        static_cast<int>(numMaskWSSpec), 1, 0, 0);
+    maskWs->setInstrument(inputWS->getInstrument());
+    for (size_t i = 0; i < maskWs->getNumberHistograms(); ++i) {
+      maskWs->mutableY(i)[0] = 1.0;
+    }
+
+    maskWs->mutableY(10)[0] = 0;
+    maskWs->mutableY(20)[0] = 0;
+    maskWs->mutableY(55)[0] = 0;
+
+    // Apply
+    MaskDetectors masker;
+    masker.initialize();
+    masker.setPropertyValue("Workspace", inputWSName);
+    masker.setProperty("MaskedWorkspace", maskWs);
+    masker.setRethrows(true);
+    TS_ASSERT_THROWS_NOTHING(masker.execute());
+    inputWS = ads.retrieveWS<MatrixWorkspace>(inputWSName);
+
+    // Check masking
+    const auto &spectrumInfo = inputWS->spectrumInfo();
+    for (size_t i = 0; i < inputWS->getNumberHistograms(); ++i) {
+      IDetector_const_sptr det;
+      TS_ASSERT_THROWS_NOTHING(det = inputWS->getDetector(i));
+      TS_ASSERT(spectrumInfo.hasDetectors(i));
+      if (i == 1 || i == 2 || i == 5) {
+        TSM_ASSERT_EQUALS("Detector with id: " +
+                              boost::lexical_cast<std::string>(det->getID()) +
+                              "; Spectra N: " +
+                              boost::lexical_cast<std::string>(i),
+                          spectrumInfo.isMasked(i), true);
+      } else {
+        TSM_ASSERT_EQUALS("Detector with id: " +
+                              boost::lexical_cast<std::string>(det->getID()) +
+                              "; Spectra N: " +
+                              boost::lexical_cast<std::string>(i),
+                          spectrumInfo.isMasked(i), false);
+      }
+    }
+  }
+
+  void test_MaskWithWorkspaceWithDetectorIDsAndWsIndexRange() {
+    auto &ads = AnalysisDataService::Instance();
+    const std::string inputWSName("inputWS"), existingMaskName("existingMask");
+    const int numInputSpec(90);
+
+    setUpWS(false, inputWSName, false, numInputSpec);
+
+    auto inputWS = ads.retrieveWS<MatrixWorkspace>(inputWSName);
+
+    // group spectra into 10
+    auto grouper = AlgorithmManager::Instance().create("GroupDetectors");
+    grouper->initialize();
+    grouper->setProperty("InputWorkspace", inputWSName);
+    grouper->setPropertyValue("OutputWorkspace", inputWSName);
+    grouper->setPropertyValue(
+        "GroupingPattern",
+        "0-9,10-19,20-29,30-39,40-49,50-59,60-69,70-79,80-89");
+    grouper->execute();
+
+    TS_ASSERT(grouper->isExecuted());
+
+    inputWS = ads.retrieveWS<MatrixWorkspace>(inputWSName);
+    TS_ASSERT(inputWS);
+
+    // Make workspace to act as mask
+    const auto numMaskWSSpec = inputWS->getInstrument()->getNumberDetectors();
+    auto maskWs = WorkspaceCreationHelper::create2DWorkspaceBinned(
+        static_cast<int>(numMaskWSSpec), 1, 0, 0);
+    maskWs->setInstrument(inputWS->getInstrument());
+    for (size_t i = 0; i < maskWs->getNumberHistograms(); ++i) {
+      maskWs->mutableY(i)[0] = 1.0;
+    }
+
+    maskWs->mutableY(10)[0] = 0;
+    maskWs->mutableY(20)[0] = 0;
+    maskWs->mutableY(55)[0] = 0;
+
+    // Apply
+    MaskDetectors masker;
+    masker.initialize();
+    masker.setPropertyValue("Workspace", inputWSName);
+    masker.setProperty("MaskedWorkspace", maskWs);
+    masker.setProperty("StartWorkspaceIndex", 2);
+    masker.setProperty("EndWorkspaceIndex", 4);
+    masker.setRethrows(true);
+    TS_ASSERT_THROWS_NOTHING(masker.execute());
+    inputWS = ads.retrieveWS<MatrixWorkspace>(inputWSName);
+
+    // Check masking
+    const auto &spectrumInfo = inputWS->spectrumInfo();
+    for (size_t i = 0; i < inputWS->getNumberHistograms(); ++i) {
+      IDetector_const_sptr det;
+      TS_ASSERT_THROWS_NOTHING(det = inputWS->getDetector(i));
+      TS_ASSERT(spectrumInfo.hasDetectors(i));
+      if (i == 2) {
+        TSM_ASSERT_EQUALS("Detector with id: " +
+                              boost::lexical_cast<std::string>(det->getID()) +
+                              "; Spectra N: " +
+                              boost::lexical_cast<std::string>(i),
+                          spectrumInfo.isMasked(i), true);
+      } else {
+        TSM_ASSERT_EQUALS("Detector with id: " +
+                              boost::lexical_cast<std::string>(det->getID()) +
+                              "; Spectra N: " +
+                              boost::lexical_cast<std::string>(i),
+                          spectrumInfo.isMasked(i), false);
+      }
+    }
+  }
+
 private:
   MaskDetectors marker;
 };
diff --git a/Framework/DataHandling/test/MergeLogsTest.h b/Framework/DataHandling/test/MergeLogsTest.h
index 8ac64140c6f14de3f74643afc245c472e4bb5de2..2505be16c0275284792ce3e12eff9b46efbda343 100644
--- a/Framework/DataHandling/test/MergeLogsTest.h
+++ b/Framework/DataHandling/test/MergeLogsTest.h
@@ -4,6 +4,7 @@
 #include <cxxtest/TestSuite.h>
 #include "MantidKernel/Timer.h"
 #include "MantidKernel/System.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/Run.h"
 #include "MantidAPI/WorkspaceFactory.h"
diff --git a/Framework/DataHandling/test/NXcanSASTestHelper.cpp b/Framework/DataHandling/test/NXcanSASTestHelper.cpp
index 699907701a65cd4eba4de3e66f53c3be26c18988..7598619c6a8129561137fed8f60f368243701cfe 100644
--- a/Framework/DataHandling/test/NXcanSASTestHelper.cpp
+++ b/Framework/DataHandling/test/NXcanSASTestHelper.cpp
@@ -79,10 +79,10 @@ Mantid::API::MatrixWorkspace_sptr
 provide1DWorkspace(NXcanSASTestParameters &parameters) {
   Mantid::API::MatrixWorkspace_sptr ws;
   if (parameters.hasDx) {
-    ws = WorkspaceCreationHelper::Create1DWorkspaceConstantWithXerror(
+    ws = WorkspaceCreationHelper::create1DWorkspaceConstantWithXerror(
         parameters.size, parameters.value, parameters.error, parameters.xerror);
   } else {
-    ws = WorkspaceCreationHelper::Create1DWorkspaceConstant(
+    ws = WorkspaceCreationHelper::create1DWorkspaceConstant(
         parameters.size, parameters.value, parameters.error);
   }
 
@@ -114,7 +114,7 @@ provide1DWorkspace(NXcanSASTestParameters &parameters) {
 
 Mantid::API::MatrixWorkspace_sptr
 getTransmissionWorkspace(NXcanSASTestTransmissionParameters &parameters) {
-  auto ws = WorkspaceCreationHelper::Create1DWorkspaceConstant(
+  auto ws = WorkspaceCreationHelper::create1DWorkspaceConstant(
       parameters.size, parameters.value, parameters.error);
   ws->setTitle(parameters.name);
   ws->getAxis(0)->unit() =
diff --git a/Framework/DataHandling/test/PDLoadCharacterizationsTest.h b/Framework/DataHandling/test/PDLoadCharacterizationsTest.h
index 59a5b057acb1ed2a5ef6bffa017dbeb7506865e6..d74a1ac87a3d5c254d70fa30393f7e2559fea8e9 100644
--- a/Framework/DataHandling/test/PDLoadCharacterizationsTest.h
+++ b/Framework/DataHandling/test/PDLoadCharacterizationsTest.h
@@ -4,6 +4,7 @@
 #include <boost/shared_ptr.hpp>
 #include <cxxtest/TestSuite.h>
 
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/ITableWorkspace.h"
 
 #include "MantidDataHandling/PDLoadCharacterizations.h"
@@ -26,7 +27,7 @@ public:
     TS_ASSERT(alg.isInitialized());
 
     // run the algorithm
-    alg.setProperty("Filename", filename);
+    alg.setPropertyValue("Filename", filename);
     alg.setPropertyValue("OutputWorkspace", filename);
     TS_ASSERT(alg.execute());
     TS_ASSERT(alg.isExecuted());
@@ -80,7 +81,7 @@ public:
   }
 
   void checkPG3(ITableWorkspace_sptr &wksp) {
-    TS_ASSERT_EQUALS(wksp->columnCount(), 10);
+    TS_ASSERT_EQUALS(wksp->columnCount(), 14);
     TS_ASSERT_EQUALS(wksp->rowCount(), 6);
 
     // check all of the contents of row 0
@@ -88,24 +89,90 @@ public:
     TS_ASSERT_EQUALS(wksp->Double(0, 1), 0.900);
     TS_ASSERT_EQUALS(wksp->Int(0, 2), 1);
     TS_ASSERT_EQUALS(wksp->String(0, 3), "15030");
-    TS_ASSERT_EQUALS(wksp->String(0, 4), "15039");
-    TS_ASSERT_EQUALS(wksp->String(0, 5), "0");
-    TS_ASSERT_EQUALS(wksp->String(0, 6), "0.20");
-    TS_ASSERT_EQUALS(wksp->String(0, 7), "4.12");
-    TS_ASSERT_EQUALS(wksp->Double(0, 8), 4700.);
-    TS_ASSERT_EQUALS(wksp->Double(0, 9), 21200.);
+    TS_ASSERT_EQUALS(wksp->String(0, 4), "0");
+    TS_ASSERT_EQUALS(wksp->String(0, 5), "15039");
+    TS_ASSERT_EQUALS(wksp->String(0, 6), "0");
+    TS_ASSERT_EQUALS(wksp->String(0, 7), "0");
+    TS_ASSERT_EQUALS(wksp->String(0, 8), "0.20");
+    TS_ASSERT_EQUALS(wksp->String(0, 9), "4.12");
+    TS_ASSERT_EQUALS(wksp->Double(0, 10), 4700.);
+    TS_ASSERT_EQUALS(wksp->Double(0, 11), 21200.);
 
     // check all of the contents of row 5
     TS_ASSERT_EQUALS(wksp->Double(5, 0), 10.);
     TS_ASSERT_EQUALS(wksp->Double(5, 1), 3.198);
     TS_ASSERT_EQUALS(wksp->Int(5, 2), 1);
     TS_ASSERT_EQUALS(wksp->String(5, 3), "15033");
-    TS_ASSERT_EQUALS(wksp->String(5, 4), "15042");
-    TS_ASSERT_EQUALS(wksp->String(5, 5), "0");
-    TS_ASSERT_EQUALS(wksp->String(5, 6), "0.05");
-    TS_ASSERT_EQUALS(wksp->String(5, 7), "15.40");
-    TS_ASSERT_EQUALS(wksp->Double(5, 8), 0.);
-    TS_ASSERT_EQUALS(wksp->Double(5, 9), 100000.);
+    TS_ASSERT_EQUALS(wksp->String(5, 4), "0");
+    TS_ASSERT_EQUALS(wksp->String(5, 5), "15042");
+    TS_ASSERT_EQUALS(wksp->String(5, 6), "0");
+    TS_ASSERT_EQUALS(wksp->String(5, 7), "0");
+    TS_ASSERT_EQUALS(wksp->String(5, 8), "0.05");
+    TS_ASSERT_EQUALS(wksp->String(5, 9), "15.40");
+    TS_ASSERT_EQUALS(wksp->Double(5, 10), 0.);
+    TS_ASSERT_EQUALS(wksp->Double(5, 11), 100000.);
+  }
+
+  void checkPG3WithContainers(ITableWorkspace_sptr &wksp) {
+    TS_ASSERT_EQUALS(wksp->columnCount(), 17);
+    TS_ASSERT_EQUALS(wksp->rowCount(), 8);
+
+    // check all of the contents of row 0
+    TS_ASSERT_EQUALS(wksp->Double(0, 0), 60.);
+    TS_ASSERT_EQUALS(wksp->Double(0, 1), 0.900);
+    TS_ASSERT_EQUALS(wksp->Int(0, 2), 1);
+    TS_ASSERT_EQUALS(wksp->String(0, 3), "15030");
+    TS_ASSERT_EQUALS(wksp->String(0, 4), "0");
+    TS_ASSERT_EQUALS(wksp->String(0, 5), "15039");
+    TS_ASSERT_EQUALS(wksp->String(0, 6), "0");
+    TS_ASSERT_EQUALS(wksp->String(0, 7), "0");
+    TS_ASSERT_EQUALS(wksp->String(0, 8), "0.20");
+    TS_ASSERT_EQUALS(wksp->String(0, 9), "4.12");
+    TS_ASSERT_EQUALS(wksp->Double(0, 10), 4700.);
+    TS_ASSERT_EQUALS(wksp->Double(0, 11), 21200.);
+    TS_ASSERT_EQUALS(wksp->Double(0, 12), 0.);
+    TS_ASSERT_EQUALS(wksp->Double(0, 13), 0.);
+    TS_ASSERT_EQUALS(wksp->String(0, 14), "0");
+    TS_ASSERT_EQUALS(wksp->String(0, 15), "0");
+    TS_ASSERT_EQUALS(wksp->String(0, 16), "0");
+
+    // check all of the contents of row 4
+    TS_ASSERT_EQUALS(wksp->Double(4, 0), 60.);
+    TS_ASSERT_EQUALS(wksp->Double(4, 1), 4.797);
+    TS_ASSERT_EQUALS(wksp->Int(4, 2), 5);
+    TS_ASSERT_EQUALS(wksp->String(4, 3), "27061");
+    TS_ASSERT_EQUALS(wksp->String(4, 4), "27055");
+    TS_ASSERT_EQUALS(wksp->String(4, 5), "15085");
+    TS_ASSERT_EQUALS(wksp->String(4, 6), "0");
+    TS_ASSERT_EQUALS(wksp->String(4, 7), "0");
+    TS_ASSERT_EQUALS(wksp->String(4, 8), "2.00");
+    TS_ASSERT_EQUALS(wksp->String(4, 9), "15.35");
+    TS_ASSERT_EQUALS(wksp->Double(4, 10), 66666.67);
+    TS_ASSERT_EQUALS(wksp->Double(4, 11), 83333.67);
+    TS_ASSERT_EQUALS(wksp->Double(4, 12), 0.);
+    TS_ASSERT_EQUALS(wksp->Double(4, 13), 0.);
+    TS_ASSERT_EQUALS(wksp->String(4, 14), "27049");
+    TS_ASSERT_EQUALS(wksp->String(4, 15), "27037");
+    TS_ASSERT_EQUALS(wksp->String(4, 16), "27043");
+
+    // check all of the contents of row 7
+    TS_ASSERT_EQUALS(wksp->Double(7, 0), 60.);
+    TS_ASSERT_EQUALS(wksp->Double(7, 1), 3.731);
+    TS_ASSERT_EQUALS(wksp->Int(7, 2), 1);
+    TS_ASSERT_EQUALS(wksp->String(7, 3), "27060");
+    TS_ASSERT_EQUALS(wksp->String(7, 4), "27054");
+    TS_ASSERT_EQUALS(wksp->String(7, 5), "0");
+    TS_ASSERT_EQUALS(wksp->String(7, 6), "0");
+    TS_ASSERT_EQUALS(wksp->String(7, 7), "0");
+    TS_ASSERT_EQUALS(wksp->String(7, 8), "0");
+    TS_ASSERT_EQUALS(wksp->String(7, 9), "0");
+    TS_ASSERT_EQUALS(wksp->Double(7, 10), 0.);
+    TS_ASSERT_EQUALS(wksp->Double(7, 11), 0.);
+    TS_ASSERT_EQUALS(wksp->Double(7, 12), 0.);
+    TS_ASSERT_EQUALS(wksp->Double(7, 13), 0.);
+    TS_ASSERT_EQUALS(wksp->String(7, 14), "27048");
+    TS_ASSERT_EQUALS(wksp->String(7, 15), "27036");
+    TS_ASSERT_EQUALS(wksp->String(7, 16), "27042");
   }
 
   void test_Init() {
@@ -161,7 +228,7 @@ public:
     runAlg(alg, wksp, CHAR_FILE);
 
     // test the table workspace
-    TS_ASSERT_EQUALS(wksp->columnCount(), 10);
+    TS_ASSERT_EQUALS(wksp->columnCount(), 14);
     TS_ASSERT_EQUALS(wksp->rowCount(), 1);
 
     // check all of the contents of row 0
@@ -171,10 +238,14 @@ public:
     TS_ASSERT_EQUALS(wksp->String(0, 3), "0");
     TS_ASSERT_EQUALS(wksp->String(0, 4), "0");
     TS_ASSERT_EQUALS(wksp->String(0, 5), "0");
-    TS_ASSERT_EQUALS(wksp->String(0, 6), ".31,.25,.13,.13,.13,.42");
-    TS_ASSERT_EQUALS(wksp->String(0, 7), "13.66,5.83,3.93,2.09,1.57,31.42");
-    TS_ASSERT_EQUALS(wksp->Double(0, 8), 300.00);
-    TS_ASSERT_EQUALS(wksp->Double(0, 9), 16666.67);
+    TS_ASSERT_EQUALS(wksp->String(0, 6), "0");
+    TS_ASSERT_EQUALS(wksp->String(0, 7), "0");
+    TS_ASSERT_EQUALS(wksp->String(0, 8), ".31,.25,.13,.13,.13,.42");
+    TS_ASSERT_EQUALS(wksp->String(0, 9), "13.66,5.83,3.93,2.09,1.57,31.42");
+    TS_ASSERT_EQUALS(wksp->Double(0, 10), 300.00);
+    TS_ASSERT_EQUALS(wksp->Double(0, 11), 16666.67);
+    TS_ASSERT_EQUALS(wksp->Double(0, 12), .1);
+    TS_ASSERT_EQUALS(wksp->Double(0, 13), 2.9);
 
     // test the other output properties
     checkNOMAD(alg);
@@ -189,7 +260,7 @@ public:
     runAlg(alg, wksp, CHAR_FILE);
 
     // test the table workspace
-    TS_ASSERT_EQUALS(wksp->columnCount(), 10);
+    TS_ASSERT_EQUALS(wksp->columnCount(), 14);
     TS_ASSERT_EQUALS(wksp->rowCount(), 0);
 
     // test the other output properties
@@ -248,8 +319,10 @@ public:
 
     TS_ASSERT_EQUALS(wksp->rowCount(), 1);
     TS_ASSERT_EQUALS(wksp->String(0, 3), "49258"); // vanadium
-    TS_ASSERT_EQUALS(wksp->String(0, 4), "49086"); // container
-    TS_ASSERT_EQUALS(wksp->String(0, 5), "49257"); // empty
+    TS_ASSERT_EQUALS(wksp->String(0, 4), "49086"); // vanadium_background
+    TS_ASSERT_EQUALS(wksp->String(0, 5), "49257"); // container
+    TS_ASSERT_EQUALS(wksp->String(0, 6), "0");     // empty_environment
+    TS_ASSERT_EQUALS(wksp->String(0, 7), "0");     // empty_instrument
   }
 
   void test_ExpIni_failing() {
@@ -268,6 +341,36 @@ public:
     TS_ASSERT_THROWS(alg.execute(), std::runtime_error);
     TS_ASSERT(!alg.isExecuted());
   }
+
+  void test_version2() {
+    const std::string CHAR_FILES("Test_characterizations_char.txt,"
+                                 "PG3_char_2016_02_15-PAC-single.txt");
+
+    // initialize and run the algorithm
+    ITableWorkspace_sptr wksp;
+    PDLoadCharacterizations alg;
+    runAlg(alg, wksp, CHAR_FILES);
+
+    checkPG3WithContainers(wksp);
+  }
+
+  void test_version2_wrongOrder() {
+    const std::string CHAR_FILES("PG3_char_2016_02_15-PAC-single.txt,"
+                                 "Test_characterizations_char.txt");
+    // initialize and run the algorithm
+    ITableWorkspace_sptr wksp;
+    PDLoadCharacterizations alg;
+    runAlg(alg, wksp, CHAR_FILES);
+
+    checkPG3WithContainers(wksp);
+  }
+
+  /* TODO this is for a later iteration
+  void xtest_version2_extras() {
+    const std::string CHAR_FILES("Test_characterizations_char.txt,"
+                                 "PG3_char_2016_02_15-PAC-extras.txt");
+  }
+  */
 };
 
 #endif /* MANTID_DATAHANDLING_LOADPDCHARACTERIZATIONSTEST_H_ */
diff --git a/Framework/DataHandling/test/ProcessDasNexusLogTest.h b/Framework/DataHandling/test/ProcessDasNexusLogTest.h
deleted file mode 100644
index 94f68475b3500ffa6e2491cc4a32808e38902623..0000000000000000000000000000000000000000
--- a/Framework/DataHandling/test/ProcessDasNexusLogTest.h
+++ /dev/null
@@ -1,123 +0,0 @@
-#ifndef MANTID_DATAHANDLING_PROCESSDASNEXUSLOGTEST_H_
-#define MANTID_DATAHANDLING_PROCESSDASNEXUSLOGTEST_H_
-
-#include <cxxtest/TestSuite.h>
-#include "MantidKernel/Timer.h"
-#include "MantidKernel/System.h"
-
-#include "MantidDataHandling/ProcessDasNexusLog.h"
-#include "MantidTestHelpers/WorkspaceCreationHelper.h"
-#include "MantidDataObjects/EventWorkspace.h"
-#include "MantidDataObjects/Events.h"
-#include "MantidDataObjects/EventList.h"
-#include "MantidKernel/TimeSeriesProperty.h"
-
-using namespace Mantid;
-using namespace Mantid::DataHandling;
-using namespace Mantid::API;
-
-class ProcessDasNexusLogTest : public CxxTest::TestSuite {
-public:
-  // This pair of boilerplate methods prevent the suite being created statically
-  // This means the constructor isn't called when running other tests
-  static ProcessDasNexusLogTest *createSuite() {
-    return new ProcessDasNexusLogTest();
-  }
-  static void destroySuite(ProcessDasNexusLogTest *suite) { delete suite; }
-
-  void test_ConvertLog() {
-    // 1. Create event workspace w/ pulse as 0.1 second
-    DataObjects::EventWorkspace_sptr eventws = createEventWorkspace(0.1, 100);
-    AnalysisDataService::Instance().addOrReplace("EventWS", eventws);
-
-    // 2. Start
-    ProcessDasNexusLog alg;
-    TS_ASSERT_THROWS_NOTHING(alg.initialize());
-    TS_ASSERT(alg.isInitialized());
-
-    // 3. Do it
-    alg.setPropertyValue("InputWorkspace", "EventWS");
-    alg.setProperty("LogToProcess", "daslog");
-    alg.setProperty("ProcessedLog", "newlog");
-    alg.setProperty("NumberOfOutputs", -1);
-    alg.setProperty("OutputLogFile", "mylog.dat");
-    alg.setProperty("OutputDirectory", "./");
-
-    TS_ASSERT_THROWS_NOTHING(alg.execute());
-    TS_ASSERT(alg.isExecuted());
-
-    // 4. Get result
-    DataObjects::EventWorkspace_sptr outws =
-        boost::dynamic_pointer_cast<DataObjects::EventWorkspace>(
-            AnalysisDataService::Instance().retrieve("EventWS"));
-    TS_ASSERT(outws);
-    if (!outws)
-      return;
-
-    // 5. Check data
-    Kernel::TimeSeriesProperty<double> *newlog =
-        dynamic_cast<Kernel::TimeSeriesProperty<double> *>(
-            outws->run().getProperty("newlog"));
-
-    TS_ASSERT_EQUALS(newlog->size(), 100);
-
-    int64_t t0 = newlog->nthTime(0).totalNanoseconds();
-    TS_ASSERT_EQUALS(t0, 20000030000);
-
-    // -1. Clean
-    AnalysisDataService::Instance().remove("EventWS");
-  }
-
-  /*
-   * Create an EventWorkspace.  This workspace will have
-   * (1) Events with wall time even in time
-   * (2) Pulse length: in second
-   */
-  DataObjects::EventWorkspace_sptr createEventWorkspace(double pulselength,
-                                                        size_t numpulses) {
-    // 1. Create an EventWorkspace with 10 detectors
-    DataObjects::EventWorkspace_sptr eventWS =
-        WorkspaceCreationHelper::createEventWorkspaceWithFullInstrument(10, 1,
-                                                                        true);
-
-    int64_t runstart_i64 = 20000000000;
-    Kernel::DateAndTime runstart(runstart_i64);
-    int64_t pulsedt = 100 * 1000 * 1000;
-    int64_t tofdt = 10 * 1000 * 1000;
-
-    // 2. Set run_start time
-    eventWS->mutableRun().addProperty("run_start", runstart.toISO8601String(),
-                                      true);
-
-    for (size_t i = 0; i < eventWS->getNumberHistograms(); i++) {
-      auto &elist = eventWS->getSpectrum(i);
-
-      for (int64_t pid = 0; pid < 5; pid++) {
-        int64_t pulsetime_i64 = pid * pulsedt + runstart.totalNanoseconds();
-        Kernel::DateAndTime pulsetime(pulsetime_i64);
-        for (size_t e = 0; e < 10; e++) {
-          double tof = static_cast<double>(e * tofdt / 1000);
-          DataObjects::TofEvent event(tof, pulsetime);
-          elist.addEventQuickly(event);
-        }
-      } // FOR each pulse
-    }   // For each bank
-
-    // 3. Add a log (DAS)
-    Kernel::TimeSeriesProperty<double> *daslog =
-        new Kernel::TimeSeriesProperty<double>("daslog");
-
-    double tofms = 300.0;
-    for (size_t i = 0; i < numpulses; i++) {
-      Kernel::DateAndTime pulsetime(
-          runstart.totalNanoseconds() +
-          static_cast<int64_t>(static_cast<double>(i) * pulselength * 1.0E-9));
-      daslog->addValue(pulsetime, tofms);
-    }
-    eventWS->mutableRun().addProperty(daslog);
-
-    return eventWS;
-  }
-};
-
-#endif /* MANTID_DATAHANDLING_PROCESSDASNEXUSLOGTEST_H_ */
diff --git a/Framework/DataHandling/test/RawFileInfoTest.h b/Framework/DataHandling/test/RawFileInfoTest.h
index 4e2fc9cc16e0b4f66d95dba9f82f9a5e1ac2186f..0afcdc16157ced33ed28bd38505532737f07617d 100644
--- a/Framework/DataHandling/test/RawFileInfoTest.h
+++ b/Framework/DataHandling/test/RawFileInfoTest.h
@@ -3,6 +3,7 @@
 
 #include <cxxtest/TestSuite.h>
 #include "MantidDataHandling/RawFileInfo.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/ITableWorkspace.h"
 
 using namespace Mantid::DataHandling;
diff --git a/Framework/DataHandling/test/RemoveLogsTest.h b/Framework/DataHandling/test/RemoveLogsTest.h
index e179a08fbde45fd947818977efa09228d8188800..33f4f7762a2d59222932c71bdb52a08a5a44657d 100644
--- a/Framework/DataHandling/test/RemoveLogsTest.h
+++ b/Framework/DataHandling/test/RemoveLogsTest.h
@@ -118,7 +118,7 @@ private:
   void createSampleWorkspace() {
     // Create the workspace
     MatrixWorkspace_sptr ws =
-        WorkspaceCreationHelper::Create2DWorkspace(10, 100);
+        WorkspaceCreationHelper::create2DWorkspace(10, 100);
 
     // Add some log entries to it
     std::vector<DateAndTime> times;
diff --git a/Framework/DataHandling/test/RenameLogTest.h b/Framework/DataHandling/test/RenameLogTest.h
index dc218afb3634fd6d9da6ef7d54b8e5a9fd7e4ebc..56d1ead62dd403d5fd105ee80d2e7fd87e25a6fb 100644
--- a/Framework/DataHandling/test/RenameLogTest.h
+++ b/Framework/DataHandling/test/RenameLogTest.h
@@ -2,6 +2,7 @@
 #define MANTID_DATAHANDLING_RENAMELOGTEST_H_
 
 #include <cxxtest/TestSuite.h>
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/Run.h"
 #include "MantidAPI/WorkspaceFactory.h"
diff --git a/Framework/DataHandling/test/RotateSourceTest.h b/Framework/DataHandling/test/RotateSourceTest.h
index f1a6c3f0e496be1e64cc38e5dad8477766b4f887..e87ac1f29b621e2e35b1b780ce05c84acadfc859 100644
--- a/Framework/DataHandling/test/RotateSourceTest.h
+++ b/Framework/DataHandling/test/RotateSourceTest.h
@@ -49,7 +49,7 @@ public:
     instr->markAsSamplePos(sample);
 
     // The workspace
-    auto ws = WorkspaceCreationHelper::Create2DWorkspace123(1, 1);
+    auto ws = WorkspaceCreationHelper::create2DWorkspace123(1, 1);
     ws->setInstrument(instr);
     // The angle
     double theta = 90.;
@@ -88,7 +88,7 @@ public:
     instr->markAsSamplePos(sample);
 
     // The workspace
-    auto ws = WorkspaceCreationHelper::Create2DWorkspace123(1, 1);
+    auto ws = WorkspaceCreationHelper::create2DWorkspace123(1, 1);
     ws->setInstrument(instr);
     // The angle
     double theta = -90.;
@@ -127,7 +127,7 @@ public:
     instr->markAsSamplePos(sample);
 
     // The workspace
-    auto ws = WorkspaceCreationHelper::Create2DWorkspace123(1, 1);
+    auto ws = WorkspaceCreationHelper::create2DWorkspace123(1, 1);
     ws->setInstrument(instr);
     // The angle
     double theta = 90.;
@@ -166,7 +166,7 @@ public:
     instr->markAsSamplePos(sample);
 
     // The workspace
-    auto ws = WorkspaceCreationHelper::Create2DWorkspace123(1, 1);
+    auto ws = WorkspaceCreationHelper::create2DWorkspace123(1, 1);
     ws->setInstrument(instr);
     // The angle
     double theta = 90.;
@@ -186,4 +186,4 @@ public:
   }
 };
 
-#endif /* MANTID_DATAHANDLING_ROTATESOURCETEST_H_ */
\ No newline at end of file
+#endif /* MANTID_DATAHANDLING_ROTATESOURCETEST_H_ */
diff --git a/Framework/DataHandling/test/SaveANSTOAsciiTest.h b/Framework/DataHandling/test/SaveANSTOAsciiTest.h
index 9969005cbd29572a765c20bee928dbf8e71fefce..10da07d9748090a32ad2d6ce98dd345425d87a39 100644
--- a/Framework/DataHandling/test/SaveANSTOAsciiTest.h
+++ b/Framework/DataHandling/test/SaveANSTOAsciiTest.h
@@ -159,7 +159,38 @@ public:
 
     cleanupafterwards();
   }
+  void testParameters() {
+    // create a new workspace and then delete it later on
+    createWS();
+
+    Mantid::API::IAlgorithm_sptr alg =
+        Mantid::API::AlgorithmManager::Instance().create("SaveANSTOAscii");
+    alg->setPropertyValue("InputWorkspace", m_name);
+    alg->setPropertyValue("Filename", m_filename);
+    alg->setPropertyValue("Separator", "comma");
+    TS_ASSERT_THROWS_NOTHING(alg->execute());
+
+    if (!alg->isExecuted()) {
+      TS_FAIL("Could not run SaveANSTOAscii");
+    }
+    m_long_filename = alg->getPropertyValue("Filename");
+    // has the algorithm written a file to disk?
+    TS_ASSERT(Poco::File(m_long_filename).exists());
+    std::ifstream in(m_long_filename.c_str());
+    std::string fullline;
+    getline(in, fullline);
+    std::vector<std::string> columns;
+    boost::split(columns, fullline, boost::is_any_of(","),
+                 boost::token_compress_on);
+    TS_ASSERT_EQUALS(columns.size(), 4);
+    TS_ASSERT_DELTA(boost::lexical_cast<double>(columns.at(0)), 1.5, 0.01);
+    TS_ASSERT_DELTA(boost::lexical_cast<double>(columns.at(1)), 1, 0.01);
+    TS_ASSERT_DELTA(boost::lexical_cast<double>(columns.at(2)), 1, 0.01);
+    TS_ASSERT_DELTA(boost::lexical_cast<double>(columns.at(3)), 0.6, 0.01);
+    in.close();
 
+    cleanupafterwards();
+  }
   void test_fail_invalid_workspace() {
     Mantid::API::IAlgorithm_sptr alg =
         Mantid::API::AlgorithmManager::Instance().create("SaveANSTOAscii");
@@ -177,7 +208,7 @@ public:
 
 private:
   void createWS(bool zeroX = false, bool zeroY = false, bool zeroE = false) {
-    MatrixWorkspace_sptr ws = WorkspaceCreationHelper::Create2DWorkspace(1, 10);
+    MatrixWorkspace_sptr ws = WorkspaceCreationHelper::create2DWorkspace(1, 10);
     AnalysisDataService::Instance().addOrReplace(m_name, ws);
     // Check if any of X, Y or E should be zeroed to check for divide by zero or
     // similiar
diff --git a/Framework/DataHandling/test/SaveAsciiTest.h b/Framework/DataHandling/test/SaveAsciiTest.h
index ac20d16588e8eddc1d9bab9fd112fc424fb87129..ada5c579b7e42b493036347766456c56cd21df13 100644
--- a/Framework/DataHandling/test/SaveAsciiTest.h
+++ b/Framework/DataHandling/test/SaveAsciiTest.h
@@ -4,6 +4,7 @@
 #include <cxxtest/TestSuite.h>
 #include "MantidDataHandling/SaveAscii.h"
 #include "MantidDataObjects/Workspace2D.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/FrameworkManager.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include <fstream>
diff --git a/Framework/DataHandling/test/SaveCalFileTest.h b/Framework/DataHandling/test/SaveCalFileTest.h
index cdd7025bb62c4c66ac33de8ed84cc96ef0be0039..9d0d643b19622b7e75b4dfbe85bc58bbe55d1459 100644
--- a/Framework/DataHandling/test/SaveCalFileTest.h
+++ b/Framework/DataHandling/test/SaveCalFileTest.h
@@ -6,6 +6,7 @@
 #include "MantidDataObjects/GroupingWorkspace.h"
 #include "MantidDataObjects/OffsetsWorkspace.h"
 #include "MantidDataObjects/MaskWorkspace.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidKernel/System.h"
 #include "MantidKernel/Timer.h"
 #include "MantidTestHelpers/ComponentCreationHelper.h"
@@ -42,7 +43,8 @@ public:
     groupWS->setValue(3, 45);
     offsetsWS->setValue(1, 0.123);
     offsetsWS->setValue(2, 0.456);
-    maskWS->maskWorkspaceIndex(0);
+    maskWS->getSpectrum(0).clearData();
+    maskWS->mutableSpectrumInfo().setMasked(0, true);
 
     // Name of the output workspace.
     std::string outWSName("SaveCalFileTest_OutputWS");
diff --git a/Framework/DataHandling/test/SaveCanSAS1dTest.h b/Framework/DataHandling/test/SaveCanSAS1dTest.h
index 9a97b40ca9f6989e2fd2b94521b9379c3fe756d2..5a8fe2c988e978398e14f42807a744d60e2ace9b 100644
--- a/Framework/DataHandling/test/SaveCanSAS1dTest.h
+++ b/Framework/DataHandling/test/SaveCanSAS1dTest.h
@@ -4,6 +4,7 @@
 
 #include "MantidAPI/Axis.h"
 #include "MantidAPI/Sample.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidDataHandling/LoadRaw3.h"
 #include "MantidDataHandling/SaveCanSAS1D.h"
 #include "MantidDataHandling/LoadCanSAS1D.h"
diff --git a/Framework/DataHandling/test/SaveCanSAS1dTest2.h b/Framework/DataHandling/test/SaveCanSAS1dTest2.h
index 8cb991cee58ea205c4abe9c11c36055093884ebf..2ea7b1cd9db174dcd349152796d89eba3d1b5de2 100644
--- a/Framework/DataHandling/test/SaveCanSAS1dTest2.h
+++ b/Framework/DataHandling/test/SaveCanSAS1dTest2.h
@@ -3,11 +3,15 @@
 #include <cxxtest/TestSuite.h>
 
 #include "MantidAPI/Axis.h"
+#include "MantidAPI/WorkspaceGroup.h"
+#include "MantidAPI/Sample.h"
 #include "MantidDataHandling/LoadRaw3.h"
 #include "MantidDataHandling/SaveCanSAS1D2.h"
-#include "MantidDataHandling/LoadCanSAS1D.h"
+#include "MantidDataHandling/LoadCanSAS1D2.h"
 #include "MantidGeometry/Instrument.h"
 #include "MantidKernel/UnitFactory.h"
+#include "MantidTestHelpers/WorkspaceCreationHelper.h"
+
 #include <Poco/Path.h>
 #include <Poco/File.h>
 
@@ -30,7 +34,6 @@ public:
         m_workspace3("SaveCanSAS1dTest2_in3"), m_filename("./savecansas1d2.xml")
 
   {
-
     LoadRaw3 loader;
     if (!loader.isInitialized())
       loader.initialize();
@@ -279,7 +282,73 @@ public:
     TS_ASSERT_DELTA(ws2d->dataE(0).back(), 0, tolerance);
   }
 
+  void test_that_can_save_and_load_full_collimation_information() {
+    std::string geometry = "Disc";
+    double width = 1;
+    double height = 2;
+    int expectedGeometryFlag = 3;
+    double expectedWidth = 1;
+    double expectedHeight = 2;
+    do_test_collimation_settings(geometry, width, height, expectedGeometryFlag,
+                                 expectedWidth, expectedHeight);
+  }
+
 private:
+  void do_test_collimation_settings(const std::string &geometry, double width,
+                                    double height, int expectedGeometry,
+                                    double expectedWidth,
+                                    double expectedHeight) {
+    // Create sample workspace
+    auto wsIn = WorkspaceCreationHelper::create1DWorkspaceRand(3);
+    auto axis = wsIn->getAxis(0);
+    axis->unit() = UnitFactory::Instance().create("MomentumTransfer");
+    axis->title() = "|Q|";
+
+    AnalysisDataService::Instance().addOrReplace("test_worksapce_can_sas_1d",
+                                                 wsIn);
+    // Save the workspace
+    SaveCanSAS1D2 savealg;
+    TS_ASSERT_THROWS_NOTHING(savealg.initialize());
+    TS_ASSERT(savealg.isInitialized());
+    savealg.setProperty("InputWorkspace", wsIn);
+    savealg.setPropertyValue("Filename", m_filename);
+    savealg.setPropertyValue("DetectorNames", "HAB");
+    savealg.setProperty("Geometry", geometry);
+    savealg.setProperty("SampleWidth", width);
+    savealg.setProperty("SampleHeight", height);
+
+    TS_ASSERT_THROWS_NOTHING(savealg.execute());
+    TS_ASSERT(savealg.isExecuted());
+
+    // retrieve the data that we saved to check it
+    LoadCanSAS1D lAlg;
+    TS_ASSERT_THROWS_NOTHING(lAlg.initialize());
+    TS_ASSERT(lAlg.isInitialized());
+    lAlg.setPropertyValue("OutputWorkspace",
+                          "test_worksapce_can_sas_1d_reloaded");
+    lAlg.setPropertyValue("Filename", m_filename);
+    TS_ASSERT_THROWS_NOTHING(lAlg.execute());
+    TS_ASSERT(lAlg.isExecuted());
+    Workspace_sptr ws = AnalysisDataService::Instance().retrieve(
+        "test_worksapce_can_sas_1d_reloaded");
+    Mantid::API::MatrixWorkspace_sptr loaded =
+        boost::dynamic_pointer_cast<Mantid::API::MatrixWorkspace>(ws);
+
+    // Check that elements are set correctly
+    TS_ASSERT(loaded->sample().getGeometryFlag() == expectedGeometry);
+    TS_ASSERT(loaded->sample().getWidth() == expectedWidth);
+    TS_ASSERT(loaded->sample().getHeight() == expectedHeight);
+
+    // Delete workspaces
+    std::string toDeleteList[2] = {"test_worksapce_can_sas_1d",
+                                   "test_worksapce_can_sas_1d_reloaded"};
+    for (auto &toDelete : toDeleteList) {
+      if (AnalysisDataService::Instance().doesExist(toDelete)) {
+        AnalysisDataService::Instance().remove(toDelete);
+      }
+    }
+  }
+
   std::string m_workspace1, m_workspace2, m_workspace3, m_filename;
   std::string m_runNum;
   MatrixWorkspace_sptr ws;
diff --git a/Framework/DataHandling/test/SaveDaveGrpTest.h b/Framework/DataHandling/test/SaveDaveGrpTest.h
index 2a6270882a332b5b637cf1c9dec01a50c8008eaa..ef9616f8956ff2c26bb96b4936e38cc587ee8b7a 100644
--- a/Framework/DataHandling/test/SaveDaveGrpTest.h
+++ b/Framework/DataHandling/test/SaveDaveGrpTest.h
@@ -267,7 +267,7 @@ private:
     // all the Y values in this new workspace are set to DEFAU_Y, which
     // currently = 2
     MatrixWorkspace_sptr inputWS =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(2, 3, 1.0);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(2, 3, 1.0);
     inputWS->getAxis(0)->unit() =
         Mantid::Kernel::UnitFactory::Instance().create("DeltaE");
     AnalysisDataService::Instance().add(input, inputWS);
diff --git a/Framework/DataHandling/test/SaveDetectorsGroupingTest.h b/Framework/DataHandling/test/SaveDetectorsGroupingTest.h
index 79ee211d051c482e58ea66dca02e3e4a1b49501d..7ab63236a7e661b38ce15fe028bcf5ce7ad3b560 100644
--- a/Framework/DataHandling/test/SaveDetectorsGroupingTest.h
+++ b/Framework/DataHandling/test/SaveDetectorsGroupingTest.h
@@ -4,6 +4,7 @@
 #include <cxxtest/TestSuite.h>
 #include "MantidKernel/Timer.h"
 #include "MantidKernel/System.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Run.h"
 
 #include "MantidDataHandling/SaveDetectorsGrouping.h"
diff --git a/Framework/DataHandling/test/SaveDiffCalTest.h b/Framework/DataHandling/test/SaveDiffCalTest.h
index 0b0d52e967b61f1d0afa676bac39246496cb08a1..3aa6f969260c2e1c28e332cfec1b8e99b92b217e 100644
--- a/Framework/DataHandling/test/SaveDiffCalTest.h
+++ b/Framework/DataHandling/test/SaveDiffCalTest.h
@@ -4,6 +4,7 @@
 #include <cxxtest/TestSuite.h>
 #include <Poco/File.h>
 
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidAPI/TableRow.h"
 #include "MantidDataHandling/SaveDiffCal.h"
 #include "MantidDataObjects/MaskWorkspace.h"
@@ -50,7 +51,8 @@ public:
 
   MaskWorkspace_sptr createMasking(Instrument_sptr instr) {
     MaskWorkspace_sptr maskWS = boost::make_shared<MaskWorkspace>(instr);
-    maskWS->maskWorkspaceIndex(0);
+    maskWS->getSpectrum(0).clearData();
+    maskWS->mutableSpectrumInfo().setMasked(0, true);
     return maskWS;
   }
 
diff --git a/Framework/DataHandling/test/SaveDspacemapTest.h b/Framework/DataHandling/test/SaveDspacemapTest.h
index 4b2bbffb535bd59aceb4cc4f44c27163f5ff21d5..1f7cdf6d5c888bbab84caed8e17f3b5a5dbc7e88 100644
--- a/Framework/DataHandling/test/SaveDspacemapTest.h
+++ b/Framework/DataHandling/test/SaveDspacemapTest.h
@@ -4,6 +4,7 @@
 #include "MantidDataHandling/SaveDspacemap.h"
 #include "MantidDataHandling/LoadDspacemap.h"
 #include "MantidDataObjects/OffsetsWorkspace.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidKernel/System.h"
 #include "MantidKernel/Timer.h"
 #include "MantidTestHelpers/ComponentCreationHelper.h"
diff --git a/Framework/DataHandling/test/SaveFITSTest.h b/Framework/DataHandling/test/SaveFITSTest.h
index e0e6c0d9fd4f6a4ce2cff600bdd1f203af87097e..479da0f6104ee55be857d6d41975e1cca477e5fa 100644
--- a/Framework/DataHandling/test/SaveFITSTest.h
+++ b/Framework/DataHandling/test/SaveFITSTest.h
@@ -8,6 +8,7 @@
 #include "MantidAPI/NumericAxis.h"
 #include "MantidDataObjects/Workspace2D.h"
 #include "MantidKernel/Exception.h"
+#include "MantidKernel/Unit.h"
 #include "MantidKernel/UnitFactory.h"
 
 #include "MantidTestHelpers/WorkspaceCreationHelper.h"
@@ -70,7 +71,7 @@ public:
   void test_exec_fails_units() {
     const std::string filename = "./savefits_wont_work.fits";
 
-    auto ws = WorkspaceCreationHelper::Create2DWorkspace(2, 2);
+    auto ws = WorkspaceCreationHelper::create2DWorkspace(2, 2);
 
     SaveFITS alg;
     TS_ASSERT_THROWS_NOTHING(alg.initialize())
@@ -102,7 +103,7 @@ public:
     const std::string filename = "./savefits_simple_test.fits";
 
     // create with appropriate units
-    auto ws = WorkspaceCreationHelper::Create2DWorkspace(2, 2);
+    auto ws = WorkspaceCreationHelper::create2DWorkspace(2, 2);
     auto lbl = boost::dynamic_pointer_cast<Mantid::Kernel::Units::Label>(
         Mantid::Kernel::UnitFactory::Instance().create("Label"));
     lbl->setLabel("width", "cm");
diff --git a/Framework/DataHandling/test/SaveFocussedXYETest.h b/Framework/DataHandling/test/SaveFocussedXYETest.h
index 644263939ca1065d4df721de205f76f6da188ef5..7f3717eea1176a55517453b6df9bc3fd13351f73 100644
--- a/Framework/DataHandling/test/SaveFocussedXYETest.h
+++ b/Framework/DataHandling/test/SaveFocussedXYETest.h
@@ -7,6 +7,7 @@
 
 #include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/AlgorithmManager.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidKernel/UnitFactory.h"
 #include "MantidDataObjects/Workspace2D.h"
 #include "MantidAPI/Axis.h"
@@ -33,7 +34,7 @@ public:
     using namespace Mantid::API;
     using namespace Mantid::DataObjects;
     Workspace2D_sptr workspace =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(1, 3, 1.0, 1.0);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(1, 3, 1.0, 1.0);
     workspace->getAxis(0)->unit() =
         Mantid::Kernel::UnitFactory::Instance().create("TOF");
 
@@ -94,27 +95,27 @@ public:
     using namespace Mantid::API;
     using namespace Mantid::DataObjects;
     Workspace2D_sptr workspace =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(1, 3, 1.0, 1.0);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(1, 3, 1.0, 1.0);
     workspace->getAxis(0)->unit() =
         Mantid::Kernel::UnitFactory::Instance().create("TOF");
 
     Workspace2D_sptr work_in1 =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(1, 3, 1.0, 1.0);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(1, 3, 1.0, 1.0);
     work_in1->getAxis(0)->unit() =
         Mantid::Kernel::UnitFactory::Instance().create("TOF");
 
     Workspace2D_sptr work_in2 =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(1, 3, 1.0, 1.0);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(1, 3, 1.0, 1.0);
     work_in2->getAxis(0)->unit() =
         Mantid::Kernel::UnitFactory::Instance().create("TOF");
 
     Workspace2D_sptr work_in3 =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(1, 3, 1.0, 1.0);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(1, 3, 1.0, 1.0);
     work_in3->getAxis(0)->unit() =
         Mantid::Kernel::UnitFactory::Instance().create("TOF");
 
     Workspace2D_sptr work_in4 =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(1, 3, 1.0, 1.0);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(1, 3, 1.0, 1.0);
     work_in4->getAxis(0)->unit() =
         Mantid::Kernel::UnitFactory::Instance().create("TOF");
 
@@ -190,27 +191,27 @@ public:
     using namespace Mantid::API;
     using namespace Mantid::DataObjects;
     Workspace2D_sptr workspace =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(1, 3, 1.0, 2.0);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(1, 3, 1.0, 2.0);
     workspace->getAxis(0)->unit() =
         Mantid::Kernel::UnitFactory::Instance().create("TOF");
 
     Workspace2D_sptr work_in1 =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(1, 3, 1.0, 2.0);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(1, 3, 1.0, 2.0);
     work_in1->getAxis(0)->unit() =
         Mantid::Kernel::UnitFactory::Instance().create("TOF");
 
     Workspace2D_sptr work_in2 =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(1, 3, 1.0, 2.0);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(1, 3, 1.0, 2.0);
     work_in2->getAxis(0)->unit() =
         Mantid::Kernel::UnitFactory::Instance().create("TOF");
 
     Workspace2D_sptr work_in3 =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(1, 3, 1.0, 2.0);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(1, 3, 1.0, 2.0);
     work_in3->getAxis(0)->unit() =
         Mantid::Kernel::UnitFactory::Instance().create("TOF");
 
     Workspace2D_sptr work_in4 =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(1, 3, 1.0, 2.0);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(1, 3, 1.0, 2.0);
     work_in4->getAxis(0)->unit() =
         Mantid::Kernel::UnitFactory::Instance().create("TOF");
 
@@ -293,12 +294,12 @@ public:
     using namespace Mantid::API;
     using namespace Mantid::DataObjects;
     Workspace2D_sptr workspace =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(1, 3, 1.0, 2.0);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(1, 3, 1.0, 2.0);
     workspace->getAxis(0)->unit() =
         Mantid::Kernel::UnitFactory::Instance().create("TOF");
 
     Workspace2D_sptr work_in1 =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(1, 3, 1.0, 2.0);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(1, 3, 1.0, 2.0);
     work_in1->getAxis(0)->unit() =
         Mantid::Kernel::UnitFactory::Instance().create("TOF");
 
@@ -370,7 +371,7 @@ public:
     using namespace Mantid::API;
     using namespace Mantid::DataObjects;
     Workspace2D_sptr workspace =
-        WorkspaceCreationHelper::Create2DWorkspace154(1, 3, false);
+        WorkspaceCreationHelper::create2DWorkspace154(1, 3, false);
     workspace->getAxis(0)->unit() =
         Mantid::Kernel::UnitFactory::Instance().create("TOF");
 
diff --git a/Framework/DataHandling/test/SaveFullprofResolutionTest.h b/Framework/DataHandling/test/SaveFullprofResolutionTest.h
index 20a011731a5a1d2c3d35f9fbe2359347c4356141..a669312e586b0f4e87687750b19875cdc85e22a4 100644
--- a/Framework/DataHandling/test/SaveFullprofResolutionTest.h
+++ b/Framework/DataHandling/test/SaveFullprofResolutionTest.h
@@ -5,6 +5,7 @@
 
 #include "MantidDataHandling/SaveFullprofResolution.h"
 #include "MantidDataObjects/TableWorkspace.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/TableRow.h"
 
 #include <Poco/File.h>
diff --git a/Framework/DataHandling/test/SaveGSASInstrumentFileTest.h b/Framework/DataHandling/test/SaveGSASInstrumentFileTest.h
index 26afed98e80782a8b1e2d03dd7de71be2ef794fb..7ef028aeaf2c9aac6d6f13fa3e7a55d35404b12a 100644
--- a/Framework/DataHandling/test/SaveGSASInstrumentFileTest.h
+++ b/Framework/DataHandling/test/SaveGSASInstrumentFileTest.h
@@ -5,6 +5,7 @@
 
 #include "MantidDataHandling/SaveGSASInstrumentFile.h"
 #include "MantidDataObjects/TableWorkspace.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/TableRow.h"
 #include "MantidAPI/FrameworkManager.h"
 
diff --git a/Framework/DataHandling/test/SaveGSSTest.h b/Framework/DataHandling/test/SaveGSSTest.h
index c5bfd1be54cfd1c880136e90cec58bd676416d21..8938025b6a334ba1bf9837e3c55b0876ef0ba41b 100644
--- a/Framework/DataHandling/test/SaveGSSTest.h
+++ b/Framework/DataHandling/test/SaveGSSTest.h
@@ -274,7 +274,7 @@ private:
     */
   API::MatrixWorkspace_sptr generateNoInstrumentWorkspace() {
     MatrixWorkspace_sptr dataws =
-        WorkspaceCreationHelper::Create2DWorkspace(2, 100);
+        WorkspaceCreationHelper::create2DWorkspace(2, 100);
     dataws->getAxis(0)->setUnit("TOF");
 
     // Set data with logarithm bin
diff --git a/Framework/DataHandling/test/SaveILLCosmosAsciiTest.h b/Framework/DataHandling/test/SaveILLCosmosAsciiTest.h
index 4360d79c3804b833efad941f852c3867b7754fab..120411c23c2e9f64bb9e450e61584add154914a4 100644
--- a/Framework/DataHandling/test/SaveILLCosmosAsciiTest.h
+++ b/Framework/DataHandling/test/SaveILLCosmosAsciiTest.h
@@ -62,7 +62,7 @@ public:
     boost::split(columns, fullline, boost::is_any_of("\t"),
                  boost::token_compress_on);
     TS_ASSERT_EQUALS(columns.size(), 5);
-    // the first is black due to the leading tab
+    // the first is black due to the leading separator
     TS_ASSERT(columns.at(0) == "");
     TS_ASSERT_DELTA(boost::lexical_cast<double>(columns.at(1)), 1.5, 0.01);
     TS_ASSERT_DELTA(boost::lexical_cast<double>(columns.at(2)), 1, 0.01);
@@ -96,7 +96,7 @@ public:
     boost::split(columns, fullline, boost::is_any_of("\t"),
                  boost::token_compress_on);
     TS_ASSERT_EQUALS(columns.size(), 5);
-    // the first is black due to the leading tab
+    // the first is black due to the leading separator
     TS_ASSERT(columns.at(0) == "");
     TS_ASSERT_DELTA(boost::lexical_cast<double>(columns.at(1)), 0, 0.01);
     TS_ASSERT_DELTA(boost::lexical_cast<double>(columns.at(2)), 1, 0.01);
@@ -130,7 +130,7 @@ public:
     boost::split(columns, fullline, boost::is_any_of("\t"),
                  boost::token_compress_on);
     TS_ASSERT_EQUALS(columns.size(), 5);
-    // the first is black due to the leading tab
+    // the first is black due to the leading separator
     TS_ASSERT(columns.at(0) == "");
     TS_ASSERT_DELTA(boost::lexical_cast<double>(columns.at(1)), 1.5, 0.01);
     TS_ASSERT_DELTA(boost::lexical_cast<double>(columns.at(2)), 0, 0.01);
@@ -164,7 +164,7 @@ public:
     boost::split(columns, fullline, boost::is_any_of("\t"),
                  boost::token_compress_on);
     TS_ASSERT_EQUALS(columns.size(), 5);
-    // the first is black due to the leading tab
+    // the first is black due to the leading separator
     TS_ASSERT(columns.at(0) == "");
     TS_ASSERT_DELTA(boost::lexical_cast<double>(columns.at(1)), 1.5, 0.01);
     TS_ASSERT_DELTA(boost::lexical_cast<double>(columns.at(2)), 1, 0.01);
@@ -184,6 +184,7 @@ public:
     alg->setPropertyValue("Filename", m_filename);
     alg->setPropertyValue("UserContact", "John Smith");
     alg->setPropertyValue("Title", "Testing this algorithm");
+    alg->setPropertyValue("Separator", "comma");
     TS_ASSERT_THROWS_NOTHING(alg->execute());
 
     if (!alg->isExecuted()) {
@@ -194,14 +195,14 @@ public:
     TS_ASSERT(Poco::File(m_long_filename).exists());
     std::ifstream in(m_long_filename.c_str());
     std::string fullline;
-    headingsTests(in, fullline, true);
+    headingsTests(in, fullline, true, ",");
     getline(in, fullline);
 
     std::vector<std::string> columns;
-    boost::split(columns, fullline, boost::is_any_of("\t"),
+    boost::split(columns, fullline, boost::is_any_of(","),
                  boost::token_compress_on);
     TS_ASSERT_EQUALS(columns.size(), 5);
-    // the first is black due to the leading tab
+    // the first is black due to the leading separator
     TS_ASSERT(columns.at(0) == "");
     TS_ASSERT_DELTA(boost::lexical_cast<double>(columns.at(1)), 1.5, 0.01);
     TS_ASSERT_DELTA(boost::lexical_cast<double>(columns.at(2)), 1, 0.01);
@@ -228,7 +229,7 @@ public:
 
 private:
   void headingsTests(std::ifstream &in, std::string &fullline,
-                     bool propertiesLogs = false) {
+                     bool propertiesLogs = false, std::string sep = "\t") {
     getline(in, fullline);
     TS_ASSERT(fullline == "MFT");
     getline(in, fullline);
@@ -258,14 +259,16 @@ private:
     getline(in, fullline);
     TS_ASSERT(fullline == "Number of file format: 2");
     getline(in, fullline);
-    TS_ASSERT(fullline == "Number of data points:\t9");
+    std::cout << sep;
+    TS_ASSERT(fullline == "Number of data points:" + sep + "9");
     getline(in, fullline);
     getline(in, fullline);
-    TS_ASSERT(fullline == "\tq\trefl\trefl_err\tq_res");
+    TS_ASSERT(fullline ==
+              sep + "q" + sep + "refl" + sep + "refl_err" + sep + "q_res");
   }
   void createWS(bool zeroX = false, bool zeroY = false, bool zeroE = false,
                 bool createLogs = false) {
-    MatrixWorkspace_sptr ws = WorkspaceCreationHelper::Create2DWorkspace(1, 10);
+    MatrixWorkspace_sptr ws = WorkspaceCreationHelper::create2DWorkspace(1, 10);
 
     if (createLogs) {
       ws->mutableRun().addProperty("run_title",
diff --git a/Framework/DataHandling/test/SaveMaskTest.h b/Framework/DataHandling/test/SaveMaskTest.h
index 5f10a4447ccef6b98b2b9c928784e0fe429e8742..6f60f7ab994380d05f79706c307048a862d01325 100644
--- a/Framework/DataHandling/test/SaveMaskTest.h
+++ b/Framework/DataHandling/test/SaveMaskTest.h
@@ -4,6 +4,7 @@
 #include <cxxtest/TestSuite.h>
 #include "MantidKernel/Timer.h"
 #include "MantidKernel/System.h"
+#include "MantidAPI/AnalysisDataService.h"
 
 #include "MantidDataHandling/SaveMask.h"
 #include "MantidDataHandling/LoadMask.h"
diff --git a/Framework/DataHandling/test/SaveNXSPETest.h b/Framework/DataHandling/test/SaveNXSPETest.h
index b7c210feae14bae75dd92dec1bdfcb64e4c4b07f..dd9667c75969ac19ef0a6ec119ccf893395d8185 100644
--- a/Framework/DataHandling/test/SaveNXSPETest.h
+++ b/Framework/DataHandling/test/SaveNXSPETest.h
@@ -6,6 +6,7 @@
 #include "MantidDataHandling/SaveNXSPE.h"
 #include "MantidKernel/UnitFactory.h"
 #include "MantidTestHelpers/WorkspaceCreationHelper.h"
+#include "MantidAPI/DetectorInfo.h"
 #include "MantidAPI/NumericAxis.h"
 #include "MantidAPI/FrameworkManager.h"
 #include "MantidDataHandling/LoadInstrument.h"
@@ -28,7 +29,7 @@ using Mantid::Geometry::ParameterMap;
 using Mantid::Geometry::Instrument;
 using Mantid::Geometry::IDetector_const_sptr;
 
-static const int THEMASKED = 2;
+static const int THEMASKED = 1;
 
 class SaveNXSPETest : public CxxTest::TestSuite {
 public:
@@ -129,7 +130,7 @@ public:
 private:
   MatrixWorkspace_sptr makeWorkspace(int nhist = 3, int nx = 10) {
     auto testWS =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(nhist, nx, 1.0);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(nhist, nx, 1.0);
     // Fill workspace with increasing counter to properly check saving
     for (int i = 0; i < nhist; ++i) {
       auto &outY = testWS->dataY(i);
@@ -152,19 +153,8 @@ private:
             dummy, dummy, dummy);
     inputWS->setInstrument(testInst);
 
-    // Associate detectors with the workspace
-    for (size_t j = 0; j < inputWS->getNumberHistograms(); ++j) {
-      // Just set the spectrum number to match the index
-      inputWS->getSpectrum(j)
-          .setSpectrumNo(static_cast<Mantid::specnum_t>(j + 1));
-    }
-
     // mask the detector
-    ParameterMap *m_Pmap = &(inputWS->instrumentParameters());
-    boost::shared_ptr<const Instrument> instru = inputWS->getInstrument();
-    IDetector_const_sptr toMask = instru->getDetector(THEMASKED);
-    TS_ASSERT(toMask);
-    m_Pmap->addBool(toMask.get(), "masked", true);
+    inputWS->mutableDetectorInfo().setMasked(THEMASKED, true);
 
     // required to get it passed the algorthms validator
     inputWS->setDistribution(true);
diff --git a/Framework/DataHandling/test/SaveNXTomoTest.h b/Framework/DataHandling/test/SaveNXTomoTest.h
index 94af06a174b99dfd9ce4f22eafcdaebfb003c1ce..d96d7e9fb574bac44415438707918c6eb3b59837 100644
--- a/Framework/DataHandling/test/SaveNXTomoTest.h
+++ b/Framework/DataHandling/test/SaveNXTomoTest.h
@@ -5,6 +5,7 @@
 
 #include "MantidDataHandling/SaveNXTomo.h"
 #include "MantidAPI/FrameworkManager.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidTestHelpers/WorkspaceCreationHelper.h"
 #include <Poco/File.h>
 
@@ -82,7 +83,7 @@ public:
     AnalysisDataService::Instance().add(m_inputWS + "0", input);
 
     TS_ASSERT_THROWS_NOTHING(
-        m_saver->setPropertyValue("InputWorkspaces", input->name()));
+        m_saver->setPropertyValue("InputWorkspaces", input->getName()));
     TS_ASSERT_THROWS_NOTHING(
         m_saver->setPropertyValue("Filename", m_outputFile));
     m_outputFile = m_saver->getPropertyValue("Filename"); // get absolute path
@@ -101,7 +102,7 @@ public:
     checksOnNXTomoFormat(3);
 
     // Tidy up
-    AnalysisDataService::Instance().remove(input->name());
+    AnalysisDataService::Instance().remove(input->getName());
     if (file.exists())
       file.remove();
   }
@@ -116,7 +117,7 @@ public:
     AnalysisDataService::Instance().add(wsgName + "0", input);
 
     TS_ASSERT_THROWS_NOTHING(
-        m_saver->setPropertyValue("InputWorkspaces", input->name()));
+        m_saver->setPropertyValue("InputWorkspaces", input->getName()));
     TS_ASSERT_THROWS_NOTHING(
         m_saver->setPropertyValue("Filename", m_outputFile));
     m_outputFile = m_saver->getPropertyValue("Filename"); // get absolute path
@@ -135,7 +136,7 @@ public:
     checksOnNXTomoFormat(2);
 
     // Tidy up
-    AnalysisDataService::Instance().remove(input->name());
+    AnalysisDataService::Instance().remove(input->getName());
     if (file.exists())
       file.remove();
   }
@@ -159,7 +160,7 @@ public:
           m_inputWS + boost::lexical_cast<std::string>(numberOfPriorWS), input);
 
       TS_ASSERT_THROWS_NOTHING(
-          m_saver->setPropertyValue("InputWorkspaces", input->name()));
+          m_saver->setPropertyValue("InputWorkspaces", input->getName()));
       TS_ASSERT_THROWS_NOTHING(
           m_saver->setPropertyValue("Filename", m_outputFile));
       m_outputFile = m_saver->getPropertyValue("Filename"); // get absolute path
@@ -178,7 +179,7 @@ public:
       checksOnNXTomoFormat(static_cast<int>(wspaces.size()) + numberOfPriorWS);
 
       // Tidy up
-      AnalysisDataService::Instance().remove(input->name());
+      AnalysisDataService::Instance().remove(input->getName());
       file.remove();
     }
   }
@@ -186,7 +187,7 @@ public:
 private:
   Workspace_sptr makeWorkspaceSingle(const std::string &input) {
     // Create a single workspace
-    Workspace2D_sptr ws = WorkspaceCreationHelper::Create2DWorkspaceBinned(
+    Workspace2D_sptr ws = WorkspaceCreationHelper::create2DWorkspaceBinned(
         m_axisSize * m_axisSize, 1, 1.0);
     ws->setTitle(input);
 
@@ -227,11 +228,11 @@ private:
 
     for (uint32_t i = 0; i < static_cast<uint32_t>(wspaces.size()); ++i) {
       if (specPerRow) {
-        wspaces[i] = WorkspaceCreationHelper::Create2DWorkspaceBinned(
+        wspaces[i] = WorkspaceCreationHelper::create2DWorkspaceBinned(
             m_axisSize, m_axisSize + 1, 1.0);
 
       } else {
-        wspaces[i] = WorkspaceCreationHelper::Create2DWorkspaceBinned(
+        wspaces[i] = WorkspaceCreationHelper::create2DWorkspaceBinned(
             m_axisSize * m_axisSize, 1, 1.0);
       }
       wspaces[i]->setTitle(
diff --git a/Framework/DataHandling/test/SaveNXcanSASTest.h b/Framework/DataHandling/test/SaveNXcanSASTest.h
index b1b8efb46f91e27f83b5cc460d7926727b621357..9e9246d6a5761cbb33a9c6fb20ffbfeb74dff750 100644
--- a/Framework/DataHandling/test/SaveNXcanSASTest.h
+++ b/Framework/DataHandling/test/SaveNXcanSASTest.h
@@ -39,7 +39,7 @@ public:
 
   void test_that_workspace_without_momentum_transfer_units_is_invalid() {
     // Arrange
-    auto ws = WorkspaceCreationHelper::Create1DWorkspaceConstantWithXerror(
+    auto ws = WorkspaceCreationHelper::create1DWorkspaceConstantWithXerror(
         10 /*size*/, 1.23 /*value&*/, 2.3 /*error*/, 23.4 /*xerror*/);
     const std::string filename = "SaveNXcanSASTestFile.h5";
 
diff --git a/Framework/DataHandling/test/SaveNexusProcessedTest.h b/Framework/DataHandling/test/SaveNexusProcessedTest.h
index e867c82d43cfd13eac97faf15c7d6d1f13893310..b0e10668043967bfd39505e199f020ee09d7955d 100644
--- a/Framework/DataHandling/test/SaveNexusProcessedTest.h
+++ b/Framework/DataHandling/test/SaveNexusProcessedTest.h
@@ -7,17 +7,21 @@
 #include "MantidDataObjects/WorkspaceSingleValue.h"
 #include "MantidDataHandling/LoadInstrument.h"
 #include "MantidAPI/Axis.h"
+#include "MantidAPI/DetectorInfo.h"
 #include "MantidAPI/FrameworkManager.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidAPI/TableRow.h"
 #include "MantidAPI/ScopedWorkspace.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidDataObjects/Workspace2D.h"
 #include "MantidDataObjects/TableWorkspace.h"
-#include "MantidDataHandling/LoadEventPreNexus.h"
 #include "MantidAPI/AnalysisDataService.h"
 #include "MantidDataHandling/SaveNexusProcessed.h"
+#include "MantidDataHandling/LoadEmptyInstrument.h"
 #include "MantidDataHandling/LoadMuonNexus.h"
 #include "MantidDataHandling/LoadNexus.h"
+#include "MantidKernel/Strings.h"
+#include "MantidKernel/Unit.h"
 #include "MantidKernel/UnitFactory.h"
 #include "MantidDataHandling/LoadRaw3.h"
 #include "MantidTestHelpers/WorkspaceCreationHelper.h"
@@ -246,7 +250,7 @@ public:
     groups[4].push_back(50);
 
     EventWorkspace_sptr WS =
-        WorkspaceCreationHelper::CreateGroupedEventWorkspace(groups, 100, 1.0,
+        WorkspaceCreationHelper::createGroupedEventWorkspace(groups, 100, 1.0,
                                                              1.0);
     WS->getSpectrum(3).clear(false);
     // Switch the event type
@@ -399,7 +403,7 @@ public:
     const int nBins = 1;
     const std::string stem = "test_group_ws";
     Mantid::API::WorkspaceGroup_sptr group_ws =
-        WorkspaceCreationHelper::CreateWorkspaceGroup(nEntries, nHist, nBins,
+        WorkspaceCreationHelper::createWorkspaceGroup(nEntries, nHist, nBins,
                                                       stem);
 
     SaveNexusProcessed alg;
@@ -732,6 +736,126 @@ public:
     AnalysisDataService::Instance().clear();
   }
 
+  void testSaveTableEmptyColumn() {
+    std::string outputFileName = "SaveNexusProcessedTest_testSaveTable.nxs";
+
+    // Create a table which we will save
+    auto table =
+        boost::dynamic_pointer_cast<Mantid::DataObjects::TableWorkspace>(
+            WorkspaceFactory::Instance().createTable());
+    table->setRowCount(3);
+    table->addColumn("int", "IntColumn");
+    {
+      auto &data = table->getColVector<int>("IntColumn");
+      data[0] = 5;
+      data[1] = 2;
+      data[2] = 3;
+    }
+    table->addColumn("str", "EmptyColumn");
+
+    SaveNexusProcessed alg;
+    alg.initialize();
+    alg.setProperty("InputWorkspace", table);
+    alg.setPropertyValue("Filename", outputFileName);
+
+    TS_ASSERT_THROWS_NOTHING(alg.execute());
+    TS_ASSERT(alg.isExecuted());
+
+    if (!alg.isExecuted())
+      return; // Nothing to check
+
+    // Get full output file path
+    outputFileName = alg.getPropertyValue("Filename");
+
+    NeXus::File savedNexus(outputFileName);
+
+    savedNexus.openGroup("mantid_workspace_1", "NXentry");
+    savedNexus.openGroup("table_workspace", "NXdata");
+
+    {
+      savedNexus.openData("column_1");
+      doTestColumnInfo(savedNexus, NX_INT32, "", "IntColumn");
+      int32_t expectedData[] = {5, 2, 3};
+      doTestColumnData("IntColumn", savedNexus, expectedData);
+    }
+
+    {
+      savedNexus.openData("column_2");
+
+      NeXus::Info columnInfo = savedNexus.getInfo();
+      TS_ASSERT_EQUALS(columnInfo.dims.size(), 2);
+      TS_ASSERT_EQUALS(columnInfo.dims[0], 3);
+      TS_ASSERT_EQUALS(columnInfo.dims[1], 1);
+      TS_ASSERT_EQUALS(columnInfo.type, NX_CHAR);
+
+      std::vector<NeXus::AttrInfo> attrInfos = savedNexus.getAttrInfos();
+      TS_ASSERT_EQUALS(attrInfos.size(), 3);
+
+      if (attrInfos.size() == 3) {
+        TS_ASSERT_EQUALS(attrInfos[1].name, "interpret_as");
+        TS_ASSERT_EQUALS(savedNexus.getStrAttr(attrInfos[1]), "A string");
+
+        TS_ASSERT_EQUALS(attrInfos[2].name, "name");
+        TS_ASSERT_EQUALS(savedNexus.getStrAttr(attrInfos[2]), "EmptyColumn");
+
+        TS_ASSERT_EQUALS(attrInfos[0].name, "units");
+        TS_ASSERT_EQUALS(savedNexus.getStrAttr(attrInfos[0]), "N/A");
+      }
+
+      std::vector<char> data;
+      savedNexus.getData(data);
+      TS_ASSERT_EQUALS(data.size(), 3);
+      TS_ASSERT_EQUALS(data[0], ' ');
+      TS_ASSERT_EQUALS(data[1], ' ');
+      TS_ASSERT_EQUALS(data[2], ' ');
+    }
+
+    savedNexus.close();
+    Poco::File(outputFileName).remove();
+    AnalysisDataService::Instance().clear();
+  }
+
+  void test_masking() {
+    LoadEmptyInstrument createWorkspace;
+    createWorkspace.initialize();
+    createWorkspace.setPropertyValue(
+        "Filename", "IDFs_for_UNIT_TESTING/IDF_for_UNIT_TESTING.xml");
+    createWorkspace.setPropertyValue("OutputWorkspace", "testSpace");
+    createWorkspace.execute();
+    auto ws = boost::dynamic_pointer_cast<Workspace2D>(
+        AnalysisDataService::Instance().retrieve("testSpace"));
+    ws->mutableDetectorInfo().setMasked(1, true);
+    TS_ASSERT_EQUALS(ws->detectorInfo().isMasked(0), false);
+    TS_ASSERT_EQUALS(ws->detectorInfo().isMasked(1), true);
+    TS_ASSERT_EQUALS(ws->detectorInfo().isMasked(2), false);
+
+    SaveNexusProcessed saveAlg;
+    saveAlg.initialize();
+    saveAlg.setPropertyValue("InputWorkspace", "testSpace");
+    std::string file = "SaveNexusProcessedTest_test_masking.nxs";
+    if (Poco::File(file).exists())
+      Poco::File(file).remove();
+    TS_ASSERT_THROWS_NOTHING(saveAlg.setPropertyValue("Filename", file));
+    TS_ASSERT_THROWS_NOTHING(saveAlg.execute());
+    TS_ASSERT(saveAlg.isExecuted());
+
+    LoadNexus loadAlg;
+    loadAlg.initialize();
+    loadAlg.setPropertyValue("Filename", file);
+    loadAlg.setPropertyValue("OutputWorkspace", "testSpaceReloaded");
+    TS_ASSERT_THROWS_NOTHING(loadAlg.execute());
+    TS_ASSERT(loadAlg.isExecuted());
+    auto wsReloaded = boost::dynamic_pointer_cast<Workspace2D>(
+        AnalysisDataService::Instance().retrieve("testSpaceReloaded"));
+    TS_ASSERT_EQUALS(wsReloaded->detectorInfo().isMasked(0), false);
+    TS_ASSERT_EQUALS(wsReloaded->detectorInfo().isMasked(1), true);
+    TS_ASSERT_EQUALS(wsReloaded->detectorInfo().isMasked(2), false);
+
+    if (clearfiles)
+      Poco::File(file).remove();
+    AnalysisDataService::Instance().remove("testSpace");
+  }
+
 private:
   void doTestColumnInfo(NeXus::File &file, int type,
                         const std::string &interpret_as,
diff --git a/Framework/DataHandling/test/SaveNexusTest.h b/Framework/DataHandling/test/SaveNexusTest.h
index 9ad2e790b21a055d9682bfb5c32b510b49418565..fd6b682e6ecc95c5556b335f4448e4963a86a8fa 100644
--- a/Framework/DataHandling/test/SaveNexusTest.h
+++ b/Framework/DataHandling/test/SaveNexusTest.h
@@ -90,7 +90,7 @@ public:
   }
 
   void test_pass_inputworkspace_as_pointer() {
-    Workspace_sptr ws = WorkspaceCreationHelper::Create2DWorkspace123(2, 5);
+    Workspace_sptr ws = WorkspaceCreationHelper::create2DWorkspace123(2, 5);
 
     SaveNexus alg;
     alg.initialize();
diff --git a/Framework/DataHandling/test/SavePARTest.h b/Framework/DataHandling/test/SavePARTest.h
index 1c65124f0847bc059b7106666083647e6a57ada1..174c1f0adbb02cade72921d29289cc33896dde62 100644
--- a/Framework/DataHandling/test/SavePARTest.h
+++ b/Framework/DataHandling/test/SavePARTest.h
@@ -140,7 +140,7 @@ private:
     // all the Y values in this new workspace are set to DEFAU_Y, which
     // currently = 2
     MatrixWorkspace_sptr inputWS =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(NHIST, 10, 1.0);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(NHIST, 10, 1.0);
     return setUpWorkspace(input, inputWS);
   }
 
@@ -149,11 +149,6 @@ private:
     inputWS->getAxis(0)->unit() =
         Mantid::Kernel::UnitFactory::Instance().create("DeltaE");
 
-    // the following is largely about associating detectors with the workspace
-    for (int j = 0; j < NHIST; ++j) {
-      // Just set the spectrum number to match the index
-      inputWS->getSpectrum(j).setSpectrumNo(j + 1);
-    }
     // we do not need to deal with analysisi data service here in test to avoid
     // holding the workspace there after the test
     AnalysisDataService::Instance().add(input, inputWS);
@@ -168,13 +163,6 @@ private:
     loader.setPropertyValue("Workspace", input);
     loader.execute();
 
-    // mask the detector
-    Geometry::ParameterMap *m_Pmap = &(inputWS->instrumentParameters());
-    boost::shared_ptr<const Instrument> instru = inputWS->getInstrument();
-    Geometry::IDetector_const_sptr toMask = instru->getDetector(THEMASKED);
-    TS_ASSERT(toMask);
-    m_Pmap->addBool(toMask.get(), "masked", true);
-
     // required to get it passed the algorthms validator
     inputWS->setDistribution(true);
 
diff --git a/Framework/DataHandling/test/SavePDFGuiTest.h b/Framework/DataHandling/test/SavePDFGuiTest.h
index 5df40229c4d6f376811fd68b9900c8d0d7189283..ac70b524ca84af8acbe3b43dd67021b74798f274 100644
--- a/Framework/DataHandling/test/SavePDFGuiTest.h
+++ b/Framework/DataHandling/test/SavePDFGuiTest.h
@@ -6,6 +6,7 @@
 #include <fstream>
 
 #include "MantidAPI/AlgorithmManager.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidDataHandling/SavePDFGui.h"
 #include "MantidDataHandling/LoadNexusProcessed.h"
 
diff --git a/Framework/DataHandling/test/SavePHXTest.h b/Framework/DataHandling/test/SavePHXTest.h
index da03b4940dc00b656f2b917f7f838fd6aea35e3f..22975866981084d1a550e27a12f2d9c295839d4b 100644
--- a/Framework/DataHandling/test/SavePHXTest.h
+++ b/Framework/DataHandling/test/SavePHXTest.h
@@ -170,7 +170,7 @@ private:
     // all the Y values in this new workspace are set to DEFAU_Y, which
     // currently = 2
     MatrixWorkspace_sptr inputWS =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(NHIST, 10, 1.0);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(NHIST, 10, 1.0);
     return setUpWorkspace(input, inputWS);
   }
 
@@ -179,11 +179,6 @@ private:
     inputWS->getAxis(0)->unit() =
         Mantid::Kernel::UnitFactory::Instance().create("DeltaE");
 
-    // the following is largely about associating detectors with the workspace
-    for (int j = 0; j < NHIST; ++j) {
-      // Just set the spectrum number to match the index
-      inputWS->getSpectrum(j).setSpectrumNo(j + 1);
-    }
     // we do not need to deal with analysisi data service here in test to avoid
     // holding the workspace there after the test
     AnalysisDataService::Instance().add(input, inputWS);
@@ -198,13 +193,6 @@ private:
     loader.setProperty("RewriteSpectraMap", Mantid::Kernel::OptionalBool(true));
     loader.execute();
 
-    // mask the detector
-    Geometry::ParameterMap *m_Pmap = &(inputWS->instrumentParameters());
-    boost::shared_ptr<const Instrument> instru = inputWS->getInstrument();
-    Geometry::IDetector_const_sptr toMask = instru->getDetector(THEMASKED);
-    TS_ASSERT(toMask)
-    m_Pmap->addBool(toMask.get(), "masked", true);
-
     // required to get it passed the algorthms validator
     inputWS->setDistribution(true);
 
diff --git a/Framework/DataHandling/test/SaveParameterFileTest.h b/Framework/DataHandling/test/SaveParameterFileTest.h
index 6ce13bf6c081ad934ac9aed300182df64b8719b7..99788e79d8f343f22d24778a29ec640a8bc1f48d 100644
--- a/Framework/DataHandling/test/SaveParameterFileTest.h
+++ b/Framework/DataHandling/test/SaveParameterFileTest.h
@@ -15,7 +15,9 @@
 #include "MantidGeometry/IDetector.h"
 #include "MantidGeometry/Instrument.h"
 #include "MantidGeometry/Instrument/Component.h"
+#include "MantidGeometry/Instrument/ParameterFactory.h"
 #include "MantidKernel/Exception.h"
+#include "MantidKernel/StringTokenizer.h"
 #include "MantidTestHelpers/ScopedFileHelper.h"
 
 using namespace Mantid::API;
@@ -148,7 +150,7 @@ public:
     LoadParameterFile loaderPF;
     TS_ASSERT_THROWS_NOTHING(loaderPF.initialize());
     loaderPF.setPropertyValue("Filename", filename);
-    loaderPF.setPropertyValue("Workspace", m_ws->name());
+    loaderPF.setPropertyValue("Workspace", m_ws->getName());
     TS_ASSERT_THROWS_NOTHING(loaderPF.execute());
     TS_ASSERT(loaderPF.isExecuted());
   }
@@ -157,7 +159,7 @@ public:
     SaveParameterFile saverPF;
     TS_ASSERT_THROWS_NOTHING(saverPF.initialize());
     saverPF.setPropertyValue("Filename", filename);
-    saverPF.setPropertyValue("Workspace", m_ws->name());
+    saverPF.setPropertyValue("Workspace", m_ws->getName());
     TS_ASSERT_THROWS_NOTHING(saverPF.execute());
     TS_ASSERT(saverPF.isExecuted());
   }
diff --git a/Framework/DataHandling/test/SaveRKHTest.h b/Framework/DataHandling/test/SaveRKHTest.h
index 75f1e0a56efc76ff1cd31d5eab15fafb4221c2b6..6f4997268a0f54758ba8ba96197b8e264d1242bc 100644
--- a/Framework/DataHandling/test/SaveRKHTest.h
+++ b/Framework/DataHandling/test/SaveRKHTest.h
@@ -45,7 +45,7 @@ public:
     TS_ASSERT_THROWS(testAlgorithm1.execute(), std::runtime_error);
     // Need a test workspace to use as input
     MatrixWorkspace_sptr inputWS1 =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(1, 10, 1.0);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(1, 10, 1.0);
     inputWS1->setDistribution(true);
 
     // Register workspace
@@ -114,7 +114,7 @@ public:
 
     using namespace Mantid::API;
     MatrixWorkspace_sptr inputWS2 =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(10, 1, 0.0);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(10, 1, 0.0);
     inputWS2->setDistribution(true);
     // Register workspace
     AnalysisDataService::Instance().add("testInputTwo", inputWS2);
diff --git a/Framework/DataHandling/test/SaveReflCustomAsciiTest.h b/Framework/DataHandling/test/SaveReflCustomAsciiTest.h
index 962a10ae5b288b567ec620c625930678e9f1961b..5a8f7f49642c935c75ebba87b1388b0b9e44a165 100644
--- a/Framework/DataHandling/test/SaveReflCustomAsciiTest.h
+++ b/Framework/DataHandling/test/SaveReflCustomAsciiTest.h
@@ -62,7 +62,7 @@ public:
     boost::split(columns, fullline, boost::is_any_of("\t"),
                  boost::token_compress_on);
     TS_ASSERT_EQUALS(columns.size(), 4);
-    // the first is black due to the leading tab
+    // the first is black due to the leading separator
     TS_ASSERT(columns.at(0) == "");
     TS_ASSERT_DELTA(boost::lexical_cast<double>(columns.at(1)), 2.5, 0.01);
     TS_ASSERT_DELTA(boost::lexical_cast<double>(columns.at(2)), 2, 0.01);
@@ -95,7 +95,7 @@ public:
     boost::split(columns, fullline, boost::is_any_of("\t"),
                  boost::token_compress_on);
     TS_ASSERT_EQUALS(columns.size(), 4);
-    // the first is black due to the leading tab
+    // the first is black due to the leading separator
     TS_ASSERT(columns.at(0) == "");
     TS_ASSERT_DELTA(boost::lexical_cast<double>(columns.at(1)), 0, 0.01);
     TS_ASSERT_DELTA(boost::lexical_cast<double>(columns.at(2)), 2, 0.01);
@@ -128,7 +128,7 @@ public:
     boost::split(columns, fullline, boost::is_any_of("\t"),
                  boost::token_compress_on);
     TS_ASSERT_EQUALS(columns.size(), 4);
-    // the first is black due to the leading tab
+    // the first is black due to the leading separator
     TS_ASSERT(columns.at(0) == "");
     TS_ASSERT_DELTA(boost::lexical_cast<double>(columns.at(1)), 2.5, 0.01);
     TS_ASSERT_DELTA(boost::lexical_cast<double>(columns.at(2)), 0, 0.01);
@@ -161,7 +161,7 @@ public:
     boost::split(columns, fullline, boost::is_any_of("\t"),
                  boost::token_compress_on);
     TS_ASSERT_EQUALS(columns.size(), 4);
-    // the first is black due to the leading tab
+    // the first is black due to the leading separator
     TS_ASSERT(columns.at(0) == "");
     TS_ASSERT_DELTA(boost::lexical_cast<double>(columns.at(1)), 2.5, 0.01);
     TS_ASSERT_DELTA(boost::lexical_cast<double>(columns.at(2)), 2, 0.01);
@@ -179,6 +179,7 @@ public:
     alg->setPropertyValue("InputWorkspace", m_name);
     alg->setPropertyValue("Filename", m_filename);
     alg->setPropertyValue("Title", "Testing this algorithm");
+    alg->setPropertyValue("Separator", "comma");
     TS_ASSERT_THROWS_NOTHING(alg->execute());
 
     if (!alg->isExecuted()) {
@@ -193,10 +194,10 @@ public:
     getline(in, fullline);
 
     std::vector<std::string> columns;
-    boost::split(columns, fullline, boost::is_any_of("\t"),
+    boost::split(columns, fullline, boost::is_any_of(","),
                  boost::token_compress_on);
     TS_ASSERT_EQUALS(columns.size(), 4);
-    // the first is black due to the leading tab
+    // the first is black due to the leading separator
     TS_ASSERT(columns.at(0) == "");
     TS_ASSERT_DELTA(boost::lexical_cast<double>(columns.at(1)), 1.5, 0.01);
     TS_ASSERT_DELTA(boost::lexical_cast<double>(columns.at(2)), 1, 0.01);
@@ -232,7 +233,7 @@ private:
   void createWS(bool zeroX = false, bool zeroY = false, bool zeroE = false,
                 bool createLogs = false) {
     createLogs = false;
-    MatrixWorkspace_sptr ws = WorkspaceCreationHelper::Create2DWorkspace(1, 10);
+    MatrixWorkspace_sptr ws = WorkspaceCreationHelper::create2DWorkspace(1, 10);
     AnalysisDataService::Instance().addOrReplace(m_name, ws);
     // Check if any of X, Y or E should be zeroed to check for divide by zero or
     // similiar
diff --git a/Framework/DataHandling/test/SaveReflThreeColumnAsciiTest.h b/Framework/DataHandling/test/SaveReflThreeColumnAsciiTest.h
index 68948a9675b1a080ea94d06cd3e179bff3cfd908..b9c1e96e8b61d6c584f36da396e642c58620cc5b 100644
--- a/Framework/DataHandling/test/SaveReflThreeColumnAsciiTest.h
+++ b/Framework/DataHandling/test/SaveReflThreeColumnAsciiTest.h
@@ -163,7 +163,38 @@ public:
 
     cleanupafterwards();
   }
+  void testParameters() {
+    // create a new workspace and then delete it later on
+    createWS();
+
+    Mantid::API::IAlgorithm_sptr alg =
+        Mantid::API::AlgorithmManager::Instance().create(
+            "SaveReflThreeColumnAscii");
+    alg->setPropertyValue("InputWorkspace", m_name);
+    alg->setPropertyValue("Filename", m_filename);
+    alg->setPropertyValue("Separator", "comma");
+    TS_ASSERT_THROWS_NOTHING(alg->execute());
+
+    if (!alg->isExecuted()) {
+      TS_FAIL("Could not run SaveReflThreeColumnAscii");
+    }
+    m_long_filename = alg->getPropertyValue("Filename");
+    // has the algorithm written a file to disk?
+    TS_ASSERT(Poco::File(m_long_filename).exists());
+    std::ifstream in(m_long_filename.c_str());
+    std::string fullline;
+    getline(in, fullline);
+    std::vector<std::string> columns;
+    boost::split(columns, fullline, boost::is_any_of(","),
+                 boost::token_compress_on);
+    TS_ASSERT_EQUALS(columns.size(), 4); // first blank
+    TS_ASSERT_DELTA(boost::lexical_cast<double>(columns.at(1)), 1.5, 0.01);
+    TS_ASSERT_DELTA(boost::lexical_cast<double>(columns.at(2)), 1, 0.01);
+    TS_ASSERT_DELTA(boost::lexical_cast<double>(columns.at(3)), 1, 0.01);
+    in.close();
 
+    cleanupafterwards();
+  }
   void test_fail_invalid_workspace() {
     Mantid::API::IAlgorithm_sptr alg =
         Mantid::API::AlgorithmManager::Instance().create(
@@ -182,7 +213,7 @@ public:
 
 private:
   void createWS(bool zeroX = false, bool zeroY = false, bool zeroE = false) {
-    MatrixWorkspace_sptr ws = WorkspaceCreationHelper::Create2DWorkspace(1, 10);
+    MatrixWorkspace_sptr ws = WorkspaceCreationHelper::create2DWorkspace(1, 10);
     AnalysisDataService::Instance().addOrReplace(m_name, ws);
     // Check if any of X, Y or E should be zeroed to check for divide by zero or
     // similiar
diff --git a/Framework/DataHandling/test/SaveSPETest.h b/Framework/DataHandling/test/SaveSPETest.h
index f42344b45a67297e002f0c4acb73c7de6b0628d1..a59e61ae980ee52a050552ce2f7daacf9454c663 100644
--- a/Framework/DataHandling/test/SaveSPETest.h
+++ b/Framework/DataHandling/test/SaveSPETest.h
@@ -5,6 +5,7 @@
 
 #include "MantidDataHandling/SaveSPE.h"
 #include "MantidTestHelpers/WorkspaceCreationHelper.h"
+#include "MantidAPI/DetectorInfo.h"
 #include "MantidAPI/FrameworkManager.h"
 #include "MantidAPI/NumericAxis.h"
 #include "MantidDataHandling/LoadInstrument.h"
@@ -27,7 +28,7 @@ static const double MASK_FLAG =
 static const double MASK_ERROR = 0.0;
 
 static const int NHIST = 3;
-static const int THEMASKED = 2;
+static const int THEMASKED = 1;
 static const int DEFAU_Y = 2;
 
 class SaveSPETest : public CxxTest::TestSuite {
@@ -91,7 +92,7 @@ public:
          ++i) { // if the spectrum number (1+index number) is that of the masked
                 // spectrum look for the mask flag, otherwise value in the
                 // workspace
-      double value = i + 1 != THEMASKED ? DEFAU_Y : MASK_FLAG;
+      double value = i != THEMASKED ? DEFAU_Y : MASK_FLAG;
 
       getline(file, tmp);
       TS_ASSERT_EQUALS(tmp, "### S(Phi,w)")
@@ -102,7 +103,7 @@ public:
       TS_ASSERT_EQUALS(tmp2, value)
       getline(file, tmp);
 
-      double error = i + 1 != THEMASKED ? M_SQRT2 : MASK_ERROR;
+      double error = i != THEMASKED ? M_SQRT2 : MASK_ERROR;
       getline(file, tmp);
       TS_ASSERT_EQUALS(tmp, "### Errors")
       file >> tmp2;
@@ -148,7 +149,7 @@ private:
     // all the Y values in this new workspace are set to DEFAU_Y, which
     // currently = 2
     MatrixWorkspace_sptr inputWS =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(NHIST, 10, 1.0);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(NHIST, 10, 1.0);
     return setUpWorkspace(input, inputWS);
   }
 
@@ -156,7 +157,7 @@ private:
     // all the Y values in this new workspace are set to DEFAU_Y, which
     // currently = 2
     MatrixWorkspace_sptr inputWS =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(NHIST, 10, 1.0);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(NHIST, 10, 1.0);
     inputWS = setUpWorkspace(input, inputWS);
     API::Axis *axisOne = inputWS->getAxis(1);
     API::NumericAxis *newAxisOne = new NumericAxis(axisOne->length());
@@ -187,11 +188,7 @@ private:
     loader.execute();
 
     // mask the detector
-    Geometry::ParameterMap *m_Pmap = &(inputWS->instrumentParameters());
-    boost::shared_ptr<const Instrument> instru = inputWS->getInstrument();
-    Geometry::IDetector_const_sptr toMask = instru->getDetector(THEMASKED);
-    TS_ASSERT(toMask);
-    m_Pmap->addBool(toMask.get(), "masked", true);
+    inputWS->mutableDetectorInfo().setMasked(THEMASKED, true);
 
     // required to get it passed the algorthms validator
     inputWS->setDistribution(true);
diff --git a/Framework/DataHandling/test/SaveTBLTest.h b/Framework/DataHandling/test/SaveTBLTest.h
index 7ad8c2c2bb693939159e9a8d2825b33631d647da..16b68d03ced4e7f155fd61e854c46b6fbf57d70f 100644
--- a/Framework/DataHandling/test/SaveTBLTest.h
+++ b/Framework/DataHandling/test/SaveTBLTest.h
@@ -2,6 +2,7 @@
 #define SAVETBLTEST_H_
 
 #include "MantidAPI/AlgorithmManager.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/FrameworkManager.h"
 #include "MantidAPI/ITableWorkspace.h"
 #include "MantidAPI/TableRow.h"
diff --git a/Framework/DataHandling/test/SetBeamTest.h b/Framework/DataHandling/test/SetBeamTest.h
index a0261731dcf253ba80028c0863522260a16a2b78..f52cba707891a0c3f685c40669cbf5750ae4c14e 100644
--- a/Framework/DataHandling/test/SetBeamTest.h
+++ b/Framework/DataHandling/test/SetBeamTest.h
@@ -27,7 +27,7 @@ public:
   }
 
   void test_Beam_Size_Parameters_Stored_On_Instrument_Source() {
-    auto inputWS = WorkspaceCreationHelper::Create2DWorkspaceBinned(1, 1);
+    auto inputWS = WorkspaceCreationHelper::create2DWorkspaceBinned(1, 1);
     auto testInst = ComponentCreationHelper::createTestInstrumentCylindrical(1);
     inputWS->setInstrument(testInst);
 
@@ -52,7 +52,7 @@ public:
   // Failure tests
   //----------------------------------------------------------------------------
   void test_Workspace_Without_Instrument_Not_Accepted() {
-    auto inputWS = WorkspaceCreationHelper::Create2DWorkspaceBinned(1, 1);
+    auto inputWS = WorkspaceCreationHelper::create2DWorkspaceBinned(1, 1);
 
     auto alg = createAlgorithm();
     TS_ASSERT_THROWS(alg->setProperty("InputWorkspace", inputWS),
@@ -60,7 +60,7 @@ public:
   }
 
   void test_No_Geometry_Inputs_Not_Accepted() {
-    auto inputWS = WorkspaceCreationHelper::Create2DWorkspaceBinned(1, 1);
+    auto inputWS = WorkspaceCreationHelper::create2DWorkspaceBinned(1, 1);
     auto testInst = ComponentCreationHelper::createTestInstrumentCylindrical(1);
     inputWS->setInstrument(testInst);
 
@@ -71,7 +71,7 @@ public:
 
   void test_Missing_Geometry_Inputs_Not_Accepted() {
     using Mantid::Kernel::PropertyManager;
-    auto inputWS = WorkspaceCreationHelper::Create2DWorkspaceBinned(1, 1);
+    auto inputWS = WorkspaceCreationHelper::create2DWorkspaceBinned(1, 1);
     auto testInst = ComponentCreationHelper::createTestInstrumentCylindrical(1);
     inputWS->setInstrument(testInst);
 
diff --git a/Framework/DataHandling/test/SetSampleTest.h b/Framework/DataHandling/test/SetSampleTest.h
index 30f03645579a3341be047486279eec0c1a1d0382..d15ae0e33896641ab5a1aa6ddc6471cd0ce3b7ea 100644
--- a/Framework/DataHandling/test/SetSampleTest.h
+++ b/Framework/DataHandling/test/SetSampleTest.h
@@ -4,6 +4,7 @@
 #include <cxxtest/TestSuite.h>
 
 #include "MantidDataHandling/SetSample.h"
+#include "MantidGeometry/Instrument/ReferenceFrame.h"
 #include "MantidGeometry/Instrument/SampleEnvironment.h"
 #include "MantidGeometry/Objects/Object.h"
 #include "MantidGeometry/Objects/Rules.h"
@@ -86,13 +87,12 @@ public:
   }
 
   void test_Setting_Material_Alone_Only_Overwrites_Material() {
-    auto inputWS = WorkspaceCreationHelper::Create2DWorkspaceBinned(1, 1);
+    auto inputWS = WorkspaceCreationHelper::create2DWorkspaceBinned(1, 1);
     auto sampleShape = ComponentCreationHelper::createSphere(0.5);
     sampleShape->setID("mysample");
     inputWS->mutableSample().setShape(*sampleShape);
 
-    auto alg = createAlgorithm();
-    alg->setProperty("InputWorkspace", inputWS);
+    auto alg = createAlgorithm(inputWS);
     alg->setProperty("Material", createMaterialProps());
     TS_ASSERT_THROWS_NOTHING(alg->execute());
     TS_ASSERT(alg->isExecuted());
@@ -108,15 +108,14 @@ public:
     using Mantid::Kernel::Material;
     using Mantid::PhysicalConstants::getNeutronAtom;
 
-    auto inputWS = WorkspaceCreationHelper::Create2DWorkspaceBinned(1, 1);
+    auto inputWS = WorkspaceCreationHelper::create2DWorkspaceBinned(1, 1);
     auto sampleShape = ComponentCreationHelper::createSphere(0.5);
     sampleShape->setID("mysample");
     Material alum("Al", getNeutronAtom(13), 2.6989);
     sampleShape->setMaterial(alum);
     inputWS->mutableSample().setShape(*sampleShape);
 
-    auto alg = createAlgorithm();
-    alg->setProperty("InputWorkspace", inputWS);
+    auto alg = createAlgorithm(inputWS);
     alg->setProperty("Geometry", createGenericGeometryProps());
     TS_ASSERT_THROWS_NOTHING(alg->execute());
     TS_ASSERT(alg->isExecuted());
@@ -133,7 +132,7 @@ public:
     using Mantid::Kernel::ConfigService;
     using Mantid::Geometry::SampleEnvironment;
 
-    auto inputWS = WorkspaceCreationHelper::Create2DWorkspaceBinned(1, 1);
+    auto inputWS = WorkspaceCreationHelper::create2DWorkspaceBinned(1, 1);
     auto testInst = ComponentCreationHelper::createTestInstrumentCylindrical(1);
     testInst->setName(m_instName);
     inputWS->setInstrument(testInst);
@@ -143,8 +142,7 @@ public:
     auto &config = ConfigService::Instance();
     const auto defaultDirs = config.getString("instrumentDefinition.directory");
     config.setString("instrumentDefinition.directory", m_testRoot);
-    auto alg = createAlgorithm();
-    alg->setProperty("InputWorkspace", inputWS);
+    auto alg = createAlgorithm(inputWS);
     alg->setProperty("Environment", createEnvironmentProps());
     TS_ASSERT_THROWS_NOTHING(alg->execute());
     TS_ASSERT(alg->isExecuted());
@@ -165,7 +163,7 @@ public:
     using Mantid::Kernel::ConfigService;
     using Mantid::Geometry::SampleEnvironment;
 
-    auto inputWS = WorkspaceCreationHelper::Create2DWorkspaceBinned(1, 1);
+    auto inputWS = WorkspaceCreationHelper::create2DWorkspaceBinned(1, 1);
     auto testInst = ComponentCreationHelper::createTestInstrumentCylindrical(1);
     testInst->setName(m_instName);
     inputWS->setInstrument(testInst);
@@ -175,8 +173,7 @@ public:
     auto &config = ConfigService::Instance();
     const auto defaultDirs = config.getString("instrumentDefinition.directory");
     config.setString("instrumentDefinition.directory", m_testRoot);
-    auto alg = createAlgorithm();
-    alg->setProperty("InputWorkspace", inputWS);
+    auto alg = createAlgorithm(inputWS);
     alg->setProperty("Environment", createEnvironmentProps());
     alg->setProperty("Geometry", createOverrideGeometryProps());
     TS_ASSERT_THROWS_NOTHING(alg->execute());
@@ -200,10 +197,10 @@ public:
 
   void test_Setting_Geometry_As_FlatPlate() {
     using Mantid::Kernel::V3D;
-    auto inputWS = WorkspaceCreationHelper::Create2DWorkspaceBinned(1, 1);
+    auto inputWS = WorkspaceCreationHelper::create2DWorkspaceBinned(1, 1);
+    setTestReferenceFrame(inputWS);
 
-    auto alg = createAlgorithm();
-    alg->setProperty("InputWorkspace", inputWS);
+    auto alg = createAlgorithm(inputWS);
     alg->setProperty("Geometry", createFlatPlateGeometryProps());
     TS_ASSERT_THROWS_NOTHING(alg->execute());
     TS_ASSERT(alg->isExecuted());
@@ -214,16 +211,46 @@ public:
     auto tag = sampleShape.getShapeXML().find("cuboid");
     TS_ASSERT(tag != std::string::npos);
 
-    TS_ASSERT_EQUALS(true, sampleShape.isValid(V3D(0, 0, 0.01)));
+    // Center
+    TS_ASSERT_EQUALS(true, sampleShape.isValid(V3D(0.01, 0, 0)));
+    TS_ASSERT_EQUALS(true, sampleShape.isValid(V3D(0.0105, 0.025, 0.02)));
+    // Origin
     TS_ASSERT_EQUALS(false, sampleShape.isValid(V3D(0, 0, 0.0)));
   }
 
+  void test_Setting_Geometry_As_FlatPlate_With_Rotation() {
+    using Mantid::Kernel::V3D;
+    auto inputWS = WorkspaceCreationHelper::create2DWorkspaceBinned(1, 1);
+    setTestReferenceFrame(inputWS);
+
+    auto alg = createAlgorithm(inputWS);
+    const double angle(45.0);
+    alg->setProperty("Geometry", createFlatPlateGeometryProps(angle));
+    TS_ASSERT_THROWS_NOTHING(alg->execute());
+    TS_ASSERT(alg->isExecuted());
+
+    // New shape
+    const auto &sampleShape = inputWS->sample().getShape();
+    TS_ASSERT(sampleShape.hasValidShape());
+    auto tag = sampleShape.getShapeXML().find("cuboid");
+    TS_ASSERT(tag != std::string::npos);
+
+    // Center should be preserved inside the shape
+    TS_ASSERT_EQUALS(true, sampleShape.isValid(V3D(0.01, 0, 0)));
+    // V3D(0.0005, 0.025, 0.02) rotated by 45 degrees CCW and translated
+    // to center
+    TS_ASSERT_EQUALS(true,
+                     sampleShape.isValid(V3D(-0.00732412, 0.01803122, 0.02)));
+    // End of horizontal axis should now not be inside the object
+    TS_ASSERT_EQUALS(false, sampleShape.isValid(V3D(0, 0.025, 0)));
+  }
+
   void test_Setting_Geometry_As_Cylinder() {
     using Mantid::Kernel::V3D;
-    auto inputWS = WorkspaceCreationHelper::Create2DWorkspaceBinned(1, 1);
+    auto inputWS = WorkspaceCreationHelper::create2DWorkspaceBinned(1, 1);
+    setTestReferenceFrame(inputWS);
 
-    auto alg = createAlgorithm();
-    alg->setProperty("InputWorkspace", inputWS);
+    auto alg = createAlgorithm(inputWS);
     alg->setProperty("Geometry", createCylinderGeometryProps());
     TS_ASSERT_THROWS_NOTHING(alg->execute());
     TS_ASSERT(alg->isExecuted());
@@ -234,18 +261,18 @@ public:
     auto tag = sampleShape.getShapeXML().find("cylinder");
     TS_ASSERT(tag != std::string::npos);
 
-    TS_ASSERT_EQUALS(true, sampleShape.isValid(V3D(0, 0.009, 0.015)));
-    TS_ASSERT_EQUALS(true, sampleShape.isValid(V3D(0, -0.009, 0.015)));
-    TS_ASSERT_EQUALS(false, sampleShape.isValid(V3D(0, 0.011, 0.015)));
-    TS_ASSERT_EQUALS(false, sampleShape.isValid(V3D(0, -0.011, 0.015)));
+    TS_ASSERT_EQUALS(true, sampleShape.isValid(V3D(0, 0.049, 0.019)));
+    TS_ASSERT_EQUALS(true, sampleShape.isValid(V3D(0, 0.049, 0.001)));
+    TS_ASSERT_EQUALS(false, sampleShape.isValid(V3D(0, 0.06, 0.021)));
+    TS_ASSERT_EQUALS(false, sampleShape.isValid(V3D(0, 0.06, -0.001)));
   }
 
   void test_Setting_Geometry_As_HollowCylinder() {
     using Mantid::Kernel::V3D;
-    auto inputWS = WorkspaceCreationHelper::Create2DWorkspaceBinned(1, 1);
+    auto inputWS = WorkspaceCreationHelper::create2DWorkspaceBinned(1, 1);
+    setTestReferenceFrame(inputWS);
 
-    auto alg = createAlgorithm();
-    alg->setProperty("InputWorkspace", inputWS);
+    auto alg = createAlgorithm(inputWS);
     alg->setProperty("Geometry", createHollowCylinderGeometryProps());
     TS_ASSERT_THROWS_NOTHING(alg->execute());
     TS_ASSERT(alg->isExecuted());
@@ -253,10 +280,10 @@ public:
     // New shape
     const auto &sampleShape = inputWS->sample().getShape();
     TS_ASSERT(sampleShape.hasValidShape());
-    TS_ASSERT_EQUALS(true, sampleShape.isValid(V3D(0, 0.009, 0.045)));
-    TS_ASSERT_EQUALS(true, sampleShape.isValid(V3D(0, -0.009, 0.045)));
-    TS_ASSERT_EQUALS(false, sampleShape.isValid(V3D(0, 0.011, 0.045)));
-    TS_ASSERT_EQUALS(false, sampleShape.isValid(V3D(0, -0.011, 0.045)));
+    TS_ASSERT_EQUALS(true, sampleShape.isValid(V3D(0, 0.035, 0.019)));
+    TS_ASSERT_EQUALS(true, sampleShape.isValid(V3D(0, 0.035, 0.001)));
+    TS_ASSERT_EQUALS(false, sampleShape.isValid(V3D(0, 0.041, 0.021)));
+    TS_ASSERT_EQUALS(false, sampleShape.isValid(V3D(0, 0.041, -0.001)));
   }
 
   //----------------------------------------------------------------------------
@@ -266,10 +293,9 @@ public:
   void test_Environment_Args_Without_Name_Invalid() {
     using Mantid::Kernel::PropertyManager;
     using StringProperty = Mantid::Kernel::PropertyWithValue<std::string>;
-    auto inputWS = WorkspaceCreationHelper::Create2DWorkspaceBinned(1, 1);
+    auto inputWS = WorkspaceCreationHelper::create2DWorkspaceBinned(1, 1);
 
-    auto alg = createAlgorithm();
-    alg->setProperty("InputWorkspace", inputWS);
+    auto alg = createAlgorithm(inputWS);
 
     auto args = boost::make_shared<PropertyManager>();
     args->declareProperty(
@@ -281,10 +307,9 @@ public:
   void test_Environment_Args_Without_Container_Invalid() {
     using Mantid::Kernel::PropertyManager;
     using StringProperty = Mantid::Kernel::PropertyWithValue<std::string>;
-    auto inputWS = WorkspaceCreationHelper::Create2DWorkspaceBinned(1, 1);
+    auto inputWS = WorkspaceCreationHelper::create2DWorkspaceBinned(1, 1);
 
-    auto alg = createAlgorithm();
-    alg->setProperty("InputWorkspace", inputWS);
+    auto alg = createAlgorithm(inputWS);
 
     auto args = boost::make_shared<PropertyManager>();
     args->declareProperty(
@@ -296,10 +321,9 @@ public:
   void test_Environment_Args_With_Empty_Strings_Invalid() {
     using Mantid::Kernel::PropertyManager;
     using StringProperty = Mantid::Kernel::PropertyWithValue<std::string>;
-    auto inputWS = WorkspaceCreationHelper::Create2DWorkspaceBinned(1, 1);
+    auto inputWS = WorkspaceCreationHelper::create2DWorkspaceBinned(1, 1);
 
-    auto alg = createAlgorithm();
-    alg->setProperty("InputWorkspace", inputWS);
+    auto alg = createAlgorithm(inputWS);
 
     auto args = boost::make_shared<PropertyManager>();
     args->declareProperty(
@@ -313,18 +337,106 @@ public:
     TS_ASSERT_THROWS(alg->execute(), std::runtime_error);
   }
 
+  void test_Negative_FlatPlate_Dimensions_Give_Validation_Errors() {
+    using Mantid::API::IAlgorithm;
+    using Mantid::Kernel::PropertyManager;
+    using DoubleProperty = Mantid::Kernel::PropertyWithValue<double>;
+    using StringProperty = Mantid::Kernel::PropertyWithValue<std::string>;
+
+    auto alg = createAlgorithm();
+    auto args = boost::make_shared<PropertyManager>();
+    args->declareProperty(
+        Mantid::Kernel::make_unique<StringProperty>("Shape", "FlatPlate"), "");
+    std::array<const std::string, 3> dimensions = {
+        {"Width", "Height", "Thick"}};
+    const std::string geometryProp("Geometry");
+    for (const auto &dim : dimensions) {
+      args->declareProperty(
+          Mantid::Kernel::make_unique<DoubleProperty>(dim, -1.0), "");
+      alg->setProperty(geometryProp, args);
+      TS_ASSERT(validateErrorProduced(*alg, geometryProp));
+      args->removeProperty(dim);
+    }
+  }
+
+  void test_Negative_Cylinder_Dimensions_Give_Validation_Errors() {
+    using Mantid::Kernel::PropertyManager;
+    using DoubleProperty = Mantid::Kernel::PropertyWithValue<double>;
+    using StringProperty = Mantid::Kernel::PropertyWithValue<std::string>;
+
+    auto alg = createAlgorithm();
+    auto args = boost::make_shared<PropertyManager>();
+    args->declareProperty(
+        Mantid::Kernel::make_unique<StringProperty>("Shape", "Cylinder"), "");
+    std::array<const std::string, 2> dimensions = {{"Radius", "Height"}};
+    const std::string geometryProp("Geometry");
+    for (const auto &dim : dimensions) {
+      args->declareProperty(
+          Mantid::Kernel::make_unique<DoubleProperty>(dim, -1.0), "");
+      alg->setProperty(geometryProp, args);
+      TS_ASSERT(validateErrorProduced(*alg, geometryProp));
+      args->removeProperty(dim);
+    }
+  }
+
+  void test_Negative_HollowCylinder_Dimensions_Give_Validation_Errors() {
+    using Mantid::API::IAlgorithm;
+    using Mantid::Kernel::PropertyManager;
+    using DoubleProperty = Mantid::Kernel::PropertyWithValue<double>;
+    using StringProperty = Mantid::Kernel::PropertyWithValue<std::string>;
+
+    auto alg = createAlgorithm();
+    auto args = boost::make_shared<PropertyManager>();
+    args->declareProperty(
+        Mantid::Kernel::make_unique<StringProperty>("Shape", "FlatPlate"), "");
+    std::array<const std::string, 3> dimensions = {
+        {"InnerRadius", "OuterRadius", "Height"}};
+    const std::string geometryProp("Geometry");
+    for (const auto &dim : dimensions) {
+      args->declareProperty(
+          Mantid::Kernel::make_unique<DoubleProperty>(dim, -1.0), "");
+      alg->setProperty(geometryProp, args);
+      TS_ASSERT(validateErrorProduced(*alg, geometryProp));
+      args->removeProperty(dim);
+    }
+  }
+
   //----------------------------------------------------------------------------
   // Non-test methods
   //----------------------------------------------------------------------------
 private:
-  Mantid::API::IAlgorithm_uptr createAlgorithm() {
+  Mantid::API::IAlgorithm_uptr
+  createAlgorithm(const Mantid::API::MatrixWorkspace_sptr &inputWS =
+                      Mantid::API::MatrixWorkspace_sptr()) {
     auto alg = Mantid::Kernel::make_unique<SetSample>();
     alg->setChild(true);
     alg->setRethrows(true);
     alg->initialize();
+    if (inputWS) {
+      alg->setProperty("InputWorkspace", inputWS);
+    }
     return std::move(alg);
   }
 
+  bool validateErrorProduced(Mantid::API::IAlgorithm &alg,
+                             const std::string &name) {
+    const auto errors = alg.validateInputs();
+    if (errors.find(name) != errors.end())
+      return true;
+    else
+      return false;
+  }
+
+  void setTestReferenceFrame(Mantid::API::MatrixWorkspace_sptr workspace) {
+    using Mantid::Geometry::Instrument;
+    using Mantid::Geometry::ReferenceFrame;
+    // Use Z=up,Y=across,X=beam so we test it listens to the reference frame
+    auto inst = boost::make_shared<Instrument>();
+    inst->setReferenceFrame(boost::make_shared<ReferenceFrame>(
+        Mantid::Geometry::Z, Mantid::Geometry::X, Mantid::Geometry::Right, ""));
+    workspace->setInstrument(inst);
+  }
+
   Mantid::Kernel::PropertyManager_sptr createMaterialProps() {
     using Mantid::Kernel::PropertyManager;
     using StringProperty = Mantid::Kernel::PropertyWithValue<std::string>;
@@ -373,7 +485,8 @@ private:
     return props;
   }
 
-  Mantid::Kernel::PropertyManager_sptr createFlatPlateGeometryProps() {
+  Mantid::Kernel::PropertyManager_sptr
+  createFlatPlateGeometryProps(double angle = 0.0) {
     using namespace Mantid::Kernel;
     using DoubleArrayProperty = ArrayProperty<double>;
     using DoubleProperty = PropertyWithValue<double>;
@@ -388,10 +501,13 @@ private:
         Mantid::Kernel::make_unique<DoubleProperty>("Height", 4), "");
     props->declareProperty(
         Mantid::Kernel::make_unique<DoubleProperty>("Thick", 0.1), "");
-    std::vector<double> center{0, 0, 1};
+    std::vector<double> center{1, 0, 0};
     props->declareProperty(
         Mantid::Kernel::make_unique<DoubleArrayProperty>("Center", center), "");
-
+    if (angle != 0.0) {
+      props->declareProperty(
+          Mantid::Kernel::make_unique<DoubleProperty>("Angle", angle), "");
+    }
     return props;
   }
 
@@ -399,7 +515,6 @@ private:
     using namespace Mantid::Kernel;
     using DoubleArrayProperty = ArrayProperty<double>;
     using DoubleProperty = PropertyWithValue<double>;
-    using IntProperty = PropertyWithValue<long>;
     using StringProperty = PropertyWithValue<std::string>;
 
     auto props = boost::make_shared<PropertyManager>();
@@ -412,8 +527,6 @@ private:
     std::vector<double> center{0, 0, 1};
     props->declareProperty(
         Mantid::Kernel::make_unique<DoubleArrayProperty>("Center", center), "");
-    props->declareProperty(Mantid::Kernel::make_unique<IntProperty>("Axis", 1),
-                           "");
 
     return props;
   }
@@ -422,7 +535,6 @@ private:
     using namespace Mantid::Kernel;
     using DoubleArrayProperty = ArrayProperty<double>;
     using DoubleProperty = PropertyWithValue<double>;
-    using IntProperty = PropertyWithValue<long>;
     using StringProperty = PropertyWithValue<std::string>;
 
     auto props = boost::make_shared<PropertyManager>();
@@ -438,8 +550,6 @@ private:
     std::vector<double> center{0, 0, 1};
     props->declareProperty(
         Mantid::Kernel::make_unique<DoubleArrayProperty>("Center", center), "");
-    props->declareProperty(Mantid::Kernel::make_unique<IntProperty>("Axis", 1),
-                           "");
 
     return props;
   }
@@ -458,6 +568,7 @@ private:
       throw std::runtime_error("Expected SurfPoint as top rule");
     }
   }
+
   std::string m_testRoot;
   // Use the TEST_LIVE entry in Facilities
   const std::string m_facilityName = "TEST_LIVE";
diff --git a/Framework/DataHandling/test/SetScalingPSDTest.h b/Framework/DataHandling/test/SetScalingPSDTest.h
index b211f8c77ebc93bde5ec1106a82c958113535e3d..a60d095378be3362edd492b0ebb94d10b3d2c6c1 100644
--- a/Framework/DataHandling/test/SetScalingPSDTest.h
+++ b/Framework/DataHandling/test/SetScalingPSDTest.h
@@ -5,6 +5,7 @@
 #include "MantidDataHandling/SetScalingPSD.h"
 #include "MantidDataHandling/LoadEmptyInstrument.h"
 #include "MantidTestHelpers/WorkspaceCreationHelper.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidKernel/ConfigService.h"
 #include <Poco/File.h>
 #include <Poco/Path.h>
@@ -57,19 +58,20 @@ public:
     double expectedYScale[3] = {0.995002, 0.995001, 0.995000};
 
     const auto &pmap = testWS->constInstrumentParameters();
+    const auto &spectrumInfo = testWS->spectrumInfo();
     for (int i = 0; i < ndets; ++i) {
-      IDetector_const_sptr det = testWS->getDetector(i);
-      V3D newPos = det->getPos();
+      V3D newPos = spectrumInfo.position(i);
       V3D oldPos = originalPositions[i];
       TS_ASSERT_DELTA(newPos.Y(), expectedYPos[i], 1e-6);
       TS_ASSERT_DELTA(fabs(oldPos.X() - newPos.X()), 0.0, 1e-05);
       TS_ASSERT_DELTA(fabs(oldPos.Z() - newPos.Z()), 0.0, 1e-05);
 
-      if (det->isMonitor()) {
-        TS_ASSERT_EQUALS(pmap.contains(det.get(), "sca"), false);
+      if (spectrumInfo.isMonitor(i)) {
+        TS_ASSERT_EQUALS(pmap.contains(&spectrumInfo.detector(i), "sca"),
+                         false);
       } else {
-        TS_ASSERT_EQUALS(pmap.contains(det.get(), "sca"), true);
-        Parameter_sptr scaleParam = pmap.get(det.get(), "sca");
+        TS_ASSERT_EQUALS(pmap.contains(&spectrumInfo.detector(i), "sca"), true);
+        Parameter_sptr scaleParam = pmap.get(&spectrumInfo.detector(i), "sca");
         const V3D scaleFactor = scaleParam->value<V3D>();
         TS_ASSERT_EQUALS(scaleFactor.X(), 1.0);
         TS_ASSERT_EQUALS(scaleFactor.Z(), 1.0);
diff --git a/Framework/DataHandling/test/SortTableWorkspaceTest.h b/Framework/DataHandling/test/SortTableWorkspaceTest.h
index fcacba9e05005ed3663f986ec5925b959002e3ee..0db8cee09545ad13712010fffe18c9a3e058ae12 100644
--- a/Framework/DataHandling/test/SortTableWorkspaceTest.h
+++ b/Framework/DataHandling/test/SortTableWorkspaceTest.h
@@ -4,6 +4,7 @@
 #include <cxxtest/TestSuite.h>
 
 #include "MantidDataHandling/SortTableWorkspace.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidAPI/ITableWorkspace.h"
 #include "MantidAPI/TableRow.h"
diff --git a/Framework/DataHandling/test/UpdateInstrumentFromFileTest.h b/Framework/DataHandling/test/UpdateInstrumentFromFileTest.h
index 9dcfc5c1a7502741ccf4420bfa6954d394815109..3e2a90ea577d1e3692d062fa7958952d796b25ab 100644
--- a/Framework/DataHandling/test/UpdateInstrumentFromFileTest.h
+++ b/Framework/DataHandling/test/UpdateInstrumentFromFileTest.h
@@ -8,6 +8,7 @@
 #include "MantidDataHandling/LoadInstrumentFromNexus.h"
 #include "MantidDataHandling/LoadInstrument.h"
 #include "MantidAPI/Algorithm.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/FrameworkManager.h"
 #include "MantidAPI/InstrumentDataService.h"
 #include "MantidAPI/WorkspaceFactory.h"
diff --git a/Framework/DataObjects/CMakeLists.txt b/Framework/DataObjects/CMakeLists.txt
index 8b50a5e5c41ac68c864809bd17bf7dfa83659e1f..7184dae6b3753aee838959cd73ea34aa13015bab 100644
--- a/Framework/DataObjects/CMakeLists.txt
+++ b/Framework/DataObjects/CMakeLists.txt
@@ -36,6 +36,7 @@ set ( SRC_FILES
 	src/PeakShapeSpherical.cpp
 	src/PeakShapeSphericalFactory.cpp
 	src/PeaksWorkspace.cpp
+	src/PropertyWithValue.cpp
 	src/RebinnedOutput.cpp
 	src/ReflectometryTransform.cpp
 	src/SpecialWorkspace2D.cpp
@@ -44,6 +45,8 @@ set ( SRC_FILES
 	src/TableWorkspace.cpp
 	src/VectorColumn.cpp
 	src/Workspace2D.cpp
+	src/WorkspaceCreation.cpp
+	src/WorkspaceProperty.cpp
 	src/WorkspaceSingleValue.cpp
 )
 
@@ -58,9 +61,9 @@ set ( INC_FILES
 	inc/MantidDataObjects/AffineMatrixParameterParser.h
 	inc/MantidDataObjects/BoxControllerNeXusIO.h
 	inc/MantidDataObjects/CalculateReflectometry.h
-    inc/MantidDataObjects/CalculateReflectometryKiKf.h
+	inc/MantidDataObjects/CalculateReflectometryKiKf.h
+	inc/MantidDataObjects/CalculateReflectometryP.h
 	inc/MantidDataObjects/CalculateReflectometryQxQz.h
-    inc/MantidDataObjects/CalculateReflectometryP.h
 	inc/MantidDataObjects/CoordTransformAffine.h
 	inc/MantidDataObjects/CoordTransformAffineParser.h
 	inc/MantidDataObjects/CoordTransformAligned.h
@@ -121,8 +124,8 @@ set ( INC_FILES
 	inc/MantidDataObjects/TableWorkspace.h
 	inc/MantidDataObjects/VectorColumn.h
 	inc/MantidDataObjects/Workspace2D.h
+	inc/MantidDataObjects/WorkspaceCreation.h
 	inc/MantidDataObjects/WorkspaceSingleValue.h
-
 )
 
 set ( TEST_FILES
@@ -171,7 +174,7 @@ set ( TEST_FILES
 	PeaksWorkspaceTest.h
 	RebinnedOutputTest.h
 	RefAxisTest.h
-        ReflectometryTransformTest.h
+	ReflectometryTransformTest.h
 	SkippingPolicyTest.h
 	SpecialWorkspace2DTest.h
 	SplittersWorkspaceTest.h
@@ -183,6 +186,7 @@ set ( TEST_FILES
 	WeightedEventNoTimeTest.h
 	WeightedEventTest.h
 	Workspace2DTest.h
+	WorkspaceCreationTest.h
 	WorkspaceSingleValueTest.h
 	WorkspaceValidatorsTest.h
 )
diff --git a/Framework/DataObjects/inc/MantidDataObjects/EventList.h b/Framework/DataObjects/inc/MantidDataObjects/EventList.h
index c2557fe1b0afbdbe5a26bc48f014f8784bc40812..b78a1098da6efb3672dbcdaf387638f511195eb7 100644
--- a/Framework/DataObjects/inc/MantidDataObjects/EventList.h
+++ b/Framework/DataObjects/inc/MantidDataObjects/EventList.h
@@ -6,18 +6,19 @@
 #endif
 #include "MantidAPI/IEventList.h"
 #include "MantidDataObjects/Events.h"
-#include "MantidKernel/DateAndTime.h"
 #include "MantidKernel/MultiThreaded.h"
 #include "MantidKernel/System.h"
-#include "MantidKernel/TimeSplitter.h"
-#include "MantidKernel/Unit.h"
 #include "MantidKernel/cow_ptr.h"
-#include <cstddef>
 #include <iosfwd>
-#include <set>
 #include <vector>
 
 namespace Mantid {
+namespace Kernel {
+class DateAndTime;
+class SplittingInterval;
+typedef std::vector<SplittingInterval> TimeSplitterType;
+class Unit;
+}
 namespace DataObjects {
 class EventWorkspaceMRU;
 
diff --git a/Framework/DataObjects/inc/MantidDataObjects/EventWorkspace.h b/Framework/DataObjects/inc/MantidDataObjects/EventWorkspace.h
index 8ad70d36ad70e88a56312bbdefa6445c7e7a0c94..da49654ab848d75a2f5ad6fda9bac7eae30a25a4 100644
--- a/Framework/DataObjects/inc/MantidDataObjects/EventWorkspace.h
+++ b/Framework/DataObjects/inc/MantidDataObjects/EventWorkspace.h
@@ -40,9 +40,16 @@ public:
     return std::unique_ptr<EventWorkspace>(doClone());
   }
 
+  /// Returns a default-initialized clone of the workspace
+  std::unique_ptr<EventWorkspace> cloneEmpty() const {
+    return std::unique_ptr<EventWorkspace>(doCloneEmpty());
+  }
+
   // Initialize the pixels
   void init(const std::size_t &, const std::size_t &,
             const std::size_t &) override;
+  void init(const std::size_t &NVectors,
+            const HistogramData::Histogram &histogram) override;
 
   bool threadSafe() const override;
 
@@ -141,6 +148,7 @@ protected:
 
 private:
   EventWorkspace *doClone() const override { return new EventWorkspace(*this); }
+  EventWorkspace *doCloneEmpty() const override { return new EventWorkspace(); }
 
   /** A vector that holds the event list for each spectrum; the key is
    * the workspace index, which is not necessarily the pixelid.
diff --git a/Framework/DataObjects/inc/MantidDataObjects/GroupingWorkspace.h b/Framework/DataObjects/inc/MantidDataObjects/GroupingWorkspace.h
index 9fd6844e6af766dcc4ff12f5a115a81998a3202d..50f21824e37b728e675e138fbd02f1bf5c56bec7 100644
--- a/Framework/DataObjects/inc/MantidDataObjects/GroupingWorkspace.h
+++ b/Framework/DataObjects/inc/MantidDataObjects/GroupingWorkspace.h
@@ -30,6 +30,11 @@ public:
     return std::unique_ptr<GroupingWorkspace>(doClone());
   }
 
+  /// Returns a default-initialized clone of the workspace
+  std::unique_ptr<GroupingWorkspace> cloneEmpty() const {
+    return std::unique_ptr<GroupingWorkspace>(doCloneEmpty());
+  }
+
   /** Gets the name of the workspace type
   @return Standard string name  */
   const std::string id() const override { return "GroupingWorkspace"; }
@@ -47,6 +52,9 @@ private:
   GroupingWorkspace *doClone() const override {
     return new GroupingWorkspace(*this);
   }
+  GroupingWorkspace *doCloneEmpty() const override {
+    return new GroupingWorkspace();
+  }
 };
 
 /// shared pointer to the GroupingWorkspace class
diff --git a/Framework/DataObjects/inc/MantidDataObjects/MDBox.h b/Framework/DataObjects/inc/MantidDataObjects/MDBox.h
index fcf58a8f83d54481c999609b892d26c5e6459538..8f504d7581f9bdf707da0baa8d55c6ee95d8163e 100644
--- a/Framework/DataObjects/inc/MantidDataObjects/MDBox.h
+++ b/Framework/DataObjects/inc/MantidDataObjects/MDBox.h
@@ -174,7 +174,8 @@ public:
   void calculateDimensionStats(MDDimensionStats *stats) const;
   void integrateSphere(Mantid::API::CoordTransform &radiusTransform,
                        const coord_t radiusSquared, signal_t &signal,
-                       signal_t &errorSquared) const override;
+                       signal_t &errorSquared,
+                       const coord_t innerRadiusSquared = 0.0) const override;
   void centroidSphere(Mantid::API::CoordTransform &radiusTransform,
                       const coord_t radiusSquared, coord_t *centroid,
                       signal_t &signal) const override;
@@ -222,6 +223,15 @@ private:
   MDBox(const MDBox &);
   /// common part of mdBox constructor
   void initMDBox(const size_t nBoxEvents);
+  struct MyComparator {
+    const std::vector<double> &value_vector;
+
+    MyComparator(const std::vector<double> &val_vec) : value_vector(val_vec) {}
+
+    bool operator()(size_t i1, size_t i2) {
+      return value_vector[i1] < value_vector[i2];
+    }
+  };
 
 public:
   /// Typedef for a shared pointer to a MDBox
@@ -279,7 +289,6 @@ public:
     return MDLeanEvent<nd>(Signal, Error, Coord);
   }
 };
-
 } // namespace DataObjects
 
 } // namespace Mantid
diff --git a/Framework/DataObjects/inc/MantidDataObjects/MDBox.tcc b/Framework/DataObjects/inc/MantidDataObjects/MDBox.tcc
index 1ccd7ce4ca07ce80bfe102542e6cd0200c6c0311..738b585b48252fe9a28d6685dd7f1e74b46c4d0d 100644
--- a/Framework/DataObjects/inc/MantidDataObjects/MDBox.tcc
+++ b/Framework/DataObjects/inc/MantidDataObjects/MDBox.tcc
@@ -435,7 +435,7 @@ for (const MDE & Evnt : data) {
       for (size_t d = 0; d < nd; d++) {
         // Total up the coordinate weighted by the signal.
         centroid[d] += Evnt.getCenter(d) * signal;
-	  }
+    }
     }
   }
 
@@ -550,20 +550,44 @@ TMDE(void MDBox)::generalBin(
  * @param radiusSquared :: radius^2 below which to integrate
  * @param[out] signal :: set to the integrated signal
  * @param[out] errorSquared :: set to the integrated squared error.
+ * @param innerRadiusSquared :: radius^2 above which to integrate
  */
 TMDE(void MDBox)::integrateSphere(Mantid::API::CoordTransform &radiusTransform,
                                   const coord_t radiusSquared, signal_t &signal,
-                                  signal_t &errorSquared) const {
+                                  signal_t &errorSquared, const coord_t innerRadiusSquared) const {
   // If the box is cached to disk, you need to retrieve it
   const std::vector<MDE> &events = this->getConstEvents();
-
-  // For each MDLeanEvent
-  for (const auto & it :events) {
-    coord_t out[nd];
-    radiusTransform.apply(it.getCenter(), out);
-    if (out[0] < radiusSquared) {
-      signal += static_cast<signal_t>(it.getSignal());
-      errorSquared += static_cast<signal_t>(it.getErrorSquared());
+  if (innerRadiusSquared == 0.0) {
+    // For each MDLeanEvent
+    for (const auto &it : events) {
+      coord_t out[nd];
+      radiusTransform.apply(it.getCenter(), out);
+      if (out[0] < radiusSquared) {
+        signal += static_cast<signal_t>(it.getSignal());
+        errorSquared += static_cast<signal_t>(it.getErrorSquared());
+      }
+    }
+  } else {
+      // For each MDLeanEvent
+    std::vector<double> eventVec, errsqVec;
+    for (const auto &it : events) {
+      coord_t out[nd];
+      radiusTransform.apply(it.getCenter(), out);
+      if (out[0] < radiusSquared && out[0] > innerRadiusSquared) {
+        eventVec.push_back(static_cast<signal_t>(it.getSignal()));
+        errsqVec.push_back(static_cast<signal_t>(it.getErrorSquared()));
+        //signal += static_cast<signal_t>(it.getSignal());
+        //errorSquared += static_cast<signal_t>(it.getErrorSquared());
+      }
+    }
+    std::sort(errsqVec.begin(), errsqVec.end(), MyComparator(eventVec));
+    std::sort(eventVec.begin(), eventVec.end());
+    // Remove top 1% of background
+    for (size_t k = 0;
+         k < static_cast<size_t>(0.99 * static_cast<double>(eventVec.size()));
+         k++) {
+      signal += eventVec[k];
+      errorSquared += errsqVec[k];
     }
   }
   // it is constant access, so no saving or fiddling with the buffer is needed.
diff --git a/Framework/DataObjects/inc/MantidDataObjects/MDBoxBase.h b/Framework/DataObjects/inc/MantidDataObjects/MDBoxBase.h
index bfe2f292b9302643ad34bc0d3208d83ff46c418e..cbab69c6f3bedd9271e79edddc6559e73f179f2f 100644
--- a/Framework/DataObjects/inc/MantidDataObjects/MDBoxBase.h
+++ b/Framework/DataObjects/inc/MantidDataObjects/MDBoxBase.h
@@ -127,9 +127,11 @@ public:
              Mantid::Geometry::MDImplicitFunction &function) const = 0;
 
   /** Sphere (peak) integration */
-  void integrateSphere(Mantid::API::CoordTransform &radiusTransform,
-                       const coord_t radiusSquared, signal_t &signal,
-                       signal_t &errorSquared) const override = 0;
+  void
+  integrateSphere(Mantid::API::CoordTransform &radiusTransform,
+                  const coord_t radiusSquared, signal_t &signal,
+                  signal_t &errorSquared,
+                  const coord_t innerRadiusSquared = 0.0) const override = 0;
 
   /** Find the centroid around a sphere */
   void centroidSphere(Mantid::API::CoordTransform &radiusTransform,
diff --git a/Framework/DataObjects/inc/MantidDataObjects/MDEventWorkspace.tcc b/Framework/DataObjects/inc/MantidDataObjects/MDEventWorkspace.tcc
index 2f7c3d4611880cbc978f31b934aecb7403300be7..4db8da03a56159193e041a491bd12370ffa2724b 100644
--- a/Framework/DataObjects/inc/MantidDataObjects/MDEventWorkspace.tcc
+++ b/Framework/DataObjects/inc/MantidDataObjects/MDEventWorkspace.tcc
@@ -19,6 +19,7 @@
 #include "MantidKernel/ConfigService.h"
 
 #include <iomanip>
+#include <iostream>
 #include <functional>
 #include <algorithm>
 #include "MantidDataObjects/MDBoxIterator.h"
@@ -920,7 +921,7 @@ TMDE(API::IMDWorkspace::LinePlot MDEventWorkspace)
   }
 
   // If everything was masked
-  if (line.x.size() == 0) {
+  if (line.x.empty()) {
     makeSinglePointWithNaN(line.x, line.y, line.e);
   }
   return line;
diff --git a/Framework/DataObjects/inc/MantidDataObjects/MDGridBox.h b/Framework/DataObjects/inc/MantidDataObjects/MDGridBox.h
index 5d788f75af963ebae0f4f40c0febb7486f4e5bd4..14260dff036d622f821a8dd45dd1c043950e870a 100644
--- a/Framework/DataObjects/inc/MantidDataObjects/MDGridBox.h
+++ b/Framework/DataObjects/inc/MantidDataObjects/MDGridBox.h
@@ -152,7 +152,8 @@ public:
 
   void integrateSphere(Mantid::API::CoordTransform &radiusTransform,
                        const coord_t radiusSquared, signal_t &signal,
-                       signal_t &errorSquared) const override;
+                       signal_t &errorSquared,
+                       const coord_t innerRadiusSquared = 0.0) const override;
 
   void centroidSphere(Mantid::API::CoordTransform &radiusTransform,
                       const coord_t radiusSquared, coord_t *centroid,
diff --git a/Framework/DataObjects/inc/MantidDataObjects/MDGridBox.tcc b/Framework/DataObjects/inc/MantidDataObjects/MDGridBox.tcc
index da749e4278b28b01d4cd382fe6a5fc9fd2be9968..d9dd883b46263753236f2c44ee12f225e74a8373 100644
--- a/Framework/DataObjects/inc/MantidDataObjects/MDGridBox.tcc
+++ b/Framework/DataObjects/inc/MantidDataObjects/MDGridBox.tcc
@@ -1082,11 +1082,13 @@ TMDE(void MDGridBox)::centerpointBin(MDBin<MDE, nd> &bin,
  * @param radiusSquared :: radius^2 below which to integrate
  * @param signal [out] :: set to the integrated signal
  * @param errorSquared [out] :: set to the integrated squared error.
+ * @param innerRadiusSquared :: radius^2 above which to integrate
  */
 TMDE(void MDGridBox)::integrateSphere(API::CoordTransform &radiusTransform,
                                       const coord_t radiusSquared,
                                       signal_t &signal,
-                                      signal_t &errorSquared) const {
+                                      signal_t &errorSquared, 
+                                      const coord_t innerRadiusSquared) const {
   // We start by looking at the vertices at every corner of every box contained,
   // to see which boxes are partially contained/fully contained.
 
@@ -1137,7 +1139,7 @@ TMDE(void MDGridBox)::integrateSphere(API::CoordTransform &radiusTransform,
     // Is this vertex contained?
     coord_t out[nd];
     radiusTransform.apply(vertexCoord, out);
-    if (out[0] < radiusSquared) {
+    if (out[0] < radiusSquared && out[0] > innerRadiusSquared) {
       // Yes, this vertex is contained within the integration volume!
       //        std::cout << "vertex at " << vertexCoord[0] << ", " <<
       //        vertexCoord[1] << ", " << vertexCoord[2] << " is contained\n";
@@ -1214,7 +1216,8 @@ TMDE(void MDGridBox)::integrateSphere(API::CoordTransform &radiusTransform,
       coord_t out[nd];
       radiusTransform.apply(boxCenter, out);
 
-      if (out[0] < diagonalSquared * 0.72 + radiusSquared) {
+      if (out[0] < diagonalSquared * 0.72 + radiusSquared || 
+          out[0] < diagonalSquared * 0.72 + innerRadiusSquared) {
         // If the center is closer than the size of the box, then it MIGHT be
         // touching.
         // (We multiply by 0.72 (about sqrt(2)) to look for half the diagonal).
@@ -1231,7 +1234,7 @@ TMDE(void MDGridBox)::integrateSphere(API::CoordTransform &radiusTransform,
     if (partialBox) {
       // Use the detailed integration method.
       box->integrateSphere(radiusTransform, radiusSquared, signal,
-                           errorSquared);
+                           errorSquared, innerRadiusSquared);
       //        std::cout << ".signal=" << signal << "\n";
       numPartiallyContained++;
     }
diff --git a/Framework/DataObjects/inc/MantidDataObjects/MaskWorkspace.h b/Framework/DataObjects/inc/MantidDataObjects/MaskWorkspace.h
index 890ce04a7c52e96e989326be76a1d64bde95cb17..a71caabb1c74d5592080165ccf1956449922084d 100644
--- a/Framework/DataObjects/inc/MantidDataObjects/MaskWorkspace.h
+++ b/Framework/DataObjects/inc/MantidDataObjects/MaskWorkspace.h
@@ -23,6 +23,10 @@ public:
   std::unique_ptr<MaskWorkspace> clone() const {
     return std::unique_ptr<MaskWorkspace>(doClone());
   }
+  /// Returns a default-initialized clone of the workspace
+  std::unique_ptr<MaskWorkspace> cloneEmpty() const {
+    return std::unique_ptr<MaskWorkspace>(doCloneEmpty());
+  }
   MaskWorkspace &operator=(const MaskWorkspace &other) = delete;
   bool isMasked(const detid_t detectorID) const override;
   bool isMasked(const std::set<detid_t> &detectorIDs) const override;
@@ -49,6 +53,7 @@ protected:
 
 private:
   MaskWorkspace *doClone() const override { return new MaskWorkspace(*this); }
+  MaskWorkspace *doCloneEmpty() const override { return new MaskWorkspace(); }
 
   IMaskWorkspace *doInterfaceClone() const override { return doClone(); };
   /// Clear original incorrect mask
diff --git a/Framework/DataObjects/inc/MantidDataObjects/OffsetsWorkspace.h b/Framework/DataObjects/inc/MantidDataObjects/OffsetsWorkspace.h
index d65930ac0de50800ea88e207487b949e64e069d6..b3108ad69bb35de929884c8be97edfe8dd98eca9 100644
--- a/Framework/DataObjects/inc/MantidDataObjects/OffsetsWorkspace.h
+++ b/Framework/DataObjects/inc/MantidDataObjects/OffsetsWorkspace.h
@@ -25,6 +25,10 @@ public:
   std::unique_ptr<OffsetsWorkspace> clone() const {
     return std::unique_ptr<OffsetsWorkspace>(doClone());
   }
+  /// Returns a default-initialized clone of the workspace
+  std::unique_ptr<OffsetsWorkspace> cloneEmpty() const {
+    return std::unique_ptr<OffsetsWorkspace>(doCloneEmpty());
+  }
   OffsetsWorkspace &operator=(const OffsetsWorkspace &) = delete;
   /** Gets the name of the workspace type
   @return Standard string name  */
@@ -38,6 +42,9 @@ private:
   OffsetsWorkspace *doClone() const override {
     return new OffsetsWorkspace(*this);
   }
+  OffsetsWorkspace *doCloneEmpty() const override {
+    return new OffsetsWorkspace();
+  }
 };
 
 /// shared pointer to the OffsetsWorkspace class
diff --git a/Framework/DataObjects/inc/MantidDataObjects/PeakColumn.h b/Framework/DataObjects/inc/MantidDataObjects/PeakColumn.h
index c2e76fd91be869d38a810b116048bbf3a1b62fff..3079799086ac2b8d83ee4c7a1892de7f29aefcae 100644
--- a/Framework/DataObjects/inc/MantidDataObjects/PeakColumn.h
+++ b/Framework/DataObjects/inc/MantidDataObjects/PeakColumn.h
@@ -40,6 +40,9 @@ public:
 
   void read(size_t index, const std::string &text) override;
 
+  /// Sets item from a stream
+  void read(const size_t index, std::istream &in) override;
+
   /// Specialized type check
   bool isBool() const override;
 
@@ -77,6 +80,8 @@ private:
   typedef boost::variant<double, int, std::string, Kernel::V3D> CacheValueType;
   ///
   mutable std::list<CacheValueType> m_oldRows;
+  /// Sets the correct value in the referenced peak.
+  void setPeakHKLOrRunNumber(const size_t index, const double val);
 };
 
 } // namespace Mantid
diff --git a/Framework/DataObjects/inc/MantidDataObjects/RebinnedOutput.h b/Framework/DataObjects/inc/MantidDataObjects/RebinnedOutput.h
index dfbc99498c14fd58a2393c5983b7c993a593a903..66ded0f1accca45826b93040691ada7161095444 100644
--- a/Framework/DataObjects/inc/MantidDataObjects/RebinnedOutput.h
+++ b/Framework/DataObjects/inc/MantidDataObjects/RebinnedOutput.h
@@ -45,6 +45,10 @@ public:
   std::unique_ptr<RebinnedOutput> clone() const {
     return std::unique_ptr<RebinnedOutput>(doClone());
   }
+  /// Returns a default-initialized clone of the workspace
+  std::unique_ptr<RebinnedOutput> cloneEmpty() const {
+    return std::unique_ptr<RebinnedOutput>(doCloneEmpty());
+  }
   RebinnedOutput &operator=(const RebinnedOutput &) = delete;
 
   /// Get the workspace ID.
@@ -72,12 +76,15 @@ protected:
   /// Called by initialize() in MatrixWorkspace
   void init(const std::size_t &NVectors, const std::size_t &XLength,
             const std::size_t &YLength) override;
+  void init(const std::size_t &NVectors,
+            const HistogramData::Histogram &histogram) override;
 
   /// A vector that holds the 1D vectors for the fractional area.
   std::vector<MantidVec> fracArea;
 
 private:
   RebinnedOutput *doClone() const override { return new RebinnedOutput(*this); }
+  RebinnedOutput *doCloneEmpty() const override { return new RebinnedOutput(); }
 };
 
 /// shared pointer to the RebinnedOutput class
diff --git a/Framework/DataObjects/inc/MantidDataObjects/SpecialWorkspace2D.h b/Framework/DataObjects/inc/MantidDataObjects/SpecialWorkspace2D.h
index ba92978d540f4b0373f510dc36b6b5ff99d29fd0..e9e7b58ad470d0a0a8fb61c20e3471938a9331c7 100644
--- a/Framework/DataObjects/inc/MantidDataObjects/SpecialWorkspace2D.h
+++ b/Framework/DataObjects/inc/MantidDataObjects/SpecialWorkspace2D.h
@@ -34,6 +34,10 @@ public:
   std::unique_ptr<SpecialWorkspace2D> clone() const {
     return std::unique_ptr<SpecialWorkspace2D>(doClone());
   }
+  /// Returns a default-initialized clone of the workspace
+  std::unique_ptr<SpecialWorkspace2D> cloneEmpty() const {
+    return std::unique_ptr<SpecialWorkspace2D>(doCloneEmpty());
+  }
   SpecialWorkspace2D &operator=(const SpecialWorkspace2D &) = delete;
   /** Gets the name of the workspace type
   @return Standard string name  */
@@ -59,6 +63,9 @@ private:
   SpecialWorkspace2D *doClone() const override {
     return new SpecialWorkspace2D(*this);
   }
+  SpecialWorkspace2D *doCloneEmpty() const override {
+    return new SpecialWorkspace2D();
+  }
   bool isCompatible(boost::shared_ptr<const SpecialWorkspace2D> ws);
 
 protected:
@@ -67,6 +74,8 @@ protected:
 
   void init(const size_t &NVectors, const size_t &XLength,
             const size_t &YLength) override;
+  void init(const size_t &NVectors,
+            const HistogramData::Histogram &histogram) override;
 
   /// Return human-readable string
   const std::string toString() const override;
diff --git a/Framework/DataObjects/inc/MantidDataObjects/TableColumn.h b/Framework/DataObjects/inc/MantidDataObjects/TableColumn.h
index d0d16857279150e892c2cff27fdab63fcfe638f4..6213255557bc595e9c0248e44c6cd58386bd3e83 100644
--- a/Framework/DataObjects/inc/MantidDataObjects/TableColumn.h
+++ b/Framework/DataObjects/inc/MantidDataObjects/TableColumn.h
@@ -138,6 +138,8 @@ public:
   }
   /// Read in a string and set the value at the given index
   void read(size_t index, const std::string &text) override;
+  /// Read in from stream and set the value at the given index
+  void read(const size_t index, std::istream &in) override;
   /// Type check
   bool isBool() const override { return typeid(Type) == typeid(API::Boolean); }
   /// Memory used by the column
@@ -251,6 +253,12 @@ void TableColumn<Type>::read(size_t index, const std::string &text) {
   istr >> m_data[index];
 }
 
+/// Read in from stream and set the value at the given index
+template <typename Type>
+void TableColumn<Type>::read(size_t index, std::istream &in) {
+  in >> m_data[index];
+}
+
 namespace {
 /// Comparison object to compare column values given their indices.
 template <typename Type> class CompareValues {
diff --git a/Framework/DataObjects/inc/MantidDataObjects/VectorColumn.h b/Framework/DataObjects/inc/MantidDataObjects/VectorColumn.h
index 2833c272232b313e357f7854965e2c0b71b9b3fd..cb957ad03f0158c6a6a056c202e8f210de31d154 100644
--- a/Framework/DataObjects/inc/MantidDataObjects/VectorColumn.h
+++ b/Framework/DataObjects/inc/MantidDataObjects/VectorColumn.h
@@ -80,8 +80,7 @@ public:
     Mantid::Kernel::StringTokenizer elements(
         text, ",", Mantid::Kernel::StringTokenizer::TOK_TRIM);
 
-    for (const auto &it : elements) {
-      std::string element(it);
+    for (const auto &element : elements) {
       try {
         newValues.push_back(boost::lexical_cast<Type>(element));
       } catch (boost::bad_lexical_cast &) {
@@ -93,6 +92,13 @@ public:
     m_data.at(index) = newValues;
   }
 
+  /// Set item from a stream
+  void read(const size_t index, std::istream &in) override {
+    std::string s;
+    in >> s;
+    read(index, s);
+  }
+
   /// Specialized type check
   bool isBool() const override { return false; }
 
diff --git a/Framework/DataObjects/inc/MantidDataObjects/Workspace2D.h b/Framework/DataObjects/inc/MantidDataObjects/Workspace2D.h
index 45401d3080b9c91cca481007d1c4e1bbdb8b1cba..21e6eddc80f3f0362e9c45cf125bf85395904d25 100644
--- a/Framework/DataObjects/inc/MantidDataObjects/Workspace2D.h
+++ b/Framework/DataObjects/inc/MantidDataObjects/Workspace2D.h
@@ -4,7 +4,7 @@
 //----------------------------------------------------------------------
 // Includes
 //----------------------------------------------------------------------
-#include "MantidAPI/MatrixWorkspace.h"
+#include "MantidAPI/HistoWorkspace.h"
 #include "MantidDataObjects/Histogram1D.h"
 
 namespace Mantid {
@@ -40,7 +40,7 @@ namespace DataObjects {
     File change history is stored at: <https://github.com/mantidproject/mantid>.
     Code Documentation is available at: <http://doxygen.mantidproject.org>
 */
-class DLLExport Workspace2D : public API::MatrixWorkspace {
+class DLLExport Workspace2D : public API::HistoWorkspace {
 public:
   /**
   Gets the name of the workspace type
@@ -57,6 +57,11 @@ public:
     return std::unique_ptr<Workspace2D>(doClone());
   }
 
+  /// Returns a default-initialized clone of the workspace
+  std::unique_ptr<Workspace2D> cloneEmpty() const {
+    return std::unique_ptr<Workspace2D>(doCloneEmpty());
+  }
+
   /// Returns the histogram number
   std::size_t getNumberHistograms() const override;
 
@@ -96,6 +101,8 @@ protected:
   /// Called by initialize()
   void init(const std::size_t &NVectors, const std::size_t &XLength,
             const std::size_t &YLength) override;
+  void init(const std::size_t &NVectors,
+            const HistogramData::Histogram &histogram) override;
 
   /// The number of vectors in the workspace
   std::size_t m_noVectors;
@@ -108,6 +115,7 @@ protected:
 
 private:
   Workspace2D *doClone() const override { return new Workspace2D(*this); }
+  Workspace2D *doCloneEmpty() const override { return new Workspace2D(); }
 
   virtual std::size_t getHistogramNumberHelper() const;
 };
diff --git a/Framework/DataObjects/inc/MantidDataObjects/WorkspaceCreation.h b/Framework/DataObjects/inc/MantidDataObjects/WorkspaceCreation.h
new file mode 100644
index 0000000000000000000000000000000000000000..2f5b2931e063ac0cdc3cf5f75031cbd09fc99fed
--- /dev/null
+++ b/Framework/DataObjects/inc/MantidDataObjects/WorkspaceCreation.h
@@ -0,0 +1,223 @@
+#ifndef MANTID_DATAOBJECTS_WORKSPACECREATION_H_
+#define MANTID_DATAOBJECTS_WORKSPACECREATION_H_
+
+#include "MantidDataObjects/DllConfig.h"
+#include "MantidHistogramData/Histogram.h"
+#include "MantidKernel/make_unique.h"
+
+#include <memory>
+#include <type_traits>
+
+namespace Mantid {
+namespace API {
+class MatrixWorkspace;
+class HistoWorkspace;
+}
+namespace DataObjects {
+class EventWorkspace;
+class Workspace2D;
+
+/** Factory methods for creating MatrixWorkspaces. A template parameter T
+  specifies the type of (or a base type of) the created workspace:
+  - The type of the output workspace is identical to T for the variants without
+    parent.
+  - The type of the output workspace is the dynamic type of the parent if T is a
+    base of the parents dynamic type.
+  - The type of the output workspace is T if the dynamic type of the parent is a
+    base of T.
+  - If T is not a base of the parents dynamic type, a conversion is attempted.
+    Currently this is the case only for EventWorkspace:
+    - If the dynamic type of the parent is EventWorkspace but T is not, either a
+      Workspace2D or T is created, whichever is more derived. For example, a
+      typical use-case is to drop events and create a Workspace2D from an
+      EventWorkspace.  This can be achieved as follows:
+      ~~~{.cpp}
+      auto ws = create<HistoWorkspace>(parent);
+      ~~~
+      This is equivalent to the old way of using
+      WorkspaceFactory::create(parent). In this case, Workspace2D is more
+      derived than HistoWorkspace, so a Workspace2D is created.
+    - If the dynamic type of the parent is derived from HistoWorkspace, and
+      EventWorkspace can be created from it.
+
+  Other arguments can include:
+  - The desired number of spectra (NumSpectra) to be created in the output
+    workspace.
+  - A reference to an IndexInfo object, defining the number of spectra and
+    spectrum number and detector IDs.
+  - A reference to a Histogram object (or alternatively BinEdges or Points),
+    defining the size of the histograms as well as whether the workspace stores
+    point data or histogram data. This is a replacement for an independent
+    specification of the X and Y lengths. This is also used to initialize the
+    workspace with X data and (optionally) Y and E data.
+
+  Available variants are:
+
+  ~~~{.cpp}
+  create<T>(NumSpectra, Histogram)
+  create<T>(IndexInfo,  Histogram)
+  create<T>(ParentWS)
+  create<T>(ParentWS, Histogram)
+  create<T>(ParentWS, NumSpectra)
+  create<T>(ParentWS, IndexInfo)
+  create<T>(ParentWS, NumSpectra, Histogram)
+  create<T>(ParentWS, IndexInfo, Histogram)
+  ~~~
+
+  - If neither NumSpectra nor IndexInfo is given, or if the new size is
+    identical to the size of the parent, the created workspace has the same
+    number of spectra as the parent workspace and spectrum number as well as
+    detector ID information is copied from the parent.
+  - If Histogram is not given, the created workspace has X identical to the
+    parent workspace and Y and E are initialized to 0.
+  - If a Histogram with 'NULL' Y and E is given, Y and E are initialized to 0.
+
+  In all cases a (smart) pointer to T is returned.
+
+  @author Simon Heybrock
+  @date 2016
+
+  Copyright &copy; 2016 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>
+*/
+
+namespace detail {
+MANTID_DATAOBJECTS_DLL HistogramData::Histogram
+stripData(HistogramData::Histogram histogram);
+
+template <class T> std::unique_ptr<T> createHelper() {
+  return Kernel::make_unique<T>();
+}
+
+template <class T> std::unique_ptr<T> createConcreteHelper() {
+  return Kernel::make_unique<T>();
+}
+
+template <>
+MANTID_DATAOBJECTS_DLL std::unique_ptr<API::HistoWorkspace> createHelper();
+
+// Dummy specialization, should never be called, must exist for compilation.
+template <>
+MANTID_DATAOBJECTS_DLL std::unique_ptr<EventWorkspace> createHelper();
+// Dummy specialization, should never be called, must exist for compilation.
+template <>
+MANTID_DATAOBJECTS_DLL std::unique_ptr<API::MatrixWorkspace> createHelper();
+
+// Dummy specialization, should never be called, must exist for compilation.
+template <>
+MANTID_DATAOBJECTS_DLL std::unique_ptr<API::MatrixWorkspace>
+createConcreteHelper();
+// Dummy specialization, should never be called, must exist for compilation.
+template <>
+MANTID_DATAOBJECTS_DLL std::unique_ptr<API::HistoWorkspace>
+createConcreteHelper();
+
+MANTID_DATAOBJECTS_DLL void
+initializeFromParent(const API::MatrixWorkspace &parent,
+                     API::MatrixWorkspace &ws);
+}
+
+template <class T, class P, class IndexArg, class HistArg,
+          class = typename std::enable_if<
+              std::is_base_of<API::MatrixWorkspace, P>::value>::type>
+std::unique_ptr<T> create(const P &parent, const IndexArg &indexArg,
+                          const HistArg &histArg) {
+  // Figure out (dynamic) target type:
+  // - Type is same as parent if T is base of parent
+  // - If T is not base of parent, conversion may occur. Currently only
+  //   supported for EventWorkspace
+  std::unique_ptr<T> ws;
+  if (std::is_base_of<API::HistoWorkspace, T>::value &&
+      parent.id() == "EventWorkspace") {
+    // Drop events, create Workspace2D or T whichever is more derived.
+    ws = detail::createHelper<T>();
+  } else {
+    try {
+      // If parent is more derived than T: create type(parent)
+      ws = dynamic_cast<const T &>(parent).cloneEmpty();
+    } catch (std::bad_cast &) {
+      // If T is more derived than parent: create T
+      ws = detail::createConcreteHelper<T>();
+    }
+  }
+
+  ws->initialize(indexArg, HistogramData::Histogram(histArg));
+  detail::initializeFromParent(parent, *ws);
+
+  return ws;
+}
+
+template <class T, class IndexArg, class HistArg,
+          typename std::enable_if<
+              !std::is_base_of<API::MatrixWorkspace, IndexArg>::value>::type * =
+              nullptr>
+std::unique_ptr<T> create(const IndexArg &indexArg, const HistArg &histArg) {
+  auto ws = Kernel::make_unique<T>();
+  ws->initialize(indexArg, HistogramData::Histogram(histArg));
+  return std::move(ws);
+}
+
+template <class T, class P,
+          typename std::enable_if<std::is_base_of<API::MatrixWorkspace,
+                                                  P>::value>::type * = nullptr>
+std::unique_ptr<T> create(const P &parent) {
+  return create<T>(parent, parent.getNumberHistograms(),
+                   detail::stripData(parent.histogram(0)));
+}
+
+template <class T, class P, class IndexArg,
+          typename std::enable_if<std::is_base_of<API::MatrixWorkspace,
+                                                  P>::value>::type * = nullptr>
+std::unique_ptr<T> create(const P &parent, const IndexArg &indexArg) {
+  return create<T>(parent, indexArg, detail::stripData(parent.histogram(0)));
+}
+
+// Templating with HistArg clashes with the IndexArg template above. Could be
+// fixed with many enable_if cases, but for now we simply provide 3 variants
+// (Histogram, BinEdges, Points) by hand.
+template <class T, class P,
+          typename std::enable_if<std::is_base_of<API::MatrixWorkspace,
+                                                  P>::value>::type * = nullptr>
+std::unique_ptr<T> create(const P &parent,
+                          const HistogramData::Histogram &histogram) {
+  return create<T>(parent, parent.getNumberHistograms(), histogram);
+}
+
+template <class T, class P,
+          typename std::enable_if<std::is_base_of<API::MatrixWorkspace,
+                                                  P>::value>::type * = nullptr>
+std::unique_ptr<T> create(const P &parent,
+                          const HistogramData::BinEdges &binEdges) {
+  return create<T>(parent, parent.getNumberHistograms(), binEdges);
+}
+
+template <class T, class P,
+          typename std::enable_if<std::is_base_of<API::MatrixWorkspace,
+                                                  P>::value>::type * = nullptr>
+std::unique_ptr<T> create(const P &parent,
+                          const HistogramData::Points &points) {
+  return create<T>(parent, parent.getNumberHistograms(), points);
+}
+
+} // namespace DataObjects
+} // namespace Mantid
+
+#endif /* MANTID_DATAOBJECTS_WORKSPACECREATION_H_ */
diff --git a/Framework/DataObjects/inc/MantidDataObjects/WorkspaceSingleValue.h b/Framework/DataObjects/inc/MantidDataObjects/WorkspaceSingleValue.h
index 048e310bc803f83347ff2436cc20e94b954045b1..596e61bc02c31f5fcc89e74c9ac17e0e95013418 100644
--- a/Framework/DataObjects/inc/MantidDataObjects/WorkspaceSingleValue.h
+++ b/Framework/DataObjects/inc/MantidDataObjects/WorkspaceSingleValue.h
@@ -4,7 +4,7 @@
 //----------------------------------------------------------------------
 // Includes
 //----------------------------------------------------------------------
-#include "MantidAPI/MatrixWorkspace.h"
+#include "MantidAPI/HistoWorkspace.h"
 #include "MantidDataObjects/Histogram1D.h"
 
 namespace Mantid {
@@ -35,7 +35,7 @@ namespace DataObjects {
     File change history is stored at: <https://github.com/mantidproject/mantid>.
     Code Documentation is available at: <http://doxygen.mantidproject.org>
 */
-class DLLExport WorkspaceSingleValue : public API::MatrixWorkspace {
+class DLLExport WorkspaceSingleValue : public API::HistoWorkspace {
 public:
   /**	Gets the name of the workspace type
    * @return Standard string name  */
@@ -47,6 +47,10 @@ public:
   std::unique_ptr<WorkspaceSingleValue> clone() const {
     return std::unique_ptr<WorkspaceSingleValue>(doClone());
   }
+  /// Returns a default-initialized clone of the workspace
+  std::unique_ptr<WorkspaceSingleValue> cloneEmpty() const {
+    return std::unique_ptr<WorkspaceSingleValue>(doCloneEmpty());
+  }
   WorkspaceSingleValue &operator=(const WorkspaceSingleValue &other) = delete;
   /// Returns the number of single indexable items in the workspace
   std::size_t size() const override { return 1; }
@@ -75,10 +79,15 @@ private:
   WorkspaceSingleValue *doClone() const override {
     return new WorkspaceSingleValue(*this);
   }
+  WorkspaceSingleValue *doCloneEmpty() const override {
+    return new WorkspaceSingleValue();
+  }
 
   // allocates space in a new workspace - does nothing in this case
   void init(const std::size_t &NVectors, const std::size_t &XLength,
             const std::size_t &YLength) override;
+  void init(const std::size_t &NVectors,
+            const HistogramData::Histogram &histogram) override;
 
   /// Instance of Histogram1D that holds the "spectrum" (AKA the single value);
   Histogram1D data{HistogramData::Histogram::XMode::Points,
diff --git a/Framework/DataObjects/src/BoxControllerNeXusIO.cpp b/Framework/DataObjects/src/BoxControllerNeXusIO.cpp
index 89fffca154c889810544ff5e475f8ca27fb763a8..7f26a67ee27d49b1cb415cb0c772db0452639174 100644
--- a/Framework/DataObjects/src/BoxControllerNeXusIO.cpp
+++ b/Framework/DataObjects/src/BoxControllerNeXusIO.cpp
@@ -3,6 +3,7 @@
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/IMDHistoWorkspace.h"
 #include "MantidDataObjects/MDBoxFlatTree.h"
+#include "MantidKernel/ConfigService.h"
 #include "MantidKernel/Exception.h"
 #include "MantidAPI/FileFinder.h"
 #include "MantidDataObjects/MDEvent.h"
diff --git a/Framework/DataObjects/src/EventList.cpp b/Framework/DataObjects/src/EventList.cpp
index c72612926d7b3c127f8e919829f2838726dc552f..5e35cd776a05fac1bd0c61de5ba55b6e722721bd 100644
--- a/Framework/DataObjects/src/EventList.cpp
+++ b/Framework/DataObjects/src/EventList.cpp
@@ -4,6 +4,7 @@
 #include "MantidKernel/DateAndTime.h"
 #include "MantidKernel/Exception.h"
 #include "MantidKernel/Logger.h"
+#include "MantidKernel/Unit.h"
 #include <cfloat>
 
 #include <cmath>
diff --git a/Framework/DataObjects/src/EventWorkspace.cpp b/Framework/DataObjects/src/EventWorkspace.cpp
index 6d8a5f58cf88627cbd99aba82eefb458fa975819..1b4b3b232ddb4377238cc0e48e59707b5eb76235 100644
--- a/Framework/DataObjects/src/EventWorkspace.cpp
+++ b/Framework/DataObjects/src/EventWorkspace.cpp
@@ -2,7 +2,6 @@
 #include "MantidAPI/Run.h"
 #include "MantidAPI/SpectraAxis.h"
 #include "MantidAPI/Progress.h"
-#include "MantidAPI/WorkspaceProperty.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidDataObjects/EventWorkspace.h"
 #include "MantidDataObjects/EventWorkspaceMRU.h"
@@ -101,6 +100,26 @@ void EventWorkspace::init(const std::size_t &NVectors,
   m_axes[1] = new API::SpectraAxis(this);
 }
 
+void EventWorkspace::init(const std::size_t &NVectors,
+                          const HistogramData::Histogram &histogram) {
+  if (histogram.xMode() != HistogramData::Histogram::XMode::BinEdges)
+    throw std::runtime_error(
+        "EventWorkspace can only be initialized with XMode::BinEdges");
+
+  if (histogram.sharedY() || histogram.sharedE())
+    throw std::runtime_error(
+        "EventWorkspace cannot be initialized non-NULL Y or E data");
+
+  data.resize(NVectors, nullptr);
+  for (size_t i = 0; i < NVectors; i++)
+    data[i] = new EventList(mru, specnum_t(i));
+  this->setAllX(histogram.binEdges());
+
+  m_axes.resize(2);
+  m_axes[0] = new API::RefAxis(histogram.x().size(), this);
+  m_axes[1] = new API::SpectraAxis(this);
+}
+
 /// The total size of the workspace
 /// @returns the number of single indexable items in the workspace
 size_t EventWorkspace::size() const {
@@ -707,10 +726,6 @@ void EventWorkspace::getIntegratedSpectra(std::vector<double> &out,
 } // namespace DataObjects
 } // namespace Mantid
 
-///\cond TEMPLATE
-template class DLLExport
-    Mantid::API::WorkspaceProperty<Mantid::DataObjects::EventWorkspace>;
-
 namespace Mantid {
 namespace Kernel {
 template <>
diff --git a/Framework/DataObjects/src/EventWorkspaceHelpers.cpp b/Framework/DataObjects/src/EventWorkspaceHelpers.cpp
index 4bbc3b827f180ee27efa2bd38ebdd6ed098a28b3..5f5416ff5d1565472d36cf1e4d19271ba46d7fdf 100644
--- a/Framework/DataObjects/src/EventWorkspaceHelpers.cpp
+++ b/Framework/DataObjects/src/EventWorkspaceHelpers.cpp
@@ -28,7 +28,7 @@ EventWorkspaceHelpers::convertEventTo2D(MatrixWorkspace_sptr inputMatrixW) {
   MatrixWorkspace_sptr outputW;
   outputW = WorkspaceFactory::Instance().create(
       "Workspace2D", inputW->getNumberHistograms(), numBins + 1, numBins);
-  WorkspaceFactory::Instance().initializeFromParent(inputW, outputW, false);
+  WorkspaceFactory::Instance().initializeFromParent(*inputW, *outputW, false);
 
   // Now let's set all the X bins and values
   for (size_t i = 0; i < inputW->getNumberHistograms(); i++) {
diff --git a/Framework/DataObjects/src/MDBoxFlatTree.cpp b/Framework/DataObjects/src/MDBoxFlatTree.cpp
index 6142e6cc179ec848ab097152b1b8e25a0df6d5aa..7a9232e17ff28a54448c6285e29f13da33762e64 100644
--- a/Framework/DataObjects/src/MDBoxFlatTree.cpp
+++ b/Framework/DataObjects/src/MDBoxFlatTree.cpp
@@ -2,7 +2,9 @@
 #include "MantidDataObjects/MDEventFactory.h"
 #include "MantidAPI/BoxController.h"
 #include "MantidAPI/FileBackedExperimentInfo.h"
+#include "MantidAPI/WorkspaceHistory.h"
 #include "MantidGeometry/Instrument.h"
+#include "MantidKernel/Logger.h"
 #include "MantidKernel/Strings.h"
 #include <Poco/File.h>
 
diff --git a/Framework/DataObjects/src/MDHistoWorkspace.cpp b/Framework/DataObjects/src/MDHistoWorkspace.cpp
index f950aa27beffee21ec1550517f91bdc4093b2f29..0b2c563a92242ce5dc0818927df67bcfac233a72 100644
--- a/Framework/DataObjects/src/MDHistoWorkspace.cpp
+++ b/Framework/DataObjects/src/MDHistoWorkspace.cpp
@@ -632,7 +632,7 @@ IMDWorkspace::LinePlot MDHistoWorkspace::getLinePoints(
     } // for each unique boundary
 
     // If all bins were masked
-    if (line.x.size() == 0) {
+    if (line.x.empty()) {
       this->makeSinglePointWithNaN(line.x, line.y, line.e);
     }
   }
diff --git a/Framework/DataObjects/src/MaskWorkspace.cpp b/Framework/DataObjects/src/MaskWorkspace.cpp
index c7c02b228ba759a69df95448b98ac86915e93d5e..3cf1d52e8899b880e06396da409e44fccdf94200 100644
--- a/Framework/DataObjects/src/MaskWorkspace.cpp
+++ b/Framework/DataObjects/src/MaskWorkspace.cpp
@@ -1,6 +1,7 @@
 #include "MantidDataObjects/MaskWorkspace.h"
 #include "MantidKernel/System.h"
 #include "MantidKernel/IPropertyManager.h"
+#include "MantidAPI/DetectorInfo.h"
 #include "MantidAPI/WorkspaceFactory.h"
 
 namespace Mantid {
@@ -71,8 +72,7 @@ void MaskWorkspace::clearMask() {
   }
 
   // Clear the mask flags
-  Geometry::ParameterMap &pmap = this->instrumentParameters();
-  pmap.clearParametersByName("masked");
+  mutableDetectorInfo().clearMaskFlags();
 }
 
 /**
@@ -95,7 +95,7 @@ size_t MaskWorkspace::getNumberMasked() const {
     } else {
       std::stringstream errss;
       errss << "No instrument is associated with mask workspace "
-            << this->name();
+            << this->getName();
       throw std::runtime_error(errss.str());
     }
   }
@@ -170,7 +170,16 @@ bool MaskWorkspace::isMasked(const detid_t detectorID) const {
   }
 
   // the mask bit on the workspace can be set
-  return this->getInstrument()->isDetectorMasked(detectorID);
+  // Performance wise, it is not optimal to call detectorInfo() for every index,
+  // but this method seems to be used rarely enough to justify this until the
+  // Instrument-2.0 implementation has progressed far enough to make this cheap.
+  const auto &detectorInfo = this->detectorInfo();
+  try {
+    return detectorInfo.isMasked(detectorInfo.indexOf(detectorID));
+  } catch (std::out_of_range &) {
+    // The workspace can contain bad detector IDs. DetectorInfo::indexOf throws.
+    return false;
+  }
 }
 
 /**
diff --git a/Framework/DataObjects/src/PeakColumn.cpp b/Framework/DataObjects/src/PeakColumn.cpp
index 3f1aec2b8effeed15fc6e9bf8642aeea3f396402..3fada157e20d05b84ccd2da2cb86000f040e76cd 100644
--- a/Framework/DataObjects/src/PeakColumn.cpp
+++ b/Framework/DataObjects/src/PeakColumn.cpp
@@ -3,6 +3,7 @@
 #include "MantidKernel/Strings.h"
 #include "MantidKernel/ConfigService.h"
 #include "MantidKernel/Exception.h"
+#include "MantidKernel/MultiThreaded.h"
 
 #include <boost/variant/get.hpp>
 
@@ -164,36 +165,39 @@ void PeakColumn::print(size_t index, std::ostream &s) const {
  */
 void PeakColumn::read(size_t index, const std::string &text) {
   // Don't modify read-only ones
-  if (this->getReadOnly())
+  if (this->getReadOnly() || index >= m_peaks.size())
     return;
 
-  // Avoid going out of bounds
-  if (size_t(index) >= m_peaks.size())
-    return;
-
-  // Reference to the peak in the workspace
-  Peak &peak = m_peaks[index];
-
   // Convert to a double
   double val = 0;
   int success = Strings::convert(text, val);
-  int ival = static_cast<int>(val);
 
   if (success == 0) {
     g_log.error() << "Could not convert string '" << text << "' to a number.\n";
     return;
   }
+  setPeakHKLOrRunNumber(index, val);
+}
 
-  if (m_name == "h")
-    peak.setH(val);
-  else if (m_name == "k")
-    peak.setK(val);
-  else if (m_name == "l")
-    peak.setL(val);
-  else if (m_name == "RunNumber")
-    peak.setRunNumber(ival);
-  else
-    throw std::runtime_error("Unexpected column " + m_name + " being set.");
+/** Read in from stream and convert to a number in the PeaksWorkspace
+ *
+ * @param index :: index of the peak to modify
+ * @param in :: input stream
+ */
+void PeakColumn::read(const size_t index, std::istream &in) {
+  if (this->getReadOnly() || index >= m_peaks.size())
+    return;
+
+  double val;
+  try {
+    in >> val;
+  } catch (std::exception &e) {
+    g_log.error() << "Could not convert input to a number. " << e.what()
+                  << '\n';
+    return;
+  }
+
+  setPeakHKLOrRunNumber(index, val);
 }
 
 //-------------------------------------------------------------------------------------
@@ -320,5 +324,19 @@ void PeakColumn::fromDouble(size_t /*index*/, double /*value*/) {
                            "general write access");
 }
 
+void PeakColumn::setPeakHKLOrRunNumber(const size_t index, const double val) {
+  Peak &peak = m_peaks[index];
+  if (m_name == "h")
+    peak.setH(val);
+  else if (m_name == "k")
+    peak.setK(val);
+  else if (m_name == "l")
+    peak.setL(val);
+  else if (m_name == "RunNumber")
+    peak.setRunNumber(static_cast<int>(val));
+  else
+    throw std::runtime_error("Unexpected column " + m_name + " being set.");
+}
+
 } // namespace Mantid
 } // namespace DataObjects
diff --git a/Framework/DataObjects/src/PeaksWorkspace.cpp b/Framework/DataObjects/src/PeaksWorkspace.cpp
index be71d11980e150a8896017473eaefabf27cbeac8..d6865c24d6fd63740ac956a0c2294b32a2e13035 100644
--- a/Framework/DataObjects/src/PeaksWorkspace.cpp
+++ b/Framework/DataObjects/src/PeaksWorkspace.cpp
@@ -6,7 +6,6 @@
 #include "MantidAPI/Run.h"
 #include "MantidAPI/Sample.h"
 #include "MantidAPI/WorkspaceFactory.h"
-#include "MantidAPI/WorkspaceProperty.h"
 #include "MantidDataObjects/Peak.h"
 #include "MantidDataObjects/TableColumn.h"
 #include "MantidDataObjects/TableWorkspace.h"
diff --git a/Framework/DataObjects/src/PropertyWithValue.cpp b/Framework/DataObjects/src/PropertyWithValue.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..36c5423db9cd69f0088d65ae571db00812cfbbee
--- /dev/null
+++ b/Framework/DataObjects/src/PropertyWithValue.cpp
@@ -0,0 +1,93 @@
+#include "MantidKernel/PropertyWithValue.h"
+#include "MantidDataObjects/DllConfig.h"
+#include "MantidDataObjects/EventWorkspace.h"
+#include "MantidDataObjects/GroupingWorkspace.h"
+#include "MantidDataObjects/MaskWorkspace.h"
+#include "MantidDataObjects/MDEvent.h"
+#include "MantidDataObjects/MDEventWorkspace.h"
+#include "MantidDataObjects/MDHistoWorkspace.h"
+#include "MantidDataObjects/OffsetsWorkspace.h"
+#include "MantidDataObjects/PeaksWorkspace.h"
+#include "MantidDataObjects/RebinnedOutput.h"
+#include "MantidDataObjects/SpecialWorkspace2D.h"
+#include "MantidDataObjects/SplittersWorkspace.h"
+#include "MantidDataObjects/TableWorkspace.h"
+#include "MantidDataObjects/Workspace2D.h"
+#include "MantidDataObjects/WorkspaceSingleValue.h"
+
+// PropertyWithValue implementation
+#include "MantidKernel/PropertyWithValue.tcc"
+
+namespace Mantid {
+namespace DataObjects {
+template <size_t nd> using MDEventWS = MDEventWorkspace<MDEvent<nd>, nd>;
+template <size_t nd>
+using MDLeanEventWS = MDEventWorkspace<MDLeanEvent<nd>, nd>;
+}
+namespace Kernel {
+
+/// @cond
+template class MANTID_DATAOBJECTS_DLL
+    PropertyWithValue<boost::shared_ptr<DataObjects::EventWorkspace>>;
+template class MANTID_DATAOBJECTS_DLL
+    PropertyWithValue<boost::shared_ptr<DataObjects::GroupingWorkspace>>;
+template class MANTID_DATAOBJECTS_DLL
+    PropertyWithValue<boost::shared_ptr<DataObjects::MaskWorkspace>>;
+template class MANTID_DATAOBJECTS_DLL
+    PropertyWithValue<boost::shared_ptr<DataObjects::MDEventWS<1>>>;
+template class MANTID_DATAOBJECTS_DLL
+    PropertyWithValue<boost::shared_ptr<DataObjects::MDEventWS<2>>>;
+template class MANTID_DATAOBJECTS_DLL
+    PropertyWithValue<boost::shared_ptr<DataObjects::MDEventWS<3>>>;
+template class MANTID_DATAOBJECTS_DLL
+    PropertyWithValue<boost::shared_ptr<DataObjects::MDEventWS<4>>>;
+template class MANTID_DATAOBJECTS_DLL
+    PropertyWithValue<boost::shared_ptr<DataObjects::MDEventWS<5>>>;
+template class MANTID_DATAOBJECTS_DLL
+    PropertyWithValue<boost::shared_ptr<DataObjects::MDEventWS<6>>>;
+template class MANTID_DATAOBJECTS_DLL
+    PropertyWithValue<boost::shared_ptr<DataObjects::MDEventWS<7>>>;
+template class MANTID_DATAOBJECTS_DLL
+    PropertyWithValue<boost::shared_ptr<DataObjects::MDEventWS<8>>>;
+template class MANTID_DATAOBJECTS_DLL
+    PropertyWithValue<boost::shared_ptr<DataObjects::MDEventWS<9>>>;
+template class MANTID_DATAOBJECTS_DLL
+    PropertyWithValue<boost::shared_ptr<DataObjects::MDLeanEventWS<1>>>;
+template class MANTID_DATAOBJECTS_DLL
+    PropertyWithValue<boost::shared_ptr<DataObjects::MDLeanEventWS<2>>>;
+template class MANTID_DATAOBJECTS_DLL
+    PropertyWithValue<boost::shared_ptr<DataObjects::MDLeanEventWS<3>>>;
+template class MANTID_DATAOBJECTS_DLL
+    PropertyWithValue<boost::shared_ptr<DataObjects::MDLeanEventWS<4>>>;
+template class MANTID_DATAOBJECTS_DLL
+    PropertyWithValue<boost::shared_ptr<DataObjects::MDLeanEventWS<5>>>;
+template class MANTID_DATAOBJECTS_DLL
+    PropertyWithValue<boost::shared_ptr<DataObjects::MDLeanEventWS<6>>>;
+template class MANTID_DATAOBJECTS_DLL
+    PropertyWithValue<boost::shared_ptr<DataObjects::MDLeanEventWS<7>>>;
+template class MANTID_DATAOBJECTS_DLL
+    PropertyWithValue<boost::shared_ptr<DataObjects::MDLeanEventWS<8>>>;
+template class MANTID_DATAOBJECTS_DLL
+    PropertyWithValue<boost::shared_ptr<DataObjects::MDLeanEventWS<9>>>;
+template class MANTID_DATAOBJECTS_DLL
+    PropertyWithValue<boost::shared_ptr<DataObjects::MDHistoWorkspace>>;
+template class MANTID_DATAOBJECTS_DLL
+    PropertyWithValue<boost::shared_ptr<DataObjects::OffsetsWorkspace>>;
+template class MANTID_DATAOBJECTS_DLL
+    PropertyWithValue<boost::shared_ptr<DataObjects::PeaksWorkspace>>;
+template class MANTID_DATAOBJECTS_DLL
+    PropertyWithValue<boost::shared_ptr<DataObjects::RebinnedOutput>>;
+template class MANTID_DATAOBJECTS_DLL
+    PropertyWithValue<boost::shared_ptr<DataObjects::SpecialWorkspace2D>>;
+template class MANTID_DATAOBJECTS_DLL
+    PropertyWithValue<boost::shared_ptr<DataObjects::SplittersWorkspace>>;
+template class MANTID_DATAOBJECTS_DLL
+    PropertyWithValue<boost::shared_ptr<DataObjects::TableWorkspace>>;
+template class MANTID_DATAOBJECTS_DLL
+    PropertyWithValue<boost::shared_ptr<DataObjects::Workspace2D>>;
+template class MANTID_DATAOBJECTS_DLL
+    PropertyWithValue<boost::shared_ptr<DataObjects::WorkspaceSingleValue>>;
+/// @endcond
+
+} // namespace Kernel
+} // namespace Mantid
diff --git a/Framework/DataObjects/src/RebinnedOutput.cpp b/Framework/DataObjects/src/RebinnedOutput.cpp
index f4e3246f07865abbd6fedccaac9f0b592760bccb..90fbbc7f869865847e584931a98586dd077ab55a 100644
--- a/Framework/DataObjects/src/RebinnedOutput.cpp
+++ b/Framework/DataObjects/src/RebinnedOutput.cpp
@@ -1,8 +1,11 @@
 #include "MantidDataObjects/RebinnedOutput.h"
 
 #include "MantidAPI/WorkspaceFactory.h"
+#include "MantidKernel/Logger.h"
 
 #include <algorithm>
+#include <iterator>
+#include <sstream>
 
 namespace Mantid {
 namespace DataObjects {
@@ -39,6 +42,16 @@ void RebinnedOutput::init(const std::size_t &NVectors,
   }
 }
 
+void RebinnedOutput::init(const std::size_t &NVectors,
+                          const HistogramData::Histogram &histogram) {
+  Workspace2D::init(NVectors, histogram);
+  std::size_t nHist = this->getNumberHistograms();
+  this->fracArea.resize(nHist);
+  for (std::size_t i = 0; i < nHist; ++i) {
+    this->fracArea[i].resize(histogram.size());
+  }
+}
+
 /**
  * Function that returns a fractional area array for a given index.
  * @param index :: the array to fetch
diff --git a/Framework/DataObjects/src/ReflectometryTransform.cpp b/Framework/DataObjects/src/ReflectometryTransform.cpp
index b328094282f0cc81d7d26c4adcf510d76f4e6333..0ad378d335a3967e6ea65ac5d7b7fb28ca97e03b 100644
--- a/Framework/DataObjects/src/ReflectometryTransform.cpp
+++ b/Framework/DataObjects/src/ReflectometryTransform.cpp
@@ -1,8 +1,10 @@
 #include "MantidDataObjects/ReflectometryTransform.h"
 
 #include "MantidAPI/BinEdgeAxis.h"
+#include "MantidAPI/DetectorInfo.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/SpectrumDetectorMapping.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidAPI/TableRow.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidDataObjects/CalculateReflectometry.h"
@@ -15,6 +17,8 @@
 #include "MantidGeometry/Instrument/DetectorGroup.h"
 #include "MantidGeometry/Instrument/ReferenceFrame.h"
 #include "MantidGeometry/MDGeometry/MDHistoDimension.h"
+#include "MantidGeometry/Objects/BoundingBox.h"
+#include "MantidGeometry/Objects/Object.h"
 #include "MantidKernel/Unit.h"
 #include "MantidKernel/UnitFactory.h"
 #include "MantidKernel/V2D.h"
@@ -215,29 +219,20 @@ DetectorAngularCache initAngularCaches(const MatrixWorkspace *const workspace) {
   std::vector<double> detectorHeights(nhist);
 
   auto inst = workspace->getInstrument();
-  const auto samplePos = inst->getSample()->getPos();
   const V3D upDirVec = inst->getReferenceFrame()->vecPointingUp();
 
-  for (size_t i = 0; i < nhist; ++i) // signed for OpenMP
-  {
-    IDetector_const_sptr det;
-    try {
-      det = workspace->getDetector(i);
-    } catch (Exception::NotFoundError &) {
-      // Catch if no detector. Next line tests whether this happened - test
-      // placed
-      // outside here because Mac Intel compiler doesn't like 'continue' in a
-      // catch
-      // in an openmp block.
-    }
-    // If no detector found, skip onto the next spectrum
-    if (!det || det->isMonitor()) {
+  const auto &spectrumInfo = workspace->spectrumInfo();
+  const auto &detectorInfo = workspace->detectorInfo();
+  for (size_t i = 0; i < nhist; ++i) {
+    if (!spectrumInfo.hasDetectors(i) || spectrumInfo.isMonitor(i)) {
+      // If no detector found, skip onto the next spectrum
       thetas[i] = -1.0; // Indicates a detector to skip
       thetaWidths[i] = -1.0;
       continue;
     }
+
     // We have to convert theta from radians to degrees
-    const double theta = workspace->detectorSignedTwoTheta(*det) * rad2deg;
+    const double theta = spectrumInfo.signedTwoTheta(i) * rad2deg;
     thetas[i] = theta;
     /**
      * Determine width from shape geometry. A group is assumed to contain
@@ -245,17 +240,15 @@ DetectorAngularCache initAngularCaches(const MatrixWorkspace *const workspace) {
      * The shape is retrieved and rotated to match the rotation of the detector.
      * The angular width is computed using the l2 distance from the sample
      */
-    if (auto group = boost::dynamic_pointer_cast<const DetectorGroup>(det)) {
-      // assume they all have same shape and same r,theta
-      auto dets = group->getDetectors();
-      det = dets[0];
-    }
-    const auto pos = det->getPos() - samplePos;
-    double l2(0.0), t(0.0), p(0.0);
-    pos.getSpherical(l2, t, p);
+    // If the spectrum is based on a group of detectors assume they all have
+    // same shape and same r,theta
+    // DetectorGroup::getID gives ID of first detector.
+    size_t detIndex = detectorInfo.indexOf(spectrumInfo.detector(i).getID());
+    double l2 = detectorInfo.l2(detIndex);
     // Get the shape
     auto shape =
-        det->shape(); // Defined in its own reference frame with centre at 0,0,0
+        detectorInfo.detector(detIndex)
+            .shape(); // Defined in its own reference frame with centre at 0,0,0
     BoundingBox bbox = shape->getBoundingBox();
     auto maxPoint(bbox.maxPoint());
     auto minPoint(bbox.minPoint());
@@ -464,11 +457,13 @@ MatrixWorkspace_sptr ReflectometryTransform::executeNormPoly(
   std::vector<detid_t> detIDMapping;
   // Create a table for the output if we want to debug vertex positioning
   addColumnHeadings(*vertexes, outputDimensions);
+  const auto &spectrumInfo = inputWS->spectrumInfo();
   for (size_t i = 0; i < nHistos; ++i) {
-    IDetector_const_sptr detector = inputWS->getDetector(i);
-    if (!detector || detector->isMasked() || detector->isMonitor()) {
+    if (!spectrumInfo.hasDetectors(i) || spectrumInfo.isMasked(i) ||
+        spectrumInfo.isMonitor(i)) {
       continue;
     }
+    const auto &detector = spectrumInfo.detector(i);
 
     // Compute polygon points
     const double theta = m_theta[i];
@@ -498,7 +493,7 @@ MatrixWorkspace_sptr ReflectometryTransform::executeNormPoly(
         // Add this spectra-detector pair to the mapping
         specNumberMapping.push_back(
             outWS->getSpectrum(qIndex - 1).getSpectrumNo());
-        detIDMapping.push_back(detector->getID());
+        detIDMapping.push_back(detector.getID());
       }
       // Debugging
       if (dumpVertexes) {
diff --git a/Framework/DataObjects/src/SpecialWorkspace2D.cpp b/Framework/DataObjects/src/SpecialWorkspace2D.cpp
index b020af133589438d76fa557b645bb5d8949896c6..1aa16d8c2b7822bf250fe3475e2bbd2767e06115 100644
--- a/Framework/DataObjects/src/SpecialWorkspace2D.cpp
+++ b/Framework/DataObjects/src/SpecialWorkspace2D.cpp
@@ -56,8 +56,7 @@ SpecialWorkspace2D::SpecialWorkspace2D(Geometry::Instrument_const_sptr inst,
  */
 SpecialWorkspace2D::SpecialWorkspace2D(API::MatrixWorkspace_const_sptr parent) {
   this->init(parent->getNumberHistograms(), 1, 1);
-  API::WorkspaceFactory::Instance().initializeFromParent(
-      parent, API::MatrixWorkspace_sptr(this, Mantid::NoDeleting()), false);
+  API::WorkspaceFactory::Instance().initializeFromParent(*parent, *this, false);
   // Make the mapping, which will be used for speed later.
   detID_to_WI.clear();
   for (size_t wi = 0; wi < m_noVectors; wi++) {
@@ -84,6 +83,17 @@ void SpecialWorkspace2D::init(const size_t &NVectors, const size_t &XLength,
   Workspace2D::init(NVectors, XLength, YLength);
 }
 
+void SpecialWorkspace2D::init(const size_t &NVectors,
+                              const HistogramData::Histogram &histogram) {
+  if (histogram.xMode() != HistogramData::Histogram::XMode::Points)
+    throw std::runtime_error(
+        "SpecialWorkspace2D can only be initialized with XMode::Points");
+  if (histogram.x().size() != 1)
+    throw std::runtime_error(
+        "SpecialWorkspace2D can only be initialized with length 1");
+  Workspace2D::init(NVectors, histogram);
+}
+
 /**
  * @return A string containing the workspace description
  */
diff --git a/Framework/DataObjects/src/TableWorkspace.cpp b/Framework/DataObjects/src/TableWorkspace.cpp
index 96da4a3cbb5269daedc8765cfbd180b2155bddb4..922824f35c203e4a6f662595bb91098fda995b81 100644
--- a/Framework/DataObjects/src/TableWorkspace.cpp
+++ b/Framework/DataObjects/src/TableWorkspace.cpp
@@ -1,7 +1,6 @@
 #include "MantidDataObjects/TableWorkspace.h"
 #include "MantidKernel/Logger.h"
 #include "MantidAPI/ColumnFactory.h"
-#include "MantidAPI/WorkspaceProperty.h"
 #include "MantidAPI/WorkspaceFactory.h"
 
 #include <queue>
diff --git a/Framework/DataObjects/src/Workspace2D.cpp b/Framework/DataObjects/src/Workspace2D.cpp
index 03e93c5c9e4781c84ac34d4b677b5d83d9be9162..3f4482c707edc106dabe9dd39422ce628ad927bb 100644
--- a/Framework/DataObjects/src/Workspace2D.cpp
+++ b/Framework/DataObjects/src/Workspace2D.cpp
@@ -3,7 +3,6 @@
 #include "MantidKernel/Exception.h"
 #include "MantidAPI/RefAxis.h"
 #include "MantidAPI/SpectraAxis.h"
-#include "MantidAPI/WorkspaceProperty.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidAPI/ISpectrum.h"
 #include "MantidKernel/VectorHelper.h"
@@ -22,7 +21,7 @@ DECLARE_WORKSPACE(Workspace2D)
 Workspace2D::Workspace2D() : m_noVectors(0) {}
 
 Workspace2D::Workspace2D(const Workspace2D &other)
-    : MatrixWorkspace(other), m_noVectors(other.m_noVectors),
+    : HistoWorkspace(other), m_noVectors(other.m_noVectors),
       m_monitorList(other.m_monitorList) {
   data.resize(m_noVectors);
 
@@ -96,6 +95,38 @@ void Workspace2D::init(const std::size_t &NVectors, const std::size_t &XLength,
   m_axes[1] = new API::SpectraAxis(this);
 }
 
+void Workspace2D::init(const std::size_t &NVectors,
+                       const HistogramData::Histogram &histogram) {
+  m_noVectors = NVectors;
+  data.resize(m_noVectors);
+
+  HistogramData::Histogram initializedHistogram(histogram);
+  if (!histogram.sharedY()) {
+    if (histogram.yMode() == HistogramData::Histogram::YMode::Frequencies) {
+      initializedHistogram.setFrequencies(histogram.size(), 0.0);
+      initializedHistogram.setFrequencyStandardDeviations(histogram.size(),
+                                                          0.0);
+    } else { // YMode::Counts or YMode::Uninitialized -> default to Counts
+      initializedHistogram.setCounts(histogram.size(), 0.0);
+      initializedHistogram.setCountStandardDeviations(histogram.size(), 0.0);
+    }
+  }
+
+  for (size_t i = 0; i < m_noVectors; i++) {
+    data[i] = new Histogram1D(initializedHistogram.xMode(),
+                              initializedHistogram.yMode());
+    data[i]->setHistogram(initializedHistogram);
+    // Default spectrum number = starts at 1, for workspace index 0.
+    data[i]->setSpectrumNo(specnum_t(i + 1));
+    data[i]->setDetectorID(detid_t(i + 1));
+  }
+
+  // Add axes that reference the data
+  m_axes.resize(2);
+  m_axes[0] = new API::RefAxis(initializedHistogram.x().size(), this);
+  m_axes[1] = new API::SpectraAxis(this);
+}
+
 /** Gets the number of histograms
 @return Integer
 */
@@ -319,10 +350,6 @@ void Workspace2D::generateHistogram(const std::size_t index, const MantidVec &X,
 } // namespace DataObjects
 } // NamespaceMantid
 
-///\cond TEMPLATE
-template class DLLExport
-    Mantid::API::WorkspaceProperty<Mantid::DataObjects::Workspace2D>;
-
 namespace Mantid {
 namespace Kernel {
 template <>
diff --git a/Framework/DataObjects/src/WorkspaceCreation.cpp b/Framework/DataObjects/src/WorkspaceCreation.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f2d68768223694c620a2fd21173cdca264cbd3fd
--- /dev/null
+++ b/Framework/DataObjects/src/WorkspaceCreation.cpp
@@ -0,0 +1,50 @@
+#include "MantidKernel/make_unique.h"
+#include "MantidAPI/WorkspaceFactory.h"
+#include "MantidDataObjects/EventWorkspace.h"
+#include "MantidDataObjects/WorkspaceCreation.h"
+#include "MantidDataObjects/Workspace2D.h"
+
+namespace Mantid {
+namespace DataObjects {
+namespace detail {
+HistogramData::Histogram stripData(HistogramData::Histogram histogram) {
+  histogram.setSharedY(nullptr);
+  histogram.setSharedE(nullptr);
+  return histogram;
+}
+
+template <> std::unique_ptr<EventWorkspace> createHelper() { return {nullptr}; }
+
+template <> std::unique_ptr<API::HistoWorkspace> createHelper() {
+  return Kernel::make_unique<Workspace2D>();
+}
+
+template <> std::unique_ptr<API::MatrixWorkspace> createHelper() {
+  return {nullptr};
+}
+
+template <> std::unique_ptr<API::MatrixWorkspace> createConcreteHelper() {
+  throw std::runtime_error(
+      "Attempt to create instance of abstract type MatrixWorkspace");
+  return {nullptr};
+}
+template <> std::unique_ptr<API::HistoWorkspace> createConcreteHelper() {
+  throw std::runtime_error(
+      "Attempt to create instance of abstract type HistoWorkspace");
+  return {nullptr};
+}
+
+void initializeFromParent(const API::MatrixWorkspace &parent,
+                          API::MatrixWorkspace &ws) {
+  bool differentSize = (parent.x(0).size() != ws.x(0).size()) ||
+                       (parent.y(0).size() != ws.y(0).size());
+  API::WorkspaceFactory::Instance().initializeFromParent(parent, ws,
+                                                         differentSize);
+  // For EventWorkspace, `ws.y(0)` put entry 0 in the MRU. However, clients
+  // would typically expect an empty MRU and fail to clear it. This dummy call
+  // removes the entry from the MRU.
+  static_cast<void>(ws.mutableX(0));
+}
+}
+} // namespace DataObjects
+} // namespace Mantid
diff --git a/Framework/DataObjects/src/WorkspaceProperty.cpp b/Framework/DataObjects/src/WorkspaceProperty.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d41fc73723bfda83d6040ec06bea5e2ec88bdfe5
--- /dev/null
+++ b/Framework/DataObjects/src/WorkspaceProperty.cpp
@@ -0,0 +1,42 @@
+#include "MantidDataObjects/EventWorkspace.h"
+#include "MantidDataObjects/GroupingWorkspace.h"
+#include "MantidDataObjects/MaskWorkspace.h"
+#include "MantidDataObjects/OffsetsWorkspace.h"
+#include "MantidDataObjects/PeaksWorkspace.h"
+#include "MantidDataObjects/SpecialWorkspace2D.h"
+#include "MantidDataObjects/SplittersWorkspace.h"
+#include "MantidDataObjects/TableWorkspace.h"
+#include "MantidDataObjects/Workspace2D.h"
+#include "MantidDataObjects/WorkspaceSingleValue.h"
+
+// WorkspaceProperty implementation
+#include "MantidAPI/WorkspaceProperty.tcc"
+
+namespace Mantid {
+// Note that this file is part of DataObjects, but we are injecting explicit
+// instantiations into API. This does not extend or modify API.
+namespace API {
+///@cond TEMPLATE
+template class MANTID_DATAOBJECTS_DLL
+    Mantid::API::WorkspaceProperty<Mantid::DataObjects::EventWorkspace>;
+template class MANTID_DATAOBJECTS_DLL
+    Mantid::API::WorkspaceProperty<Mantid::DataObjects::SpecialWorkspace2D>;
+template class MANTID_DATAOBJECTS_DLL
+    Mantid::API::WorkspaceProperty<Mantid::DataObjects::SplittersWorkspace>;
+template class MANTID_DATAOBJECTS_DLL
+    Mantid::API::WorkspaceProperty<Mantid::DataObjects::TableWorkspace>;
+template class MANTID_DATAOBJECTS_DLL
+    Mantid::API::WorkspaceProperty<Mantid::DataObjects::Workspace2D>;
+template class MANTID_DATAOBJECTS_DLL
+    Mantid::API::WorkspaceProperty<Mantid::DataObjects::WorkspaceSingleValue>;
+template class MANTID_DATAOBJECTS_DLL
+    Mantid::API::WorkspaceProperty<Mantid::DataObjects::GroupingWorkspace>;
+template class MANTID_DATAOBJECTS_DLL
+    Mantid::API::WorkspaceProperty<Mantid::DataObjects::PeaksWorkspace>;
+template class MANTID_DATAOBJECTS_DLL
+    Mantid::API::WorkspaceProperty<Mantid::DataObjects::MaskWorkspace>;
+template class MANTID_DATAOBJECTS_DLL
+    Mantid::API::WorkspaceProperty<Mantid::DataObjects::OffsetsWorkspace>;
+///@endcond TEMPLATE
+} // namespace API
+} // namespace Mantid
diff --git a/Framework/DataObjects/src/WorkspaceSingleValue.cpp b/Framework/DataObjects/src/WorkspaceSingleValue.cpp
index 2181ee3857635f79c373efb36abbd947ffc755a5..579545de25425d1d6bf32a54f199e73881568688 100644
--- a/Framework/DataObjects/src/WorkspaceSingleValue.cpp
+++ b/Framework/DataObjects/src/WorkspaceSingleValue.cpp
@@ -1,5 +1,4 @@
 #include "MantidDataObjects/WorkspaceSingleValue.h"
-#include "MantidAPI/WorkspaceProperty.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidKernel/IPropertyManager.h"
 
@@ -12,7 +11,7 @@ DECLARE_WORKSPACE(WorkspaceSingleValue)
 
 /// Constructor
 WorkspaceSingleValue::WorkspaceSingleValue(double value, double error)
-    : API::MatrixWorkspace() {
+    : API::HistoWorkspace() {
   // Set the "histogram" to the single value
   data.dataX().resize(1, 0.0);
   data.setCounts(1, value);
@@ -23,7 +22,7 @@ WorkspaceSingleValue::WorkspaceSingleValue(double value, double error)
 }
 
 WorkspaceSingleValue::WorkspaceSingleValue(const WorkspaceSingleValue &other)
-    : MatrixWorkspace(other), data(other.data) {
+    : HistoWorkspace(other), data(other.data) {
   setDistribution(true);
 }
 
@@ -41,6 +40,12 @@ void WorkspaceSingleValue::init(const std::size_t &NVectors,
   (void)YLength; // Avoid compiler warning
 }
 
+void WorkspaceSingleValue::init(const std::size_t &NVectors,
+                                const HistogramData::Histogram &histogram) {
+  UNUSED_ARG(NVectors);
+  UNUSED_ARG(histogram);
+}
+
 /// Return the underlying Histogram1D at the given workspace index.
 Histogram1D &WorkspaceSingleValue::getSpectrum(const size_t /*index*/) {
   return data;
@@ -72,11 +77,6 @@ size_t WorkspaceSingleValue::getNumDims() const { return 0; }
 } // namespace DataObjects
 } // namespace Mantid
 
-///\cond TEMPLATE
-
-template class DLLExport
-    Mantid::API::WorkspaceProperty<Mantid::DataObjects::WorkspaceSingleValue>;
-
 namespace Mantid {
 namespace Kernel {
 template <>
diff --git a/Framework/DataObjects/test/CMakeLists.txt b/Framework/DataObjects/test/CMakeLists.txt
index 01b57ac5a341e3a713992eca98ab6e85c4761253..3befa081181d6d7441297a41a954bd4c0bd94b4e 100644
--- a/Framework/DataObjects/test/CMakeLists.txt
+++ b/Framework/DataObjects/test/CMakeLists.txt
@@ -12,6 +12,7 @@ if ( CXXTEST_FOUND )
                         ../../TestHelpers/src/MDEventsTestHelper.cpp 
                         ../../TestHelpers/src/ScopedFileHelper.cpp
                         ../../TestHelpers/src/BoxControllerDummyIO.cpp
+                        ../../TestHelpers/src/FakeObjects.cpp
   )
 
   cxxtest_add_test ( DataObjectsTest ${TEST_FILES} )
@@ -20,6 +21,7 @@ if ( CXXTEST_FOUND )
             DataObjects
             Geometry
             HistogramData
+            Indexing
             Kernel
             ${NEXUS_LIBRARIES}
             ${JSONCPP_LIBRARIES}
diff --git a/Framework/DataObjects/test/EventListTest.h b/Framework/DataObjects/test/EventListTest.h
index 91b705a1afcac555dce10bb04c4997899904a3d7..84d8211b8bc56cb015fdb92144f18af9fe7af847 100644
--- a/Framework/DataObjects/test/EventListTest.h
+++ b/Framework/DataObjects/test/EventListTest.h
@@ -6,6 +6,7 @@
 #include "MantidDataObjects/EventWorkspace.h"
 #include "MantidKernel/Timer.h"
 #include "MantidKernel/CPUTimer.h"
+#include "MantidKernel/Unit.h"
 
 #include <boost/scoped_ptr.hpp>
 #include <cmath>
diff --git a/Framework/DataObjects/test/EventWorkspaceTest.h b/Framework/DataObjects/test/EventWorkspaceTest.h
index 9bb026d442bbbbf2be54425d6ef8082e6de21ac4..73024a94bcbd99ca2b6f2e1b84b199a5d9f778e9 100644
--- a/Framework/DataObjects/test/EventWorkspaceTest.h
+++ b/Framework/DataObjects/test/EventWorkspaceTest.h
@@ -17,6 +17,7 @@
 
 #include "MantidHistogramData/LinearGenerator.h"
 #include "MantidAPI/Axis.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidDataObjects/EventList.h"
 #include "MantidDataObjects/EventWorkspace.h"
 #include "MantidTestHelpers/WorkspaceCreationHelper.h"
@@ -169,7 +170,8 @@ public:
         WorkspaceCreationHelper::createEventWorkspaceWithFullInstrument(
             1, 10, false /*dont clear the events*/);
     TS_ASSERT_EQUALS(ws->getSpectrum(2).getNumberEvents(), 200);
-    ws->maskWorkspaceIndex(2);
+    ws->getSpectrum(2).clearData();
+    ws->mutableSpectrumInfo().setMasked(2, true);
     TS_ASSERT_EQUALS(ws->getSpectrum(2).getNumberEvents(), 0);
   }
 
@@ -533,7 +535,7 @@ public:
 
   void test_sortAll_TOF() {
     EventWorkspace_sptr test_in =
-        WorkspaceCreationHelper::CreateRandomEventWorkspace(NUMBINS, NUMPIXELS);
+        WorkspaceCreationHelper::createRandomEventWorkspace(NUMBINS, NUMPIXELS);
     Progress *prog = NULL;
 
     test_in->sortAll(TOF_SORT, prog);
@@ -553,7 +555,7 @@ public:
   void test_sortAll_SingleEventList() {
     int numEvents = 30;
     EventWorkspace_sptr test_in =
-        WorkspaceCreationHelper::CreateRandomEventWorkspace(numEvents, 1);
+        WorkspaceCreationHelper::createRandomEventWorkspace(numEvents, 1);
     Progress *prog = NULL;
 
     test_in->sortAll(TOF_SORT, prog);
@@ -571,7 +573,7 @@ public:
   void test_sortAll_byTime_SingleEventList() {
     int numEvents = 30;
     EventWorkspace_sptr test_in =
-        WorkspaceCreationHelper::CreateRandomEventWorkspace(numEvents, 1);
+        WorkspaceCreationHelper::createRandomEventWorkspace(numEvents, 1);
     Progress *prog = NULL;
 
     test_in->sortAll(PULSETIME_SORT, prog);
@@ -585,7 +587,7 @@ public:
 
   void test_sortAll_ByTime() {
     EventWorkspace_sptr test_in =
-        WorkspaceCreationHelper::CreateRandomEventWorkspace(NUMBINS, NUMPIXELS);
+        WorkspaceCreationHelper::createRandomEventWorkspace(NUMBINS, NUMPIXELS);
     Progress *prog = NULL;
 
     test_in->sortAll(PULSETIME_SORT, prog);
@@ -608,7 +610,7 @@ public:
   {
     int numpix = 100000;
     EventWorkspace_const_sptr ew1 =
-        WorkspaceCreationHelper::CreateRandomEventWorkspace(50, numpix);
+        WorkspaceCreationHelper::createRandomEventWorkspace(50, numpix);
 
     PARALLEL_FOR_NO_WSP_CHECK()
     for (int i = 0; i < numpix; i++) {
@@ -625,7 +627,7 @@ public:
     // 50 pixels, 100 bins, 2 events in each
     int numpixels = 900;
     EventWorkspace_sptr ew1 =
-        WorkspaceCreationHelper::CreateEventWorkspace2(numpixels, 100);
+        WorkspaceCreationHelper::createEventWorkspace2(numpixels, 100);
     PARALLEL_FOR_IF(do_parallel)
     for (int i = 0; i < numpixels; i += 3) {
       const MantidVec &Y = ew1->readY(i);
@@ -731,7 +733,7 @@ public:
     int numEvents = 2;
     int numHistograms = 2;
     EventWorkspace_sptr ws =
-        WorkspaceCreationHelper::CreateRandomEventWorkspace(numEvents,
+        WorkspaceCreationHelper::createRandomEventWorkspace(numEvents,
                                                             numHistograms);
     // Calling isCommonBins() sets the flag m_isCommonBinsFlagSet
     TS_ASSERT(ws->isCommonBins());
@@ -750,7 +752,7 @@ public:
     int numEvents = 2;
     int numHistograms = 2;
     EventWorkspace_const_sptr ws =
-        WorkspaceCreationHelper::CreateRandomEventWorkspace(numEvents,
+        WorkspaceCreationHelper::createRandomEventWorkspace(numEvents,
                                                             numHistograms);
     TS_ASSERT_THROWS_NOTHING(ws->readY(0));
     TS_ASSERT_THROWS_NOTHING(ws->dataY(0));
@@ -762,7 +764,7 @@ public:
     int numEvents = 2;
     int numHistograms = 2;
     EventWorkspace_const_sptr ws =
-        WorkspaceCreationHelper::CreateRandomEventWorkspace(numEvents,
+        WorkspaceCreationHelper::createRandomEventWorkspace(numEvents,
                                                             numHistograms);
     auto hist1 = ws->histogram(0);
     auto hist2 = ws->histogram(0);
@@ -773,7 +775,7 @@ public:
   }
 
   void test_clearing_EventList_clears_MRU() {
-    auto ws = WorkspaceCreationHelper::CreateRandomEventWorkspace(2, 1);
+    auto ws = WorkspaceCreationHelper::createRandomEventWorkspace(2, 1);
     auto y = ws->sharedY(0);
     TS_ASSERT_EQUALS(y.use_count(), 2);
     ws->getSpectrum(0).clear();
@@ -784,7 +786,7 @@ public:
     int numEvents = 2;
     int numHistograms = 2;
     EventWorkspace_sptr ws =
-        WorkspaceCreationHelper::CreateRandomEventWorkspace(numEvents,
+        WorkspaceCreationHelper::createRandomEventWorkspace(numEvents,
                                                             numHistograms);
     // put two items into MRU
     auto &yOld0 = ws->y(0);
@@ -802,7 +804,7 @@ public:
   }
 
   void test_deleting_spectra_removes_them_from_MRU() {
-    auto ws = WorkspaceCreationHelper::CreateRandomEventWorkspace(2, 1);
+    auto ws = WorkspaceCreationHelper::createRandomEventWorkspace(2, 1);
     auto y = ws->sharedY(0);
     TS_ASSERT_EQUALS(y.use_count(), 2);
 
diff --git a/Framework/DataObjects/test/MDBoxBaseTest.h b/Framework/DataObjects/test/MDBoxBaseTest.h
index 4e85de4680582f92f6039656d47055a7a8cdca21..40633ee09731c8caa5479f8fdd8cb3751ed9d0fb 100644
--- a/Framework/DataObjects/test/MDBoxBaseTest.h
+++ b/Framework/DataObjects/test/MDBoxBaseTest.h
@@ -118,7 +118,8 @@ public:
   coord_t *getCentroid() const override { return 0; };
   void integrateSphere(Mantid::API::CoordTransform & /*radiusTransform*/,
                        const coord_t /*radiusSquared*/, signal_t & /*signal*/,
-                       signal_t & /*errorSquared*/) const override{};
+                       signal_t & /*errorSquared*/,
+                       const coord_t /*innerRadiusSquared*/) const override{};
   void centroidSphere(Mantid::API::CoordTransform & /*radiusTransform*/,
                       const coord_t /*radiusSquared*/, coord_t *,
                       signal_t &) const override{};
diff --git a/Framework/DataObjects/test/PeakColumnTest.h b/Framework/DataObjects/test/PeakColumnTest.h
index 3ca0e7870f7f36c04c3492afa2dd5a2431f3f60d..435c34867648c60438ac14b7e7e6fe5e507476c0 100644
--- a/Framework/DataObjects/test/PeakColumnTest.h
+++ b/Framework/DataObjects/test/PeakColumnTest.h
@@ -9,6 +9,7 @@
 #include "MantidTestHelpers/ComponentCreationHelper.h"
 
 #include <boost/make_shared.hpp>
+#include <locale>
 
 using namespace Mantid::DataObjects;
 
@@ -116,7 +117,53 @@ public:
     TS_ASSERT(readOnly);
   }
 
+  void test_read_locale_awerness() {
+    const std::vector<std::string> columnNames{"h", "k", "l", "RunNumber"};
+    const std::vector<double> columnValues{-2.0, 5.0, 12.0, 143290.0};
+    TestingNumpunctFacet numpunct;
+    const std::locale testLocale(std::locale::classic(), &numpunct);
+    for (size_t i = 0; i < columnNames.size(); ++i) {
+      PeakColumn pc(m_peaks, columnNames[i]);
+      // Use a fake punctuation facet for numeric formatting.
+      std::ostringstream out;
+      out.imbue(testLocale);
+      // Force some decimals to the numbers.
+      out << std::fixed;
+      out << std::setprecision(2);
+      out << columnValues[i];
+      std::istringstream in(out.str());
+      in.imbue(testLocale);
+      pc.read(0, in);
+      switch (i) {
+      case 0:
+        TS_ASSERT_EQUALS(m_peaks[0].getH(), columnValues[i])
+        break;
+      case 1:
+        TS_ASSERT_EQUALS(m_peaks[0].getK(), columnValues[i])
+        break;
+      case 2:
+        TS_ASSERT_EQUALS(m_peaks[0].getL(), columnValues[i])
+        break;
+      case 3:
+        TS_ASSERT_EQUALS(m_peaks[0].getRunNumber(), columnValues[i])
+        break;
+      }
+    }
+  }
+
 private:
+  /// A locale facet mocking non-english numerical punctuation.
+  class TestingNumpunctFacet : public std::numpunct<char> {
+  public:
+    /// Informs locales not to delete this facet.
+    TestingNumpunctFacet() : std::numpunct<char>(1) {}
+
+  private:
+    char_type do_decimal_point() const override { return '%'; }
+    char_type do_thousands_sep() const override { return '@'; }
+    string_type do_grouping() const override { return "\03"; }
+  };
+
   Mantid::Geometry::Instrument_sptr m_inst;
   std::vector<Peak> m_peaks;
 };
diff --git a/Framework/DataObjects/test/RebinnedOutputTest.h b/Framework/DataObjects/test/RebinnedOutputTest.h
index 36400658edab22b71a7d1c5df1c630a653300ff9..9d17d3ea6b63e4a2b0ce919ecb657892b9952903 100644
--- a/Framework/DataObjects/test/RebinnedOutputTest.h
+++ b/Framework/DataObjects/test/RebinnedOutputTest.h
@@ -25,7 +25,7 @@ public:
 
   RebinnedOutputTest() {
     nHist = 6;
-    ws = WorkspaceCreationHelper::CreateRebinnedOutputWorkspace();
+    ws = WorkspaceCreationHelper::createRebinnedOutputWorkspace();
   }
 
   void testClone() {
diff --git a/Framework/DataObjects/test/TableWorkspacePropertyTest.h b/Framework/DataObjects/test/TableWorkspacePropertyTest.h
index 7cf08046d341574431b0466fb6d74438eef7f433..252b69205a936288b750792cb5e717b6b6f71868 100644
--- a/Framework/DataObjects/test/TableWorkspacePropertyTest.h
+++ b/Framework/DataObjects/test/TableWorkspacePropertyTest.h
@@ -8,6 +8,7 @@
 
 #include "MantidDataObjects/TableWorkspace.h"
 #include "MantidAPI/Algorithm.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidKernel/Property.h"
 #include "MantidAPI/TableRow.h"
 #include "MantidAPI/ColumnFactory.h"
diff --git a/Framework/DataObjects/test/Workspace2DTest.h b/Framework/DataObjects/test/Workspace2DTest.h
index 70b7b0fa0c6e817bd3fe0c938b99541fefb78863..e9fe344d5002d159b569df240160308514c94d70 100644
--- a/Framework/DataObjects/test/Workspace2DTest.h
+++ b/Framework/DataObjects/test/Workspace2DTest.h
@@ -21,7 +21,7 @@ using namespace Mantid::API;
 using HistogramData::Counts;
 using HistogramData::CountStandardDeviations;
 using HistogramData::LinearGenerator;
-using WorkspaceCreationHelper::Create2DWorkspaceBinned;
+using WorkspaceCreationHelper::create2DWorkspaceBinned;
 
 class Workspace2DTest : public CxxTest::TestSuite {
 public:
@@ -36,7 +36,7 @@ public:
   Workspace2DTest() {
     nbins = 5;
     nhist = 10;
-    ws = Create2DWorkspaceBinned(nhist, nbins);
+    ws = create2DWorkspaceBinned(nhist, nbins);
   }
 
   void testClone() {
@@ -128,7 +128,7 @@ public:
   }
 
   void testIntegrateSpectra_entire_range() {
-    ws = Create2DWorkspaceBinned(nhist, nbins);
+    ws = create2DWorkspaceBinned(nhist, nbins);
     MantidVec sums;
     ws->getIntegratedSpectra(sums, 10, 5, true);
     for (int i = 0; i < nhist; ++i) {
@@ -137,7 +137,7 @@ public:
     }
   }
   void testIntegrateSpectra_empty_range() {
-    ws = Create2DWorkspaceBinned(nhist, nbins);
+    ws = create2DWorkspaceBinned(nhist, nbins);
     MantidVec sums;
     ws->getIntegratedSpectra(sums, 10, 5, false);
     for (int i = 0; i < nhist; ++i) {
@@ -147,7 +147,7 @@ public:
   }
 
   void testIntegrateSpectra_partial_range() {
-    ws = Create2DWorkspaceBinned(nhist, nbins);
+    ws = create2DWorkspaceBinned(nhist, nbins);
     MantidVec sums;
     ws->getIntegratedSpectra(sums, 1.9, 3.2, false);
     for (int i = 0; i < nhist; ++i) {
@@ -157,7 +157,7 @@ public:
   }
 
   void test_generateHistogram() {
-    Workspace2D_sptr ws = Create2DWorkspaceBinned(2, 5);
+    Workspace2D_sptr ws = create2DWorkspaceBinned(2, 5);
     MantidVec X, Y, E;
     X.push_back(0.0);
     X.push_back(0.5);
@@ -181,7 +181,7 @@ public:
   }
 
   void test_getMemorySizeForXAxes() {
-    ws = Create2DWorkspaceBinned(nhist, nbins);
+    ws = create2DWorkspaceBinned(nhist, nbins);
     // Here they are shared, so only 1 X axis
     TS_ASSERT_EQUALS(ws->getMemorySizeForXAxes(),
                      1 * (nbins + 1) * sizeof(double));
@@ -267,8 +267,8 @@ public:
 
   Workspace2DTestPerformance() {
     nhist = 1000000; // 1 million
-    ws1 = WorkspaceCreationHelper::Create2DWorkspaceBinned(nhist, 5);
-    ws2 = WorkspaceCreationHelper::Create2DWorkspaceBinned(10, 5);
+    ws1 = WorkspaceCreationHelper::create2DWorkspaceBinned(nhist, 5);
+    ws2 = WorkspaceCreationHelper::create2DWorkspaceBinned(10, 5);
     for (size_t i = 0; i < 10; i++) {
       auto &spec = ws2->getSpectrum(i);
       for (detid_t j = detid_t(i) * 100000; j < detid_t(i + 1) * 100000; j++) {
diff --git a/Framework/DataObjects/test/WorkspaceCreationTest.h b/Framework/DataObjects/test/WorkspaceCreationTest.h
new file mode 100644
index 0000000000000000000000000000000000000000..03adcbf2bb35e6778ee984e673185154f666c95b
--- /dev/null
+++ b/Framework/DataObjects/test/WorkspaceCreationTest.h
@@ -0,0 +1,159 @@
+#ifndef MANTID_DATAOBJECTS_WORKSPACECREATIONTEST_H_
+#define MANTID_DATAOBJECTS_WORKSPACECREATIONTEST_H_
+
+#include <cxxtest/TestSuite.h>
+
+#include "MantidDataObjects/SpecialWorkspace2D.h"
+#include "MantidDataObjects/WorkspaceCreation.h"
+#include "MantidDataObjects/Workspace2D.h"
+#include "MantidDataObjects/EventWorkspace.h"
+#include "MantidIndexing/IndexInfo.h"
+
+using namespace Mantid;
+using namespace API;
+using namespace DataObjects;
+using namespace HistogramData;
+using Mantid::Indexing::IndexInfo;
+
+class WorkspaceCreationTest : public CxxTest::TestSuite {
+public:
+  // This pair of boilerplate methods prevent the suite being created statically
+  // This means the constructor isn't called when running other tests
+  static WorkspaceCreationTest *createSuite() {
+    return new WorkspaceCreationTest();
+  }
+  static void destroySuite(WorkspaceCreationTest *suite) { delete suite; }
+
+  IndexInfo make_indices() {
+    IndexInfo indices(2);
+    indices.setSpectrumNumbers({2, 4});
+    indices.setDetectorIDs({{0}, {2, 3}});
+    return indices;
+  }
+
+  void check_size(const MatrixWorkspace &ws) {
+    TS_ASSERT_EQUALS(ws.getNumberHistograms(), 2);
+  }
+
+  void check_default_indices(const MatrixWorkspace &ws) {
+    check_size(ws);
+    TS_ASSERT_EQUALS(ws.getSpectrum(0).getSpectrumNo(), 1);
+    TS_ASSERT_EQUALS(ws.getSpectrum(1).getSpectrumNo(), 2);
+    TS_ASSERT_EQUALS(ws.getSpectrum(0).getDetectorIDs(),
+                     (std::set<detid_t>{1}));
+    TS_ASSERT_EQUALS(ws.getSpectrum(1).getDetectorIDs(),
+                     (std::set<detid_t>{2}));
+  }
+
+  void check_indices(const MatrixWorkspace &ws) {
+    check_size(ws);
+    TS_ASSERT_EQUALS(ws.getSpectrum(0).getSpectrumNo(), 2);
+    TS_ASSERT_EQUALS(ws.getSpectrum(1).getSpectrumNo(), 4);
+    TS_ASSERT_EQUALS(ws.getSpectrum(0).getDetectorIDs(),
+                     (std::set<detid_t>{0}));
+    TS_ASSERT_EQUALS(ws.getSpectrum(1).getDetectorIDs(),
+                     (std::set<detid_t>{2, 3}));
+  }
+
+  void check_data(const MatrixWorkspace &ws) {
+    TS_ASSERT_EQUALS(ws.x(0).rawData(), std::vector<double>({1, 2, 4}));
+    TS_ASSERT_EQUALS(ws.x(1).rawData(), std::vector<double>({1, 2, 4}));
+    TS_ASSERT_EQUALS(ws.y(0).rawData(), std::vector<double>({0, 0}));
+    TS_ASSERT_EQUALS(ws.y(1).rawData(), std::vector<double>({0, 0}));
+    TS_ASSERT_EQUALS(ws.e(0).rawData(), std::vector<double>({0, 0}));
+    TS_ASSERT_EQUALS(ws.e(1).rawData(), std::vector<double>({0, 0}));
+  }
+
+  void test_create_size_Histogram() {
+    const auto ws = create<Workspace2D>(2, Histogram(BinEdges{1, 2, 4}));
+    check_default_indices(*ws);
+    check_data(*ws);
+  }
+
+  void test_create_IndexInfo_Histogram() {
+    const auto ws =
+        create<Workspace2D>(make_indices(), Histogram(BinEdges{1, 2, 4}));
+    check_indices(*ws);
+    check_data(*ws);
+  }
+
+  void test_create_parent() {
+    const auto parent =
+        create<Workspace2D>(make_indices(), Histogram(BinEdges{1, 2, 4}));
+    const auto ws = create<Workspace2D>(*parent);
+    check_indices(*ws);
+    check_data(*ws);
+  }
+
+  void test_create_parent_Histogram() {
+    const auto parent =
+        create<Workspace2D>(make_indices(), Histogram(BinEdges{0, 1}));
+    const auto ws = create<Workspace2D>(*parent, Histogram(BinEdges{1, 2, 4}));
+    check_indices(*ws);
+    check_data(*ws);
+  }
+
+  void test_create_parent_same_size() {
+    const auto parent =
+        create<Workspace2D>(make_indices(), Histogram(BinEdges{1, 2, 4}));
+    const auto ws = create<Workspace2D>(*parent, 2);
+    // Same size -> Indices copied from parent
+    check_indices(*ws);
+    check_data(*ws);
+  }
+
+  void test_create_parent_size() {
+    const auto parent = create<Workspace2D>(3, Histogram(BinEdges{1, 2, 4}));
+    parent->getSpectrum(0).setSpectrumNo(7);
+    const auto ws = create<Workspace2D>(*parent, 2);
+    check_default_indices(*ws);
+    check_data(*ws);
+  }
+
+  void test_create_parent_IndexInfo_same_size() {
+    const auto parent = create<Workspace2D>(2, Histogram(BinEdges{1, 2, 4}));
+    const auto ws = create<Workspace2D>(*parent, make_indices());
+    // If parent has same size, data in IndexInfo is ignored
+    check_default_indices(*ws);
+    check_data(*ws);
+  }
+
+  void test_create_parent_IndexInfo() {
+    const auto parent = create<Workspace2D>(3, Histogram(BinEdges{1, 2, 4}));
+    const auto ws = create<Workspace2D>(*parent, make_indices());
+    check_indices(*ws);
+    check_data(*ws);
+  }
+
+  void test_create_drop_events() {
+    auto eventWS = create<EventWorkspace>(1, Histogram(BinEdges(3)));
+    auto ws = create<HistoWorkspace>(*eventWS);
+    TS_ASSERT_EQUALS(ws->id(), "Workspace2D");
+  }
+
+  void test_EventWorkspace_MRU_is_empty() {
+    const auto ws1 = create<EventWorkspace>(1, Histogram(BinEdges(3)));
+    const auto ws2 = create<EventWorkspace>(*ws1, 1, Histogram(BinEdges(3)));
+    TS_ASSERT_EQUALS(ws2->MRUSize(), 0);
+  }
+
+  void test_create_from_more_derived() {
+    const auto parent = create<SpecialWorkspace2D>(2, Histogram(Points(1)));
+    const auto ws = create<Workspace2D>(*parent);
+    TS_ASSERT_EQUALS(ws->id(), "SpecialWorkspace2D");
+  }
+
+  void test_create_from_less_derived() {
+    const auto parent = create<Workspace2D>(2, Histogram(Points(1)));
+    const auto ws = create<SpecialWorkspace2D>(*parent);
+    TS_ASSERT_EQUALS(ws->id(), "SpecialWorkspace2D");
+  }
+
+  void test_create_event_from_histo() {
+    const auto parent = create<Workspace2D>(2, Histogram(BinEdges(2)));
+    const auto ws = create<EventWorkspace>(*parent);
+    TS_ASSERT_EQUALS(ws->id(), "EventWorkspace");
+  }
+};
+
+#endif /* MANTID_DATAOBJECTS_WORKSPACECREATIONTEST_H_ */
diff --git a/Framework/Geometry/CMakeLists.txt b/Framework/Geometry/CMakeLists.txt
index de7a6ed907a007b4b7c07c69f68459acee95e078..0f7812e6ecc086980ef2ed03fce0d6390443be0f 100644
--- a/Framework/Geometry/CMakeLists.txt
+++ b/Framework/Geometry/CMakeLists.txt
@@ -53,7 +53,6 @@ set ( SRC_FILES
 	src/Instrument/Goniometer.cpp
 	src/Instrument/IDFObject.cpp
 	src/Instrument/InstrumentDefinitionParser.cpp
-	src/Instrument/NearestNeighbours.cpp
 	src/Instrument/ObjCompAssembly.cpp
 	src/Instrument/ObjComponent.cpp
 	src/Instrument/ParComponentFactory.cpp
@@ -206,7 +205,6 @@ set ( INC_FILES
 	inc/MantidGeometry/Instrument/Goniometer.h
 	inc/MantidGeometry/Instrument/IDFObject.h
 	inc/MantidGeometry/Instrument/InstrumentDefinitionParser.h
-	inc/MantidGeometry/Instrument/NearestNeighbours.h
 	inc/MantidGeometry/Instrument/ObjCompAssembly.h
 	inc/MantidGeometry/Instrument/ObjComponent.h
 	inc/MantidGeometry/Instrument/ParComponentFactory.h
@@ -350,7 +348,6 @@ set ( TEST_FILES
 	MathSupportTest.h
 	MatrixVectorPairParserTest.h
 	MatrixVectorPairTest.h
-	NearestNeighboursTest.h
 	NiggliCellTest.h
 	NullImplicitFunctionTest.h
 	ObjCompAssemblyTest.h
diff --git a/Framework/Geometry/inc/MantidGeometry/Crystal/IndexingUtils.h b/Framework/Geometry/inc/MantidGeometry/Crystal/IndexingUtils.h
index 0756868ab09a659e5a216157c9fd53b7a9707052..9dcfbc2ea6b00ad2aafedbc9c0d250983ed550d6 100644
--- a/Framework/Geometry/inc/MantidGeometry/Crystal/IndexingUtils.h
+++ b/Framework/Geometry/inc/MantidGeometry/Crystal/IndexingUtils.h
@@ -6,10 +6,11 @@
 //----------------------------------------------------------------------
 // Includes
 //----------------------------------------------------------------------
+#include "MantidGeometry/Crystal/OrientedLattice.h"
 #include "MantidGeometry/DllConfig.h"
-#include "MantidKernel/V3D.h"
-#include "MantidKernel/Matrix.h"
 #include "MantidKernel/Logger.h"
+#include "MantidKernel/Matrix.h"
+#include "MantidKernel/V3D.h"
 
 namespace Mantid {
 namespace Geometry {
@@ -51,10 +52,10 @@ public:
   /// Find the UB matrix that most nearly indexes the specified qxyz values
   /// given the lattice parameters
   static double Find_UB(Kernel::DblMatrix &UB,
-                        const std::vector<Kernel::V3D> &q_vectors, double a,
-                        double b, double c, double alpha, double beta,
-                        double gamma, double required_tolerance, int base_index,
-                        size_t num_initial, double degrees_per_step);
+                        const std::vector<Kernel::V3D> &q_vectors,
+                        OrientedLattice &lattice, double required_tolerance,
+                        int base_index, size_t num_initial,
+                        double degrees_per_step, bool fixAll = false);
 
   /// Find the UB matrix that most nearly indexes the specified qxyz values
   /// given the range of possible real space unit cell edge lengths.
@@ -88,9 +89,8 @@ public:
 
   /// Scan rotations to find UB that indexes peaks given lattice parameters
   static double ScanFor_UB(Kernel::DblMatrix &UB,
-                           const std::vector<Kernel::V3D> &q_vectors, double a,
-                           double b, double c, double alpha, double beta,
-                           double gamma, double degrees_per_step,
+                           const std::vector<Kernel::V3D> &q_vectors,
+                           const UnitCell &lattice, double degrees_per_step,
                            double required_tolerance);
 
   /// Get list of possible directions and lengths for real space unit cell
diff --git a/Framework/Geometry/inc/MantidGeometry/Crystal/ReducedCell.h b/Framework/Geometry/inc/MantidGeometry/Crystal/ReducedCell.h
index e547ed6c6d0136b195d9068b0131cb3e4dd4bd7a..d7f8fa7beaee5f3992826d14b6e083e00fdf6d0b 100644
--- a/Framework/Geometry/inc/MantidGeometry/Crystal/ReducedCell.h
+++ b/Framework/Geometry/inc/MantidGeometry/Crystal/ReducedCell.h
@@ -3,6 +3,7 @@
 
 #include "MantidGeometry/DllConfig.h"
 #include "MantidKernel/Matrix.h"
+#include <string>
 
 namespace Mantid {
 namespace Geometry {
diff --git a/Framework/Geometry/inc/MantidGeometry/IDetector.h b/Framework/Geometry/inc/MantidGeometry/IDetector.h
index 617dd4477b7d5864a6b54521945d773fb59b076a..343b8bf96e184e5d99961e78196eeb792926e761 100644
--- a/Framework/Geometry/inc/MantidGeometry/IDetector.h
+++ b/Framework/Geometry/inc/MantidGeometry/IDetector.h
@@ -100,15 +100,17 @@ public:
   /// Gives the phi of this detector offset from y=0 by offset.
   virtual double getPhiOffset(const double &offset) const = 0;
 
-  /// Indicates whether the detector has been masked
-  virtual bool isMasked() const = 0;
-  /// Indicates whether this is a monitor detector
-  virtual bool isMonitor() const = 0;
-
   /// returns the geometry of detectors, meaningful for groups, rectangular for
   /// single; returns the centre of a detector
   virtual det_topology getTopology(Kernel::V3D &center) const = 0;
 
+  /// Helper for legacy access mode. Returns a reference to the ParameterMap.
+  virtual const ParameterMap &parameterMap() const = 0;
+  /// Helper for legacy access mode. Returns the index of the detector.
+  virtual size_t index() const = 0;
+  /// Helper for legacy access mode. Sets the index of the detector.
+  virtual void setIndex(const size_t index) = 0;
+
   /// (Empty) Constructor.
   /// prevent Warning C4436 and many failing unit tests on MSVC 2015.
   IDetector() {} // NOLINT
diff --git a/Framework/Geometry/inc/MantidGeometry/IObjComponent.h b/Framework/Geometry/inc/MantidGeometry/IObjComponent.h
index e806cdcd9ea347e8efdf40d93ca1f61a920550e1..17b29750842746e243ff3f7b4cf96c066e3f3dab 100644
--- a/Framework/Geometry/inc/MantidGeometry/IObjComponent.h
+++ b/Framework/Geometry/inc/MantidGeometry/IObjComponent.h
@@ -1,12 +1,8 @@
 #ifndef IMANTID_GEOMETRY_OBJCOMPONENT_H_
 #define IMANTID_GEOMETRY_OBJCOMPONENT_H_
 
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidGeometry/DllConfig.h"
 #include "MantidGeometry/IComponent.h"
-#include "MantidGeometry/Objects/Track.h"
 
 namespace Mantid {
 
@@ -15,9 +11,7 @@ class Material;
 }
 
 namespace Geometry {
-//----------------------------------------------------------------------
-// Forward Declaration
-//----------------------------------------------------------------------
+class Track;
 class Object;
 class GeometryHandler;
 
diff --git a/Framework/Geometry/inc/MantidGeometry/Instrument.h b/Framework/Geometry/inc/MantidGeometry/Instrument.h
index 00639c0af60e1f4a4f5db2d29b039ff3a7569209..ee2a6ef89af12d3ef650a0784bb1720ad546fd7b 100644
--- a/Framework/Geometry/inc/MantidGeometry/Instrument.h
+++ b/Framework/Geometry/inc/MantidGeometry/Instrument.h
@@ -1,9 +1,6 @@
 #ifndef MANTID_GEOMETRY_INSTRUMENT_H_
 #define MANTID_GEOMETRY_INSTRUMENT_H_
 
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidGeometry/DllConfig.h"
 #include "MantidGeometry/Instrument_fwd.h"
 #include "MantidGeometry/IDetector.h"
@@ -14,16 +11,18 @@
 
 #include <string>
 #include <map>
+#include <tuple>
+#include <vector>
 
 namespace Mantid {
 /// Typedef of a map from detector ID to detector shared pointer.
 typedef std::map<detid_t, Geometry::IDetector_const_sptr> detid2det_map;
 
+namespace Beamline {
+class DetectorInfo;
+}
 namespace Geometry {
 
-//------------------------------------------------------------------
-// Forward declarations
-//------------------------------------------------------------------
 class XMLInstrumentParameter;
 class ParameterMap;
 class ReferenceFrame;
@@ -86,11 +85,9 @@ public:
   const IDetector *getBaseDetector(const detid_t &detector_id) const;
   bool isMonitor(const detid_t &detector_id) const;
   bool isMonitor(const std::set<detid_t> &detector_ids) const;
-  bool isDetectorMasked(const detid_t &detector_id) const;
-  bool isDetectorMasked(const std::set<detid_t> &detector_ids) const;
 
   /// Returns a pointer to the geometrical object for the given set of IDs
-  IDetector_const_sptr getDetectorG(const std::vector<detid_t> &det_ids) const;
+  IDetector_const_sptr getDetectorG(const std::set<detid_t> &det_ids) const;
 
   /// Returns a list of Detectors for the given detectors ids
   std::vector<IDetector_const_sptr>
@@ -120,12 +117,14 @@ public:
   /// child comp.)
   /// to be a Detector component by adding it to _detectorCache
   void markAsDetector(const IDetector *);
+  void markAsDetectorIncomplete(const IDetector *);
+  void markAsDetectorFinalize();
 
   /// mark a Component which has already been added to the Instrument (as a
   /// child comp.)
   /// to be a monitor and also add it to _detectorCache for possible later
   /// retrieval
-  void markAsMonitor(IDetector *);
+  void markAsMonitor(const IDetector *);
 
   /// Remove a detector from the instrument
   void removeDetector(IDetector *);
@@ -144,8 +143,6 @@ public:
 
   /// Returns a list containing the detector ids of monitors
   std::vector<detid_t> getMonitors() const;
-  /// Returns the number of monitors
-  size_t numMonitors() const;
 
   /// Get the bounding box for this component and store it in the given argument
   void getBoundingBox(BoundingBox &assemblyBox) const override;
@@ -219,7 +216,7 @@ public:
   static double calcConversion(const double l1, const Kernel::V3D &beamline,
                                const double beamline_norm,
                                const Kernel::V3D &samplePos,
-                               const IDetector_const_sptr &det,
+                               const Kernel::V3D &detectorPos,
                                const double offset);
 
   static double
@@ -253,6 +250,13 @@ public:
   /// @return Full if all detectors are rect., Partial if some, None if none
   ContainsState containsRectDetectors() const;
 
+  bool isMonitorViaIndex(const size_t index) const;
+
+  bool hasDetectorInfo() const;
+  const Beamline::DetectorInfo &detectorInfo() const;
+  void
+  setDetectorInfo(boost::shared_ptr<const Beamline::DetectorInfo> detectorInfo);
+
 private:
   /// Save information about a set of detectors to Nexus
   void saveDetectorSetInfoToNexus(::NeXus::File *file,
@@ -265,8 +269,9 @@ private:
   void appendPlottable(const CompAssembly &ca,
                        std::vector<IObjComponent_const_sptr> &lst) const;
 
-  /// Map which holds detector-IDs and pointers to detector components
-  std::map<detid_t, IDetector_const_sptr> m_detectorCache;
+  /// Map which holds detector-IDs and pointers to detector components, and
+  /// monitor flags.
+  std::vector<std::tuple<detid_t, IDetector_const_sptr, bool>> m_detectorCache;
 
   /// Purpose to hold copy of source component. For now assumed to be just one
   /// component
@@ -296,9 +301,6 @@ private:
   /// by the user in radian (not degrees)
   std::map<std::string, std::string> m_logfileUnit;
 
-  /// a vector holding detector ids of monitor s
-  std::vector<detid_t> m_monitorCache;
-
   /// Stores the default type of the instrument view: 3D or one of the
   /// "unwrapped"
   std::string m_defaultView;
@@ -329,6 +331,10 @@ private:
 
   /// Pointer to the reference frame object.
   boost::shared_ptr<ReferenceFrame> m_referenceFrame;
+
+  /// Pointer to the DetectorInfo object. NULL unless the instrument is
+  /// associated with an ExperimentInfo object.
+  boost::shared_ptr<const Beamline::DetectorInfo> m_detectorInfo{nullptr};
 };
 
 } // namespace Geometry
diff --git a/Framework/Geometry/inc/MantidGeometry/Instrument/Component.h b/Framework/Geometry/inc/MantidGeometry/Instrument/Component.h
index 72b7f492039b97da4547a44ebcef55526ef95d44..df454c38b2205628ab98c575d1efd530f4758d65 100644
--- a/Framework/Geometry/inc/MantidGeometry/Instrument/Component.h
+++ b/Framework/Geometry/inc/MantidGeometry/Instrument/Component.h
@@ -1,16 +1,11 @@
 #ifndef MANTID_GEOMETRY_Component_H_
 #define MANTID_GEOMETRY_Component_H_
 
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidGeometry/DllConfig.h"
 #include "MantidGeometry/Instrument/ParameterMap.h"
 #include <string>
-#include <sstream>
 #include <typeinfo>
 #include <vector>
-#include <Poco/SAX/Attributes.h>
 #ifdef _MSC_VER
 // Disable a flood of warnings from Poco about inheriting from
 // std::basic_istream
@@ -20,12 +15,17 @@
 #pragma warning(disable : 4250)
 #endif
 
-#include <Poco/XML/XMLWriter.h>
-
 #ifdef _MSC_VER
 #pragma warning(pop)
 #endif
 
+namespace Poco {
+namespace XML {
+class Attributes;
+class XMLWriter;
+}
+}
+
 namespace Mantid {
 namespace Kernel {
 class V3D;
diff --git a/Framework/Geometry/inc/MantidGeometry/Instrument/ComponentHelper.h b/Framework/Geometry/inc/MantidGeometry/Instrument/ComponentHelper.h
index 1427d5643e523195dd459187e561a065bfe26204..106ee0ad75b857227b2f282b6b808160b7f8718d 100644
--- a/Framework/Geometry/inc/MantidGeometry/Instrument/ComponentHelper.h
+++ b/Framework/Geometry/inc/MantidGeometry/Instrument/ComponentHelper.h
@@ -73,7 +73,7 @@ createVirtualInstrument(Kernel::V3D sourcePos, Kernel::V3D samplePos,
                         const std::vector<Kernel::V3D> &vecdetpos,
                         const std::vector<detid_t> &vecdetid);
 
-MANTID_GEOMETRY_DLL Object_sptr
+MANTID_GEOMETRY_DLL boost::shared_ptr<Object>
 createSphere(double radius, const Kernel::V3D &centre, const std::string &id);
 
 MANTID_GEOMETRY_DLL std::string
diff --git a/Framework/Geometry/inc/MantidGeometry/Instrument/Detector.h b/Framework/Geometry/inc/MantidGeometry/Instrument/Detector.h
index 02495eefbfc9a160a0917a3432429db7e7188610..5459f9c301b840ae479cc79529b448ce322e5469 100644
--- a/Framework/Geometry/inc/MantidGeometry/Instrument/Detector.h
+++ b/Framework/Geometry/inc/MantidGeometry/Instrument/Detector.h
@@ -11,6 +11,7 @@
 
 namespace Mantid {
 namespace Geometry {
+class Instrument;
 
 /**
  * This class represents a detector - i.e. a single pixel in an instrument.
@@ -69,10 +70,7 @@ public:
                            const Kernel::V3D &instrumentUp) const override;
   double getPhi() const override;
   double getPhiOffset(const double &offset) const override;
-  bool isMasked() const override;
-  bool isMonitor() const override;
   // end IDetector methods
-  void markAsMonitor(const bool flag = true);
   /** returns the detector's topology, namely, the meaning of the detector's
      angular measurements.
       It is different in cartesian and cylindrical (surrounding the beam)
@@ -84,11 +82,15 @@ public:
     return ObjComponent::getRelativePos();
   }
 
+  const ParameterMap &parameterMap() const override;
+  size_t index() const override;
+  void setIndex(const size_t index) override;
+
 private:
+  /// Linear index of the detector in the instrument
+  size_t m_index{static_cast<size_t>(-1)};
   /// The detector id
   const detid_t m_id;
-  /// Flags if this is a monitor
-  bool m_isMonitor;
 
 protected:
   /// Constructor for parametrized version
diff --git a/Framework/Geometry/inc/MantidGeometry/Instrument/DetectorGroup.h b/Framework/Geometry/inc/MantidGeometry/Instrument/DetectorGroup.h
index 0b31e0656c984e934ebe29b5f7e3ef2544cf2c41..92c988cb48b9bba8658ad2885313dc2cee379e66 100644
--- a/Framework/Geometry/inc/MantidGeometry/Instrument/DetectorGroup.h
+++ b/Framework/Geometry/inc/MantidGeometry/Instrument/DetectorGroup.h
@@ -1,9 +1,6 @@
 #ifndef MANTID_GEOMETRY_DETECTORGROUP_H_
 #define MANTID_GEOMETRY_DETECTORGROUP_H_
 
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidGeometry/IDetector.h"
 #include "MantidGeometry/Instrument/Component.h"
 #include "MantidGeometry/Instrument/ObjComponent.h"
@@ -47,10 +44,9 @@ Code Documentation is available at: <http://doxygen.mantidproject.org>
 class MANTID_GEOMETRY_DLL DetectorGroup : public virtual IDetector {
 public:
   DetectorGroup();
-  DetectorGroup(const std::vector<IDetector_const_sptr> &dets,
-                bool warnAboutMasked = false);
+  DetectorGroup(const std::vector<IDetector_const_sptr> &dets);
 
-  void addDetector(IDetector_const_sptr det, bool &warn);
+  void addDetector(IDetector_const_sptr det);
 
   // IDetector methods
   IDetector *cloneParameterized(const ParameterMap *) const override {
@@ -68,8 +64,6 @@ public:
   double getPhiOffset(const double &offset) const override;
   double solidAngle(const Kernel::V3D &observer) const override;
   bool isParametrized() const override;
-  bool isMasked() const override;
-  bool isMonitor() const override;
   bool isValid(const Kernel::V3D &point) const override;
   bool isOnSide(const Kernel::V3D &point) const override;
   /// Try to find a point that lies within (or on) the object
@@ -185,6 +179,10 @@ public:
     return const_cast<const DetectorGroup *>(this);
   }
 
+  const ParameterMap &parameterMap() const override;
+  size_t index() const override;
+  void setIndex(const size_t index) override;
+
 protected:
   /// The ID of this effective detector
   int m_id;
diff --git a/Framework/Geometry/inc/MantidGeometry/Instrument/ObjComponent.h b/Framework/Geometry/inc/MantidGeometry/Instrument/ObjComponent.h
index d81fa527e2d186ad2b621ef26484401687bde138..5730838c2639798409b9aad009bd9b9becfd5bc3 100644
--- a/Framework/Geometry/inc/MantidGeometry/Instrument/ObjComponent.h
+++ b/Framework/Geometry/inc/MantidGeometry/Instrument/ObjComponent.h
@@ -1,14 +1,9 @@
 #ifndef MANTID_GEOMETRY_OBJCOMPONENT_H_
 #define MANTID_GEOMETRY_OBJCOMPONENT_H_
 
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidGeometry/DllConfig.h"
 #include "MantidGeometry/Instrument/Component.h"
 #include "MantidGeometry/IObjComponent.h"
-#include "MantidGeometry/Objects/Track.h"
-#include "MantidGeometry/Objects/Object.h"
 
 #ifdef _WIN32
 #pragma warning(disable : 4250)
@@ -16,6 +11,7 @@
 
 namespace Mantid {
 namespace Geometry {
+class Objects;
 //----------------------------------------------------------------------
 // Forward Declaration
 //----------------------------------------------------------------------
@@ -61,7 +57,8 @@ public:
   // Looking to get rid of the first of these constructors in due course (and
   // probably add others)
   explicit ObjComponent(const std::string &name, IComponent *parent = nullptr);
-  explicit ObjComponent(const std::string &name, Object_const_sptr shape,
+  explicit ObjComponent(const std::string &name,
+                        boost::shared_ptr<const Object> shape,
                         IComponent *parent = nullptr);
 
   /** Virtual Copy Constructor
@@ -92,9 +89,9 @@ public:
   void initDraw() const override;
 
   /// Return the shape of the component
-  const Object_const_sptr shape() const override;
+  const boost::shared_ptr<const Object> shape() const override;
   /// Set a new shape on the component
-  void setShape(Object_const_sptr newShape);
+  void setShape(boost::shared_ptr<const Object> newShape);
   /// Return the material this component is made from
   const Kernel::Material material() const override;
 
@@ -103,7 +100,7 @@ protected:
   // Made a pointer to a const object. Since this is a shared object we
   // shouldn't be
   // exposing non-const methods of Object through this class.
-  Object_const_sptr m_shape;
+  boost::shared_ptr<const Object> m_shape;
 
   const Kernel::V3D factorOutComponentPosition(const Kernel::V3D &point) const;
   const Kernel::V3D takeOutRotation(Kernel::V3D point) const;
diff --git a/Framework/Geometry/inc/MantidGeometry/Instrument/Parameter.h b/Framework/Geometry/inc/MantidGeometry/Instrument/Parameter.h
index 47691bd996599d6d7fa30af9591a52b5c9e29099..61f11fef33fcda6616459cb677b4f0f68b7e1156 100644
--- a/Framework/Geometry/inc/MantidGeometry/Instrument/Parameter.h
+++ b/Framework/Geometry/inc/MantidGeometry/Instrument/Parameter.h
@@ -22,6 +22,7 @@
 #ifndef Q_MOC_RUN
 #include <boost/shared_ptr.hpp>
 #endif
+#include <sstream>
 #include <string>
 #include <typeinfo>
 #include <vector>
diff --git a/Framework/Geometry/inc/MantidGeometry/Instrument/ParameterMap.h b/Framework/Geometry/inc/MantidGeometry/Instrument/ParameterMap.h
index edbbf966840b7e2dc699fae047d1406cd7cc2a80..de532b3a601d2d2b0a3f6054198b687a354f7058 100644
--- a/Framework/Geometry/inc/MantidGeometry/Instrument/ParameterMap.h
+++ b/Framework/Geometry/inc/MantidGeometry/Instrument/ParameterMap.h
@@ -6,21 +6,21 @@
 #include "MantidGeometry/IDetector.h"
 #include "MantidGeometry/IDTypes.h" //For specnum_t
 #include "MantidGeometry/Instrument/Parameter.h"
-#include "MantidGeometry/Instrument/ParameterFactory.h"
-#include "MantidGeometry/Objects/BoundingBox.h"
-#include "MantidKernel/Cache.h"
 
 #include "tbb/concurrent_unordered_map.h"
 
+#include <memory>
 #include <vector>
 #include <typeinfo>
 
 namespace Mantid {
+namespace Kernel {
+template <class KEYTYPE, class VALUETYPE> class Cache;
+}
+namespace Beamline {
+class DetectorInfo;
+}
 namespace Geometry {
-
-//---------------------------------------------------------------------------
-// Forward declarations
-//---------------------------------------------------------------------------
 class BoundingBox;
 
 /** @class ParameterMap ParameterMap.h
@@ -74,6 +74,9 @@ public:
       ComponentID, boost::shared_ptr<Parameter>>::const_iterator pmap_cit;
   /// Default constructor
   ParameterMap();
+  /// Const constructor
+  ParameterMap(const ParameterMap &other);
+  ~ParameterMap();
   /// Returns true if the map is empty, false otherwise
   inline bool empty() const { return m_map.empty(); }
   /// Return the size of the map
@@ -141,7 +144,7 @@ public:
   void add(const std::string &type, const IComponent *comp,
            const std::string &name, const T &value,
            const std::string *const pDescription = nullptr) {
-    auto param = ParameterFactory::create(type, name);
+    auto param = create(type, name);
     auto typedParam = boost::dynamic_pointer_cast<ParameterType<T>>(param);
     assert(typedParam); // If not true the factory has created the wrong type
     typedParam->setValue(value);
@@ -199,6 +202,7 @@ public:
   void addQuat(const IComponent *comp, const std::string &name,
                const Kernel::Quat &value,
                const std::string *const pDescription = nullptr);
+  void forceUnsafeSetMasked(const IComponent *comp, bool value);
   //@}
 
   /// Does the named parameter exist for the given component and type
@@ -339,7 +343,15 @@ public:
   pmap_it end() { return m_map.end(); }
   pmap_cit end() const { return m_map.end(); }
 
+  bool hasDetectorInfo() const;
+  const Beamline::DetectorInfo &detectorInfo() const;
+  void
+  setDetectorInfo(boost::shared_ptr<const Beamline::DetectorInfo> detectorInfo);
+
 private:
+  boost::shared_ptr<Parameter> create(const std::string &className,
+                                      const std::string &name) const;
+
   /// Assignment operator
   ParameterMap &operator=(ParameterMap *rhs);
   /// internal function to get position of the parameter in the parameter map
@@ -356,11 +368,16 @@ private:
   /// internal parameter map instance
   pmap m_map;
   /// internal cache map instance for cached position values
-  mutable Kernel::Cache<const ComponentID, Kernel::V3D> m_cacheLocMap;
+  std::unique_ptr<Kernel::Cache<const ComponentID, Kernel::V3D>> m_cacheLocMap;
   /// internal cache map instance for cached rotation values
-  mutable Kernel::Cache<const ComponentID, Kernel::Quat> m_cacheRotMap;
+  std::unique_ptr<Kernel::Cache<const ComponentID, Kernel::Quat>> m_cacheRotMap;
   /// internal cache map for cached bounding boxes
-  mutable Kernel::Cache<const ComponentID, BoundingBox> m_boundingBoxMap;
+  std::unique_ptr<Kernel::Cache<const ComponentID, BoundingBox>>
+      m_boundingBoxMap;
+
+  /// Pointer to the DetectorInfo object. NULL unless the instrument is
+  /// associated with an ExperimentInfo object.
+  boost::shared_ptr<const Beamline::DetectorInfo> m_detectorInfo{nullptr};
 };
 
 /// ParameterMap shared pointer typedef
diff --git a/Framework/Geometry/inc/MantidGeometry/Instrument/SampleEnvironment.h b/Framework/Geometry/inc/MantidGeometry/Instrument/SampleEnvironment.h
index 62cd6b4d1779a74f86da83729ae1635d18af8249..d61f3479ffe1c2b2187e2ea11b06de2e2b6243e6 100644
--- a/Framework/Geometry/inc/MantidGeometry/Instrument/SampleEnvironment.h
+++ b/Framework/Geometry/inc/MantidGeometry/Instrument/SampleEnvironment.h
@@ -8,6 +8,9 @@
 #include "MantidGeometry/Instrument/Container.h"
 
 namespace Mantid {
+namespace Kernel {
+class PseudoRandomNumberGenerator;
+}
 namespace Geometry {
 class Track;
 
@@ -52,6 +55,14 @@ public:
   inline size_t nelements() const { return m_components.size(); }
 
   Geometry::BoundingBox boundingBox() const;
+  /// Select a random point within a component
+  Kernel::V3D generatePoint(Kernel::PseudoRandomNumberGenerator &rng,
+                            const size_t maxAttempts) const;
+  /// Select a random point within a component that is also bound by a
+  /// given region
+  Kernel::V3D generatePoint(Kernel::PseudoRandomNumberGenerator &rng,
+                            const BoundingBox &activeRegion,
+                            const size_t maxAttempts) const;
   bool isValid(const Kernel::V3D &point) const;
   int interceptSurfaces(Track &track) const;
 
diff --git a/Framework/Geometry/inc/MantidGeometry/MDGeometry/IMDDimension.h b/Framework/Geometry/inc/MantidGeometry/MDGeometry/IMDDimension.h
index 919038af3ca0d631c6b18b7bbcbfa239c93bc29e..9053ccc800cdb631b14235efeef839bd6c3351cf 100644
--- a/Framework/Geometry/inc/MantidGeometry/MDGeometry/IMDDimension.h
+++ b/Framework/Geometry/inc/MantidGeometry/MDGeometry/IMDDimension.h
@@ -73,7 +73,7 @@ public:
   /// can be usually find by its ID and various
   /// various method exist to manipulate set of dimensions by their names.
   /// @return Dimension ID string.
-  virtual std::string getDimensionId() const = 0;
+  virtual const std::string &getDimensionId() const = 0;
 
   /// @return the minimum extent of this dimension
   virtual coord_t getMinimum() const = 0;
diff --git a/Framework/Geometry/inc/MantidGeometry/MDGeometry/MDGeometryXMLBuilder.h b/Framework/Geometry/inc/MantidGeometry/MDGeometry/MDGeometryXMLBuilder.h
index 15addeb270351e4b842b85724ff2220849c366c5..40753107697782a78c8c9f7b9ac4e10193e90d34 100644
--- a/Framework/Geometry/inc/MantidGeometry/MDGeometry/MDGeometryXMLBuilder.h
+++ b/Framework/Geometry/inc/MantidGeometry/MDGeometry/MDGeometryXMLBuilder.h
@@ -108,7 +108,7 @@ private:
   mutable IMDDimension_const_sptr m_spTDimension;
 
   /// Instantiate and apply the checking policy.
-  void applyPolicyChecking(IMDDimension_const_sptr dimensionToAdd) const;
+  void applyPolicyChecking(const IMDDimension &dimensionToAdd) const;
 
   /// Flag indicating that some change in the inputs has occured. Triggers full
   /// recreation.
@@ -125,17 +125,16 @@ private:
  @date May 2011
  @version 1.0
 */
-struct MANTID_GEOMETRY_DLL StrictDimensionPolicy
-    : public std::unary_function<IMDDimension_const_sptr, void> {
+struct MANTID_GEOMETRY_DLL StrictDimensionPolicy {
 public:
   StrictDimensionPolicy() {}
-  void operator()(IMDDimension_const_sptr item) {
-    if (true == item->getIsIntegrated()) {
+  void operator()(const IMDDimension &item) {
+    if (true == item.getIsIntegrated()) {
       std::string message = "StrictDimensionPolicy bans the use of integrated "
                             "IMDDimensions mapped to x, y, z or t in a "
-                            "IMDWorkspace.";
-      message +=
-          "Attempted to do so with IMDDimension: " + item->getDimensionId();
+                            "IMDWorkspace."
+                            "Attempted to do so with IMDDimension: " +
+                            item.getDimensionId();
       throw std::invalid_argument(message);
     }
   }
@@ -147,9 +146,8 @@ public:
  @author Owen Arnold
  @date May 2011
 */
-struct MANTID_GEOMETRY_DLL NoDimensionPolicy
-    : public std::unary_function<IMDDimension_const_sptr, void> {
-  void operator()(IMDDimension_const_sptr) {
+struct MANTID_GEOMETRY_DLL NoDimensionPolicy {
+  void operator()(const IMDDimension &) {
     // Do nothing.
   }
 };
diff --git a/Framework/Geometry/inc/MantidGeometry/MDGeometry/MDHistoDimension.h b/Framework/Geometry/inc/MantidGeometry/MDGeometry/MDHistoDimension.h
index 13643c0d53fff1cd4854fcb0720176e1e72af8d5..f014c472bbe093cdc68b11ab249a01cc6cdf73fb 100644
--- a/Framework/Geometry/inc/MantidGeometry/MDGeometry/MDHistoDimension.h
+++ b/Framework/Geometry/inc/MantidGeometry/MDGeometry/MDHistoDimension.h
@@ -71,7 +71,7 @@ public:
    * A dimension can be usually found by its ID and various
    * various method exist to manipulate set of dimensions by their names.
    */
-  std::string getDimensionId() const override { return m_dimensionId; }
+  const std::string &getDimensionId() const override { return m_dimensionId; }
 
   /// Returns the maximum extent of this dimension
   coord_t getMaximum() const override { return m_max; }
diff --git a/Framework/Geometry/inc/MantidGeometry/Objects/BoundingBox.h b/Framework/Geometry/inc/MantidGeometry/Objects/BoundingBox.h
index 08736f79496362b1a7a099ed83902eb10108a158..f1b0a16b005f6ddd45e4e73340eec90fe0dcf553 100644
--- a/Framework/Geometry/inc/MantidGeometry/Objects/BoundingBox.h
+++ b/Framework/Geometry/inc/MantidGeometry/Objects/BoundingBox.h
@@ -142,9 +142,10 @@ public:
   std::vector<Kernel::V3D> const &getCoordSystem() const {
     return coord_system;
   }
-
   //@}
 
+  /// Generate a random point within the box
+  Kernel::V3D generatePointInside(double r1, double r2, double r3) const;
   /** returns the expanded box consisting of all 8 box points,
     * shifted into the coordinate system with the observer centre; */
   void getFullBox(std::vector<Kernel::V3D> &box,
diff --git a/Framework/Geometry/inc/MantidGeometry/Objects/InstrumentRayTracer.h b/Framework/Geometry/inc/MantidGeometry/Objects/InstrumentRayTracer.h
index 5951682bdd63986570e90a0aabfbe5df31055ea3..8e6d76947817185bd8a142721276378bd6a9b2a6 100644
--- a/Framework/Geometry/inc/MantidGeometry/Objects/InstrumentRayTracer.h
+++ b/Framework/Geometry/inc/MantidGeometry/Objects/InstrumentRayTracer.h
@@ -1,11 +1,9 @@
 #ifndef MANTID_GEOMETRY_INSTRUMENTRAYTRACER_H_
 #define MANTID_GEOMETRY_INSTRUMENTRAYTRACER_H_
 
-//-------------------------------------------------------------
-// Includes
-//-------------------------------------------------------------
 #include "MantidGeometry/IDetector.h"
 #include "MantidGeometry/Instrument.h"
+#include "MantidGeometry/Objects/Track.h"
 #include <deque>
 #include <list>
 
@@ -14,9 +12,6 @@ namespace Kernel {
 class V3D;
 }
 namespace Geometry {
-//-------------------------------------------------------------
-// Forward declarations
-//-------------------------------------------------------------
 struct Link;
 class Track;
 /// Typedef for object intersections
diff --git a/Framework/Geometry/inc/MantidGeometry/Objects/Object.h b/Framework/Geometry/inc/MantidGeometry/Objects/Object.h
index b16b816b5a9f1d1e599e6430cc62ca9e9f3cad36..5a1be5728a3ebf910d4b99ffe51615db6d05b27b 100644
--- a/Framework/Geometry/inc/MantidGeometry/Objects/Object.h
+++ b/Framework/Geometry/inc/MantidGeometry/Objects/Object.h
@@ -15,17 +15,18 @@ namespace Mantid {
 // Forward declarations
 //----------------------------------------------------------------------
 namespace Kernel {
-class V3D;
+class PseudoRandomNumberGenerator;
 class Material;
+class V3D;
 }
 
 namespace Geometry {
-class Rule;
+class CacheGeometryHandler;
 class CompGrp;
+class GeometryHandler;
+class Rule;
 class Surface;
 class Track;
-class GeometryHandler;
-class CacheGeometryHandler;
 class vtkGeometryCacheReader;
 class vtkGeometryCacheWriter;
 
@@ -153,6 +154,13 @@ public:
   // find internal point to object
   int getPointInObject(Kernel::V3D &point) const;
 
+  /// Select a random point within the object
+  Kernel::V3D generatePointInObject(Kernel::PseudoRandomNumberGenerator &rng,
+                                    const size_t) const;
+  Kernel::V3D generatePointInObject(Kernel::PseudoRandomNumberGenerator &rng,
+                                    const BoundingBox &activeRegion,
+                                    const size_t) const;
+
   // Rendering member functions
   void draw() const;
   // Initialize Drawing
diff --git a/Framework/Geometry/inc/MantidGeometry/Objects/Track.h b/Framework/Geometry/inc/MantidGeometry/Objects/Track.h
index df06aacfcfb04f604e6e66b7606e4198271904ea..3a7863d289fb37228af9e32feb383085c462ec4a 100644
--- a/Framework/Geometry/inc/MantidGeometry/Objects/Track.h
+++ b/Framework/Geometry/inc/MantidGeometry/Objects/Track.h
@@ -143,8 +143,8 @@ struct IntersectionPoint {
 */
 class MANTID_GEOMETRY_DLL Track {
 public:
-  typedef std::list<Link> LType;              ///< Type for the Link storage
-  typedef std::list<IntersectionPoint> PType; ///< Type for the partial
+  using LType = std::list<Link>;
+  using PType = std::list<IntersectionPoint>;
 
 public:
   /// Default constructor
@@ -175,10 +175,24 @@ public:
   LType::iterator begin() { return m_links.begin(); }
   /// Returns an interator to one-past-the-end of the set of links
   LType::iterator end() { return m_links.end(); }
-  /// Returns an interator to the start of the set of links
+  /// Returns an interator to the start of the set of links (const version)
+  LType::const_iterator begin() const { return m_links.begin(); }
+  /// Returns an interator to one-past-the-end of the set of links (const
+  /// version)
+  LType::const_iterator end() const { return m_links.end(); }
+  /// Returns an interator to the start of the set of links (const version)
   LType::const_iterator cbegin() const { return m_links.cbegin(); }
-  /// Returns an interator to one-past-the-end of the set of links
+  /// Returns an interator to one-past-the-end of the set of links (const
+  /// version)
   LType::const_iterator cend() const { return m_links.cend(); }
+  /// Returns a reference to the first link
+  LType::reference front() { return m_links.front(); }
+  /// Returns a reference to the last link
+  LType::reference back() { return m_links.back(); }
+  /// Returns a reference to the first link (const version)
+  LType::const_reference front() const { return m_links.front(); }
+  /// Returns a reference to the last link (const version)
+  LType::const_reference back() const { return m_links.back(); }
   /// Returns the number of links
   int count() const { return static_cast<int>(m_links.size()); }
   /// Is the link complete?
diff --git a/Framework/Geometry/inc/MantidGeometry/Surfaces/Line.h b/Framework/Geometry/inc/MantidGeometry/Surfaces/Line.h
index d61990b010d5a1c4ab8cec05f9f421d04428110a..dd57786c6369ac5955e2cba182ca91b48f39c604 100644
--- a/Framework/Geometry/inc/MantidGeometry/Surfaces/Line.h
+++ b/Framework/Geometry/inc/MantidGeometry/Surfaces/Line.h
@@ -3,6 +3,7 @@
 
 #include "MantidGeometry/DllConfig.h"
 #include "MantidKernel/V3D.h"
+#include <complex>
 
 namespace Mantid {
 
diff --git a/Framework/Geometry/src/Crystal/CompositeBraggScatterer.cpp b/Framework/Geometry/src/Crystal/CompositeBraggScatterer.cpp
index c36f94ac2505dd30f4194f7d4ddfa8b55362bab8..3e49afd85880d8f856895931d019b794cbbfd355 100644
--- a/Framework/Geometry/src/Crystal/CompositeBraggScatterer.cpp
+++ b/Framework/Geometry/src/Crystal/CompositeBraggScatterer.cpp
@@ -186,7 +186,7 @@ void CompositeBraggScatterer::redeclareProperties() {
     std::vector<Property *> properties =
         scatterer->getPropertiesInGroup(getPropagatingGroupName());
     for (auto &property : properties) {
-      std::string propertyName = property->name();
+      const std::string &propertyName = property->name();
       if (!existsProperty(propertyName)) {
         declareProperty(std::unique_ptr<Property>(property->clone()));
       }
diff --git a/Framework/Geometry/src/Crystal/HKLFilterWavelength.cpp b/Framework/Geometry/src/Crystal/HKLFilterWavelength.cpp
index c186dad1e842f99bb43bae74939b95209bbdc2fc..85d41346ff6c66e5483a80d0df12e3c59dfbc309 100644
--- a/Framework/Geometry/src/Crystal/HKLFilterWavelength.cpp
+++ b/Framework/Geometry/src/Crystal/HKLFilterWavelength.cpp
@@ -1,4 +1,5 @@
 #include "MantidGeometry/Crystal/HKLFilterWavelength.h"
+#include <sstream>
 #include <stdexcept>
 
 namespace Mantid {
diff --git a/Framework/Geometry/src/Crystal/IndexingUtils.cpp b/Framework/Geometry/src/Crystal/IndexingUtils.cpp
index 4e423f22dcc8285bd72c4aa4a3d8dc03ecf3cd39..676619bb1fedf3579658cabc9a8a02dfeb3033ca 100644
--- a/Framework/Geometry/src/Crystal/IndexingUtils.cpp
+++ b/Framework/Geometry/src/Crystal/IndexingUtils.cpp
@@ -1,6 +1,5 @@
 #include "MantidGeometry/Crystal/IndexingUtils.h"
 #include "MantidGeometry/Crystal/NiggliCell.h"
-#include "MantidGeometry/Crystal/OrientedLattice.h"
 #include "MantidKernel/Quat.h"
 #include <algorithm>
 #include <cmath>
@@ -53,12 +52,9 @@ const constexpr double RAD_TO_DEG = 180. / M_PI;
   @param  q_vectors           std::vector of V3D objects that contains the
                               list of q_vectors that are to be indexed
                               NOTE: There must be at least 2 q_vectors.
-  @param  a                   First unit cell edge length in Angstroms.
-  @param  b                   Second unit cell edge length in Angstroms.
-  @param  c                   Third unit cell edge length in Angstroms.
-  @param  alpha               First unit cell angle in degrees.
-  @param  beta                second unit cell angle in degrees.
-  @param  gamma               third unit cell angle in degrees.
+  @param  lattice             The orientated lattice with the lattice
+                              parameters a,b,c and alpha, beta, gamma. The found
+                              UB and errors will be set on this lattice.
   @param  required_tolerance  The maximum allowed deviation of Miller indices
                               from integer values for a peak to be indexed.
   @param  base_index          The sequence number of the peak that should
@@ -77,6 +73,8 @@ const constexpr double RAD_TO_DEG = 180. / M_PI;
                               used to scan for an initial orientation matrix.
   @param  degrees_per_step    The number of degrees between different
                               orientations used during the initial scan.
+  @param  fixAll              Fix the lattice parameters and do not optimise
+                              the UB matrix.
 
   @return  This will return the sum of the squares of the residual errors.
 
@@ -87,10 +85,10 @@ const constexpr double RAD_TO_DEG = 180. / M_PI;
                                  is <= 0.
 */
 double IndexingUtils::Find_UB(DblMatrix &UB, const std::vector<V3D> &q_vectors,
-                              double a, double b, double c, double alpha,
-                              double beta, double gamma,
+                              OrientedLattice &lattice,
                               double required_tolerance, int base_index,
-                              size_t num_initial, double degrees_per_step) {
+                              size_t num_initial, double degrees_per_step,
+                              bool fixAll) {
   if (UB.numRows() != 3 || UB.numCols() != 3) {
     throw std::invalid_argument("Find_UB(): UB matrix NULL or not 3X3");
   }
@@ -156,20 +154,18 @@ double IndexingUtils::Find_UB(DblMatrix &UB, const std::vector<V3D> &q_vectors,
   for (size_t i = 0; i < num_initial; i++)
     some_qs.push_back(sorted_qs[i]);
 
-  ScanFor_UB(UB, some_qs, a, b, c, alpha, beta, gamma, degrees_per_step,
-             required_tolerance);
+  ScanFor_UB(UB, some_qs, lattice, degrees_per_step, required_tolerance);
 
   double fit_error = 0;
   std::vector<V3D> miller_ind;
   std::vector<V3D> indexed_qs;
   miller_ind.reserve(q_vectors.size());
   indexed_qs.reserve(q_vectors.size());
+
   // now gradually bring in the remaining
   // peaks and re-optimize the UB to index
   // them as well
-  size_t count = 0;
-  while (num_initial < sorted_qs.size()) {
-    count++;
+  while (!fixAll && num_initial < sorted_qs.size()) {
     num_initial = std::lround(1.5 * static_cast<double>(num_initial + 3));
     // add 3, in case we started with
     // a very small number of peaks!
@@ -190,13 +186,15 @@ double IndexingUtils::Find_UB(DblMatrix &UB, const std::vector<V3D> &q_vectors,
     }
   }
 
-  if (q_vectors.size() >= 3) // try one last refinement using all peaks
+  std::vector<double> sigabc(7);
+  if (!fixAll &&
+      q_vectors.size() >= 3) // try one last refinement using all peaks
   {
     try {
       GetIndexedPeaks(UB, q_vectors, required_tolerance, miller_ind, indexed_qs,
                       fit_error);
-      Matrix<double> temp_UB(3, 3, false);
-      fit_error = Optimize_UB(temp_UB, miller_ind, indexed_qs);
+      Matrix<double> temp_UB = UB;
+      fit_error = Optimize_UB(temp_UB, miller_ind, indexed_qs, sigabc);
       UB = temp_UB;
     } catch (...) {
       // failed to improve UB using these peaks, so just return the current UB
@@ -207,6 +205,10 @@ double IndexingUtils::Find_UB(DblMatrix &UB, const std::vector<V3D> &q_vectors,
   // HKL space.
   GetIndexedPeaks(UB, q_vectors, required_tolerance, miller_ind, indexed_qs,
                   fit_error);
+  // set the error on the lattice parameters
+  lattice.setUB(UB);
+  lattice.setError(sigabc[0], sigabc[1], sigabc[2], sigabc[3], sigabc[4],
+                   sigabc[5]);
   return fit_error;
 }
 
@@ -583,7 +585,9 @@ double IndexingUtils::Optimize_UB(DblMatrix &UB,
                                   const std::vector<V3D> &hkl_vectors,
                                   const std::vector<V3D> &q_vectors,
                                   std::vector<double> &sigabc) {
-  double result = Optimize_UB(UB, hkl_vectors, q_vectors);
+  double result = 0;
+  result = Optimize_UB(UB, hkl_vectors, q_vectors);
+
   if (sigabc.size() < 6) {
     sigabc.clear();
     return result;
@@ -611,11 +615,10 @@ double IndexingUtils::Optimize_UB(DblMatrix &UB,
     for (int c = 0; c < 3; c++) {
 
       UB[r][c] += SMALL;
-
       GetLatticeParameters(UB, latNew);
       UB[r][c] -= SMALL;
 
-      for (int l = 0; l < 7; l++)
+      for (size_t l = 0; l < 7; l++)
         derivs[c][l] = (latNew[l] - latOrig[l]) / SMALL;
     }
 
@@ -880,12 +883,8 @@ double IndexingUtils::Optimize_Direction(V3D &best_vec,
     @param UB                 This will be set to the UB matrix that best
                               indexes the supplied list of q_vectors.
     @param q_vectors          List of locations of peaks in "Q".
-    @param a                  Lattice parameter "a".
-    @param b                  Lattice parameter "b".
-    @param c                  Lattice parameter "c".
-    @param alpha              Lattice parameter alpha.
-    @param beta               Lattice parameter beta.
-    @param gamma              Lattice parameter gamma.
+    @param cell               Unit cell defining the parameters a,b,c and
+                              alpha, beta, gamma.
     @param degrees_per_step   The number of degrees per step used when
                               scanning through all possible directions and
                               orientations for the unit cell. NOTE: The
@@ -906,14 +905,21 @@ double IndexingUtils::Optimize_Direction(V3D &best_vec,
 
  */
 double IndexingUtils::ScanFor_UB(DblMatrix &UB,
-                                 const std::vector<V3D> &q_vectors, double a,
-                                 double b, double c, double alpha, double beta,
-                                 double gamma, double degrees_per_step,
+                                 const std::vector<V3D> &q_vectors,
+                                 const UnitCell &cell, double degrees_per_step,
                                  double required_tolerance) {
   if (UB.numRows() != 3 || UB.numCols() != 3) {
     throw std::invalid_argument("Find_UB(): UB matrix NULL or not 3X3");
   }
 
+  auto a = cell.a();
+  auto b = cell.b();
+  auto c = cell.c();
+
+  auto alpha = cell.alpha();
+  auto beta = cell.beta();
+  auto gamma = cell.gamma();
+
   V3D a_dir;
   V3D b_dir;
   V3D c_dir;
diff --git a/Framework/Geometry/src/Crystal/SymmetryOperationSymbolParser.cpp b/Framework/Geometry/src/Crystal/SymmetryOperationSymbolParser.cpp
index aba6ceafb47dacbb3e2b738b03b7f7b71b01bf80..2a70dcc0792d92875125aa0f8e5de7f5fe04e598 100644
--- a/Framework/Geometry/src/Crystal/SymmetryOperationSymbolParser.cpp
+++ b/Framework/Geometry/src/Crystal/SymmetryOperationSymbolParser.cpp
@@ -98,7 +98,7 @@ std::string SymmetryOperationSymbolParser::getNormalizedIdentifier(
         if (matrix[r][c] < 0) {
           currentComponent << "-";
         } else {
-          if (currentComponent.str().size() > 0) {
+          if (!currentComponent.str().empty()) {
             currentComponent << "+";
           }
         }
diff --git a/Framework/Geometry/src/Instrument.cpp b/Framework/Geometry/src/Instrument.cpp
index ed3f35541097fb048e36d1e970bd513901c2077d..ac1e9032bb376109b777c44f2d5db38f650fc2c2 100644
--- a/Framework/Geometry/src/Instrument.cpp
+++ b/Framework/Geometry/src/Instrument.cpp
@@ -3,7 +3,9 @@
 #include "MantidGeometry/Instrument/DetectorGroup.h"
 #include "MantidGeometry/Instrument/ReferenceFrame.h"
 #include "MantidGeometry/Instrument/RectangularDetector.h"
+#include "MantidBeamline/DetectorInfo.h"
 #include "MantidKernel/Exception.h"
+#include "MantidKernel/Logger.h"
 #include "MantidKernel/PhysicalConstants.h"
 
 #include <boost/make_shared.hpp>
@@ -45,7 +47,8 @@ Instrument::Instrument(const boost::shared_ptr<const Instrument> instr,
       m_sampleCache(instr->m_sampleCache), m_defaultView(instr->m_defaultView),
       m_defaultViewAxis(instr->m_defaultViewAxis), m_instr(instr),
       m_map_nonconst(map), m_ValidFrom(instr->m_ValidFrom),
-      m_ValidTo(instr->m_ValidTo), m_referenceFrame(new ReferenceFrame) {}
+      m_ValidTo(instr->m_ValidTo), m_referenceFrame(new ReferenceFrame),
+      m_detectorInfo(instr->m_detectorInfo) {}
 
 /** Copy constructor
  *  This method was added to deal with having distinct neutronic and physical
@@ -57,11 +60,12 @@ Instrument::Instrument(const Instrument &instr)
       m_chopperPoints(new std::vector<const ObjComponent *>),
       m_sampleCache(nullptr), /* Should only be temporarily null */
       m_logfileCache(instr.m_logfileCache), m_logfileUnit(instr.m_logfileUnit),
-      m_monitorCache(instr.m_monitorCache), m_defaultView(instr.m_defaultView),
+      m_defaultView(instr.m_defaultView),
       m_defaultViewAxis(instr.m_defaultViewAxis), m_instr(),
       m_map_nonconst(), /* Should not be parameterized */
       m_ValidFrom(instr.m_ValidFrom), m_ValidTo(instr.m_ValidTo),
-      m_referenceFrame(instr.m_referenceFrame) {
+      m_referenceFrame(instr.m_referenceFrame),
+      m_detectorInfo(instr.m_detectorInfo) {
   // Now we need to fill the detector, source and sample caches with pointers
   // into the new instrument
   std::vector<IComponent_const_sptr> children;
@@ -70,11 +74,11 @@ Instrument::Instrument(const Instrument &instr)
   for (it = children.begin(); it != children.end(); ++it) {
     // First check if the current component is a detector and add to cache if it
     // is
-    // N.B. The list of monitors should remain unchanged. As the cache holds
-    // detector id
-    // numbers rather than pointers, there's no need for special handling
     if (const IDetector *det = dynamic_cast<const Detector *>(it->get())) {
-      markAsDetector(det);
+      if (instr.isMonitor(det->getID()))
+        markAsMonitor(det);
+      else
+        markAsDetector(det);
       continue;
     }
     // Now check whether the current component is the source or sample.
@@ -182,16 +186,18 @@ void Instrument::getDetectors(detid2det_map &out_map) const {
   if (m_map) {
     // Get the base instrument detectors
     out_map.clear();
-    const detid2det_map &in_dets =
-        static_cast<const Instrument *>(m_base)->m_detectorCache;
+    const auto &in_dets = m_instr->m_detectorCache;
     // And turn them into parametrized versions
     for (const auto &in_det : in_dets) {
-      out_map.emplace(in_det.first, ParComponentFactory::createDetector(
-                                        in_det.second.get(), m_map));
+      out_map.emplace(std::get<0>(in_det),
+                      ParComponentFactory::createDetector(
+                          std::get<1>(in_det).get(), m_map));
     }
   } else {
     // You can just return the detector cache directly.
-    out_map = m_detectorCache;
+    out_map.clear();
+    for (const auto &in_det : m_detectorCache)
+      out_map.emplace(std::get<0>(in_det), std::get<1>(in_det));
   }
 }
 
@@ -200,16 +206,15 @@ void Instrument::getDetectors(detid2det_map &out_map) const {
 std::vector<detid_t> Instrument::getDetectorIDs(bool skipMonitors) const {
   std::vector<detid_t> out;
   if (m_map) {
-    const detid2det_map &in_dets =
-        static_cast<const Instrument *>(m_base)->m_detectorCache;
+    const auto &in_dets = m_instr->m_detectorCache;
     for (const auto &in_det : in_dets)
-      if (!skipMonitors || !in_det.second->isMonitor())
-        out.push_back(in_det.first);
+      if (!skipMonitors || !std::get<2>(in_det))
+        out.push_back(std::get<0>(in_det));
   } else {
-    const detid2det_map &in_dets = m_detectorCache;
+    const auto &in_dets = m_detectorCache;
     for (const auto &in_det : in_dets)
-      if (!skipMonitors || !in_det.second->isMonitor())
-        out.push_back(in_det.first);
+      if (!skipMonitors || !std::get<2>(in_det))
+        out.push_back(std::get<0>(in_det));
   }
   return out;
 }
@@ -219,7 +224,7 @@ std::size_t Instrument::getNumberDetectors(bool skipMonitors) const {
   std::size_t numDetIDs(0);
 
   if (m_map) {
-    numDetIDs = static_cast<const Instrument *>(m_base)->m_detectorCache.size();
+    numDetIDs = m_instr->m_detectorCache.size();
   } else {
     numDetIDs = m_detectorCache.size();
   }
@@ -228,15 +233,14 @@ std::size_t Instrument::getNumberDetectors(bool skipMonitors) const {
   {
     std::size_t monitors(0);
     if (m_map) {
-      const detid2det_map &in_dets =
-          static_cast<const Instrument *>(m_base)->m_detectorCache;
+      const auto &in_dets = m_instr->m_detectorCache;
       for (const auto &in_det : in_dets)
-        if (in_det.second->isMonitor())
+        if (std::get<2>(in_det))
           monitors += 1;
     } else {
-      const detid2det_map &in_dets = m_detectorCache;
+      const auto &in_dets = m_detectorCache;
       for (const auto &in_det : in_dets)
-        if (in_det.second->isMonitor())
+        if (std::get<2>(in_det))
           monitors += 1;
     }
     return (numDetIDs - monitors);
@@ -251,18 +255,14 @@ std::size_t Instrument::getNumberDetectors(bool skipMonitors) const {
  * @param max :: set to the max detector ID
  */
 void Instrument::getMinMaxDetectorIDs(detid_t &min, detid_t &max) const {
-  const detid2det_map *in_dets;
-  if (m_map)
-    in_dets = &(static_cast<const Instrument *>(m_base)->m_detectorCache);
-  else
-    in_dets = &this->m_detectorCache;
+  const auto *in_dets = m_map ? &m_instr->m_detectorCache : &m_detectorCache;
 
   if (in_dets->empty())
     throw std::runtime_error(
         "No detectors on this instrument. Can't find min/max ids");
   // Maps are sorted by key. So it is easy to find
-  min = in_dets->begin()->first;
-  max = in_dets->rbegin()->first;
+  min = std::get<0>(*in_dets->begin());
+  max = std::get<0>(*in_dets->rbegin());
 }
 
 //------------------------------------------------------------------------------------------
@@ -450,6 +450,28 @@ Instrument::getAllComponentsWithName(const std::string &cname) const {
   return retVec;
 }
 
+namespace {
+// Helpers for accessing m_detectorCache, which is a vector of tuples used as a
+// map. Lookup is by first element in a tuple. Templated to support const and
+// non-const.
+template <class T>
+auto lower_bound(T &map, const detid_t key) -> decltype(map.begin()) {
+  return std::lower_bound(
+      map.begin(), map.end(),
+      std::make_tuple(key, IDetector_const_sptr(nullptr), false),
+      [](const typename T::value_type &a, const typename T::value_type &b)
+          -> bool { return std::get<0>(a) < std::get<0>(b); });
+}
+
+template <class T>
+auto find(T &map, const detid_t key) -> decltype(map.begin()) {
+  auto it = lower_bound(map, key);
+  if ((it != map.end()) && (std::get<0>(*it) == key))
+    return it;
+  return map.end();
+}
+}
+
 /**	Gets a pointer to the detector from its ID
 *  Note that for getting the detector associated with a spectrum, the
 * MatrixWorkspace::getDetector
@@ -461,20 +483,24 @@ Instrument::getAllComponentsWithName(const std::string &cname) const {
 *  @throw   NotFoundError If no detector is found for the detector ID given
 */
 IDetector_const_sptr Instrument::getDetector(const detid_t &detector_id) const {
-  if (m_map) {
-    IDetector_const_sptr baseDet = m_instr->getDetector(detector_id);
-    return ParComponentFactory::createDetector(baseDet.get(), m_map);
-  } else {
-    auto it = m_detectorCache.find(detector_id);
-    if (it == m_detectorCache.end()) {
-      std::stringstream readInt;
-      readInt << detector_id;
-      throw Kernel::Exception::NotFoundError(
-          "Instrument: Detector with ID " + readInt.str() + " not found.", "");
-    }
-
-    return it->second;
+  const auto &baseInstr = m_map ? *m_instr : *this;
+  const auto it = find(baseInstr.m_detectorCache, detector_id);
+  if (it == baseInstr.m_detectorCache.end()) {
+    std::stringstream readInt;
+    readInt << detector_id;
+    throw Kernel::Exception::NotFoundError(
+        "Instrument: Detector with ID " + readInt.str() + " not found.", "");
   }
+  IDetector_const_sptr baseDet = std::get<1>(*it);
+
+  if (!m_map)
+    return baseDet;
+
+  auto det = ParComponentFactory::createDetector(baseDet.get(), m_map);
+  // Set the linear detector index, used for legacy accessors to obtain data
+  // from Beamline::DetectorInfo, which is stored in the ParameterMap.
+  det->setIndex(std::distance(baseInstr.m_detectorCache.cbegin(), it));
+  return det;
 }
 
 /**	Gets a pointer to the base (non-parametrized) detector from its ID
@@ -483,23 +509,19 @@ IDetector_const_sptr Instrument::getDetector(const detid_t &detector_id) const {
   *  @returns A const pointer to the detector object
   */
 const IDetector *Instrument::getBaseDetector(const detid_t &detector_id) const {
-  auto it = m_instr->m_detectorCache.find(detector_id);
+  auto it = find(m_instr->m_detectorCache, detector_id);
   if (it == m_instr->m_detectorCache.end()) {
     return nullptr;
   }
-  return it->second.get();
+  return std::get<1>(*it).get();
 }
 
 bool Instrument::isMonitor(const detid_t &detector_id) const {
-  // Find the (base) detector object in the map.
-  auto it = m_instr->m_detectorCache.find(detector_id);
-  if (it == m_instr->m_detectorCache.end())
-    return false;
-  // This is the detector
-  const Detector *det = dynamic_cast<const Detector *>(it->second.get());
-  if (det == nullptr)
+  const auto &baseInstr = m_map ? *m_instr : *this;
+  const auto it = find(baseInstr.m_detectorCache, detector_id);
+  if (it == baseInstr.m_detectorCache.end())
     return false;
-  return det->isMonitor();
+  return std::get<2>(*it);
 }
 
 bool Instrument::isMonitor(const std::set<detid_t> &detector_ids) const {
@@ -513,53 +535,6 @@ bool Instrument::isMonitor(const std::set<detid_t> &detector_ids) const {
   return false;
 }
 
-//--------------------------------------------------------------------------
-/** Is the detector with the given ID masked?
- *
- * @param detector_id :: detector ID to look for.
- * @return true if masked; false if not masked or if the detector was not found.
- */
-bool Instrument::isDetectorMasked(const detid_t &detector_id) const {
-  // With no parameter map, then no detector is EVER masked
-  if (!isParametrized())
-    return false;
-  // Find the (base) detector object in the map.
-  auto it = m_instr->m_detectorCache.find(detector_id);
-  if (it == m_instr->m_detectorCache.end())
-    return false;
-  // This is the detector
-  const Detector *det = dynamic_cast<const Detector *>(it->second.get());
-  if (det == nullptr)
-    return false;
-  // Access the parameter map directly.
-  Parameter_sptr maskedParam = m_map->get(det, "masked");
-  if (!maskedParam)
-    return false;
-  // If the parameter is defined, then yes, it is masked.
-  return maskedParam->value<bool>();
-}
-
-//--------------------------------------------------------------------------
-/** Is this group of detectors masked?
- *
- * This returns true (masked) if ALL of the detectors listed are masked.
- * It returns false (not masked) if there are no detectors in the list
- * It returns false (not masked) if any of the detectors are NOT masked.
- *
- * @param detector_ids :: set of detector IDs
- * @return true if masked.
- */
-bool Instrument::isDetectorMasked(const std::set<detid_t> &detector_ids) const {
-  if (detector_ids.empty())
-    return false;
-
-  for (auto detector_id : detector_ids) {
-    if (!this->isDetectorMasked(detector_id))
-      return false;
-  }
-  return true;
-}
-
 /**
  * Returns a pointer to the geometrical object for the given set of IDs
  * @param det_ids :: A list of detector ids
@@ -567,16 +542,15 @@ bool Instrument::isDetectorMasked(const std::set<detid_t> &detector_ids) const {
  *  @throw   NotFoundError If no detector is found for the detector ID given
  */
 IDetector_const_sptr
-Instrument::getDetectorG(const std::vector<detid_t> &det_ids) const {
+Instrument::getDetectorG(const std::set<detid_t> &det_ids) const {
   const size_t ndets(det_ids.size());
   if (ndets == 1) {
-    return this->getDetector(det_ids[0]);
+    return this->getDetector(*det_ids.begin());
   } else {
     boost::shared_ptr<DetectorGroup> det_group =
         boost::make_shared<DetectorGroup>();
-    bool warn(false);
-    for (size_t i = 0; i < ndets; ++i) {
-      det_group->addDetector(this->getDetector(det_ids[i]), warn);
+    for (const auto detID : det_ids) {
+      det_group->addDetector(this->getDetector(detID));
     }
     return det_group;
   }
@@ -710,9 +684,45 @@ void Instrument::markAsDetector(const IDetector *det) {
 
   // Create a (non-deleting) shared pointer to it
   IDetector_const_sptr det_sptr = IDetector_const_sptr(det, NoDeleting());
-  auto it = m_detectorCache.end();
-  m_detectorCache.insert(it, std::map<int, IDetector_const_sptr>::value_type(
-                                 det->getID(), det_sptr));
+  auto it = lower_bound(m_detectorCache, det->getID());
+  // Silently ignore detector IDs that are already marked as detectors, even if
+  // the actual detector is different.
+  if ((it == m_detectorCache.end()) || (std::get<0>(*it) != det->getID())) {
+    bool isMonitor = false;
+    m_detectorCache.emplace(it, det->getID(), det_sptr, isMonitor);
+  }
+}
+
+/// As markAsDetector but without the required sorting. Must call
+/// markAsDetectorFinalize before accessing detectors.
+void Instrument::markAsDetectorIncomplete(const IDetector *det) {
+  if (m_map)
+    throw std::runtime_error("Instrument::markAsDetector() called on a "
+                             "parametrized Instrument object.");
+
+  // Create a (non-deleting) shared pointer to it
+  IDetector_const_sptr det_sptr = IDetector_const_sptr(det, NoDeleting());
+  bool isMonitor = false;
+  m_detectorCache.emplace_back(det->getID(), det_sptr, isMonitor);
+}
+
+/// Sorts the detector cache. Called after all detectors have been marked via
+/// markAsDetectorIncomplete.
+void Instrument::markAsDetectorFinalize() {
+  // markAsDetector silently ignores detector IDs that are already marked as
+  // detectors, even if the actual detector is different. We mimic this behavior
+  // in this final sort by using stable_sort and removing duplicates. This will
+  // effectively favor the first detector with a certain ID that was added.
+  std::stable_sort(m_detectorCache.begin(), m_detectorCache.end(),
+                   [](const std::tuple<detid_t, IDetector_const_sptr, bool> &a,
+                      const std::tuple<detid_t, IDetector_const_sptr, bool> &b)
+                       -> bool { return std::get<0>(a) < std::get<0>(b); });
+  m_detectorCache.erase(
+      std::unique(m_detectorCache.begin(), m_detectorCache.end(),
+                  [](const std::tuple<detid_t, IDetector_const_sptr, bool> &a,
+                     const std::tuple<detid_t, IDetector_const_sptr, bool> &b)
+                      -> bool { return std::get<0>(a) == std::get<0>(b); }),
+      m_detectorCache.end());
 }
 
 /** Mark a Component which has already been added to the Instrument class
@@ -723,7 +733,7 @@ void Instrument::markAsDetector(const IDetector *det) {
 *
 * @throw Exception::ExistsError if cannot add detector to cache
 */
-void Instrument::markAsMonitor(IDetector *det) {
+void Instrument::markAsMonitor(const IDetector *det) {
   if (m_map)
     throw std::runtime_error("Instrument::markAsMonitor() called on a "
                              "parametrized Instrument object.");
@@ -732,14 +742,8 @@ void Instrument::markAsMonitor(IDetector *det) {
   markAsDetector(det);
 
   // mark detector as a monitor
-  Detector *d = dynamic_cast<Detector *>(det);
-  if (d) {
-    d->markAsMonitor();
-    m_monitorCache.push_back(det->getID());
-  } else {
-    throw std::invalid_argument(
-        "The IDetector pointer does not point to a Detector object");
-  }
+  auto it = find(m_detectorCache, det->getID());
+  std::get<2>(*it) = true;
 }
 
 /** Removes a detector from the instrument and from the detector cache.
@@ -753,13 +757,8 @@ void Instrument::removeDetector(IDetector *det) {
 
   const detid_t id = det->getID();
   // Remove the detector from the detector cache
-  m_detectorCache.erase(id);
-  // Also need to remove from monitor cache if appropriate
-  if (det->isMonitor()) {
-    auto it = std::find(m_monitorCache.begin(), m_monitorCache.end(), id);
-    if (it != m_monitorCache.end())
-      m_monitorCache.erase(it);
-  }
+  const auto it = find(m_detectorCache, id);
+  m_detectorCache.erase(it);
 
   // Remove it from the parent assembly (and thus the instrument). Evilness
   // required here unfortunately.
@@ -777,21 +776,13 @@ void Instrument::removeDetector(IDetector *det) {
 std::vector<detid_t> Instrument::getMonitors() const {
   // Monitors cannot be parametrized. So just return the base.
   if (m_map)
-    return static_cast<const Instrument *>(m_base)->m_monitorCache;
-  else
-    return m_monitorCache;
-}
+    return m_instr->getMonitors();
 
-/**
- * Returns the number of monitors attached to this instrument
- * @returns The number of monitors within the instrument
- */
-size_t Instrument::numMonitors() const {
-  if (m_map) {
-    return static_cast<const Instrument *>(m_base)->m_monitorCache.size();
-  } else {
-    return m_monitorCache.size();
-  }
+  std::vector<detid_t> mons;
+  for (const auto &item : m_detectorCache)
+    if (std::get<2>(item))
+      mons.push_back(std::get<0>(item));
+  return mons;
 }
 
 /**
@@ -902,14 +893,14 @@ const double CONSTANT = (PhysicalConstants::h * 1e10) /
  *        the length of the distance between the two.
  * @param beamline_norm: (source to sample distance) * 2.0 (apparently)
  * @param samplePos: position of the sample
- * @param det: Geometry object representing the detector (position of the pixel)
+ * @param detPos: position of the detector
  * @param offset: value (close to zero) that changes the factor := factor *
  *(1+offset).
  */
 double Instrument::calcConversion(const double l1, const Kernel::V3D &beamline,
                                   const double beamline_norm,
                                   const Kernel::V3D &samplePos,
-                                  const IDetector_const_sptr &det,
+                                  const Kernel::V3D &detPos,
                                   const double offset) {
   if (offset <=
       -1.) // not physically possible, means result is negative d-spacing
@@ -920,17 +911,12 @@ double Instrument::calcConversion(const double l1, const Kernel::V3D &beamline,
     throw std::logic_error(msg.str());
   }
 
-  // Get the sample-detector distance for this detector (in metres)
-
-  // The scattering angle for this detector (in radians).
-  Kernel::V3D detPos;
-  detPos = det->getPos();
-
   // Now detPos will be set with respect to samplePos
-  detPos -= samplePos;
+  Kernel::V3D relDetPos = detPos - samplePos;
   // 0.5*cos(2theta)
-  double l2 = detPos.norm();
-  double halfcosTwoTheta = detPos.scalar_prod(beamline) / (l2 * beamline_norm);
+  double l2 = relDetPos.norm();
+  double halfcosTwoTheta =
+      relDetPos.scalar_prod(beamline) / (l2 * beamline_norm);
   // This is sin(theta)
   double sinTheta = sqrt(0.5 - halfcosTwoTheta);
   const double numerator = (1.0 + offset);
@@ -957,8 +943,9 @@ double Instrument::calcConversion(
     } else {
       offset = 0.;
     }
-    factor += calcConversion(l1, beamline, beamline_norm, samplePos,
-                             instrument->getDetector(detector), offset);
+    factor +=
+        calcConversion(l1, beamline, beamline_norm, samplePos,
+                       instrument->getDetector(detector)->getPos(), offset);
   }
   return factor / static_cast<double>(detectors.size());
 }
@@ -1062,7 +1049,18 @@ void Instrument::saveNexus(::NeXus::File *file,
 
   // Now the parameter map, as a NXnote via its saveNexus method
   if (isParametrized()) {
-    const Geometry::ParameterMap &params = *getParameterMap();
+    Geometry::ParameterMap params(*getParameterMap());
+    // Masking is in DetectorInfo. Insert it into ParameterMap so it is saved
+    // alongside other parameters.
+    if (m_detectorInfo) {
+      const auto &detIDs = getDetectorIDs();
+      for (size_t i = 0; i < m_detectorInfo->size(); ++i) {
+        if (m_detectorInfo->isMasked(i)) {
+          const auto *det = getBaseDetector(detIDs.at(i));
+          params.forceUnsafeSetMasked(det, true);
+        }
+      }
+    }
     params.saveNexus(file, "instrument_parameter_map");
   }
 
@@ -1080,7 +1078,7 @@ void Instrument::saveNexus(::NeXus::File *file,
     auto detmons = getDetectors(detmonIDs);
     std::vector<detid_t> monitorIDs;
     for (size_t i = 0; i < detmonIDs.size(); i++) {
-      if (detmons[i]->isMonitor())
+      if (isMonitorViaIndex(i))
         monitorIDs.push_back(detmonIDs[i]);
     }
 
@@ -1242,7 +1240,7 @@ Instrument::ContainsState Instrument::containsRectDetectors() const {
     // Skip monitors
     IDetector_const_sptr detector =
         boost::dynamic_pointer_cast<const IDetector>(comp);
-    if (detector && detector->isMonitor())
+    if (detector && isMonitor(detector->getID()))
       continue;
 
     // skip choppers HACK!
@@ -1281,5 +1279,33 @@ Instrument::ContainsState Instrument::containsRectDetectors() const {
 
 } // containsRectDetectors
 
+/// Temporary helper for refactoring. Argument is index, *not* ID!
+bool Instrument::isMonitorViaIndex(const size_t index) const {
+  if (m_map)
+    return std::get<2>(m_instr->m_detectorCache[index]);
+  else
+    return std::get<2>(m_detectorCache[index]);
+}
+
+/// Only for use by ExperimentInfo. Returns returns true if this instrument
+/// contains a DetectorInfo.
+bool Instrument::hasDetectorInfo() const {
+  return static_cast<bool>(m_detectorInfo);
+}
+/// Only for use by ExperimentInfo. Returns a reference to the DetectorInfo.
+const Beamline::DetectorInfo &Instrument::detectorInfo() const {
+  if (!hasDetectorInfo())
+    throw std::runtime_error("Cannot return reference to NULL DetectorInfo");
+  return *m_detectorInfo;
+}
+
+/// Only for use by ExperimentInfo. Sets the pointer to the DetectorInfo.
+void Instrument::setDetectorInfo(
+    boost::shared_ptr<const Beamline::DetectorInfo> detectorInfo) {
+  if (m_map_nonconst)
+    m_map_nonconst->setDetectorInfo(detectorInfo);
+  m_detectorInfo = std::move(detectorInfo);
+}
+
 } // namespace Geometry
 } // Namespace Mantid
diff --git a/Framework/Geometry/src/Instrument/Component.cpp b/Framework/Geometry/src/Instrument/Component.cpp
index a707ea7e27872af535b52a947499f398e51a3e9b..98434ee78a2d438c6ab65d74b11fc29dc55f2ebc 100644
--- a/Framework/Geometry/src/Instrument/Component.cpp
+++ b/Framework/Geometry/src/Instrument/Component.cpp
@@ -1,6 +1,7 @@
 #include "MantidGeometry/IComponent.h"
 #include "MantidGeometry/Instrument/ParComponentFactory.h"
 #include "MantidGeometry/Instrument/Component.h"
+#include "MantidGeometry/Objects/BoundingBox.h"
 #include "MantidKernel/Exception.h"
 
 #include <Poco/XML/XMLWriter.h>
diff --git a/Framework/Geometry/src/Instrument/ComponentHelper.cpp b/Framework/Geometry/src/Instrument/ComponentHelper.cpp
index ffc46c880af12d8efae417f88eda2eb3656f3945..7c9b75afdddd03f5d6c738341beedaf4212d72d2 100644
--- a/Framework/Geometry/src/Instrument/ComponentHelper.cpp
+++ b/Framework/Geometry/src/Instrument/ComponentHelper.cpp
@@ -1,10 +1,8 @@
-//-----------------------------------------------------------------------------
-// Includes
-//-----------------------------------------------------------------------------
 #include "MantidGeometry/Instrument/ComponentHelper.h"
 #include "MantidGeometry/Instrument/ParameterMap.h"
 #include "MantidGeometry/IComponent.h"
 #include "MantidGeometry/Instrument/ReferenceFrame.h"
+#include "MantidGeometry/Objects/Object.h"
 #include "MantidGeometry/Objects/ShapeFactory.h"
 #include "MantidGeometry/Instrument/Detector.h"
 
diff --git a/Framework/Geometry/src/Instrument/Detector.cpp b/Framework/Geometry/src/Instrument/Detector.cpp
index ce6d6b477919482b56129096303b37be9cc25a4d..1391d3d4c7088d864e2e617eb90f9abf6b6ae0f8 100644
--- a/Framework/Geometry/src/Instrument/Detector.cpp
+++ b/Framework/Geometry/src/Instrument/Detector.cpp
@@ -1,5 +1,6 @@
 #include "MantidGeometry/Instrument/Detector.h"
 #include "MantidGeometry/Instrument/ParameterMap.h"
+#include "MantidKernel/Logger.h"
 
 namespace Mantid {
 namespace Geometry {
@@ -16,7 +17,7 @@ using Kernel::Quat;
  * @param map: pointer to the ParameterMap
  * */
 Detector::Detector(const Detector *base, const ParameterMap *map)
-    : ObjComponent(base, map), m_id(base->m_id), m_isMonitor(false) {}
+    : ObjComponent(base, map), m_id(base->m_id) {}
 
 /** Constructor
  *  @param name :: The name of the component
@@ -24,7 +25,7 @@ Detector::Detector(const Detector *base, const ParameterMap *map)
  *  @param parent :: The parent component
  */
 Detector::Detector(const std::string &name, int id, IComponent *parent)
-    : IDetector(), ObjComponent(name, parent), m_id(id), m_isMonitor(false) {}
+    : IDetector(), ObjComponent(name, parent), m_id(id) {}
 
 /** Constructor
  *  @param name :: The name of the component
@@ -35,8 +36,7 @@ Detector::Detector(const std::string &name, int id, IComponent *parent)
  */
 Detector::Detector(const std::string &name, int id,
                    boost::shared_ptr<Object> shape, IComponent *parent)
-    : IDetector(), ObjComponent(name, shape, parent), m_id(id),
-      m_isMonitor(false) {}
+    : IDetector(), ObjComponent(name, shape, parent), m_id(id) {}
 
 /** Gets the detector id
  *  @returns the detector id
@@ -121,38 +121,14 @@ det_topology Detector::getTopology(V3D &center) const {
   return rect;
 }
 
-/** Returns true if the detector is masked. Only Parametrized instruments
- * can have masked detectors.
- *  @return false
- */
-bool Detector::isMasked() const {
-  if (m_map) {
-    Parameter_sptr par = m_map->get(m_base, "masked");
-    if (par)
-      return par->value<bool>();
-  }
-  // If you get to here, instead of the Detector method, then it isn't masked
-  return false;
-}
-
-/// Is the detector a monitor?
-///@return true if it is a monitor
-bool Detector::isMonitor() const {
-  if (m_map) {
-    const Detector *d = dynamic_cast<const Detector *>(m_base);
-    if (d) {
-      return d->isMonitor();
-    }
-  }
+/// Helper for legacy access mode. Returns a reference to the ParameterMap.
+const ParameterMap &Detector::parameterMap() const { return *m_map; }
 
-  return m_isMonitor;
-}
+/// Helper for legacy access mode. Returns the index of the detector.
+size_t Detector::index() const { return m_index; }
 
-/** Sets the flag for whether this detector object is a monitor
- *  @param flag :: True to mark the detector a monitor (default), false
- * otherwise
- */
-void Detector::markAsMonitor(const bool flag) { m_isMonitor = flag; }
+/// Helper for legacy access mode. Sets the index of the detector.
+void Detector::setIndex(const size_t index) { m_index = index; }
 
 } // Namespace Geometry
 } // Namespace Mantid
diff --git a/Framework/Geometry/src/Instrument/DetectorGroup.cpp b/Framework/Geometry/src/Instrument/DetectorGroup.cpp
index abc36ded770f0b95735c53ce7becf958eee74473..cde28fbc98066e1dc200af5bd319cb97df5fcaa4 100644
--- a/Framework/Geometry/src/Instrument/DetectorGroup.cpp
+++ b/Framework/Geometry/src/Instrument/DetectorGroup.cpp
@@ -1,9 +1,7 @@
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidGeometry/Instrument/DetectorGroup.h"
 #include "MantidGeometry/Objects/BoundingBox.h"
 #include "MantidKernel/Exception.h"
+#include "MantidKernel/Logger.h"
 #include "MantidKernel/Material.h"
 
 namespace Mantid {
@@ -25,12 +23,9 @@ DetectorGroup::DetectorGroup()
 /** Constructor that takes a list of detectors to add
 *  @param dets :: The vector of IDetector pointers that this virtual detector
 * will hold
-*  @param warnAboutMasked :: If true a log message at warning level will be
-* generated if a one of the detectors in dets is masked.
 *  @throw std::invalid_argument If an empty vector is passed as argument
 */
-DetectorGroup::DetectorGroup(const std::vector<IDetector_const_sptr> &dets,
-                             bool warnAboutMasked)
+DetectorGroup::DetectorGroup(const std::vector<IDetector_const_sptr> &dets)
     : IDetector(), m_id(), m_detectors(), group_topology(undef) {
   if (dets.empty()) {
     g_log.error("Illegal attempt to create an empty DetectorGroup");
@@ -38,36 +33,23 @@ DetectorGroup::DetectorGroup(const std::vector<IDetector_const_sptr> &dets,
   }
   std::vector<IDetector_const_sptr>::const_iterator it;
   for (it = dets.begin(); it != dets.end(); ++it) {
-    addDetector(*it, warnAboutMasked);
+    addDetector(*it);
   }
 }
 
 /** Add a detector to the collection
 *  @param det ::  A pointer to the detector to add
-*  @param warn :: Whether to issue warnings to the log
 */
-void DetectorGroup::addDetector(IDetector_const_sptr det, bool &warn) {
+void DetectorGroup::addDetector(IDetector_const_sptr det) {
   // the topology of the group become undefined and needs recalculation if new
   // detector has been added to the group
   group_topology = undef;
-  // Warn if adding a masked detector
-  if (warn && det->isMasked()) {
-    g_log.warning() << "Adding a detector (ID:" << det->getID()
-                    << ") that is flagged as masked.\n";
-    warn = false;
-  }
 
   // For now at least, the ID is the same as the first detector that is added
   if (m_detectors.empty())
     m_id = det->getID();
 
-  if ((!m_detectors.insert(DetCollection::value_type(det->getID(), det))
-            .second) &&
-      warn) {
-    g_log.warning() << "Detector with ID " << det->getID()
-                    << " is already in group.\n";
-    warn = false;
-  }
+  m_detectors.insert(DetCollection::value_type(det->getID(), det));
 }
 
 detid_t DetectorGroup::getID() const { return m_id; }
@@ -204,7 +186,6 @@ std::vector<IDetector_const_sptr> DetectorGroup::getDetectors() const {
 
 /** Gives the total solid angle subtended by a group of detectors by summing the
  *  contributions from the individual detectors.
- *  Any masked detector in the group is excluded from the sum.
  *  @param observer :: The point from which the detector is being viewed
  *  @return The solid angle in steradians
  *  @throw NullPointerException If geometrical form of any detector has not been
@@ -215,28 +196,11 @@ double DetectorGroup::solidAngle(const V3D &observer) const {
   DetCollection::const_iterator it;
   for (it = m_detectors.begin(); it != m_detectors.end(); ++it) {
     IDetector_const_sptr det = (*it).second;
-    if (!det->isMasked())
-      result += det->solidAngle(observer);
+    result += det->solidAngle(observer);
   }
   return result;
 }
 
-/** Are ALL the detectors in this group masked?
- *  @return True if every one of the detectors in this group is masked, false
- * otherwise.
- */
-bool DetectorGroup::isMasked() const {
-  bool isMasked = true;
-  DetCollection::const_iterator it;
-  for (it = m_detectors.begin(); it != m_detectors.end(); ++it) {
-    if (!(*it).second->isMasked()) {
-      isMasked = false;
-      break;
-    }
-  }
-  return isMasked;
-}
-
 /** Return true if any detector in the group is parametrized.
  *
  */
@@ -248,22 +212,6 @@ bool DetectorGroup::isParametrized() const {
   return false;
 }
 
-/** Indicates whether this is a monitor.
-*  Will return false if even one member of the group is not flagged as a monitor
-*  @return is detector group a monitor
-*/
-bool DetectorGroup::isMonitor() const {
-  // Would you ever want to group monitors?
-  // For now, treat as NOT a monitor if even one isn't
-  bool isMonitor = true;
-  DetCollection::const_iterator it;
-  for (it = m_detectors.begin(); it != m_detectors.end(); ++it) {
-    if (!(*it).second->isMonitor())
-      isMonitor = false;
-  }
-  return isMonitor;
-}
-
 /** isValid() is true if the point is inside any of the detectors, i.e. one of
 * the
 *  detectors has isValid() == true
@@ -496,5 +444,21 @@ const Kernel::Material DetectorGroup::material() const {
   return Kernel::Material();
 }
 
+/// Helper for legacy access mode. Always throws for DetectorGroup.
+const ParameterMap &DetectorGroup::parameterMap() const {
+  throw std::runtime_error("A DetectorGroup cannot have a ParameterMap");
+}
+
+/// Helper for legacy access mode. Always throws for DetectorGroup.
+size_t DetectorGroup::index() const {
+  throw std::runtime_error("A DetectorGroup cannot have an index");
+}
+
+/// Helper for legacy access mode. Always throws for DetectorGroup.
+void DetectorGroup::setIndex(const size_t index) {
+  UNUSED_ARG(index);
+  throw std::runtime_error("A DetectorGroup cannot have an index");
+}
+
 } // namespace Geometry
 } // namespace Mantid
diff --git a/Framework/Geometry/src/Instrument/InstrumentDefinitionParser.cpp b/Framework/Geometry/src/Instrument/InstrumentDefinitionParser.cpp
index ad4df1589551b08db77111481a7d00deb1a8f1a2..bd39329746cd72c27efc4ab948855c53239e4b14 100644
--- a/Framework/Geometry/src/Instrument/InstrumentDefinitionParser.cpp
+++ b/Framework/Geometry/src/Instrument/InstrumentDefinitionParser.cpp
@@ -28,6 +28,7 @@
 #include <Poco/Path.h>
 #include <Poco/SAX/AttributesImpl.h>
 #include <Poco/String.h>
+#include <Poco/XML/XMLWriter.h>
 
 #include <boost/make_shared.hpp>
 #include <boost/regex.hpp>
@@ -454,6 +455,12 @@ InstrumentDefinitionParser::parseXML(Kernel::ProgressBase *prog) {
   if (m_indirectPositions)
     createNeutronicInstrument();
 
+  // Instrument::markAsDetector is slow unless the detector IDs in the IDF are
+  // sorted. To circumvent this we use the 2-part interface,
+  // markAsDetectorIncomplete (which does not sort) and markAsDetectorFinalize
+  // (which does the final sorting).
+  m_instrument->markAsDetectorFinalize();
+
   // And give back what we created
   return m_instrument;
 }
@@ -753,7 +760,7 @@ Poco::XML::Element *InstrumentDefinitionParser::getParentComponent(
     const Poco::XML::Element *pLocElem) {
   if ((pLocElem->tagName()).compare("location") &&
       (pLocElem->tagName()).compare("locations")) {
-    std::string tagname = pLocElem->tagName();
+    const std::string &tagname = pLocElem->tagName();
     g_log.error("Argument to function getParentComponent must be a pointer to "
                 "an XML element with tag name location or locations.");
     throw std::logic_error(
@@ -1237,7 +1244,7 @@ void InstrumentDefinitionParser::createDetectorOrMonitor(
            pLocElem->getAttribute("mark-as").compare("monitor") == 0)) {
         m_instrument->markAsMonitor(detector);
       } else
-        m_instrument->markAsDetector(detector);
+        m_instrument->markAsDetectorIncomplete(detector);
     }
 
   } catch (Kernel::Exception::ExistsError &) {
@@ -1350,7 +1357,7 @@ void InstrumentDefinitionParser::createRectangularDetector(
           if (m_haveDefaultFacing)
             makeXYplaneFaceComponent(comp, m_defaultFacing);
           // Mark it as a detector (add to the instrument cache)
-          m_instrument->markAsDetector(detector.get());
+          m_instrument->markAsDetectorIncomplete(detector.get());
         }
       }
     }
@@ -1495,7 +1502,7 @@ void InstrumentDefinitionParser::createStructuredDetector(
           if (m_haveDefaultFacing)
             makeXYplaneFaceComponent(comp, m_defaultFacing);
           // Mark it as a detector (add to the instrument cache)
-          m_instrument->markAsDetector(detector.get());
+          m_instrument->markAsDetectorIncomplete(detector.get());
         }
       }
     }
diff --git a/Framework/Geometry/src/Instrument/ObjComponent.cpp b/Framework/Geometry/src/Instrument/ObjComponent.cpp
index 98a4c86a987f90810111b2b1dcf1e031b60b538e..127e17a3a983dd139eba31a56058b8d8438daea4 100644
--- a/Framework/Geometry/src/Instrument/ObjComponent.cpp
+++ b/Framework/Geometry/src/Instrument/ObjComponent.cpp
@@ -1,9 +1,7 @@
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidGeometry/Instrument/ObjComponent.h"
 #include "MantidGeometry/Objects/Object.h"
 #include "MantidGeometry/Objects/BoundingBox.h"
+#include "MantidGeometry/Objects/Track.h"
 #include "MantidKernel/Exception.h"
 #include "MantidKernel/Material.h"
 #include "MantidGeometry/Rendering/GeometryHandler.h"
@@ -34,7 +32,8 @@ ObjComponent::ObjComponent(const std::string &name, IComponent *parent)
 * component
 *  @param parent :: The Parent geometry object of this component
 */
-ObjComponent::ObjComponent(const std::string &name, Object_const_sptr shape,
+ObjComponent::ObjComponent(const std::string &name,
+                           boost::shared_ptr<const Object> shape,
                            IComponent *parent)
     : IObjComponent(), Component(name, parent), m_shape(shape) {}
 
diff --git a/Framework/Geometry/src/Instrument/ParameterMap.cpp b/Framework/Geometry/src/Instrument/ParameterMap.cpp
index f7fa224ba088f67db961c7d6a454603f336c34f0..0d7916d7a88c33fdf04c3c66bd6dedeebc74f9ef 100644
--- a/Framework/Geometry/src/Instrument/ParameterMap.cpp
+++ b/Framework/Geometry/src/Instrument/ParameterMap.cpp
@@ -1,8 +1,10 @@
 #include "MantidGeometry/Instrument/ParameterMap.h"
 #include "MantidGeometry/Objects/BoundingBox.h"
 #include "MantidGeometry/IDetector.h"
+#include "MantidKernel/Cache.h"
 #include "MantidKernel/MultiThreaded.h"
 #include "MantidGeometry/Instrument.h"
+#include "MantidGeometry/Instrument/ParameterFactory.h"
 #include <cstring>
 #include <boost/algorithm/string.hpp>
 
@@ -38,6 +40,12 @@ const std::string QUAT_PARAM_NAME = "Quat";
 
 // static logger reference
 Kernel::Logger g_log("ParameterMap");
+
+void checkIsNotMaskingParameter(const std::string &name) {
+  if (name == std::string("masked"))
+    throw std::runtime_error("Masking data (\"masked\") cannot be stored in "
+                             "ParameterMap. Use DetectorInfo instead");
+}
 }
 //--------------------------------------------------------------------------
 // Public method
@@ -45,7 +53,29 @@ Kernel::Logger g_log("ParameterMap");
 /**
  * Default constructor
  */
-ParameterMap::ParameterMap() : m_parameterFileNames(), m_map() {}
+ParameterMap::ParameterMap()
+    : m_cacheLocMap(
+          Kernel::make_unique<Kernel::Cache<const ComponentID, Kernel::V3D>>()),
+      m_cacheRotMap(Kernel::make_unique<
+          Kernel::Cache<const ComponentID, Kernel::Quat>>()),
+      m_boundingBoxMap(Kernel::make_unique<
+          Kernel::Cache<const ComponentID, BoundingBox>>()) {}
+
+ParameterMap::ParameterMap(const ParameterMap &other)
+    : m_parameterFileNames(other.m_parameterFileNames), m_map(other.m_map),
+      m_cacheLocMap(
+          Kernel::make_unique<Kernel::Cache<const ComponentID, Kernel::V3D>>(
+              *other.m_cacheLocMap)),
+      m_cacheRotMap(
+          Kernel::make_unique<Kernel::Cache<const ComponentID, Kernel::Quat>>(
+              *other.m_cacheRotMap)),
+      m_boundingBoxMap(
+          Kernel::make_unique<Kernel::Cache<const ComponentID, BoundingBox>>(
+              *other.m_boundingBoxMap)),
+      m_detectorInfo(other.m_detectorInfo) {}
+
+// Defined as default in source for forward declaration with std::unique_ptr.
+ParameterMap::~ParameterMap() = default;
 
 /**
 * Return string to be inserted into the parameter map
@@ -262,6 +292,7 @@ const std::string ParameterMap::diff(const ParameterMap &rhs,
  * @param name :: The name of the parameter
  */
 void ParameterMap::clearParametersByName(const std::string &name) {
+  checkIsNotMaskingParameter(name);
   // Key is component ID so have to search through whole lot
   for (auto itr = m_map.begin(); itr != m_map.end();) {
     if (itr->second->name() == name) {
@@ -282,6 +313,7 @@ void ParameterMap::clearParametersByName(const std::string &name) {
  */
 void ParameterMap::clearParametersByName(const std::string &name,
                                          const IComponent *comp) {
+  checkIsNotMaskingParameter(name);
   if (!m_map.empty()) {
     const ComponentID id = comp->getComponentID();
     auto itrs = m_map.equal_range(id);
@@ -332,6 +364,7 @@ void ParameterMap::add(const std::string &type, const IComponent *comp,
 void ParameterMap::add(const IComponent *comp,
                        const boost::shared_ptr<Parameter> &par,
                        const std::string *const pDescription) {
+  checkIsNotMaskingParameter(par->name());
   // can not add null pointer
   if (!par)
     return;
@@ -573,6 +606,33 @@ void ParameterMap::addBool(const IComponent *comp, const std::string &name,
   add(pBool(), comp, name, value, pDescription);
 }
 
+/** Force adding masking information. ONLY FOR INTERNAL USE by class Instrument.
+ *
+ * ParameterMap usually rejects "legacy style" masking information since it is
+ * now stored in DetectorInfo. However, for the purpose of writing files class
+ * Instrument needs to insert masking information. This method is only for
+ * internal use by class Instrument. ParameterMaps modified by this method are
+ * only for use as a temporary. */
+void ParameterMap::forceUnsafeSetMasked(const IComponent *comp, bool value) {
+  const std::string name("masked");
+  auto param = create(pBool(), name);
+  auto typedParam = boost::dynamic_pointer_cast<ParameterType<bool>>(param);
+  typedParam->setValue(value);
+
+// When using Clang & Linux, TBB 4.4 doesn't detect C++11 features.
+// https://software.intel.com/en-us/forums/intel-threading-building-blocks/topic/641658
+#if defined(__clang__) && !defined(__APPLE__)
+#define CLANG_ON_LINUX true
+#else
+#define CLANG_ON_LINUX false
+#endif
+#if TBB_VERSION_MAJOR >= 4 && TBB_VERSION_MINOR >= 4 && !CLANG_ON_LINUX
+  m_map.emplace(comp->getComponentID(), param);
+#else
+  m_map.insert(std::make_pair(comp->getComponentID(), param));
+#endif
+}
+
 /**
  * Adds a std::string value to the parameter map.
  * @param comp :: Component to which the new parameter is related
@@ -668,6 +728,7 @@ bool ParameterMap::contains(const IComponent *comp, const std::string &name,
  */
 bool ParameterMap::contains(const IComponent *comp, const char *name,
                             const char *type) const {
+  checkIsNotMaskingParameter(name);
   if (m_map.empty())
     return false;
   const ComponentID id = comp->getComponentID();
@@ -690,6 +751,7 @@ bool ParameterMap::contains(const IComponent *comp, const char *name,
  */
 bool ParameterMap::contains(const IComponent *comp,
                             const Parameter &parameter) const {
+  checkIsNotMaskingParameter(parameter.name());
   if (m_map.empty() || !comp)
     return false;
 
@@ -731,6 +793,7 @@ Parameter_sptr ParameterMap::get(const IComponent *comp,
 boost::shared_ptr<Parameter> ParameterMap::get(const IComponent *comp,
                                                const char *name,
                                                const char *type) const {
+  checkIsNotMaskingParameter(name);
   Parameter_sptr result;
   if (!comp)
     return result;
@@ -874,6 +937,7 @@ Parameter_sptr ParameterMap::getRecursive(const IComponent *comp,
 Parameter_sptr ParameterMap::getRecursive(const IComponent *comp,
                                           const char *name,
                                           const char *type) const {
+  checkIsNotMaskingParameter(name);
   Parameter_sptr result = this->get(comp->getComponentID(), name, type);
   if (result)
     return result;
@@ -961,9 +1025,9 @@ std::string ParameterMap::asString() const {
  * Clears the location, rotation & bounding box caches
  */
 void ParameterMap::clearPositionSensitiveCaches() {
-  m_cacheLocMap.clear();
-  m_cacheRotMap.clear();
-  m_boundingBoxMap.clear();
+  m_cacheLocMap->clear();
+  m_cacheRotMap->clear();
+  m_boundingBoxMap->clear();
 }
 
 /// Sets a cached location on the location cache
@@ -971,7 +1035,7 @@ void ParameterMap::clearPositionSensitiveCaches() {
 /// @param location :: The location
 void ParameterMap::setCachedLocation(const IComponent *comp,
                                      const V3D &location) const {
-  m_cacheLocMap.setCache(comp->getComponentID(), location);
+  m_cacheLocMap->setCache(comp->getComponentID(), location);
 }
 
 /// Attempts to retrieve a location from the location cache
@@ -980,7 +1044,7 @@ void ParameterMap::setCachedLocation(const IComponent *comp,
 /// @returns true if the location is in the map, otherwise false
 bool ParameterMap::getCachedLocation(const IComponent *comp,
                                      V3D &location) const {
-  return m_cacheLocMap.getCache(comp->getComponentID(), location);
+  return m_cacheLocMap->getCache(comp->getComponentID(), location);
 }
 
 /// Sets a cached rotation on the rotation cache
@@ -988,7 +1052,7 @@ bool ParameterMap::getCachedLocation(const IComponent *comp,
 /// @param rotation :: The rotation as a quaternion
 void ParameterMap::setCachedRotation(const IComponent *comp,
                                      const Quat &rotation) const {
-  m_cacheRotMap.setCache(comp->getComponentID(), rotation);
+  m_cacheRotMap->setCache(comp->getComponentID(), rotation);
 }
 
 /// Attempts to retrieve a rotation from the rotation cache
@@ -997,7 +1061,7 @@ void ParameterMap::setCachedRotation(const IComponent *comp,
 /// @returns true if the rotation is in the map, otherwise false
 bool ParameterMap::getCachedRotation(const IComponent *comp,
                                      Quat &rotation) const {
-  return m_cacheRotMap.getCache(comp->getComponentID(), rotation);
+  return m_cacheRotMap->getCache(comp->getComponentID(), rotation);
 }
 
 /// Sets a cached bounding box
@@ -1005,7 +1069,7 @@ bool ParameterMap::getCachedRotation(const IComponent *comp,
 /// @param box :: A reference to the bounding box
 void ParameterMap::setCachedBoundingBox(const IComponent *comp,
                                         const BoundingBox &box) const {
-  m_boundingBoxMap.setCache(comp->getComponentID(), box);
+  m_boundingBoxMap->setCache(comp->getComponentID(), box);
 }
 
 /// Attempts to retrieve a bounding box from the cache
@@ -1014,7 +1078,7 @@ void ParameterMap::setCachedBoundingBox(const IComponent *comp,
 /// @returns true if the bounding is in the map, otherwise false
 bool ParameterMap::getCachedBoundingBox(const IComponent *comp,
                                         BoundingBox &box) const {
-  return m_boundingBoxMap.getCache(comp->getComponentID(), box);
+  return m_boundingBoxMap->getCache(comp->getComponentID(), box);
 }
 
 /**
@@ -1079,5 +1143,33 @@ void ParameterMap::addParameterFilename(const std::string &filename) {
   m_parameterFileNames.push_back(filename);
 }
 
+/// Wrapper for ParameterFactory::create to avoid include in header
+boost::shared_ptr<Parameter>
+ParameterMap::create(const std::string &className,
+                     const std::string &name) const {
+  return ParameterFactory::create(className, name);
+}
+
+/// Only for use by ExperimentInfo. Returns returns true if this instrument
+/// contains a DetectorInfo.
+bool ParameterMap::hasDetectorInfo() const {
+  return static_cast<bool>(m_detectorInfo);
+}
+/// Only for use by ExperimentInfo. Returns a reference to the DetectorInfo.
+const Beamline::DetectorInfo &ParameterMap::detectorInfo() const {
+  if (!hasDetectorInfo())
+    throw std::runtime_error("Cannot return reference to NULL DetectorInfo");
+  return *m_detectorInfo;
+}
+
+/// Only for use by ExperimentInfo. Sets the pointer to the DetectorInfo.
+void ParameterMap::setDetectorInfo(
+    boost::shared_ptr<const Beamline::DetectorInfo> detectorInfo) {
+  if (detectorInfo != m_detectorInfo) {
+    PARALLEL_CRITICAL(ParameterMap_setDetectorInfo)
+    m_detectorInfo = std::move(detectorInfo);
+  }
+}
+
 } // Namespace Geometry
 } // Namespace Mantid
diff --git a/Framework/Geometry/src/Instrument/RectangularDetector.cpp b/Framework/Geometry/src/Instrument/RectangularDetector.cpp
index c9af1b9cd8f6c7533f933bf2abf36a2ba24bf76d..794a1369ae26ef426080b79a3e7502e823de8a60 100644
--- a/Framework/Geometry/src/Instrument/RectangularDetector.cpp
+++ b/Framework/Geometry/src/Instrument/RectangularDetector.cpp
@@ -4,6 +4,7 @@
 #include "MantidGeometry/Objects/BoundingBox.h"
 #include "MantidGeometry/Objects/Object.h"
 #include "MantidGeometry/Objects/ShapeFactory.h"
+#include "MantidGeometry/Objects/Track.h"
 #include "MantidGeometry/Rendering/BitmapGeometryHandler.h"
 #include "MantidKernel/Exception.h"
 #include "MantidKernel/Material.h"
diff --git a/Framework/Geometry/src/Instrument/SampleEnvironment.cpp b/Framework/Geometry/src/Instrument/SampleEnvironment.cpp
index 58f1ce9d1a6e3f866999759faaff5a341747870f..a714c507e807913c4dc62d64be7035618c532a6c 100644
--- a/Framework/Geometry/src/Instrument/SampleEnvironment.cpp
+++ b/Framework/Geometry/src/Instrument/SampleEnvironment.cpp
@@ -5,6 +5,7 @@
 #include "MantidGeometry/IObjComponent.h"
 #include "MantidGeometry/Objects/Object.h"
 #include "MantidGeometry/Objects/Track.h"
+#include "MantidKernel/PseudoRandomNumberGenerator.h"
 
 namespace Mantid {
 namespace Geometry {
@@ -38,6 +39,41 @@ Geometry::BoundingBox SampleEnvironment::boundingBox() const {
   return box;
 }
 
+/**
+ * Generate a random point within one of the environment's components. The
+ * method first selects a random component and then selects a random point
+ * within that component using Object::generatePointObject
+ * @param rng A reference to a PseudoRandomNumberGenerator where
+ * nextValue should return a flat random number between 0.0 & 1.0
+ * @param maxAttempts The maximum number of attempts at generating a point
+ * @return The generated point
+ */
+Kernel::V3D
+SampleEnvironment::generatePoint(Kernel::PseudoRandomNumberGenerator &rng,
+                                 const size_t maxAttempts) const {
+  auto componentIndex = rng.nextInt(1, static_cast<int>(nelements())) - 1;
+  return m_components[componentIndex]->generatePointInObject(rng, maxAttempts);
+}
+
+/**
+ * Generate a random point within one of the environment's components. The
+ * method first selects a random component and then selects a random point
+ * within that component using Object::generatePointObject
+ * @param rng A reference to a PseudoRandomNumberGenerator where
+ * nextValue should return a flat random number between 0.0 & 1.0
+ * @param activeRegion Restrict the generated point to be defined by this box
+ * @param maxAttempts The maximum number of attempts at generating a point
+ * @return The generated point
+ */
+Kernel::V3D
+SampleEnvironment::generatePoint(Kernel::PseudoRandomNumberGenerator &rng,
+                                 const Geometry::BoundingBox &activeRegion,
+                                 const size_t maxAttempts) const {
+  auto componentIndex = rng.nextInt(1, static_cast<int>(nelements())) - 1;
+  return m_components[componentIndex]->generatePointInObject(rng, activeRegion,
+                                                             maxAttempts);
+}
+
 /**
  * Is the point given a valid point within the environment
  * @param point Is the point valid within the environment
diff --git a/Framework/Geometry/src/MDGeometry/MDGeometryXMLBuilder.cpp b/Framework/Geometry/src/MDGeometry/MDGeometryXMLBuilder.cpp
index 036968a097705ebf82c2ecda830f7f9b7d6b1d2c..9e57c123ae3894a2f7b56dec3003d9a5233df8a2 100644
--- a/Framework/Geometry/src/MDGeometry/MDGeometryXMLBuilder.cpp
+++ b/Framework/Geometry/src/MDGeometry/MDGeometryXMLBuilder.cpp
@@ -16,25 +16,6 @@
 namespace Mantid {
 namespace Geometry {
 
-/*
- @class CompareIMDDimension_const_sptr
- @brief Helper comparitor. Compares IMDDimensions constant shared pointers on
- the basis of their id.
- @author Owen Arnold
- @date May 2011
-*/
-struct CompareIMDDimension_const_sptr
-    : public std::unary_function<IMDDimension_const_sptr, bool> {
-private:
-  IMDDimension_const_sptr _a;
-
-public:
-  explicit CompareIMDDimension_const_sptr(IMDDimension_const_sptr a) : _a(a) {}
-  bool operator()(IMDDimension_const_sptr b) {
-    return _a->getDimensionId() == b->getDimensionId();
-  }
-};
-
 /**
  Add an ordinary dimension.
  @param dimensionToAdd :: The dimension to add to the geometry.
@@ -44,12 +25,15 @@ template <typename CheckDimensionPolicy>
 bool MDGeometryBuilderXML<CheckDimensionPolicy>::addOrdinaryDimension(
     IMDDimension_const_sptr dimensionToAdd) const {
   bool bAdded = false; // Addition fails by default.
-  if (dimensionToAdd.get() != nullptr) {
-    CompareIMDDimension_const_sptr comparitor(dimensionToAdd);
-    auto location = std::find_if(m_vecDimensions.begin(), m_vecDimensions.end(),
-                                 comparitor);
-    if (location == m_vecDimensions.end()) {
-      m_vecDimensions.push_back(dimensionToAdd);
+  if (dimensionToAdd) {
+    const std::string dimensionId = dimensionToAdd->getDimensionId();
+    auto location =
+        std::find_if(m_vecDimensions.cbegin(), m_vecDimensions.cend(),
+                     [&dimensionId](const IMDDimension_const_sptr &b) {
+                       return dimensionId == b->getDimensionId();
+                     });
+    if (location == m_vecDimensions.cend()) {
+      m_vecDimensions.push_back(std::move(dimensionToAdd));
       bAdded = true;
       m_changed = true;
     }
@@ -104,7 +88,7 @@ MDGeometryBuilderXML<CheckDimensionPolicy> &
  */
 template <typename CheckDimensionPolicy>
 void MDGeometryBuilderXML<CheckDimensionPolicy>::applyPolicyChecking(
-    IMDDimension_const_sptr dimensionToAdd) const {
+    const IMDDimension &dimensionToAdd) const {
   CheckDimensionPolicy policy;
   policy(dimensionToAdd);
 }
@@ -119,10 +103,10 @@ bool MDGeometryBuilderXML<CheckDimensionPolicy>::addXDimension(
     IMDDimension_const_sptr dimension) const {
 
   bool bAdded = false;
-  if (dimension.get() != nullptr) {
-    applyPolicyChecking(dimension);
+  if (dimension) {
+    applyPolicyChecking(*dimension);
     addOrdinaryDimension(dimension);
-    m_spXDimension = dimension;
+    m_spXDimension = std::move(dimension);
     m_changed = true;
     bAdded = true;
   }
@@ -139,10 +123,10 @@ bool MDGeometryBuilderXML<CheckDimensionPolicy>::addYDimension(
     IMDDimension_const_sptr dimension) const {
 
   bool bAdded = false;
-  if (dimension.get() != nullptr) {
-    applyPolicyChecking(dimension);
+  if (dimension) {
+    applyPolicyChecking(*dimension);
     addOrdinaryDimension(dimension);
-    m_spYDimension = dimension;
+    m_spYDimension = std::move(dimension);
     m_changed = true;
     bAdded = true;
   }
@@ -158,10 +142,10 @@ template <typename CheckDimensionPolicy>
 bool MDGeometryBuilderXML<CheckDimensionPolicy>::addZDimension(
     IMDDimension_const_sptr dimension) const {
   bool bAdded = false;
-  if (dimension.get() != nullptr) {
-    applyPolicyChecking(dimension);
+  if (dimension) {
+    applyPolicyChecking(*dimension);
     addOrdinaryDimension(dimension);
-    m_spZDimension = dimension;
+    m_spZDimension = std::move(dimension);
     m_changed = true;
     bAdded = true;
   }
@@ -178,10 +162,10 @@ bool MDGeometryBuilderXML<CheckDimensionPolicy>::addTDimension(
     IMDDimension_const_sptr dimension) const {
 
   bool bAdded = false;
-  if (dimension.get() != nullptr) {
-    applyPolicyChecking(dimension);
+  if (dimension) {
+    applyPolicyChecking(*dimension);
     addOrdinaryDimension(dimension);
-    m_spTDimension = dimension;
+    m_spTDimension = std::move(dimension);
     m_changed = true;
     bAdded = true;
   }
diff --git a/Framework/Geometry/src/MDGeometry/MDHistoDimension.cpp b/Framework/Geometry/src/MDGeometry/MDHistoDimension.cpp
index dc4c70b8b485d2e9349f5063fbdce43c46180f22..d0590b84ce7f3b8163f296eccc52dc258b6ac7bb 100644
--- a/Framework/Geometry/src/MDGeometry/MDHistoDimension.cpp
+++ b/Framework/Geometry/src/MDGeometry/MDHistoDimension.cpp
@@ -1,4 +1,5 @@
 #include "MantidGeometry/MDGeometry/MDHistoDimension.h"
+#include <sstream>
 
 #include <boost/algorithm/string.hpp>
 #include <boost/format.hpp>
diff --git a/Framework/Geometry/src/Math/Acomp.cpp b/Framework/Geometry/src/Math/Acomp.cpp
index aced68e7e39bf3bb7cb8ee1eeac980bd8564b3e5..1661ec2ac9644181684e299378d9e1e4de3116e1 100644
--- a/Framework/Geometry/src/Math/Acomp.cpp
+++ b/Framework/Geometry/src/Math/Acomp.cpp
@@ -459,7 +459,7 @@ Units are sorted after this function is returned.
         Express += iu;
     }
   }
-  if (Express.size() > 0) {
+  if (!Express.empty()) {
     Acomp AX;
     try {
       AX.setString(Express);
diff --git a/Framework/Geometry/src/Objects/BoundingBox.cpp b/Framework/Geometry/src/Objects/BoundingBox.cpp
index ad4572dc5fa3f023527da1610329f66c800cb49c..7dde97876bac777553e87d2b3456af48564d748f 100644
--- a/Framework/Geometry/src/Objects/BoundingBox.cpp
+++ b/Framework/Geometry/src/Objects/BoundingBox.cpp
@@ -147,7 +147,21 @@ double BoundingBox::angularWidth(const Kernel::V3D &observer) const {
   }
   return thetaMax;
 }
-//
+
+/**
+ * Generate a random point within this box assuming the 3 numbers given
+ * are random numbers in the range (0,1) & selected from a flat distribution.
+ * @param r1 Flat random number in range (0,1)
+ * @param r2 Flat random number in range (0,1)
+ * @param r3 Flat random number in range (0,1)
+ * @return A new point within the box such that isPointInside(pt) == true
+ */
+Kernel::V3D BoundingBox::generatePointInside(double r1, double r2,
+                                             double r3) const {
+  return V3D(xMin() + r1 * (xMax() - xMin()), yMin() + r2 * (yMax() - yMin()),
+             zMin() + r3 * (zMax() - zMin()));
+}
+
 void BoundingBox::getFullBox(std::vector<Kernel::V3D> &box,
                              const Kernel::V3D &observer) const {
   box.resize(8);
@@ -160,6 +174,7 @@ void BoundingBox::getFullBox(std::vector<Kernel::V3D> &box,
   box[6] = Kernel::V3D(xMax(), yMin(), zMax()) - observer;
   box[7] = Kernel::V3D(xMax(), yMax(), zMax()) - observer;
 }
+
 void BoundingBox::setBoxAlignment(const Kernel::V3D &R0,
                                   const std::vector<Kernel::V3D> &orts) {
   this->coord_system.resize(4);
@@ -169,6 +184,7 @@ void BoundingBox::setBoxAlignment(const Kernel::V3D &R0,
   coord_system[3] = orts[2];
   is_axis_aligned = false;
 }
+
 void BoundingBox::nullify() {
   this->m_null = true;
   for (int i = 0; i < 3; i++) {
@@ -176,7 +192,7 @@ void BoundingBox::nullify() {
     this->m_maxPoint[i] = -FLT_MAX;
   }
 }
-//
+
 void BoundingBox::realign(std::vector<Kernel::V3D> const *const pCS) {
   if (pCS) {
     this->coord_system.resize(pCS->size());
@@ -224,6 +240,7 @@ void BoundingBox::realign(std::vector<Kernel::V3D> const *const pCS) {
   this->zMin() = zMin;
   this->zMax() = zMax;
 }
+
 /**
  * Enlarges this bounding box so that it encompasses that given.
  * @param other :: The bounding box that should be encompassed
diff --git a/Framework/Geometry/src/Objects/InstrumentRayTracer.cpp b/Framework/Geometry/src/Objects/InstrumentRayTracer.cpp
index a8739e18ceb230039825dfb3d66eb64669cec149..58d5ffb3396e2059f3eb6c5c9c02eeb521c9d57b 100644
--- a/Framework/Geometry/src/Objects/InstrumentRayTracer.cpp
+++ b/Framework/Geometry/src/Objects/InstrumentRayTracer.cpp
@@ -98,7 +98,7 @@ IDetector_const_sptr InstrumentRayTracer::getDetectorResult() const {
     IDetector_const_sptr det =
         boost::dynamic_pointer_cast<const IDetector>(component);
     if (det) {
-      if (!det->isMonitor()) {
+      if (!m_instrument->isMonitor(det->getID())) {
         return det;
       }
     } // (is a detector)
diff --git a/Framework/Geometry/src/Objects/Object.cpp b/Framework/Geometry/src/Objects/Object.cpp
index 644d7a337344b2b35c68220a35749110d330fe22..ae4818b0615fa4183bc4e4f14b4e2ba8ba13aaae 100644
--- a/Framework/Geometry/src/Objects/Object.cpp
+++ b/Framework/Geometry/src/Objects/Object.cpp
@@ -4,6 +4,7 @@
 #include "MantidKernel/Exception.h"
 #include "MantidKernel/Material.h"
 #include "MantidKernel/MultiThreaded.h"
+#include "MantidKernel/PseudoRandomNumberGenerator.h"
 #include "MantidKernel/Strings.h"
 
 #include "MantidGeometry/Surfaces/Cone.h"
@@ -261,7 +262,6 @@ int Object::hasComplement() const {
 int Object::populate(const std::map<int, boost::shared_ptr<Surface>> &Smap) {
   std::deque<Rule *> Rst;
   Rst.push_back(TopRule.get());
-  int Rcount(0);
   while (!Rst.empty()) {
     Rule *T1 = Rst.front();
     Rst.pop_front();
@@ -273,7 +273,6 @@ int Object::populate(const std::map<int, boost::shared_ptr<Surface>> &Smap) {
         auto mf = Smap.find(KV->getKeyN());
         if (mf != Smap.end()) {
           KV->setKey(mf->second);
-          Rcount++;
         } else {
           throw Kernel::Exception::NotFoundError("Object::populate",
                                                  KV->getKeyN());
@@ -1823,6 +1822,54 @@ int Object::getPointInObject(Kernel::V3D &point) const {
   return 0;
 }
 
+/**
+ * Generate a random point within the object. The method simply generates a
+ * point within the bounding box and tests if this is a valid point within
+ * the object: if so the point is return otherwise a new point is selected.
+ * @param rng  A reference to a PseudoRandomNumberGenerator where
+ * nextValue should return a flat random number between 0.0 & 1.0
+ * @param maxAttempts The maximum number of attempts at generating a point
+ * @return The generated point
+ */
+V3D Object::generatePointInObject(Kernel::PseudoRandomNumberGenerator &rng,
+                                  const size_t maxAttempts) const {
+  const auto &bbox = getBoundingBox();
+  if (bbox.isNull()) {
+    throw std::runtime_error("Object::generatePointInObject() - Invalid "
+                             "bounding box. Cannot generate new point.");
+  }
+  return generatePointInObject(rng, bbox, maxAttempts);
+}
+
+/**
+ * Generate a random point within the object that is also bound by the
+ * activeRegion box.
+ * @param rng A reference to a PseudoRandomNumberGenerator where
+ * nextValue should return a flat random number between 0.0 & 1.0
+ * @param activeRegion Restrict point generation to this sub-region of the
+ * object
+ * @param maxAttempts The maximum number of attempts at generating a point
+ * @return The newly generated point
+ */
+V3D Object::generatePointInObject(Kernel::PseudoRandomNumberGenerator &rng,
+                                  const BoundingBox &activeRegion,
+                                  const size_t maxAttempts) const {
+  size_t attempts(0);
+  while (attempts < maxAttempts) {
+    const double r1 = rng.nextValue();
+    const double r2 = rng.nextValue();
+    const double r3 = rng.nextValue();
+    auto pt = activeRegion.generatePointInside(r1, r2, r3);
+    if (this->isValid(pt))
+      return pt;
+    else
+      ++attempts;
+  };
+  throw std::runtime_error("Object::generatePointInObject() - Unable to "
+                           "generate point in object after " +
+                           std::to_string(maxAttempts) + " attempts");
+}
+
 /**
 * Try to find a point that lies within (or on) the object, given a seed point
 * @param point :: on entry the seed point, on exit point in object, if found
diff --git a/Framework/Geometry/src/Rendering/CacheGeometryHandler.cpp b/Framework/Geometry/src/Rendering/CacheGeometryHandler.cpp
index dcdb018e5e2c36487eac583452c7cfb959260016..54a9d8d3926f7d608a1d7bfd01388dc5243ca592 100644
--- a/Framework/Geometry/src/Rendering/CacheGeometryHandler.cpp
+++ b/Framework/Geometry/src/Rendering/CacheGeometryHandler.cpp
@@ -4,6 +4,7 @@
 #include "MantidGeometry/Rendering/CacheGeometryHandler.h"
 #include "MantidGeometry/Rendering/CacheGeometryRenderer.h"
 #include "MantidGeometry/Rendering/CacheGeometryGenerator.h"
+#include "MantidKernel/MultiThreaded.h"
 
 #include <boost/make_shared.hpp>
 
diff --git a/Framework/Geometry/src/Rendering/GluGeometryHandler.cpp b/Framework/Geometry/src/Rendering/GluGeometryHandler.cpp
index 2014b93e034fabf3724496ec28de44b2f24eb7f3..3ecd3e61fc9033bc6315ed5630e7dde6852ece11 100644
--- a/Framework/Geometry/src/Rendering/GluGeometryHandler.cpp
+++ b/Framework/Geometry/src/Rendering/GluGeometryHandler.cpp
@@ -3,6 +3,7 @@
 #include "MantidGeometry/Objects/Object.h"
 #include "MantidGeometry/Rendering/GeometryHandler.h"
 #include "MantidGeometry/Rendering/GluGeometryRenderer.h"
+#include "MantidKernel/make_unique.h"
 
 #include <boost/make_shared.hpp>
 
diff --git a/Framework/Geometry/test/BoundingBoxTest.h b/Framework/Geometry/test/BoundingBoxTest.h
index b5ceb38ceb9826da81456d774a134b4595e04c3f..1357e628347d5ab4cd5d0a47f388add02b9c4b98 100644
--- a/Framework/Geometry/test/BoundingBoxTest.h
+++ b/Framework/Geometry/test/BoundingBoxTest.h
@@ -209,6 +209,18 @@ public:
     TS_ASSERT_EQUALS(box.maxPoint() == V3D(-FLT_MAX, -FLT_MAX, -FLT_MAX), true);
     TS_ASSERT_EQUALS(box.minPoint() == V3D(FLT_MAX, FLT_MAX, FLT_MAX), true);
   }
+
+  void test_generatePointInside_Gives_Point_Inside() {
+    BoundingBox box(3.0, 4.0, 5.0, 1.0, 1.0, 2.5);
+
+    auto pt = box.generatePointInside(0.1, 0.2, 0.3);
+    TS_ASSERT(box.isPointInside(pt));
+    const double tolerance(1e-10);
+    TS_ASSERT_DELTA(1.2, pt.X(), tolerance);
+    TS_ASSERT_DELTA(1.6, pt.Y(), tolerance);
+    TS_ASSERT_DELTA(3.25, pt.Z(), tolerance);
+  }
+
   void testBB_expansion_works_fine() {
     BoundingBox box(3.0, 4.0, 5.5, 1.0, 1.0, 1.5);
     std::vector<V3D> points;
diff --git a/Framework/Geometry/test/DetectorGroupTest.h b/Framework/Geometry/test/DetectorGroupTest.h
index ea032d563cc5a62331908698e0588c6ac5bad3df..ea0b551b9f3b9cc6f51eaed5011102229a948fd8 100644
--- a/Framework/Geometry/test/DetectorGroupTest.h
+++ b/Framework/Geometry/test/DetectorGroupTest.h
@@ -81,15 +81,6 @@ public:
     TS_ASSERT_DELTA(m_detGroup->getDistance(m_origin), 4.24614987, 1e-08);
   }
 
-  void testMasked() { TS_ASSERT(!m_detGroup->isMasked()); }
-
-  void testIsMonitor() {
-    boost::shared_ptr<DetectorGroup> monitorGroup =
-        ComponentCreationHelper::createGroupOfTwoMonitors();
-    TS_ASSERT(!m_detGroup->isMonitor());
-    TS_ASSERT(monitorGroup->isMonitor());
-  }
-
   void testBoundingBox() {}
 
   void testAddDetector() {
@@ -97,9 +88,7 @@ public:
         ComponentCreationHelper::createDetectorGroupWith5CylindricalDetectors();
     auto d = boost::make_shared<Detector>("d", 6, nullptr);
     d->setPos(6.0, 3.0, 2.0);
-    TS_ASSERT(!detg->isMasked());
-    bool warn = true;
-    detg->addDetector(d, warn);
+    detg->addDetector(d);
     TS_ASSERT_EQUALS(detg->getID(), 1);
     TS_ASSERT_DELTA(detg->getPos()[0], 3.5, 1e-08);
     TS_ASSERT_DELTA(detg->getPos()[1], 2.16666667, 1e-08);
@@ -124,8 +113,7 @@ public:
     DetectorGroup cluster;
     Detector *det = new Detector("det", 0, 0);
     det->setPos(1, -1, 0);
-    bool warn = false;
-    cluster.addDetector(IDetector_const_sptr(det), warn);
+    cluster.addDetector(IDetector_const_sptr(det));
 
     V3D axis(1, 0, 0);
     V3D sample(0, 0, 0);
diff --git a/Framework/Geometry/test/DetectorTest.h b/Framework/Geometry/test/DetectorTest.h
index c9181e9192c6138a23d8449207327460821b2660..3a2afac5411de1dffbf76723a72ee322c7a77ae6 100644
--- a/Framework/Geometry/test/DetectorTest.h
+++ b/Framework/Geometry/test/DetectorTest.h
@@ -18,8 +18,6 @@ public:
     TS_ASSERT_EQUALS(det.getName(), "det1");
     TS_ASSERT(!det.getParent());
     TS_ASSERT_EQUALS(det.getID(), 0);
-    TS_ASSERT(!det.isMasked());
-    TS_ASSERT(!det.isMonitor());
     TS_ASSERT(!det.isParametrized());
   }
   void testDetTopology() {
@@ -35,8 +33,6 @@ public:
     TS_ASSERT_EQUALS(det.getName(), "det1");
     TS_ASSERT(det.getParent());
     TS_ASSERT_EQUALS(det.getID(), 0);
-    TS_ASSERT(!det.isMasked());
-    TS_ASSERT(!det.isMonitor());
   }
 
   void testId() {
@@ -50,20 +46,6 @@ public:
     TS_ASSERT_EQUALS(det.type(), "DetectorComponent");
   }
 
-  void testDead() {
-    Detector det("det", 0, 0);
-    TS_ASSERT(!det.isMasked());
-  }
-
-  void testMonitor() {
-    Detector det("det", 0, 0);
-    TS_ASSERT(!det.isMonitor());
-    TS_ASSERT_THROWS_NOTHING(det.markAsMonitor());
-    TS_ASSERT(det.isMonitor());
-    TS_ASSERT_THROWS_NOTHING(det.markAsMonitor(false));
-    TS_ASSERT(!det.isMonitor());
-  }
-
   void testGetNumberParameter() {
     Detector det("det", 0, 0);
     TS_ASSERT_EQUALS(det.getNumberParameter("testparam").size(), 0);
diff --git a/Framework/Geometry/test/IndexingUtilsTest.h b/Framework/Geometry/test/IndexingUtilsTest.h
index b8b66458b2b4b6dfe85472af9af4e42ff788d271..fdc03cb12474534f85a8c735df88f66c632f1f28 100644
--- a/Framework/Geometry/test/IndexingUtilsTest.h
+++ b/Framework/Geometry/test/IndexingUtilsTest.h
@@ -111,12 +111,7 @@ public:
 
     std::vector<V3D> q_vectors = getNatroliteQs();
 
-    double a = 6.6;
-    double b = 9.7;
-    double c = 9.9;
-    double alpha = 84;
-    double beta = 71;
-    double gamma = 70;
+    OrientedLattice lattice(6.6, 9.7, 9.9, 84, 71, 70);
     // test both default case(-1) and
     // case with specified base index(4)
     for (int base_index = -1; base_index < 5; base_index += 5) {
@@ -124,9 +119,9 @@ public:
       size_t num_initial = 3;
       double degrees_per_step = 3;
 
-      double error = IndexingUtils::Find_UB(
-          UB, q_vectors, a, b, c, alpha, beta, gamma, required_tolerance,
-          base_index, num_initial, degrees_per_step);
+      double error =
+          IndexingUtils::Find_UB(UB, q_vectors, lattice, required_tolerance,
+                                 base_index, num_initial, degrees_per_step);
 
       //      std::cout << std::endl << "USING LATTICE PARAMETERS\n";
       //      ShowIndexingStats( UB, q_vectors, required_tolerance );
@@ -260,18 +255,12 @@ public:
     Matrix<double> UB(3, 3, false);
     int degrees_per_step = 3;
     double required_tolerance = 0.2;
-    double a = 6.6f;
-    double b = 9.7f;
-    double c = 9.9f;
-    double alpha = 84;
-    double beta = 71;
-    double gamma = 70;
 
+    UnitCell cell(6.6f, 9.7f, 9.9f, 84, 71, 70);
     std::vector<V3D> q_vectors = getNatroliteQs();
 
-    double error =
-        IndexingUtils::ScanFor_UB(UB, q_vectors, a, b, c, alpha, beta, gamma,
-                                  degrees_per_step, required_tolerance);
+    double error = IndexingUtils::ScanFor_UB(
+        UB, q_vectors, cell, degrees_per_step, required_tolerance);
 
     TS_ASSERT_DELTA(error, 0.147397, 1.e-5);
 
diff --git a/Framework/Geometry/test/InstrumentRayTracerTest.h b/Framework/Geometry/test/InstrumentRayTracerTest.h
index 18b472f359de17c77c19c1bf752699a2db23a4f1..b7e24f821495f173c9f517678d915f35a635c924 100644
--- a/Framework/Geometry/test/InstrumentRayTracerTest.h
+++ b/Framework/Geometry/test/InstrumentRayTracerTest.h
@@ -61,7 +61,7 @@ public:
     // Check they are actually what we expect: 1 with the sample and 1 with the
     // central detector
     IComponent_const_sptr centralPixel =
-        testInst->getComponentByName("pixel-(0,0)");
+        testInst->getComponentByName("pixel-(0;0)");
     IComponent_const_sptr sampleComp = testInst->getSample();
 
     if (!sampleComp) {
@@ -119,7 +119,7 @@ public:
     TS_ASSERT_EQUALS(results.size(), 1);
 
     const IComponent *interceptedPixel =
-        testInst->getComponentByName("pixel-(1,0)").get();
+        testInst->getComponentByName("pixel-(1;0)").get();
 
     Link intersect = results.front();
     TS_ASSERT_DELTA(intersect.distFromStart, 15.003468, 1e-6);
diff --git a/Framework/Geometry/test/InstrumentTest.h b/Framework/Geometry/test/InstrumentTest.h
index b75d9830d630b73ef893aa5aae42d53ff306ebfc..f87028832637ba1e63e9550908da829eacd07777 100644
--- a/Framework/Geometry/test/InstrumentTest.h
+++ b/Framework/Geometry/test/InstrumentTest.h
@@ -240,11 +240,6 @@ public:
                      ndets - 1); // skipMonitors
   }
 
-  void testNumMonitors() {
-    TS_ASSERT_EQUALS(instrument.numMonitors(), 1);
-    TS_ASSERT_EQUALS(Instrument().numMonitors(), 0);
-  }
-
   void testDetector() {
     TS_ASSERT_THROWS(instrument.getDetector(0), Exception::NotFoundError);
     TS_ASSERT_EQUALS(instrument.getDetector(1).get(), det);
@@ -301,10 +296,8 @@ public:
 
   void test_GetDetector_With_A_List_Returns_A_Group() {
     const size_t ndets(3);
-    std::vector<detid_t> detIDs(ndets);
-    detIDs[0] = 1;
-    detIDs[1] = 10;
-    detIDs[2] = 11;
+    std::set<detid_t> detIDs{1, 10, 11};
+    std::vector<detid_t> detIDsVec(detIDs.begin(), detIDs.end());
 
     IDetector_const_sptr det;
     TS_ASSERT_THROWS_NOTHING(det = instrument.getDetectorG(detIDs));
@@ -315,14 +308,12 @@ public:
     TS_ASSERT_EQUALS(detGroup->nDets(), ndets);
     std::vector<detid_t> memberIDs = detGroup->getDetectorIDs();
     for (size_t i = 0; i < ndets; ++i) {
-      TS_ASSERT_EQUALS(memberIDs[i], detIDs[i]);
+      TS_ASSERT_EQUALS(memberIDs[i], detIDsVec[i]);
     }
   }
 
   void test_GetDetectors_Throws_With_Invalid_IDs() {
-    const size_t ndets(1);
-    std::vector<detid_t> detIDs(ndets);
-    detIDs[0] = 10000;
+    std::set<detid_t> detIDs{10000};
 
     std::vector<IDetector_const_sptr> dets;
     TS_ASSERT_THROWS(dets = instrument.getDetectors(detIDs),
diff --git a/Framework/Geometry/test/MDGeometryXMLBuilderTest.h b/Framework/Geometry/test/MDGeometryXMLBuilderTest.h
index f7259d938109999a813668d73d247621e66b1f72..a28aae01d05b4cbea48cfe472ee30471a1989e22 100644
--- a/Framework/Geometry/test/MDGeometryXMLBuilderTest.h
+++ b/Framework/Geometry/test/MDGeometryXMLBuilderTest.h
@@ -4,7 +4,6 @@
 #include <cxxtest/TestSuite.h>
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
-#include <string>
 
 #include "MantidGeometry/MDGeometry/MDGeometryXMLBuilder.h"
 #include "MantidGeometry/MDGeometry/IMDDimension.h"
@@ -12,9 +11,10 @@
 #include "MantidKernel/UnitLabel.h"
 #include "MantidKernel/WarningSuppressions.h"
 
-#include <boost/functional/hash.hpp>
+#include "boost/make_shared.hpp"
 #include <boost/algorithm/string.hpp>
 #include <boost/format.hpp>
+#include <boost/functional/hash.hpp>
 
 #include <Poco/AutoPtr.h>
 #include <Poco/DOM/DOMParser.h>
@@ -22,6 +22,8 @@
 #include <Poco/DOM/Element.h>
 #include <Poco/DOM/NodeList.h>
 
+#include <string>
+
 using namespace Mantid;
 using namespace Mantid::Geometry;
 using namespace testing;
@@ -35,7 +37,7 @@ private:
     GCC_DIAG_OFF_SUGGEST_OVERRIDE
     MOCK_CONST_METHOD0(getName, std::string());
     MOCK_CONST_METHOD0(getUnits, const Mantid::Kernel::UnitLabel());
-    MOCK_CONST_METHOD0(getDimensionId, std::string());
+    MOCK_CONST_METHOD0(getDimensionId, const std::string &());
     MOCK_CONST_METHOD0(getMaximum, coord_t());
     MOCK_CONST_METHOD0(getMinimum, coord_t());
     MOCK_CONST_METHOD0(getNBins, size_t());
@@ -63,20 +65,25 @@ private:
 
 public:
   void testCopyConstruction() {
-    MockIMDDimension *pDimensionX = new MockIMDDimension;
-    EXPECT_CALL(*pDimensionX, getDimensionId()).WillRepeatedly(Return("_a"));
+    auto pDimensionX = boost::make_shared<MockIMDDimension>();
+    std::string a{"_a"}, b{"_b"}, c{"_c"}, d{"_d"};
+    EXPECT_CALL(Const(*pDimensionX), getDimensionId())
+        .WillRepeatedly(ReturnRef(a));
     EXPECT_CALL(*pDimensionX, toXMLString()).WillRepeatedly(Return("_a_xml"));
 
-    MockIMDDimension *pDimensionY = new MockIMDDimension;
-    EXPECT_CALL(*pDimensionY, getDimensionId()).WillRepeatedly(Return("_b"));
+    auto pDimensionY = boost::make_shared<MockIMDDimension>();
+    EXPECT_CALL(Const(*pDimensionY), getDimensionId())
+        .WillRepeatedly(ReturnRef(b));
     EXPECT_CALL(*pDimensionY, toXMLString()).WillRepeatedly(Return("_b_xml"));
 
-    MockIMDDimension *pDimensionZ = new MockIMDDimension;
-    EXPECT_CALL(*pDimensionZ, getDimensionId()).WillRepeatedly(Return("_c"));
+    auto pDimensionZ = boost::make_shared<MockIMDDimension>();
+    EXPECT_CALL(Const(*pDimensionZ), getDimensionId())
+        .WillRepeatedly(ReturnRef(c));
     EXPECT_CALL(*pDimensionZ, toXMLString()).WillRepeatedly(Return("_c_xml"));
 
-    MockIMDDimension *pDimensionT = new MockIMDDimension;
-    EXPECT_CALL(*pDimensionT, getDimensionId()).WillRepeatedly(Return("_d"));
+    auto pDimensionT = boost::make_shared<MockIMDDimension>();
+    EXPECT_CALL(Const(*pDimensionT), getDimensionId())
+        .WillRepeatedly(ReturnRef(d));
     EXPECT_CALL(*pDimensionT, toXMLString()).WillRepeatedly(Return("_d_xml"));
 
     MDGeometryBuilderXML<NoDimensionPolicy> original;
@@ -95,20 +102,25 @@ public:
   }
 
   void testAssignment() {
-    MockIMDDimension *pDimensionX = new MockIMDDimension;
-    EXPECT_CALL(*pDimensionX, getDimensionId()).WillRepeatedly(Return("_a"));
+    auto pDimensionX = boost::make_shared<MockIMDDimension>();
+    std::string a{"_a"}, b{"_b"}, c{"_c"}, d{"_d"};
+    EXPECT_CALL(Const(*pDimensionX), getDimensionId())
+        .WillRepeatedly(ReturnRef(a));
     EXPECT_CALL(*pDimensionX, toXMLString()).WillRepeatedly(Return("_a_xml"));
 
-    MockIMDDimension *pDimensionY = new MockIMDDimension;
-    EXPECT_CALL(*pDimensionY, getDimensionId()).WillRepeatedly(Return("_b"));
+    auto pDimensionY = boost::make_shared<MockIMDDimension>();
+    EXPECT_CALL(Const(*pDimensionY), getDimensionId())
+        .WillRepeatedly(ReturnRef(b));
     EXPECT_CALL(*pDimensionY, toXMLString()).WillRepeatedly(Return("_b_xml"));
 
-    MockIMDDimension *pDimensionZ = new MockIMDDimension;
-    EXPECT_CALL(*pDimensionZ, getDimensionId()).WillRepeatedly(Return("_c"));
+    auto pDimensionZ = boost::make_shared<MockIMDDimension>();
+    EXPECT_CALL(Const(*pDimensionZ), getDimensionId())
+        .WillRepeatedly(ReturnRef(c));
     EXPECT_CALL(*pDimensionZ, toXMLString()).WillRepeatedly(Return("_c_xml"));
 
-    MockIMDDimension *pDimensionT = new MockIMDDimension;
-    EXPECT_CALL(*pDimensionT, getDimensionId()).WillRepeatedly(Return("_d"));
+    auto pDimensionT = boost::make_shared<MockIMDDimension>();
+    EXPECT_CALL(Const(*pDimensionT), getDimensionId())
+        .WillRepeatedly(ReturnRef(d));
     EXPECT_CALL(*pDimensionT, toXMLString()).WillRepeatedly(Return("_d_xml"));
 
     MDGeometryBuilderXML<NoDimensionPolicy> A;
@@ -127,8 +139,10 @@ public:
   }
 
   void testCannotAddSameDimensionMultipleTimes() {
-    MockIMDDimension *pDimensionX = new MockIMDDimension;
-    EXPECT_CALL(*pDimensionX, getDimensionId()).WillRepeatedly(Return("a"));
+    auto pDimensionX = boost::make_shared<MockIMDDimension>();
+    std::string a{"a"};
+    EXPECT_CALL(Const(*pDimensionX), getDimensionId())
+        .WillRepeatedly(ReturnRef(a));
     IMDDimension_const_sptr dimension(pDimensionX);
 
     MDGeometryBuilderXML<NoDimensionPolicy> builder;
@@ -156,8 +170,10 @@ public:
   }
 
   void testStrictPolicy() {
-    MockIMDDimension *pDimensionX = new MockIMDDimension;
-    EXPECT_CALL(*pDimensionX, getDimensionId()).WillRepeatedly(Return("a"));
+    auto pDimensionX = boost::make_shared<MockIMDDimension>();
+    std::string a{"a"};
+    EXPECT_CALL(Const(*pDimensionX), getDimensionId())
+        .WillRepeatedly(ReturnRef(a));
     EXPECT_CALL(*pDimensionX, getIsIntegrated()).WillRepeatedly(Return(true));
     IMDDimension_const_sptr dimension(pDimensionX);
 
@@ -178,8 +194,10 @@ public:
 
   // Same as test above, but shouldn't throw.
   void testNoPolicy() {
-    MockIMDDimension *pDimensionX = new MockIMDDimension;
-    EXPECT_CALL(*pDimensionX, getDimensionId()).WillRepeatedly(Return("a"));
+    std::string a{"a"};
+    auto pDimensionX = boost::make_shared<MockIMDDimension>();
+    EXPECT_CALL(Const(*pDimensionX), getDimensionId())
+        .WillRepeatedly(ReturnRef(a));
     EXPECT_CALL(*pDimensionX, getIsIntegrated()).WillRepeatedly(Return(true));
     IMDDimension_const_sptr dimension(pDimensionX);
 
@@ -199,12 +217,16 @@ public:
   }
 
   void testWithOrinaryDimensionOnly() {
-    MockIMDDimension *pDimensionOrdinary = new MockIMDDimension;
+    auto pDimensionOrdinary = boost::make_shared<MockIMDDimension>();
 
     EXPECT_CALL(*pDimensionOrdinary, toXMLString())
         .Times(1)
         .WillOnce(Return(createDimensionXMLString(1, -1, 1, "O", "o")));
 
+    std::string o{"o"};
+    EXPECT_CALL(Const(*pDimensionOrdinary), getDimensionId())
+        .WillRepeatedly(ReturnRef(o));
+
     MDGeometryBuilderXML<NoDimensionPolicy> builder;
     builder.addOrdinaryDimension(IMDDimension_const_sptr(pDimensionOrdinary));
     Poco::XML::DOMParser pParser;
@@ -239,13 +261,13 @@ public:
   }
 
   void testManyOrinaryDimensions() {
-    MockIMDDimension *pDimA = new MockIMDDimension;
-    MockIMDDimension *pDimB = new MockIMDDimension;
-    MockIMDDimension *pDimC = new MockIMDDimension;
-
-    EXPECT_CALL(*pDimA, getDimensionId()).WillRepeatedly(Return("a"));
-    EXPECT_CALL(*pDimB, getDimensionId()).WillRepeatedly(Return("b"));
-    EXPECT_CALL(*pDimC, getDimensionId()).WillRepeatedly(Return("c"));
+    auto pDimA = boost::make_shared<MockIMDDimension>();
+    auto pDimB = boost::make_shared<MockIMDDimension>();
+    auto pDimC = boost::make_shared<MockIMDDimension>();
+    std::string a{"a"}, b{"b"}, c{"c"};
+    EXPECT_CALL(Const(*pDimA), getDimensionId()).WillRepeatedly(ReturnRef(a));
+    EXPECT_CALL(Const(*pDimB), getDimensionId()).WillRepeatedly(ReturnRef(b));
+    EXPECT_CALL(Const(*pDimC), getDimensionId()).WillRepeatedly(ReturnRef(c));
 
     EXPECT_CALL(*pDimA, toXMLString())
         .Times(1)
@@ -266,17 +288,18 @@ public:
     builder.addManyOrdinaryDimensions(vecDims);
 
     TS_ASSERT_THROWS_NOTHING(builder.create()); // Serialize the geometry.
-    TS_ASSERT(testing::Mock::VerifyAndClear(pDimA));
-    TS_ASSERT(testing::Mock::VerifyAndClear(pDimB));
-    TS_ASSERT(testing::Mock::VerifyAndClear(pDimC));
+    TS_ASSERT(testing::Mock::VerifyAndClear(pDimA.get()));
+    TS_ASSERT(testing::Mock::VerifyAndClear(pDimB.get()));
+    TS_ASSERT(testing::Mock::VerifyAndClear(pDimC.get()));
   }
 
   void testWithXDimensionOnly() {
-    MockIMDDimension *pDimensionX = new MockIMDDimension;
-
+    auto pDimensionX = boost::make_shared<MockIMDDimension>();
+    std::string a{"a"};
     EXPECT_CALL(*pDimensionX, toXMLString())
-        .WillOnce(Return(createDimensionXMLString(1, -1, 1, "A", "a")));
-    EXPECT_CALL(*pDimensionX, getDimensionId()).WillOnce(Return("a"));
+        .WillOnce(Return(createDimensionXMLString(1, -1, 1, "A", a)));
+    EXPECT_CALL(Const(*pDimensionX), getDimensionId())
+        .WillRepeatedly(ReturnRef(a));
 
     MDGeometryBuilderXML<NoDimensionPolicy> builder;
     builder.addXDimension(IMDDimension_const_sptr(pDimensionX));
@@ -312,16 +335,19 @@ public:
   }
 
   void testWithXYDimensionOnly() {
-    MockIMDDimension *pDimensionX = new MockIMDDimension;
-    MockIMDDimension *pDimensionY = new MockIMDDimension;
+    auto pDimensionX = boost::make_shared<MockIMDDimension>();
+    auto pDimensionY = boost::make_shared<MockIMDDimension>();
+    std::string a{"a"}, b{"b"};
 
     EXPECT_CALL(*pDimensionX, toXMLString())
-        .WillRepeatedly(Return(createDimensionXMLString(1, -1, 1, "A", "a")));
-    EXPECT_CALL(*pDimensionX, getDimensionId()).WillRepeatedly(Return("a"));
+        .WillRepeatedly(Return(createDimensionXMLString(1, -1, 1, "A", a)));
+    EXPECT_CALL(Const(*pDimensionX), getDimensionId())
+        .WillRepeatedly(ReturnRef(a));
 
     EXPECT_CALL(*pDimensionY, toXMLString())
-        .WillRepeatedly(Return(createDimensionXMLString(1, -1, 1, "B", "b")));
-    EXPECT_CALL(*pDimensionY, getDimensionId()).WillRepeatedly(Return("b"));
+        .WillRepeatedly(Return(createDimensionXMLString(1, -1, 1, "B", b)));
+    EXPECT_CALL(Const(*pDimensionY), getDimensionId())
+        .WillRepeatedly(ReturnRef(b));
 
     MDGeometryBuilderXML<NoDimensionPolicy> builder;
     builder.addXDimension(IMDDimension_const_sptr(pDimensionX));
@@ -359,21 +385,25 @@ public:
   }
 
   void testWithXYZDimensionOnly() {
-    MockIMDDimension *pDimensionX = new MockIMDDimension;
-    MockIMDDimension *pDimensionY = new MockIMDDimension;
-    MockIMDDimension *pDimensionZ = new MockIMDDimension;
+    auto pDimensionX = boost::make_shared<MockIMDDimension>();
+    auto pDimensionY = boost::make_shared<MockIMDDimension>();
+    auto pDimensionZ = boost::make_shared<MockIMDDimension>();
+    std::string a{"a"}, b{"b"}, c{"c"};
 
     EXPECT_CALL(*pDimensionX, toXMLString())
-        .WillRepeatedly(Return(createDimensionXMLString(1, -1, 1, "A", "a")));
-    EXPECT_CALL(*pDimensionX, getDimensionId()).WillRepeatedly(Return("a"));
+        .WillRepeatedly(Return(createDimensionXMLString(1, -1, 1, "A", a)));
+    EXPECT_CALL(Const(*pDimensionX), getDimensionId())
+        .WillRepeatedly(ReturnRef(a));
 
     EXPECT_CALL(*pDimensionY, toXMLString())
-        .WillRepeatedly(Return(createDimensionXMLString(1, -1, 1, "B", "b")));
-    EXPECT_CALL(*pDimensionY, getDimensionId()).WillRepeatedly(Return("b"));
+        .WillRepeatedly(Return(createDimensionXMLString(1, -1, 1, "B", b)));
+    EXPECT_CALL(Const(*pDimensionY), getDimensionId())
+        .WillRepeatedly(ReturnRef(b));
 
     EXPECT_CALL(*pDimensionZ, toXMLString())
-        .WillRepeatedly(Return(createDimensionXMLString(1, -1, 1, "C", "c")));
-    EXPECT_CALL(*pDimensionZ, getDimensionId()).WillRepeatedly(Return("c"));
+        .WillRepeatedly(Return(createDimensionXMLString(1, -1, 1, "C", c)));
+    EXPECT_CALL(Const(*pDimensionZ), getDimensionId())
+        .WillRepeatedly(ReturnRef(c));
 
     MDGeometryBuilderXML<NoDimensionPolicy> builder;
     builder.addXDimension(IMDDimension_const_sptr(pDimensionX));
@@ -412,32 +442,37 @@ public:
   }
 
   void testFullCreate() {
-    MockIMDDimension *pDimensionX = new MockIMDDimension;
-    MockIMDDimension *pDimensionY = new MockIMDDimension;
-    MockIMDDimension *pDimensionZ = new MockIMDDimension;
-    MockIMDDimension *pDimensionT = new MockIMDDimension;
+    auto pDimensionX = boost::make_shared<MockIMDDimension>();
+    auto pDimensionY = boost::make_shared<MockIMDDimension>();
+    auto pDimensionZ = boost::make_shared<MockIMDDimension>();
+    auto pDimensionT = boost::make_shared<MockIMDDimension>();
+    std::string a{"a"}, b{"b"}, c{"c"}, d{"d"};
 
     EXPECT_CALL(*pDimensionX, toXMLString())
-        .WillRepeatedly(Return(createDimensionXMLString(1, -1, 1, "A", "a")));
-    EXPECT_CALL(*pDimensionX, getDimensionId()).WillRepeatedly(Return("a"));
+        .WillRepeatedly(Return(createDimensionXMLString(1, -1, 1, "A", a)));
+    EXPECT_CALL(Const(*pDimensionX), getDimensionId())
+        .WillRepeatedly(ReturnRef(a));
 
     EXPECT_CALL(*pDimensionY, toXMLString())
-        .WillRepeatedly(Return(createDimensionXMLString(1, -1, 1, "B", "b")));
-    EXPECT_CALL(*pDimensionY, getDimensionId()).WillRepeatedly(Return("b"));
+        .WillRepeatedly(Return(createDimensionXMLString(1, -1, 1, "B", b)));
+    EXPECT_CALL(Const(*pDimensionY), getDimensionId())
+        .WillRepeatedly(ReturnRef(b));
 
     EXPECT_CALL(*pDimensionZ, toXMLString())
-        .WillRepeatedly(Return(createDimensionXMLString(1, -1, 1, "C", "c")));
-    EXPECT_CALL(*pDimensionZ, getDimensionId()).WillRepeatedly(Return("c"));
+        .WillRepeatedly(Return(createDimensionXMLString(1, -1, 1, "C", c)));
+    EXPECT_CALL(Const(*pDimensionZ), getDimensionId())
+        .WillRepeatedly(ReturnRef(c));
 
     EXPECT_CALL(*pDimensionT, toXMLString())
-        .WillRepeatedly(Return(createDimensionXMLString(1, -1, 1, "D", "d")));
-    EXPECT_CALL(*pDimensionT, getDimensionId()).WillRepeatedly(Return("d"));
+        .WillRepeatedly(Return(createDimensionXMLString(1, -1, 1, "D", d)));
+    EXPECT_CALL(Const(*pDimensionT), getDimensionId())
+        .WillRepeatedly(ReturnRef(d));
 
     MDGeometryBuilderXML<NoDimensionPolicy> builder;
-    builder.addXDimension(IMDDimension_const_sptr(pDimensionX));
-    builder.addYDimension(IMDDimension_const_sptr(pDimensionY));
-    builder.addZDimension(IMDDimension_const_sptr(pDimensionZ));
-    builder.addTDimension(IMDDimension_const_sptr(pDimensionT));
+    builder.addXDimension(pDimensionX);
+    builder.addYDimension(pDimensionY);
+    builder.addZDimension(pDimensionZ);
+    builder.addTDimension(pDimensionT);
 
     // Only practicle way to check the xml output in the absense of xsd is as
     // part of a dom tree.
diff --git a/Framework/Geometry/test/ObjComponentTest.h b/Framework/Geometry/test/ObjComponentTest.h
index a9f5bf5051babf65550d4b14954411fc47e7ef54..37f19be9f51d9fa5f5c8ba04090adae7a0a4167b 100644
--- a/Framework/Geometry/test/ObjComponentTest.h
+++ b/Framework/Geometry/test/ObjComponentTest.h
@@ -8,6 +8,7 @@
 #include "MantidGeometry/Surfaces/Cylinder.h"
 #include "MantidGeometry/Surfaces/Plane.h"
 #include "MantidGeometry/Objects/Object.h"
+#include "MantidGeometry/Objects/Track.h"
 #include "MantidKernel/Exception.h"
 
 #include "MantidKernel/Timer.h"
diff --git a/Framework/Geometry/test/ObjectTest.h b/Framework/Geometry/test/ObjectTest.h
index 17bbf3b128bfcc6cc2436ba2cd975ad0dae3ca42..85764166dac8008bc38886f08396fee54c9c22cb 100644
--- a/Framework/Geometry/test/ObjectTest.h
+++ b/Framework/Geometry/test/ObjectTest.h
@@ -21,15 +21,38 @@
 #include "MantidGeometry/Objects/Track.h"
 #include "MantidGeometry/Rendering/GluGeometryHandler.h"
 #include "MantidGeometry/Objects/ShapeFactory.h"
-
 #include "MantidKernel/Material.h"
-
+#include "MantidKernel/MersenneTwister.h"
+#include "MantidKernel/WarningSuppressions.h"
 #include "MantidTestHelpers/ComponentCreationHelper.h"
 
+#include <gmock/gmock.h>
+
 using namespace Mantid;
 using namespace Geometry;
 using Mantid::Kernel::V3D;
 
+namespace {
+// -----------------------------------------------------------------------------
+// Mock Random Number Generator
+// -----------------------------------------------------------------------------
+class MockRNG final : public Mantid::Kernel::PseudoRandomNumberGenerator {
+public:
+  GCC_DIAG_OFF_SUGGEST_OVERRIDE
+  MOCK_METHOD0(nextValue, double());
+  MOCK_METHOD2(nextValue, double(double, double));
+  MOCK_METHOD2(nextInt, int(int, int));
+  MOCK_METHOD0(restart, void());
+  MOCK_METHOD0(save, void());
+  MOCK_METHOD0(restore, void());
+  MOCK_METHOD1(setSeed, void(size_t));
+  MOCK_METHOD2(setRange, void(const double, const double));
+  MOCK_CONST_METHOD0(min, double());
+  MOCK_CONST_METHOD0(max, double());
+  GCC_DIAG_ON_SUGGEST_OVERRIDE
+};
+}
+
 class ObjectTest : public CxxTest::TestSuite {
 
 public:
@@ -53,8 +76,7 @@ public:
   }
 
   void testCopyConstructorGivesObjectWithSameAttributes() {
-    Object_sptr original =
-        ComponentCreationHelper::createSphere(1.0, V3D(), "sphere");
+    Object_sptr original = ComponentCreationHelper::createSphere(1.0);
     original->setID("sp-1");
     int objType(-1);
     double radius(-1.0), height(-1.0);
@@ -80,8 +102,7 @@ public:
   }
 
   void testAssignmentOperatorGivesObjectWithSameAttributes() {
-    Object_sptr original =
-        ComponentCreationHelper::createSphere(1.0, V3D(), "sphere");
+    Object_sptr original = ComponentCreationHelper::createSphere(1.0);
     original->setID("sp-1");
     int objType(-1);
     double radius(-1.0), height(-1.0);
@@ -181,7 +202,7 @@ public:
   }
 
   void testIsOnSideSphere() {
-    Object_sptr geom_obj = createSphere();
+    Object_sptr geom_obj = ComponentCreationHelper::createSphere(4.1);
     // inside
     TS_ASSERT_EQUALS(geom_obj->isOnSide(V3D(0, 0, 0)), false); // origin
     TS_ASSERT_EQUALS(geom_obj->isOnSide(V3D(0, 4.0, 0)), false);
@@ -202,7 +223,7 @@ public:
   }
 
   void testIsValidSphere() {
-    Object_sptr geom_obj = createSphere();
+    Object_sptr geom_obj = ComponentCreationHelper::createSphere(4.1);
     // inside
     TS_ASSERT_EQUALS(geom_obj->isValid(V3D(0, 0, 0)), true); // origin
     TS_ASSERT_EQUALS(geom_obj->isValid(V3D(0, 4.0, 0)), true);
@@ -223,7 +244,7 @@ public:
   }
 
   void testCalcValidTypeSphere() {
-    Object_sptr geom_obj = createSphere();
+    Object_sptr geom_obj = ComponentCreationHelper::createSphere(4.1);
     // entry on the normal
     TS_ASSERT_EQUALS(geom_obj->calcValidType(V3D(-4.1, 0, 0), V3D(1, 0, 0)), 1);
     TS_ASSERT_EQUALS(geom_obj->calcValidType(V3D(-4.1, 0, 0), V3D(-1, 0, 0)),
@@ -246,7 +267,7 @@ public:
   }
 
   void testGetBoundingBoxForSphere() {
-    Object_sptr geom_obj = createSphere();
+    Object_sptr geom_obj = ComponentCreationHelper::createSphere(4.1);
     const double tolerance(1e-10);
 
     double xmax, ymax, zmax, xmin, ymin, zmin;
@@ -322,7 +343,7 @@ public:
 
   void testInterceptSurfaceSphereY() {
     std::vector<Link> expectedResults;
-    Object_sptr geom_obj = createSphere();
+    Object_sptr geom_obj = ComponentCreationHelper::createSphere(4.1);
     Track track(V3D(0, -10, 0), V3D(0, 1, 0));
 
     // format = startPoint, endPoint, total distance so far
@@ -334,7 +355,7 @@ public:
 
   void testInterceptSurfaceSphereX() {
     std::vector<Link> expectedResults;
-    Object_sptr geom_obj = createSphere();
+    Object_sptr geom_obj = ComponentCreationHelper::createSphere(4.1);
     Track track(V3D(-10, 0, 0), V3D(1, 0, 0));
 
     // format = startPoint, endPoint, total distance so far
@@ -555,7 +576,7 @@ public:
   }
 
   void testComplementWithTwoPrimitives() {
-    auto shell = createSphericalShell();
+    auto shell = ComponentCreationHelper::createHollowShell(0.5, 1.0);
 
     TS_ASSERT_EQUALS(2, shell->getSurfaceIndex().size());
 
@@ -566,7 +587,7 @@ public:
     TS_ASSERT_EQUALS("SurfPoint", leaf1->className());
     auto surfPt1 = dynamic_cast<const SurfPoint *>(leaf1);
     TS_ASSERT(surfPt1);
-    TS_ASSERT_EQUALS(1, surfPt1->getKeyN());
+    TS_ASSERT_EQUALS(2, surfPt1->getKeyN());
     auto outer = dynamic_cast<const Sphere *>(surfPt1->getKey());
     TS_ASSERT(outer);
     TS_ASSERT_DELTA(1.0, outer->getRadius(), 1e-10);
@@ -577,7 +598,7 @@ public:
     TS_ASSERT(compRule);
     TS_ASSERT_EQUALS("SurfPoint", compRule->leaf(0)->className());
     auto surfPt2 = dynamic_cast<const SurfPoint *>(compRule->leaf(0));
-    TS_ASSERT_EQUALS(2, surfPt2->getKeyN());
+    TS_ASSERT_EQUALS(1, surfPt2->getKeyN());
     auto inner = dynamic_cast<const Sphere *>(surfPt2->getKey());
     TS_ASSERT(inner);
     TS_ASSERT_DELTA(0.5, inner->getRadius(), 1e-10);
@@ -661,17 +682,83 @@ public:
                          -M_SQRT2 - 0.5 * M_SQRT1_2,
                          -M_SQRT2 - 0.5 * M_SQRT1_2);
     TS_ASSERT_EQUALS(F->getPointInObject(pt), 1);
-    Object_sptr S = createSphere();
+    Object_sptr S = ComponentCreationHelper::createSphere(4.1);
     TS_ASSERT_EQUALS(S->getPointInObject(pt), 1);
     TS_ASSERT_EQUALS(pt, V3D(0.0, 0.0, 0));
   }
 
+  void testGeneratePointInside() {
+    using namespace ::testing;
+
+    // Generate "random" sequence
+    MockRNG rng;
+    Sequence rand;
+    EXPECT_CALL(rng, nextValue()).InSequence(rand).WillOnce(Return(0.55));
+    EXPECT_CALL(rng, nextValue()).InSequence(rand).WillOnce(Return(0.65));
+    EXPECT_CALL(rng, nextValue()).InSequence(rand).WillOnce(Return(0.70));
+
+    // inner radius=0.5, outer=1. Random sequence set up so as to give point
+    // inside hole
+    auto shell = ComponentCreationHelper::createHollowShell(0.5, 1.0);
+    size_t maxAttempts(1);
+    V3D point;
+    TS_ASSERT_THROWS_NOTHING(
+        point = shell->generatePointInObject(rng, maxAttempts));
+
+    const double tolerance(1e-10);
+    TS_ASSERT_DELTA(-1. + 2. * 0.55, point.X(), tolerance);
+    TS_ASSERT_DELTA(-1. + 2. * 0.65, point.Y(), tolerance);
+    TS_ASSERT_DELTA(-1. + 2. * 0.70, point.Z(), tolerance);
+  }
+
+  void testGeneratePointInsideRespectsMaxAttempts() {
+    using namespace ::testing;
+
+    // Generate "random" sequence
+    MockRNG rng;
+    Sequence rand;
+    EXPECT_CALL(rng, nextValue()).InSequence(rand).WillOnce(Return(0.1));
+    EXPECT_CALL(rng, nextValue()).InSequence(rand).WillOnce(Return(0.2));
+    EXPECT_CALL(rng, nextValue()).InSequence(rand).WillOnce(Return(0.3));
+
+    // inner radius=0.5, outer=1. Random sequence set up so as to give point
+    // inside hole
+    auto shell = ComponentCreationHelper::createHollowShell(0.5, 1.0);
+    size_t maxAttempts(1);
+    TS_ASSERT_THROWS(shell->generatePointInObject(rng, maxAttempts),
+                     std::runtime_error);
+  }
+
+  void testGeneratePointInsideRespectsActiveRegion() {
+    using namespace ::testing;
+
+    // Generate "random" sequence.
+    MockRNG rng;
+    Sequence rand;
+    EXPECT_CALL(rng, nextValue()).InSequence(rand).WillOnce(Return(0.01));
+    EXPECT_CALL(rng, nextValue()).InSequence(rand).WillOnce(Return(0.02));
+    EXPECT_CALL(rng, nextValue()).InSequence(rand).WillOnce(Return(0.03));
+
+    // Radius=0.5
+    auto ball = ComponentCreationHelper::createSphere(0.5);
+    // Create a thin infinite rectangular region to restrict point generation
+    BoundingBox activeRegion(0.1, 0.1, 0.1, -0.1, -0.1, -0.1);
+    size_t maxAttempts(1);
+    V3D point;
+    TS_ASSERT_THROWS_NOTHING(
+        point = ball->generatePointInObject(rng, activeRegion, maxAttempts));
+    const double tolerance(1e-10);
+    TS_ASSERT_DELTA(-0.1 + 0.01 * 0.2, point.X(), tolerance);
+    TS_ASSERT_DELTA(-0.1 + 0.02 * 0.2, point.Y(), tolerance);
+    TS_ASSERT_DELTA(-0.1 + 0.03 * 0.2, point.Z(), tolerance);
+  }
+
   void testSolidAngleSphere()
   /**
   Test solid angle calculation for a sphere
   */
   {
-    Object_sptr geom_obj = createSphere();
+    Object_sptr geom_obj = ComponentCreationHelper::createSphere(4.1);
     double satol = 2e-2; // tolerance for solid angle
 
     // Solid angle at distance 8.1 from centre of sphere radius 4.1 x/y/z
@@ -936,7 +1023,7 @@ public:
   Test solid angle calculation for a sphere from triangulation
   */
   {
-    Object_sptr geom_obj = createSphere();
+    Object_sptr geom_obj = ComponentCreationHelper::createSphere(4.1);
     double satol = 1e-3; // tolerance for solid angle
 
     // Solid angle at distance 8.1 from centre of sphere radius 4.1 x/y/z
@@ -1026,45 +1113,6 @@ private:
     return retVal;
   }
 
-  Object_sptr createSphere() {
-    std::string S41 = "so 4.1"; // Sphere at origin radius 4.1
-
-    // First create some surfaces
-    std::map<int, boost::shared_ptr<Surface>> SphSurMap;
-    SphSurMap[41] = boost::make_shared<Sphere>();
-    SphSurMap[41]->setSurface(S41);
-    SphSurMap[41]->setName(41);
-
-    // A sphere
-    std::string ObjSphere = "-41";
-
-    Object_sptr retVal = Object_sptr(new Object);
-    retVal->setObject(41, ObjSphere);
-    retVal->populate(SphSurMap);
-
-    return retVal;
-  }
-
-  Object_sptr createSphericalShell() {
-    // First create some surfaces
-    auto outer = boost::make_shared<Sphere>();
-    outer->setName(1);
-    outer->setRadius(1.0);
-    auto inner = boost::make_shared<Sphere>();
-    inner->setName(2);
-    inner->setRadius(0.5);
-    std::map<int, boost::shared_ptr<Surface>> surfaces = {{1, outer},
-                                                          {2, inner}};
-
-    // algebra string is outer with intersection of complement of inner
-    const std::string algebra = "(-1) # (-2)";
-    auto shell = boost::make_shared<Object>();
-    shell->setObject(21, algebra);
-    shell->populate(surfaces);
-
-    return shell;
-  }
-
   void clearSurfMap()
   /**
   Clears the surface map for a new test
@@ -1294,4 +1342,43 @@ private:
   }
 };
 
+// -----------------------------------------------------------------------------
+// Performance tests
+// -----------------------------------------------------------------------------
+class ObjectTestPerformance : public CxxTest::TestSuite {
+public:
+  // This pair of boilerplate methods prevent the suite being created statically
+  // This means the constructor isn't called when running other tests
+  static ObjectTestPerformance *createSuite() {
+    return new ObjectTestPerformance();
+  }
+  static void destroySuite(ObjectTestPerformance *suite) { delete suite; }
+
+  ObjectTestPerformance()
+      : rng(200000), solid(ComponentCreationHelper::createSphere(0.1)),
+        shell(ComponentCreationHelper::createHollowShell(0.009, 0.01)) {}
+
+  void test_generatePointInside_Solid_Primitive() {
+    const size_t maxAttempts(500);
+    V3D dummy;
+    for (size_t i = 0; i < npoints; ++i) {
+      dummy = solid->generatePointInObject(rng, maxAttempts);
+    }
+  }
+
+  void test_Point_Inside_Solid_Composite_With_Hole() {
+    const size_t maxAttempts(500);
+    V3D dummy;
+    for (size_t i = 0; i < npoints; ++i) {
+      dummy = shell->generatePointInObject(rng, maxAttempts);
+    }
+  }
+
+private:
+  const size_t npoints = 20000;
+  Mantid::Kernel::MersenneTwister rng;
+  Object_sptr solid;
+  Object_sptr shell;
+};
+
 #endif // MANTID_TESTOBJECT__
diff --git a/Framework/Geometry/test/ParDetectorTest.h b/Framework/Geometry/test/ParDetectorTest.h
index 06cdce1055fec487294493e369fb723d746e1d79..2472f113b994e334c1f7eb16549fd29f51361e4b 100644
--- a/Framework/Geometry/test/ParDetectorTest.h
+++ b/Framework/Geometry/test/ParDetectorTest.h
@@ -19,8 +19,6 @@ public:
     TS_ASSERT_EQUALS(pdet->getName(), "det1");
     TS_ASSERT(!pdet->getParent());
     TS_ASSERT_EQUALS(pdet->getID(), 0);
-    TS_ASSERT(!pdet->isMasked());
-    TS_ASSERT(!pdet->isMonitor());
   }
 
   void testNameParentConstructor() {
@@ -33,8 +31,6 @@ public:
     TS_ASSERT_EQUALS(pdet->getName(), "det1");
     TS_ASSERT(pdet->getParent());
     TS_ASSERT_EQUALS(pdet->getID(), 0);
-    TS_ASSERT(!pdet->isMasked());
-    TS_ASSERT(!pdet->isMonitor());
   }
 
   void testId() {
@@ -62,22 +58,10 @@ public:
     ParameterMap_sptr pmap(new ParameterMap());
     boost::shared_ptr<Detector> pdet(det.cloneParameterized(pmap.get()));
 
-    TS_ASSERT(!pdet->isMasked());
-    pmap->addBool(&det, "masked", true);
-    TS_ASSERT(pdet->isMasked());
-  }
-
-  void testMonitor() {
-    Detector det("det", 0, 0);
-
-    ParameterMap_sptr pmap(new ParameterMap());
-    boost::shared_ptr<Detector> pdet(det.cloneParameterized(pmap.get()));
-
-    TS_ASSERT(!pdet->isMonitor());
-    TS_ASSERT_THROWS_NOTHING(det.markAsMonitor());
-    TS_ASSERT(pdet->isMonitor());
-    TS_ASSERT_THROWS_NOTHING(det.markAsMonitor(false));
-    TS_ASSERT(!pdet->isMonitor());
+    // Reading and writing masking should throw: Masking is now stored in
+    // DetectorInfo and ParameterMap should reject it.
+    TS_ASSERT_THROWS(pmap->get(&det, "masked"), std::runtime_error);
+    TS_ASSERT_THROWS(pmap->addBool(&det, "masked", true), std::runtime_error);
   }
 
   void testGetNumberParameter() {
diff --git a/Framework/Geometry/test/ParInstrumentTest.h b/Framework/Geometry/test/ParInstrumentTest.h
index 0182404e4e886ba1d06040bc91e13663e893bba9..908331ababf331365b89441af8fb1245e3cf462c 100644
--- a/Framework/Geometry/test/ParInstrumentTest.h
+++ b/Framework/Geometry/test/ParInstrumentTest.h
@@ -52,6 +52,14 @@ public:
                      std::invalid_argument);
   }
 
+  void test_getMonitors() {
+    // testDetector injects a pointer into `instrument` that is deleted later.
+    // Instrument::getMonitors will then cause a segmentation fault, so this
+    // test must run before we have invalid pointers.
+    Instrument pinstrument(instrument, pmap);
+    TS_ASSERT_EQUALS(pinstrument.getMonitors().size(), 1)
+  }
+
   void testDetector() {
     Instrument pinstrument(instrument, pmap);
     TS_ASSERT_THROWS(pinstrument.getDetector(0), Exception::NotFoundError);
@@ -88,11 +96,6 @@ public:
                      instrument->getComponentByID(id3)->getName());
   }
 
-  void test_numMonitors() {
-    Instrument pinstrument(instrument, pmap);
-    TS_ASSERT_EQUALS(pinstrument.numMonitors(), 1)
-  }
-
 private:
   boost::shared_ptr<Instrument> instrument;
   Mantid::Geometry::ParameterMap_sptr pmap;
diff --git a/Framework/Geometry/test/ParObjComponentTest.h b/Framework/Geometry/test/ParObjComponentTest.h
index b59bd6e9b8cf7e4bc3d1dfc123ab133cbfb43dd0..97a1d8c11de4e5abcf19fdd28299850ca5313248 100644
--- a/Framework/Geometry/test/ParObjComponentTest.h
+++ b/Framework/Geometry/test/ParObjComponentTest.h
@@ -9,6 +9,7 @@
 #include "MantidGeometry/Surfaces/Cylinder.h"
 #include "MantidGeometry/Surfaces/Plane.h"
 #include "MantidGeometry/Objects/Object.h"
+#include "MantidGeometry/Objects/Track.h"
 #include "MantidKernel/Exception.h"
 
 #include "boost/make_shared.hpp"
diff --git a/Framework/Geometry/test/ParameterMapTest.h b/Framework/Geometry/test/ParameterMapTest.h
index 96bc3e32a4ca05eb4aea0f3f4c1f91609ac0891f..4b3a053d158009296e6fe6e3ec95f8a642f8a5ab 100644
--- a/Framework/Geometry/test/ParameterMapTest.h
+++ b/Framework/Geometry/test/ParameterMapTest.h
@@ -2,6 +2,7 @@
 #define PARAMETERMAPTEST_H_
 
 #include "MantidGeometry/Instrument/Parameter.h"
+#include "MantidGeometry/Instrument/ParameterFactory.h"
 #include "MantidGeometry/Instrument/ParameterMap.h"
 #include "MantidGeometry/Instrument/Detector.h"
 #include "MantidTestHelpers/ComponentCreationHelper.h"
diff --git a/Framework/Geometry/test/SampleEnvironmentFactoryTest.h b/Framework/Geometry/test/SampleEnvironmentFactoryTest.h
index 06290556258504d693be53760501fab00137dc23..65a6b4f07ce912d43225cf56a8b6b68a6ccec1eb 100644
--- a/Framework/Geometry/test/SampleEnvironmentFactoryTest.h
+++ b/Framework/Geometry/test/SampleEnvironmentFactoryTest.h
@@ -5,6 +5,7 @@
 #include "MantidGeometry/Instrument/SampleEnvironmentFactory.h"
 #include "MantidGeometry/Instrument/Container.h"
 #include "MantidGeometry/Objects/ShapeFactory.h"
+#include "MantidKernel/make_unique.h"
 
 #include "MantidTestHelpers/ComponentCreationHelper.h"
 
diff --git a/Framework/Geometry/test/SampleEnvironmentTest.h b/Framework/Geometry/test/SampleEnvironmentTest.h
index 1326e5dc00306cb88110f9fb8f769b4dc165079f..4acf34dbca96941e8d1afb22fd76258b9d88d89a 100644
--- a/Framework/Geometry/test/SampleEnvironmentTest.h
+++ b/Framework/Geometry/test/SampleEnvironmentTest.h
@@ -3,14 +3,39 @@
 
 #include "MantidGeometry/Instrument/SampleEnvironment.h"
 #include "MantidGeometry/Objects/ShapeFactory.h"
+#include "MantidGeometry/Objects/Track.h"
 #include "MantidKernel/V3D.h"
 #include "MantidTestHelpers/ComponentCreationHelper.h"
+#include "MantidKernel/PseudoRandomNumberGenerator.h"
+#include "MantidKernel/WarningSuppressions.h"
 
 #include <boost/make_shared.hpp>
 #include <cxxtest/TestSuite.h>
+#include <gmock/gmock.h>
 
 using Mantid::Geometry::SampleEnvironment;
 
+namespace {
+// -----------------------------------------------------------------------------
+// Mock Random Number Generator
+// -----------------------------------------------------------------------------
+class MockRNG final : public Mantid::Kernel::PseudoRandomNumberGenerator {
+public:
+  GCC_DIAG_OFF_SUGGEST_OVERRIDE
+  MOCK_METHOD0(nextValue, double());
+  MOCK_METHOD2(nextValue, double(double, double));
+  MOCK_METHOD2(nextInt, int(int, int));
+  MOCK_METHOD0(restart, void());
+  MOCK_METHOD0(save, void());
+  MOCK_METHOD0(restore, void());
+  MOCK_METHOD1(setSeed, void(size_t));
+  MOCK_METHOD2(setRange, void(const double, const double));
+  MOCK_CONST_METHOD0(min, double());
+  MOCK_CONST_METHOD0(max, double());
+  GCC_DIAG_ON_SUGGEST_OVERRIDE
+};
+}
+
 class SampleEnvironmentTest : public CxxTest::TestSuite {
 public:
   // This pair of boilerplate methods prevent the suite being created statically
@@ -82,6 +107,78 @@ public:
     TS_ASSERT_DELTA(0.2, widths.Z(), 1e-12);
   }
 
+  void testGeneratePointConsidersAllComponents() {
+    using namespace ::testing;
+    using namespace Mantid::Kernel;
+
+    auto kit = createTestKit();
+    size_t maxAttempts(1);
+
+    // Generate "random" sequence
+    MockRNG rng;
+    // Selects first component
+    EXPECT_CALL(rng, nextInt(_, _)).Times(Exactly(1)).WillOnce(Return(1));
+    EXPECT_CALL(rng, nextValue())
+        .Times(3)
+        .WillOnce(Return(0.55))
+        .WillOnce(Return(0.65))
+        .WillOnce(Return(0.70));
+    V3D comp1Point;
+    TS_ASSERT_THROWS_NOTHING(comp1Point = kit->generatePoint(rng, maxAttempts));
+    TS_ASSERT(kit->isValid(comp1Point));
+    Mock::VerifyAndClearExpectations(&rng);
+
+    // Selects second component
+    EXPECT_CALL(rng, nextInt(_, _)).Times(Exactly(1)).WillOnce(Return(2));
+    EXPECT_CALL(rng, nextValue())
+        .Times(3)
+        .WillOnce(Return(0.55))
+        .WillOnce(Return(0.65))
+        .WillOnce(Return(0.70));
+    V3D comp2Point;
+    TS_ASSERT_THROWS_NOTHING(comp2Point = kit->generatePoint(rng, maxAttempts));
+    TS_ASSERT(comp2Point != comp1Point);
+    TS_ASSERT(kit->isValid(comp2Point));
+    Mock::VerifyAndClearExpectations(&rng);
+
+    // Selects third component
+    EXPECT_CALL(rng, nextInt(_, _)).Times(Exactly(1)).WillOnce(Return(3));
+    EXPECT_CALL(rng, nextValue())
+        .Times(3)
+        .WillOnce(Return(0.55))
+        .WillOnce(Return(0.65))
+        .WillOnce(Return(0.70));
+    V3D comp3Point;
+    TS_ASSERT_THROWS_NOTHING(comp3Point = kit->generatePoint(rng, maxAttempts));
+    TS_ASSERT(comp3Point != comp2Point);
+    TS_ASSERT(comp3Point != comp1Point);
+    TS_ASSERT(kit->isValid(comp3Point));
+    Mock::VerifyAndClearExpectations(&rng);
+  }
+
+  void testGeneratePointRespectsActiveRegion() {
+    using namespace ::testing;
+    using namespace Mantid::Kernel;
+
+    auto kit = createTestKit();
+    size_t maxAttempts(1);
+
+    // Generate "random" sequence
+    MockRNG rng;
+    // Sequence will try to select one of the non-container pieces
+    EXPECT_CALL(rng, nextInt(_, _)).Times(Exactly(1)).WillOnce(Return(2));
+    EXPECT_CALL(rng, nextValue())
+        .Times(3)
+        .WillOnce(Return(0.5))
+        .WillOnce(Return(0.5))
+        .WillOnce(Return(0.5));
+    // Restrict region to can
+    TS_ASSERT_THROWS(kit->generatePoint(rng, kit->container()->getBoundingBox(),
+                                        maxAttempts),
+                     std::runtime_error);
+    Mock::VerifyAndClearExpectations(&rng);
+  }
+
 private:
   boost::shared_ptr<SampleEnvironment> createTestKit() {
     using namespace Mantid::Geometry;
diff --git a/Framework/Geometry/test/TrackTest.h b/Framework/Geometry/test/TrackTest.h
index 2de7b8eb9b476e96f7f618340de61f1340bf3d8a..c9e82ea561bd831c99c1f4de47b6acf073472fc8 100644
--- a/Framework/Geometry/test/TrackTest.h
+++ b/Framework/Geometry/test/TrackTest.h
@@ -40,6 +40,9 @@ public:
     Track A(V3D(1, 1, 1), V3D(1.0, 0.0, 0.0));
     Object shape;
     A.addLink(V3D(2, 2, 2), V3D(3, 3, 3), 2.0, shape, NULL);
+    const auto &linkFront = A.front();
+    const auto &linkBack = A.back();
+    TS_ASSERT_EQUALS(&linkFront, &linkBack);
     Track::LType::const_iterator iterBegin = A.cbegin();
     Track::LType::const_iterator iterEnd = A.cend();
     iterBegin++;
diff --git a/Framework/HistogramData/CMakeLists.txt b/Framework/HistogramData/CMakeLists.txt
index 0776268658c61b7139de40879a3bd67719c918c7..1f58d2f4216231a6c3ce90f8cd5020f66f5698b8 100644
--- a/Framework/HistogramData/CMakeLists.txt
+++ b/Framework/HistogramData/CMakeLists.txt
@@ -3,6 +3,7 @@ set ( SRC_FILES
 	src/CountStandardDeviations.cpp
 	src/CountVariances.cpp
 	src/Counts.cpp
+	src/Exception.cpp
 	src/Frequencies.cpp
 	src/FrequencyStandardDeviations.cpp
 	src/FrequencyVariances.cpp
@@ -20,6 +21,7 @@ set ( INC_FILES
 	inc/MantidHistogramData/CountVariances.h
 	inc/MantidHistogramData/Counts.h
 	inc/MantidHistogramData/EValidation.h
+	inc/MantidHistogramData/Exception.h
 	inc/MantidHistogramData/FixedLengthVector.h
 	inc/MantidHistogramData/Frequencies.h
 	inc/MantidHistogramData/FrequencyStandardDeviations.h
diff --git a/Framework/HistogramData/inc/MantidHistogramData/Exception.h b/Framework/HistogramData/inc/MantidHistogramData/Exception.h
new file mode 100644
index 0000000000000000000000000000000000000000..3600e327d94d1983646b68bc31c24939522814ba
--- /dev/null
+++ b/Framework/HistogramData/inc/MantidHistogramData/Exception.h
@@ -0,0 +1,16 @@
+#include "MantidHistogramData/DllConfig.h"
+#include <stdexcept>
+
+namespace Mantid {
+namespace HistogramData {
+namespace Exception {
+
+/// Thrown whenever invalid bin edges are encountered by HistogramData Rebin
+class MANTID_HISTOGRAMDATA_DLL InvalidBinEdgesError
+    : public std::runtime_error {
+public:
+  InvalidBinEdgesError(const char *what);
+};
+}
+}
+}
\ No newline at end of file
diff --git a/Framework/HistogramData/src/Exception.cpp b/Framework/HistogramData/src/Exception.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..235c8cfaa7226f8c52cbd77833b8c35858f19e59
--- /dev/null
+++ b/Framework/HistogramData/src/Exception.cpp
@@ -0,0 +1,10 @@
+#include "MantidHistogramData/Exception.h"
+
+namespace Mantid {
+namespace HistogramData {
+namespace Exception {
+InvalidBinEdgesError::InvalidBinEdgesError(const char *what)
+    : runtime_error(what) {}
+}
+}
+}
\ No newline at end of file
diff --git a/Framework/HistogramData/src/Histogram.cpp b/Framework/HistogramData/src/Histogram.cpp
index 4570161a0736f7e2819691046b873f58c5b2dbb6..d6367b8cd828eeccdf3530a70ece473b25707cd6 100644
--- a/Framework/HistogramData/src/Histogram.cpp
+++ b/Framework/HistogramData/src/Histogram.cpp
@@ -137,7 +137,8 @@ void Histogram::setSharedY(const Kernel::cow_ptr<HistogramY> &y) & {
   if (yMode() == YMode::Uninitialized)
     throw std::logic_error(
         "Histogram::setSharedY: YMode is not set and cannot be determined");
-  checkSize(*y);
+  if (y)
+    checkSize(*y);
   m_y = y;
 }
 
@@ -145,7 +146,8 @@ void Histogram::setSharedY(const Kernel::cow_ptr<HistogramY> &y) & {
 
   Throws if the size does not match the current size. */
 void Histogram::setSharedE(const Kernel::cow_ptr<HistogramE> &e) & {
-  checkSize(*e);
+  if (e)
+    checkSize(*e);
   m_e = e;
 }
 
@@ -232,15 +234,15 @@ void Histogram::setUncertainties(const FrequencyStandardDeviations &e) {
 
 void Histogram::checkAndSetYModeCounts() {
   if (yMode() == YMode::Frequencies)
-    throw std::logic_error("Histogram: Y is storing Counts, modifying "
-                           "Frequencies is not possible.");
+    throw std::logic_error("Histogram: Y is storing Frequencies, modifying "
+                           "Counts is not possible.");
   m_yMode = YMode::Counts;
 }
 
 void Histogram::checkAndSetYModeFrequencies() {
   if (yMode() == YMode::Counts)
-    throw std::logic_error("Histogram: Y is storing Frequencies, modifying "
-                           "Counts is not possible.");
+    throw std::logic_error("Histogram: Y is storing Counts, modifying "
+                           "Frequencies is not possible.");
   m_yMode = YMode::Frequencies;
 }
 
diff --git a/Framework/HistogramData/src/Rebin.cpp b/Framework/HistogramData/src/Rebin.cpp
index 19d767e674c3590a73096cd4b61a94e00061fa11..ff06056bfc2f38293ed664a90472da1c36e07630 100644
--- a/Framework/HistogramData/src/Rebin.cpp
+++ b/Framework/HistogramData/src/Rebin.cpp
@@ -1,5 +1,6 @@
 #include "MantidHistogramData/Rebin.h"
 #include "MantidHistogramData/BinEdges.h"
+#include "MantidHistogramData/Exception.h"
 #include "MantidHistogramData/Histogram.h"
 #include <algorithm>
 #include <numeric>
@@ -12,6 +13,7 @@ using Mantid::HistogramData::CountVariances;
 using Mantid::HistogramData::Frequencies;
 using Mantid::HistogramData::FrequencyStandardDeviations;
 using Mantid::HistogramData::FrequencyVariances;
+using Mantid::HistogramData::Exception::InvalidBinEdgesError;
 
 namespace {
 Histogram rebinCounts(const Histogram &input, const BinEdges &binEdges) {
@@ -39,7 +41,7 @@ Histogram rebinCounts(const Histogram &input, const BinEdges &binEdges) {
     auto nwidth = xn_high - xn_low;
 
     if (owidth <= 0.0 || nwidth <= 0.0)
-      throw std::runtime_error("Negative or zero bin widths not allowed.");
+      throw InvalidBinEdgesError("Negative or zero bin widths not allowed.");
 
     if (xn_high <= xo_low)
       inew++; /* old and new bins do not overlap */
@@ -50,9 +52,8 @@ Histogram rebinCounts(const Histogram &input, const BinEdges &binEdges) {
       auto delta = xo_high < xn_high ? xo_high : xn_high;
       delta -= xo_low > xn_low ? xo_low : xn_low;
 
-      auto factor = 1 / owidth;
-      ynew[inew] += yold[iold] * delta * factor;
-      enew[inew] += eold[iold] * eold[iold] * delta * factor;
+      ynew[inew] += yold[iold] * delta / owidth;
+      enew[inew] += eold[iold] * eold[iold] * delta / owidth;
 
       if (xn_high > xo_high) {
         iold++;
@@ -92,7 +93,7 @@ Histogram rebinFrequencies(const Histogram &input, const BinEdges &binEdges) {
     auto nwidth = xn_high - xn_low;
 
     if (owidth <= 0.0 || nwidth <= 0.0)
-      throw std::runtime_error("Negative or zero bin widths not allowed.");
+      throw InvalidBinEdgesError("Negative or zero bin widths not allowed.");
 
     if (xn_high <= xo_low)
       inew++; /* old and new bins do not overlap */
@@ -109,14 +110,18 @@ Histogram rebinFrequencies(const Histogram &input, const BinEdges &binEdges) {
       if (xn_high > xo_high) {
         iold++;
       } else {
-        auto factor = 1 / nwidth;
-        ynew[inew] *= factor;
-        enew[inew] = sqrt(enew[inew]) * factor;
         inew++;
       }
     }
   }
 
+  for (size_t i = 0; i < size_ynew; ++i) {
+    auto width = xnew[i + 1] - xnew[i];
+    auto factor = 1 / width;
+    ynew[i] *= factor;
+    enew[i] = sqrt(enew[i]) * factor;
+  }
+
   return Histogram(binEdges, newFrequencies, newFrequencyStdDev);
 }
 } // anonymous namespace
diff --git a/Framework/HistogramData/test/RebinTest.h b/Framework/HistogramData/test/RebinTest.h
index e3b4a7d78424ca94576a2e9dbf2c179e54be22ff..61aa1a04e8b2b6f09988b81da61ae6def4c13147 100644
--- a/Framework/HistogramData/test/RebinTest.h
+++ b/Framework/HistogramData/test/RebinTest.h
@@ -3,6 +3,7 @@
 
 #include <cxxtest/TestSuite.h>
 
+#include "MantidHistogramData/Exception.h"
 #include "MantidHistogramData/Histogram.h"
 #include "MantidHistogramData/LinearGenerator.h"
 #include "MantidHistogramData/Rebin.h"
@@ -12,6 +13,7 @@
 #include <random>
 
 using namespace Mantid::HistogramData;
+using namespace Mantid::HistogramData::Exception;
 
 class RebinTest : public CxxTest::TestSuite {
 public:
@@ -47,21 +49,30 @@ public:
     std::vector<double> binEdges{1, 2, 3, 3, 5, 7};
     BinEdges edges(binEdges);
 
-    TS_ASSERT_THROWS(rebin(getCountsHistogram(), edges), std::runtime_error);
+    TS_ASSERT_THROWS(rebin(getCountsHistogram(), edges), InvalidBinEdgesError);
   }
 
   void testRebinFailsStartBinEdgesInvalid() {
     std::vector<double> binEdges{1, 1, 3, 4, 5, 7};
     BinEdges edges(binEdges);
 
-    TS_ASSERT_THROWS(rebin(getCountsHistogram(), edges), std::runtime_error);
+    TS_ASSERT_THROWS(rebin(getCountsHistogram(), edges), InvalidBinEdgesError);
   }
 
   void testRebinEndCentralBinEdgesInvalid() {
     std::vector<double> binEdges{1, 2, 3, 4, 5, 5};
     BinEdges edges(binEdges);
 
-    TS_ASSERT_THROWS(rebin(getCountsHistogram(), edges), std::runtime_error);
+    TS_ASSERT_THROWS(rebin(getCountsHistogram(), edges), InvalidBinEdgesError);
+  }
+
+  void testNegativeBinEdges() {
+    auto hist = Histogram(BinEdges(3, LinearGenerator(-3, 3)), Counts{20, 10},
+                          CountStandardDeviations{4.4721, 3.1622});
+    std::vector<double> binEdges{-3, -2, -1, 0, 1, 2, 3};
+    BinEdges edges(std::move(binEdges));
+
+    TS_ASSERT_THROWS_NOTHING(rebin(getCountsHistogram(), edges));
   }
 
   void testRebinFailsInputBinEdgesInvalid() {
@@ -69,7 +80,7 @@ public:
     Histogram hist(BinEdges(std::move(binEdges)), Counts(5, 10));
     BinEdges edges{1, 2, 3, 4, 5, 6};
 
-    TS_ASSERT_THROWS(rebin(hist, edges), std::runtime_error);
+    TS_ASSERT_THROWS(rebin(hist, edges), InvalidBinEdgesError);
   }
 
   void testRebinFailsInputAndOutputBinEdgesInvalid() {
@@ -77,7 +88,7 @@ public:
     Histogram hist(BinEdges(binEdges), Counts(5, 10));
     BinEdges edges(std::move(binEdges));
 
-    TS_ASSERT_THROWS(rebin(hist, edges), std::runtime_error);
+    TS_ASSERT_THROWS(rebin(hist, edges), InvalidBinEdgesError);
   }
 
   void testRebinIdenticalBins() {
@@ -321,7 +332,7 @@ public:
 
     TS_ASSERT_DELTA(outFreq.e()[0], std::sqrt(outFreq.y()[0]), 1e-14);
     TS_ASSERT_DELTA(outFreq.e()[1], std::sqrt(outFreq.y()[1]), 1e-14);
-    TS_ASSERT_DELTA(outFreq.e()[2], outFreq.y()[2], 1e-14);
+    TS_ASSERT_DELTA(outFreq.e()[2], std::sqrt(outFreq.y()[2]), 1e-14);
   }
 
   void testSmallerBinsSymmetric() {
diff --git a/Framework/ICat/src/CatalogKeepAlive.cpp b/Framework/ICat/src/CatalogKeepAlive.cpp
index 0bc549faa7aaf5effd3b28561fd38281cd4d5d08..fb55f97be3ede909c37f4a1f18c5bb95b6599d1d 100644
--- a/Framework/ICat/src/CatalogKeepAlive.cpp
+++ b/Framework/ICat/src/CatalogKeepAlive.cpp
@@ -1,5 +1,6 @@
 #include "MantidICat/CatalogKeepAlive.h"
 #include "MantidAPI/CatalogManager.h"
+#include "MantidKernel/DateAndTime.h"
 
 #include <Poco/Thread.h>
 
diff --git a/Framework/ICat/src/CatalogPublish.cpp b/Framework/ICat/src/CatalogPublish.cpp
index abd34318cc546189b367e8b5ad638ecb6cab013e..5a25d57c881b3ff031a1c6a311e2236499ae5df8 100644
--- a/Framework/ICat/src/CatalogPublish.cpp
+++ b/Framework/ICat/src/CatalogPublish.cpp
@@ -96,10 +96,10 @@ void CatalogPublish::exec() {
   } else // The user wants to upload a workspace.
   {
     if (nameInCatalog.empty()) {
-      setProperty("NameInCatalog", workspace->name());
+      setProperty("NameInCatalog", workspace->getName());
       g_log.notice(
           "NameInCatalog has not been set. Using workspace name instead: " +
-          workspace->name() + ".");
+          workspace->getName() + ".");
     }
 
     // Save workspace to a .nxs file in the user's default directory.
@@ -108,7 +108,7 @@ void CatalogPublish::exec() {
     // workspace was saved to).
     filePath = Mantid::Kernel::ConfigService::Instance().getString(
                    "defaultsave.directory") +
-               workspace->name() + ".nxs";
+               workspace->getName() + ".nxs";
   }
 
   // Obtain the mode to used base on file extension.
@@ -223,11 +223,11 @@ void CatalogPublish::saveWorkspaceToNexus(
       Mantid::API::AlgorithmManager::Instance().create("SaveNexus");
   saveNexus->initialize();
   // Set the required properties & execute.
-  saveNexus->setProperty("InputWorkspace", workspace->name());
+  saveNexus->setProperty("InputWorkspace", workspace->getName());
   saveNexus->setProperty("FileName",
                          Mantid::Kernel::ConfigService::Instance().getString(
                              "defaultsave.directory") +
-                             workspace->name() + ".nxs");
+                             workspace->getName() + ".nxs");
   saveNexus->execute();
 }
 
@@ -263,7 +263,7 @@ const std::string CatalogPublish::generateWorkspaceHistory(
   auto wsHistory = Mantid::API::AlgorithmManager::Instance().createUnmanaged(
       "GeneratePythonScript");
   wsHistory->initialize();
-  wsHistory->setProperty("InputWorkspace", workspace->name());
+  wsHistory->setProperty("InputWorkspace", workspace->getName());
   wsHistory->execute();
   return wsHistory->getPropertyValue("ScriptText");
 }
diff --git a/Framework/ICat/test/ICatTestHelper.cpp b/Framework/ICat/test/ICatTestHelper.cpp
index 199bb9d6eaf3eb5999cee4b0b8eba0e0e561ae58..5b3b18968181bb66e3940b8fb6b9e82d2f53178d 100644
--- a/Framework/ICat/test/ICatTestHelper.cpp
+++ b/Framework/ICat/test/ICatTestHelper.cpp
@@ -1,5 +1,7 @@
 #include "ICatTestHelper.h"
 
+#include <iostream>
+
 namespace ICatTestHelper {
 /// Skip all unit tests if ICat server is down
 bool skipTests() {
diff --git a/Framework/Indexing/CMakeLists.txt b/Framework/Indexing/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..1a471e6eb0e8540e790fe98d5627a6ebf7a7d052
--- /dev/null
+++ b/Framework/Indexing/CMakeLists.txt
@@ -0,0 +1,55 @@
+set ( SRC_FILES
+	src/Extract.cpp
+	src/Group.cpp
+	src/IndexInfo.cpp
+)
+
+set ( INC_FILES
+	inc/MantidIndexing/DllConfig.h
+	inc/MantidIndexing/Extract.h
+	inc/MantidIndexing/Group.h
+	inc/MantidIndexing/IndexInfo.h
+	inc/MantidIndexing/MakeRange.h
+)
+
+set ( TEST_FILES
+	ExtractTest.h
+	GroupTest.h
+	IndexInfoTest.h
+	MakeRangeTest.h
+)
+
+if (COVERALLS)
+  foreach( loop_var ${SRC_FILES} ${INC_FILES})
+    set_property(GLOBAL APPEND PROPERTY COVERAGE_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/${loop_var}")
+  endforeach(loop_var)
+endif()
+
+if(UNITY_BUILD)
+  include(UnityBuild)
+  enable_unity_build(Indexing SRC_FILES SRC_UNITY_IGNORE_FILES 10)
+endif(UNITY_BUILD)
+
+# Add the target for this directory
+add_library ( Indexing ${SRC_FILES} ${INC_FILES} )
+# Set the name of the generated library
+set_target_properties ( Indexing PROPERTIES OUTPUT_NAME MantidIndexing
+  COMPILE_DEFINITIONS IN_MANTID_INDEXING )
+
+if (OSX_VERSION VERSION_GREATER 10.8)
+  set_target_properties ( Indexing PROPERTIES INSTALL_RPATH "@loader_path/../MacOS")
+endif ()
+
+# Add to the 'Framework' group in VS
+set_property ( TARGET Indexing PROPERTY FOLDER "MantidFramework" )
+
+target_link_libraries ( Indexing LINK_PRIVATE ${TCMALLOC_LIBRARIES_LINKTIME} ${MANTIDLIBS} )
+
+# Add the unit tests directory
+add_subdirectory ( test )
+
+###########################################################################
+# Installation settings
+###########################################################################
+
+install ( TARGETS Indexing ${SYSTEM_PACKAGE_TARGET} DESTINATION ${LIB_DIR} )
diff --git a/Framework/Indexing/inc/MantidIndexing/DllConfig.h b/Framework/Indexing/inc/MantidIndexing/DllConfig.h
new file mode 100644
index 0000000000000000000000000000000000000000..d05769d3c0b34117bd4efc1eb5a70d91d23c75d3
--- /dev/null
+++ b/Framework/Indexing/inc/MantidIndexing/DllConfig.h
@@ -0,0 +1,37 @@
+#ifndef MANTID_INDEXING_DLLCONFIG_H_
+#define MANTID_INDEXING_DLLCONFIG_H_
+
+/*
+  This file contains the DLLExport/DLLImport linkage configuration for the
+  Indexing library
+
+  Copyright &copy; 2016 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 "MantidKernel/System.h"
+
+#ifdef IN_MANTID_INDEXING
+#define MANTID_INDEXING_DLL DLLExport
+#else
+#define MANTID_INDEXING_DLL DLLImport
+#endif // IN_MANTID_INDEXING
+
+#endif // MANTID_INDEXING_DLLCONFIG_H_
diff --git a/Framework/Indexing/inc/MantidIndexing/Extract.h b/Framework/Indexing/inc/MantidIndexing/Extract.h
new file mode 100644
index 0000000000000000000000000000000000000000..ffb31d730f47dd79d5d1a5898b23463d20cdd289
--- /dev/null
+++ b/Framework/Indexing/inc/MantidIndexing/Extract.h
@@ -0,0 +1,47 @@
+#ifndef MANTID_INDEXING_EXTRACT_H_
+#define MANTID_INDEXING_EXTRACT_H_
+
+#include "MantidIndexing/DllConfig.h"
+
+#include <vector>
+
+namespace Mantid {
+namespace Indexing {
+class IndexInfo;
+
+/** Functions for extracting spectra. A new IndexInfo with the desired spectra
+  is created based on an existing one.
+
+  @author Simon Heybrock
+  @date 2016
+
+  Copyright &copy; 2016 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>
+*/
+MANTID_INDEXING_DLL IndexInfo
+extract(const IndexInfo &source, const std::vector<size_t> &indices);
+MANTID_INDEXING_DLL IndexInfo
+extract(const IndexInfo &source, const size_t minIndex, const size_t maxIndex);
+
+} // namespace Indexing
+} // namespace Mantid
+
+#endif /* MANTID_INDEXING_EXTRACT_H_ */
diff --git a/Framework/Indexing/inc/MantidIndexing/Group.h b/Framework/Indexing/inc/MantidIndexing/Group.h
new file mode 100644
index 0000000000000000000000000000000000000000..1210c7dda63cc2d1cca7f14f3bb87d8a400e890f
--- /dev/null
+++ b/Framework/Indexing/inc/MantidIndexing/Group.h
@@ -0,0 +1,47 @@
+#ifndef MANTID_INDEXING_GROUP_H_
+#define MANTID_INDEXING_GROUP_H_
+
+#include "MantidIndexing/DllConfig.h"
+
+#include <vector>
+
+namespace Mantid {
+using specnum_t = int32_t;
+namespace Indexing {
+class IndexInfo;
+
+/** Functions for grouping spectra. A new IndexInfo with the desired grouping is
+  created based on an existing one.
+
+  @author Simon Heybrock
+  @date 2016
+
+  Copyright &copy; 2016 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>
+*/
+MANTID_INDEXING_DLL IndexInfo
+group(const IndexInfo &source, std::vector<specnum_t> &&specNums,
+      const std::vector<std::vector<size_t>> &grouping);
+
+} // namespace Indexing
+} // namespace Mantid
+
+#endif /* MANTID_INDEXING_GROUP_H_ */
diff --git a/Framework/Indexing/inc/MantidIndexing/IndexInfo.h b/Framework/Indexing/inc/MantidIndexing/IndexInfo.h
new file mode 100644
index 0000000000000000000000000000000000000000..3c0ab78410679edea49b4c3f0c1930213d287b51
--- /dev/null
+++ b/Framework/Indexing/inc/MantidIndexing/IndexInfo.h
@@ -0,0 +1,99 @@
+#ifndef MANTID_INDEXING_INDEXINFO_H_
+#define MANTID_INDEXING_INDEXINFO_H_
+
+#include "MantidIndexing/DllConfig.h"
+#include "MantidKernel/cow_ptr.h"
+
+#include <functional>
+#include <set>
+#include <vector>
+
+namespace Mantid {
+
+using specnum_t = int32_t;
+using detid_t = int32_t;
+
+namespace Indexing {
+
+/** IndexInfo is an object for holding information about spectrum numbers and
+  detector IDs associated to the spectra in a workspace.
+
+  Currently this class supports a legacy "wrapper mode": Spectrum numbers and
+  detector IDs are still stored inside the ISpectrums that are part of a
+  MatrixWorkspace. Ultimately this data will be moved into IndexInfo. For the
+  time being, while the old interface still exists, this cannot be done.
+  Instead, for any IndexInfo object that is part of a MatrixWorkspace, the
+  methods in IndexInfo will provide access to data stored in the associated
+  MatrixWorkspace (or the respective ISpectrum objects). The m_isLegacy flag
+  indicates that an instance of IndexInfo is in such a wrapping state. Taking a
+  copy of IndexInfo will cause a transition from this wrapping legacy state to a
+  stand-alone state without associated MatrixWorkspace.
+
+  @author Simon Heybrock
+  @date 2016
+
+  Copyright &copy; 2016 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>
+*/
+class MANTID_INDEXING_DLL IndexInfo {
+public:
+  explicit IndexInfo(const size_t globalSize);
+  IndexInfo(std::vector<specnum_t> &&spectrumNumbers,
+            std::vector<std::vector<detid_t>> &&detectorIDs);
+  IndexInfo(
+      std::function<size_t()> getSize,
+      std::function<specnum_t(const size_t)> getSpectrumNumber,
+      std::function<const std::set<specnum_t> &(const size_t)> getDetectorIDs);
+
+  IndexInfo(const IndexInfo &other);
+  // Assignment is not needed currently, disabling this for now.
+  IndexInfo &operator=(const IndexInfo &) = delete;
+
+  size_t size() const;
+
+  specnum_t spectrumNumber(const size_t index) const;
+  std::vector<detid_t> detectorIDs(const size_t index) const;
+
+  void setSpectrumNumbers(std::vector<specnum_t> &&spectrumNumbers) & ;
+  void setDetectorIDs(const std::vector<detid_t> &detectorIDs) & ;
+  void setDetectorIDs(std::vector<std::vector<detid_t>> &&detectorIDs) & ;
+
+private:
+  /// True if class is legacy wrapper.
+  bool m_isLegacy{false};
+  /// Function bound to MatrixWorkspace::getNumbersHistograms(), used only in
+  /// legacy mode.
+  std::function<size_t()> m_getSize;
+  /// Function bound to MatrixWorkspace::spectrumNumber(), used only in legacy
+  /// mode.
+  std::function<specnum_t(const size_t)> m_getSpectrumNumber;
+  /// Function bound to MatrixWorkspace::detectorIDs(), used only in legacy
+  /// mode.
+  std::function<const std::set<specnum_t> &(const size_t)> m_getDetectorIDs;
+
+  Kernel::cow_ptr<std::vector<specnum_t>> m_spectrumNumbers;
+  Kernel::cow_ptr<std::vector<std::vector<detid_t>>> m_detectorIDs;
+};
+
+} // namespace Indexing
+} // namespace Mantid
+
+#endif /* MANTID_INDEXING_INDEXINFO_H_ */
diff --git a/Framework/Indexing/inc/MantidIndexing/MakeRange.h b/Framework/Indexing/inc/MantidIndexing/MakeRange.h
new file mode 100644
index 0000000000000000000000000000000000000000..0adeff3a5f7d734a6fd243464fd9ec7acd5a7154
--- /dev/null
+++ b/Framework/Indexing/inc/MantidIndexing/MakeRange.h
@@ -0,0 +1,49 @@
+#ifndef MANTID_INDEXING_MAKERANGE_H_
+#define MANTID_INDEXING_MAKERANGE_H_
+
+#include "MantidIndexing/DllConfig.h"
+
+#include <numeric>
+#include <type_traits>
+
+namespace Mantid {
+namespace Indexing {
+
+/** Helper function for generating a vector with a range of integers, similar to
+  Python's range(). Return a vector of integers starting at 'first' and eding
+  with 'last' with increments of 1.
+
+  Copyright &copy; 2016 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>
+*/
+template <class T1, class T2,
+          class = typename std::enable_if<std::is_integral<T1>::value &&
+                                          std::is_integral<T2>::value>::type>
+std::vector<T2> makeRange(T1 first, T2 last) {
+  std::vector<T2> vec(last - static_cast<T2>(first) + 1);
+  std::iota(vec.begin(), vec.end(), static_cast<T2>(first));
+  return vec;
+}
+
+} // namespace Indexing
+} // namespace Mantid
+
+#endif /* MANTID_INDEXING_MAKERANGE_H_ */
diff --git a/Framework/Indexing/src/Extract.cpp b/Framework/Indexing/src/Extract.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..20529f9ea794ddcde81c91f9d1a3509478f18088
--- /dev/null
+++ b/Framework/Indexing/src/Extract.cpp
@@ -0,0 +1,33 @@
+#include "MantidIndexing/Extract.h"
+#include "MantidIndexing/IndexInfo.h"
+
+namespace Mantid {
+namespace Indexing {
+
+/// Extracts IndexInfo from source IndexInfo, extracting data for all indices
+/// specified by vector.
+IndexInfo extract(const IndexInfo &source, const std::vector<size_t> &indices) {
+  std::vector<specnum_t> specNums;
+  std::vector<std::vector<detid_t>> detIDs;
+  for (const auto &i : indices) {
+    specNums.emplace_back(source.spectrumNumber(i));
+    detIDs.emplace_back(source.detectorIDs(i));
+  }
+  return {std::move(specNums), std::move(detIDs)};
+}
+
+/// Extracts IndexInfo from source IndexInfo, extracting data for all indices
+/// specified by range.
+IndexInfo extract(const IndexInfo &source, const size_t minIndex,
+                  const size_t maxIndex) {
+  std::vector<specnum_t> specNums;
+  std::vector<std::vector<detid_t>> detIDs;
+  for (size_t i = minIndex; i <= maxIndex; ++i) {
+    specNums.emplace_back(source.spectrumNumber(i));
+    detIDs.emplace_back(source.detectorIDs(i));
+  }
+  return {std::move(specNums), std::move(detIDs)};
+}
+
+} // namespace Indexing
+} // namespace Mantid
diff --git a/Framework/Indexing/src/Group.cpp b/Framework/Indexing/src/Group.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1503a1eb49c9dd2b8a2202ccb137c30b051db09a
--- /dev/null
+++ b/Framework/Indexing/src/Group.cpp
@@ -0,0 +1,33 @@
+#include "MantidIndexing/Group.h"
+#include "MantidIndexing/IndexInfo.h"
+
+namespace Mantid {
+namespace Indexing {
+
+/** Return IndexInfo with grouped spectra as specified in the arguments.
+*
+* @param source IndexInfo to use as starting point for grouping.
+* @param specNums Vector of spectrum numbers to use for the ouput IndexInfo.
+* @param grouping Vector for specifying the grouping. The i-th entry in this
+* vector describes the group for the i-th entry in 'specNums'. Each entry is a
+* vector of indices of spectra in 'source' that are to be grouped.
+*/
+IndexInfo group(const IndexInfo &source, std::vector<specnum_t> &&specNums,
+                const std::vector<std::vector<size_t>> &grouping) {
+  if (specNums.size() != grouping.size())
+    throw std::runtime_error("Indexing::group: Size mismatch between spectrum "
+                             "number and grouping vectors");
+  std::vector<std::vector<detid_t>> detIDs;
+  for (const auto &group : grouping) {
+    detIDs.emplace_back(std::vector<detid_t>());
+    for (const auto &i : group) {
+      const auto &IDs = source.detectorIDs(i);
+      auto &newIDs = detIDs.back();
+      newIDs.insert(newIDs.end(), IDs.begin(), IDs.end());
+    }
+  }
+  return {std::move(specNums), std::move(detIDs)};
+}
+
+} // namespace Indexing
+} // namespace Mantid
diff --git a/Framework/Indexing/src/IndexInfo.cpp b/Framework/Indexing/src/IndexInfo.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..23fa66d2104d35f9cfae8585ef51ca9d3e275704
--- /dev/null
+++ b/Framework/Indexing/src/IndexInfo.cpp
@@ -0,0 +1,122 @@
+#include "MantidIndexing/IndexInfo.h"
+#include "MantidKernel/make_cow.h"
+
+#include <algorithm>
+#include <functional>
+#include <numeric>
+
+namespace Mantid {
+namespace Indexing {
+
+/// Construct a default IndexInfo, with contiguous spectrum numbers starting at
+/// 1 and no detector IDs.
+IndexInfo::IndexInfo(const size_t globalSize)
+    : m_spectrumNumbers(Kernel::make_cow<std::vector<specnum_t>>(globalSize)),
+      m_detectorIDs(
+          Kernel::make_cow<std::vector<std::vector<detid_t>>>(globalSize)) {
+  // Default to spectrum numbers 1...globalSize
+  auto &specNums = m_spectrumNumbers.access();
+  std::iota(specNums.begin(), specNums.end(), 1);
+}
+
+/// Construct with given spectrum number and vector of detector IDs for each
+/// index.
+IndexInfo::IndexInfo(std::vector<specnum_t> &&spectrumNumbers,
+                     std::vector<std::vector<detid_t>> &&detectorIDs) {
+  if (spectrumNumbers.size() != detectorIDs.size())
+    throw std::runtime_error("IndexInfo: Size mismatch between spectrum number "
+                             "and detector ID vectors");
+  m_spectrumNumbers.access() = std::move(spectrumNumbers);
+  m_detectorIDs.access() = std::move(detectorIDs);
+}
+
+/// Constructor for internal use by MatrixWorkspace (legacy mode).
+IndexInfo::IndexInfo(
+    std::function<size_t()> getSize,
+    std::function<specnum_t(const size_t)> getSpectrumNumber,
+    std::function<const std::set<specnum_t> &(const size_t)> getDetectorIDs)
+    : m_isLegacy{true}, m_getSize(getSize),
+      m_getSpectrumNumber(getSpectrumNumber), m_getDetectorIDs(getDetectorIDs) {
+}
+
+/// Copy constructor.
+IndexInfo::IndexInfo(const IndexInfo &other) {
+  if (other.m_isLegacy) {
+    // Workaround while IndexInfo is not holding index data stored in
+    // MatrixWorkspace: build IndexInfo based on data in ISpectrum.
+    auto size = other.m_getSize();
+    auto &specNums = m_spectrumNumbers.access();
+    auto &detIDs = m_detectorIDs.access();
+    for (size_t i = 0; i < size; ++i) {
+      specNums.push_back(other.m_getSpectrumNumber(i));
+      const auto &set = other.m_getDetectorIDs(i);
+      detIDs.emplace_back(set.begin(), set.end());
+    }
+  } else {
+    m_spectrumNumbers = other.m_spectrumNumbers;
+    m_detectorIDs = other.m_detectorIDs;
+  }
+}
+
+/// The *local* size, i.e., the number of spectra in this partition.
+size_t IndexInfo::size() const {
+  if (m_isLegacy)
+    return m_getSize();
+  return m_spectrumNumbers->size();
+}
+
+/// Returns the spectrum number for given index.
+specnum_t IndexInfo::spectrumNumber(const size_t index) const {
+  if (m_isLegacy)
+    return m_getSpectrumNumber(index);
+  return (*m_spectrumNumbers)[index];
+}
+
+/// Return a vector of the detector IDs for given index.
+std::vector<detid_t> IndexInfo::detectorIDs(const size_t index) const {
+  if (m_isLegacy) {
+    const auto &ids = m_getDetectorIDs(index);
+    return std::vector<detid_t>(ids.begin(), ids.end());
+  }
+  return (*m_detectorIDs)[index];
+}
+
+/// Set a spectrum number for each index.
+void IndexInfo::setSpectrumNumbers(std::vector<specnum_t> &&spectrumNumbers) & {
+  // No test of m_isLegacy, we cannot have non-const access in that case.
+  if (m_spectrumNumbers->size() != spectrumNumbers.size())
+    throw std::runtime_error(
+        "IndexInfo: Size mismatch when setting new spectrum numbers");
+  m_spectrumNumbers.access() = std::move(spectrumNumbers);
+}
+
+/// Set a single detector ID for each index.
+void IndexInfo::setDetectorIDs(const std::vector<detid_t> &detectorIDs) & {
+  // No test of m_isLegacy, we cannot have non-const access in that case.
+  if (m_detectorIDs->size() != detectorIDs.size())
+    throw std::runtime_error(
+        "IndexInfo: Size mismatch when setting new detector IDs");
+
+  auto &detIDs = m_detectorIDs.access();
+  for (size_t i = 0; i < detectorIDs.size(); ++i)
+    detIDs[i] = {detectorIDs[i]};
+}
+
+/// Set a vector of detector IDs for each index.
+void IndexInfo::setDetectorIDs(
+    // No test of m_isLegacy, we cannot have non-const access in that case.
+    std::vector<std::vector<detid_t>> &&detectorIDs) & {
+  if (m_detectorIDs->size() != detectorIDs.size())
+    throw std::runtime_error(
+        "IndexInfo: Size mismatch when setting new detector IDs");
+
+  auto &detIDs = m_detectorIDs.access();
+  detIDs = std::move(detectorIDs);
+  for (auto &ids : detIDs) {
+    std::sort(ids.begin(), ids.end());
+    ids.erase(std::unique(ids.begin(), ids.end()), ids.end());
+  }
+}
+
+} // namespace Indexing
+} // namespace Mantid
diff --git a/Framework/Indexing/test/CMakeLists.txt b/Framework/Indexing/test/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..9844dbbf908a15f3b396951d949ac21fa9da848f
--- /dev/null
+++ b/Framework/Indexing/test/CMakeLists.txt
@@ -0,0 +1,13 @@
+if ( CXXTEST_FOUND )
+  include_directories ( SYSTEM ${CXXTEST_INCLUDE_DIR} ${GMOCK_INCLUDE_DIR} ${GTEST_INCLUDE_DIR} )
+
+  cxxtest_add_test ( IndexingTest ${TEST_FILES} ${GMOCK_TEST_FILES})
+  target_link_libraries( IndexingTest LINK_PRIVATE ${TCMALLOC_LIBRARIES_LINKTIME}
+    Indexing
+    ${Boost_LIBRARIES}
+    ${GTEST_LIBRARIES} )
+
+  add_dependencies ( FrameworkTests IndexingTest )
+  # Add to the 'FrameworkTests' group in VS
+  set_property ( TARGET IndexingTest PROPERTY FOLDER "UnitTests" )
+endif ()
diff --git a/Framework/Indexing/test/ExtractTest.h b/Framework/Indexing/test/ExtractTest.h
new file mode 100644
index 0000000000000000000000000000000000000000..462157faceb8e62f6cf0fc2178c52241fcf091a5
--- /dev/null
+++ b/Framework/Indexing/test/ExtractTest.h
@@ -0,0 +1,44 @@
+#ifndef MANTID_INDEXING_EXTRACTTEST_H_
+#define MANTID_INDEXING_EXTRACTTEST_H_
+
+#include <cxxtest/TestSuite.h>
+
+#include "MantidIndexing/Extract.h"
+#include "MantidIndexing/IndexInfo.h"
+
+using namespace Mantid;
+using namespace Indexing;
+
+class ExtractTest : public CxxTest::TestSuite {
+public:
+  // This pair of boilerplate methods prevent the suite being created statically
+  // This means the constructor isn't called when running other tests
+  static ExtractTest *createSuite() { return new ExtractTest(); }
+  static void destroySuite(ExtractTest *suite) { delete suite; }
+
+  void test_extract() {
+    IndexInfo source({1, 2, 3}, {{10}, {20}, {30}});
+    std::vector<size_t> indices{{0, 2}};
+    auto result = extract(source, indices);
+    TS_ASSERT_EQUALS(result.size(), 2);
+    TS_ASSERT_EQUALS(result.spectrumNumber(0), 1);
+    TS_ASSERT_EQUALS(result.spectrumNumber(1), 3);
+    TS_ASSERT_EQUALS(result.detectorIDs(0), std::vector<detid_t>{10});
+    TS_ASSERT_EQUALS(result.detectorIDs(1), std::vector<detid_t>{30});
+  }
+
+  void test_reorder() {
+    IndexInfo source({1, 2, 3}, {{10}, {20}, {30}});
+    std::vector<size_t> indices{{2, 1, 0}};
+    auto result = extract(source, indices);
+    TS_ASSERT_EQUALS(result.size(), 3);
+    TS_ASSERT_EQUALS(result.spectrumNumber(0), 3);
+    TS_ASSERT_EQUALS(result.spectrumNumber(1), 2);
+    TS_ASSERT_EQUALS(result.spectrumNumber(2), 1);
+    TS_ASSERT_EQUALS(result.detectorIDs(0), std::vector<detid_t>{30});
+    TS_ASSERT_EQUALS(result.detectorIDs(1), std::vector<detid_t>{20});
+    TS_ASSERT_EQUALS(result.detectorIDs(2), std::vector<detid_t>{10});
+  }
+};
+
+#endif /* MANTID_INDEXING_EXTRACTTEST_H_ */
diff --git a/Framework/Indexing/test/GroupTest.h b/Framework/Indexing/test/GroupTest.h
new file mode 100644
index 0000000000000000000000000000000000000000..5c5c272d96123e493f34031c43237f40232be93e
--- /dev/null
+++ b/Framework/Indexing/test/GroupTest.h
@@ -0,0 +1,75 @@
+#ifndef MANTID_INDEXING_GROUPTEST_H_
+#define MANTID_INDEXING_GROUPTEST_H_
+
+#include <cxxtest/TestSuite.h>
+
+#include "MantidIndexing/Group.h"
+#include "MantidIndexing/IndexInfo.h"
+
+using namespace Mantid;
+using namespace Indexing;
+
+class GroupTest : public CxxTest::TestSuite {
+public:
+  // This pair of boilerplate methods prevent the suite being created statically
+  // This means the constructor isn't called when running other tests
+  static GroupTest *createSuite() { return new GroupTest(); }
+  static void destroySuite(GroupTest *suite) { delete suite; }
+
+  void test_size_mismatch_fail() {
+    IndexInfo source({1, 2, 3}, {{10}, {20}, {30}});
+    std::vector<std::vector<size_t>> grouping{{0}, {1}, {2}};
+    std::vector<specnum_t> specNums{4, 5};
+    TS_ASSERT_THROWS(group(source, std::move(specNums), grouping),
+                     std::runtime_error);
+    TS_ASSERT_EQUALS(specNums.size(), 2);
+  }
+
+  void test_no_grouping() {
+    IndexInfo source({1, 2, 3}, {{10}, {20}, {30}});
+    std::vector<std::vector<size_t>> grouping{{0}, {1}, {2}};
+    auto result = group(source, {4, 5, 6}, grouping);
+    TS_ASSERT_EQUALS(result.size(), 3);
+    TS_ASSERT_EQUALS(result.spectrumNumber(0), 4);
+    TS_ASSERT_EQUALS(result.spectrumNumber(1), 5);
+    TS_ASSERT_EQUALS(result.spectrumNumber(2), 6);
+    TS_ASSERT_EQUALS(result.detectorIDs(0), std::vector<detid_t>{10});
+    TS_ASSERT_EQUALS(result.detectorIDs(1), std::vector<detid_t>{20});
+    TS_ASSERT_EQUALS(result.detectorIDs(2), std::vector<detid_t>{30});
+  }
+
+  void test_swap_ids() {
+    IndexInfo source({1, 2, 3}, {{10}, {20}, {30}});
+    std::vector<std::vector<size_t>> grouping{{1}, {0}, {2}};
+    auto result = group(source, {1, 2, 3}, grouping);
+    TS_ASSERT_EQUALS(result.size(), 3);
+    TS_ASSERT_EQUALS(result.spectrumNumber(0), 1);
+    TS_ASSERT_EQUALS(result.spectrumNumber(1), 2);
+    TS_ASSERT_EQUALS(result.spectrumNumber(2), 3);
+    TS_ASSERT_EQUALS(result.detectorIDs(0), std::vector<detid_t>{20});
+    TS_ASSERT_EQUALS(result.detectorIDs(1), std::vector<detid_t>{10});
+    TS_ASSERT_EQUALS(result.detectorIDs(2), std::vector<detid_t>{30});
+  }
+
+  void test_extract() {
+    IndexInfo source({1, 2, 3}, {{10}, {20}, {30}});
+    std::vector<std::vector<size_t>> grouping{{1}};
+    auto result = group(source, {1}, grouping);
+    TS_ASSERT_EQUALS(result.size(), 1);
+    TS_ASSERT_EQUALS(result.spectrumNumber(0), 1);
+    TS_ASSERT_EQUALS(result.detectorIDs(0), std::vector<detid_t>{20});
+  }
+
+  void test_group() {
+    IndexInfo source({1, 2, 3}, {{10}, {20}, {30}});
+    std::vector<std::vector<size_t>> grouping{{0, 2}, {1}};
+    auto result = group(source, {1, 2}, grouping);
+    TS_ASSERT_EQUALS(result.size(), 2);
+    TS_ASSERT_EQUALS(result.spectrumNumber(0), 1);
+    TS_ASSERT_EQUALS(result.spectrumNumber(1), 2);
+    TS_ASSERT_EQUALS(result.detectorIDs(0), std::vector<detid_t>({10, 30}));
+    TS_ASSERT_EQUALS(result.detectorIDs(1), std::vector<detid_t>{20});
+  }
+};
+
+#endif /* MANTID_INDEXING_GROUPTEST_H_ */
diff --git a/Framework/Indexing/test/IndexInfoTest.h b/Framework/Indexing/test/IndexInfoTest.h
new file mode 100644
index 0000000000000000000000000000000000000000..e0d1e636d0911d7b2639dd70c60513390b6f7a4a
--- /dev/null
+++ b/Framework/Indexing/test/IndexInfoTest.h
@@ -0,0 +1,73 @@
+#ifndef MANTID_INDEXING_INDEXINFOTEST_H_
+#define MANTID_INDEXING_INDEXINFOTEST_H_
+
+#include <cxxtest/TestSuite.h>
+
+#include "MantidIndexing/IndexInfo.h"
+
+using namespace Mantid;
+using namespace Indexing;
+
+class IndexInfoTest : public CxxTest::TestSuite {
+public:
+  // This pair of boilerplate methods prevent the suite being created statically
+  // This means the constructor isn't called when running other tests
+  static IndexInfoTest *createSuite() { return new IndexInfoTest(); }
+  static void destroySuite(IndexInfoTest *suite) { delete suite; }
+
+  void test_size_constructor() { TS_ASSERT_THROWS_NOTHING(IndexInfo(3)); }
+
+  void test_size_constructor_sets_correct_indices() {
+    IndexInfo info(3);
+    TS_ASSERT_EQUALS(info.spectrumNumber(0), 1);
+    TS_ASSERT_EQUALS(info.spectrumNumber(1), 2);
+    TS_ASSERT_EQUALS(info.spectrumNumber(2), 3);
+    TS_ASSERT(info.detectorIDs(0).empty());
+    TS_ASSERT(info.detectorIDs(1).empty());
+    TS_ASSERT(info.detectorIDs(2).empty());
+  }
+
+  void test_vector_constructor() {
+    TS_ASSERT_THROWS_NOTHING(IndexInfo({3, 2, 1}, {{}, {10}, {20, 30}}));
+  }
+
+  void test_vector_constructor_sets_correct_indices() {
+    IndexInfo info({3, 2, 1}, {{}, {10}, {20, 30}});
+    TS_ASSERT_EQUALS(info.spectrumNumber(0), 3);
+    TS_ASSERT_EQUALS(info.spectrumNumber(1), 2);
+    TS_ASSERT_EQUALS(info.spectrumNumber(2), 1);
+    TS_ASSERT_EQUALS(info.detectorIDs(0), (std::vector<detid_t>{}));
+    TS_ASSERT_EQUALS(info.detectorIDs(1), (std::vector<detid_t>{10}));
+    TS_ASSERT_EQUALS(info.detectorIDs(2), (std::vector<detid_t>{20, 30}));
+  }
+
+  void test_size() { TS_ASSERT_EQUALS(IndexInfo(3).size(), 3); }
+
+  void test_setSpectrumNumbers_size_mismatch() {
+    IndexInfo t(3);
+    TS_ASSERT_THROWS(t.setSpectrumNumbers({1, 2}), std::runtime_error);
+  }
+
+  void test_setDetectorIDs_size_mismatch() {
+    IndexInfo t(3);
+    TS_ASSERT_THROWS(t.setDetectorIDs({1, 2}), std::runtime_error);
+  }
+
+  void test_setSpectrumNumbers() {
+    IndexInfo t(3);
+    TS_ASSERT_THROWS_NOTHING(t.setSpectrumNumbers({3, 4, 5}));
+    TS_ASSERT_EQUALS(t.spectrumNumber(0), 3);
+    TS_ASSERT_EQUALS(t.spectrumNumber(1), 4);
+    TS_ASSERT_EQUALS(t.spectrumNumber(2), 5);
+  }
+
+  void test_setDetectorIDs() {
+    IndexInfo t(3);
+    TS_ASSERT_THROWS_NOTHING(t.setDetectorIDs({6, 7, 8}));
+    TS_ASSERT_EQUALS(t.detectorIDs(0), std::vector<detid_t>{6});
+    TS_ASSERT_EQUALS(t.detectorIDs(1), std::vector<detid_t>{7});
+    TS_ASSERT_EQUALS(t.detectorIDs(2), std::vector<detid_t>{8});
+  }
+};
+
+#endif /* MANTID_INDEXING_INDEXINFOTEST_H_ */
diff --git a/Framework/Indexing/test/MakeRangeTest.h b/Framework/Indexing/test/MakeRangeTest.h
new file mode 100644
index 0000000000000000000000000000000000000000..5065f45208419e35b8afc74cfb853147f81a358c
--- /dev/null
+++ b/Framework/Indexing/test/MakeRangeTest.h
@@ -0,0 +1,22 @@
+#ifndef MANTID_INDEXING_MAKERANGETEST_H_
+#define MANTID_INDEXING_MAKERANGETEST_H_
+
+#include <cxxtest/TestSuite.h>
+
+#include "MantidIndexing/MakeRange.h"
+
+using Mantid::Indexing::makeRange;
+
+class MakeRangeTest : public CxxTest::TestSuite {
+public:
+  // This pair of boilerplate methods prevent the suite being created statically
+  // This means the constructor isn't called when running other tests
+  static MakeRangeTest *createSuite() { return new MakeRangeTest(); }
+  static void destroySuite(MakeRangeTest *suite) { delete suite; }
+
+  void test_int() {
+    TS_ASSERT_EQUALS(makeRange(1, 3), (std::vector<int>{1, 2, 3}));
+  }
+};
+
+#endif /* MANTID_INDEXING_MAKERANGETEST_H_ */
diff --git a/Framework/Kernel/CMakeLists.txt b/Framework/Kernel/CMakeLists.txt
index 449ba77b6e3e513bbc061741ba64913da73dd388..7750e384a01a146a9c2c84a5642f17cca5136ddd 100644
--- a/Framework/Kernel/CMakeLists.txt
+++ b/Framework/Kernel/CMakeLists.txt
@@ -2,6 +2,7 @@ set ( SRC_FILES
 	src/ANN_complete.cpp
 	src/ArrayBoundedValidator.cpp
 	src/ArrayLengthValidator.cpp
+  src/ArrayOrderedPairsValidator.cpp
 	src/ArrayProperty.cpp
 	src/Atom.cpp
 	src/BinFinder.cpp
@@ -43,6 +44,7 @@ set ( SRC_FILES
 	src/Interpolation.cpp
 	src/LibraryManager.cpp
 	src/LibraryWrapper.cpp
+	src/LiveListenerInfo.cpp
 	src/LogFilter.cpp
 	src/LogParser.cpp
 	src/Logger.cpp
@@ -71,6 +73,7 @@ set ( SRC_FILES
 	src/NDRandomNumberGenerator.cpp
 	src/NeutronAtom.cpp
 	src/NexusDescriptor.cpp
+	src/NormalDistribution.cpp
 	src/NullValidator.cpp
 	src/OptionalBool.cpp
 	src/ParaViewVersion.cpp
@@ -139,6 +142,7 @@ set ( INC_FILES
 	inc/MantidKernel/ANN/ANNx.h
 	inc/MantidKernel/ArrayBoundedValidator.h
 	inc/MantidKernel/ArrayLengthValidator.h
+  inc/MantidKernel/ArrayOrderedPairsValidator.h
 	inc/MantidKernel/ArrayProperty.h
 	inc/MantidKernel/Atom.h
 	inc/MantidKernel/BinFinder.h
@@ -147,6 +151,7 @@ set ( INC_FILES
 	inc/MantidKernel/BoundedValidator.h
 	inc/MantidKernel/CPUTimer.h
 	inc/MantidKernel/Cache.h
+	inc/MantidKernel/CaseInsensitiveMap.h
 	inc/MantidKernel/CatalogInfo.h
 	inc/MantidKernel/Chainable.h
 	inc/MantidKernel/ChainableFactory.h
@@ -197,6 +202,7 @@ set ( INC_FILES
 	inc/MantidKernel/LibraryManager.h
 	inc/MantidKernel/LibraryWrapper.h
 	inc/MantidKernel/ListValidator.h
+	inc/MantidKernel/LiveListenerInfo.h
 	inc/MantidKernel/LogFilter.h
 	inc/MantidKernel/LogParser.h
 	inc/MantidKernel/Logger.h
@@ -229,6 +235,7 @@ set ( INC_FILES
 	inc/MantidKernel/NetworkProxy.h
 	inc/MantidKernel/NeutronAtom.h
 	inc/MantidKernel/NexusDescriptor.h
+	inc/MantidKernel/NormalDistribution.h
 	inc/MantidKernel/NullValidator.h
 	inc/MantidKernel/OptionalBool.h
 	inc/MantidKernel/ParaViewVersion.h
@@ -237,13 +244,14 @@ set ( INC_FILES
 	inc/MantidKernel/ProgressBase.h
 	inc/MantidKernel/ProgressText.h
 	inc/MantidKernel/Property.h
+	inc/MantidKernel/PropertyHelper.h
 	inc/MantidKernel/PropertyHistory.h
 	inc/MantidKernel/PropertyManager.h
 	inc/MantidKernel/PropertyManagerDataService.h
 	inc/MantidKernel/PropertyManagerOwner.h
 	inc/MantidKernel/PropertyManagerProperty.h
 	inc/MantidKernel/PropertyManager_fwd.h
-    	inc/MantidKernel/PropertyNexus.h
+	inc/MantidKernel/PropertyNexus.h
 	inc/MantidKernel/PropertyWithValue.h
 	inc/MantidKernel/ProxyInfo.h
 	inc/MantidKernel/PseudoRandomNumberGenerator.h
@@ -293,8 +301,7 @@ set ( INC_FILES
 	inc/MantidKernel/WarningSuppressions.h
 	inc/MantidKernel/WriteLock.h
 	inc/MantidKernel/XMLInstantiator.h
-  inc/MantidKernel/CaseInsensitiveMap.h
-  inc/MantidKernel/cow_ptr.h
+	inc/MantidKernel/cow_ptr.h
 	inc/MantidKernel/make_cow.h
 	inc/MantidKernel/make_unique.h
 )
@@ -302,6 +309,7 @@ set ( INC_FILES
 set ( TEST_FILES
 	ArrayBoundedValidatorTest.h
 	ArrayLengthValidatorTest.h
+  ArrayOrderedPairsValidatorTest.h
 	ArrayPropertyTest.h
 	AtomTest.h
 	BinFinderTest.h
@@ -349,6 +357,7 @@ set ( TEST_FILES
 	InternetHelperTest.h
 	InterpolationTest.h
 	ListValidatorTest.h
+	LiveListenerInfoTest.h
 	LogFilterTest.h
 	LogParserTest.h
 	LoggerTest.h
@@ -376,6 +385,7 @@ set ( TEST_FILES
 	NDRandomNumberGeneratorTest.h
 	NeutronAtomTest.h
 	NexusDescriptorTest.h
+	NormalDistributionTest.h
 	NullValidatorTest.h
 	OptionalBoolTest.h
 	ProgressBaseTest.h
diff --git a/Framework/Kernel/inc/MantidKernel/ArrayOrderedPairsValidator.h b/Framework/Kernel/inc/MantidKernel/ArrayOrderedPairsValidator.h
new file mode 100644
index 0000000000000000000000000000000000000000..a21d4ca0330146cb3de1304ead0516165f216e00
--- /dev/null
+++ b/Framework/Kernel/inc/MantidKernel/ArrayOrderedPairsValidator.h
@@ -0,0 +1,51 @@
+#ifndef MANTID_KERNEL_ARRAYORDEREDPAIRSVALIDATOR_H_
+#define MANTID_KERNEL_ARRAYORDEREDPAIRSVALIDATOR_H_
+
+#include "MantidKernel/BoundedValidator.h"
+#include "MantidKernel/TypedValidator.h"
+#include <vector>
+
+namespace Mantid {
+namespace Kernel {
+/** @class ArrayOrderedPairsValidator ArrayOrderedPairsValidator.h
+   Kernel/ArrayOrderedPairsValidator.h
+
+    ArrayOrderedPairsValidator validates that an array contains a sequence of
+    ordered pairs of numbers.
+
+    Copyright &copy; 2007-10 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>
+*/
+template <typename TYPE>
+class MANTID_KERNEL_DLL ArrayOrderedPairsValidator
+    : public TypedValidator<std::vector<TYPE>> {
+public:
+  /// Clone the current state
+  IValidator_sptr clone() const override;
+
+private:
+  std::string checkValidity(const std::vector<TYPE> &value) const override;
+};
+
+} // Kernel
+} // Mantid
+
+#endif /* MANTID_KERNEL_ARRAYORDEREDPAIRSVALIDATOR_H_ */
diff --git a/Framework/Kernel/inc/MantidKernel/ArrayProperty.h b/Framework/Kernel/inc/MantidKernel/ArrayProperty.h
index bccc9de20ad92e5e7f5d1c630b793d89bb1f9770..8783a389bcaf267d037ab9c73f2a4dbd30a02d7e 100644
--- a/Framework/Kernel/inc/MantidKernel/ArrayProperty.h
+++ b/Framework/Kernel/inc/MantidKernel/ArrayProperty.h
@@ -1,9 +1,6 @@
 #ifndef MANTID_KERNEL_ARRAYPROPERTY_H_
 #define MANTID_KERNEL_ARRAYPROPERTY_H_
 
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "PropertyWithValue.h"
 
 namespace Mantid {
@@ -39,94 +36,27 @@ namespace Kernel {
     Code Documentation is available at: <http://doxygen.mantidproject.org>
  */
 template <typename T>
-class DLLExport ArrayProperty : public PropertyWithValue<std::vector<T>> {
+class ArrayProperty : public PropertyWithValue<std::vector<T>> {
 public:
-  /** Constructor
-   *  @param name ::      The name to assign to the property
-   *  @param vec ::       The initial vector of values to assign to the
-   * property.
-   *  @param validator :: The validator to use for this property, if required.
-   *  @param direction :: The direction (Input/Output/InOut) of this property
-   */
   ArrayProperty(const std::string &name, const std::vector<T> &vec,
                 IValidator_sptr validator = IValidator_sptr(new NullValidator),
-                const unsigned int direction = Direction::Input)
-      : PropertyWithValue<std::vector<T>>(name, vec, validator, direction) {}
-
-  /** Constructor
-   *  Will lead to the property having a default-constructed (i.e. empty) vector
-   *  as its initial (default) value
-   *  @param name ::      The name to assign to the property
-   *  @param validator :: The validator to use for this property, if required
-   *  @param direction :: The direction (Input/Output/InOut) of this property
-   */
-
+                const unsigned int direction = Direction::Input);
   ArrayProperty(const std::string &name, IValidator_sptr validator,
-                const unsigned int direction = Direction::Input)
-      : PropertyWithValue<std::vector<T>>(name, std::vector<T>(), validator,
-                                          direction) {}
-
-  /** Constructor that's useful for output properties or inputs with an empty
-   * default and no validator.
-   *  Will lead to the property having a default-constructed (i.e. empty) vector
-   *  as its initial (default) value and no validator
-   *  @param name ::      The name to assign to the property
-   *  @param direction :: The direction (Input/Output/InOut) of this property
-   */
+                const unsigned int direction = Direction::Input);
   ArrayProperty(const std::string &name,
-                const unsigned int direction = Direction::Input)
-      : PropertyWithValue<std::vector<T>>(name, std::vector<T>(),
-                                          IValidator_sptr(new NullValidator),
-                                          direction) {}
-
-  /** Constructor from which you can set the property's values through a string:
-   *
-   * Inherits from the constructor of PropertyWithValue specifically made to
-   * handle a list
-   * of numeric values in a string format so that initial value is set
-   * correctly.
-   *
-   *  @param name ::      The name to assign to the property
-   *  @param values ::    A comma-separated string containing the values to
-   * store in the property
-   *  @param validator :: The validator to use for this property, if required
-   *  @param direction :: The direction (Input/Output/InOut) of this property
-   *  @throw std::invalid_argument if the string passed is not compatible with
-   * the array type
-   */
+                const unsigned int direction = Direction::Input);
   ArrayProperty(const std::string &name, const std::string &values,
                 IValidator_sptr validator = IValidator_sptr(new NullValidator),
-                const unsigned int direction = Direction::Input)
-      : PropertyWithValue<std::vector<T>>(name, std::vector<T>(), values,
-                                          validator, direction) {}
+                const unsigned int direction = Direction::Input);
 
-  /// 'Virtual copy constructor'
-  ArrayProperty<T> *clone() const override {
-    return new ArrayProperty<T>(*this);
-  }
+  ArrayProperty<T> *clone() const override;
 
   // Unhide the base class assignment operator
   using PropertyWithValue<std::vector<T>>::operator=;
 
-  /** Returns the values stored in the ArrayProperty
-   *  @return The stored values as a comma-separated list
-   */
-  std::string value() const override {
-    // Implemented this method for documentation reasons. Just calls base class
-    // method.
-    return PropertyWithValue<std::vector<T>>::value();
-  }
+  std::string value() const override;
 
-  /** Sets the values stored in the ArrayProperty from a string representation
-   *  @param value :: The values to assign to the property, given as a
-   * comma-separated list
-   *  @return True if the assignment was successful
-   */
-  std::string setValue(const std::string &value) override {
-    // Implemented this method for documentation reasons. Just calls base class
-    // method.
-    return PropertyWithValue<std::vector<T>>::setValue(value);
-  }
+  std::string setValue(const std::string &value) override;
   // May want to add specialisation the the class later, e.g. setting just one
   // element of the vector
 };
diff --git a/Framework/Kernel/inc/MantidKernel/DataItem.h b/Framework/Kernel/inc/MantidKernel/DataItem.h
index 0aa0b9c8349e3620f82a22b545d671ea64cdda80..fd02ec7edaab21fee142de507f7bac540e019a6a 100644
--- a/Framework/Kernel/inc/MantidKernel/DataItem.h
+++ b/Framework/Kernel/inc/MantidKernel/DataItem.h
@@ -63,7 +63,7 @@ public:
   /// A string ID for the class
   virtual const std::string id() const = 0;
   /// The name of the object
-  virtual const std::string name() const = 0;
+  virtual const std::string &getName() const = 0;
   /// Can this object be accessed from multiple threads safely
   virtual bool threadSafe() const = 0;
   /// Serializes the object to a string
diff --git a/Framework/Kernel/inc/MantidKernel/DynamicFactory.h b/Framework/Kernel/inc/MantidKernel/DynamicFactory.h
index 7f203ce9057e4aa7c5617fdd50fa85f3214353e0..625381c994f7c054914643084697a22da39653a7 100644
--- a/Framework/Kernel/inc/MantidKernel/DynamicFactory.h
+++ b/Framework/Kernel/inc/MantidKernel/DynamicFactory.h
@@ -18,10 +18,8 @@
 // Poco
 #include <Poco/Notification.h>
 #include <Poco/NotificationCenter.h>
-#include <Poco/AutoPtr.h>
 
 // std
-#include <cstring>
 #include <functional>
 #include <iterator>
 #include <vector>
diff --git a/Framework/Kernel/inc/MantidKernel/EmptyValues.h b/Framework/Kernel/inc/MantidKernel/EmptyValues.h
index 411e660305cd4ab1e3b206ce7b67a47b5a9e4d09..343abf06d4bead86bc774c0ab37d42ce074703ba 100644
--- a/Framework/Kernel/inc/MantidKernel/EmptyValues.h
+++ b/Framework/Kernel/inc/MantidKernel/EmptyValues.h
@@ -37,6 +37,9 @@ DLLExport int EMPTY_INT();
 /// Returns what we consider an "empty" long
 DLLExport long EMPTY_LONG();
 
+/// Returns what we consider an "empty" int64_t
+DLLExport int64_t EMPTY_INT64();
+
 /// Return what we consider to be an empty double
 DLLExport double EMPTY_DBL();
 }
diff --git a/Framework/Kernel/inc/MantidKernel/FacilityInfo.h b/Framework/Kernel/inc/MantidKernel/FacilityInfo.h
index d8c66b9bb9b3e45f272037c1ce8df28ec6aa64cb..c4484eab302d27443c14f4baa10ad9cac7a2f7b3 100644
--- a/Framework/Kernel/inc/MantidKernel/FacilityInfo.h
+++ b/Framework/Kernel/inc/MantidKernel/FacilityInfo.h
@@ -71,8 +71,6 @@ public:
   const std::vector<std::string> &archiveSearch() const {
     return m_archiveSearch;
   }
-  /// Returns the name of the default live listener
-  const std::string &liveListener() const { return m_liveListener; }
   /// Returns a list of instruments of this facility
   const std::vector<InstrumentInfo> &instruments() const {
     return m_instruments;
@@ -104,7 +102,6 @@ private:
   void fillExtensions(const Poco::XML::Element *elem);
   void fillArchiveNames(const Poco::XML::Element *elem);
   void fillInstruments(const Poco::XML::Element *elem);
-  void fillLiveListener(const Poco::XML::Element *elem);
   void fillHTTPProxy(const Poco::XML::Element *elem);
   void fillComputeResources(const Poco::XML::Element *elem);
   void fillNoFilePrefix(const Poco::XML::Element *elem);
@@ -122,8 +119,7 @@ private:
   std::vector<std::string>
       m_archiveSearch; ///< names of the archive search interface
   std::vector<InstrumentInfo>
-      m_instruments;          ///< list of instruments of this facility
-  std::string m_liveListener; ///< name of the default live listener
+      m_instruments;   ///< list of instruments of this facility
   bool m_noFilePrefix; ///< flag indicating if prefix is required in file names
   std::vector<ComputeResourceInfo> m_computeResInfos; ///< (remote) compute
   /// resources available in
diff --git a/Framework/Kernel/inc/MantidKernel/IPropertyManager.h b/Framework/Kernel/inc/MantidKernel/IPropertyManager.h
index 3b5675c897a1f38e4f2bceb87215dcad1fad2b01..93863f6edaed274ad015707febbe36023d9d0c75 100644
--- a/Framework/Kernel/inc/MantidKernel/IPropertyManager.h
+++ b/Framework/Kernel/inc/MantidKernel/IPropertyManager.h
@@ -1,14 +1,17 @@
 #ifndef MANTID_KERNEL_IPROPERTYMANAGER_H_
 #define MANTID_KERNEL_IPROPERTYMANAGER_H_
 
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidKernel/PropertyWithValue.h"
 #include "MantidKernel/OptionalBool.h"
 #include "MantidKernel/make_unique.h"
-#include <vector>
+
+#ifndef Q_MOC_RUN
+#include <boost/make_shared.hpp>
+#include <boost/type_traits.hpp>
+#endif
+
 #include <unordered_set>
+#include <vector>
 
 namespace Json {
 class Value;
@@ -18,12 +21,10 @@ namespace Mantid {
 
 namespace Kernel {
 
-//----------------------------------------------------------------------
-// Forward Declaration
-//----------------------------------------------------------------------
 class Logger;
 class DataItem;
 class DateAndTime;
+class IPropertySettings;
 class PropertyManager;
 template <typename T> class TimeSeriesProperty;
 template <typename T> class Matrix;
@@ -139,8 +140,23 @@ public:
    */
   template <typename T>
   IPropertyManager *setProperty(const std::string &name, const T &value) {
-    setTypedProperty(name, value,
-                     boost::is_convertible<T, boost::shared_ptr<DataItem>>());
+    return doSetProperty(name, value);
+  }
+
+  /** Templated method to set the value of a PropertyWithValue from a
+   * std::unique_ptr
+   *  @param name :: The name of the property (case insensitive)
+   *  @param value :: The value to assign to the property
+   *  @throw Exception::NotFoundError If the named property is unknown
+   *  @throw std::invalid_argument If an attempt is made to assign to a property
+   * of different type
+   */
+  template <typename T>
+  IPropertyManager *setProperty(const std::string &name,
+                                std::unique_ptr<T> value) {
+    setTypedProperty(name, std::move(value),
+                     boost::is_convertible<std::unique_ptr<T>,
+                                           boost::shared_ptr<DataItem>>());
     this->afterPropertySet(name);
     return this;
   }
@@ -179,17 +195,9 @@ public:
   /// Return the property manager serialized as a json object.
   virtual ::Json::Value asJson(bool withDefaultValues = false) const = 0;
 
-  /** Give settings to a property to determine when it gets enabled/hidden.
-   * Passes ownership of the given IPropertySettings object to the named
-   * property
-   * @param name :: property name
-   * @param settings :: IPropertySettings     */
   void setPropertySettings(const std::string &name,
-                           std::unique_ptr<IPropertySettings> settings) {
-    Property *prop = getPointerToProperty(name);
-    if (prop)
-      prop->setSettings(std::move(settings));
-  }
+                           std::unique_ptr<IPropertySettings> settings);
+
   /** Set the group for a given property
    * @param name :: property name
    * @param group :: Name of the group it belongs to     */
@@ -288,11 +296,12 @@ protected:
   */
   void declareProperty(
       const std::string &name, const char *value,
-      IValidator_sptr validator = IValidator_sptr(new NullValidator),
-      const std::string &doc = "",
+      IValidator_sptr validator = boost::make_shared<NullValidator>(),
+      const std::string &doc = std::string(),
       const unsigned int direction = Direction::Input) {
     // Simply call templated method, converting character array to a string
-    declareProperty(name, std::string(value), validator, doc, direction);
+    declareProperty(name, std::string(value), std::move(validator), doc,
+                    direction);
   }
 
   /** Specialised version of declareProperty template method to prevent the
@@ -314,10 +323,11 @@ protected:
   */
   void declareProperty(
       const std::string &name, const char *value, const std::string &doc,
-      IValidator_sptr validator = IValidator_sptr(new NullValidator),
+      IValidator_sptr validator = boost::make_shared<NullValidator>(),
       const unsigned int direction = Direction::Input) {
     // Simply call templated method, converting character array to a string
-    declareProperty(name, std::string(value), validator, doc, direction);
+    declareProperty(name, std::string(value), std::move(validator), doc,
+                    direction);
   }
 
   /** Add a property of string type to the list of managed properties
@@ -426,6 +436,45 @@ public:
   virtual Property *getPointerToProperty(const std::string &name) const = 0;
 
 private:
+  /** Helper method to set the value of a PropertyWithValue
+   *  @param name :: The name of the property (case insensitive)
+   *  @param value :: The value to assign to the property
+   *  @throw Exception::NotFoundError If the named property is unknown
+   *  @throw std::invalid_argument If an attempt is made to assign to a property
+   * of different type
+   */
+  template <typename T>
+  IPropertyManager *doSetProperty(const std::string &name, const T &value) {
+    setTypedProperty(name, value,
+                     boost::is_convertible<T, boost::shared_ptr<DataItem>>());
+    this->afterPropertySet(name);
+    return this;
+  }
+
+  /** Helper method to set the value of a PropertyWithValue, variant for
+   * shared_ptr types. This variant is required to enforce checks for complete
+   * types, do not remove it.
+   *  @param name :: The name of the property (case insensitive)
+   *  @param value :: The value to assign to the property
+   *  @throw Exception::NotFoundError If the named property is unknown
+   *  @throw std::invalid_argument If an attempt is made to assign to a property
+   * of different type
+   */
+  template <typename T>
+  IPropertyManager *doSetProperty(const std::string &name,
+                                  const boost::shared_ptr<T> &value) {
+    // CAREFUL: is_convertible has undefined behavior for incomplete types. If T
+    // is forward-declared in the calling code, e.g., an algorithm that calls
+    // setProperty, compilation and linking do work. However, the BEHAVIOR IS
+    // UNDEFINED and the compiler will not complain, but things crash or go
+    // wrong badly. To circumvent this we call `sizeof` here to force a compiler
+    // error if T is an incomplete type.
+    static_cast<void>(sizeof(T)); // DO NOT REMOVE, enforces complete type
+    setTypedProperty(name, value, boost::is_convertible<T *, DataItem *>());
+    this->afterPropertySet(name);
+    return this;
+  }
+
   /**
    * Set a property value that is not convertible to a DataItem_sptr
    *  @param name :: The name of the property (case insensitive)
@@ -467,6 +516,28 @@ private:
     }
     return this;
   }
+
+  /**
+   * Set a property value from std::unique_ptr that is convertible to a
+   * DataItem_sptr
+   *  @param name :: The name of the property (case insensitive)
+   *  @param value :: The value to assign to the property
+   *  @throw Exception::NotFoundError If the named property is unknown
+   *  @throw std::invalid_argument If an attempt is made to assign to a property
+   * of different type
+   */
+  template <typename T>
+  IPropertyManager *setTypedProperty(const std::string &name,
+                                     std::unique_ptr<T> value,
+                                     const boost::true_type &) {
+    // T is convertible to DataItem_sptr
+    boost::shared_ptr<DataItem> data(std::move(value));
+    std::string error = getPointerToProperty(name)->setDataItem(data);
+    if (!error.empty()) {
+      throw std::invalid_argument(error);
+    }
+    return this;
+  }
 };
 
 } // namespace Kernel
diff --git a/Framework/Kernel/inc/MantidKernel/InstrumentInfo.h b/Framework/Kernel/inc/MantidKernel/InstrumentInfo.h
index d42957f6d9d05a258fe7345bdd50534a9ad33926..85dc0b5de58cf210a3559df30da1dddf9fb52cbe 100644
--- a/Framework/Kernel/inc/MantidKernel/InstrumentInfo.h
+++ b/Framework/Kernel/inc/MantidKernel/InstrumentInfo.h
@@ -5,9 +5,12 @@
 // Includes
 //----------------------------------------------------------------------
 #include "MantidKernel/DllConfig.h"
+#include "MantidKernel/LiveListenerInfo.h"
+
 #include <set>
 #include <string>
 #include <map>
+#include <vector>
 
 //----------------------------------------------------------------------
 // Forward declarations
@@ -64,16 +67,22 @@ public:
   std::string filePrefix(unsigned int runNumber) const;
   /// Returns the default delimiter between instrument name and run number
   std::string delimiter() const;
-  /// Returns the name of the live listener
-  const std::string &liveListener() const;
-  /// Returns an object representing the host & port to connect to for a live
-  /// data stream
-  const std::string &liveDataAddress() const;
   /// Return list of techniques
   const std::set<std::string> &techniques() const;
   /// The facility to which this instrument belongs
   const FacilityInfo &facility() const;
 
+  /// Returns the name of the default live listener
+  std::string liveListener(const std::string &name = "") const;
+  /// Returns a string containing the "host:port" for default live listener
+  std::string liveDataAddress(const std::string &name = "") const;
+  /// Returns LiveListenerInfo for specified connection name (or default)
+  const LiveListenerInfo &liveListenerInfo(std::string name = "") const;
+  /// Returns true if this instrument has at least one live listener defined
+  bool hasLiveListenerInfo() const;
+  /// Returns all available LiveListenerInfos as a vector
+  const std::vector<LiveListenerInfo> &liveListenerInfoList() const;
+
 private:
   void fillTechniques(const Poco::XML::Element *elem);
   void fillLiveData(const Poco::XML::Element *elem);
@@ -96,10 +105,11 @@ private:
   std::string m_shortName;        ///< Instrument short name
   ZeroPaddingMap m_zeroPadding;   ///< Run number-dependent zero padding
   std::string m_delimiter; ///< Delimiter between instrument name and run number
-  std::string m_liveListener;    ///< Name of the live listener class
-  std::string m_liveDataAddress; ///< Host & port for live data connection
   std::set<std::string>
       m_technique; ///< List of techniques the instrument can do
+
+  std::vector<LiveListenerInfo> m_listeners; ///< LiveListener connections
+  std::string m_defaultListener; ///< Default LiveListener connection to use
 };
 
 /// Allow this object to be printed to a stream
diff --git a/Framework/Kernel/inc/MantidKernel/LiveListenerInfo.h b/Framework/Kernel/inc/MantidKernel/LiveListenerInfo.h
new file mode 100644
index 0000000000000000000000000000000000000000..5d126e231b2f38207ef18925d4f8589dabccb717
--- /dev/null
+++ b/Framework/Kernel/inc/MantidKernel/LiveListenerInfo.h
@@ -0,0 +1,82 @@
+#ifndef MANTID_KERNEL_LIVELISTENERINFO_H_
+#define MANTID_KERNEL_LIVELISTENERINFO_H_
+
+//----------------------------------------------------------------------
+// Includes
+//----------------------------------------------------------------------
+#include "MantidKernel/DllConfig.h"
+#include <string>
+
+//----------------------------------------------------------------------
+// Forward declarations
+//----------------------------------------------------------------------
+namespace Poco {
+namespace XML {
+class Element;
+}
+}
+
+namespace Mantid {
+namespace Kernel {
+
+//----------------------------------------------------------------------
+// Forward declarations
+//----------------------------------------------------------------------
+class InstrumentInfo;
+
+/**
+ * A class that holds information about a LiveListener connection.
+ *
+ * Copyright &copy; 2016 STFC Rutherford Appleton Laboratory
+ *
+ * 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>
+ */
+class MANTID_KERNEL_DLL LiveListenerInfo {
+public:
+  LiveListenerInfo(InstrumentInfo *inst, const Poco::XML::Element *elem);
+  LiveListenerInfo(const std::string &listener = "",
+                   const std::string &address = "",
+                   const std::string &name = "");
+
+  /// Required for Python bindings
+  bool operator==(const LiveListenerInfo &rhs) const;
+
+  /// Return the name of this LiveListener connection
+  const std::string &name() const;
+
+  /// Returns the address string of this LiveListener connection
+  const std::string &address() const;
+
+  /// Returns the classname of the specific LiveListener to use
+  const std::string &listener() const;
+
+private:
+  std::string m_name;     ///< Listener name
+  std::string m_address;  ///< Listener address
+  std::string m_listener; ///< Listener classname
+};
+
+/// Allow this object to be printed to a stream
+MANTID_KERNEL_DLL std::ostream &operator<<(std::ostream &buffer,
+                                           const LiveListenerInfo &listener);
+
+} // namespace Kernel
+} // namespace Mantid
+
+#endif /* MANTID_KERNEL_LIVELISTENERINFO_H_ */
diff --git a/Framework/Kernel/inc/MantidKernel/MaskedProperty.h b/Framework/Kernel/inc/MantidKernel/MaskedProperty.h
index 79c15d52e0934dc70c7a252c01a85350a711c390..7c5a8db855dbc4b5b4105c574b3e826174cfed69 100644
--- a/Framework/Kernel/inc/MantidKernel/MaskedProperty.h
+++ b/Framework/Kernel/inc/MantidKernel/MaskedProperty.h
@@ -41,8 +41,7 @@
 namespace Mantid {
 namespace Kernel {
 template <typename TYPE = std::string>
-class MANTID_KERNEL_DLL MaskedProperty
-    : public Kernel::PropertyWithValue<TYPE> {
+class MaskedProperty : public Kernel::PropertyWithValue<TYPE> {
 public:
   /// Constructor with a validator
   MaskedProperty(const std::string &name, TYPE defaultvalue,
diff --git a/Framework/Kernel/inc/MantidKernel/Matrix.h b/Framework/Kernel/inc/MantidKernel/Matrix.h
index 17d763e0c241ae321ce2065de994f809d21cd222..f5625946f5a5834614b94155c7913fb510f33ac2 100644
--- a/Framework/Kernel/inc/MantidKernel/Matrix.h
+++ b/Framework/Kernel/inc/MantidKernel/Matrix.h
@@ -4,7 +4,7 @@
 #include "MantidKernel/DllConfig.h"
 #include <vector>
 #include <cfloat>
-#include <ostream>
+#include <iosfwd>
 
 namespace Mantid {
 
diff --git a/Framework/Kernel/inc/MantidKernel/MatrixProperty.h b/Framework/Kernel/inc/MantidKernel/MatrixProperty.h
index 3dc44a7a1e27143edb21fad46f49fd177861a6ff..2d0a49f831f116645fadf73c29ecf832a4a6a6dc 100644
--- a/Framework/Kernel/inc/MantidKernel/MatrixProperty.h
+++ b/Framework/Kernel/inc/MantidKernel/MatrixProperty.h
@@ -33,7 +33,7 @@ File change history is stored at: <https://github.com/mantidproject/mantid>.
 Code Documentation is available at: <http://doxygen.mantidproject.org>
 */
 template <class TYPE = double>
-class DLLExport MatrixProperty : public PropertyWithValue<Matrix<TYPE>> {
+class MatrixProperty : public PropertyWithValue<Matrix<TYPE>> {
   /// Typedef the held type
   typedef Kernel::Matrix<TYPE> HeldType;
 
diff --git a/Framework/Kernel/inc/MantidKernel/MersenneTwister.h b/Framework/Kernel/inc/MantidKernel/MersenneTwister.h
index 87f097381c5d8c9112d1f641ee11b9105eac7483..beebed2387f115ada4cd4e66a99f5bd149f2df8e 100644
--- a/Framework/Kernel/inc/MantidKernel/MersenneTwister.h
+++ b/Framework/Kernel/inc/MantidKernel/MersenneTwister.h
@@ -50,6 +50,10 @@ class MANTID_KERNEL_DLL MersenneTwister final
     : public PseudoRandomNumberGenerator {
 
 public:
+  /// Construct the generator using time stamp for the initial seed.
+  MersenneTwister();
+  /// Construct the generator with an initial range and default seed.
+  MersenneTwister(const double start, const double end);
   /// Construct the generator with an initial seed. It can be reseeded using
   /// setSeed.
   explicit MersenneTwister(const size_t seedValue);
@@ -79,6 +83,10 @@ public:
   /// Restores the generator to the last saved point, or the beginning if
   /// nothing has been saved
   void restore() override;
+  /// Return the minimum value of the range
+  double min() const override { return m_start; }
+  /// Return the maximum value of the range
+  double max() const override { return m_end; }
 
 private:
   /// The boost Mersenne Twister generator
@@ -90,8 +98,7 @@ private:
   /// The current seed
   boost::mt19937::result_type m_currentSeed;
   /// A generator that will take the value when save is requested. Pointer so
-  /// that
-  /// it is only instantiated when required
+  /// that it is only instantiated when required
   boost::mt19937 *m_savedStateGenerator;
 };
 }
diff --git a/Framework/Kernel/inc/MantidKernel/NormalDistribution.h b/Framework/Kernel/inc/MantidKernel/NormalDistribution.h
new file mode 100644
index 0000000000000000000000000000000000000000..68a64e707e73d95f8124439902a59f97df79a85d
--- /dev/null
+++ b/Framework/Kernel/inc/MantidKernel/NormalDistribution.h
@@ -0,0 +1,78 @@
+#ifndef MANTID_KERNEL_NORMAL_DISTRIBUTION_H_
+#define MANTID_KERNEL_NORMAL_DISTRIBUTION_H_
+
+//------------------------------------------------------------------------------
+// Includes
+//------------------------------------------------------------------------------
+#include "MantidKernel/DllConfig.h"
+#include "MantidKernel/MersenneTwister.h"
+
+#include <boost/random/normal_distribution.hpp>
+
+namespace Mantid {
+namespace Kernel {
+
+/**
+  This implements a generator of normally distributed pseudo-random numbers.
+
+  Copyright &copy; 2010 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>
+*/
+class MANTID_KERNEL_DLL NormalDistribution {
+
+public:
+  /// Construct the generator using time stamp for the initial seed.
+  NormalDistribution();
+  /// Construct the generator with initial distribution parameters
+  /// and default seed.
+  NormalDistribution(const double mean, const double sigma);
+  /// Construct the generator with initial distribution parameters and
+  /// a seed value.
+  NormalDistribution(const size_t seedValue, const double mean,
+                     const double sigma);
+
+  NormalDistribution(const NormalDistribution &) = delete;
+  NormalDistribution &operator=(const NormalDistribution &) = delete;
+
+  /// Set the random number seed
+  void setSeed(const size_t seedValue);
+  /// Generate the next random number in the sequence
+  double nextValue();
+  /// Get the mean of the distribution
+  double mean() const { return m_generator.mean(); }
+  /// Get the sigma of the distribution
+  double sigma() const { return m_generator.sigma(); }
+  /// Generate a random number from a distribution with given mean and sigma
+  double randomValue(double argMean, double argSigma);
+
+private:
+  /// The boost Mersenne Twister generator
+  /// (In the future when we have other uniform generators this can be a ref
+  /// to a PseudoRandomNumberGenerator base class and the user can initialize it
+  /// with an implementation of choise)
+  MersenneTwister m_uniform_generator;
+  /// The boost normal distribution generator
+  boost::normal_distribution<double> m_generator;
+};
+}
+}
+
+#endif // MANTID_KERNEL_NORMAL_DISTRIBUTION_H_
diff --git a/Framework/Kernel/inc/MantidKernel/PropertyHelper.h b/Framework/Kernel/inc/MantidKernel/PropertyHelper.h
new file mode 100644
index 0000000000000000000000000000000000000000..397b88b1de7fa3ff9b12e7c8bfaa3079641ef058
--- /dev/null
+++ b/Framework/Kernel/inc/MantidKernel/PropertyHelper.h
@@ -0,0 +1,252 @@
+#ifndef MANTID_KERNEL_PROPERTYHELPER_H_
+#define MANTID_KERNEL_PROPERTYHELPER_H_
+
+#ifndef Q_MOC_RUN
+#include <boost/lexical_cast.hpp>
+#include <boost/make_shared.hpp>
+#endif
+
+#include "MantidKernel/OptionalBool.h"
+#include "MantidKernel/StringTokenizer.h"
+
+namespace Mantid {
+namespace Kernel {
+
+// --------------------- convert values to strings
+namespace {
+/// Convert values to strings.
+template <typename T> std::string toString(const T &value) {
+  return boost::lexical_cast<std::string>(value);
+}
+
+/// Throw an exception if a shared pointer is converted to a string.
+template <typename T> std::string toString(const boost::shared_ptr<T> &value) {
+  UNUSED_ARG(value);
+  throw boost::bad_lexical_cast();
+}
+
+/// Specialisation for a property of type std::vector.
+template <typename T>
+std::string toString(const std::vector<T> &value,
+                     const std::string &delimiter = ",") {
+  std::stringstream result;
+  std::size_t vsize = value.size();
+  for (std::size_t i = 0; i < vsize; ++i) {
+    result << value[i];
+    if (i + 1 != vsize)
+      result << delimiter;
+  }
+  return result.str();
+}
+
+/// Specialisation for a property of type std::vector<std::vector>.
+template <typename T>
+std::string toString(const std::vector<std::vector<T>> &value,
+                     const std::string &outerDelimiter = ",",
+                     const std::string &innerDelimiter = "+") {
+  std::stringstream result;
+  std::size_t vsize = value.size();
+  for (std::size_t i = 0; i < vsize; ++i) {
+    std::size_t innervsize = value[i].size();
+    for (std::size_t j = 0; j < innervsize; ++j) {
+      result << value[i][j];
+      if (j + 1 != innervsize)
+        result << innerDelimiter;
+    }
+
+    if (i + 1 != vsize)
+      result << outerDelimiter;
+  }
+  return result.str();
+}
+
+/// Specialisation for any type, should be appropriate for properties with a
+/// single value.
+template <typename T> int findSize(const T &) { return 1; }
+
+/// Specialisation for properties that are of type vector.
+template <typename T> int findSize(const std::vector<T> &value) {
+  return static_cast<int>(value.size());
+}
+
+// ------------- Convert strings to values
+template <typename T>
+inline void appendValue(const std::string &strvalue, std::vector<T> &value) {
+  // try to split the string
+  std::size_t pos = strvalue.find(':');
+  if (pos == std::string::npos) {
+    pos = strvalue.find('-', 1);
+  }
+
+  // just convert the whole thing into a value
+  if (pos == std::string::npos) {
+    value.push_back(boost::lexical_cast<T>(strvalue));
+    return;
+  }
+
+  // convert the input string into boundaries and run through a list
+  T start = boost::lexical_cast<T>(strvalue.substr(0, pos));
+  T stop = boost::lexical_cast<T>(strvalue.substr(pos + 1));
+  for (T i = start; i <= stop; i++)
+    value.push_back(i);
+}
+
+template <typename T> void toValue(const std::string &strvalue, T &value) {
+  value = boost::lexical_cast<T>(strvalue);
+}
+
+template <typename T>
+void toValue(const std::string &, boost::shared_ptr<T> &) {
+  throw boost::bad_lexical_cast();
+}
+
+namespace detail {
+// vector<int> specializations
+template <typename T>
+void toValue(const std::string &strvalue, std::vector<T> &value,
+             std::true_type) {
+  typedef Mantid::Kernel::StringTokenizer tokenizer;
+  tokenizer values(strvalue, ",",
+                   tokenizer::TOK_IGNORE_EMPTY | tokenizer::TOK_TRIM);
+  value.clear();
+  value.reserve(values.count());
+  for (const auto &token : values) {
+    appendValue(token, value);
+  }
+}
+
+template <typename T>
+void toValue(const std::string &strvalue, std::vector<T> &value,
+             std::false_type) {
+  // Split up comma-separated properties
+  typedef Mantid::Kernel::StringTokenizer tokenizer;
+  tokenizer values(strvalue, ",",
+                   tokenizer::TOK_IGNORE_EMPTY | tokenizer::TOK_TRIM);
+
+  value.clear();
+  value.reserve(values.count());
+  std::transform(
+      values.cbegin(), values.cend(), std::back_inserter(value),
+      [](const std::string &str) { return boost::lexical_cast<T>(str); });
+}
+
+// bool and char don't make sense as types to generate a range of values.
+// This is similar to std::is_integral<T>, but bool and char are std::false_type
+template <class T> struct is_range_type : public std::false_type {};
+template <class T> struct is_range_type<const T> : public is_range_type<T> {};
+template <class T>
+struct is_range_type<volatile const T> : public is_range_type<T> {};
+template <class T>
+struct is_range_type<volatile T> : public is_range_type<T> {};
+
+template <> struct is_range_type<unsigned short> : public std::true_type {};
+template <> struct is_range_type<unsigned int> : public std::true_type {};
+template <> struct is_range_type<unsigned long> : public std::true_type {};
+template <> struct is_range_type<unsigned long long> : public std::true_type {};
+
+template <> struct is_range_type<short> : public std::true_type {};
+template <> struct is_range_type<int> : public std::true_type {};
+template <> struct is_range_type<long> : public std::true_type {};
+template <> struct is_range_type<long long> : public std::true_type {};
+}
+template <typename T>
+void toValue(const std::string &strvalue, std::vector<T> &value) {
+  detail::toValue(strvalue, value, detail::is_range_type<T>());
+}
+
+template <typename T>
+void toValue(const std::string &strvalue, std::vector<std::vector<T>> &value,
+             const std::string &outerDelimiter = ",",
+             const std::string &innerDelimiter = "+") {
+  typedef Mantid::Kernel::StringTokenizer tokenizer;
+  tokenizer tokens(strvalue, outerDelimiter,
+                   tokenizer::TOK_IGNORE_EMPTY | tokenizer::TOK_TRIM);
+
+  value.clear();
+  value.reserve(tokens.count());
+
+  for (const auto &token : tokens) {
+    tokenizer values(token, innerDelimiter,
+                     tokenizer::TOK_IGNORE_EMPTY | tokenizer::TOK_TRIM);
+    std::vector<T> vect;
+    vect.reserve(values.count());
+    std::transform(
+        values.begin(), values.end(), std::back_inserter(vect),
+        [](const std::string &str) { return boost::lexical_cast<T>(str); });
+    value.push_back(std::move(vect));
+  }
+}
+
+/*Used specifically to retrieve a vector of type T populated with values
+ * given to it from strvalue parameter, Using toValue method.
+ (See constructor used specifically for vector assignments)
+ */
+template <typename T> T extractToValueVector(const std::string &strvalue) {
+  T valueVec;
+  toValue(strvalue, valueVec);
+  return valueVec;
+}
+
+//------------------------------------------------------------------------------------------------
+// Templated += operator functions for specific types
+template <typename T> inline void addingOperator(T &lhs, const T &rhs) {
+  // The cast here (and the expansion of the compound operator which that
+  // necessitates) is because if this function is created for a template
+  // type narrower than an int, the compiler will expande the operands to
+  // ints which leads to a compiler warning when it's assigned back to the
+  // narrower type.
+  lhs = static_cast<T>(lhs + rhs);
+}
+
+template <typename T>
+inline void addingOperator(std::vector<T> &lhs, const std::vector<T> &rhs) {
+  // This concatenates the two
+  if (&lhs != &rhs) {
+    lhs.insert(lhs.end(), rhs.begin(), rhs.end());
+  } else {
+    std::vector<T> rhs_copy(rhs);
+    lhs.insert(lhs.end(), rhs_copy.begin(), rhs_copy.end());
+  }
+}
+
+template <> inline void addingOperator(bool &, const bool &) {
+  throw Exception::NotImplementedError(
+      "PropertyWithValue.h: += operator not implemented for type bool");
+}
+
+template <> inline void addingOperator(OptionalBool &, const OptionalBool &) {
+  throw Exception::NotImplementedError(
+      "PropertyWithValue.h: += operator not implemented for type OptionalBool");
+}
+
+template <typename T>
+inline void addingOperator(boost::shared_ptr<T> &,
+                           const boost::shared_ptr<T> &) {
+  throw Exception::NotImplementedError(
+      "PropertyWithValue.h: += operator not implemented for boost::shared_ptr");
+}
+
+template <typename T>
+inline std::vector<std::string>
+determineAllowedValues(const T &, const IValidator &validator) {
+  return validator.allowedValues();
+}
+
+template <>
+inline std::vector<std::string> determineAllowedValues(const OptionalBool &,
+                                                       const IValidator &) {
+  auto enumMap = OptionalBool::enumToStrMap();
+  std::vector<std::string> values;
+  values.reserve(enumMap.size());
+  std::transform(enumMap.cbegin(), enumMap.cend(), std::back_inserter(values),
+                 [](const std::pair<OptionalBool::Value, std::string> &str) {
+                   return str.second;
+                 });
+  return values;
+}
+}
+
+} // namespace Kernel
+} // namespace Mantid
+
+#endif /* MANTID_KERNEL_PROPERTYHELPER_H_ */
diff --git a/Framework/Kernel/inc/MantidKernel/PropertyWithValue.h b/Framework/Kernel/inc/MantidKernel/PropertyWithValue.h
index c04d643af4d5a456940e4c8a47f5c26964f80517..fab07ec92ba664e38a31bc222f3840224538ebe4 100644
--- a/Framework/Kernel/inc/MantidKernel/PropertyWithValue.h
+++ b/Framework/Kernel/inc/MantidKernel/PropertyWithValue.h
@@ -5,21 +5,13 @@
 #include "MantidKernel/Exception.h"
 #include "MantidKernel/Logger.h"
 #include "MantidKernel/NullValidator.h"
-#include "MantidKernel/OptionalBool.h"
 
-#ifndef Q_MOC_RUN
-#include <boost/lexical_cast.hpp>
-#include <boost/make_shared.hpp>
-#include <boost/algorithm/string/trim.hpp>
-#endif
-
-#include <nexus/NeXusFile.hpp>
-
-#include "MantidKernel/IPropertySettings.h"
-#include <MantidKernel/StringTokenizer.h>
-#include <type_traits>
 #include <vector>
 
+namespace NeXus {
+class File;
+}
+
 namespace Mantid {
 
 namespace Kernel {
@@ -58,507 +50,38 @@ namespace Kernel {
     File change history is stored at: <https://github.com/mantidproject/mantid>.
     Code Documentation is available at: <http://doxygen.mantidproject.org>
 */
-
-// --------------------- convert values to strings
-namespace {
-/// Convert values to strings.
-template <typename T> std::string toString(const T &value) {
-  return boost::lexical_cast<std::string>(value);
-}
-
-/// Throw an exception if a shared pointer is converted to a string.
-template <typename T> std::string toString(const boost::shared_ptr<T> &value) {
-  UNUSED_ARG(value);
-  throw boost::bad_lexical_cast();
-}
-
-/// Specialisation for a property of type std::vector.
-template <typename T>
-std::string toString(const std::vector<T> &value,
-                     const std::string &delimiter = ",") {
-  std::stringstream result;
-  std::size_t vsize = value.size();
-  for (std::size_t i = 0; i < vsize; ++i) {
-    result << value[i];
-    if (i + 1 != vsize)
-      result << delimiter;
-  }
-  return result.str();
-}
-
-/// Specialisation for a property of type std::vector<std::vector>.
-template <typename T>
-std::string toString(const std::vector<std::vector<T>> &value,
-                     const std::string &outerDelimiter = ",",
-                     const std::string &innerDelimiter = "+") {
-  std::stringstream result;
-  std::size_t vsize = value.size();
-  for (std::size_t i = 0; i < vsize; ++i) {
-    std::size_t innervsize = value[i].size();
-    for (std::size_t j = 0; j < innervsize; ++j) {
-      result << value[i][j];
-      if (j + 1 != innervsize)
-        result << innerDelimiter;
-    }
-
-    if (i + 1 != vsize)
-      result << outerDelimiter;
-  }
-  return result.str();
-}
-
-/// Specialisation for any type, should be appropriate for properties with a
-/// single value.
-template <typename T> int findSize(const T &) { return 1; }
-
-/// Specialisation for properties that are of type vector.
-template <typename T> int findSize(const std::vector<T> &value) {
-  return static_cast<int>(value.size());
-}
-
-// ------------- Convert strings to values
-template <typename T>
-inline void appendValue(const std::string &strvalue, std::vector<T> &value) {
-  // try to split the string
-  std::size_t pos = strvalue.find(':');
-  if (pos == std::string::npos) {
-    pos = strvalue.find('-', 1);
-  }
-
-  // just convert the whole thing into a value
-  if (pos == std::string::npos) {
-    value.push_back(boost::lexical_cast<T>(strvalue));
-    return;
-  }
-
-  // convert the input string into boundaries and run through a list
-  T start = boost::lexical_cast<T>(strvalue.substr(0, pos));
-  T stop = boost::lexical_cast<T>(strvalue.substr(pos + 1));
-  for (T i = start; i <= stop; i++)
-    value.push_back(i);
-}
-
-template <typename T> void toValue(const std::string &strvalue, T &value) {
-  value = boost::lexical_cast<T>(strvalue);
-}
-
-template <typename T>
-void toValue(const std::string &, boost::shared_ptr<T> &) {
-  throw boost::bad_lexical_cast();
-}
-
-namespace detail {
-// vector<int> specializations
-template <typename T>
-void toValue(const std::string &strvalue, std::vector<T> &value,
-             std::true_type) {
-  typedef Mantid::Kernel::StringTokenizer tokenizer;
-  tokenizer values(strvalue, ",",
-                   tokenizer::TOK_IGNORE_EMPTY | tokenizer::TOK_TRIM);
-  value.clear();
-  value.reserve(values.count());
-  for (const auto &token : values) {
-    appendValue(token, value);
-  }
-}
-
-template <typename T>
-void toValue(const std::string &strvalue, std::vector<T> &value,
-             std::false_type) {
-  // Split up comma-separated properties
-  typedef Mantid::Kernel::StringTokenizer tokenizer;
-  tokenizer values(strvalue, ",",
-                   tokenizer::TOK_IGNORE_EMPTY | tokenizer::TOK_TRIM);
-
-  value.clear();
-  value.reserve(values.count());
-  std::transform(
-      values.cbegin(), values.cend(), std::back_inserter(value),
-      [](const std::string &str) { return boost::lexical_cast<T>(str); });
-}
-
-// bool and char don't make sense as types to generate a range of values.
-// This is similar to std::is_integral<T>, but bool and char are std::false_type
-template <class T> struct is_range_type : public std::false_type {};
-template <class T> struct is_range_type<const T> : public is_range_type<T> {};
-template <class T>
-struct is_range_type<volatile const T> : public is_range_type<T> {};
-template <class T>
-struct is_range_type<volatile T> : public is_range_type<T> {};
-
-template <> struct is_range_type<unsigned short> : public std::true_type {};
-template <> struct is_range_type<unsigned int> : public std::true_type {};
-template <> struct is_range_type<unsigned long> : public std::true_type {};
-template <> struct is_range_type<unsigned long long> : public std::true_type {};
-
-template <> struct is_range_type<short> : public std::true_type {};
-template <> struct is_range_type<int> : public std::true_type {};
-template <> struct is_range_type<long> : public std::true_type {};
-template <> struct is_range_type<long long> : public std::true_type {};
-}
-template <typename T>
-void toValue(const std::string &strvalue, std::vector<T> &value) {
-  detail::toValue(strvalue, value, detail::is_range_type<T>());
-}
-
-template <typename T>
-void toValue(const std::string &strvalue, std::vector<std::vector<T>> &value,
-             const std::string &outerDelimiter = ",",
-             const std::string &innerDelimiter = "+") {
-  typedef Mantid::Kernel::StringTokenizer tokenizer;
-  tokenizer tokens(strvalue, outerDelimiter,
-                   tokenizer::TOK_IGNORE_EMPTY | tokenizer::TOK_TRIM);
-
-  value.clear();
-  value.reserve(tokens.count());
-
-  for (const auto &token : tokens) {
-    tokenizer values(token, innerDelimiter,
-                     tokenizer::TOK_IGNORE_EMPTY | tokenizer::TOK_TRIM);
-    std::vector<T> vect;
-    vect.reserve(values.count());
-    std::transform(
-        values.begin(), values.end(), std::back_inserter(vect),
-        [](const std::string &str) { return boost::lexical_cast<T>(str); });
-    value.push_back(std::move(vect));
-  }
-}
-
-/*Used specifically to retrieve a vector of type T populated with values
- * given to it from strvalue parameter, Using toValue method.
- (See constructor used specifically for vector assignments)
- */
-template <typename T> T extractToValueVector(const std::string &strvalue) {
-  T valueVec;
-  toValue(strvalue, valueVec);
-  return valueVec;
-}
-
-//------------------------------------------------------------------------------------------------
-// Templated += operator functions for specific types
-template <typename T> inline void addingOperator(T &lhs, const T &rhs) {
-  // The cast here (and the expansion of the compound operator which that
-  // necessitates) is because if this function is created for a template
-  // type narrower than an int, the compiler will expande the operands to
-  // ints which leads to a compiler warning when it's assigned back to the
-  // narrower type.
-  lhs = static_cast<T>(lhs + rhs);
-}
-
-template <typename T>
-inline void addingOperator(std::vector<T> &lhs, const std::vector<T> &rhs) {
-  // This concatenates the two
-  if (&lhs != &rhs) {
-    lhs.insert(lhs.end(), rhs.begin(), rhs.end());
-  } else {
-    std::vector<T> rhs_copy(rhs);
-    lhs.insert(lhs.end(), rhs_copy.begin(), rhs_copy.end());
-  }
-}
-
-template <> inline void addingOperator(bool &, const bool &) {
-  throw Exception::NotImplementedError(
-      "PropertyWithValue.h: += operator not implemented for type bool");
-}
-
-template <> inline void addingOperator(OptionalBool &, const OptionalBool &) {
-  throw Exception::NotImplementedError(
-      "PropertyWithValue.h: += operator not implemented for type OptionalBool");
-}
-
-template <typename T>
-inline void addingOperator(boost::shared_ptr<T> &,
-                           const boost::shared_ptr<T> &) {
-  throw Exception::NotImplementedError(
-      "PropertyWithValue.h: += operator not implemented for boost::shared_ptr");
-}
-
-template <typename T>
-inline std::vector<std::string>
-determineAllowedValues(const T &, const IValidator &validator) {
-  return validator.allowedValues();
-}
-
-template <>
-inline std::vector<std::string> determineAllowedValues(const OptionalBool &,
-                                                       const IValidator &) {
-  auto enumMap = OptionalBool::enumToStrMap();
-  std::vector<std::string> values;
-  values.reserve(enumMap.size());
-  std::transform(enumMap.cbegin(), enumMap.cend(), std::back_inserter(values),
-                 [](const std::pair<OptionalBool::Value, std::string> &str) {
-                   return str.second;
-                 });
-  return values;
-}
-}
-//------------------------------------------------------------------------------------------------
-// Now the PropertyWithValue class itself
-//------------------------------------------------------------------------------------------------
-
 template <typename TYPE> class DLLExport PropertyWithValue : public Property {
 public:
-  /** Constructor
-   *  @param name :: The name to assign to the property
-   *  @param defaultValue :: Is stored initial default value of the property
-   *  @param validator :: The validator to use for this property
-   *  @param direction :: Whether this is a Direction::Input, Direction::Output
-   * or Direction::InOut (Input & Output) property
-   */
   PropertyWithValue(
       const std::string &name, const TYPE &defaultValue,
       IValidator_sptr validator = IValidator_sptr(new NullValidator),
-      const unsigned int direction = Direction::Input)
-      : Property(name, typeid(TYPE), direction), m_value(defaultValue),
-        m_initialValue(defaultValue), m_validator(validator) {}
-
-  /** Constructor
-   *  @param name :: The name to assign to the property
-   *  @param defaultValue :: Is stored initial default value of the property
-   *  @param direction :: Whether this is a Direction::Input, Direction::Output
-   * or Direction::InOut (Input & Output) property
-   */
+      const unsigned int direction = Direction::Input);
   PropertyWithValue(const std::string &name, const TYPE &defaultValue,
-                    const unsigned int direction)
-      : Property(name, typeid(TYPE), direction), m_value(defaultValue),
-        m_initialValue(defaultValue),
-        m_validator(boost::make_shared<NullValidator>()) {}
-
-  /*
-    Constructor to handle vector value assignments to m_initialValue
-    so they can be remembered when the algorithm dialog is reloaded.
-  */
-  /**Constructor
-    *  @param name :: The name to assign to the property.
-    *  @param defaultValue :: A vector of numerical type, empty to comply with
-   * other definitions.
-    *  @param defaultValueStr :: The numerical values you wish to assign to the
-   * property
-    *  @param validator :: The validator to use for this property
-    *  @param direction :: Whether this is a Direction::Input, Direction::Output
-    * or Direction::InOut (Input & Output) property
-    */
+                    const unsigned int direction);
   PropertyWithValue(const std::string &name, const TYPE &defaultValue,
                     const std::string defaultValueStr,
-                    IValidator_sptr validator, const unsigned int direction)
-      : Property(name, typeid(TYPE), direction),
-        m_value(extractToValueVector<TYPE>(defaultValueStr)),
-        m_initialValue(extractToValueVector<TYPE>(defaultValueStr)),
-        m_validator(validator) {
-    UNUSED_ARG(defaultValue);
-  }
-
-  /**Copy constructor
-  *  Note the default value of the copied object is the initial value of
-  * original
-  */
-  PropertyWithValue(const PropertyWithValue &right)
-      : Property(right), m_value(right.m_value),
-        m_initialValue(right.m_initialValue), // the default is the initial
-                                              // value of the original object
-        m_validator(right.m_validator->clone()) {}
-  /// 'Virtual copy constructor'
-  PropertyWithValue<TYPE> *clone() const override {
-    return new PropertyWithValue<TYPE>(*this);
-  }
+                    IValidator_sptr validator, const unsigned int direction);
+  PropertyWithValue(const PropertyWithValue &right);
+  PropertyWithValue<TYPE> *clone() const override;
 
   void saveProperty(::NeXus::File *file) override;
-
-  /** Get the value of the property as a string
-   *  @return The property's value
-   */
-  std::string value() const override { return toString(m_value); }
-
-  /**
-   * Deep comparison.
-   * @param rhs The other property to compare to.
-   * @return true if the are equal.
-   */
-  virtual bool operator==(const PropertyWithValue<TYPE> &rhs) const {
-    if (this->name() != rhs.name())
-      return false;
-    return (m_value == rhs.m_value);
-  }
-
-  /**
-   * Deep comparison (not equal).
-   * @param rhs The other property to compare to.
-   * @return true if the are not equal.
-   */
-  virtual bool operator!=(const PropertyWithValue<TYPE> &rhs) const {
-    return !(*this == rhs);
-  }
-
-  /** Get the size of the property.
-  */
-  int size() const override { return findSize(m_value); }
-
-  /** Get the value the property was initialised with -its default value
-   *  @return The default value
-   */
-  std::string getDefault() const override { return toString(m_initialValue); }
-
-  /** Set the value of the property from a string representation.
-   *  Note that "1" & "0" must be used for bool properties rather than
-   * true/false.
-   *  @param value :: The value to assign to the property
-   *  @return Returns "" if the assignment was successful or a user level
-   * description of the problem
-   */
-  std::string setValue(const std::string &value) override {
-    try {
-      TYPE result = m_value;
-      std::string valueCopy = value;
-      if (autoTrim()) {
-        boost::trim(valueCopy);
-      }
-      toValue(valueCopy, result);
-      // Uses the assignment operator defined below which runs isValid() and
-      // throws based on the result
-      *this = result;
-      return "";
-    } catch (boost::bad_lexical_cast &) {
-      std::string error = "Could not set property " + name() +
-                          ". Can not convert \"" + value + "\" to " + type();
-      g_logger.debug() << error;
-      return error;
-    } catch (std::invalid_argument &except) {
-      g_logger.debug() << "Could not set property " << name() << ": "
-                       << except.what();
-      return except.what();
-    }
-  }
-
-  /**
-   * Set a property value via a DataItem
-   * @param data :: A shared pointer to a data item
-   * @return "" if the assignment was successful or a user level description of
-   * the problem
-   */
-  std::string setDataItem(const boost::shared_ptr<DataItem> data) override {
-    // Pass of the helper function that is able to distinguish whether
-    // the TYPE of the PropertyWithValue can be converted to a
-    // shared_ptr<DataItem>
-    return setTypedValue(
-        data, boost::is_convertible<TYPE, boost::shared_ptr<DataItem>>());
-  }
-
-  /// Copy assignment operator assigns only the value and the validator not the
-  /// name, default (initial) value, etc.
-  PropertyWithValue &operator=(const PropertyWithValue &right) {
-    if (&right == this)
-      return *this;
-    m_value = right.m_value;
-    m_validator = right.m_validator->clone();
-    return *this;
-  }
-
-  //--------------------------------------------------------------------------------------
-  /** Add the value of another property
-  * @param right the property to add
-  * @return the sum
-  */
-  PropertyWithValue &operator+=(Property const *right) override {
-    PropertyWithValue const *rhs =
-        dynamic_cast<PropertyWithValue const *>(right);
-
-    if (rhs) {
-      // This function basically does:
-      //  m_value += rhs->m_value; for values
-      //  or concatenates vectors for vectors
-      addingOperator(m_value, rhs->m_value);
-    } else
-      g_logger.warning() << "PropertyWithValue " << this->name()
-                         << " could not be added to another property of the "
-                            "same name but incompatible type.\n";
-
-    return *this;
-  }
-
-  //--------------------------------------------------------------------------------------
-  /** Assignment operator.
-   *  Allows assignment of a new value to the property by writing,
-   *  e.g., myProperty = 3;
-   *  @param value :: The new value to assign to the property
-   *  @return the reference to itself
-   */
-  virtual TYPE &operator=(const TYPE &value) {
-    TYPE oldValue = m_value;
-    if (std::is_same<TYPE, std::string>::value) {
-      std::string valueCopy = toString(value);
-      if (autoTrim()) {
-        boost::trim(valueCopy);
-      }
-      toValue(valueCopy, m_value);
-    } else {
-      m_value = value;
-    }
-    std::string problem = this->isValid();
-    if (problem == "") {
-      return m_value;
-    } else if (problem == "_alias") {
-      m_value = getValueForAlias(value);
-      return m_value;
-    } else {
-      m_value = oldValue;
-      throw std::invalid_argument(problem);
-    }
-  }
-
-  /** Allows you to get the value of the property via an expression like
-   * myProperty()
-   *  @returns the value of the property
-   */
-  virtual const TYPE &operator()() const { return m_value; }
-
-  /** Allows you to get the value of the property simply by typing its name.
-   *  Means you can use an expression like: int i = myProperty;
-   * @return the value
-   */
-  virtual operator const TYPE &() const { return m_value; }
-
-  /** Check the value chosen for the property is OK, unless overidden it just
-   * calls the validator's isValid()
-   *  N.B. Problems found in validator are written to the log
-   *  if you override this function to do checking outside a validator may want
-   * to do more logging
-   *  @returns "" if the value is valid or a discription of the problem
-   */
-  std::string isValid() const override { return m_validator->isValid(m_value); }
-
-  /** Indicates if the property's value is the same as it was when it was set
-  *  N.B. Uses an unsafe comparison in the case of doubles, consider overriding
-  * if the value is a pointer or floating point type
-  *  @return true if the value is the same as the initial value or false
-  * otherwise
-  */
-  bool isDefault() const override { return m_initialValue == m_value; }
-
-  /** Returns the set of valid values for this property, if such a set exists.
-   *  If not, it returns an empty vector.
-   *  @return Returns the set of valid values for this property, or it returns
-   * an empty vector.
-   */
-  std::vector<std::string> allowedValues() const override {
-    return determineAllowedValues(m_value, *m_validator);
-  }
-
-  /** Returns the set of valid values for this property, if such a set exists.
-  *  If not, it returns an empty vector.
-  *  @return Returns the set of valid values for this property, or it returns
-  * an empty vector.
-  */
-  bool isMultipleSelectionAllowed() override {
-    return m_validator->isMultipleSelectionAllowed();
-  }
-
-  /**
-   * Replace the current validator with the given one
-   * @param newValidator :: A replacement validator
-   */
-  virtual void replaceValidator(IValidator_sptr newValidator) {
-    m_validator = newValidator;
-  }
+  std::string value() const override;
+  virtual bool operator==(const PropertyWithValue<TYPE> &rhs) const;
+  virtual bool operator!=(const PropertyWithValue<TYPE> &rhs) const;
+  int size() const override;
+  std::string getDefault() const override;
+  std::string setValue(const std::string &value) override;
+  std::string setDataItem(const boost::shared_ptr<DataItem> data) override;
+  PropertyWithValue &operator=(const PropertyWithValue &right);
+  PropertyWithValue &operator+=(Property const *right) override;
+  virtual TYPE &operator=(const TYPE &value);
+  virtual const TYPE &operator()() const;
+  virtual operator const TYPE &() const;
+  std::string isValid() const override;
+  bool isDefault() const override;
+  std::vector<std::string> allowedValues() const override;
+  bool isMultipleSelectionAllowed() override;
+  virtual void replaceValidator(IValidator_sptr newValidator);
 
 protected:
   /// The value of the property
@@ -568,74 +91,15 @@ protected:
   TYPE m_initialValue;
 
 private:
-  /**
-   * Set the value of the property via a reference to another property.
-   * If the value is unacceptable the value is not changed but a string is
-   * returned.
-   * The value is only accepted if the other property has the same type as this
-   * @param right :: A reference to a property.
-   */
-  std::string setValueFromProperty(const Property &right) override {
-    auto prop = dynamic_cast<const PropertyWithValue<TYPE> *>(&right);
-    if (!prop) {
-      return "Could not set value: properties have different type.";
-    }
-    m_value = prop->m_value;
-    return "";
-  }
+  std::string setValueFromProperty(const Property &right) override;
 
-  /**
-   * Helper function for setValue(DataItem_sptr). Uses boost type traits to
-   * ensure
-   * it is only used if U is a type that is convertible to
-   * boost::shared_ptr<DataItem>
-   * @param value :: A object of type convertible to boost::shared_ptr<DataItem>
-   */
   template <typename U>
-  std::string setTypedValue(const U &value, const boost::true_type &) {
-    TYPE data = boost::dynamic_pointer_cast<typename TYPE::element_type>(value);
-    std::string msg;
-    if (data) {
-      try {
-        (*this) = data;
-      } catch (std::invalid_argument &exc) {
-        msg = exc.what();
-      }
-    } else {
-      msg = "Invalid DataItem. The object type (" +
-            std::string(typeid(value).name()) +
-            ") does not match the declared type of the property (" +
-            std::string(this->type()) + ").";
-    }
-    return msg;
-  }
+  std::string setTypedValue(const U &value, const boost::true_type &);
 
-  /**
-   * Helper function for setValue(DataItem_sptr). Uses boost type traits to
-   * ensure
-   * it is only used if U is NOT a type that is convertible to
-   * boost::shared_ptr<DataItem>
-   * @param value :: A object of type convertible to boost::shared_ptr<DataItem>
-   */
   template <typename U>
-  std::string setTypedValue(const U &value, const boost::false_type &) {
-    UNUSED_ARG(value);
-    return "Attempt to assign object of type DataItem to property (" + name() +
-           ") of incorrect type";
-  }
+  std::string setTypedValue(const U &value, const boost::false_type &);
 
-  /** Return value for a given alias.
-   * @param alias :: An alias for a value. If a value cannot be found throw an
-   * invalid_argument exception.
-   * @return :: A value.
-   */
-  const TYPE getValueForAlias(const TYPE &alias) const {
-    std::string strAlias = toString(alias);
-    std::string strValue = m_validator->getValueForAlias(strAlias);
-    TYPE value;
-    toValue(strValue, value);
-    return value;
-  }
+  const TYPE getValueForAlias(const TYPE &alias) const;
 
   /// Visitor validator class
   IValidator_sptr m_validator;
@@ -644,31 +108,36 @@ private:
   static Logger g_logger;
 
   /// Private default constructor
-  PropertyWithValue();
+  PropertyWithValue() = default;
 };
 
-template <> void PropertyWithValue<float>::saveProperty(::NeXus::File *file);
-template <> void PropertyWithValue<double>::saveProperty(::NeXus::File *file);
-template <> void PropertyWithValue<int32_t>::saveProperty(::NeXus::File *file);
-template <> void PropertyWithValue<uint32_t>::saveProperty(::NeXus::File *file);
-template <> void PropertyWithValue<int64_t>::saveProperty(::NeXus::File *file);
-template <> void PropertyWithValue<uint64_t>::saveProperty(::NeXus::File *file);
 template <>
-void PropertyWithValue<std::string>::saveProperty(::NeXus::File *file);
+MANTID_KERNEL_DLL void
+PropertyWithValue<float>::saveProperty(::NeXus::File *file);
 template <>
-void PropertyWithValue<std::vector<double>>::saveProperty(::NeXus::File *file);
+MANTID_KERNEL_DLL void
+PropertyWithValue<double>::saveProperty(::NeXus::File *file);
 template <>
-void PropertyWithValue<std::vector<int32_t>>::saveProperty(::NeXus::File *file);
-
-template <typename TYPE>
-void PropertyWithValue<TYPE>::saveProperty(::NeXus::File * /*file*/) {
-  // AppleClang 7.3 and later gives a -Winfinite-recursion warning if I call the
-  // base class method. The function is small enough that reimplementing it
-  // isn't a big deal.
-  throw std::invalid_argument(
-      "PropertyWithValue::saveProperty - Cannot save '" + this->name() +
-      "', property type not implemented.");
-}
+MANTID_KERNEL_DLL void
+PropertyWithValue<int32_t>::saveProperty(::NeXus::File *file);
+template <>
+MANTID_KERNEL_DLL void
+PropertyWithValue<uint32_t>::saveProperty(::NeXus::File *file);
+template <>
+MANTID_KERNEL_DLL void
+PropertyWithValue<int64_t>::saveProperty(::NeXus::File *file);
+template <>
+MANTID_KERNEL_DLL void
+PropertyWithValue<uint64_t>::saveProperty(::NeXus::File *file);
+template <>
+MANTID_KERNEL_DLL void
+PropertyWithValue<std::string>::saveProperty(::NeXus::File *file);
+template <>
+MANTID_KERNEL_DLL void
+PropertyWithValue<std::vector<double>>::saveProperty(::NeXus::File *file);
+template <>
+MANTID_KERNEL_DLL void
+PropertyWithValue<std::vector<int32_t>>::saveProperty(::NeXus::File *file);
 
 template <typename TYPE>
 Logger PropertyWithValue<TYPE>::g_logger("PropertyWithValue");
diff --git a/Framework/Kernel/inc/MantidKernel/PropertyWithValue.tcc b/Framework/Kernel/inc/MantidKernel/PropertyWithValue.tcc
new file mode 100644
index 0000000000000000000000000000000000000000..fb0bdb27655df2f60b419c54a4438c37c5046be5
--- /dev/null
+++ b/Framework/Kernel/inc/MantidKernel/PropertyWithValue.tcc
@@ -0,0 +1,414 @@
+#include "MantidKernel/PropertyWithValue.h"
+#include "MantidKernel/PropertyHelper.h"
+#include "MantidKernel/Exception.h"
+#include "MantidKernel/Logger.h"
+#include "MantidKernel/NullValidator.h"
+#include "MantidKernel/OptionalBool.h"
+
+#ifndef Q_MOC_RUN
+#include <boost/make_shared.hpp>
+#include <boost/algorithm/string/trim.hpp>
+#endif
+
+#include <nexus/NeXusFile.hpp>
+
+#include "MantidKernel/IPropertySettings.h"
+#include <MantidKernel/StringTokenizer.h>
+#include <type_traits>
+#include <vector>
+
+namespace Mantid {
+namespace Kernel {
+
+//------------------------------------------------------------------------------------------------
+// Now the PropertyWithValue class itself
+//------------------------------------------------------------------------------------------------
+
+/** Constructor
+ *  @param name :: The name to assign to the property
+ *  @param defaultValue :: Is stored initial default value of the property
+ *  @param validator :: The validator to use for this property
+ *  @param direction :: Whether this is a Direction::Input, Direction::Output
+ * or Direction::InOut (Input & Output) property
+ */
+template <typename TYPE>
+PropertyWithValue<TYPE>::PropertyWithValue(const std::string &name,
+                                           const TYPE &defaultValue,
+                                           IValidator_sptr validator,
+                                           const unsigned int direction)
+    : Property(name, typeid(TYPE), direction), m_value(defaultValue),
+      m_initialValue(defaultValue), m_validator(validator) {}
+
+/** Constructor
+ *  @param name :: The name to assign to the property
+ *  @param defaultValue :: Is stored initial default value of the property
+ *  @param direction :: Whether this is a Direction::Input, Direction::Output
+ * or Direction::InOut (Input & Output) property
+ */
+template <typename TYPE>
+PropertyWithValue<TYPE>::PropertyWithValue(const std::string &name,
+                                           const TYPE &defaultValue,
+                                           const unsigned int direction)
+    : Property(name, typeid(TYPE), direction), m_value(defaultValue),
+      m_initialValue(defaultValue),
+      m_validator(boost::make_shared<NullValidator>()) {}
+
+/*
+  Constructor to handle vector value assignments to m_initialValue
+  so they can be remembered when the algorithm dialog is reloaded.
+*/
+/**Constructor
+  *  @param name :: The name to assign to the property.
+  *  @param defaultValue :: A vector of numerical type, empty to comply with
+ * other definitions.
+  *  @param defaultValueStr :: The numerical values you wish to assign to the
+ * property
+  *  @param validator :: The validator to use for this property
+  *  @param direction :: Whether this is a Direction::Input, Direction::Output
+  * or Direction::InOut (Input & Output) property
+  */
+template <typename TYPE>
+PropertyWithValue<TYPE>::PropertyWithValue(const std::string &name,
+                                           const TYPE &defaultValue,
+                                           const std::string defaultValueStr,
+                                           IValidator_sptr validator,
+                                           const unsigned int direction)
+    : Property(name, typeid(TYPE), direction),
+      m_value(extractToValueVector<TYPE>(defaultValueStr)),
+      m_initialValue(extractToValueVector<TYPE>(defaultValueStr)),
+      m_validator(validator) {
+  UNUSED_ARG(defaultValue);
+}
+
+/**Copy constructor
+*  Note the default value of the copied object is the initial value of
+* original
+*/
+template <typename TYPE>
+PropertyWithValue<TYPE>::PropertyWithValue(const PropertyWithValue &right)
+    : Property(right), m_value(right.m_value),
+      m_initialValue(right.m_initialValue), // the default is the initial
+                                            // value of the original object
+      m_validator(right.m_validator->clone()) {}
+
+/// 'Virtual copy constructor'
+template <typename TYPE>
+PropertyWithValue<TYPE> *PropertyWithValue<TYPE>::clone() const {
+  return new PropertyWithValue<TYPE>(*this);
+}
+
+template <typename TYPE>
+void PropertyWithValue<TYPE>::saveProperty(::NeXus::File * /*file*/) {
+  // AppleClang 7.3 and later gives a -Winfinite-recursion warning if I call the
+  // base class method. The function is small enough that reimplementing it
+  // isn't a big deal.
+  throw std::invalid_argument(
+      "PropertyWithValue::saveProperty - Cannot save '" + this->name() +
+      "', property type not implemented.");
+}
+
+/** Get the value of the property as a string
+ *  @return The property's value
+ */
+template <typename TYPE> std::string PropertyWithValue<TYPE>::value() const {
+  return toString(m_value);
+}
+
+/**
+ * Deep comparison.
+ * @param rhs The other property to compare to.
+ * @return true if the are equal.
+ */
+template <typename TYPE>
+bool PropertyWithValue<TYPE>::
+operator==(const PropertyWithValue<TYPE> &rhs) const {
+  if (this->name() != rhs.name())
+    return false;
+  return (m_value == rhs.m_value);
+}
+
+/**
+ * Deep comparison (not equal).
+ * @param rhs The other property to compare to.
+ * @return true if the are not equal.
+ */
+template <typename TYPE>
+bool PropertyWithValue<TYPE>::
+operator!=(const PropertyWithValue<TYPE> &rhs) const {
+  return !(*this == rhs);
+}
+
+/** Get the size of the property.
+*/
+template <typename TYPE> int PropertyWithValue<TYPE>::size() const {
+  return findSize(m_value);
+}
+
+/** Get the value the property was initialised with -its default value
+ *  @return The default value
+ */
+template <typename TYPE>
+std::string PropertyWithValue<TYPE>::getDefault() const {
+  return toString(m_initialValue);
+}
+
+/** Set the value of the property from a string representation.
+ *  Note that "1" & "0" must be used for bool properties rather than
+ * true/false.
+ *  @param value :: The value to assign to the property
+ *  @return Returns "" if the assignment was successful or a user level
+ * description of the problem
+ */
+template <typename TYPE>
+std::string PropertyWithValue<TYPE>::setValue(const std::string &value) {
+  try {
+    TYPE result = m_value;
+    std::string valueCopy = value;
+    if (autoTrim()) {
+      boost::trim(valueCopy);
+    }
+    toValue(valueCopy, result);
+    // Uses the assignment operator defined below which runs isValid() and
+    // throws based on the result
+    *this = result;
+    return "";
+  } catch (boost::bad_lexical_cast &) {
+    std::string error = "Could not set property " + name() +
+                        ". Can not convert \"" + value + "\" to " + type();
+    g_logger.debug() << error;
+    return error;
+  } catch (std::invalid_argument &except) {
+    g_logger.debug() << "Could not set property " << name() << ": "
+                     << except.what();
+    return except.what();
+  }
+}
+
+/**
+ * Set a property value via a DataItem
+ * @param data :: A shared pointer to a data item
+ * @return "" if the assignment was successful or a user level description of
+ * the problem
+ */
+template <typename TYPE>
+std::string
+PropertyWithValue<TYPE>::setDataItem(const boost::shared_ptr<DataItem> data) {
+  // Pass of the helper function that is able to distinguish whether
+  // the TYPE of the PropertyWithValue can be converted to a
+  // shared_ptr<DataItem>
+  return setTypedValue(
+      data, boost::is_convertible<TYPE, boost::shared_ptr<DataItem>>());
+}
+
+/// Copy assignment operator assigns only the value and the validator not the
+/// name, default (initial) value, etc.
+template <typename TYPE>
+PropertyWithValue<TYPE> &PropertyWithValue<TYPE>::
+operator=(const PropertyWithValue &right) {
+  if (&right == this)
+    return *this;
+  m_value = right.m_value;
+  m_validator = right.m_validator->clone();
+  return *this;
+}
+
+//--------------------------------------------------------------------------------------
+/** Add the value of another property
+* @param right the property to add
+* @return the sum
+*/
+template <typename TYPE>
+PropertyWithValue<TYPE> &PropertyWithValue<TYPE>::
+operator+=(Property const *right) {
+  PropertyWithValue const *rhs = dynamic_cast<PropertyWithValue const *>(right);
+
+  if (rhs) {
+    // This function basically does:
+    //  m_value += rhs->m_value; for values
+    //  or concatenates vectors for vectors
+    addingOperator(m_value, rhs->m_value);
+  } else
+    g_logger.warning() << "PropertyWithValue " << this->name()
+                       << " could not be added to another property of the "
+                          "same name but incompatible type.\n";
+
+  return *this;
+}
+
+//--------------------------------------------------------------------------------------
+/** Assignment operator.
+ *  Allows assignment of a new value to the property by writing,
+ *  e.g., myProperty = 3;
+ *  @param value :: The new value to assign to the property
+ *  @return the reference to itself
+ */
+template <typename TYPE>
+TYPE &PropertyWithValue<TYPE>::operator=(const TYPE &value) {
+  TYPE oldValue = m_value;
+  if (std::is_same<TYPE, std::string>::value) {
+    std::string valueCopy = toString(value);
+    if (autoTrim()) {
+      boost::trim(valueCopy);
+    }
+    toValue(valueCopy, m_value);
+  } else {
+    m_value = value;
+  }
+  std::string problem = this->isValid();
+  if (problem == "") {
+    return m_value;
+  } else if (problem == "_alias") {
+    m_value = getValueForAlias(value);
+    return m_value;
+  } else {
+    m_value = oldValue;
+    throw std::invalid_argument(problem);
+  }
+}
+
+/** Allows you to get the value of the property via an expression like
+ * myProperty()
+ *  @returns the value of the property
+ */
+template <typename TYPE>
+const TYPE &PropertyWithValue<TYPE>::operator()() const {
+  return m_value;
+}
+
+/** Allows you to get the value of the property simply by typing its name.
+ *  Means you can use an expression like: int i = myProperty;
+ * @return the value
+ */
+template <typename TYPE>
+PropertyWithValue<TYPE>::operator const TYPE &() const {
+  return m_value;
+}
+
+/** Check the value chosen for the property is OK, unless overidden it just
+ * calls the validator's isValid()
+ *  N.B. Problems found in validator are written to the log
+ *  if you this function to do checking outside a validator may want
+ * to do more logging
+ *  @returns "" if the value is valid or a discription of the problem
+ */
+template <typename TYPE> std::string PropertyWithValue<TYPE>::isValid() const {
+  return m_validator->isValid(m_value);
+}
+
+/** Indicates if the property's value is the same as it was when it was set
+*  N.B. Uses an unsafe comparison in the case of doubles, consider overriding
+* if the value is a pointer or floating point type
+*  @return true if the value is the same as the initial value or false
+* otherwise
+*/
+template <typename TYPE> bool PropertyWithValue<TYPE>::isDefault() const {
+  return m_initialValue == m_value;
+}
+
+/** Returns the set of valid values for this property, if such a set exists.
+ *  If not, it returns an empty vector.
+ *  @return Returns the set of valid values for this property, or it returns
+ * an empty vector.
+ */
+template <typename TYPE>
+std::vector<std::string> PropertyWithValue<TYPE>::allowedValues() const {
+  return determineAllowedValues(m_value, *m_validator);
+}
+
+/** Returns the set of valid values for this property, if such a set exists.
+*  If not, it returns an empty vector.
+*  @return Returns the set of valid values for this property, or it returns
+* an empty vector.
+*/
+template <typename TYPE>
+bool PropertyWithValue<TYPE>::isMultipleSelectionAllowed() {
+  return m_validator->isMultipleSelectionAllowed();
+}
+
+/**
+ * Replace the current validator with the given one
+ * @param newValidator :: A replacement validator
+ */
+template <typename TYPE>
+void PropertyWithValue<TYPE>::replaceValidator(IValidator_sptr newValidator) {
+  m_validator = newValidator;
+}
+
+/**
+ * Set the value of the property via a reference to another property.
+ * If the value is unacceptable the value is not changed but a string is
+ * returned.
+ * The value is only accepted if the other property has the same type as this
+ * @param right :: A reference to a property.
+ */
+template <typename TYPE>
+std::string
+PropertyWithValue<TYPE>::setValueFromProperty(const Property &right) {
+  auto prop = dynamic_cast<const PropertyWithValue<TYPE> *>(&right);
+  if (!prop) {
+    return "Could not set value: properties have different type.";
+  }
+  m_value = prop->m_value;
+  return "";
+}
+
+/**
+ * Helper function for setValue(DataItem_sptr). Uses boost type traits to
+ * ensure
+ * it is only used if U is a type that is convertible to
+ * boost::shared_ptr<DataItem>
+ * @param value :: A object of type convertible to boost::shared_ptr<DataItem>
+ */
+template <typename TYPE>
+template <typename U>
+std::string PropertyWithValue<TYPE>::setTypedValue(const U &value,
+                                                   const boost::true_type &) {
+  TYPE data = boost::dynamic_pointer_cast<typename TYPE::element_type>(value);
+  std::string msg;
+  if (data) {
+    try {
+      (*this) = data;
+    } catch (std::invalid_argument &exc) {
+      msg = exc.what();
+    }
+  } else {
+    msg = "Invalid DataItem. The object type (" +
+          std::string(typeid(value).name()) +
+          ") does not match the declared type of the property (" +
+          std::string(this->type()) + ").";
+  }
+  return msg;
+}
+
+/**
+ * Helper function for setValue(DataItem_sptr). Uses boost type traits to
+ * ensure
+ * it is only used if U is NOT a type that is convertible to
+ * boost::shared_ptr<DataItem>
+ * @param value :: A object of type convertible to boost::shared_ptr<DataItem>
+ */
+template <typename TYPE>
+template <typename U>
+std::string PropertyWithValue<TYPE>::setTypedValue(const U &value,
+                                                   const boost::false_type &) {
+  UNUSED_ARG(value);
+  return "Attempt to assign object of type DataItem to property (" + name() +
+         ") of incorrect type";
+}
+
+/** Return value for a given alias.
+ * @param alias :: An alias for a value. If a value cannot be found throw an
+ * invalid_argument exception.
+ * @return :: A value.
+ */
+template <typename TYPE>
+const TYPE PropertyWithValue<TYPE>::getValueForAlias(const TYPE &alias) const {
+  std::string strAlias = toString(alias);
+  std::string strValue = m_validator->getValueForAlias(strAlias);
+  TYPE value;
+  toValue(strValue, value);
+  return value;
+}
+
+} // namespace Kernel
+} // namespace Mantid
diff --git a/Framework/Kernel/inc/MantidKernel/PseudoRandomNumberGenerator.h b/Framework/Kernel/inc/MantidKernel/PseudoRandomNumberGenerator.h
index 35aac7958f1f93be3980852493d74066d74196de..c9fc4f216f9453711d2d8fdf44d15476468c4cfc 100644
--- a/Framework/Kernel/inc/MantidKernel/PseudoRandomNumberGenerator.h
+++ b/Framework/Kernel/inc/MantidKernel/PseudoRandomNumberGenerator.h
@@ -53,6 +53,15 @@ public:
   virtual int nextInt(int start, int end) = 0;
   /// Generates the next point
   void generateNextPoint() override;
+  // Interface to boost distribution generators
+  /// Result (output) value type.
+  typedef double result_type;
+  /// Return the minimum value of the range
+  virtual double min() const = 0;
+  /// Return the maximum value of the range
+  virtual double max() const = 0;
+  /// Return next random value
+  double operator()() { return nextValue(); }
 
 private:
   DISABLE_COPY_AND_ASSIGN(PseudoRandomNumberGenerator)
diff --git a/Framework/Kernel/inc/MantidKernel/Strings.h b/Framework/Kernel/inc/MantidKernel/Strings.h
index e1f9f2d8738f111c7b65937538bb23ed8d3a1214..a43f38a95c6059d2244ea97604d83db3112a27da 100644
--- a/Framework/Kernel/inc/MantidKernel/Strings.h
+++ b/Framework/Kernel/inc/MantidKernel/Strings.h
@@ -57,7 +57,7 @@ namespace Strings {
  */
 template <typename ITERATOR_TYPE>
 DLLExport std::string join(ITERATOR_TYPE begin, ITERATOR_TYPE end,
-                           const std::string separator) {
+                           const std::string &separator) {
   std::ostringstream output;
   ITERATOR_TYPE it;
   for (it = begin; it != end;) {
@@ -101,7 +101,11 @@ MANTID_KERNEL_DLL int isEmpty(const std::string &A);
 /// Determines if a string starts with a #
 MANTID_KERNEL_DLL bool skipLine(const std::string &line);
 /// Get a line and strip comments
-MANTID_KERNEL_DLL std::string getLine(std::istream &fh, const int spc = 256);
+/// Use only for a single call
+MANTID_KERNEL_DLL std::string getLine(std::istream &fh);
+/// Get a line and strip comments
+/// Use within a loop
+MANTID_KERNEL_DLL void getLine(std::istream &fh, std::string &Line);
 /// Peek at a line without extracting it from the stream
 MANTID_KERNEL_DLL std::string peekLine(std::istream &fh);
 /// get a part of a long line
diff --git a/Framework/Kernel/inc/MantidKernel/System.h b/Framework/Kernel/inc/MantidKernel/System.h
index 65fbb9545cb6645eb132c260747bb09e13ebe237..9fd4783776846db9976b1a2a6a5b9046e564fd4d 100644
--- a/Framework/Kernel/inc/MantidKernel/System.h
+++ b/Framework/Kernel/inc/MantidKernel/System.h
@@ -94,37 +94,6 @@
  *  For size_t and ptrdiff_t
  */
 #include <cstddef>
-
-/**
- * Information for holding onto stdint.h if it is
- * not available
- */
-#ifdef HAVE_STDINT_H
 #include <cstdint>
-#else
-#ifdef BOOST_CSTDINT_HPP
-#include <cstdint.hpp>
-#else
-#ifdef _WIN32
-typedef signed char int8_t;
-typedef unsigned char uint8_t;
-typedef short int16_t;
-typedef unsigned short uint16_t;
-typedef int int32_t;
-typedef unsigned uint32_t;
-typedef long long int64_t;
-typedef unsigned long long uint64_t;
-#else
-typedef signed char int8_t;
-typedef unsigned char uint8_t;
-typedef short int16_t;
-typedef unsigned short uint16_t;
-typedef int int32_t;
-typedef unsigned int uint32_t;
-typedef long int64_t;
-typedef unsigned long uint64_t;
-#endif
-#endif
-#endif
 
 #endif /*MANTID_KERNEL_SYSTEM_H_*/
diff --git a/Framework/Kernel/inc/MantidKernel/TimeSeriesProperty.h b/Framework/Kernel/inc/MantidKernel/TimeSeriesProperty.h
index 9ca7d05fdaa6b517ced578d6ac61c1a0dc0e2520..1aa6a2abba00a274a95752f40328b37057627519 100644
--- a/Framework/Kernel/inc/MantidKernel/TimeSeriesProperty.h
+++ b/Framework/Kernel/inc/MantidKernel/TimeSeriesProperty.h
@@ -178,11 +178,13 @@ public:
   ///  Return the time series as a correct C++ map<DateAndTime, TYPE>. All
   ///  values
   std::map<DateAndTime, TYPE> valueAsCorrectMap() const;
-  ///  Return the time series's values as a vector<TYPE>
+  ///  Return the time series's values (unfiltered) as a vector<TYPE>
   std::vector<TYPE> valuesAsVector() const;
   ///  Return the time series as a correct C++ multimap<DateAndTime, TYPE>. All
   ///  values
   std::multimap<DateAndTime, TYPE> valueAsMultiMap() const;
+  /// Get filtered values as a vector
+  std::vector<TYPE> filteredValuesAsVector() const;
 
   /// Return the time series's times as a vector<DateAndTime>
   std::vector<DateAndTime> timesAsVector() const override;
@@ -296,12 +298,15 @@ public:
     * total size you'll need easily available in advance.  */
   void reserve(size_t size) { m_values.reserve(size); };
 
+  /// If filtering by log, get the time intervals for splitting
+  std::vector<Mantid::Kernel::SplittingInterval> getSplittingIntervals() const;
+
 private:
   //----------------------------------------------------------------------------------------------
   /// Saves the time vector has time + start attribute
   void saveTimeVector(::NeXus::File *file);
-  /// Sort the property into increasing times
-  void sort() const;
+  /// Sort the property into increasing times, if not already sorted
+  void sortIfNecessary() const;
   ///  Find the index of the entry of time t in the mP vector (sorted)
   int findIndex(Kernel::DateAndTime t) const;
   ///  Find the upper_bound of time t in container.
@@ -313,6 +318,8 @@ private:
   size_t findNthIndexFromQuickRef(int n) const;
   /// Set a value from another property
   std::string setValueFromProperty(const Property &right) override;
+  /// Find if time lies in a filtered region
+  bool isTimeFiltered(const Kernel::DateAndTime &time) const;
 
   /// Holds the time series data
   mutable std::vector<TimeValueUnit<TYPE>> m_values;
diff --git a/Framework/Kernel/inc/MantidKernel/TypedValidator.h b/Framework/Kernel/inc/MantidKernel/TypedValidator.h
index 078eef53f94f15166fd966d54401b18413d031a7..eb83c0be3a35a178671b9125d00622f4f1915a62 100644
--- a/Framework/Kernel/inc/MantidKernel/TypedValidator.h
+++ b/Framework/Kernel/inc/MantidKernel/TypedValidator.h
@@ -132,7 +132,7 @@ private:
     ElementType_sptr typedValue =
         boost::dynamic_pointer_cast<ElementType>(data);
     if (!typedValue) {
-      throw std::invalid_argument("DataItem \"" + data->name() +
+      throw std::invalid_argument("DataItem \"" + data->getName() +
                                   "\" is not of the expected type.");
     }
     return typedValue;
diff --git a/Framework/Kernel/inc/MantidKernel/UnitConversion.h b/Framework/Kernel/inc/MantidKernel/UnitConversion.h
index 2ea8dc18fcbf7c3c785af5fdcf0c9110ee6bcd1a..deed08db400e249e6b0dc7c666015179e0210bd8 100644
--- a/Framework/Kernel/inc/MantidKernel/UnitConversion.h
+++ b/Framework/Kernel/inc/MantidKernel/UnitConversion.h
@@ -41,15 +41,15 @@ public:
   /// Convert a single value between the given units (as strings)
   static double run(const std::string &src, const std::string &dest,
                     const double srcValue, const double l1, const double l2,
-                    const double twoTheta, const DeltaEMode::Type emode,
+                    const double theta, const DeltaEMode::Type emode,
                     const double efixed);
   /// Convert a single value between the given units
   static double run(Unit &srcUnit, Unit &destUnit, const double srcValue,
-                    const double l1, const double l2, const double twoTheta,
+                    const double l1, const double l2, const double theta,
                     const DeltaEMode::Type emode, const double efixed);
 
   /// Convert to ElasticQ
-  static double run(const double twoTheta, const double efixed);
+  static double run(const double theta, const double efixed);
 
 private:
   /// Perform a quick conversion
@@ -58,12 +58,12 @@ private:
   /// Convert through TOF
   static double convertViaTOF(Unit &srcUnit, Unit &destUnit,
                               const double srcValue, const double l1,
-                              const double l2, const double twoTheta,
+                              const double l2, const double theta,
                               const DeltaEMode::Type emode,
                               const double efixed);
 
   /// Convert to ElasticQ from Energy
-  static double convertToElasticQ(const double twoTheta, const double efixed);
+  static double convertToElasticQ(const double theta, const double efixed);
 };
 
 } // namespace Kernel
diff --git a/Framework/Kernel/inc/MantidKernel/UnitLabel.h b/Framework/Kernel/inc/MantidKernel/UnitLabel.h
index 0cd9829df37de1a85768d7f76f3e28775150af05..9348e7d16a616c82abc8ef4a360759b9265c64c0 100644
--- a/Framework/Kernel/inc/MantidKernel/UnitLabel.h
+++ b/Framework/Kernel/inc/MantidKernel/UnitLabel.h
@@ -24,7 +24,6 @@
   File change history is stored at: <https://github.com/mantidproject/mantid>
   Code Documentation is available at: <http://doxygen.mantidproject.org>
 */
-#include "MantidKernel/ClassMacros.h"
 #include "MantidKernel/DllConfig.h"
 #include <string>
 
@@ -36,6 +35,8 @@ namespace Kernel {
  */
 class MANTID_KERNEL_DLL UnitLabel {
 public:
+  UnitLabel() = delete;
+
   /// Type that contains a plain-text string
   typedef std::string AsciiString;
   /// Type that can hold a unicode string. This may vary per-platform depending
@@ -80,8 +81,6 @@ public:
   operator std::string() const;
 
 private:
-  DISABLE_DEFAULT_CONSTRUCT(UnitLabel)
-
   /// Value of plain-text label
   std::string m_ascii;
   /// Value of utf-8 encoded string
diff --git a/Framework/Kernel/inc/MantidKernel/V3D.h b/Framework/Kernel/inc/MantidKernel/V3D.h
index cd15ff1070eb146b6a39307957304231158c4027..f7052cf23238a0de0e5e87e5d2aef475324e5ef7 100644
--- a/Framework/Kernel/inc/MantidKernel/V3D.h
+++ b/Framework/Kernel/inc/MantidKernel/V3D.h
@@ -2,8 +2,6 @@
 #define MANTID_KERNEL_V3D_H_
 
 #include <cmath>
-#include <cfloat>
-#include <complex>
 #include <vector>
 #include "MantidKernel/DllConfig.h"
 #include "MantidKernel/Matrix.h"
diff --git a/Framework/Kernel/inc/MantidKernel/VMD.h b/Framework/Kernel/inc/MantidKernel/VMD.h
index 01b448c6fcff4bac2ee7a45d5190e0bb281af8be..e8d60d2ea5d9f0ae5a3baa081e24ef515ce3554d 100644
--- a/Framework/Kernel/inc/MantidKernel/VMD.h
+++ b/Framework/Kernel/inc/MantidKernel/VMD.h
@@ -1,18 +1,13 @@
 #ifndef MANTID_KERNEL_VMD_H_
 #define MANTID_KERNEL_VMD_H_
 
-#include "MantidKernel/StringTokenizer.h"
-#include "MantidKernel/Strings.h"
-#include "MantidKernel/System.h"
-#include "MantidKernel/Tolerance.h"
-#include "MantidKernel/V3D.h"
-#include <algorithm>
-#include <cstddef>
-#include <sstream>
-#include <stdexcept>
+#include "MantidKernel/DllConfig.h"
+#include <string>
+#include <vector>
 
 namespace Mantid {
 namespace Kernel {
+class V3D;
 
 /** Simple vector class for multiple dimensions (i.e. > 3).
 
@@ -42,456 +37,53 @@ namespace Kernel {
 */
 template <typename TYPE = double> class DLLExport VMDBase {
 public:
-  //-------------------------------------------------------------------------------------------
-  /** Default constructor, build with 1 dimension */
-  VMDBase() : nd(1) {
-    data = new TYPE[nd];
-    for (size_t d = 0; d < nd; d++)
-      data[d] = TYPE(0.0);
-  }
-
-  //-------------------------------------------------------------------------------------------
-  /** Constructor
-   * @param nd :: number of dimensions  */
-  VMDBase(size_t nd) : nd(nd) {
-    if (nd <= 0)
-      throw std::invalid_argument("nd must be > 0");
-    data = new TYPE[nd];
-    for (size_t d = 0; d < nd; d++)
-      data[d] = TYPE(0.0);
-  }
-
-  //-------------------------------------------------------------------------------------------
-  /** 2D Constructor
-   * @param val0 :: value at first dimension
-   * @param val1 :: value at second dimension
-   */
-  VMDBase(double val0, double val1) : nd(2) {
-    data = new TYPE[nd];
-    data[0] = TYPE(val0);
-    data[1] = TYPE(val1);
-  }
-
-  //-------------------------------------------------------------------------------------------
-  /** 3D Constructor
-   * @param val0 :: value at first dimension
-   * @param val1 :: value at second dimension
-   * @param val2 :: value at third dimension
-   */
-  VMDBase(double val0, double val1, double val2) : nd(3) {
-    data = new TYPE[nd];
-    data[0] = TYPE(val0);
-    data[1] = TYPE(val1);
-    data[2] = TYPE(val2);
-  }
-
-  //-------------------------------------------------------------------------------------------
-  /** 4D Constructor
-   * @param val0 :: value at first dimension
-   * @param val1 :: value at second dimension
-   * @param val2 :: value at third dimension
-   * @param val3 :: value at fourth dimension
-   */
-  VMDBase(double val0, double val1, double val2, double val3) : nd(4) {
-    data = new TYPE[nd];
-    data[0] = TYPE(val0);
-    data[1] = TYPE(val1);
-    data[2] = TYPE(val2);
-    data[3] = TYPE(val3);
-  }
-
-  //-------------------------------------------------------------------------------------------
-  /** 5D Constructor
-   * @param val0 :: value at first dimension
-   * @param val1 :: value at second dimension
-   * @param val2 :: value at third dimension
-   * @param val3 :: value at fourth dimension
-   * @param val4 :: value at fifth dimension
-   */
-  VMDBase(double val0, double val1, double val2, double val3, double val4)
-      : nd(5) {
-    data = new TYPE[nd];
-    data[0] = TYPE(val0);
-    data[1] = TYPE(val1);
-    data[2] = TYPE(val2);
-    data[3] = TYPE(val3);
-    data[4] = TYPE(val4);
-  }
-
-  //-------------------------------------------------------------------------------------------
-  /** 6D Constructor
-   * @param val0 :: value at first dimension
-   * @param val1 :: value at second dimension
-   * @param val2 :: value at third dimension
-   * @param val3 :: value at fourth dimension
-   * @param val4 :: value at fifth dimension
-   * @param val5 :: value at sixth dimension
-   */
+  VMDBase();
+  VMDBase(size_t nd);
+  VMDBase(double val0, double val1);
+  VMDBase(double val0, double val1, double val2);
+  VMDBase(double val0, double val1, double val2, double val3);
+  VMDBase(double val0, double val1, double val2, double val3, double val4);
   VMDBase(double val0, double val1, double val2, double val3, double val4,
-          double val5)
-      : nd(6) {
-    data = new TYPE[nd];
-    data[0] = TYPE(val0);
-    data[1] = TYPE(val1);
-    data[2] = TYPE(val2);
-    data[3] = TYPE(val3);
-    data[4] = TYPE(val4);
-    data[5] = TYPE(val5);
-  }
-
-  //-------------------------------------------------------------------------------------------
-  /** Copy constructor
-   * @param other :: other to copy */
-  VMDBase(const VMDBase &other) : nd(other.nd) {
-    if (nd <= 0)
-      throw std::invalid_argument("nd must be > 0");
-    data = new TYPE[nd];
-    for (size_t d = 0; d < nd; d++)
-      data[d] = other.data[d];
-  }
-
-  //-------------------------------------------------------------------------------------------
-  /** Assignment operator
-   * @param other :: copy into this
-   */
-  VMDBase &operator=(const VMDBase &other) {
-    if ((other.nd) != nd) {
-      nd = other.nd;
-      delete[] data;
-      data = new TYPE[nd];
-    }
-    for (size_t d = 0; d < nd; d++)
-      data[d] = other.data[d];
-    return *this;
-  }
-
-  //-------------------------------------------------------------------------------------------
-  /** Constructor
-   * @param nd :: number of dimensions
-   * @param bareData :: pointer to a nd-sized bare data array */
-  VMDBase(size_t nd, const double *bareData) : nd(nd) {
-    if (nd <= 0)
-      throw std::invalid_argument("nd must be > 0");
-    data = new TYPE[nd];
-    for (size_t d = 0; d < nd; d++)
-      data[d] = TYPE(bareData[d]);
-  }
-
-  //-------------------------------------------------------------------------------------------
-  /** Constructor
-   * @param nd :: number of dimensions
-   * @param bareData :: pointer to a nd-sized bare data array */
-  VMDBase(size_t nd, const float *bareData) : nd(nd) {
-    if (nd <= 0)
-      throw std::invalid_argument("nd must be > 0");
-    data = new TYPE[nd];
-    for (size_t d = 0; d < nd; d++)
-      data[d] = TYPE(bareData[d]);
-  }
-
-  //-------------------------------------------------------------------------------------------
-  /** Constructor
-   * @param vector :: V3D */
-  VMDBase(const V3D &vector) : nd(3) {
-    data = new TYPE[nd];
-    for (size_t d = 0; d < nd; d++)
-      data[d] = TYPE(vector[d]);
-  }
-
-  //-------------------------------------------------------------------------------------------
-  /** Constructor
-   * @param vector :: vector of doubles */
-  template <class T> VMDBase(const std::vector<T> &vector) : nd(vector.size()) {
-    if (nd <= 0)
-      throw std::invalid_argument("nd must be > 0");
-    data = new TYPE[nd];
-    for (size_t d = 0; d < nd; d++)
-      data[d] = TYPE(vector[d]);
-  }
-
-  //-------------------------------------------------------------------------------------------
-  /** Constructor
-   * @param vector :: vector of floats */
-  VMDBase(const std::vector<float> &vector) : nd(vector.size()) {
-    if (nd <= 0)
-      throw std::invalid_argument("nd must be > 0");
-    data = new TYPE[nd];
-    for (size_t d = 0; d < nd; d++)
-      data[d] = TYPE(vector[d]);
-  }
-
-  //-------------------------------------------------------------------------------------------
-  /** Constructor from string
-   * @param str :: string of comma or space-separated numbers for each component
-   */
-  VMDBase(const std::string &str) {
-
-    StringTokenizer strs(str, ", ", StringTokenizer::TOK_IGNORE_EMPTY);
-
-    std::vector<TYPE> vals;
-    std::transform(strs.cbegin(), strs.cend(), std::back_inserter(vals),
-                   [](const std::string &token) {
-                     TYPE v;
-                     if (!Strings::convert(token, v))
-                       throw std::invalid_argument(
-                           "VMDBase: Unable to convert the string '" + token +
-                           "' to a number.");
-                     return v;
-                   });
-
-    nd = vals.size();
-    if (nd <= 0)
-      throw std::invalid_argument("nd must be > 0");
-    data = new TYPE[nd];
-    std::copy(vals.cbegin(), vals.cend(), data);
-  }
-
-  //-------------------------------------------------------------------------------------------
-  /// Destructor
-  virtual ~VMDBase() { delete[] data; }
-
-  //-------------------------------------------------------------------------------------------
-  /// @return the number of dimensions
-  size_t getNumDims() const { return nd; }
-
-  //-------------------------------------------------------------------------------------------
-  /// @return the number of dimensions
-  size_t size() const { return nd; }
-
-  /** @return the value at the index */
-  const TYPE &operator[](const size_t index) const { return data[index]; }
-
-  /** @return the value at the index */
-  TYPE &operator[](const size_t index) { return data[index]; }
-
-  //-------------------------------------------------------------------------------------------
-  /** @return the bare data array directly. */
-  const TYPE *getBareArray() const { return data; }
-
-  //-------------------------------------------------------------------------------------------
-  /** Return a simple string representation of the vector
-   * @param separator :: string to place between values, one space is the
-   * default
-   */
-  std::string toString(const std::string &separator = " ") const {
-    std::ostringstream mess;
-    for (size_t d = 0; d < nd; d++)
-      mess << (d > 0 ? separator : "") << data[d];
-    return mess.str();
-  }
-
-  //-------------------------------------------------------------------------------------------
-  /** Get the vector as a vector
-   * @tparam T :: type to convert to (double/float)
-   * @return the vector as a std::vector
-   */
-  template <class T> std::vector<T> toVector() const {
-    typename std::vector<T> out;
-    for (size_t d = 0; d < nd; d++)
-      out.push_back(T(data[d]));
-    return out;
-  }
-
-  //-------------------------------------------------------------------------------------------
-  /** Equals operator with tolerance factor
-    @param v :: VMDBase for comparison
-    @return true if the items are equal
-   */
-  bool operator==(const VMDBase &v) const {
-    if (v.nd != nd)
-      return false;
-    for (size_t d = 0; d < nd; d++)
-      if ((std::fabs(data[d] - v.data[d]) > Tolerance))
-        return false;
-    return true;
-  }
-
-  //-------------------------------------------------------------------------------------------
-  /** Not-equals operator with tolerance factor
-    @param v :: VMDBase for comparison
-    @return true if the items are equal
-   */
-  bool operator!=(const VMDBase &v) const { return !operator==(v); }
-
-  //-------------------------------------------------------------------------------------------
-  /** Add two vectors together
-   * @param v :: other vector, must match number of dimensions  */
-  VMDBase operator+(const VMDBase &v) const {
-    VMDBase out(*this);
-    out += v;
-    return out;
-  }
-
-  //-------------------------------------------------------------------------------------------
-  /** Add two vectors together
-   * @param v :: other vector, must match number of dimensions  */
-  VMDBase &operator+=(const VMDBase &v) {
-    if (v.nd != this->nd)
-      throw std::runtime_error("Mismatch in number of dimensions in operation "
-                               "between two VMDBase vectors.");
-    for (size_t d = 0; d < nd; d++)
-      data[d] += v.data[d];
-    return *this;
-  }
-
-  //-------------------------------------------------------------------------------------------
-  /** Subtract two vectors
-   * @param v
-   *  :: other vector, must match number of dimensions  */
-  VMDBase operator-(const VMDBase &v) const {
-    VMDBase out(*this);
-    out -= v;
-    return out;
-  }
-
-  //-------------------------------------------------------------------------------------------
-  /** Subtract two vectors
-   * @param v :: other vector, must match number of dimensions  */
-  VMDBase &operator-=(const VMDBase &v) {
-    if (v.nd != this->nd)
-      throw std::runtime_error("Mismatch in number of dimensions in operation "
-                               "between two VMDBase vectors.");
-    for (size_t d = 0; d < nd; d++)
-      data[d] -= v.data[d];
-    return *this;
-  }
-
-  //-------------------------------------------------------------------------------------------
-  /** Inner product of two vectors (element-by-element)
-   * @param v :: other vector, must match number of dimensions  */
-  VMDBase operator*(const VMDBase &v) const {
-    VMDBase out(*this);
-    out *= v;
-    return out;
-  }
-
-  //-------------------------------------------------------------------------------------------
-  /** Inner product of two vectors (element-by-element)
-   * @param v :: other vector, must match number of dimensions  */
-  VMDBase &operator*=(const VMDBase &v) {
-    if (v.nd != this->nd)
-      throw std::runtime_error("Mismatch in number of dimensions in operation "
-                               "between two VMDBase vectors.");
-    for (size_t d = 0; d < nd; d++)
-      data[d] *= v.data[d];
-    return *this;
-  }
-
-  //-------------------------------------------------------------------------------------------
-  /** Inner division of two vectors (element-by-element)
-   * @param v :: other vector, must match number of dimensions  */
-  VMDBase operator/(const VMDBase &v) const {
-    VMDBase out(*this);
-    out /= v;
-    return out;
-  }
-
-  //-------------------------------------------------------------------------------------------
-  /** Inner division of two vectors (element-by-element)
-   * @param v :: other vector, must match number of dimensions  */
-  VMDBase &operator/=(const VMDBase &v) {
-    if (v.nd != this->nd)
-      throw std::runtime_error("Mismatch in number of dimensions in operation "
-                               "between two VMDBase vectors.");
-    for (size_t d = 0; d < nd; d++)
-      data[d] /= v.data[d];
-    return *this;
-  }
-
-  //-------------------------------------------------------------------------------------------
-  /** Multiply by a scalar
-   * @param scalar :: double scalar to multiply each element  */
-  VMDBase operator*(const double scalar) const {
-    VMDBase out(*this);
-    out *= scalar;
-    return out;
-  }
-
-  //-------------------------------------------------------------------------------------------
-  /** Multiply by a scalar
-   * @param scalar :: double scalar to multiply each element  */
-  VMDBase &operator*=(const double scalar) {
-    for (size_t d = 0; d < nd; d++)
-      data[d] *= TYPE(scalar);
-    return *this;
-  }
-
-  //-------------------------------------------------------------------------------------------
-  /** Divide by a scalar
-   * @param scalar :: double scalar to Divide each element  */
-  VMDBase operator/(const double scalar) const {
-    VMDBase out(*this);
-    out /= scalar;
-    return out;
-  }
-
-  //-------------------------------------------------------------------------------------------
-  /** Divide by a scalar
-   * @param scalar :: double scalar to Divide each element  */
-  VMDBase &operator/=(const double scalar) {
-    for (size_t d = 0; d < nd; d++)
-      data[d] /= TYPE(scalar);
-    return *this;
-  }
-
-  //-------------------------------------------------------------------------------------------
-  /** Scalar product of two vectors
-   * @param v :: other vector, must match number of dimensions  */
-  TYPE scalar_prod(const VMDBase &v) const {
-    TYPE out = 0;
-    if (v.nd != this->nd)
-      throw std::runtime_error("Mismatch in number of dimensions in operation "
-                               "between two VMDBase vectors.");
-    for (size_t d = 0; d < nd; d++)
-      out += (data[d] * v.data[d]);
-    return out;
-  }
-
-  //-------------------------------------------------------------------------------------------
-  /** Cross product of two vectors. Only works in 3D
-   * @param v :: other vector, also 3D  */
-  VMDBase cross_prod(const VMDBase &v) const {
-    if (v.nd != this->nd)
-      throw std::runtime_error("Mismatch in number of dimensions in operation "
-                               "between two VMDBase vectors.");
-    if (v.nd != 3)
-      throw std::runtime_error(
-          "Cross product of vectors only works in 3 dimensions.");
-    V3D a(data[0], data[1], data[2]);
-    V3D b(v.data[0], v.data[1], v.data[2]);
-    V3D c = a.cross_prod(b);
-    VMDBase out(c);
-    return out;
-  }
-
-  //-------------------------------------------------------------------------------------------
-  /** @return the length of this vector */
-  TYPE length() const { return TYPE(std::sqrt(this->norm2())); }
-
-  /** @return the length of this vector */
-  TYPE norm() const { return this->length(); }
-
-  /** @return the length of this vector */
-  TYPE norm2() const { return this->scalar_prod(*this); }
-
-  //-------------------------------------------------------------------------------------------
-  /** Normalize this vector to unity length
-   * @return the length of this vector BEFORE normalizing */
-  TYPE normalize() {
-    TYPE length = this->length();
-    for (size_t d = 0; d < nd; d++)
-      data[d] /= length;
-    return length;
-  }
-
-  //-------------------------------------------------------------------------------------------
-  /** Return the angle between this and another vector
-   *  @param v :: The other vector
-   *  @return The angle between the vectors in radians (0 < theta < pi)
-   */
-  TYPE angle(const VMDBase &v) const {
-    return TYPE(acos(this->scalar_prod(v) / (this->norm() * v.norm())));
-  }
+          double val5);
+
+  VMDBase(const VMDBase &other);
+  VMDBase &operator=(const VMDBase &other);
+  VMDBase(size_t nd, const double *bareData);
+  VMDBase(size_t nd, const float *bareData);
+  VMDBase(const V3D &vector);
+  VMDBase(const std::vector<double> &vector);
+  VMDBase(const std::vector<float> &vector);
+  VMDBase(const std::string &str);
+  ~VMDBase();
+
+  size_t getNumDims() const;
+  size_t size() const;
+  const TYPE &operator[](const size_t index) const;
+  TYPE &operator[](const size_t index);
+  const TYPE *getBareArray() const;
+  std::string toString(const std::string &separator = " ") const;
+  template <class T> std::vector<T> toVector() const;
+  bool operator==(const VMDBase &v) const;
+  bool operator!=(const VMDBase &v) const;
+  VMDBase operator+(const VMDBase &v) const;
+  VMDBase &operator+=(const VMDBase &v);
+  VMDBase operator-(const VMDBase &v) const;
+  VMDBase &operator-=(const VMDBase &v);
+  VMDBase operator*(const VMDBase &v) const;
+  VMDBase &operator*=(const VMDBase &v);
+  VMDBase operator/(const VMDBase &v) const;
+  VMDBase &operator/=(const VMDBase &v);
+  VMDBase operator*(const double scalar) const;
+  VMDBase &operator*=(const double scalar);
+  VMDBase operator/(const double scalar) const;
+  VMDBase &operator/=(const double scalar);
+  TYPE scalar_prod(const VMDBase &v) const;
+  VMDBase cross_prod(const VMDBase &v) const;
+  TYPE length() const;
+  TYPE norm() const;
+  TYPE norm2() const;
+  TYPE normalize();
+  TYPE angle(const VMDBase &v) const;
 
   static std::vector<VMDBase>
   makeVectorsOrthogonal(std::vector<VMDBase> &vectors);
diff --git a/Framework/Kernel/src/ArrayBoundedValidator.cpp b/Framework/Kernel/src/ArrayBoundedValidator.cpp
index 2b07a8125d502044c9c4068f4b35ad16e96697b9..68ae912ea9f50fcc354761a3d63dbbe9279f5e50 100644
--- a/Framework/Kernel/src/ArrayBoundedValidator.cpp
+++ b/Framework/Kernel/src/ArrayBoundedValidator.cpp
@@ -137,8 +137,11 @@ template <typename TYPE> void ArrayBoundedValidator<TYPE>::clearUpper() {
 
 // Required explicit instantiations
 template class ArrayBoundedValidator<double>;
-template class ArrayBoundedValidator<int>;
+template class ArrayBoundedValidator<int32_t>;
+template class ArrayBoundedValidator<int64_t>;
+#if defined(_WIN32) || defined(__clang__) && defined(__APPLE__)
 template class ArrayBoundedValidator<long>;
+#endif
 
 } // Kernel
 } // Mantid
diff --git a/Framework/Kernel/src/ArrayLengthValidator.cpp b/Framework/Kernel/src/ArrayLengthValidator.cpp
index 5a4adb6ae10429ad89f7edb4a4d6c3ac1d188ad3..72e740564b5b6739ced66695f33030ddaf66e403 100644
--- a/Framework/Kernel/src/ArrayLengthValidator.cpp
+++ b/Framework/Kernel/src/ArrayLengthValidator.cpp
@@ -185,8 +185,11 @@ std::string ArrayLengthValidator<TYPE>::checkValidity(
 
 // Required explicit instantiations
 template class ArrayLengthValidator<double>;
-template class ArrayLengthValidator<int>;
-template class ArrayLengthValidator<long>;
+template class ArrayLengthValidator<int32_t>;
+template class ArrayLengthValidator<int64_t>;
 template class ArrayLengthValidator<std::string>;
+#if defined(_WIN32) || defined(__clang__) && defined(__APPLE__)
+template class ArrayLengthValidator<long>;
+#endif
 } // namespace Mantid
 } // namespace Kernel
diff --git a/Framework/Kernel/src/ArrayOrderedPairsValidator.cpp b/Framework/Kernel/src/ArrayOrderedPairsValidator.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..67a2d36fce0feb4623e623fcd4c67dbb72419728
--- /dev/null
+++ b/Framework/Kernel/src/ArrayOrderedPairsValidator.cpp
@@ -0,0 +1,53 @@
+#include "MantidKernel/ArrayOrderedPairsValidator.h"
+
+#include <boost/make_shared.hpp>
+#include <sstream>
+
+namespace Mantid {
+namespace Kernel {
+
+/**
+ * Create a clone of the current ArrayBoundedValidator.
+ * @return The cloned object.
+ */
+template <typename TYPE>
+IValidator_sptr ArrayOrderedPairsValidator<TYPE>::clone() const {
+  return boost::make_shared<ArrayOrderedPairsValidator<TYPE>>(*this);
+}
+
+/**
+ * Function that actually does the work of checking the validity of the
+ * array elements.
+ * @param value :: The array to be checked.
+ * @return An error message giving the values of wrong entries.
+ */
+template <typename TYPE>
+std::string ArrayOrderedPairsValidator<TYPE>::checkValidity(
+    const std::vector<TYPE> &value) const {
+  std::stringstream error;
+  error << "";
+  // Check the number of entries is even
+  if (value.size() % 2 != 0) {
+    error << "Array has an odd number of entries ("
+          << std::to_string(value.size()) << ").";
+  } else {
+    // Check that each pair is ordered.
+    for (auto it = value.begin(); it != value.end(); it += 2) {
+      if (*it > *(it + 1)) {
+        error << "Pair (" << *it << ", " << *(it + 1) << ") is not ordered.\n";
+      }
+    }
+  }
+  return error.str();
+}
+
+// Required explicit instantiations
+template class ArrayOrderedPairsValidator<double>;
+template class ArrayOrderedPairsValidator<int32_t>;
+template class ArrayOrderedPairsValidator<int64_t>;
+#if defined(_WIN32) || defined(__clang__) && defined(__APPLE__)
+template class ArrayOrderedPairsValidator<long>;
+#endif
+
+} // Kernel
+} // Mantid
diff --git a/Framework/Kernel/src/ArrayProperty.cpp b/Framework/Kernel/src/ArrayProperty.cpp
index e1192f60a83b0d1b9da4d67fb48049b0544b444f..a951c7972aad406c501338cae00beaf7b86937d8 100644
--- a/Framework/Kernel/src/ArrayProperty.cpp
+++ b/Framework/Kernel/src/ArrayProperty.cpp
@@ -1,21 +1,128 @@
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidKernel/ArrayProperty.h"
 
+// PropertyWithValue implementation
+#include "MantidKernel/PropertyWithValue.tcc"
+
 namespace Mantid {
 namespace Kernel {
 
+/** Constructor
+ *  @param name ::      The name to assign to the property
+ *  @param vec ::       The initial vector of values to assign to the
+ * property.
+ *  @param validator :: The validator to use for this property, if required.
+ *  @param direction :: The direction (Input/Output/InOut) of this property
+ */
+template <typename T>
+ArrayProperty<T>::ArrayProperty(const std::string &name,
+                                const std::vector<T> &vec,
+                                IValidator_sptr validator,
+                                const unsigned int direction)
+    : PropertyWithValue<std::vector<T>>(name, vec, validator, direction) {}
+
+/** Constructor
+ *  Will lead to the property having a default-constructed (i.e. empty) vector
+ *  as its initial (default) value
+ *  @param name ::      The name to assign to the property
+ *  @param validator :: The validator to use for this property, if required
+ *  @param direction :: The direction (Input/Output/InOut) of this property
+ */
+
+template <typename T>
+ArrayProperty<T>::ArrayProperty(const std::string &name,
+                                IValidator_sptr validator,
+                                const unsigned int direction)
+    : PropertyWithValue<std::vector<T>>(name, std::vector<T>(), validator,
+                                        direction) {}
+
+/** Constructor that's useful for output properties or inputs with an empty
+ * default and no validator.
+ *  Will lead to the property having a default-constructed (i.e. empty) vector
+ *  as its initial (default) value and no validator
+ *  @param name ::      The name to assign to the property
+ *  @param direction :: The direction (Input/Output/InOut) of this property
+ */
+template <typename T>
+ArrayProperty<T>::ArrayProperty(const std::string &name,
+                                const unsigned int direction)
+    : PropertyWithValue<std::vector<T>>(name, std::vector<T>(),
+                                        IValidator_sptr(new NullValidator),
+                                        direction) {}
+
+/** Constructor from which you can set the property's values through a string:
+ *
+ * Inherits from the constructor of PropertyWithValue specifically made to
+ * handle a list
+ * of numeric values in a string format so that initial value is set
+ * correctly.
+ *
+ *  @param name ::      The name to assign to the property
+ *  @param values ::    A comma-separated string containing the values to
+ * store in the property
+ *  @param validator :: The validator to use for this property, if required
+ *  @param direction :: The direction (Input/Output/InOut) of this property
+ *  @throw std::invalid_argument if the string passed is not compatible with
+ * the array type
+ */
+template <typename T>
+ArrayProperty<T>::ArrayProperty(const std::string &name,
+                                const std::string &values,
+                                IValidator_sptr validator,
+                                const unsigned int direction)
+    : PropertyWithValue<std::vector<T>>(name, std::vector<T>(), values,
+                                        validator, direction) {}
+
+/// 'Virtual copy constructor'
+template <typename T> ArrayProperty<T> *ArrayProperty<T>::clone() const {
+  return new ArrayProperty<T>(*this);
+}
+
+/** Returns the values stored in the ArrayProperty
+ *  @return The stored values as a comma-separated list
+ */
+template <typename T> std::string ArrayProperty<T>::value() const {
+  // Implemented this method for documentation reasons. Just calls base class
+  // method.
+  return PropertyWithValue<std::vector<T>>::value();
+}
+
+/** Sets the values stored in the ArrayProperty from a string representation
+ *  @param value :: The values to assign to the property, given as a
+ * comma-separated list
+ *  @return True if the assignment was successful
+ */
+template <typename T>
+std::string ArrayProperty<T>::setValue(const std::string &value) {
+  // Implemented this method for documentation reasons. Just calls base class
+  // method.
+  return PropertyWithValue<std::vector<T>>::setValue(value);
+}
+
 /// @cond
 
 template class DLLExport ArrayProperty<int32_t>;
+template class DLLExport ArrayProperty<uint32_t>;
 template class DLLExport ArrayProperty<int64_t>;
-template class DLLExport ArrayProperty<size_t>;
+template class DLLExport ArrayProperty<uint64_t>;
+template class DLLExport ArrayProperty<float>;
 template class DLLExport ArrayProperty<double>;
 template class DLLExport ArrayProperty<std::string>;
 
+template class DLLExport ArrayProperty<std::vector<int32_t>>;
+template class DLLExport ArrayProperty<std::vector<uint32_t>>;
+template class DLLExport ArrayProperty<std::vector<int64_t>>;
+template class DLLExport ArrayProperty<std::vector<uint64_t>>;
+template class DLLExport ArrayProperty<std::vector<float>>;
+template class DLLExport ArrayProperty<std::vector<double>>;
 template class DLLExport ArrayProperty<std::vector<std::string>>;
 
+#if defined(_WIN32) || defined(__clang__) && defined(__APPLE__)
+template class DLLExport ArrayProperty<long>;
+template class DLLExport ArrayProperty<unsigned long>;
+template class DLLExport ArrayProperty<std::vector<long>>;
+template class DLLExport ArrayProperty<std::vector<unsigned long>>;
+#endif
+
 /// @endcond
 
 } // namespace Kernel
diff --git a/Framework/Kernel/src/ConfigService.cpp b/Framework/Kernel/src/ConfigService.cpp
index 938d41bfbf9bb7c31f653ffb82a2c856fcb365ac..fa4d4e9779e222284ea25bc574bf8dd9e4f0ad5a 100644
--- a/Framework/Kernel/src/ConfigService.cpp
+++ b/Framework/Kernel/src/ConfigService.cpp
@@ -1628,6 +1628,12 @@ const std::string ConfigServiceImpl::getVTPFileDirectory() {
 }
 /**
  * Fills the internal cache of instrument definition directories
+ *
+ * This will normally contain from Index 0
+ * - The download directory (win %appdata%/mantidproject/mantid/instrument)
+ *   (linux $home/.mantid/instrument )
+ * - The user instrument area /etc/mantid/instrument (not on windows)
+ * - The install directory/instrument
  */
 void ConfigServiceImpl::cacheInstrumentPaths() {
   m_InstrumentDirs.clear();
@@ -1689,14 +1695,31 @@ bool ConfigServiceImpl::addDirectoryifExists(
 void ConfigServiceImpl::updateFacilities(const std::string &fName) {
   clearFacilities();
 
-  std::string instrDir = getString("instrumentDefinition.directory");
-  std::string fileName = fName.empty() ? instrDir + "Facilities.xml" : fName;
+  // search all of the instrument directories
+  std::vector<std::string> directoryNames = getInstrumentDirectories();
+  std::string fileName = "";
+  for (const auto &instrDir : directoryNames) {
+    fileName = fName.empty() ? instrDir + "Facilities.xml" : fName;
+
+    Poco::File facilitiesFile(fileName);
+    // stop when you find the first one
+    if (facilitiesFile.exists())
+      break;
+  }
 
   // Set up the DOM parser and parse xml file
   Poco::XML::DOMParser pParser;
   Poco::AutoPtr<Poco::XML::Document> pDoc;
 
   try {
+    if (fileName.empty()) {
+      std::string directoryNamesList =
+          boost::algorithm::join(directoryNames, ", ");
+      throw std::runtime_error(
+          "Could not find a facilities info file! Searched for " +
+          directoryNamesList);
+    }
+
     try {
       pDoc = pParser.parse(fileName);
     } catch (...) {
diff --git a/Framework/Kernel/src/DeltaEMode.cpp b/Framework/Kernel/src/DeltaEMode.cpp
index 5a9181b96c28670792dfa4108ab91147377ba928..e802a147dde8e7f72ccbced78d1386d2a4010727 100644
--- a/Framework/Kernel/src/DeltaEMode.cpp
+++ b/Framework/Kernel/src/DeltaEMode.cpp
@@ -32,12 +32,10 @@ const std::vector<std::string> DeltaEMode::availableTypes() {
   const ModeIndex &lookup = typeStringLookup();
   std::vector<std::string> modes;
   modes.reserve(lookup.index.size());
-  size_t index(0);
   for (const auto &iter : lookup.index) {
     if (iter.first == DeltaEMode::Undefined)
       continue;
     modes.push_back(iter.second);
-    ++index;
   }
   return modes;
 }
diff --git a/Framework/Kernel/src/EmptyValues.cpp b/Framework/Kernel/src/EmptyValues.cpp
index c7f6cd92b2ecc537b1c1ded4c25e7549b5e9c2df..bd87b168341101aa95f4b74f7566af2968b6cff0 100644
--- a/Framework/Kernel/src/EmptyValues.cpp
+++ b/Framework/Kernel/src/EmptyValues.cpp
@@ -19,6 +19,12 @@ int EMPTY_INT() { return INT_MAX; }
  */
 long EMPTY_LONG() { return LONG_MAX; }
 
+/**
+ * Returns what we consider an "empty" int64_t within a property
+ * @returns An flag value
+ */
+int64_t EMPTY_INT64() { return INT64_MAX; }
+
 /**
  * Returns what we consider an "empty" double within a property
  * @returns An flag value
diff --git a/Framework/Kernel/src/EnabledWhenProperty.cpp b/Framework/Kernel/src/EnabledWhenProperty.cpp
index d6a11eceb245104ba4c90f9123fcba15e1d4227b..4c41660fb653048b750621c593795aef31fa6e13 100644
--- a/Framework/Kernel/src/EnabledWhenProperty.cpp
+++ b/Framework/Kernel/src/EnabledWhenProperty.cpp
@@ -1,5 +1,7 @@
 #include "MantidKernel/EnabledWhenProperty.h"
 
+#include <boost/lexical_cast.hpp>
+
 using namespace Mantid::Kernel;
 
 namespace Mantid {
diff --git a/Framework/Kernel/src/FacilityInfo.cpp b/Framework/Kernel/src/FacilityInfo.cpp
index 1ade6df6880df9f9ff7bf6c399c143441a614738..ed5491190bcac65965c40ef43f43026cb1e740b0 100644
--- a/Framework/Kernel/src/FacilityInfo.cpp
+++ b/Framework/Kernel/src/FacilityInfo.cpp
@@ -33,7 +33,7 @@ Logger g_log("FacilityInfo");
 FacilityInfo::FacilityInfo(const Poco::XML::Element *elem)
     : m_catalogs(elem), m_name(elem->getAttribute("name")), m_zeroPadding(0),
       m_delimiter(), m_extensions(), m_archiveSearch(), m_instruments(),
-      m_liveListener(), m_noFilePrefix(), m_computeResources() {
+      m_noFilePrefix(), m_computeResources() {
   if (m_name.empty()) {
     g_log.error("Facility name is not defined");
     throw std::runtime_error("Facility name is not defined");
@@ -44,7 +44,6 @@ FacilityInfo::FacilityInfo(const Poco::XML::Element *elem)
   fillDelimiter(elem);
   fillExtensions(elem);
   fillArchiveNames(elem);
-  fillLiveListener(elem);
   fillComputeResources(elem);
   fillNoFilePrefix(elem);
   fillInstruments(elem); // Make sure this is last as it picks up some defaults
@@ -143,16 +142,6 @@ void FacilityInfo::fillInstruments(const Poco::XML::Element *elem) {
   }
 }
 
-/// Called from constructor to fill live listener name
-void FacilityInfo::fillLiveListener(const Poco::XML::Element *elem) {
-  // Get the first livedata element (will be NULL if there's none)
-  Element *live = elem->getChildElement("livedata");
-  if (live) {
-    // Get the name of the listener - empty string will be returned if missing
-    m_liveListener = live->getAttribute("listener");
-  }
-}
-
 /// Called from constructor to fill compute resources map
 void FacilityInfo::fillComputeResources(const Poco::XML::Element *elem) {
   Poco::AutoPtr<Poco::XML::NodeList> pNL_compute =
diff --git a/Framework/Kernel/src/IPropertyManager.cpp b/Framework/Kernel/src/IPropertyManager.cpp
index 54e318ac22e32a85447e27a64221dab4c54152e9..51be0b084e195d1d08a28615030505d32fef1d3d 100644
--- a/Framework/Kernel/src/IPropertyManager.cpp
+++ b/Framework/Kernel/src/IPropertyManager.cpp
@@ -1,7 +1,5 @@
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidKernel/IPropertyManager.h"
+#include "MantidKernel/IPropertySettings.h"
 
 ///@cond
 DEFINE_IPROPERTYMANAGER_GETVALUE(int16_t)
@@ -79,6 +77,18 @@ void IPropertyManager::updatePropertyValues(const IPropertyManager &other) {
   }
 }
 
+/** Give settings to a property to determine when it gets enabled/hidden.
+ * Passes ownership of the given IPropertySettings object to the named
+ * property
+ * @param name :: property name
+ * @param settings :: IPropertySettings     */
+void IPropertyManager::setPropertySettings(
+    const std::string &name, std::unique_ptr<IPropertySettings> settings) {
+  Property *prop = getPointerToProperty(name);
+  if (prop)
+    prop->setSettings(std::move(settings));
+}
+
 /**
  * Get all properties in a group.
  * @param group Name of a group.
diff --git a/Framework/Kernel/src/InstrumentInfo.cpp b/Framework/Kernel/src/InstrumentInfo.cpp
index 932712b44399942197ebe038026a7d2f50648ab4..5ddda927a7a31a8a57c39d19fbc616afcb3ba03e 100644
--- a/Framework/Kernel/src/InstrumentInfo.cpp
+++ b/Framework/Kernel/src/InstrumentInfo.cpp
@@ -9,6 +9,7 @@
 #include "MantidKernel/Strings.h"
 
 #include <boost/lexical_cast.hpp>
+#include <boost/algorithm/string.hpp>
 
 #include <Poco/AutoPtr.h>
 #include <Poco/DOM/Element.h>
@@ -29,7 +30,7 @@ Logger g_log("InstrumentInfo");
 */
 InstrumentInfo::InstrumentInfo(const FacilityInfo *f,
                                const Poco::XML::Element *elem)
-    : m_facility(f), m_liveListener(), m_liveDataAddress() {
+    : m_facility(f) {
 
   m_name = elem->getAttribute("name");
   if (m_name.empty()) {
@@ -121,16 +122,64 @@ std::string InstrumentInfo::filePrefix(unsigned int runNumber) const {
 }
 
 /// Returns the name of the live listener
-const std::string &InstrumentInfo::liveListener() const {
-  return m_liveListener;
+std::string InstrumentInfo::liveListener(const std::string &name) const {
+  if (!hasLiveListenerInfo())
+    return "";
+
+  return liveListenerInfo(name).listener();
 }
 
 /** Returns the host & port to connect to for a live data stream
  *  No guarantees are given that the provided string is well-formed and valid
  *    - the caller should check this themselves
  */
-const std::string &InstrumentInfo::liveDataAddress() const {
-  return m_liveDataAddress;
+std::string InstrumentInfo::liveDataAddress(const std::string &name) const {
+  if (!hasLiveListenerInfo())
+    return "";
+
+  return liveListenerInfo(name).address();
+}
+
+/**
+ * Get LiveListenerInfo for specified connection (or default).
+ *
+ * @param name Name attribute of connection to return info on
+ * @return Reference to LiveListenerInfo for specified connection
+ * @throw std::runtime_error When no listeners, or name not found
+ */
+const LiveListenerInfo &
+InstrumentInfo::liveListenerInfo(std::string name) const {
+  if (!hasLiveListenerInfo())
+    throw std::runtime_error("Attempted to access live listener for " + m_name +
+                             " instrument, which has no listeners.");
+
+  // Default to specified default connection
+  if (name.empty())
+    name = m_defaultListener;
+
+  // If no default connection specified, fallback to first connection
+  if (name.empty())
+    return m_listeners.front();
+
+  // Name specified, find requested connection
+  for (auto &listener : m_listeners) {
+    // Names are compared case insensitively
+    if (boost::iequals(listener.name(), name))
+      return listener;
+  }
+
+  // The provided name was not valid / did not match any listeners
+  throw std::runtime_error("Could not find connection " + name +
+                           " for instrument " + m_name);
+}
+
+bool InstrumentInfo::hasLiveListenerInfo() const {
+  return !m_listeners.empty();
+}
+
+const std::vector<LiveListenerInfo> &
+InstrumentInfo::liveListenerInfoList() const {
+  return m_listeners;
 }
 
 /// Return list of techniques
@@ -205,7 +254,7 @@ void InstrumentInfo::fillTechniques(const Poco::XML::Element *elem) {
     if (pNL->length() > 0) {
       Poco::XML::Text *txt = dynamic_cast<Poco::XML::Text *>(pNL->item(0));
       if (txt) {
-        std::string tech = txt->getData();
+        const std::string &tech = txt->getData();
         if (!tech.empty()) {
           m_technique.insert(tech);
         }
@@ -221,32 +270,28 @@ void InstrumentInfo::fillTechniques(const Poco::XML::Element *elem) {
 
 /// Called from constructor to fill live listener name
 void InstrumentInfo::fillLiveData(const Poco::XML::Element *elem) {
-  // Get the first livedata element (will be NULL if there's none)
+  // See if we have a <livedata> element (will be NULL if there's none)
   Poco::XML::Element *live = elem->getChildElement("livedata");
-  if (live) {
-    // Get the name of the listener - empty string will be returned if missing
-    m_liveListener = live->getAttribute("listener");
-    // Get the host+port. Would have liked to put straight into a
-    // Poco::Net::SocketAddress
-    // but that tries to contact the given address on construction, which won't
-    // always be possible (or scalable)
-    m_liveDataAddress = live->getAttribute("address");
-    // Warn rather than throw if there are problems with the address
-    if (m_liveDataAddress.empty()) {
-      g_log.warning()
-          << "No connection details specified for live data listener of "
-          << m_name << "\n";
-    }
-    // Check for a colon, which would suggest that a host & port are present
-    else if (m_liveDataAddress.find(':') == std::string::npos) {
-      g_log.warning() << "Live data address for " << m_name
-                      << " appears not to have both host and port specified.\n";
+  if (!live)
+    return;
+
+  // Load default connection name attribute
+  m_defaultListener = live->getAttribute("default");
+
+  // Get connections under <livedata>
+  Poco::AutoPtr<Poco::XML::NodeList> connections =
+      elem->getElementsByTagName("connection");
+
+  // Load connection info for each child element
+  for (unsigned long i = 0; i < connections->length(); ++i) {
+    auto *conn = dynamic_cast<Poco::XML::Element *>(connections->item(i));
+    try {
+      m_listeners.emplace_back(this, conn);
+    } catch (...) {
+      g_log.error() << "Exception occurred while loading livedata for "
+                    << m_name << " instrument. Skipping faulty connection.\n";
     }
   }
-  // Apply the facility default listener if none specified for this instrument
-  if (m_liveListener.empty()) {
-    m_liveListener = m_facility->liveListener();
-  }
 }
 
 //-------------------------------------------------------------------------
diff --git a/Framework/Kernel/src/LiveListenerInfo.cpp b/Framework/Kernel/src/LiveListenerInfo.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..51eefd2c0d8a22fb15a5aa4584e3ac2673e7f377
--- /dev/null
+++ b/Framework/Kernel/src/LiveListenerInfo.cpp
@@ -0,0 +1,89 @@
+//----------------------------------------------------------------------
+// Includes
+//----------------------------------------------------------------------
+#include "MantidKernel/LiveListenerInfo.h"
+
+#include <iosfwd>
+
+#include "MantidKernel/FacilityInfo.h"
+#include "MantidKernel/InstrumentInfo.h"
+#include "MantidKernel/Logger.h"
+
+#include <Poco/DOM/Element.h>
+
+namespace Mantid {
+namespace Kernel {
+namespace {
+// static logger object
+Logger g_log("InstrumentInfo");
+}
+
+/**
+ * Construct from Facility Info XML.
+ *
+ * @param inst Pointer to InstrumentInfo that this LiveListenerInfo belongs to
+ * @param elem The Poco::XML::Element to read the data from
+ */
+LiveListenerInfo::LiveListenerInfo(InstrumentInfo *inst,
+                                   const Poco::XML::Element *elem) {
+  m_name = elem->getAttribute("name");
+  if (m_name.empty()) {
+    g_log.error() << "Listener connection name for " << inst->name()
+                  << "is not defined. This listener will not be selectable.\n";
+  }
+
+  m_address = elem->getAttribute("address");
+  if (m_address.empty()) {
+    g_log.error() << "Listener address for " << inst->name()
+                  << " is not defined.\n";
+  }
+
+  m_listener = elem->getAttribute("listener");
+  if (m_listener.empty()) {
+    g_log.error() << "Listener class for " << inst->name()
+                  << " is not defined.\n";
+  }
+}
+
+/**
+ * Construct manually.
+ *
+ * @param listener Class name of specific listener to use
+ * @param address Address which listener should use to connect
+ * @param name Name designator for this listener connection info
+ */
+LiveListenerInfo::LiveListenerInfo(const std::string &listener,
+                                   const std::string &address,
+                                   const std::string &name)
+    : m_name(name), m_address(address), m_listener(listener) {}
+
+bool LiveListenerInfo::operator==(const LiveListenerInfo &rhs) const {
+  return (this->address() == rhs.address() &&
+          this->listener() == rhs.listener());
+}
+
+const std::string &LiveListenerInfo::name() const { return m_name; }
+
+const std::string &LiveListenerInfo::address() const { return m_address; }
+
+const std::string &LiveListenerInfo::listener() const { return m_listener; }
+
+//-------------------------------------------------------------------------
+// Non-member functions
+//-------------------------------------------------------------------------
+/**
+ * Prints the listener to the stream.
+ *
+ * @param buffer :: A reference to an output stream
+ * @param listener :: A reference to a LiveListenerInfo object
+ * @return A reference to the stream written to
+ */
+std::ostream &operator<<(std::ostream &buffer,
+                         const LiveListenerInfo &listener) {
+  buffer << listener.name() << "(" << listener.address() << ", "
+         << listener.listener() << ")";
+  return buffer;
+}
+
+} // namespace Kernel
+} // namespace Mantid
diff --git a/Framework/Kernel/src/MandatoryValidator.cpp b/Framework/Kernel/src/MandatoryValidator.cpp
index e942e808b4a0dcf82dee4d90d364c9a84d941d65..95fdcc1793429e0d46611d23ae3d73e82641a715 100644
--- a/Framework/Kernel/src/MandatoryValidator.cpp
+++ b/Framework/Kernel/src/MandatoryValidator.cpp
@@ -39,8 +39,19 @@ template <> DLLExport bool checkIsEmpty(const int &value) {
  * @return True if the value is considered empty, see EmptyValues.h
  */
 template <> DLLExport bool checkIsEmpty(const long &value) {
+  // 32 bit for Windows and Clang, 64 bit for GCC
   return (value == Mantid::EMPTY_LONG());
 }
+#if defined(_WIN32) || defined(__clang__) && defined(__APPLE__)
+/**
+ * Specialization of checkIsEmpty for 64 bit intiger
+ * @param value :: A int64_t value
+ * @return True if the value is considered empty, see EmptyValues.h
+ */
+template <> DLLExport bool checkIsEmpty(const int64_t &value) {
+  return (value == Mantid::EMPTY_INT64());
+}
+#endif
 /**
  * Specialization of checkIsEmpty for OptionalBool
  * @param value :: A long value
diff --git a/Framework/Kernel/src/MaskedProperty.cpp b/Framework/Kernel/src/MaskedProperty.cpp
index 71a173945907c9d114e76257c3f3e2dec4d2103c..d61df06576acf192c870b87af0bbb4b72462472d 100644
--- a/Framework/Kernel/src/MaskedProperty.cpp
+++ b/Framework/Kernel/src/MaskedProperty.cpp
@@ -1,6 +1,9 @@
 #include "MantidKernel/MaskedProperty.h"
 #include "MantidKernel/PropertyHistory.h"
 
+// PropertyWithValue implementation
+#include "MantidKernel/PropertyWithValue.tcc"
+
 namespace Mantid {
 namespace Kernel {
 
diff --git a/Framework/Kernel/src/Material.cpp b/Framework/Kernel/src/Material.cpp
index 622d0efa87f30690ead9203ba60095e59cf39a6f..30363639b86dd92f7e5d166aa6488e4fe5dacf8f 100644
--- a/Framework/Kernel/src/Material.cpp
+++ b/Framework/Kernel/src/Material.cpp
@@ -392,7 +392,7 @@ void Material::saveNexus(::NeXus::File *file, const std::string &group) const {
 
   // determine how the information will be stored
   std::string style = "formula"; // default is a chemical formula
-  if (m_chemicalFormula.size() == 0) {
+  if (m_chemicalFormula.empty()) {
     style = "empty";
   } else if (m_chemicalFormula.size() == 1) {
     if (m_chemicalFormula[0].atom->symbol == "user") {
diff --git a/Framework/Kernel/src/MatrixProperty.cpp b/Framework/Kernel/src/MatrixProperty.cpp
index ddd680bdac9ea217da6fab7c7c783134e2d069ef..3d034013529f4c2c6ca3f7fea4ec53570991f58a 100644
--- a/Framework/Kernel/src/MatrixProperty.cpp
+++ b/Framework/Kernel/src/MatrixProperty.cpp
@@ -1,9 +1,9 @@
-//-----------------------------------------------------------------------------
-// Includes
-//-----------------------------------------------------------------------------
 #include "MantidKernel/MatrixProperty.h"
 #include "MantidKernel/IPropertyManager.h"
 
+// PropertyWithValue implementation
+#include "MantidKernel/PropertyWithValue.tcc"
+
 namespace Mantid {
 namespace Kernel {
 /**
diff --git a/Framework/Kernel/src/MersenneTwister.cpp b/Framework/Kernel/src/MersenneTwister.cpp
index f021254eca2e171cffaa31837422c0639247a9f1..45c52580405f9ae4ac371c07be014549c80e4e3a 100644
--- a/Framework/Kernel/src/MersenneTwister.cpp
+++ b/Framework/Kernel/src/MersenneTwister.cpp
@@ -7,6 +7,8 @@
 #include <boost/random/uniform_real.hpp>
 #include <boost/random/variate_generator.hpp>
 
+#include <Poco/Timestamp.h>
+
 namespace Mantid {
 namespace Kernel {
 
@@ -21,6 +23,20 @@ namespace Kernel {
 MersenneTwister::MersenneTwister(const size_t seedValue)
     : MersenneTwister(seedValue, 0.0, 1.0) {}
 
+/**
+ * Construct the generator time stamp for the initial seed.
+ * The range is set to [0.0, 1.0]
+ */
+MersenneTwister::MersenneTwister() : MersenneTwister(0.0, 1.0) {}
+
+/**
+ * Constructor taking a range
+ * @param start :: The minimum value a generated number should take
+ * @param end :: The maximum value a generated number should take
+ */
+MersenneTwister::MersenneTwister(const double start, const double end)
+    : MersenneTwister(Poco::Timestamp().epochMicroseconds(), start, end) {}
+
 /**
  * Constructor taking a seed value and a range
  * @param seedValue :: The initial seed
diff --git a/Framework/Kernel/src/MultiFileNameParser.cpp b/Framework/Kernel/src/MultiFileNameParser.cpp
index 2808204f2d7710674a35c1183d94e6856df0bb07..ee2697908883f01a640ce0939a9ef415f5761650 100644
--- a/Framework/Kernel/src/MultiFileNameParser.cpp
+++ b/Framework/Kernel/src/MultiFileNameParser.cpp
@@ -618,7 +618,7 @@ std::vector<std::vector<unsigned int>> generateRange(unsigned int from,
  */
 void validateToken(const std::string &token) {
   // Each token must be non-empty.
-  if (token.size() == 0)
+  if (token.empty())
     throw std::runtime_error("A comma-separated token is empty.");
 
   // Each token must begin and end with a numeric character.
diff --git a/Framework/Kernel/src/NormalDistribution.cpp b/Framework/Kernel/src/NormalDistribution.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e7ff30c4280bd54e798bfbebb1b4b41b55f734f4
--- /dev/null
+++ b/Framework/Kernel/src/NormalDistribution.cpp
@@ -0,0 +1,62 @@
+//------------------------------------------------------------------------------
+// Includes
+//------------------------------------------------------------------------------
+#include <string>
+#include "MantidKernel/NormalDistribution.h"
+#include "MantidKernel/MersenneTwister.h"
+
+namespace Mantid {
+namespace Kernel {
+
+//------------------------------------------------------------------------------
+// Public member functions
+//------------------------------------------------------------------------------
+
+/// Construct the default generator for standard normal distribution
+/// (mean = 0.0, sigma = 1.0)
+NormalDistribution::NormalDistribution()
+    : m_uniform_generator(), m_generator(0.0, 1.0) {}
+
+/// Construct the generator with initial distribution parameters
+/// and default seed.
+NormalDistribution::NormalDistribution(const double mean, const double sigma)
+    : m_uniform_generator(), m_generator(mean, sigma) {
+  if (sigma <= 0.0) {
+    throw std::runtime_error(
+        "Normal distribution must have positive sigma, given " +
+        std::to_string(sigma));
+  }
+}
+
+/// Construct the generator with initial distribution parameters and
+/// a seed value.
+NormalDistribution::NormalDistribution(const size_t seedValue,
+                                       const double mean, const double sigma)
+    : m_uniform_generator(seedValue), m_generator(mean, sigma) {
+  if (sigma <= 0.0) {
+    throw std::runtime_error(
+        "Normal distribution must have positive sigma, given " +
+        std::to_string(sigma));
+  }
+}
+
+/// Set the random number seed.
+/// @param seedValue :: A seed for the generator.
+void NormalDistribution::setSeed(const size_t seedValue) {
+  m_uniform_generator.setSeed(seedValue);
+}
+
+/// Generate the next random number in the sequence
+double NormalDistribution::nextValue() {
+  return m_generator(m_uniform_generator);
+}
+
+/// Generate a random number from a distribution with given mean and sigma.
+/// @param argMean :: A mean of the distribution.
+/// @param argSigma :: A sigma of the distribution.
+double NormalDistribution::randomValue(double argMean, double argSigma) {
+  boost::normal_distribution<double>::param_type param(argMean, argSigma);
+  return m_generator(m_uniform_generator, param);
+}
+}
+}
diff --git a/Framework/Kernel/src/PropertyManager.cpp b/Framework/Kernel/src/PropertyManager.cpp
index 11c59cf54bf0a301ec41b5f16d21cc318c646f19..a61700e8e71be117aa8416071ee3fec55dc3c2c9 100644
--- a/Framework/Kernel/src/PropertyManager.cpp
+++ b/Framework/Kernel/src/PropertyManager.cpp
@@ -351,7 +351,6 @@ void PropertyManager::setPropertiesWithSimpleString(
   boost::char_separator<char> sep(";");
   tokenizer propPairs(propertiesString, ";",
                       Mantid::Kernel::StringTokenizer::TOK_TRIM);
-  int index = 0;
   // Iterate over the properties
   for (const auto &pair : propPairs) {
     size_t n = pair.find('=');
@@ -372,7 +371,6 @@ void PropertyManager::setPropertiesWithSimpleString(
       // Set it
       propertyJson[propName] = value;
     }
-    index++;
   }
   setProperties(propertyJson, ignoreProperties);
 }
diff --git a/Framework/Kernel/src/PropertyNexus.cpp b/Framework/Kernel/src/PropertyNexus.cpp
index 0f74bd52806b41e722d94ffac32fb0c2d8fcc38f..10a50b7bd45e63060679a25456bcc347a18bc44d 100644
--- a/Framework/Kernel/src/PropertyNexus.cpp
+++ b/Framework/Kernel/src/PropertyNexus.cpp
@@ -10,6 +10,9 @@
 #include "MantidKernel/TimeSeriesProperty.h"
 #include "MantidKernel/make_unique.h"
 
+// PropertyWithValue implementation
+#include "MantidKernel/PropertyWithValue.tcc"
+
 #include <boost/algorithm/string/split.hpp>
 #include <boost/algorithm/string/trim.hpp>
 #include <boost/scoped_array.hpp>
diff --git a/Framework/Kernel/src/PropertyWithValue.cpp b/Framework/Kernel/src/PropertyWithValue.cpp
index ba8ba9cecf3650785be6ac8d8381234c7e3c70ff..52d17727d30bd08ba6f867d7554c2b5c4d8a3b4f 100644
--- a/Framework/Kernel/src/PropertyWithValue.cpp
+++ b/Framework/Kernel/src/PropertyWithValue.cpp
@@ -2,8 +2,10 @@
 #include "MantidKernel/PropertyManager.h"
 #include "MantidKernel/Matrix.h"
 
-namespace Mantid {
+// PropertyWithValue implementation
+#include "MantidKernel/PropertyWithValue.tcc"
 
+namespace Mantid {
 namespace Kernel {
 
 #define PROPERTYWITHVALUE_SAVEPROPERTY(type)                                   \
@@ -25,39 +27,62 @@ PROPERTYWITHVALUE_SAVEPROPERTY(std::vector<double>)
 PROPERTYWITHVALUE_SAVEPROPERTY(std::vector<int32_t>)
 
 /// @cond
-#define INSTANTIATE_WITH_EXPORT(Type)                                          \
-  template class DLLExport PropertyWithValue<Type>;
-
-// Explicit instantiations
-INSTANTIATE_WITH_EXPORT(uint16_t)
-INSTANTIATE_WITH_EXPORT(bool)
-INSTANTIATE_WITH_EXPORT(OptionalBool)
+template class MANTID_KERNEL_DLL PropertyWithValue<uint16_t>;
+template class MANTID_KERNEL_DLL PropertyWithValue<bool>;
+template class MANTID_KERNEL_DLL PropertyWithValue<OptionalBool>;
+template class MANTID_KERNEL_DLL PropertyWithValue<std::vector<float>>;
+template class MANTID_KERNEL_DLL PropertyWithValue<std::vector<uint16_t>>;
+template class MANTID_KERNEL_DLL PropertyWithValue<std::vector<uint32_t>>;
+template class MANTID_KERNEL_DLL PropertyWithValue<std::vector<int64_t>>;
+template class MANTID_KERNEL_DLL PropertyWithValue<std::vector<uint64_t>>;
+template class MANTID_KERNEL_DLL PropertyWithValue<std::vector<bool>>;
+template class MANTID_KERNEL_DLL PropertyWithValue<std::vector<OptionalBool>>;
+template class MANTID_KERNEL_DLL PropertyWithValue<std::vector<std::string>>;
+template class MANTID_KERNEL_DLL PropertyWithValue<Matrix<float>>;
+template class MANTID_KERNEL_DLL PropertyWithValue<Matrix<double>>;
+template class MANTID_KERNEL_DLL PropertyWithValue<Matrix<int>>;
+template class MANTID_KERNEL_DLL
+    PropertyWithValue<std::vector<std::vector<int32_t>>>;
+template class MANTID_KERNEL_DLL
+    PropertyWithValue<std::vector<std::vector<std::string>>>;
+template class MANTID_KERNEL_DLL
+    PropertyWithValue<boost::shared_ptr<IValidator>>;
+template class MANTID_KERNEL_DLL
+    PropertyWithValue<boost::shared_ptr<PropertyManager>>;
+#if defined(_WIN32) || defined(__clang__) && defined(__APPLE__)
+template class MANTID_KERNEL_DLL PropertyWithValue<long>;
+template class MANTID_KERNEL_DLL PropertyWithValue<unsigned long>;
+template class MANTID_KERNEL_DLL PropertyWithValue<std::vector<long>>;
+template class MANTID_KERNEL_DLL PropertyWithValue<std::vector<unsigned long>>;
+template class MANTID_KERNEL_DLL
+    PropertyWithValue<std::vector<std::vector<long>>>;
+#endif
+#ifdef __linux__
+template class MANTID_KERNEL_DLL PropertyWithValue<long long>;
+template class MANTID_KERNEL_DLL PropertyWithValue<unsigned long long>;
+template class MANTID_KERNEL_DLL PropertyWithValue<std::vector<long long>>;
+template class MANTID_KERNEL_DLL
+    PropertyWithValue<std::vector<unsigned long long>>;
+template class MANTID_KERNEL_DLL
+    PropertyWithValue<std::vector<std::vector<long long>>>;
+#endif
 /// @endcond
 
-#define INSTANTIATE_WITH_EXPORT_VECTOR(Type)                                   \
-  template class DLLExport PropertyWithValue<std::vector<Type>>;
-INSTANTIATE_WITH_EXPORT_VECTOR(uint16_t)
-INSTANTIATE_WITH_EXPORT_VECTOR(uint32_t)
-INSTANTIATE_WITH_EXPORT_VECTOR(int64_t)
-INSTANTIATE_WITH_EXPORT_VECTOR(uint64_t)
-INSTANTIATE_WITH_EXPORT_VECTOR(bool)
-INSTANTIATE_WITH_EXPORT_VECTOR(OptionalBool)
-INSTANTIATE_WITH_EXPORT_VECTOR(std::string)
-
 // The explicit template instantiations for some types does not have an export
 // macro
 // since this produces a warning on "gcc: warning: type attributes ignored after
 // type is already define". We can remove the issue, by removing the visibility
 // attribute
+template class PropertyWithValue<float>;
 template class PropertyWithValue<double>;
-template class PropertyWithValue<std::vector<double>>;
-
 template class PropertyWithValue<int32_t>;
-template class PropertyWithValue<std::vector<int32_t>>;
-
 template class PropertyWithValue<uint32_t>;
 template class PropertyWithValue<int64_t>;
 template class PropertyWithValue<uint64_t>;
+
+template class PropertyWithValue<std::vector<double>>;
+template class PropertyWithValue<std::vector<int32_t>>;
+
 template class PropertyWithValue<std::string>;
 
 } // namespace Kernel
diff --git a/Framework/Kernel/src/Quat.cpp b/Framework/Kernel/src/Quat.cpp
index ffc9cba34894112a887e287a5d524cbecb20a4d6..158713f56c1f098ff2e07ff48edcb40e3b41ff64 100644
--- a/Framework/Kernel/src/Quat.cpp
+++ b/Framework/Kernel/src/Quat.cpp
@@ -4,6 +4,7 @@
 #include "MantidKernel/V3D.h"
 
 #include <boost/algorithm/string.hpp>
+#include <sstream>
 
 namespace Mantid {
 namespace Kernel {
diff --git a/Framework/Kernel/src/RemoteJobManager.cpp b/Framework/Kernel/src/RemoteJobManager.cpp
index 3f11a4bed3f9b67528401478255374a7478c5d76..df29071281e26c4cb02829c7441b8d88f92e41d0 100644
--- a/Framework/Kernel/src/RemoteJobManager.cpp
+++ b/Framework/Kernel/src/RemoteJobManager.cpp
@@ -225,7 +225,7 @@ void RemoteJobManager::initHTTPRequest(Poco::Net::HTTPRequest &req,
   path += extraPath;
 
   uri.setPath(path);
-  if (method == Poco::Net::HTTPRequest::HTTP_GET && queryString.size() > 0) {
+  if (method == Poco::Net::HTTPRequest::HTTP_GET && !queryString.empty()) {
     uri.setQuery(queryString);
   }
 
diff --git a/Framework/Kernel/src/Strings.cpp b/Framework/Kernel/src/Strings.cpp
index ae7dd875e87be760c4535f0b53c9cad3a3410a2f..7869d9035b714f808fbe3afa08711cb707c8e97c 100644
--- a/Framework/Kernel/src/Strings.cpp
+++ b/Framework/Kernel/src/Strings.cpp
@@ -273,28 +273,33 @@ std::string removeSpace(const std::string &CLine) {
   return Out;
 }
 
+//------------------------------------------------------------------------------------------------
+/**
+  *  Reads a line from the stream of max length spc.
+  *  Trailing comments are removed. (with # or ! character)
+  *  @param fh :: already open file handle
+  *  @return String read.
+  */
+std::string getLine(std::istream &fh) {
+  std::string line;
+  getLine(fh, line);
+  return line;
+}
+
 //------------------------------------------------------------------------------------------------
 /**
  *  Reads a line from the stream of max length spc.
  *  Trailing comments are removed. (with # or ! character)
  *  @param fh :: already open file handle
- *  @param spc :: max number of characters to read
- *  @return String read.
+ *  @param Line :: string read
  */
-std::string getLine(std::istream &fh, const int spc) {
-  auto ss = new char[spc + 1];
-  std::string Line;
-  if (fh.good()) {
-    fh.getline(ss, spc, '\n');
-    ss[spc] = 0; // incase line failed to read completely
-    Line = ss;
+void getLine(std::istream &fh, std::string &Line) {
+  if (std::getline(fh, Line)) {
     // remove trailing comments
-    std::string::size_type pos = Line.find_first_of("#!");
+    auto pos = Line.find_first_of("#!");
     if (pos != std::string::npos)
       Line.erase(pos);
   }
-  delete[] ss;
-  return Line;
 }
 
 /**
diff --git a/Framework/Kernel/src/TimeSeriesProperty.cpp b/Framework/Kernel/src/TimeSeriesProperty.cpp
index 1d09e8985ab6c3965357105a855d5bd82dc1e745..898f13ed8f974d08c7590adb9254d66855c0cc4c 100644
--- a/Framework/Kernel/src/TimeSeriesProperty.cpp
+++ b/Framework/Kernel/src/TimeSeriesProperty.cpp
@@ -71,7 +71,7 @@ TimeSeriesProperty<TYPE>::getDerivative() const {
                              "property with less then two values");
   }
 
-  this->sort();
+  this->sortIfNecessary();
   auto it = this->m_values.begin();
   int64_t t0 = it->time().totalNanoseconds();
   TYPE v0 = it->value();
@@ -162,7 +162,7 @@ operator+=(Property const *right) {
 template <typename TYPE>
 bool TimeSeriesProperty<TYPE>::
 operator==(const TimeSeriesProperty<TYPE> &right) const {
-  sort();
+  sortIfNecessary();
 
   if (this->name() != right.name()) // should this be done?
   {
@@ -261,7 +261,7 @@ template <typename TYPE>
 void TimeSeriesProperty<TYPE>::filterByTime(const Kernel::DateAndTime &start,
                                             const Kernel::DateAndTime &stop) {
   // 0. Sort
-  sort();
+  sortIfNecessary();
 
   // 1. Do nothing for single (constant) value
   if (m_values.size() <= 1)
@@ -319,7 +319,7 @@ template <typename TYPE>
 void TimeSeriesProperty<TYPE>::filterByTimes(
     const std::vector<SplittingInterval> &splittervec) {
   // 1. Sort
-  sort();
+  sortIfNecessary();
 
   // 2. Return for single value
   if (m_values.size() <= 1) {
@@ -406,7 +406,7 @@ void TimeSeriesProperty<TYPE>::splitByTime(
     std::vector<SplittingInterval> &splitter, std::vector<Property *> outputs,
     bool isPeriodic) const {
   // 0. Sort if necessary
-  sort();
+  sortIfNecessary();
 
   if (outputs.empty())
     return;
@@ -581,7 +581,7 @@ void TimeSeriesProperty<TYPE>::makeFilterByValue(
     return;
 
   // 1. Sort
-  sort();
+  sortIfNecessary();
 
   // 2. Do the rest
   bool lastGood(false);
@@ -726,8 +726,7 @@ double TimeSeriesProperty<TYPE>::averageValueInFilter(
     return static_cast<double>(m_values.front().value());
   }
 
-  // Sort, if necessary.
-  sort();
+  sortIfNecessary();
 
   double numerator(0.0), totalTime(0.0);
   // Loop through the filter ranges
@@ -764,8 +763,7 @@ template <typename TYPE>
 double TimeSeriesProperty<TYPE>::timeAverageValue() const {
   double retVal = 0.0;
   try {
-    TimeSplitterType filter;
-    filter.emplace_back(this->firstTime(), this->lastTime());
+    const auto &filter = getSplittingIntervals();
     retVal = this->averageValueInFilter(filter);
   } catch (std::exception &) {
     // just return nan
@@ -803,7 +801,7 @@ template <typename TYPE>
 std::map<DateAndTime, TYPE>
 TimeSeriesProperty<TYPE>::valueAsCorrectMap() const {
   // 1. Sort if necessary
-  sort();
+  sortIfNecessary();
 
   // 2. Data Strcture
   std::map<DateAndTime, TYPE> asMap;
@@ -822,7 +820,7 @@ TimeSeriesProperty<TYPE>::valueAsCorrectMap() const {
  */
 template <typename TYPE>
 std::vector<TYPE> TimeSeriesProperty<TYPE>::valuesAsVector() const {
-  sort();
+  sortIfNecessary();
 
   std::vector<TYPE> out;
   out.reserve(m_values.size());
@@ -859,7 +857,7 @@ TimeSeriesProperty<TYPE>::valueAsMultiMap() const {
  */
 template <typename TYPE>
 std::vector<DateAndTime> TimeSeriesProperty<TYPE>::timesAsVector() const {
-  sort();
+  sortIfNecessary();
 
   std::vector<DateAndTime> out;
   out.reserve(m_values.size());
@@ -878,7 +876,7 @@ std::vector<DateAndTime> TimeSeriesProperty<TYPE>::timesAsVector() const {
 template <typename TYPE>
 std::vector<double> TimeSeriesProperty<TYPE>::timesAsVectorSeconds() const {
   // 1. Sort if necessary
-  sort();
+  sortIfNecessary();
 
   // 2. Output data structure
   std::vector<double> out;
@@ -996,7 +994,7 @@ DateAndTime TimeSeriesProperty<TYPE>::lastTime() const {
     throw std::runtime_error(error);
   }
 
-  sort();
+  sortIfNecessary();
 
   return m_values.rbegin()->time();
 }
@@ -1012,7 +1010,7 @@ template <typename TYPE> TYPE TimeSeriesProperty<TYPE>::firstValue() const {
     throw std::runtime_error(error);
   }
 
-  sort();
+  sortIfNecessary();
 
   return m_values[0].value();
 }
@@ -1029,7 +1027,7 @@ DateAndTime TimeSeriesProperty<TYPE>::firstTime() const {
     throw std::runtime_error(error);
   }
 
-  sort();
+  sortIfNecessary();
 
   return m_values[0].time();
 }
@@ -1046,7 +1044,7 @@ template <typename TYPE> TYPE TimeSeriesProperty<TYPE>::lastValue() const {
     throw std::runtime_error(error);
   }
 
-  sort();
+  sortIfNecessary();
 
   return m_values.rbegin()->value();
 }
@@ -1080,7 +1078,7 @@ template <typename TYPE> int TimeSeriesProperty<TYPE>::realSize() const {
  * @return time series property as a string
  */
 template <typename TYPE> std::string TimeSeriesProperty<TYPE>::value() const {
-  sort();
+  sortIfNecessary();
 
   std::stringstream ins;
   for (size_t i = 0; i < m_values.size(); i++) {
@@ -1104,7 +1102,7 @@ template <typename TYPE> std::string TimeSeriesProperty<TYPE>::value() const {
  */
 template <typename TYPE>
 std::vector<std::string> TimeSeriesProperty<TYPE>::time_tValue() const {
-  sort();
+  sortIfNecessary();
 
   std::vector<std::string> values;
   values.reserve(m_values.size());
@@ -1128,7 +1126,7 @@ std::vector<std::string> TimeSeriesProperty<TYPE>::time_tValue() const {
 template <typename TYPE>
 std::map<DateAndTime, TYPE> TimeSeriesProperty<TYPE>::valueAsMap() const {
   // 1. Sort if necessary
-  sort();
+  sortIfNecessary();
 
   // 2. Build map
 
@@ -1187,7 +1185,8 @@ template <typename TYPE> void TimeSeriesProperty<TYPE>::clear() {
  *  The last value is the last entry in the m_values vector - no sorting is
  *  done or checked for to ensure that the last value is the most recent in
  * time.
- *  It is up to the client to call sort() first if this is a requirement.
+ *  It is up to the client to call sortIfNecessary() first if this is a
+ * requirement.
  */
 template <typename TYPE> void TimeSeriesProperty<TYPE>::clearOutdated() {
   if (realSize() > 1) {
@@ -1271,7 +1270,7 @@ TYPE TimeSeriesProperty<TYPE>::getSingleValue(const DateAndTime &t) const {
   }
 
   // 1. Get sorted
-  sort();
+  sortIfNecessary();
 
   // 2.
   TYPE value;
@@ -1320,7 +1319,7 @@ TYPE TimeSeriesProperty<TYPE>::getSingleValue(const DateAndTime &t,
   }
 
   // 1. Get sorted
-  sort();
+  sortIfNecessary();
 
   // 2.
   TYPE value;
@@ -1376,7 +1375,7 @@ TimeInterval TimeSeriesProperty<TYPE>::nthInterval(int n) const {
   }
 
   // 1. Sort
-  sort();
+  sortIfNecessary();
 
   // 2. Calculate time interval
 
@@ -1495,7 +1494,7 @@ template <typename TYPE> TYPE TimeSeriesProperty<TYPE>::nthValue(int n) const {
   }
 
   // 2. Sort and apply filter
-  sort();
+  sortIfNecessary();
 
   if (m_filter.empty()) {
     // 3. Situation 1:  No filter
@@ -1541,7 +1540,7 @@ template <typename TYPE> TYPE TimeSeriesProperty<TYPE>::nthValue(int n) const {
  */
 template <typename TYPE>
 Kernel::DateAndTime TimeSeriesProperty<TYPE>::nthTime(int n) const {
-  sort();
+  sortIfNecessary();
 
   if (m_values.empty()) {
     const std::string error("nthTime(): TimeSeriesProperty '" + name() +
@@ -1687,8 +1686,8 @@ template <typename TYPE> std::string TimeSeriesProperty<TYPE>::isValid() const {
 }
 
 /*
- * Not implemented in this class
- * @throw Exception::NotImplementedError Not yet implemented
+ * A TimeSeriesProperty never has a default, so return empty string
+ * @returns Empty string as no defaults can be provided
  */
 template <typename TYPE>
 std::string TimeSeriesProperty<TYPE>::getDefault() const {
@@ -1705,20 +1704,26 @@ template <typename TYPE> bool TimeSeriesProperty<TYPE>::isDefault() const {
 /**
  * Return a TimeSeriesPropertyStatistics struct containing the
  * statistics of this TimeSeriesProperty object.
+ *
+ * N.B. This method DOES take filtering into account
  */
 template <typename TYPE>
 TimeSeriesPropertyStatistics TimeSeriesProperty<TYPE>::getStatistics() const {
   TimeSeriesPropertyStatistics out;
   Mantid::Kernel::Statistics raw_stats =
-      Mantid::Kernel::getStatistics(this->valuesAsVector());
+      Mantid::Kernel::getStatistics(this->filteredValuesAsVector());
   out.mean = raw_stats.mean;
   out.standard_deviation = raw_stats.standard_deviation;
   out.median = raw_stats.median;
   out.minimum = raw_stats.minimum;
   out.maximum = raw_stats.maximum;
   if (this->size() > 0) {
-    out.duration =
-        DateAndTime::secondsFromDuration(this->lastTime() - this->firstTime());
+    const auto &intervals = this->getSplittingIntervals();
+    double duration_sec = 0.0;
+    for (const auto &interval : intervals) {
+      duration_sec += interval.duration();
+    }
+    out.duration = duration_sec;
   } else {
     out.duration = std::numeric_limits<double>::quiet_NaN();
   }
@@ -1732,7 +1737,7 @@ TimeSeriesPropertyStatistics TimeSeriesProperty<TYPE>::getStatistics() const {
  */
 template <typename TYPE> void TimeSeriesProperty<TYPE>::eliminateDuplicates() {
   // 1. Sort if necessary
-  sort();
+  sortIfNecessary();
 
   // 2. Detect and Remove Duplicated
   size_t numremoved = 0;
@@ -1786,9 +1791,11 @@ std::string TimeSeriesProperty<TYPE>::toString() const {
 
 //----------------------------------------------------------------------------------
 /*
- * Sort vector mP and set the flag
+ * Sort vector mP and set the flag. Only sorts if the values are not already
+ * sorted.
  */
-template <typename TYPE> void TimeSeriesProperty<TYPE>::sort() const {
+template <typename TYPE>
+void TimeSeriesProperty<TYPE>::sortIfNecessary() const {
   if (m_propSortedFlag == TimeSeriesSortStatus::TSUNKNOWN) {
     bool sorted = is_sorted(m_values.begin(), m_values.end());
     if (sorted)
@@ -1818,7 +1825,7 @@ int TimeSeriesProperty<TYPE>::findIndex(Kernel::DateAndTime t) const {
     return 0;
 
   // 1. Sort
-  sort();
+  sortIfNecessary();
 
   // 2. Extreme value
   if (t <= m_values[0].time()) {
@@ -1868,7 +1875,7 @@ int TimeSeriesProperty<TYPE>::upperBound(Kernel::DateAndTime t, int istart,
   }
 
   // 2. Sort
-  sort();
+  sortIfNecessary();
 
   // 3. Construct the pair for comparison and do lower_bound()
   TimeValueUnit<TYPE> temppair(t, m_values[0].value());
@@ -2186,6 +2193,121 @@ void TimeSeriesProperty<std::string>::histogramData(
                            "properties containing strings");
 }
 
+/**
+ * Get a vector of values taking the filter into account.
+ * Values will be excluded if their times lie in a region where the filter is
+ * false.
+ * @returns :: Vector of included values only
+ */
+template <typename TYPE>
+std::vector<TYPE> TimeSeriesProperty<TYPE>::filteredValuesAsVector() const {
+  if (m_filter.empty()) {
+    return this->valuesAsVector(); // no filtering to do
+  }
+
+  std::vector<TYPE> filteredValues;
+
+  if (!m_filterApplied) {
+    applyFilter();
+  }
+
+  sortIfNecessary();
+
+  const auto &valueMap = valueAsCorrectMap();
+  for (const auto &entry : valueMap) {
+    if (isTimeFiltered(entry.first)) {
+      filteredValues.push_back(entry.second);
+    }
+  }
+
+  return filteredValues;
+}
+
+/**
+ * Find out if the given time is included in the filtered data
+ * i.e. it does not lie in an excluded region
+ * @param time :: [input] Time to check
+ * @returns :: True if time is in an included region, false if the filter
+ * excludes it.
+ */
+template <typename TYPE>
+bool TimeSeriesProperty<TYPE>::isTimeFiltered(
+    const Kernel::DateAndTime &time) const {
+  if (m_filter.empty()) {
+    return false; // no filter
+  }
+
+  if (!m_filterApplied) {
+    applyFilter();
+  }
+
+  // Find which range it lives in
+  auto filterEntry = std::lower_bound(
+      m_filter.begin(), m_filter.end(), time,
+      [](const std::pair<Kernel::DateAndTime, bool> &filterEntry,
+         const Kernel::DateAndTime &t) { return filterEntry.first < t; });
+
+  if (filterEntry != m_filter.begin()) {
+    --filterEntry; // get the latest time BEFORE the given time
+  }
+  return filterEntry->second;
+}
+
+/**
+ * Get a list of the splitting intervals, if filtering is enabled.
+ * Otherwise the interval is just first time - last time.
+ * @returns :: Vector of splitting intervals
+ */
+template <typename TYPE>
+std::vector<SplittingInterval>
+TimeSeriesProperty<TYPE>::getSplittingIntervals() const {
+  std::vector<SplittingInterval> intervals;
+  // Case where there is no filter
+  if (m_filter.empty()) {
+    intervals.emplace_back(firstTime(), lastTime());
+    return intervals;
+  }
+
+  if (!m_filterApplied) {
+    applyFilter();
+  }
+
+  // (local reference to use in lambda)
+  const auto &localFilter = m_filter;
+  /// Count along to find the next time in the filter for which value is 'val'
+  const auto findNext = [&localFilter](size_t &index, const bool val) {
+    for (; index < localFilter.size(); ++index) {
+      const auto &entry = localFilter[index];
+      if (entry.second == val) {
+        return entry.first;
+      }
+    }
+    return localFilter.back().first;
+  };
+
+  // Look through filter to find start/stop pairs
+  size_t index = 0;
+  while (index < m_filter.size()) {
+    DateAndTime start, stop;
+    // cppcheck-suppress knownConditionTrueFalse
+    if (index == 0) {
+      if (m_filter[0].second) {
+        start = m_filter[0].first;
+      } else {
+        start = firstTime();
+      }
+    } else {
+      start = findNext(index, true);
+    }
+    stop = findNext(index, false);
+    if (stop != start) { // avoid empty ranges
+      intervals.emplace_back(start, stop);
+    }
+  }
+
+  return intervals;
+}
+
 /// @cond
 // -------------------------- Macro to instantiation concrete types
 // --------------------------------
diff --git a/Framework/Kernel/src/UnitConversion.cpp b/Framework/Kernel/src/UnitConversion.cpp
index ba3b70496dc408b24b89fde535254af8988948c0..765850fdc8a5b08f8c68e11fee53ca970f39c0e3 100644
--- a/Framework/Kernel/src/UnitConversion.cpp
+++ b/Framework/Kernel/src/UnitConversion.cpp
@@ -13,7 +13,7 @@ namespace Kernel {
  * @param srcValue :: The value to convert
  *  @param l1 ::       The source-sample distance (in metres)
  *  @param l2 ::       The sample-detector distance (in metres)
- *  @param twoTheta :: The scattering angle (in radians)
+ *  @param theta :: The scattering angle (in radians)
  *  @param emode ::    The energy mode enumeration
  *  @param efixed ::   Value of fixed energy: EI (emode=1) or EF (emode=2) (in
  * meV)
@@ -21,11 +21,11 @@ namespace Kernel {
  */
 double UnitConversion::run(const std::string &src, const std::string &dest,
                            const double srcValue, const double l1,
-                           const double l2, const double twoTheta,
+                           const double l2, const double theta,
                            const DeltaEMode::Type emode, const double efixed) {
   Unit_sptr srcUnit = UnitFactory::Instance().create(src);
   Unit_sptr destUnit = UnitFactory::Instance().create(dest);
-  return UnitConversion::run(*srcUnit, *destUnit, srcValue, l1, l2, twoTheta,
+  return UnitConversion::run(*srcUnit, *destUnit, srcValue, l1, l2, theta,
                              emode, efixed);
 }
 
@@ -36,34 +36,33 @@ double UnitConversion::run(const std::string &src, const std::string &dest,
  * @param srcValue :: The value to convert
  * @param l1 ::       The source-sample distance (in metres)
  * @param l2 ::       The sample-detector distance (in metres)
- * @param twoTheta :: The scattering angle (in radians)
+ * @param theta :: The scattering angle (in radians)
  * @param emode ::    The energy mode enumeration
  * @param efixed ::   Value of fixed energy: EI (emode=1) or EF (emode=2) (in
  * meV)
  * @return The value converted to the destination unit
  */
 double UnitConversion::run(Unit &srcUnit, Unit &destUnit, const double srcValue,
-                           const double l1, const double l2,
-                           const double twoTheta, const DeltaEMode::Type emode,
-                           const double efixed) {
+                           const double l1, const double l2, const double theta,
+                           const DeltaEMode::Type emode, const double efixed) {
   double factor(0.0), power(0.0);
   if (srcUnit.quickConversion(destUnit, factor, power)) {
     return convertQuickly(srcValue, factor, power);
   } else {
-    return convertViaTOF(srcUnit, destUnit, srcValue, l1, l2, twoTheta, emode,
+    return convertViaTOF(srcUnit, destUnit, srcValue, l1, l2, theta, emode,
                          efixed);
   }
 }
 
 /**
  * Convert a single value between the given units (overload for Unit objects)
- * @param twoTheta :: The scattering angle (in radians)
+ * @param theta :: The scattering angle (in radians)
  * @param efixed ::   Value of fixed energy: EI (emode=1) or EF (emode=2) (in
  * meV)
  * @return The value converted to the destination unit
  */
-double UnitConversion::run(const double twoTheta, const double efixed) {
-  return convertToElasticQ(twoTheta, efixed);
+double UnitConversion::run(const double theta, const double efixed) {
+  return convertToElasticQ(theta, efixed);
 }
 
 //---------------------------------------------------------------------------------------------
@@ -89,7 +88,7 @@ double UnitConversion::convertQuickly(const double srcValue,
  * @param srcValue :: The value to convert
  * @param l1 ::       The source-sample distance (in metres)
  * @param l2 ::       The sample-detector distance (in metres)
- * @param twoTheta :: The scattering angle (in radians)
+ * @param theta :: The scattering angle (in radians)
  * @param emode ::    The energy mode enumeration
  * @param efixed ::   Value of fixed energy: EI (emode=1) or EF (emode=2) (in
  * meV)
@@ -97,7 +96,7 @@ double UnitConversion::convertQuickly(const double srcValue,
  */
 double UnitConversion::convertViaTOF(Unit &srcUnit, Unit &destUnit,
                                      const double srcValue, const double l1,
-                                     const double l2, const double twoTheta,
+                                     const double l2, const double theta,
                                      const DeltaEMode::Type emode,
                                      const double efixed) {
   // Translate the emode to the int formulation
@@ -119,27 +118,27 @@ double UnitConversion::convertViaTOF(Unit &srcUnit, Unit &destUnit,
   };
 
   const double unused(0.0);
-  const double tof = srcUnit.convertSingleToTOF(srcValue, l1, l2, twoTheta,
+  const double tof = srcUnit.convertSingleToTOF(srcValue, l1, l2, theta,
                                                 emodeAsInt, efixed, unused);
-  return destUnit.convertSingleFromTOF(tof, l1, l2, twoTheta, emodeAsInt,
-                                       efixed, unused);
+  return destUnit.convertSingleFromTOF(tof, l1, l2, theta, emodeAsInt, efixed,
+                                       unused);
 }
 
 /**
  *  Convert a to ElasticQ
- *  @param twoTheta :: The scattering angle (in radians)
+ *  @param theta :: The scattering angle (in radians)
  *  @param efixed ::   Value of fixed energy: EI (emode=1) or EF (emode=2) (in
  * meV)
  * @return The value converted to ElasticQ
  */
-double UnitConversion::convertToElasticQ(const double twoTheta,
+double UnitConversion::convertToElasticQ(const double theta,
                                          const double efixed) {
 
   Mantid::Kernel::Units::Energy energyUnit;
   double wavelengthFactor(0.0), wavelengthPower(0.0);
   energyUnit.quickConversion("Wavelength", wavelengthFactor, wavelengthPower);
 
-  const double stheta = std::sin(twoTheta);
+  const double stheta = std::sin(theta);
   // Calculate the wavelength to allow it to be used to convert to elasticQ.
   double wavelength = wavelengthFactor * std::pow(efixed, wavelengthPower);
   // The MomentumTransfer value.
diff --git a/Framework/Kernel/src/V2D.cpp b/Framework/Kernel/src/V2D.cpp
index f53139dcea3b9b9a8a3e4bc4e302a87f6ece8a35..85545693ba479ab623c3fc70d18ca3d018bd7adf 100644
--- a/Framework/Kernel/src/V2D.cpp
+++ b/Framework/Kernel/src/V2D.cpp
@@ -1,9 +1,7 @@
-//-----------------------------------------------------------------------------
-// Includes
-//-----------------------------------------------------------------------------
 #include "MantidKernel/V2D.h"
 #include "MantidKernel/V3D.h"
 #include "MantidKernel/Exception.h"
+#include <complex>
 #include <limits>
 
 namespace Mantid {
diff --git a/Framework/Kernel/src/V3D.cpp b/Framework/Kernel/src/V3D.cpp
index 163c806efb6edacc0262f686837c8187220852fb..ef0a3bf2d1e7fd76157bc05b62375f2423001829 100644
--- a/Framework/Kernel/src/V3D.cpp
+++ b/Framework/Kernel/src/V3D.cpp
@@ -1,5 +1,6 @@
 #include <cfloat>
 #include <cmath>
+#include <complex>
 #include <vector>
 
 #include "MantidKernel/V3D.h"
diff --git a/Framework/Kernel/src/VMD.cpp b/Framework/Kernel/src/VMD.cpp
index 2d0a526fff2e2208c0ecec8e172dff8271809b2f..c3bddeec97af9e5fd772ed7cc2a13e2dab9f3851 100644
--- a/Framework/Kernel/src/VMD.cpp
+++ b/Framework/Kernel/src/VMD.cpp
@@ -1,10 +1,484 @@
 #include "MantidKernel/VMD.h"
+#include "MantidKernel/StringTokenizer.h"
+#include "MantidKernel/Strings.h"
+#include "MantidKernel/System.h"
+#include "MantidKernel/Tolerance.h"
+#include "MantidKernel/V3D.h"
+#include <algorithm>
+#include <cstddef>
+#include <sstream>
+#include <stdexcept>
 
 using namespace Mantid::Kernel;
 
 namespace Mantid {
 namespace Kernel {
 
+/** Default constructor, build with 1 dimension */
+template <typename TYPE> VMDBase<TYPE>::VMDBase() : nd(1) {
+  data = new TYPE[nd];
+  for (size_t d = 0; d < nd; d++)
+    data[d] = TYPE(0.0);
+}
+
+/** Constructor
+ * @param nd :: number of dimensions  */
+template <typename TYPE> VMDBase<TYPE>::VMDBase(size_t nd) : nd(nd) {
+  if (nd <= 0)
+    throw std::invalid_argument("nd must be > 0");
+  data = new TYPE[nd];
+  for (size_t d = 0; d < nd; d++)
+    data[d] = TYPE(0.0);
+}
+
+/** 2D Constructor
+ * @param val0 :: value at first dimension
+ * @param val1 :: value at second dimension
+ */
+template <typename TYPE>
+VMDBase<TYPE>::VMDBase(double val0, double val1)
+    : nd(2) {
+  data = new TYPE[nd];
+  data[0] = TYPE(val0);
+  data[1] = TYPE(val1);
+}
+
+/** 3D Constructor
+ * @param val0 :: value at first dimension
+ * @param val1 :: value at second dimension
+ * @param val2 :: value at third dimension
+ */
+template <typename TYPE>
+VMDBase<TYPE>::VMDBase(double val0, double val1, double val2)
+    : nd(3) {
+  data = new TYPE[nd];
+  data[0] = TYPE(val0);
+  data[1] = TYPE(val1);
+  data[2] = TYPE(val2);
+}
+
+/** 4D Constructor
+ * @param val0 :: value at first dimension
+ * @param val1 :: value at second dimension
+ * @param val2 :: value at third dimension
+ * @param val3 :: value at fourth dimension
+ */
+template <typename TYPE>
+VMDBase<TYPE>::VMDBase(double val0, double val1, double val2, double val3)
+    : nd(4) {
+  data = new TYPE[nd];
+  data[0] = TYPE(val0);
+  data[1] = TYPE(val1);
+  data[2] = TYPE(val2);
+  data[3] = TYPE(val3);
+}
+
+/** 5D Constructor
+ * @param val0 :: value at first dimension
+ * @param val1 :: value at second dimension
+ * @param val2 :: value at third dimension
+ * @param val3 :: value at fourth dimension
+ * @param val4 :: value at fifth dimension
+ */
+template <typename TYPE>
+VMDBase<TYPE>::VMDBase(double val0, double val1, double val2, double val3,
+                       double val4)
+    : nd(5) {
+  data = new TYPE[nd];
+  data[0] = TYPE(val0);
+  data[1] = TYPE(val1);
+  data[2] = TYPE(val2);
+  data[3] = TYPE(val3);
+  data[4] = TYPE(val4);
+}
+
+/** 6D Constructor
+ * @param val0 :: value at first dimension
+ * @param val1 :: value at second dimension
+ * @param val2 :: value at third dimension
+ * @param val3 :: value at fourth dimension
+ * @param val4 :: value at fifth dimension
+ * @param val5 :: value at sixth dimension
+ */
+template <typename TYPE>
+VMDBase<TYPE>::VMDBase(double val0, double val1, double val2, double val3,
+                       double val4, double val5)
+    : nd(6) {
+  data = new TYPE[nd];
+  data[0] = TYPE(val0);
+  data[1] = TYPE(val1);
+  data[2] = TYPE(val2);
+  data[3] = TYPE(val3);
+  data[4] = TYPE(val4);
+  data[5] = TYPE(val5);
+}
+
+/** Copy constructor
+ * @param other :: other to copy */
+template <typename TYPE>
+VMDBase<TYPE>::VMDBase(const VMDBase &other)
+    : nd(other.nd) {
+  if (nd <= 0)
+    throw std::invalid_argument("nd must be > 0");
+  data = new TYPE[nd];
+  for (size_t d = 0; d < nd; d++)
+    data[d] = other.data[d];
+}
+
+/** Assignment operator
+ * @param other :: copy into this
+ */
+template <typename TYPE>
+VMDBase<TYPE> &VMDBase<TYPE>::operator=(const VMDBase &other) {
+  if ((other.nd) != nd) {
+    nd = other.nd;
+    delete[] data;
+    data = new TYPE[nd];
+  }
+  for (size_t d = 0; d < nd; d++)
+    data[d] = other.data[d];
+  return *this;
+}
+
+/** Constructor
+ * @param nd :: number of dimensions
+ * @param bareData :: pointer to a nd-sized bare data array */
+template <typename TYPE>
+VMDBase<TYPE>::VMDBase(size_t nd, const double *bareData)
+    : nd(nd) {
+  if (nd <= 0)
+    throw std::invalid_argument("nd must be > 0");
+  data = new TYPE[nd];
+  for (size_t d = 0; d < nd; d++)
+    data[d] = TYPE(bareData[d]);
+}
+
+/** Constructor
+ * @param nd :: number of dimensions
+ * @param bareData :: pointer to a nd-sized bare data array */
+template <typename TYPE>
+VMDBase<TYPE>::VMDBase(size_t nd, const float *bareData)
+    : nd(nd) {
+  if (nd <= 0)
+    throw std::invalid_argument("nd must be > 0");
+  data = new TYPE[nd];
+  for (size_t d = 0; d < nd; d++)
+    data[d] = TYPE(bareData[d]);
+}
+
+/** Constructor
+ * @param vector :: V3D */
+template <typename TYPE> VMDBase<TYPE>::VMDBase(const V3D &vector) : nd(3) {
+  data = new TYPE[nd];
+  for (size_t d = 0; d < nd; d++)
+    data[d] = TYPE(vector[d]);
+}
+
+/** Constructor
+ * @param vector :: vector of doubles */
+template <typename TYPE>
+VMDBase<TYPE>::VMDBase(const std::vector<double> &vector)
+    : nd(vector.size()) {
+  if (nd <= 0)
+    throw std::invalid_argument("nd must be > 0");
+  data = new TYPE[nd];
+  for (size_t d = 0; d < nd; d++)
+    data[d] = TYPE(vector[d]);
+}
+
+/** Constructor
+ * @param vector :: vector of floats */
+template <typename TYPE>
+VMDBase<TYPE>::VMDBase(const std::vector<float> &vector)
+    : nd(vector.size()) {
+  if (nd <= 0)
+    throw std::invalid_argument("nd must be > 0");
+  data = new TYPE[nd];
+  for (size_t d = 0; d < nd; d++)
+    data[d] = TYPE(vector[d]);
+}
+
+/** Constructor from string
+ * @param str :: string of comma or space-separated numbers for each component
+ */
+template <typename TYPE> VMDBase<TYPE>::VMDBase(const std::string &str) {
+
+  StringTokenizer strs(str, ", ", StringTokenizer::TOK_IGNORE_EMPTY);
+
+  std::vector<TYPE> vals;
+  std::transform(strs.cbegin(), strs.cend(), std::back_inserter(vals),
+                 [](const std::string &token) {
+                   TYPE v;
+                   if (!Strings::convert(token, v))
+                     throw std::invalid_argument(
+                         "VMDBase: Unable to convert the string '" + token +
+                         "' to a number.");
+                   return v;
+                 });
+
+  nd = vals.size();
+  if (nd <= 0)
+    throw std::invalid_argument("nd must be > 0");
+  data = new TYPE[nd];
+  std::copy(vals.cbegin(), vals.cend(), data);
+}
+
+/// Destructor
+template <typename TYPE> VMDBase<TYPE>::~VMDBase() { delete[] data; }
+
+/// @return the number of dimensions
+template <typename TYPE> size_t VMDBase<TYPE>::getNumDims() const { return nd; }
+
+/// @return the number of dimensions
+template <typename TYPE> size_t VMDBase<TYPE>::size() const { return nd; }
+
+/** @return the value at the index */
+template <typename TYPE>
+const TYPE &VMDBase<TYPE>::operator[](const size_t index) const {
+  return data[index];
+}
+
+/** @return the value at the index */
+template <typename TYPE> TYPE &VMDBase<TYPE>::operator[](const size_t index) {
+  return data[index];
+}
+
+/** @return the bare data array directly. */
+template <typename TYPE> const TYPE *VMDBase<TYPE>::getBareArray() const {
+  return data;
+}
+
+/** Return a simple string representation of the vector
+ * @param separator :: string to place between values, one space is the
+ * default
+ */
+template <typename TYPE>
+std::string VMDBase<TYPE>::toString(const std::string &separator) const {
+  std::ostringstream mess;
+  for (size_t d = 0; d < nd; d++)
+    mess << (d > 0 ? separator : "") << data[d];
+  return mess.str();
+}
+
+/** Get the vector as a vector
+ * @tparam T :: type to convert to (double/float)
+ * @return the vector as a std::vector
+ */
+template <typename TYPE>
+template <class T>
+std::vector<T> VMDBase<TYPE>::toVector() const {
+  typename std::vector<T> out;
+  for (size_t d = 0; d < nd; d++)
+    out.push_back(T(data[d]));
+  return out;
+}
+
+/** Equals operator with tolerance factor
+  @param v :: VMDBase for comparison
+  @return true if the items are equal
+ */
+template <typename TYPE>
+bool VMDBase<TYPE>::operator==(const VMDBase &v) const {
+  if (v.nd != nd)
+    return false;
+  for (size_t d = 0; d < nd; d++)
+    if ((std::fabs(data[d] - v.data[d]) > Tolerance))
+      return false;
+  return true;
+}
+
+/** Not-equals operator with tolerance factor
+  @param v :: VMDBase for comparison
+  @return true if the items are equal
+ */
+template <typename TYPE>
+bool VMDBase<TYPE>::operator!=(const VMDBase &v) const {
+  return !operator==(v);
+}
+
+/** Add two vectors together
+ * @param v :: other vector, must match number of dimensions  */
+template <typename TYPE>
+VMDBase<TYPE> VMDBase<TYPE>::operator+(const VMDBase &v) const {
+  VMDBase out(*this);
+  out += v;
+  return out;
+}
+
+/** Add two vectors together
+ * @param v :: other vector, must match number of dimensions  */
+template <typename TYPE>
+VMDBase<TYPE> &VMDBase<TYPE>::operator+=(const VMDBase &v) {
+  if (v.nd != this->nd)
+    throw std::runtime_error("Mismatch in number of dimensions in operation "
+                             "between two VMDBase vectors.");
+  for (size_t d = 0; d < nd; d++)
+    data[d] += v.data[d];
+  return *this;
+}
+
+/** Subtract two vectors
+ * @param v
+ *  :: other vector, must match number of dimensions  */
+template <typename TYPE>
+VMDBase<TYPE> VMDBase<TYPE>::operator-(const VMDBase &v) const {
+  VMDBase out(*this);
+  out -= v;
+  return out;
+}
+
+/** Subtract two vectors
+ * @param v :: other vector, must match number of dimensions  */
+template <typename TYPE>
+VMDBase<TYPE> &VMDBase<TYPE>::operator-=(const VMDBase &v) {
+  if (v.nd != this->nd)
+    throw std::runtime_error("Mismatch in number of dimensions in operation "
+                             "between two VMDBase vectors.");
+  for (size_t d = 0; d < nd; d++)
+    data[d] -= v.data[d];
+  return *this;
+}
+
+/** Inner product of two vectors (element-by-element)
+ * @param v :: other vector, must match number of dimensions  */
+template <typename TYPE>
+VMDBase<TYPE> VMDBase<TYPE>::operator*(const VMDBase &v) const {
+  VMDBase out(*this);
+  out *= v;
+  return out;
+}
+
+/** Inner product of two vectors (element-by-element)
+ * @param v :: other vector, must match number of dimensions  */
+template <typename TYPE>
+VMDBase<TYPE> &VMDBase<TYPE>::operator*=(const VMDBase &v) {
+  if (v.nd != this->nd)
+    throw std::runtime_error("Mismatch in number of dimensions in operation "
+                             "between two VMDBase vectors.");
+  for (size_t d = 0; d < nd; d++)
+    data[d] *= v.data[d];
+  return *this;
+}
+
+/** Inner division of two vectors (element-by-element)
+ * @param v :: other vector, must match number of dimensions  */
+template <typename TYPE>
+VMDBase<TYPE> VMDBase<TYPE>::operator/(const VMDBase &v) const {
+  VMDBase out(*this);
+  out /= v;
+  return out;
+}
+
+/** Inner division of two vectors (element-by-element)
+ * @param v :: other vector, must match number of dimensions  */
+template <typename TYPE>
+VMDBase<TYPE> &VMDBase<TYPE>::operator/=(const VMDBase &v) {
+  if (v.nd != this->nd)
+    throw std::runtime_error("Mismatch in number of dimensions in operation "
+                             "between two VMDBase vectors.");
+  for (size_t d = 0; d < nd; d++)
+    data[d] /= v.data[d];
+  return *this;
+}
+
+/** Multiply by a scalar
+ * @param scalar :: double scalar to multiply each element  */
+template <typename TYPE>
+VMDBase<TYPE> VMDBase<TYPE>::operator*(const double scalar) const {
+  VMDBase out(*this);
+  out *= scalar;
+  return out;
+}
+
+/** Multiply by a scalar
+ * @param scalar :: double scalar to multiply each element  */
+template <typename TYPE>
+VMDBase<TYPE> &VMDBase<TYPE>::operator*=(const double scalar) {
+  for (size_t d = 0; d < nd; d++)
+    data[d] *= TYPE(scalar);
+  return *this;
+}
+
+/** Divide by a scalar
+ * @param scalar :: double scalar to Divide each element  */
+template <typename TYPE>
+VMDBase<TYPE> VMDBase<TYPE>::operator/(const double scalar) const {
+  VMDBase out(*this);
+  out /= scalar;
+  return out;
+}
+
+/** Divide by a scalar
+ * @param scalar :: double scalar to Divide each element  */
+template <typename TYPE>
+VMDBase<TYPE> &VMDBase<TYPE>::operator/=(const double scalar) {
+  for (size_t d = 0; d < nd; d++)
+    data[d] /= TYPE(scalar);
+  return *this;
+}
+
+/** Scalar product of two vectors
+ * @param v :: other vector, must match number of dimensions  */
+template <typename TYPE>
+TYPE VMDBase<TYPE>::scalar_prod(const VMDBase &v) const {
+  TYPE out = 0;
+  if (v.nd != this->nd)
+    throw std::runtime_error("Mismatch in number of dimensions in operation "
+                             "between two VMDBase vectors.");
+  for (size_t d = 0; d < nd; d++)
+    out += (data[d] * v.data[d]);
+  return out;
+}
+
+/** Cross product of two vectors. Only works in 3D
+ * @param v :: other vector, also 3D  */
+template <typename TYPE>
+VMDBase<TYPE> VMDBase<TYPE>::cross_prod(const VMDBase &v) const {
+  if (v.nd != this->nd)
+    throw std::runtime_error("Mismatch in number of dimensions in operation "
+                             "between two VMDBase vectors.");
+  if (v.nd != 3)
+    throw std::runtime_error(
+        "Cross product of vectors only works in 3 dimensions.");
+  V3D a(data[0], data[1], data[2]);
+  V3D b(v.data[0], v.data[1], v.data[2]);
+  V3D c = a.cross_prod(b);
+  VMDBase out(c);
+  return out;
+}
+
+/** @return the length of this vector */
+template <typename TYPE> TYPE VMDBase<TYPE>::length() const {
+  return TYPE(std::sqrt(this->norm2()));
+}
+
+/** @return the length of this vector */
+template <typename TYPE> TYPE VMDBase<TYPE>::norm() const {
+  return this->length();
+}
+
+/** @return the length of this vector */
+template <typename TYPE> TYPE VMDBase<TYPE>::norm2() const {
+  return this->scalar_prod(*this);
+}
+
+/** Normalize this vector to unity length
+ * @return the length of this vector BEFORE normalizing */
+template <typename TYPE> TYPE VMDBase<TYPE>::normalize() {
+  TYPE length = this->length();
+  for (size_t d = 0; d < nd; d++)
+    data[d] /= length;
+  return length;
+}
+
+/** Return the angle between this and another vector
+ *  @param v :: The other vector
+ *  @return The angle between the vectors in radians (0 < theta < pi)
+ */
+template <typename TYPE> TYPE VMDBase<TYPE>::angle(const VMDBase &v) const {
+  return TYPE(acos(this->scalar_prod(v) / (this->norm() * v.norm())));
+}
+
 //-------------------------------------------------------------------------------------------------
 /** Make an orthogonal system with 2 input 3D vectors.
  * Currently only works in 3D!
@@ -117,8 +591,8 @@ VMDBase<TYPE>::getNormalVector(const std::vector<VMDBase<TYPE>> &vectors) {
 }
 
 /// Instantiate VMDBase classes
-template class MANTID_KERNEL_DLL VMDBase<double>;
-template class MANTID_KERNEL_DLL VMDBase<float>;
+template class VMDBase<double>;
+template class VMDBase<float>;
 
 /**
   Prints a text representation of itself
diff --git a/Framework/Kernel/test/ArrayOrderedPairsValidatorTest.h b/Framework/Kernel/test/ArrayOrderedPairsValidatorTest.h
new file mode 100644
index 0000000000000000000000000000000000000000..983c7f8ab2a20de74d69c20822a68d4a13500aea
--- /dev/null
+++ b/Framework/Kernel/test/ArrayOrderedPairsValidatorTest.h
@@ -0,0 +1,49 @@
+#ifndef ARRAYBOUNDEDVALIDATORTEST_H_
+#define ARRAYBOUNDEDVALIDATORTEST_H_
+
+#include "MantidKernel/ArrayOrderedPairsValidator.h"
+#include "MantidKernel/BoundedValidator.h"
+#include <cxxtest/TestSuite.h>
+#include <string>
+#include <vector>
+
+using namespace Mantid::Kernel;
+using namespace std;
+
+class ArrayOrderedPairsValidatorTest : public CxxTest::TestSuite {
+public:
+  void test_double_clone() {
+    IValidator_sptr vd(new ArrayOrderedPairsValidator<double>());
+    IValidator_sptr vvd = vd->clone();
+    TS_ASSERT_DIFFERS(vd, vvd);
+  }
+
+  void test_int_clone() {
+    IValidator_sptr vi(new ArrayOrderedPairsValidator<int>);
+    IValidator_sptr vvi = vi->clone();
+    TS_ASSERT_DIFFERS(vi, vvi);
+  }
+
+  void test_array_validation() {
+    std::vector<int> vec{1, 5, 2, 3, 10, 10};
+    ArrayOrderedPairsValidator<int> validator;
+    TS_ASSERT_EQUALS(validator.isValid(vec), "");
+  }
+
+  void test_array_validation_unordered() {
+    std::vector<int> vec{10, 5, 3, 2, 10, 10};
+    ArrayOrderedPairsValidator<int> validator;
+    TS_ASSERT_EQUALS(
+        validator.isValid(vec),
+        "Pair (10, 5) is not ordered.\nPair (3, 2) is not ordered.\n");
+  }
+
+  void test_array_validation_odd() {
+    std::vector<int> vec{1, 5, 2, 3, 10};
+    ArrayOrderedPairsValidator<int> validator;
+    TS_ASSERT_EQUALS(validator.isValid(vec),
+                     "Array has an odd number of entries (5).");
+  }
+};
+
+#endif // ARRAYBOUNDEDVALIDATORTEST_H_
diff --git a/Framework/Kernel/test/ArrayPropertyTest.h b/Framework/Kernel/test/ArrayPropertyTest.h
index c5ff6e73cdf2f246b3bbd1d3fcc8a20c696fbc9a..1805ef6bad8e34d4a0c6724e90bad05722c0e9f9 100644
--- a/Framework/Kernel/test/ArrayPropertyTest.h
+++ b/Framework/Kernel/test/ArrayPropertyTest.h
@@ -146,6 +146,14 @@ public:
     TS_ASSERT_THROWS(ArrayProperty<double> dd("dd", "aa,bb"), std::bad_cast)
   }
 
+  void testConstructorByString_long() {
+    ArrayProperty<long> prop("long", "0:2,5");
+    TS_ASSERT_EQUALS(prop.operator()()[0], 0);
+    TS_ASSERT_EQUALS(prop.operator()()[1], 1);
+    TS_ASSERT_EQUALS(prop.operator()()[2], 2);
+    TS_ASSERT_EQUALS(prop.operator()()[3], 5);
+  }
+
   void testCopyConstructor() {
     ArrayProperty<int> i = *iProp;
     TS_ASSERT(!i.name().compare("intProp"))
diff --git a/Framework/Kernel/test/FacilitiesTest.h b/Framework/Kernel/test/FacilitiesTest.h
index 25aa2cee8d236b10d70c53d6b3359315a156136b..684bf4d04a79788c547a82bab8acc6673a2c77c1 100644
--- a/Framework/Kernel/test/FacilitiesTest.h
+++ b/Framework/Kernel/test/FacilitiesTest.h
@@ -74,7 +74,6 @@ public:
     TS_ASSERT_EQUALS(fac->extensions()[0], ".xyz");
     TS_ASSERT_EQUALS(fac->preferredExtension(), ".xyz");
     TS_ASSERT(fac->archiveSearch().empty());
-    TS_ASSERT(fac->liveListener().empty());
     TS_ASSERT_EQUALS(fac->instruments().size(), 1);
     TS_ASSERT_EQUALS(fac->instruments().front().name(), "AnInst");
     TS_ASSERT_EQUALS(fac->instruments("Measuring Stuff").front().name(),
@@ -155,9 +154,6 @@ public:
     TS_ASSERT_EQUALS(crysInstr.size(), 1);
     TS_ASSERT_EQUALS(fac->instruments("rubbish category").size(), 0);
 
-    // Test default live listener is empty
-    TS_ASSERT(fac->liveListener().empty())
-
     delete fac;
   }
 
@@ -197,25 +193,6 @@ public:
     delete fac;
   }
 
-  void testListener() {
-    const std::string xmlStr =
-        "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
-        "<facilities>"
-        "  <facility name=\"TESTER\" FileExtensions=\"*.*\" >"
-        "    <livedata listener=\"Listener1\" />"
-        "    <instrument name=\"ABCD\" >"
-        "      <livedata listener=\"Listener2\" />"
-        "      <technique>None</technique>"
-        "    </instrument>"
-        "  </facility>"
-        "</facilities>";
-
-    FacilityInfo *fac = getFacility(xmlStr);
-    TS_ASSERT(fac);
-    TS_ASSERT_EQUALS(fac->liveListener(), "Listener1");
-    delete fac;
-  }
-
 private:
   FacilityInfo *getFacility(const std::string &xmlStr) const {
     Poco::XML::DOMParser parser;
diff --git a/Framework/Kernel/test/InstrumentInfoTest.h b/Framework/Kernel/test/InstrumentInfoTest.h
index d859873ddbae3baf3862ac085a123d9c7b367467..8f65a009ac8bfb0b9c0c522b453d99b873ffdcd2 100644
--- a/Framework/Kernel/test/InstrumentInfoTest.h
+++ b/Framework/Kernel/test/InstrumentInfoTest.h
@@ -55,9 +55,7 @@ public:
         "<facilities>"
         "  <facility name=\"MyFacility\" zeropadding=\"99\" delimiter=\"!\" "
         "FileExtensions=\".xyz\">"
-        "    <livedata listener=\"I'm listening\" />"
         "    <instrument name=\"AnInst\">"
-        "      <livedata address=\"127.0.0.1:99\" />"
         "      <technique>Measuring Stuff</technique>"
         "    </instrument>"
         "  </facility>"
@@ -70,7 +68,6 @@ public:
 
     TS_ASSERT_EQUALS(inst.zeroPadding(123), 99);
     TS_ASSERT_EQUALS(inst.delimiter(), "!");
-    TS_ASSERT_EQUALS(inst.liveListener(), "I'm listening");
 
     delete fac;
   }
@@ -81,10 +78,8 @@ public:
         "<facilities>"
         "  <facility name=\"MyFacility\" zeropadding=\"99\" delimiter=\"!\" "
         "FileExtensions=\".xyz\">"
-        "    <livedata listener=\"I'm listening\" />"
         "    <instrument name=\"AnInst\" delimiter=\"?\" >"
         "      <zeropadding size=\"66\"/>"
-        "      <livedata listener=\"pardon\" />"
         "      <technique>Measuring Stuff</technique>"
         "    </instrument>"
         "  </facility>"
@@ -97,7 +92,6 @@ public:
 
     TS_ASSERT_EQUALS(inst.zeroPadding(123), 66);
     TS_ASSERT_EQUALS(inst.delimiter(), "?");
-    TS_ASSERT_EQUALS(inst.liveListener(), "pardon");
 
     delete fac;
   }
@@ -106,8 +100,11 @@ public:
     const std::string instStr =
         "<instrument name=\"MyInst\" shortname=\"mine\" delimiter=\":\" >"
         "  <zeropadding size=\"8\"/>"
-        "  <livedata listener=\"AListener\" address=\"myinst.facility.gov:99\" "
-        "/>"
+        "  <livedata>"
+        "    <connection name=\"default\" "
+        "                listener=\"AListener\" "
+        "                address=\"myinst.facility.gov:99\" />"
+        "  </livedata>"
         "  <technique>Measuring Stuff</technique>"
         "  <technique>Doing Stuff</technique>"
         "</instrument>";
@@ -268,4 +265,4 @@ private:
     return new FacilityInfo(elem);
   }
 };
-#endif /*MANTID_FACILITIESTEST_H_*/
+#endif // INSTRUMENTINFOTEST_H_
diff --git a/Framework/Kernel/test/LiveListenerInfoTest.h b/Framework/Kernel/test/LiveListenerInfoTest.h
new file mode 100644
index 0000000000000000000000000000000000000000..4c14b1434a7f5d70017e1d35b74f378db5c1d3af
--- /dev/null
+++ b/Framework/Kernel/test/LiveListenerInfoTest.h
@@ -0,0 +1,177 @@
+#ifndef LIVELISTENERINFOTEST_H_
+#define LIVELISTENERINFOTEST_H_
+
+#include <cxxtest/TestSuite.h>
+
+#include "MantidKernel/Exception.h"
+#include "MantidKernel/LiveListenerInfo.h"
+#include "MantidKernel/FacilityInfo.h"
+
+#include <Poco/AutoPtr.h>
+#include <Poco/DOM/DOMParser.h>
+#include <Poco/DOM/Document.h>
+#include <Poco/DOM/Element.h>
+
+using namespace Mantid::Kernel;
+
+class LiveListenerInfoTest : public CxxTest::TestSuite {
+public:
+  void test_xml_throws_no_connection() {
+    TS_ASSERT_THROWS_NOTHING(createMinimalFacility("<livedata />"));
+  }
+
+  void test_xml_empty_connection() {
+    const std::string xml = "<livedata>"
+                            "<connection />"
+                            "</livedata>";
+
+    FacilityInfo *fac = nullptr;
+    TS_ASSERT_THROWS_NOTHING(fac = createMinimalFacility(xml));
+
+    InstrumentInfo inst = fac->instruments().front();
+    LiveListenerInfo info = inst.liveListenerInfo();
+
+    TS_ASSERT_EQUALS(info.name(), "");
+    TS_ASSERT_EQUALS(info.address(), "");
+    TS_ASSERT_EQUALS(info.listener(), "");
+  }
+
+  void test_xml_single_connection() {
+    const std::string xml = "<livedata>"
+                            "<connection name='n' address='a' listener='l' />"
+                            "</livedata>";
+
+    FacilityInfo *fac = nullptr;
+    TS_ASSERT_THROWS_NOTHING(fac = createMinimalFacility(xml));
+
+    InstrumentInfo inst = fac->instruments().front();
+    LiveListenerInfo info = inst.liveListenerInfo();
+
+    TS_ASSERT_EQUALS(info.name(), "n");
+    TS_ASSERT_EQUALS(info.address(), "a");
+    TS_ASSERT_EQUALS(info.listener(), "l");
+  }
+
+  void test_xml_two_connections() {
+    const std::string xml = "<livedata>"
+                            "<connection name='n1' address='a' listener='l' />"
+                            "<connection name='n2' address='A' listener='L' />"
+                            "</livedata>";
+
+    FacilityInfo *fac = nullptr;
+    TS_ASSERT_THROWS_NOTHING(fac = createMinimalFacility(xml));
+
+    InstrumentInfo inst = fac->instruments().front();
+    LiveListenerInfo info;
+
+    info = inst.liveListenerInfo();
+    TS_ASSERT_EQUALS(info.name(), "n1");
+    TS_ASSERT_EQUALS(info.address(), "a");
+    TS_ASSERT_EQUALS(info.listener(), "l");
+
+    info = inst.liveListenerInfo("n1");
+    TS_ASSERT_EQUALS(info.name(), "n1");
+    TS_ASSERT_EQUALS(info.address(), "a");
+    TS_ASSERT_EQUALS(info.listener(), "l");
+
+    info = inst.liveListenerInfo("n2");
+    TS_ASSERT_EQUALS(info.name(), "n2");
+    TS_ASSERT_EQUALS(info.address(), "A");
+    TS_ASSERT_EQUALS(info.listener(), "L");
+
+    TS_ASSERT_THROWS(inst.liveListenerInfo("n3"), std::runtime_error);
+  }
+
+  void test_xml_two_connections_default() {
+    const std::string xml = "<livedata default='n2'>"
+                            "<connection name='n1' address='a' listener='l' />"
+                            "<connection name='n2' address='A' listener='L' />"
+                            "</livedata>";
+
+    FacilityInfo *fac = nullptr;
+    TS_ASSERT_THROWS_NOTHING(fac = createMinimalFacility(xml));
+
+    InstrumentInfo inst = fac->instruments().front();
+    LiveListenerInfo info;
+
+    info = inst.liveListenerInfo();
+    TS_ASSERT_EQUALS(info.name(), "n2");
+    TS_ASSERT_EQUALS(info.address(), "A");
+    TS_ASSERT_EQUALS(info.listener(), "L");
+
+    info = inst.liveListenerInfo("n1");
+    TS_ASSERT_EQUALS(info.name(), "n1");
+    TS_ASSERT_EQUALS(info.address(), "a");
+    TS_ASSERT_EQUALS(info.listener(), "l");
+
+    info = inst.liveListenerInfo("n2");
+    TS_ASSERT_EQUALS(info.name(), "n2");
+    TS_ASSERT_EQUALS(info.address(), "A");
+    TS_ASSERT_EQUALS(info.listener(), "L");
+
+    TS_ASSERT_THROWS(inst.liveListenerInfo("n3"), std::runtime_error);
+  }
+
+  void test_manual_construction() {
+    TS_ASSERT_THROWS_NOTHING(LiveListenerInfo{});
+
+    LiveListenerInfo info;
+    TS_ASSERT_EQUALS(info.name(), "");
+    TS_ASSERT_EQUALS(info.address(), "");
+    TS_ASSERT_EQUALS(info.listener(), "");
+
+    TS_ASSERT_THROWS_NOTHING(info = LiveListenerInfo("l"));
+    TS_ASSERT_EQUALS(info.name(), "");
+    TS_ASSERT_EQUALS(info.address(), "");
+    TS_ASSERT_EQUALS(info.listener(), "l");
+
+    TS_ASSERT_THROWS_NOTHING(info = LiveListenerInfo("l", "a"));
+    TS_ASSERT_EQUALS(info.name(), "");
+    TS_ASSERT_EQUALS(info.address(), "a");
+    TS_ASSERT_EQUALS(info.listener(), "l");
+
+    TS_ASSERT_THROWS_NOTHING(info = LiveListenerInfo("l", "a", "n"));
+    TS_ASSERT_EQUALS(info.name(), "n");
+    TS_ASSERT_EQUALS(info.address(), "a");
+    TS_ASSERT_EQUALS(info.listener(), "l");
+  }
+
+  void test_equality() {
+    LiveListenerInfo info1("l", "a", "n");
+    LiveListenerInfo info2 = info1;
+
+    TS_ASSERT_EQUALS(info1, info2);
+    TS_ASSERT_EQUALS(info1.name(), info2.name());
+    TS_ASSERT_EQUALS(info1.address(), info2.address());
+    TS_ASSERT_EQUALS(info1.listener(), info2.listener());
+
+    LiveListenerInfo info3;
+    TS_ASSERT_DIFFERS(info1, info3);
+  }
+
+private:
+  FacilityInfo *createMinimalFacility(const std::string &livedataXml) {
+    const std::string xmlStr =
+        "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+        "<facilities>"
+        "  <facility name=\"MyFacility\" FileExtensions=\".xyz\">"
+        "    <instrument name=\"INST\">"
+        "      <technique>Technique</technique>" +
+        livedataXml + "    </instrument>"
+                      "  </facility>"
+                      "</facilities>";
+
+    return createFacility(xmlStr);
+  }
+
+  FacilityInfo *createFacility(const std::string &xml) {
+    Poco::XML::DOMParser parser;
+    Poco::AutoPtr<Poco::XML::Document> pDoc = parser.parseString(xml);
+    Poco::XML::Element *pRootElem = pDoc->documentElement();
+    Poco::XML::Element *elem = pRootElem->getChildElement("facility");
+
+    return new FacilityInfo(elem);
+  }
+};
+
+#endif // LIVELISTENERINFOTEST_H_
diff --git a/Framework/Kernel/test/LogParserTest.h b/Framework/Kernel/test/LogParserTest.h
index 10694ec8978ec232cb03c597e437a3513f783fe7..81249f6310179910c36cb207b8b8d0befe63d6e0 100644
--- a/Framework/Kernel/test/LogParserTest.h
+++ b/Framework/Kernel/test/LogParserTest.h
@@ -10,6 +10,8 @@
 #include "MantidKernel/make_unique.h"
 #include "MantidKernel/PropertyWithValue.h"
 #include "MantidKernel/TimeSeriesProperty.h"
+#include <boost/lexical_cast.hpp>
+#include <boost/scoped_ptr.hpp>
 
 #include <Poco/File.h>
 
@@ -694,9 +696,8 @@ private:
     const auto *prop_with_value =
         dynamic_cast<PropertyWithValue<int> *>(prop.get());
 
-    int value;
     TS_ASSERT(prop_with_value != NULL);
-    Mantid::Kernel::toValue<int>(prop_with_value->value(), value);
+    int value = boost::lexical_cast<int>(prop_with_value->value());
     TS_ASSERT_EQUALS(expected_period, value);
   }
 
diff --git a/Framework/Kernel/test/NormalDistributionTest.h b/Framework/Kernel/test/NormalDistributionTest.h
new file mode 100644
index 0000000000000000000000000000000000000000..7e06c8d8d2c3d5271615678dcc6bcb261ab24941
--- /dev/null
+++ b/Framework/Kernel/test/NormalDistributionTest.h
@@ -0,0 +1,67 @@
+#ifndef NORMALDISTRIBUTIONTEST_H_
+#define NORMALDISTRIBUTIONTEST_H_
+
+#include <cxxtest/TestSuite.h>
+#include "MantidKernel/NormalDistribution.h"
+
+using Mantid::Kernel::NormalDistribution;
+
+class NormalDistributionTest : public CxxTest::TestSuite {
+
+public:
+  void test_That_Object_Construction_Does_Not_Throw() {
+    TS_ASSERT_THROWS_NOTHING(NormalDistribution());
+    TS_ASSERT_THROWS_NOTHING(NormalDistribution(2.0, 1.1));
+    TS_ASSERT_THROWS_NOTHING(NormalDistribution(1, 2.0, 1.1));
+  }
+
+  void test_bad_input() {
+    TS_ASSERT_THROWS(NormalDistribution(1.0, 0.0), std::runtime_error);
+#ifdef NDEBUG
+    // In debug assert in boost code calls abort()
+    TS_ASSERT_THROWS(NormalDistribution(1.0, -1.0), std::runtime_error);
+#endif // NDEBUG
+  }
+
+  void test_standard_normal_distribution() {
+    NormalDistribution norm;
+    norm.setSeed(1);
+    size_t in(0), out(0);
+    for (size_t i = 0; i < 100; ++i) {
+      auto value = norm.nextValue();
+      if (std::fabs(value) < 1.0) {
+        ++in;
+      } else {
+        ++out;
+      }
+    }
+#ifdef _WIN32
+    TS_ASSERT_EQUALS(in, 67);
+    TS_ASSERT_EQUALS(out, 33);
+#else
+    TS_ASSERT_LESS_THAN(out, in);
+#endif
+  }
+
+  void test_normal_distribution() {
+    NormalDistribution norm(30.0, 5.0);
+    norm.setSeed(2);
+    size_t in(0), out(0);
+    for (size_t i = 0; i < 100; ++i) {
+      auto value = (norm.nextValue() - 30.0) / 5.0;
+      if (std::fabs(value) < 1.0) {
+        ++in;
+      } else {
+        ++out;
+      }
+    }
+#ifdef _WIN32
+    TS_ASSERT_EQUALS(in, 58);
+    TS_ASSERT_EQUALS(out, 42);
+#else
+    TS_ASSERT_LESS_THAN(out, in);
+#endif
+  }
+};
+
+#endif // NORMALDISTRIBUTIONTEST_H_
diff --git a/Framework/Kernel/test/PropertyWithValueTest.h b/Framework/Kernel/test/PropertyWithValueTest.h
index 147806b007028cd555fc3283758ff4edf90766de..ad414b6601916b6ad457e779d6bc4c95a8b5b0bf 100644
--- a/Framework/Kernel/test/PropertyWithValueTest.h
+++ b/Framework/Kernel/test/PropertyWithValueTest.h
@@ -23,7 +23,7 @@ public:
     iProp = new PropertyWithValue<int>("intProp", 1);
     dProp = new PropertyWithValue<double>("doubleProp", 9.99);
     sProp = new PropertyWithValue<std::string>("stringProp", "theValue");
-    lProp = new PropertyWithValue<long long>("int64Prop", -9876543210987654LL);
+    lProp = new PropertyWithValue<int64_t>("int64Prop", -9876543210987654LL);
     bProp = new PropertyWithValue<OptionalBool>("boolProp", bool(true));
   }
 
@@ -54,7 +54,7 @@ public:
 
     TS_ASSERT(!lProp->name().compare("int64Prop"));
     TS_ASSERT(!lProp->documentation().compare(""));
-    TS_ASSERT(typeid(long long) == *lProp->type_info());
+    TS_ASSERT(typeid(int64_t) == *lProp->type_info());
     TS_ASSERT(lProp->isDefault());
 
     TS_ASSERT(!bProp->name().compare("boolProp"));
@@ -148,7 +148,7 @@ public:
     TS_ASSERT_EQUALS(s.setValue("it works"), "");
     TS_ASSERT_EQUALS(s.operator()(), "it works");
 
-    PropertyWithValue<long long> l("test", 1);
+    PropertyWithValue<int64_t> l("test", 1);
     TS_ASSERT_EQUALS(l.setValue("10"), "");
     TS_ASSERT_EQUALS(l, 10);
     TS_ASSERT_EQUALS(l.setValue("1234567890123456"), "");
@@ -164,17 +164,23 @@ public:
 
 private:
   class DataObjectOne : public DataItem {
-    const std::string name() const override { return "MyName1"; };
+    const std::string &getName() const override { return m_name; };
     const std::string id() const override { return "DataObjectOne"; }
     bool threadSafe() const override { return true; }
-    const std::string toString() const override { return name(); }
+    const std::string toString() const override { return m_name; }
+
+  private:
+    std::string m_name{"MyName1"};
   };
 
   class DataObjectTwo : public DataItem {
-    const std::string name() const override { return "MyName2"; };
+    const std::string &getName() const override { return m_name; };
     const std::string id() const override { return "DataObjectTwo"; }
     bool threadSafe() const override { return true; }
-    const std::string toString() const override { return name(); }
+    const std::string toString() const override { return m_name; }
+
+  private:
+    std::string m_name{"MyName2"};
   };
 
 public:
@@ -194,7 +200,7 @@ public:
             i.type());
     TS_ASSERT_EQUALS(i.getDefault(), "3");
 
-    PropertyWithValue<long long> l("defau1", 987987987987LL);
+    PropertyWithValue<int64_t> l("defau1", 987987987987LL);
     TS_ASSERT_EQUALS(l.getDefault(), "987987987987");
     TS_ASSERT_EQUALS(l.setValue("5"), "");
     TS_ASSERT_EQUALS(l.getDefault(), "987987987987");
@@ -242,10 +248,10 @@ public:
     TS_ASSERT(s.isDefault());
     TS_ASSERT_EQUALS(sProp->operator()(), "theValue");
 
-    PropertyWithValue<long long> l = *lProp;
+    PropertyWithValue<int64_t> l = *lProp;
     TS_ASSERT(!lProp->name().compare("int64Prop"));
     TS_ASSERT(!lProp->documentation().compare(""));
-    TS_ASSERT(typeid(long long) == *lProp->type_info());
+    TS_ASSERT(typeid(int64_t) == *lProp->type_info());
     TS_ASSERT(lProp->isDefault());
     TS_ASSERT_EQUALS(l, -9876543210987654LL);
   }
@@ -272,7 +278,7 @@ public:
     TS_ASSERT(!s.isDefault());
     TS_ASSERT_EQUALS(sProp->operator()(), "theValue");
 
-    PropertyWithValue<long long> l("Prop4", 5);
+    PropertyWithValue<int64_t> l("Prop4", 5);
     l = *lProp;
     TS_ASSERT(!l.name().compare("Prop4"));
     TS_ASSERT(!l.documentation().compare(""));
@@ -300,7 +306,7 @@ public:
     s = "testing";
     TS_ASSERT(i.isDefault());
 
-    PropertyWithValue<long long> l("Prop4", 987987987987LL);
+    PropertyWithValue<int64_t> l("Prop4", 987987987987LL);
     TS_ASSERT_EQUALS(l = 2, 2);
     TS_ASSERT(!l.isDefault());
     l = 987987987987LL;
@@ -321,7 +327,7 @@ public:
     TS_ASSERT_EQUALS(ss.operator()(), "tested");
     TS_ASSERT_EQUALS(s.operator()(), "tested");
 
-    PropertyWithValue<long long> ll("Prop4.4", 6);
+    PropertyWithValue<int64_t> ll("Prop4.4", 6);
     l = ll = 789789789789LL;
     TS_ASSERT_EQUALS(ll, 789789789789LL);
     TS_ASSERT_EQUALS(l, 789789789789LL);
@@ -368,7 +374,7 @@ public:
     TS_ASSERT_EQUALS(d, 9.99);
     std::string str = *sProp;
     TS_ASSERT(!str.compare("theValue"));
-    long long l = *lProp;
+    int64_t l = *lProp;
     TS_ASSERT_EQUALS(l, -9876543210987654LL);
   }
 
@@ -419,7 +425,7 @@ public:
 
     TS_ASSERT_DIFFERS(dynamic_cast<Property *>(lProp),
                       static_cast<Property *>(0));
-    PropertyWithValue<long long> l("Prop4", 789789789789LL);
+    PropertyWithValue<int64_t> l("Prop4", 789789789789LL);
     Property *pppp = dynamic_cast<Property *>(&l);
     TS_ASSERT(!pppp->name().compare("Prop4"));
     TS_ASSERT(!pppp->value().compare("789789789789"));
@@ -500,9 +506,9 @@ public:
     TS_ASSERT_EQUALS(ps.isValid(), "");
 
     // int64 tests
-    PropertyWithValue<long long> pl(
+    PropertyWithValue<int64_t> pl(
         "test", 987987987987LL,
-        boost::make_shared<BoundedValidator<long long>>(0, 789789789789LL));
+        boost::make_shared<BoundedValidator<int64_t>>(0, 789789789789LL));
     TS_ASSERT_EQUALS(pl.isValid(), start + "987987987987" + greaterThan +
                                        "789789789789" + end);
     TS_ASSERT_EQUALS(pl.setValue("-1"), start + "-1" + lessThan + "0" + end);
@@ -739,7 +745,7 @@ private:
   PropertyWithValue<int> *iProp;
   PropertyWithValue<double> *dProp;
   PropertyWithValue<std::string> *sProp;
-  PropertyWithValue<long long> *lProp;
+  PropertyWithValue<int64_t> *lProp;
   PropertyWithValue<OptionalBool> *bProp;
 };
 
diff --git a/Framework/Kernel/test/ReadLockTest.h b/Framework/Kernel/test/ReadLockTest.h
index 5ba6b4ba0788fbfdaf6cd80655454033e08da676..348aaed4661654baf9abcfefdafd65cd1bd3f65d 100644
--- a/Framework/Kernel/test/ReadLockTest.h
+++ b/Framework/Kernel/test/ReadLockTest.h
@@ -13,12 +13,15 @@ class MockDataItem : public DataItem {
 public:
   const std::string id() const override { return "MockDataItem"; }
   /// The name of the object
-  const std::string name() const override { return "Noone"; }
+  const std::string &getName() const override { return m_name; }
   /// Can this object be accessed from multiple threads safely
   bool threadSafe() const override { return true; }
   /// Serializes the object to a string
   const std::string toString() const override { return "Nothing"; }
   friend class ReadLockTest;
+
+private:
+  std::string m_name{"Noone"};
 };
 
 class ReadLockTest : public CxxTest::TestSuite {
diff --git a/Framework/Kernel/test/StringsTest.h b/Framework/Kernel/test/StringsTest.h
index 105ae299476c848e555d89fd49a7195b707cd36b..e233c2e033b914cb867843108afd447dae65a185 100644
--- a/Framework/Kernel/test/StringsTest.h
+++ b/Framework/Kernel/test/StringsTest.h
@@ -419,18 +419,23 @@ public:
   }
 
   void test_toString_vector_of_ints() {
-    std::vector<int> sortedInts;
-    sortedInts.push_back(1);
-    sortedInts.push_back(2);
-    sortedInts.push_back(3);
-    sortedInts.push_back(5);
-    sortedInts.push_back(6);
-    sortedInts.push_back(8);
-
+    std::vector<int> sortedInts{1, 2, 3, 5, 6, 8};
     auto result = toString(sortedInts);
-
     TS_ASSERT_EQUALS(std::string("1-3,5-6,8"), result);
   }
+
+  void test_getLine() {
+    std::istringstream text("blah blah\nfoo bar#comment\n");
+    std::string line = getLine(text);
+    TSM_ASSERT_EQUALS("Strings::getLine failed to read the first line.", line,
+                      "blah blah");
+    getLine(text, line);
+    TSM_ASSERT_EQUALS("Strings::getLine failed to remove comment.", line,
+                      "foo bar");
+    getLine(text, line);
+    TSM_ASSERT_EQUALS("Strings::getLine didn't return empty string after eof.",
+                      line, "");
+  }
 };
 
 #endif // MANTID_SUPPORTTEST_H_
diff --git a/Framework/Kernel/test/TimeSeriesPropertyTest.h b/Framework/Kernel/test/TimeSeriesPropertyTest.h
index 90e0693bdb573820429d4ef4ca5782368dacacc9..764ce1f79f96072e80baf172fc774132e52ce6b5 100644
--- a/Framework/Kernel/test/TimeSeriesPropertyTest.h
+++ b/Framework/Kernel/test/TimeSeriesPropertyTest.h
@@ -4,6 +4,7 @@
 #include <cxxtest/TestSuite.h>
 #include "MantidKernel/TimeSeriesProperty.h"
 #include "MantidKernel/Exception.h"
+#include "MantidKernel/make_unique.h"
 #include "MantidKernel/PropertyWithValue.h"
 #include "MantidKernel/TimeSplitter.h"
 
@@ -702,6 +703,7 @@ public:
     TS_ASSERT_DELTA(stats.mean, 6.0, 1e-3);
     TS_ASSERT_DELTA(stats.duration, 100.0, 1e-3);
     TS_ASSERT_DELTA(stats.standard_deviation, 3.1622, 1e-3);
+    TS_ASSERT_DELTA(log->timeAverageValue(), 5.5, 1e-3);
 
     delete log;
   }
@@ -1923,7 +1925,130 @@ public:
     delete log;
   }
 
+  /// Test that getStatistics respects the filter
+  void test_getStatistics_filtered() {
+    const auto &log = getFilteredTestLog();
+
+    // Get the stats and compare to expected values
+    const auto &stats = log->getStatistics();
+    TS_ASSERT_DELTA(stats.minimum, 1.0, 1e-6);
+    TS_ASSERT_DELTA(stats.maximum, 10.0, 1e-6);
+    TS_ASSERT_DELTA(stats.median, 6.0, 1e-6);
+    TS_ASSERT_DELTA(stats.mean, 5.77778, 1e-3);
+    TS_ASSERT_DELTA(stats.duration, 85.0, 1e-6);
+    TS_ASSERT_DELTA(stats.standard_deviation, 2.8974, 1e-4);
+  }
+
+  /// Test that timeAverageValue respects the filter
+  void test_timeAverageValue_filtered() {
+    const auto &log = getFilteredTestLog();
+    TS_ASSERT_DELTA(log->timeAverageValue(), 5.588, 1e-3);
+  }
+
+  void test_filteredValuesAsVector() {
+    const auto &log = getFilteredTestLog();
+
+    const auto &unfilteredValues = log->valuesAsVector();
+    const auto &filteredValues = log->filteredValuesAsVector();
+
+    TS_ASSERT_DIFFERS(unfilteredValues.size(), filteredValues.size());
+    TS_ASSERT_EQUALS(unfilteredValues.size(), 11);
+    TS_ASSERT_EQUALS(filteredValues.size(), 9);
+  }
+
+  void test_getSplittingIntervals_noFilter() {
+    const auto &log = getTestLog(); // no filter
+    const auto &intervals = log->getSplittingIntervals();
+    TS_ASSERT_EQUALS(intervals.size(), 1);
+    const auto &range = intervals.front();
+    TS_ASSERT_EQUALS(range.start(), log->firstTime());
+    TS_ASSERT_EQUALS(range.stop(), log->lastTime());
+  }
+
+  void test_getSplittingIntervals_repeatedEntries() {
+    const auto &log = getTestLog();
+    // Add the filter
+    auto filter =
+        Mantid::Kernel::make_unique<TimeSeriesProperty<bool>>("Filter");
+    Mantid::Kernel::DateAndTime firstStart("2007-11-30T16:17:00"),
+        firstEnd("2007-11-30T16:17:15"), secondStart("2007-11-30T16:18:35"),
+        secondEnd("2007-11-30T16:18:40");
+    filter->addValue(firstStart.toISO8601String(), true);
+    filter->addValue(firstEnd.toISO8601String(), false);
+    filter->addValue("2007-11-30T16:17:25", false);
+    filter->addValue(secondStart.toISO8601String(), true);
+    filter->addValue("2007-11-30T16:18:38", true);
+    filter->addValue(secondEnd.toISO8601String(), false);
+    log->filterWith(filter.get());
+    const auto &intervals = log->getSplittingIntervals();
+    TS_ASSERT_EQUALS(intervals.size(), 2);
+    if (intervals.size() == 2) {
+      const auto &firstRange = intervals.front(),
+                 &secondRange = intervals.back();
+      TS_ASSERT_EQUALS(firstRange.start(), firstStart);
+      TS_ASSERT_EQUALS(firstRange.stop(), firstEnd);
+      TS_ASSERT_EQUALS(secondRange.start(), secondStart);
+      TS_ASSERT_EQUALS(secondRange.stop(), secondEnd);
+    }
+  }
+
+  void test_getSplittingIntervals_startEndTimes() {
+    const auto &log = getTestLog();
+    // Add the filter
+    auto filter =
+        Mantid::Kernel::make_unique<TimeSeriesProperty<bool>>("Filter");
+    Mantid::Kernel::DateAndTime firstEnd("2007-11-30T16:17:05"),
+        secondStart("2007-11-30T16:17:10"), secondEnd("2007-11-30T16:17:15"),
+        thirdStart("2007-11-30T16:18:35");
+    filter->addValue(log->firstTime(), true);
+    filter->addValue(firstEnd.toISO8601String(), false);
+    filter->addValue(secondStart.toISO8601String(), true);
+    filter->addValue(secondEnd.toISO8601String(), false);
+    filter->addValue(thirdStart.toISO8601String(), true);
+    log->filterWith(filter.get());
+    const auto &intervals = log->getSplittingIntervals();
+    TS_ASSERT_EQUALS(intervals.size(), 3);
+    if (intervals.size() == 3) {
+      TS_ASSERT_EQUALS(intervals[0].start(), log->firstTime());
+      TS_ASSERT_EQUALS(intervals[0].stop(), firstEnd);
+      TS_ASSERT_EQUALS(intervals[1].start(), secondStart);
+      TS_ASSERT_EQUALS(intervals[1].stop(), secondEnd);
+      TS_ASSERT_EQUALS(intervals[2].start(), thirdStart);
+      TS_ASSERT(intervals[2].stop() > thirdStart);
+    }
+  }
+
 private:
+  /// Generate a test log
+  std::unique_ptr<TimeSeriesProperty<double>> getTestLog() {
+    // Build the log
+    auto log =
+        Mantid::Kernel::make_unique<TimeSeriesProperty<double>>("DoubleLog");
+    Mantid::Kernel::DateAndTime logTime("2007-11-30T16:17:00");
+    const double incrementSecs(10.0);
+    for (int i = 1; i < 12; ++i) {
+      const double val = static_cast<double>(i);
+      log->addValue(logTime.toISO8601String(), val);
+      logTime += incrementSecs;
+    }
+    return log;
+  }
+
+  /// Generate a test log that has been filtered
+  std::unique_ptr<TimeSeriesProperty<double>> getFilteredTestLog() {
+    // Build the log
+    auto log = getTestLog();
+    // Add the filter
+    auto filter =
+        Mantid::Kernel::make_unique<TimeSeriesProperty<bool>>("Filter");
+    filter->addValue("2007-11-30T16:17:00", true);
+    filter->addValue("2007-11-30T16:17:15", false);
+    filter->addValue("2007-11-30T16:17:25", true);
+    filter->addValue("2007-11-30T16:18:35", false);
+    log->filterWith(filter.get());
+    return log;
+  }
+
   TimeSeriesProperty<int> *iProp;
   TimeSeriesProperty<double> *dProp;
   TimeSeriesProperty<std::string> *sProp;
diff --git a/Framework/Kernel/test/TypedValidatorTest.h b/Framework/Kernel/test/TypedValidatorTest.h
index 9e19b13d2a7a9bf72f19f78f99bbaf707e18d1c8..1f30741db24eb6ec59a98131c1977ab74200e4da 100644
--- a/Framework/Kernel/test/TypedValidatorTest.h
+++ b/Framework/Kernel/test/TypedValidatorTest.h
@@ -24,9 +24,12 @@ DECLARE_TEST_VALIDATOR(PODTypedValidator, double)
 class FakeDataItem : public Mantid::Kernel::DataItem {
 public:
   const std::string id() const override { return "FakeDataItem"; }
-  const std::string name() const override { return "Empty"; }
+  const std::string &getName() const override { return m_name; }
   bool threadSafe() const override { return true; }
   const std::string toString() const override { return "FakeDataItem{}"; }
+
+private:
+  std::string m_name{"Empty"};
 };
 DECLARE_TEST_VALIDATOR(DataItemSptrTypedValidator,
                        boost::shared_ptr<FakeDataItem>)
diff --git a/Framework/Kernel/test/UnitConversionTest.h b/Framework/Kernel/test/UnitConversionTest.h
index 369caac852ad64d24fd85e11192719c38fc3b8c3..39e301bf85ec2ffed54255a6058dccd0c048bbac 100644
--- a/Framework/Kernel/test/UnitConversionTest.h
+++ b/Framework/Kernel/test/UnitConversionTest.h
@@ -57,14 +57,14 @@ public:
     const double srcValue(1.5); // In angstroms
     const std::string &destUnit = "MomentumTransfer";
 
-    const double l1(10.0), l2(1.1), twoTheta(10.0 * M_PI / 180.0), efixed(12.0);
+    const double l1(10.0), l2(1.1), theta(10.0 * M_PI / 180.0), efixed(12.0);
     const DeltaEMode::Type emode = DeltaEMode::Direct;
 
     const double expected(0.437943919458);
     double result(-1.0);
     TS_ASSERT_THROWS_NOTHING(
-        result = UnitConversion::run(srcUnit, destUnit, srcValue, l1, l2,
-                                     twoTheta, emode, efixed));
+        result = UnitConversion::run(srcUnit, destUnit, srcValue, l1, l2, theta,
+                                     emode, efixed));
     TS_ASSERT_DELTA(result, expected, 1e-12);
   }
 };
diff --git a/Framework/Kernel/test/VMDTest.h b/Framework/Kernel/test/VMDTest.h
index 0d550ab59a508ebce516b1ca4b6b48ed55d047b2..7bc51cad7c1bdcc8cfae86655c0096d0aec12c65 100644
--- a/Framework/Kernel/test/VMDTest.h
+++ b/Framework/Kernel/test/VMDTest.h
@@ -7,6 +7,7 @@
 #include <cmath>
 
 #include "MantidKernel/VMD.h"
+#include "MantidKernel/V3D.h"
 
 using namespace Mantid;
 using namespace Mantid::Kernel;
diff --git a/Framework/Kernel/test/WriteLockTest.h b/Framework/Kernel/test/WriteLockTest.h
index 1748b14ddd7614fe5cd5485b4905498fdd9029af..3cdb766a186160698d1d77d3dd96638844bcb976 100644
--- a/Framework/Kernel/test/WriteLockTest.h
+++ b/Framework/Kernel/test/WriteLockTest.h
@@ -13,12 +13,15 @@ class MockDataItem : public DataItem {
 public:
   const std::string id() const override { return "MockDataItem"; }
   /// The name of the object
-  const std::string name() const override { return "Noone"; }
+  const std::string &getName() const override { return m_name; }
   /// Can this object be accessed from multiple threads safely
   bool threadSafe() const override { return true; }
   /// Serializes the object to a string
   const std::string toString() const override { return "Nothing"; }
   friend class WriteLockTest;
+
+private:
+  std::string m_name{"Noone"};
 };
 
 class WriteLockTest : public CxxTest::TestSuite {
diff --git a/Framework/LiveData/inc/MantidLiveData/LiveDataAlgorithm.h b/Framework/LiveData/inc/MantidLiveData/LiveDataAlgorithm.h
index 3c4a9fc1b0cd39bea72ba869f6854807e1e2dc0f..686e453c74050ffa7e531b779d38a2f545d63be0 100644
--- a/Framework/LiveData/inc/MantidLiveData/LiveDataAlgorithm.h
+++ b/Framework/LiveData/inc/MantidLiveData/LiveDataAlgorithm.h
@@ -44,7 +44,8 @@ public:
 
   void copyPropertyValuesFrom(const LiveDataAlgorithm &other);
 
-  Mantid::API::ILiveListener_sptr getLiveListener();
+  Mantid::API::ILiveListener_sptr getLiveListener(bool start = true);
+  Mantid::API::ILiveListener_sptr createLiveListener(bool connect = false);
   void setLiveListener(Mantid::API::ILiveListener_sptr listener);
 
   std::map<std::string, std::string> validateInputs() override;
diff --git a/Framework/LiveData/inc/MantidLiveData/SNSLiveEventDataListener.h b/Framework/LiveData/inc/MantidLiveData/SNSLiveEventDataListener.h
index 82e025b3b54ae0f87acd56e9000e05fed252c51c..6396042255336735245f5b98118910180602c3d1 100644
--- a/Framework/LiveData/inc/MantidLiveData/SNSLiveEventDataListener.h
+++ b/Framework/LiveData/inc/MantidLiveData/SNSLiveEventDataListener.h
@@ -99,9 +99,9 @@ private:
   // complicated and I didn't want to be repeating the same tests in several
   // places...
   bool readyForInitPart2() {
-    if (m_instrumentXML.size() == 0)
+    if (m_instrumentXML.empty())
       return false;
-    if (m_instrumentName.size() == 0)
+    if (m_instrumentName.empty())
       return false;
     if (m_dataStartTime == Kernel::DateAndTime())
       return false;
diff --git a/Framework/LiveData/src/FileEventDataListener.cpp b/Framework/LiveData/src/FileEventDataListener.cpp
index 81ac4301f8688e6673c3ecfd3bd07a5997e78602..e35a1f290d127eab8e97675582fc162d223eb46b 100644
--- a/Framework/LiveData/src/FileEventDataListener.cpp
+++ b/Framework/LiveData/src/FileEventDataListener.cpp
@@ -1,4 +1,5 @@
 #include "MantidLiveData/FileEventDataListener.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/LiveListenerFactory.h"
 #include "MantidAPI/AlgorithmManager.h"
 #include "MantidAPI/FileFinder.h"
diff --git a/Framework/LiveData/src/ISIS/ISISLiveEventDataListener.cpp b/Framework/LiveData/src/ISIS/ISISLiveEventDataListener.cpp
index d1c9d3a3cbf40971be4c285703ef093a746db894..0f0f8e1e88ab50d3a75ad23810b3a1d3423f626e 100644
--- a/Framework/LiveData/src/ISIS/ISISLiveEventDataListener.cpp
+++ b/Framework/LiveData/src/ISIS/ISISLiveEventDataListener.cpp
@@ -8,6 +8,7 @@
 #include "MantidAPI/Run.h"
 #include "MantidAPI/SpectrumDetectorMapping.h"
 #include "MantidAPI/WorkspaceFactory.h"
+#include "MantidAPI/WorkspaceGroup.h"
 
 #include "MantidKernel/DateAndTime.h"
 #include "MantidKernel/TimeSeriesProperty.h"
@@ -182,8 +183,8 @@ boost::shared_ptr<API::Workspace> ISISLiveEventDataListener::extractData() {
                 1));
 
     // Copy geometry over.
-    API::WorkspaceFactory::Instance().initializeFromParent(m_eventBuffer[i],
-                                                           temp, false);
+    API::WorkspaceFactory::Instance().initializeFromParent(*m_eventBuffer[i],
+                                                           *temp, false);
 
     // Clear out the old logs
     temp->mutableRun().clearTimeSeriesLogs();
@@ -363,7 +364,7 @@ void ISISLiveEventDataListener::initEventBuffer(
 
       // Copy geometry over.
       API::WorkspaceFactory::Instance().initializeFromParent(
-          m_eventBuffer[0], m_eventBuffer[i], false);
+          *m_eventBuffer[0], *m_eventBuffer[i], false);
     }
   }
 }
diff --git a/Framework/LiveData/src/LiveDataAlgorithm.cpp b/Framework/LiveData/src/LiveDataAlgorithm.cpp
index 97f346199884739da12d124c3d6e06638beb21ff..1e4d8670c592aba116cbf389b96589f30e703898 100644
--- a/Framework/LiveData/src/LiveDataAlgorithm.cpp
+++ b/Framework/LiveData/src/LiveDataAlgorithm.cpp
@@ -3,6 +3,7 @@
 #include "MantidAPI/FileProperty.h"
 #include "MantidAPI/LiveListenerFactory.h"
 #include "MantidKernel/ArrayProperty.h"
+#include "MantidKernel/ConfigService.h"
 #include "MantidKernel/DateAndTime.h"
 #include "MantidKernel/FacilityInfo.h"
 #include "MantidKernel/ListValidator.h"
@@ -32,22 +33,36 @@ void LiveDataAlgorithm::initProps() {
   auto &instrInfo =
       Kernel::ConfigService::Instance().getFacility().instruments();
   for (const auto &instrument : instrInfo) {
-    if (!instrument.liveDataAddress().empty()) {
+    if (instrument.hasLiveListenerInfo()) {
       instruments.push_back(instrument.name());
     }
   }
-#ifndef NDEBUG
-  // Debug builds only: Add all the listeners by hand for development testing
-  // purposes
-  std::vector<std::string> listeners =
-      Mantid::API::LiveListenerFactory::Instance().getKeys();
-  instruments.insert(instruments.end(), listeners.begin(), listeners.end());
-#endif
+
+  // All available listener class names
+  auto listeners = LiveListenerFactory::Instance().getKeys();
+  listeners.push_back(""); // Allow not specifying a listener too
+
   declareProperty(Kernel::make_unique<PropertyWithValue<std::string>>(
                       "Instrument", "",
                       boost::make_shared<StringListValidator>(instruments)),
                   "Name of the instrument to monitor.");
 
+  declareProperty(make_unique<PropertyWithValue<std::string>>("Connection", "",
+                                                              Direction::Input),
+                  "Selects the listener connection entry to use. "
+                  "Default connection will be used if not specified");
+
+  declareProperty(
+      Kernel::make_unique<PropertyWithValue<std::string>>(
+          "Listener", "", boost::make_shared<StringListValidator>(listeners)),
+      "Name of the listener class to use. "
+      "If specified, overrides class specified by Connection.");
+
+  declareProperty(make_unique<PropertyWithValue<std::string>>("Address", "",
+                                                              Direction::Input),
+                  "Address for the listener to connect to. "
+                  "If specified, overrides address specified by Connection.");
+
   declareProperty(make_unique<PropertyWithValue<std::string>>("StartTime", "",
                                                               Direction::Input),
                   "Absolute start time, if you selected FromTime.\n"
@@ -170,28 +185,66 @@ bool LiveDataAlgorithm::hasPostProcessing() const {
 }
 
 //----------------------------------------------------------------------------------------------
-/** Return or create the ILiveListener for this algorithm.
+/**
+ * Return or create the ILiveListener for this algorithm.
  *
  * If the ILiveListener has not already been created, it creates it using
  * the properties on the algorithm. It then starts the listener
- * by calling the ILiveListener->start(StartTime) method.
+ * by calling the ILiveListener->start(StartTime) method if start is true.
  *
- * @return ILiveListener_sptr
+ * @param start Whether to start data acquisition right away
+ * @return Shared pointer to interface of this algorithm's LiveListener.
  */
-ILiveListener_sptr LiveDataAlgorithm::getLiveListener() {
+ILiveListener_sptr LiveDataAlgorithm::getLiveListener(bool start) {
   if (m_listener)
     return m_listener;
 
-  // Not stored? Need to create it
-  std::string inst = this->getPropertyValue("Instrument");
-  m_listener = LiveListenerFactory::Instance().create(inst, true, this);
+  // Create a new listener
+  m_listener = createLiveListener(start);
 
   // Start at the given date/time
-  m_listener->start(this->getStartTime());
+  if (start)
+    m_listener->start(this->getStartTime());
 
   return m_listener;
 }
 
+/**
+ * Creates a new instance of a LiveListener based on current values of this
+ * algorithm's properties, respecting Facilities.xml defaults as well as any
+ * provided properties to override them.
+ *
+ * The created LiveListener is not stored or cached as this algorithm's
+ * LiveListener. This is useful for creating temporary instances.
+ *
+ * @param connect Whether the created LiveListener should attempt to connect
+ *                immediately after creation.
+ * @return Shared pointer to interface of created LiveListener instance.
+ */
+ILiveListener_sptr LiveDataAlgorithm::createLiveListener(bool connect) {
+  // Get the LiveListenerInfo from Facilities.xml
+  std::string inst_name = this->getPropertyValue("Instrument");
+  std::string conn_name = this->getPropertyValue("Connection");
+
+  const auto &inst = ConfigService::Instance().getInstrument(inst_name);
+  const auto &conn = inst.liveListenerInfo(conn_name);
+
+  // See if listener and/or address override has been specified
+  std::string listener = this->getPropertyValue("Listener");
+  if (listener.empty())
+    listener = conn.listener();
+
+  std::string address = this->getPropertyValue("Address");
+  if (address.empty())
+    address = conn.address();
+
+  // Construct new LiveListenerInfo with overrides, if given
+  LiveListenerInfo info(listener, address);
+
+  // Create and return
+  return LiveListenerFactory::Instance().create(info, connect, this);
+}
+
 //----------------------------------------------------------------------------------------------
 /** Directly set the LiveListener for this algorithm.
  *
@@ -291,9 +344,7 @@ std::map<std::string, std::string> LiveDataAlgorithm::validateInputs() {
   if (m_listener) {
     eventListener = m_listener->buffersEvents();
   } else {
-    eventListener = LiveListenerFactory::Instance()
-                        .create(instrument, false)
-                        ->buffersEvents();
+    eventListener = createLiveListener()->buffersEvents();
   }
   if (!eventListener && getPropertyValue("AccumulationMethod") == "Add") {
     out["AccumulationMethod"] =
diff --git a/Framework/LiveData/src/LoadLiveData.cpp b/Framework/LiveData/src/LoadLiveData.cpp
index 50d6e8d122180aa8b5327b854186b4fbc9333e9b..a556f6c2f5f976ce43cb0c1906f0f27a8371b952 100644
--- a/Framework/LiveData/src/LoadLiveData.cpp
+++ b/Framework/LiveData/src/LoadLiveData.cpp
@@ -4,6 +4,7 @@
 #include "MantidKernel/ReadLock.h"
 #include "MantidAPI/AlgorithmManager.h"
 #include "MantidAPI/Workspace.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidDataObjects/EventWorkspace.h"
 #include "MantidKernel/CPUTimer.h"
 
@@ -373,7 +374,7 @@ void LoadLiveData::doSortEvents(Mantid::API::Workspace_sptr ws) {
   alg->setProperty("InputWorkspace", eventWS);
   alg->setPropertyValue("SortBy", "X Value");
   alg->executeAsChildAlg();
-  g_log.debug() << tim << " to perform SortEvents on " << ws->name() << '\n';
+  g_log.debug() << tim << " to perform SortEvents on " << ws->getName() << '\n';
 }
 
 //----------------------------------------------------------------------------------------------
@@ -508,7 +509,7 @@ void LoadLiveData::exec() {
     size_t n = static_cast<size_t>(out_gws->getNumberOfEntries());
     for (size_t i = 0; i < n; ++i) {
       auto ws = out_gws->getItem(i);
-      std::string itemName = ws->name();
+      const std::string &itemName = ws->getName();
       std::string wsName =
           getPropertyValue("OutputWorkspace") + "_" + std::to_string(i + 1);
       if (wsName != itemName) {
diff --git a/Framework/LiveData/src/MonitorLiveData.cpp b/Framework/LiveData/src/MonitorLiveData.cpp
index b245674366a5e5b0c6f1c987d7b7e1d8fcb2afbc..eec8a8fd35b1ce06176559baef43e1692fc63454 100644
--- a/Framework/LiveData/src/MonitorLiveData.cpp
+++ b/Framework/LiveData/src/MonitorLiveData.cpp
@@ -1,6 +1,8 @@
 #include "MantidAPI/AlgorithmManager.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidKernel/Memory.h"
+#include "MantidKernel/Strings.h"
 #include "MantidKernel/System.h"
 #include "MantidKernel/WriteLock.h"
 #include "MantidLiveData/LoadLiveData.h"
diff --git a/Framework/LiveData/src/SNSLiveEventDataListener.cpp b/Framework/LiveData/src/SNSLiveEventDataListener.cpp
index a3a2a57bb7e4095497e8055bd5b5611a797f9f5d..05ac1dcca276ea9562fc35106bf3d5a1889120bc 100644
--- a/Framework/LiveData/src/SNSLiveEventDataListener.cpp
+++ b/Framework/LiveData/src/SNSLiveEventDataListener.cpp
@@ -10,6 +10,7 @@
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidDataObjects/Events.h"
 #include "MantidGeometry/Instrument.h"
+#include "MantidKernel/ConfigService.h"
 #include "MantidKernel/DateAndTime.h"
 #include "MantidKernel/Strings.h"
 #include "MantidKernel/TimeSeriesProperty.h"
@@ -1198,8 +1199,8 @@ bool SNSLiveEventDataListener::rxPacket(const ADARA::AnnotationPkt &pkt) {
   } // mutex auto unlocks here
 
   // if there's a comment in the packet, log it at the info level
-  std::string comment = pkt.comment();
-  if (comment.size() > 0) {
+  const std::string &comment = pkt.comment();
+  if (!comment.empty()) {
     g_log.information() << "Annotation: " << comment << '\n';
   }
 
@@ -1255,7 +1256,7 @@ void SNSLiveEventDataListener::initWorkspacePart2() {
 
   auto tmp = createWorkspace<DataObjects::EventWorkspace>(
       m_eventBuffer->getInstrument()->getDetectorIDs(true).size(), 2, 1);
-  WorkspaceFactory::Instance().initializeFromParent(m_eventBuffer, tmp, true);
+  WorkspaceFactory::Instance().initializeFromParent(*m_eventBuffer, *tmp, true);
   if (m_eventBuffer->getNumberHistograms() != tmp->getNumberHistograms()) {
     // need to generate the spectra to detector map
     tmp->rebuildSpectraMapping();
@@ -1293,8 +1294,8 @@ void SNSLiveEventDataListener::initMonitorWorkspace() {
   auto monitors = m_eventBuffer->getInstrument()->getMonitors();
   auto monitorsBuffer = WorkspaceFactory::Instance().create(
       "EventWorkspace", monitors.size(), 1, 1);
-  WorkspaceFactory::Instance().initializeFromParent(m_eventBuffer,
-                                                    monitorsBuffer, true);
+  WorkspaceFactory::Instance().initializeFromParent(*m_eventBuffer,
+                                                    *monitorsBuffer, true);
   // Set the id numbers
   for (size_t i = 0; i < monitors.size(); ++i) {
     monitorsBuffer->getSpectrum(i).setDetectorID(monitors[i]);
@@ -1390,7 +1391,7 @@ boost::shared_ptr<Workspace> SNSLiveEventDataListener::extractData() {
           "EventWorkspace", m_eventBuffer->getNumberHistograms(), 2, 1));
 
   // Copy geometry over.
-  API::WorkspaceFactory::Instance().initializeFromParent(m_eventBuffer, temp,
+  API::WorkspaceFactory::Instance().initializeFromParent(*m_eventBuffer, *temp,
                                                          false);
 
   // Clear out the old logs, except for the most recent entry
@@ -1406,8 +1407,8 @@ boost::shared_ptr<Workspace> SNSLiveEventDataListener::extractData() {
   auto monitorBuffer = m_eventBuffer->monitorWorkspace();
   auto newMonitorBuffer = WorkspaceFactory::Instance().create(
       "EventWorkspace", monitorBuffer->getNumberHistograms(), 1, 1);
-  WorkspaceFactory::Instance().initializeFromParent(monitorBuffer,
-                                                    newMonitorBuffer, false);
+  WorkspaceFactory::Instance().initializeFromParent(*monitorBuffer,
+                                                    *newMonitorBuffer, false);
   temp->setMonitorWorkspace(newMonitorBuffer);
 
   // Lock the mutex and swap the workspaces
diff --git a/Framework/LiveData/src/StartLiveData.cpp b/Framework/LiveData/src/StartLiveData.cpp
index 37a6dd95ebb4b584755aa641362d3ab6ddc2a0dc..29830267bf8ea6e1fbd159a1629cf68fa03e079f 100644
--- a/Framework/LiveData/src/StartLiveData.cpp
+++ b/Framework/LiveData/src/StartLiveData.cpp
@@ -6,6 +6,7 @@
 #include "MantidAPI/AlgorithmProxy.h"
 #include "MantidAPI/AlgorithmProperty.h"
 #include "MantidAPI/LiveListenerFactory.h"
+#include "MantidAPI/Workspace.h"
 #include "MantidKernel/ArrayProperty.h"
 #include "MantidKernel/ArrayBoundedValidator.h"
 
@@ -71,19 +72,22 @@ void StartLiveData::init() {
 }
 
 /**
- * After Instrument property is set copy any properties that the instrument's
- * listener may have to this algorithm.
+ * After Listener or Connection properties are set, copy any properties that
+ * the listener may have to this algorithm.
+ *
+ * @param propName Name of property that was just set
  */
 void StartLiveData::afterPropertySet(const std::string &propName) {
-  if (propName == "Instrument") {
+  // If any of these properties change, the listener class might change
+  if (propName == "Instrument" || propName == "Listener" ||
+      propName == "Connection") {
     // Properties of old listener, if any, need to be removed
     removeListenerProperties();
 
-    // Get of instance of listener for this instrument
-    auto listener = LiveListenerFactory::Instance().create(
-        getPropertyValue(propName), false);
+    // Get temp instance of listener for this instrument with current properties
+    auto listener = createLiveListener();
 
-    // Copy over properties of new listener to this algorithm
+    // Copy over properties of listener to this algorithm
     copyListenerProperties(listener);
   }
 }
@@ -108,12 +112,19 @@ void StartLiveData::copyListenerProperties(
  * Removes previously copied ILiveListener properties.
  */
 void StartLiveData::removeListenerProperties() {
-  // Remove all properties tagged with the listener property group
-  for (auto prop : getProperties()) {
+  std::vector<std::string> propertiesToRemove;
+
+  // Find properties tagged with the listener property group
+  for (const auto &prop : getProperties()) {
     if (prop->getGroup() == listenerPropertyGroup) {
-      removeProperty(prop->name());
+      propertiesToRemove.push_back(prop->name());
     }
   }
+
+  // Remove identified properties
+  for (const auto &prop : propertiesToRemove) {
+    removeProperty(prop);
+  }
 }
 
 //----------------------------------------------------------------------------------------------
diff --git a/Framework/LiveData/src/TOPAZLiveEventDataListener.cpp b/Framework/LiveData/src/TOPAZLiveEventDataListener.cpp
index a2bcc57a8dbea0ebd980cf3989ad8200fbe346f2..7117fbf38f3791a988dc1f338e6feff5eb1271fa 100644
--- a/Framework/LiveData/src/TOPAZLiveEventDataListener.cpp
+++ b/Framework/LiveData/src/TOPAZLiveEventDataListener.cpp
@@ -476,7 +476,7 @@ void TOPAZLiveEventDataListener::initWorkspace() {
 
   auto tmp = createWorkspace<DataObjects::EventWorkspace>(
       m_eventBuffer->getInstrument()->getDetectorIDs(true).size(), 2, 1);
-  WorkspaceFactory::Instance().initializeFromParent(m_eventBuffer, tmp, true);
+  WorkspaceFactory::Instance().initializeFromParent(*m_eventBuffer, *tmp, true);
   if (m_eventBuffer->getNumberHistograms() != tmp->getNumberHistograms()) {
     // need to generate the spectra to detector map
     tmp->rebuildSpectraMapping();
@@ -502,8 +502,8 @@ void TOPAZLiveEventDataListener::initMonitorWorkspace() {
   auto monitors = m_eventBuffer->getInstrument()->getMonitors();
   auto monitorsBuffer = WorkspaceFactory::Instance().create(
       "EventWorkspace", monitors.size(), 1, 1);
-  WorkspaceFactory::Instance().initializeFromParent(m_eventBuffer,
-                                                    monitorsBuffer, true);
+  WorkspaceFactory::Instance().initializeFromParent(*m_eventBuffer,
+                                                    *monitorsBuffer, true);
   // Set the id numbers
   for (size_t i = 0; i < monitors.size(); ++i) {
     monitorsBuffer->getSpectrum(i).setDetectorID(monitors[i]);
@@ -564,7 +564,7 @@ boost::shared_ptr<Workspace> TOPAZLiveEventDataListener::extractData() {
           "EventWorkspace", m_eventBuffer->getNumberHistograms(), 2, 1));
 
   // Copy geometry over.
-  API::WorkspaceFactory::Instance().initializeFromParent(m_eventBuffer, temp,
+  API::WorkspaceFactory::Instance().initializeFromParent(*m_eventBuffer, *temp,
                                                          false);
 
   // Clear out the old logs, except for the most recent entry
@@ -583,8 +583,8 @@ boost::shared_ptr<Workspace> TOPAZLiveEventDataListener::extractData() {
   auto monitorBuffer = m_eventBuffer->monitorWorkspace();
   auto newMonitorBuffer = WorkspaceFactory::Instance().create(
       "EventWorkspace", monitorBuffer->getNumberHistograms(), 1, 1);
-  WorkspaceFactory::Instance().initializeFromParent(monitorBuffer,
-                                                    newMonitorBuffer, false);
+  WorkspaceFactory::Instance().initializeFromParent(*monitorBuffer,
+                                                    *newMonitorBuffer, false);
   temp->setMonitorWorkspace(newMonitorBuffer);
 
   // Lock the mutex and swap the workspaces
diff --git a/Framework/LiveData/test/FileEventDataListenerTest.h b/Framework/LiveData/test/FileEventDataListenerTest.h
index 8268b53daed7858840c6d2b19b7a7891eb327543..bdcdc758c7d5dce2d0d8f82f30ab63a80036a9b8 100644
--- a/Framework/LiveData/test/FileEventDataListenerTest.h
+++ b/Framework/LiveData/test/FileEventDataListenerTest.h
@@ -2,6 +2,7 @@
 #define MANTID_LIVEDATA_FILEEVENTDATALISTENERTEST_H_
 
 #include <cxxtest/TestSuite.h>
+#include "MantidKernel/ConfigService.h"
 #include "MantidAPI/LiveListenerFactory.h"
 #include "MantidDataObjects/EventWorkspace.h"
 
diff --git a/Framework/LiveData/test/LoadLiveDataTest.h b/Framework/LiveData/test/LoadLiveDataTest.h
index ad1bb0c04451a1d7724f39b1ff271b7a5a45fa16..f898f70305edca933bc8ea9757598e62a1d00d0d 100644
--- a/Framework/LiveData/test/LoadLiveDataTest.h
+++ b/Framework/LiveData/test/LoadLiveDataTest.h
@@ -322,7 +322,7 @@ public:
                                ILiveListener_sptr(new TestGroupDataListener));
     TS_ASSERT(ws);
     TS_ASSERT_EQUALS(ws->getNumberOfEntries(), 3);
-    TS_ASSERT_EQUALS(ws->name(), "fake");
+    TS_ASSERT_EQUALS(ws->getName(), "fake");
     MatrixWorkspace_sptr mws =
         AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("fake_2");
     TS_ASSERT(mws);
@@ -342,7 +342,7 @@ public:
         ILiveListener_sptr(new TestGroupDataListener));
     TS_ASSERT(ws);
     TS_ASSERT_EQUALS(ws->getNumberOfEntries(), 3);
-    TS_ASSERT_EQUALS(ws->name(), "fake");
+    TS_ASSERT_EQUALS(ws->getName(), "fake");
     MatrixWorkspace_sptr mws =
         AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("fake_2");
     TS_ASSERT(mws);
@@ -362,7 +362,7 @@ public:
         ILiveListener_sptr(new TestGroupDataListener));
     TS_ASSERT(ws);
     TS_ASSERT_EQUALS(ws->getNumberOfEntries(), 3);
-    TS_ASSERT_EQUALS(ws->name(), "fake");
+    TS_ASSERT_EQUALS(ws->getName(), "fake");
     MatrixWorkspace_sptr mws =
         AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("fake_2");
     TS_ASSERT(mws);
@@ -385,7 +385,7 @@ public:
                                ILiveListener_sptr(new TestGroupDataListener));
     TS_ASSERT(ws);
     TS_ASSERT_EQUALS(ws->getNumberOfEntries(), 3);
-    TS_ASSERT_EQUALS(ws->name(), "fake");
+    TS_ASSERT_EQUALS(ws->getName(), "fake");
     MatrixWorkspace_sptr mws =
         AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("fake_2");
     TS_ASSERT(mws);
@@ -407,7 +407,7 @@ public:
                                ILiveListener_sptr(new TestGroupDataListener));
     TS_ASSERT(ws);
     TS_ASSERT_EQUALS(ws->getNumberOfEntries(), 3);
-    TS_ASSERT_EQUALS(ws->name(), "fake");
+    TS_ASSERT_EQUALS(ws->getName(), "fake");
     MatrixWorkspace_sptr mws =
         AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("fake_2");
     TS_ASSERT(mws);
@@ -429,7 +429,7 @@ public:
                                ILiveListener_sptr(new TestGroupDataListener));
     TS_ASSERT(ws);
     TS_ASSERT_EQUALS(ws->getNumberOfEntries(), 3);
-    TS_ASSERT_EQUALS(ws->name(), "fake");
+    TS_ASSERT_EQUALS(ws->getName(), "fake");
     MatrixWorkspace_sptr mws =
         AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("fake_2");
     TS_ASSERT(mws);
@@ -452,7 +452,7 @@ public:
                                ILiveListener_sptr(new TestGroupDataListener));
     TS_ASSERT(ws);
     TS_ASSERT_EQUALS(ws->getNumberOfEntries(), 3);
-    TS_ASSERT_EQUALS(ws->name(), "fake");
+    TS_ASSERT_EQUALS(ws->getName(), "fake");
     MatrixWorkspace_sptr mws =
         AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("fake_2");
     TS_ASSERT(mws);
@@ -474,7 +474,7 @@ public:
                                ILiveListener_sptr(new TestGroupDataListener));
     TS_ASSERT(ws);
     TS_ASSERT_EQUALS(ws->getNumberOfEntries(), 3);
-    TS_ASSERT_EQUALS(ws->name(), "fake");
+    TS_ASSERT_EQUALS(ws->getName(), "fake");
     MatrixWorkspace_sptr mws =
         AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("fake_2");
     TS_ASSERT(mws);
@@ -496,7 +496,7 @@ public:
                                ILiveListener_sptr(new TestGroupDataListener));
     TS_ASSERT(ws);
     TS_ASSERT_EQUALS(ws->getNumberOfEntries(), 3);
-    TS_ASSERT_EQUALS(ws->name(), "fake");
+    TS_ASSERT_EQUALS(ws->getName(), "fake");
     MatrixWorkspace_sptr mws =
         AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("fake_2");
     TS_ASSERT(mws);
diff --git a/Framework/LiveData/test/MonitorLiveDataTest.h b/Framework/LiveData/test/MonitorLiveDataTest.h
index 301d3e19a9dd42e1a4f90ff57440b6a6a74d0a45..fef854358edb0216d4574f1f4a47cf91f36722a9 100644
--- a/Framework/LiveData/test/MonitorLiveDataTest.h
+++ b/Framework/LiveData/test/MonitorLiveDataTest.h
@@ -7,6 +7,7 @@
 
 #include "MantidLiveData/MonitorLiveData.h"
 #include "MantidAPI/AlgorithmManager.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidKernel/Strings.h"
 #include "MantidDataObjects/EventWorkspace.h"
 #include "MantidKernel/ConfigService.h"
diff --git a/Framework/LiveData/test/StartLiveDataTest.h b/Framework/LiveData/test/StartLiveDataTest.h
index 023343ebd11be6149873e508b8dd7c9c1df932bf..da11133464ace110a32975c456895bc6a6fb6f71 100644
--- a/Framework/LiveData/test/StartLiveDataTest.h
+++ b/Framework/LiveData/test/StartLiveDataTest.h
@@ -102,7 +102,7 @@ public:
 
     // Make an existing output workspace "fake" that should be overwritten
     AnalysisDataService::Instance().addOrReplace(
-        "fake", WorkspaceCreationHelper::Create2DWorkspace(23, 12));
+        "fake", WorkspaceCreationHelper::create2DWorkspace(23, 12));
 
     EventWorkspace_sptr ws;
     ws = doExecEvent("Add", 0, "", "");
diff --git a/Framework/LiveData/test/TestDataListener.cpp b/Framework/LiveData/test/TestDataListener.cpp
index 1801c8c66c006f0ce8c9d0fc7d391cd9b1de408d..7071a245b7db875fa2307bd6f4783f536ea5afb7 100644
--- a/Framework/LiveData/test/TestDataListener.cpp
+++ b/Framework/LiveData/test/TestDataListener.cpp
@@ -96,7 +96,8 @@ void TestDataListener::createEmptyWorkspace() {
   // Add a monitor workspace
   auto monitorWS =
       WorkspaceFactory::Instance().create("EventWorkspace", 1, 2, 1);
-  WorkspaceFactory::Instance().initializeFromParent(m_buffer, monitorWS, true);
+  WorkspaceFactory::Instance().initializeFromParent(*m_buffer, *monitorWS,
+                                                    true);
   monitorWS->dataX(0)[0] = 40000;
   monitorWS->dataX(0)[1] = 60000;
   m_buffer->setMonitorWorkspace(monitorWS);
diff --git a/Framework/LiveData/test/TestGroupDataListener.cpp b/Framework/LiveData/test/TestGroupDataListener.cpp
index bc442527bd263bfb007ff726d4a33e4d13e9b22f..63798f8a30e319a6a853838f0dcd906f8f70fad0 100644
--- a/Framework/LiveData/test/TestGroupDataListener.cpp
+++ b/Framework/LiveData/test/TestGroupDataListener.cpp
@@ -40,7 +40,7 @@ void TestGroupDataListener::start(
 /** Create the default empty event workspace */
 void TestGroupDataListener::createWorkspace() {
   // create a group
-  m_buffer = WorkspaceCreationHelper::CreateWorkspaceGroup(3, 2, 10, "tst");
+  m_buffer = WorkspaceCreationHelper::createWorkspaceGroup(3, 2, 10, "tst");
   // it must not be in the ADS
   API::AnalysisDataService::Instance().deepRemoveGroup("tst");
 }
diff --git a/Framework/MDAlgorithms/inc/MantidMDAlgorithms/CentroidPeaksMD.h b/Framework/MDAlgorithms/inc/MantidMDAlgorithms/CentroidPeaksMD.h
index b595bfaf8e834e0211cf7f2b5a074b1ad6182a0d..b1692ca3fa01a7fd1f15346ed0c2adc3a2846c56 100644
--- a/Framework/MDAlgorithms/inc/MantidMDAlgorithms/CentroidPeaksMD.h
+++ b/Framework/MDAlgorithms/inc/MantidMDAlgorithms/CentroidPeaksMD.h
@@ -3,6 +3,7 @@
 
 #include "MantidKernel/System.h"
 #include "MantidAPI/Algorithm.h"
+#include "MantidAPI/DeprecatedAlgorithm.h"
 #include "MantidAPI/IMDEventWorkspace_fwd.h"
 #include "MantidDataObjects/PeaksWorkspace.h"
 #include "MantidDataObjects/MDEventWorkspace.h"
@@ -16,8 +17,12 @@ namespace MDAlgorithms {
  * @author Janik Zikovsky
  * @date 2011-06-01
  */
-class DLLExport CentroidPeaksMD : public API::Algorithm {
+class DLLExport CentroidPeaksMD : public API::Algorithm,
+                                  public API::DeprecatedAlgorithm {
 public:
+  /// Constructor
+  CentroidPeaksMD();
+
   /// Algorithm's name for identification
   const std::string name() const override { return "CentroidPeaksMD"; };
   /// Summary of algorithms purpose
diff --git a/Framework/MDAlgorithms/inc/MantidMDAlgorithms/ConvertCWSDExpToMomentum.h b/Framework/MDAlgorithms/inc/MantidMDAlgorithms/ConvertCWSDExpToMomentum.h
index 212e0608c2e093fdfb28afda5036255664bda50f..6b2cdab5a565553a9d638043281894251e7851d0 100644
--- a/Framework/MDAlgorithms/inc/MantidMDAlgorithms/ConvertCWSDExpToMomentum.h
+++ b/Framework/MDAlgorithms/inc/MantidMDAlgorithms/ConvertCWSDExpToMomentum.h
@@ -97,6 +97,12 @@ private:
   API::IMDEventWorkspace_sptr m_outputWS;
   Geometry::Instrument_sptr m_virtualInstrument;
 
+  /// Shifts in detector position set from user (calibration): all in the unit
+  /// as meter
+  double m_detSampleDistanceShift;
+  double m_detXShift;
+  double m_detYShift;
+
   Kernel::V3D m_samplePos;
   Kernel::V3D m_sourcePos;
 
diff --git a/Framework/MDAlgorithms/inc/MantidMDAlgorithms/ConvertSpiceDataToRealSpace.h b/Framework/MDAlgorithms/inc/MantidMDAlgorithms/ConvertSpiceDataToRealSpace.h
index 51263d1b46f8275994583af73a8e83e7871d30e2..2768a7ac1aa17f7f8aba067ad49b41bbc9a3a5b6 100644
--- a/Framework/MDAlgorithms/inc/MantidMDAlgorithms/ConvertSpiceDataToRealSpace.h
+++ b/Framework/MDAlgorithms/inc/MantidMDAlgorithms/ConvertSpiceDataToRealSpace.h
@@ -7,6 +7,8 @@
 #include "MantidGeometry/IDTypes.h"
 #include "MantidKernel/FileDescriptor.h"
 
+#include <deque>
+
 namespace Mantid {
 namespace MDAlgorithms {
 
diff --git a/Framework/MDAlgorithms/inc/MantidMDAlgorithms/IntegrateEllipsoids.h b/Framework/MDAlgorithms/inc/MantidMDAlgorithms/IntegrateEllipsoids.h
index 1063f3d689c4168006aa98ac691a9b7bccb0ef98..0d261d677e1db296a8547c7a3c88279bc63abe45 100644
--- a/Framework/MDAlgorithms/inc/MantidMDAlgorithms/IntegrateEllipsoids.h
+++ b/Framework/MDAlgorithms/inc/MantidMDAlgorithms/IntegrateEllipsoids.h
@@ -12,6 +12,9 @@
 #include "MantidDataObjects/PeaksWorkspace.h"
 
 namespace Mantid {
+namespace API {
+class DetectorInfo;
+}
 namespace MDAlgorithms {
 
 class DLLExport IntegrateEllipsoids : public API::Algorithm {
@@ -37,7 +40,7 @@ private:
                         Kernel::DblMatrix const &UBinv, bool hkl_integ);
 
   /// Calculate if this Q is on a detector
-  void calculateE1(Geometry::Instrument_const_sptr inst);
+  void calculateE1(const API::DetectorInfo &detectorInfo);
 
   void runMaskDetectors(Mantid::DataObjects::PeaksWorkspace_sptr peakWS,
                         std::string property, std::string values);
diff --git a/Framework/MDAlgorithms/inc/MantidMDAlgorithms/IntegratePeaksMD2.h b/Framework/MDAlgorithms/inc/MantidMDAlgorithms/IntegratePeaksMD2.h
index 4c2c16351cf4d6f2d79ce9388e1cba449bcdd769..2cae330fbf9fac946683465635c493b100cd2127 100644
--- a/Framework/MDAlgorithms/inc/MantidMDAlgorithms/IntegratePeaksMD2.h
+++ b/Framework/MDAlgorithms/inc/MantidMDAlgorithms/IntegratePeaksMD2.h
@@ -9,6 +9,9 @@
 #include "MantidAPI/CompositeFunction.h"
 
 namespace Mantid {
+namespace API {
+class DetectorInfo;
+}
 namespace MDAlgorithms {
 
 /** Integrate single-crystal peaks in reciprocal-space.
@@ -44,7 +47,7 @@ private:
   Mantid::API::IMDEventWorkspace_sptr inWS;
 
   /// Calculate if this Q is on a detector
-  void calculateE1(Geometry::Instrument_const_sptr inst);
+  void calculateE1(const API::DetectorInfo &detectorInfo);
   double detectorQ(Mantid::Kernel::V3D QLabFrame, double r);
   void runMaskDetectors(Mantid::DataObjects::PeaksWorkspace_sptr peakWS,
                         std::string property, std::string values);
diff --git a/Framework/MDAlgorithms/inc/MantidMDAlgorithms/LoadILLAscii.h b/Framework/MDAlgorithms/inc/MantidMDAlgorithms/LoadILLAscii.h
index 4756d66f92eac5122ca77d20fd72144480a20bcf..3cfc72e43da568b517909f7595ef5b12b356062f 100644
--- a/Framework/MDAlgorithms/inc/MantidMDAlgorithms/LoadILLAscii.h
+++ b/Framework/MDAlgorithms/inc/MantidMDAlgorithms/LoadILLAscii.h
@@ -3,6 +3,7 @@
 
 #include "MantidKernel/System.h"
 #include "MantidAPI/Algorithm.h"
+#include "MantidAPI/DeprecatedAlgorithm.h"
 
 #include "MantidMDAlgorithms/LoadILLAsciiHelper.h"
 #include "MantidAPI/IFileLoader.h"
@@ -38,7 +39,8 @@ namespace MDAlgorithms {
  File change history is stored at: <https://github.com/mantidproject/mantid>
  Code Documentation is available at: <http://doxygen.mantidproject.org>
  */
-class DLLExport LoadILLAscii : public API::IFileLoader<Kernel::FileDescriptor> {
+class DLLExport LoadILLAscii : public API::IFileLoader<Kernel::FileDescriptor>,
+                               public API::DeprecatedAlgorithm {
 public:
   const std::string name() const override;
   int version() const override;
diff --git a/Framework/MDAlgorithms/inc/MantidMDAlgorithms/MDNormDirectSC.h b/Framework/MDAlgorithms/inc/MantidMDAlgorithms/MDNormDirectSC.h
index 7a5e3bea51ef257648242bff8303b7fafce0ddc9..09414c9b161118e729decf67f7415c3c15857d14 100644
--- a/Framework/MDAlgorithms/inc/MantidMDAlgorithms/MDNormDirectSC.h
+++ b/Framework/MDAlgorithms/inc/MantidMDAlgorithms/MDNormDirectSC.h
@@ -60,11 +60,6 @@ private:
   void calculateNormalization(const std::vector<coord_t> &otherValues,
                               const Kernel::Matrix<coord_t> &affineTrans);
 
-  std::vector<detid_t> removeGroupedIDs(const API::ExperimentInfo &exptInfo,
-                                        const std::vector<detid_t> &detIDs);
-  Geometry::IDetector_const_sptr
-  getThetaPhi(const detid_t detID, const API::ExperimentInfo &exptInfo,
-              double &theta, double &phi);
   std::vector<Kernel::VMD> calculateIntersections(const double theta,
                                                   const double phi);
 
diff --git a/Framework/MDAlgorithms/inc/MantidMDAlgorithms/MDNormSCD.h b/Framework/MDAlgorithms/inc/MantidMDAlgorithms/MDNormSCD.h
index b7d0f3ddfad0703bf1c72cc1f3ca919735e3998a..8ba22641dfb9b96503ca5fb2f1d8bf218b749886 100644
--- a/Framework/MDAlgorithms/inc/MantidMDAlgorithms/MDNormSCD.h
+++ b/Framework/MDAlgorithms/inc/MantidMDAlgorithms/MDNormSCD.h
@@ -63,11 +63,6 @@ private:
                                      const API::MatrixWorkspace &integrFlux,
                                      size_t sp,
                                      std::vector<double> &yValues) const;
-  std::vector<detid_t> removeGroupedIDs(const API::ExperimentInfo &exptInfo,
-                                        const std::vector<detid_t> &detIDs);
-  Geometry::IDetector_const_sptr
-  getThetaPhi(const detid_t detID, const API::ExperimentInfo &exptInfo,
-              double &theta, double &phi);
   std::vector<Kernel::VMD> calculateIntersections(const double theta,
                                                   const double phi);
 
diff --git a/Framework/MDAlgorithms/inc/MantidMDAlgorithms/MDWSDescription.h b/Framework/MDAlgorithms/inc/MantidMDAlgorithms/MDWSDescription.h
index 2b17821ecadc3bf03afe0bf9c06f5848cbfb8c41..53d03df7f08e4bbeec6e7d7c9240b8b3cdacc362 100644
--- a/Framework/MDAlgorithms/inc/MantidMDAlgorithms/MDWSDescription.h
+++ b/Framework/MDAlgorithms/inc/MantidMDAlgorithms/MDWSDescription.h
@@ -101,7 +101,7 @@ public: // for the time being
   // functions
   API::MatrixWorkspace_const_sptr getInWS() const { return m_InWS; }
   void setWS(API::MatrixWorkspace_sptr otherMatrixWS);
-  std::string getWSName() const { return m_InWS->name(); }
+  const std::string &getWSName() const { return m_InWS->getName(); }
   bool isPowder() const;
   bool isQ3DMode() const;
   bool hasLattice() const;
diff --git a/Framework/MDAlgorithms/inc/MantidMDAlgorithms/Quantification/CachedExperimentInfo.h b/Framework/MDAlgorithms/inc/MantidMDAlgorithms/Quantification/CachedExperimentInfo.h
index c3ffe130d930b885fd39866a3fcaf6e66d8d97c2..71841a2059636db307644ef742fde62a73d64660 100644
--- a/Framework/MDAlgorithms/inc/MantidMDAlgorithms/Quantification/CachedExperimentInfo.h
+++ b/Framework/MDAlgorithms/inc/MantidMDAlgorithms/Quantification/CachedExperimentInfo.h
@@ -24,6 +24,7 @@
 */
 #include "MantidAPI/ExperimentInfo.h"
 #include "MantidGeometry/IDetector.h"
+#include "MantidGeometry/Objects/BoundingBox.h"
 #include "MantidKernel/ClassMacros.h"
 #include "MantidKernel/Matrix.h"
 
diff --git a/Framework/MDAlgorithms/src/AccumulateMD.cpp b/Framework/MDAlgorithms/src/AccumulateMD.cpp
index f78ad4e98b34a3d9237da76d4a9bf0796b856a7f..63c4467e051a48de2f30278a820e6c9fbb7dbd71 100644
--- a/Framework/MDAlgorithms/src/AccumulateMD.cpp
+++ b/Framework/MDAlgorithms/src/AccumulateMD.cpp
@@ -6,12 +6,17 @@
 #include "MantidKernel/ListValidator.h"
 #include "MantidKernel/MandatoryValidator.h"
 #include "MantidKernel/PropertyWithValue.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/FileFinder.h"
 #include "MantidAPI/HistoryView.h"
 #include "MantidDataObjects/MDHistoWorkspaceIterator.h"
 #include "MantidAPI/FileProperty.h"
 #include "MantidKernel/EnabledWhenProperty.h"
+
 #include <Poco/File.h>
+#include <boost/algorithm/string/classification.hpp>
+#include <boost/algorithm/string/split.hpp>
+#include <boost/algorithm/string/trim.hpp>
 
 using namespace Mantid::Kernel;
 using namespace Mantid::API;
diff --git a/Framework/MDAlgorithms/src/BoxControllerSettingsAlgorithm.cpp b/Framework/MDAlgorithms/src/BoxControllerSettingsAlgorithm.cpp
index cbf036aaa7a463dcbe00d4f842eb9534d111afce..0d15d133c9477ad740b95059894fb8e7f0cb1c98 100644
--- a/Framework/MDAlgorithms/src/BoxControllerSettingsAlgorithm.cpp
+++ b/Framework/MDAlgorithms/src/BoxControllerSettingsAlgorithm.cpp
@@ -3,6 +3,7 @@
 #include "MantidKernel/Strings.h"
 #include "MantidKernel/ArrayProperty.h"
 #include "MantidKernel/BoundedValidator.h"
+#include "MantidKernel/StringTokenizer.h"
 
 using namespace Mantid::Kernel;
 using namespace Mantid::API;
diff --git a/Framework/MDAlgorithms/src/CalculateCoverageDGS.cpp b/Framework/MDAlgorithms/src/CalculateCoverageDGS.cpp
index 4af3ee1f476b02a17f792b2e51dac3eaf8a76abe..b1bccf772186a66d0a33c104770b74b5024b2880 100644
--- a/Framework/MDAlgorithms/src/CalculateCoverageDGS.cpp
+++ b/Framework/MDAlgorithms/src/CalculateCoverageDGS.cpp
@@ -1,11 +1,14 @@
 #include "MantidMDAlgorithms/CalculateCoverageDGS.h"
+#include "MantidAPI/DetectorInfo.h"
 #include "MantidAPI/InstrumentValidator.h"
 #include "MantidAPI/Run.h"
 #include "MantidAPI/Sample.h"
 #include "MantidDataObjects/MDHistoWorkspace.h"
+#include "MantidGeometry/Instrument/Goniometer.h"
 #include "MantidKernel/ArrayProperty.h"
 #include "MantidKernel/ArrayLengthValidator.h"
 #include "MantidKernel/BoundedValidator.h"
+#include "MantidKernel/ConfigService.h"
 #include "MantidKernel/Strings.h"
 #include "MantidKernel/ListValidator.h"
 #include "MantidGeometry/Instrument.h"
@@ -13,6 +16,8 @@
 #include "MantidGeometry/Crystal/OrientedLattice.h"
 #include "MantidKernel/VectorHelper.h"
 
+#include <boost/lexical_cast.hpp>
+
 namespace Mantid {
 namespace MDAlgorithms {
 using namespace Mantid::Kernel;
@@ -131,7 +136,7 @@ void CalculateCoverageDGS::init() {
 
   for (int i = 1; i <= 4; i++) {
     std::string dim("Dimension");
-    dim += Kernel::toString(i);
+    dim += boost::lexical_cast<std::string>(i);
     declareProperty(dim, options[i - 1],
                     boost::make_shared<StringListValidator>(options),
                     "Dimension to bin or integrate");
@@ -161,14 +166,13 @@ void CalculateCoverageDGS::exec() {
       getProperty("InputWorkspace");
   convention = Kernel::ConfigService::Instance().getString("Q.convention");
   // cache two theta and phi
-  auto instrument = inputWS->getInstrument();
-  std::vector<detid_t> detIDS = instrument->getDetectorIDs(true);
+  const auto &detectorInfo = inputWS->detectorInfo();
   std::vector<double> tt, phi;
-  for (auto &id : detIDS) {
-    auto detector = instrument->getDetector(id);
-    if (!detector->isMasked()) {
-      tt.push_back(detector->getTwoTheta(V3D(0, 0, 0), V3D(0, 0, 1)));
-      phi.push_back(detector->getPhi());
+  for (size_t i = 0; i < detectorInfo.size(); ++i) {
+    if (!detectorInfo.isMasked(i) && !detectorInfo.isMonitor(i)) {
+      const auto &detector = detectorInfo.detector(i);
+      tt.push_back(detector.getTwoTheta(V3D(0, 0, 0), V3D(0, 0, 1)));
+      phi.push_back(detector.getPhi());
     }
   }
 
@@ -196,7 +200,7 @@ void CalculateCoverageDGS::exec() {
   size_t q1NumBins = 1, q2NumBins = 1, q3NumBins = 1, dENumBins = 1;
   for (int i = 1; i <= 4; i++) {
     std::string dim("Dimension");
-    dim += Kernel::toString(i);
+    dim += boost::lexical_cast<std::string>(i);
     std::string dimensioni = getProperty(dim);
     if (dimensioni == "Q1") {
       affineMat[i - 1][0] = 1.;
diff --git a/Framework/MDAlgorithms/src/CentroidPeaksMD.cpp b/Framework/MDAlgorithms/src/CentroidPeaksMD.cpp
index ce66efc09465025272708ef095555192154c560b..7c8f59197405c7d55d46eb4be046c85441bc7d78 100644
--- a/Framework/MDAlgorithms/src/CentroidPeaksMD.cpp
+++ b/Framework/MDAlgorithms/src/CentroidPeaksMD.cpp
@@ -21,6 +21,8 @@ using namespace Mantid::Geometry;
 using namespace Mantid::Kernel;
 using namespace Mantid::DataObjects;
 
+CentroidPeaksMD::CentroidPeaksMD() { this->useAlgorithm("CentroidPeaksMD", 2); }
+
 //----------------------------------------------------------------------------------------------
 /** Initialize the algorithm's properties.
  */
diff --git a/Framework/MDAlgorithms/src/CompactMD.cpp b/Framework/MDAlgorithms/src/CompactMD.cpp
index 9d1a5382dee686698e9e801de0461a61c077bb74..84f22c58767e48ede53fe586f4136e1592c3e133 100644
--- a/Framework/MDAlgorithms/src/CompactMD.cpp
+++ b/Framework/MDAlgorithms/src/CompactMD.cpp
@@ -1,5 +1,8 @@
 #include "MantidMDAlgorithms/CompactMD.h"
 #include "MantidAPI/IMDIterator.h"
+
+#include <boost/lexical_cast.hpp>
+
 using namespace Mantid::API;
 using namespace Mantid::Geometry;
 using namespace Mantid::Kernel;
@@ -147,4 +150,4 @@ void CompactMD::exec() {
   this->setProperty("OutputWorkspace", out_ws);
 }
 }
-}
\ No newline at end of file
+}
diff --git a/Framework/MDAlgorithms/src/CompareMDWorkspaces.cpp b/Framework/MDAlgorithms/src/CompareMDWorkspaces.cpp
index 4223a88d247cf121b17b51b33020dc46cbff1658..e11d0a2a9c98131cf29363fb787b4066361e7c5d 100644
--- a/Framework/MDAlgorithms/src/CompareMDWorkspaces.cpp
+++ b/Framework/MDAlgorithms/src/CompareMDWorkspaces.cpp
@@ -178,8 +178,7 @@ void CompareMDWorkspaces::compareMDHistoWorkspaces(
 */
 template <typename MDE, size_t nd>
 void CompareMDWorkspaces::compareMDWorkspaces(
-    typename MDEventWorkspace<MDE, nd>::sptr ws) {
-  typename MDEventWorkspace<MDE, nd>::sptr ws1 = ws;
+    typename MDEventWorkspace<MDE, nd>::sptr ws1) {
   typename MDEventWorkspace<MDE, nd>::sptr ws2 =
       boost::dynamic_pointer_cast<MDEventWorkspace<MDE, nd>>(inWS2);
   if (!ws1 || !ws2)
diff --git a/Framework/MDAlgorithms/src/ConvertCWPDMDToSpectra.cpp b/Framework/MDAlgorithms/src/ConvertCWPDMDToSpectra.cpp
index f416050888412bd97f73d1a862ab07a3c56fedba..c278b1b0bf195e380ab8289493439fa5b8c69bd7 100644
--- a/Framework/MDAlgorithms/src/ConvertCWPDMDToSpectra.cpp
+++ b/Framework/MDAlgorithms/src/ConvertCWPDMDToSpectra.cpp
@@ -463,8 +463,8 @@ void ConvertCWPDMDToSpectra::binMD(API::IMDEventWorkspace_const_sptr mdws,
   while (scancell) {
     // get the number of events of this cell
     size_t numev2 = mditer->getNumEvents();
-    g_log.debug() << "MDWorkspace " << mdws->name() << " Cell " << nextindex - 1
-                  << ": Number of events = " << numev2
+    g_log.debug() << "MDWorkspace " << mdws->getName() << " Cell "
+                  << nextindex - 1 << ": Number of events = " << numev2
                   << " Does NEXT cell exist = " << mditer->next() << "\n";
 
     // loop over all the events in current cell
@@ -499,7 +499,7 @@ void ConvertCWPDMDToSpectra::binMD(API::IMDEventWorkspace_const_sptr mdws,
             std::stringstream errss;
             errss << "Event " << iev << " has run ID as " << temprun << ". "
                   << "It has no corresponding ExperimentInfo in MDWorkspace "
-                  << mdws->name() << ".";
+                  << mdws->getName() << ".";
             throw std::runtime_error(errss.str());
           }
           currWavelength = miter->second;
diff --git a/Framework/MDAlgorithms/src/ConvertCWSDExpToMomentum.cpp b/Framework/MDAlgorithms/src/ConvertCWSDExpToMomentum.cpp
index c3ceb29ea17ccbdce5cf9d5f56dc624a7f96dc82..bb767538aaa14de970e7b089d510368276ac01c5 100644
--- a/Framework/MDAlgorithms/src/ConvertCWSDExpToMomentum.cpp
+++ b/Framework/MDAlgorithms/src/ConvertCWSDExpToMomentum.cpp
@@ -7,6 +7,7 @@
 #include "MantidDataObjects/MDEventFactory.h"
 #include "MantidAPI/ExperimentInfo.h"
 #include "MantidGeometry/Instrument/ComponentHelper.h"
+#include "MantidGeometry/Instrument/Goniometer.h"
 #include "MantidMDAlgorithms/MDWSDescription.h"
 #include "MantidMDAlgorithms/MDWSTransform.h"
 #include "MantidAPI/FileProperty.h"
@@ -37,6 +38,21 @@ void ConvertCWSDExpToMomentum::init() {
                                                       Direction::Input),
       "Name of table workspace for data file names in the experiment.");
 
+  declareProperty(
+      "DetectorSampleDistanceShift", 0.0,
+      "Amount of shift in sample-detector distance from 0.3750 meter.");
+
+  declareProperty(
+      "DetectorCenterXShift", 0.0,
+      "Amount of shift of detector center in X-direction from (115, 128).");
+
+  declareProperty(
+      "DetectorCenterYShift", 0.0,
+      "Amount of shift of detector center in Y-direction from (115, 128).");
+
+  declareProperty("UserDefinedWavelength", EMPTY_DBL(),
+                  "User defined wave length if it is specified.");
+
   declareProperty("CreateVirtualInstrument", false,
                   "Flag to create virtual instrument.");
 
@@ -87,10 +103,13 @@ void ConvertCWSDExpToMomentum::exec() {
     g_log.error() << "Importing error: " << errmsg << "\n";
     throw std::runtime_error(errmsg);
   }
+  m_detSampleDistanceShift = getProperty("DetectorSampleDistanceShift");
+  m_detXShift = getProperty("DetectorCenterXShift");
+  m_detYShift = getProperty("DetectorCenterYShift");
 
   // background
   std::string bkgdwsname = getPropertyValue("BackgroundWorkspace");
-  if (bkgdwsname.size() > 0) {
+  if (!bkgdwsname.empty()) {
     m_removeBackground = true;
     m_backgroundWS = getProperty("BackgroundWorkspace");
     // check background
@@ -214,7 +233,7 @@ void ConvertCWSDExpToMomentum::addMDEvents(bool usevirtual) {
 
   // Check whether to add / or \ to m_dataDir
   std::string sep;
-  if (m_dataDir.size() > 0) {
+  if (!m_dataDir.empty()) {
 // Determine system
 #if _WIN64
     const bool isWindows = true;
@@ -226,6 +245,7 @@ void ConvertCWSDExpToMomentum::addMDEvents(bool usevirtual) {
 
     if (isWindows && *m_dataDir.rbegin() != '\\') {
       sep = "\\";
+      // cppcheck-suppress knownConditionTrueFalse
     } else if (!isWindows && *m_dataDir.rbegin() != '/')
       sep = "/";
   }
@@ -236,7 +256,6 @@ void ConvertCWSDExpToMomentum::addMDEvents(bool usevirtual) {
     g_log.warning("There are more than 1 experiment to import. "
                   "Make sure that all of them have the same instrument.");
   }
-  size_t numFileNotLoaded(0);
 
   // Loop through all data files in the experiment
   for (size_t ir = 0; ir < numrows; ++ir) {
@@ -260,7 +279,6 @@ void ConvertCWSDExpToMomentum::addMDEvents(bool usevirtual) {
     spicews = loadSpiceData(filename, loaded, errmsg);
     if (!loaded) {
       g_log.error(errmsg);
-      ++numFileNotLoaded;
       continue;
     }
     if (m_removeBackground) {
@@ -541,7 +559,7 @@ bool ConvertCWSDExpToMomentum::getInputs(bool virtualinstrument,
 
   errmsg = errss.str();
 
-  return (errmsg.size() == 0);
+  return (errmsg.empty());
 }
 
 //----------------------------------------------------------------------------------------------
@@ -600,6 +618,15 @@ ConvertCWSDExpToMomentum::loadSpiceData(const std::string &filename,
     sizelist[1] = 256;
     loader->setProperty("DetectorGeometry", sizelist);
     loader->setProperty("LoadInstrument", true);
+    loader->setProperty("ShiftedDetectorDistance", m_detSampleDistanceShift);
+    loader->setProperty("DetectorCenterXShift", m_detXShift);
+    loader->setProperty("DetectorCenterYShift", m_detYShift);
+
+    double wavelength = getProperty("UserDefinedWavelength");
+
+    if (wavelength != EMPTY_DBL()) {
+      loader->setProperty("UserSpecifiedWaveLength", wavelength);
+    }
 
     loader->execute();
 
diff --git a/Framework/MDAlgorithms/src/ConvertCWSDMDtoHKL.cpp b/Framework/MDAlgorithms/src/ConvertCWSDMDtoHKL.cpp
index 0b4cfb8c09e8d03c85fc907c89b421410b518b94..8d3ad9c0fdb2c5fab94b19c6f5ecfceab3cac00c 100644
--- a/Framework/MDAlgorithms/src/ConvertCWSDMDtoHKL.cpp
+++ b/Framework/MDAlgorithms/src/ConvertCWSDMDtoHKL.cpp
@@ -1,5 +1,6 @@
 #include "MantidMDAlgorithms/ConvertCWSDMDtoHKL.h"
 
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/WorkspaceProperty.h"
 #include "MantidAPI/IMDEventWorkspace.h"
 #include "MantidAPI/IMDIterator.h"
@@ -105,7 +106,7 @@ void ConvertCWSDMDtoHKL::exec() {
 
   std::string qsamplefilename = getPropertyValue("QSampleFileName");
   // Abort with an empty string
-  if (qsamplefilename.size() > 0)
+  if (!qsamplefilename.empty())
     saveEventsToFile(qsamplefilename, vec_event_qsample, vec_event_signal,
                      vec_event_det);
 
@@ -116,7 +117,7 @@ void ConvertCWSDMDtoHKL::exec() {
   // Get file name
   std::string hklfilename = getPropertyValue("HKLFileName");
   // Abort mission if no file name is given
-  if (hklfilename.size() > 0)
+  if (!hklfilename.empty())
     saveEventsToFile(hklfilename, vec_event_hkl, vec_event_signal,
                      vec_event_det);
 
@@ -136,7 +137,7 @@ void ConvertCWSDMDtoHKL::exec() {
 
 void ConvertCWSDMDtoHKL::getUBMatrix() {
   std::string peakwsname = getPropertyValue("PeaksWorkspace");
-  if (peakwsname.size() > 0 &&
+  if (!peakwsname.empty() &&
       AnalysisDataService::Instance().doesExist(peakwsname)) {
     // Get from peak works
     DataObjects::PeaksWorkspace_sptr peakws = getProperty("PeaksWorkspace");
@@ -221,7 +222,7 @@ void ConvertCWSDMDtoHKL::saveMDToFile(
   std::string filename = getPropertyValue("QSampleFileName");
 
   // Abort with an empty string
-  if (filename.size() == 0)
+  if (filename.empty())
     return;
   if (vec_event_qsample.size() != vec_event_signal.size())
     throw std::runtime_error(
diff --git a/Framework/MDAlgorithms/src/ConvertToDetectorFaceMD.cpp b/Framework/MDAlgorithms/src/ConvertToDetectorFaceMD.cpp
index 93898efc6aac2ad4fab39739c8e6b326ade77a7f..b863c49c5157ec73ae80074f03a61fc29c047fa4 100644
--- a/Framework/MDAlgorithms/src/ConvertToDetectorFaceMD.cpp
+++ b/Framework/MDAlgorithms/src/ConvertToDetectorFaceMD.cpp
@@ -4,6 +4,7 @@
 #include "MantidKernel/ArrayLengthValidator.h"
 #include "MantidKernel/Strings.h"
 #include "MantidKernel/System.h"
+#include "MantidKernel/Unit.h"
 #include "MantidDataObjects/EventWorkspace.h"
 #include "MantidDataObjects/MDEventFactory.h"
 #include "MantidGeometry/Instrument/RectangularDetector.h"
diff --git a/Framework/MDAlgorithms/src/ConvertToDiffractionMDWorkspace.cpp b/Framework/MDAlgorithms/src/ConvertToDiffractionMDWorkspace.cpp
index 67072208957d5369f20b051c98230b8418fd9496..21d131ade6e6383a94c1f9e17a566546bf1fe653 100644
--- a/Framework/MDAlgorithms/src/ConvertToDiffractionMDWorkspace.cpp
+++ b/Framework/MDAlgorithms/src/ConvertToDiffractionMDWorkspace.cpp
@@ -20,6 +20,7 @@
 #include "MantidKernel/ProgressText.h"
 #include "MantidKernel/System.h"
 #include "MantidKernel/Timer.h"
+#include "MantidKernel/Unit.h"
 #include "MantidKernel/UnitLabelTypes.h"
 #include "MantidKernel/ListValidator.h"
 #include "MantidKernel/ConfigService.h"
diff --git a/Framework/MDAlgorithms/src/ConvertToMD.cpp b/Framework/MDAlgorithms/src/ConvertToMD.cpp
index 357b1895c9e41ce8fd54288603d5bef07d82d5ef..7fe708222b341a2c09a3d13dbde976054e333595 100644
--- a/Framework/MDAlgorithms/src/ConvertToMD.cpp
+++ b/Framework/MDAlgorithms/src/ConvertToMD.cpp
@@ -5,6 +5,7 @@
 #include "MantidAPI/IMDEventWorkspace.h"
 #include "MantidAPI/FileProperty.h"
 #include "MantidAPI/Run.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidKernel/EnabledWhenProperty.h"
 
 #include "MantidKernel/ArrayProperty.h"
@@ -307,18 +308,15 @@ void ConvertToMD::copyMetaData(API::IMDEventWorkspace_sptr &mdEventWS) const {
   // found detector which is not a monitor to get proper bin boundaries.
   size_t spectra_index(0);
   bool dector_found(false);
+  const auto &spectrumInfo = m_InWS2D->spectrumInfo();
   for (size_t i = 0; i < m_InWS2D->getNumberHistograms(); ++i) {
-    try {
-      auto det = m_InWS2D->getDetector(i);
-      if (!det->isMonitor()) {
-        spectra_index = i;
-        dector_found = true;
-        g_log.debug() << "Using spectra N " << i << " as the source of the bin "
-                                                    "boundaries for the "
-                                                    "resolution corrections \n";
-        break;
-      }
-    } catch (...) {
+    if (spectrumInfo.hasDetectors(i) && spectrumInfo.isMonitor(i)) {
+      spectra_index = i;
+      dector_found = true;
+      g_log.debug() << "Using spectra N " << i
+                    << " as the source of the bin "
+                       "boundaries for the resolution corrections \n";
+      break;
     }
   }
   if (!dector_found)
@@ -357,10 +355,7 @@ void ConvertToMD::copyMetaData(API::IMDEventWorkspace_sptr &mdEventWS) const {
   auto mapping = boost::make_shared<det2group_map>();
   for (size_t i = 0; i < m_InWS2D->getNumberHistograms(); ++i) {
     const auto &dets = m_InWS2D->getSpectrum(i).getDetectorIDs();
-    if (!dets.empty()) {
-      mapping->emplace(*dets.begin(),
-                       std::vector<detid_t>(dets.begin(), dets.end()));
-    }
+    mapping->emplace(*dets.begin(), dets);
   }
 
   // The last experiment info should always be the one that refers
diff --git a/Framework/MDAlgorithms/src/ConvertToMDParent.cpp b/Framework/MDAlgorithms/src/ConvertToMDParent.cpp
index c1ab2ba739b112a5d9000c176f4e77f6c344a03f..69eec8c85ef1f5ee2edc564fc847d3d2adeb5bf4 100644
--- a/Framework/MDAlgorithms/src/ConvertToMDParent.cpp
+++ b/Framework/MDAlgorithms/src/ConvertToMDParent.cpp
@@ -1,5 +1,6 @@
 #include "MantidMDAlgorithms/ConvertToMDParent.h"
 
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/IMDEventWorkspace.h"
 #include "MantidAPI/InstrumentValidator.h"
 #include "MantidAPI/Run.h"
diff --git a/Framework/MDAlgorithms/src/ConvertToReflectometryQ.cpp b/Framework/MDAlgorithms/src/ConvertToReflectometryQ.cpp
index 17ca579dfd540b6d65f53a061651b8ca8c20ead7..67332bf786317f9b1d5337bccf159c235e5f18e2 100644
--- a/Framework/MDAlgorithms/src/ConvertToReflectometryQ.cpp
+++ b/Framework/MDAlgorithms/src/ConvertToReflectometryQ.cpp
@@ -22,6 +22,7 @@
 #include "MantidKernel/EnabledWhenProperty.h"
 #include "MantidKernel/ListValidator.h"
 #include "MantidKernel/TimeSeriesProperty.h"
+#include "MantidKernel/Unit.h"
 
 #include "MantidMDAlgorithms/ReflectometryTransformKiKf.h"
 #include "MantidMDAlgorithms/ReflectometryTransformQxQz.h"
diff --git a/Framework/MDAlgorithms/src/CreateMD.cpp b/Framework/MDAlgorithms/src/CreateMD.cpp
index a492605d2b14f04ab6c51b32e319152870b9f356..7241c8dc04155765d937ee231d47f14e24201551 100644
--- a/Framework/MDAlgorithms/src/CreateMD.cpp
+++ b/Framework/MDAlgorithms/src/CreateMD.cpp
@@ -1,5 +1,6 @@
 #include "MantidMDAlgorithms/CreateMD.h"
 #include "MantidKernel/ArrayProperty.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/FileProperty.h"
 #include "MantidAPI/Run.h"
 #include "MantidAPI/Sample.h"
diff --git a/Framework/MDAlgorithms/src/GetSpiceDataRawCountsFromMD.cpp b/Framework/MDAlgorithms/src/GetSpiceDataRawCountsFromMD.cpp
index ddf4bdc9fca8e93ba2abe6f21f428021e7365a67..d50c77384c93a16ff03303fef1a021e541aa305c 100644
--- a/Framework/MDAlgorithms/src/GetSpiceDataRawCountsFromMD.cpp
+++ b/Framework/MDAlgorithms/src/GetSpiceDataRawCountsFromMD.cpp
@@ -108,7 +108,7 @@ void GetSpiceDataRawCountsFromMD::exec() {
                               ylabel, donormalize);
   } else if (mode.compare("Sample Log") == 0) {
     std::string samplelogname = getProperty("SampleLogName");
-    if (samplelogname.size() == 0)
+    if (samplelogname.empty())
       throw std::runtime_error(
           "For mode 'Sample Log', value of 'SampleLogName' must be specified.");
     exportSampleLogValue(datamdws, samplelogname, vecX, vecY, xlabel, ylabel);
@@ -220,7 +220,7 @@ void GetSpiceDataRawCountsFromMD::exportIndividualDetCounts(
   std::vector<double> vecDetCounts;
   int runnumber = -1;
   bool get2theta = false;
-  if (xlabel.size() == 0) {
+  if (xlabel.empty()) {
     // xlabel is in default and thus use 2-theta for X
     get2theta = true;
   }
@@ -305,7 +305,7 @@ void GetSpiceDataRawCountsFromMD::exportSampleLogValue(
   ylabel = samplelogname;
 
   // X values
-  if (xlabel.size() == 0) {
+  if (xlabel.empty()) {
     // default
     xlabel = "Pt.";
   }
@@ -382,8 +382,8 @@ void GetSpiceDataRawCountsFromMD::getDetCounts(
   while (scancell) {
     // get the number of events of this cell
     size_t numev2 = mditer->getNumEvents();
-    g_log.debug() << "MDWorkspace " << mdws->name() << " Cell " << nextindex - 1
-                  << ": Number of events = " << numev2
+    g_log.debug() << "MDWorkspace " << mdws->getName() << " Cell "
+                  << nextindex - 1 << ": Number of events = " << numev2
                   << " Does NEXT cell exist = " << mditer->next() << "\n";
 
     // loop over all the events in current cell
@@ -460,7 +460,7 @@ void GetSpiceDataRawCountsFromMD::getSampleLogValues(
     // Check property exists
     if (!expinfo->run().hasProperty(samplelogname)) {
       std::stringstream ess;
-      ess << "Workspace " << mdws->name() << "'s " << iexp
+      ess << "Workspace " << mdws->getName() << "'s " << iexp
           << "-th ExperimentInfo with "
              "run number " << thisrunnumber
           << " does not have specified property " << samplelogname;
@@ -513,7 +513,7 @@ MatrixWorkspace_sptr GetSpiceDataRawCountsFromMD::createOutputWorkspace(
 
   // Set label
   outws->setYUnitLabel(ylabel);
-  if (xlabel.size() != 0) {
+  if (!xlabel.empty()) {
     try {
       outws->getAxis(0)->setUnit(xlabel);
     } catch (...) {
diff --git a/Framework/MDAlgorithms/src/IntegrateEllipsoids.cpp b/Framework/MDAlgorithms/src/IntegrateEllipsoids.cpp
index d66b667fd9674db809b6ba27aaf2614bd53db80b..3d01e70a23099ff9aa1429a52ecae26444f090ee 100644
--- a/Framework/MDAlgorithms/src/IntegrateEllipsoids.cpp
+++ b/Framework/MDAlgorithms/src/IntegrateEllipsoids.cpp
@@ -1,5 +1,7 @@
 #include "MantidMDAlgorithms/IntegrateEllipsoids.h"
 
+#include "MantidAPI/AnalysisDataService.h"
+#include "MantidAPI/DetectorInfo.h"
 #include "MantidAPI/FileProperty.h"
 #include "MantidAPI/InstrumentValidator.h"
 #include "MantidAPI/Run.h"
@@ -277,6 +279,16 @@ void IntegrateEllipsoids::init() {
       "IntegrateIfOnEdge", true,
       "Set to false to not integrate if peak radius is off edge of detector."
       "Background will be scaled if background radius is off edge.");
+
+  declareProperty("AdaptiveQBackground", false,
+                  "Default is false.   If true, "
+                  "BackgroundOuterRadius + AdaptiveQMultiplier * **|Q|** and "
+                  "BackgroundInnerRadius + AdaptiveQMultiplier * **|Q|**");
+
+  declareProperty("AdaptiveQMultiplier", 0.0,
+                  "PeakRadius + AdaptiveQMultiplier * **|Q|** "
+                  "so each peak has a "
+                  "different integration radius.  Q includes the 2*pi factor.");
 }
 
 //---------------------------------------------------------------------
@@ -314,6 +326,11 @@ void IntegrateEllipsoids::exec() {
   double back_outer_radius = getProperty("BackgroundOuterSize");
   bool hkl_integ = getProperty("IntegrateInHKL");
   bool integrateEdge = getProperty("IntegrateIfOnEdge");
+  bool adaptiveQBackground = getProperty("AdaptiveQBackground");
+  double adaptiveQMultiplier = getProperty("AdaptiveQMultiplier");
+  double adaptiveQBackgroundMultiplier = 0.0;
+  if (adaptiveQBackground)
+    adaptiveQBackgroundMultiplier = adaptiveQMultiplier;
   if (!integrateEdge) {
     // This only fails in the unit tests which say that MaskBTP is not
     // registered
@@ -324,9 +341,7 @@ void IntegrateEllipsoids::exec() {
       g_log.error("Can't execute MaskBTP algorithm for this instrument to set "
                   "edge for IntegrateIfOnEdge option");
     }
-    // Get the instrument and its detectors
-    Geometry::Instrument_const_sptr inst = in_peak_ws->getInstrument();
-    calculateE1(inst); // fill E1Vec for use in detectorQ
+    calculateE1(in_peak_ws->detectorInfo()); // fill E1Vec for use in detectorQ
   }
 
   Mantid::DataObjects::PeaksWorkspace_sptr peak_ws =
@@ -417,10 +432,38 @@ void IntegrateEllipsoids::exec() {
     if (Geometry::IndexingUtils::ValidIndex(hkl, 1.0)) {
       peak_q = peaks[i].getQLabFrame();
       std::vector<double> axes_radii;
+      // modulus of Q
+      double lenQpeak = 0.0;
+      if (adaptiveQMultiplier != 0.0) {
+        for (size_t d = 0; d < 3; d++) {
+          lenQpeak += peak_q[d] * peak_q[d];
+        }
+        lenQpeak = std::sqrt(lenQpeak);
+      }
+      const double adaptiveRadius =
+          adaptiveQMultiplier * lenQpeak + peak_radius;
+      if (adaptiveRadius <= 0.0) {
+        g_log.error() << "Error: Radius for integration sphere of peak " << i
+                      << " is negative =  " << adaptiveRadius << '\n';
+        peaks[i].setIntensity(0.0);
+        peaks[i].setSigmaIntensity(0.0);
+        PeakRadiusVector[i] = 0.0;
+        BackgroundInnerRadiusVector[i] = 0.0;
+        BackgroundOuterRadiusVector[i] = 0.0;
+        continue;
+      }
+      const double adaptiveBack_inner_radius =
+          adaptiveQBackgroundMultiplier * lenQpeak + back_inner_radius;
+      const double adaptiveBack_outer_radius =
+          adaptiveQBackgroundMultiplier * lenQpeak + back_outer_radius;
+      PeakRadiusVector[i] = adaptiveRadius;
+      BackgroundInnerRadiusVector[i] = adaptiveBack_inner_radius;
+      BackgroundOuterRadiusVector[i] = adaptiveBack_outer_radius;
       Mantid::Geometry::PeakShape_const_sptr shape =
           integrator.ellipseIntegrateEvents(
-              E1Vec, peak_q, specify_size, peak_radius, back_inner_radius,
-              back_outer_radius, axes_radii, inti, sigi);
+              E1Vec, peak_q, specify_size, adaptiveRadius,
+              adaptiveBack_inner_radius, adaptiveBack_outer_radius, axes_radii,
+              inti, sigi);
       peaks[i].setIntensity(inti);
       peaks[i].setSigmaIntensity(sigi);
       peaks[i].setPeakShape(shape);
@@ -483,9 +526,8 @@ void IntegrateEllipsoids::exec() {
                                                   stats2.standard_deviation),
                                          stats3.standard_deviation);
       back_inner_radius = peak_radius;
-      back_outer_radius =
-          peak_radius *
-          1.25992105; // A factor of 2 ^ (1/3) will make the background
+      back_outer_radius = peak_radius * 1.25992105; // A factor of 2 ^ (1/3)
+                                                    // will make the background
       // shell volume equal to the peak region volume.
       V3D peak_q;
       for (size_t i = 0; i < n_peaks; i++) {
@@ -585,17 +627,15 @@ void IntegrateEllipsoids::initTargetWSDescr(MatrixWorkspace_sptr &wksp) {
  *
  * @param inst: instrument
  */
-void IntegrateEllipsoids::calculateE1(Geometry::Instrument_const_sptr inst) {
-  std::vector<detid_t> detectorIDs = inst->getDetectorIDs();
-
-  for (auto &detectorID : detectorIDs) {
-    Mantid::Geometry::IDetector_const_sptr det = inst->getDetector(detectorID);
-    if (det->isMonitor())
+void IntegrateEllipsoids::calculateE1(const API::DetectorInfo &detectorInfo) {
+  for (size_t i = 0; i < detectorInfo.size(); ++i) {
+    if (detectorInfo.isMonitor(i))
       continue; // skip monitor
-    if (!det->isMasked())
+    if (!detectorInfo.isMasked(i))
       continue; // edge is masked so don't check if not masked
-    double tt1 = det->getTwoTheta(V3D(0, 0, 0), V3D(0, 0, 1)); // two theta
-    double ph1 = det->getPhi();                                // phi
+    const auto &det = detectorInfo.detector(i);
+    double tt1 = det.getTwoTheta(V3D(0, 0, 0), V3D(0, 0, 1)); // two theta
+    double ph1 = det.getPhi();                                // phi
     V3D E1 = V3D(-std::sin(tt1) * std::cos(ph1), -std::sin(tt1) * std::sin(ph1),
                  1. - std::cos(tt1)); // end of trajectory
     E1 = E1 * (1. / E1.norm());       // normalize
diff --git a/Framework/MDAlgorithms/src/IntegratePeaksCWSD.cpp b/Framework/MDAlgorithms/src/IntegratePeaksCWSD.cpp
index 4c724bcb83d0a2615662feb52351fe6496cc42e0..82ee67bace0ac3997e3dd46ad003be4ed13127bf 100644
--- a/Framework/MDAlgorithms/src/IntegratePeaksCWSD.cpp
+++ b/Framework/MDAlgorithms/src/IntegratePeaksCWSD.cpp
@@ -125,7 +125,7 @@ void IntegratePeaksCWSD::processInputs() {
 
   // Input peaks
   std::vector<double> peak_center = getProperty("PeakCentre");
-  if (peak_center.size() > 0) {
+  if (!peak_center.empty()) {
     // assigned peak center
     if (peak_center.size() != 3)
       throw std::invalid_argument("PeakCentre must have 3 elements.");
@@ -187,7 +187,7 @@ void IntegratePeaksCWSD::processInputs() {
 
   // optional mask workspace
   std::string maskwsname = getPropertyValue("MaskWorkspace");
-  if (maskwsname.size() > 0) {
+  if (!maskwsname.empty()) {
     // process mask workspace
     m_maskDets = true;
     m_maskWS = getProperty("MaskWorkspace");
@@ -254,7 +254,7 @@ void IntegratePeaksCWSD::simplePeakIntegration(
       // ... debug */
 
       // Check whether this detector is masked
-      if (vecMaskedDetID.size() > 0) {
+      if (!vecMaskedDetID.empty()) {
         detid_t detid = mditer->getInnerDetectorID(iev);
         std::vector<detid_t>::const_iterator it;
 
diff --git a/Framework/MDAlgorithms/src/IntegratePeaksMD2.cpp b/Framework/MDAlgorithms/src/IntegratePeaksMD2.cpp
index 93bc846481f64e5b918f0d561d69bd4110427e0a..e319a3ae00201c9ce4e3c3d5cc2887f9266c430c 100644
--- a/Framework/MDAlgorithms/src/IntegratePeaksMD2.cpp
+++ b/Framework/MDAlgorithms/src/IntegratePeaksMD2.cpp
@@ -13,6 +13,7 @@
 #include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/TextAxis.h"
 #include "MantidKernel/Utils.h"
+#include "MantidAPI/DetectorInfo.h"
 #include "MantidAPI/FileProperty.h"
 #include "MantidAPI/TableRow.h"
 #include "MantidAPI/Column.h"
@@ -89,7 +90,7 @@ void IntegratePeaksMD2::init() {
 
   declareProperty("AdaptiveQBackground", false,
                   "Default is false.   If true, "
-                  "BackgroundOuterRadius + AdaptiveQMultiplier * **|Q|**"
+                  "BackgroundOuterRadius + AdaptiveQMultiplier * **|Q|** and "
                   "BackgroundInnerRadius + AdaptiveQMultiplier * **|Q|**");
 
   declareProperty("Cylinder", false,
@@ -170,9 +171,7 @@ void IntegratePeaksMD2::integrate(typename MDEventWorkspace<MDE, nd>::sptr ws) {
                 "edge for IntegrateIfOnEdge option");
   }
 
-  // Get the instrument and its detectors
-  Geometry::Instrument_const_sptr inst = inPeakWS->getInstrument();
-  calculateE1(inst); // fill E1Vec for use in detectorQ
+  calculateE1(inPeakWS->detectorInfo()); // fill E1Vec for use in detectorQ
   Mantid::Kernel::SpecialCoordinateSystem CoordinatesToUse =
       ws->getSpecialCoordinateSystem();
 
@@ -377,32 +376,11 @@ void IntegratePeaksMD2::integrate(typename MDEventWorkspace<MDE, nd>::sptr ws) {
                                   BackgroundOuterRadius) *
                                  (adaptiveQBackgroundMultiplier * lenQpeak +
                                   BackgroundOuterRadius)),
-            bgSignal, bgErrorSquared);
-
-        // Evaluate the signal inside "BackgroundInnerRadius"
-        signal_t interiorSignal = 0;
-        signal_t interiorErrorSquared = 0;
-
-        // Integrate this 3rd radius, if needed
-        if (BackgroundInnerRadius != PeakRadius) {
-          ws->getBox()->integrateSphere(
-              sphere,
-              static_cast<coord_t>((adaptiveQBackgroundMultiplier * lenQpeak +
-                                    BackgroundInnerRadius) *
-                                   (adaptiveQBackgroundMultiplier * lenQpeak +
-                                    BackgroundInnerRadius)),
-              interiorSignal, interiorErrorSquared);
-        } else {
-          // PeakRadius == BackgroundInnerRadius, so use the previous value
-          interiorSignal = signal;
-          interiorErrorSquared = errorSquared;
-        }
-        // Subtract the peak part to get the intensity in the shell
-        // (BackgroundInnerRadius < r < BackgroundOuterRadius)
-        bgSignal -= interiorSignal;
-        // We can subtract the error (instead of adding) because the two values
-        // are 100% dependent; this is the same as integrating a shell.
-        bgErrorSquared -= interiorErrorSquared;
+            bgSignal, bgErrorSquared,
+            static_cast<coord_t>((adaptiveQBackgroundMultiplier * lenQpeak +
+                                  BackgroundInnerRadius) *
+                                 (adaptiveQBackgroundMultiplier * lenQpeak +
+                                  BackgroundInnerRadius)));
 
         // Relative volume of peak vs the BackgroundOuterRadius sphere
         double ratio = (PeakRadius / BackgroundOuterRadius);
@@ -703,17 +681,15 @@ void IntegratePeaksMD2::integrate(typename MDEventWorkspace<MDE, nd>::sptr ws) {
  *
  * @param inst: instrument
  */
-void IntegratePeaksMD2::calculateE1(Geometry::Instrument_const_sptr inst) {
-  std::vector<detid_t> detectorIDs = inst->getDetectorIDs();
-
-  for (auto &detectorID : detectorIDs) {
-    Mantid::Geometry::IDetector_const_sptr det = inst->getDetector(detectorID);
-    if (det->isMonitor())
+void IntegratePeaksMD2::calculateE1(const API::DetectorInfo &detectorInfo) {
+  for (size_t i = 0; i < detectorInfo.size(); ++i) {
+    if (detectorInfo.isMonitor(i))
       continue; // skip monitor
-    if (!det->isMasked())
+    if (!detectorInfo.isMasked(i))
       continue; // edge is masked so don't check if not masked
-    double tt1 = det->getTwoTheta(V3D(0, 0, 0), V3D(0, 0, 1)); // two theta
-    double ph1 = det->getPhi();                                // phi
+    const auto &det = detectorInfo.detector(i);
+    double tt1 = det.getTwoTheta(V3D(0, 0, 0), V3D(0, 0, 1)); // two theta
+    double ph1 = det.getPhi();                                // phi
     V3D E1 = V3D(-std::sin(tt1) * std::cos(ph1), -std::sin(tt1) * std::sin(ph1),
                  1. - std::cos(tt1)); // end of trajectory
     E1 = E1 * (1. / E1.norm());       // normalize
diff --git a/Framework/MDAlgorithms/src/LoadILLAscii.cpp b/Framework/MDAlgorithms/src/LoadILLAscii.cpp
index e5cb0a709f132cdf732e78fb9f5c504e027c3954..589437c2d6779eb87385ee750fa55e59f09105de 100644
--- a/Framework/MDAlgorithms/src/LoadILLAscii.cpp
+++ b/Framework/MDAlgorithms/src/LoadILLAscii.cpp
@@ -270,7 +270,7 @@ IMDEventWorkspace_sptr LoadILLAscii::mergeWorkspaces(
     std::vector<API::MatrixWorkspace_sptr> &workspaceList) {
 
   Poco::TemporaryFile tmpFile;
-  std::string tempFileName = tmpFile.path();
+  const std::string &tempFileName = tmpFile.path();
   g_log.debug() << "Dumping WSs in a temp file: " << tempFileName << '\n';
 
   std::ofstream myfile;
diff --git a/Framework/MDAlgorithms/src/LoadMD.cpp b/Framework/MDAlgorithms/src/LoadMD.cpp
index 9ab86e6b054d38f0b219c9a51b0bfb200aba3930..1840056ee62f63d3ee6979b7c64055d338847dfa 100644
--- a/Framework/MDAlgorithms/src/LoadMD.cpp
+++ b/Framework/MDAlgorithms/src/LoadMD.cpp
@@ -3,6 +3,7 @@
 #include "MantidAPI/IMDEventWorkspace.h"
 #include "MantidAPI/IMDWorkspace.h"
 #include "MantidAPI/RegisterFileLoader.h"
+#include "MantidAPI/WorkspaceHistory.h"
 #include "MantidGeometry/MDGeometry/IMDDimension.h"
 #include "MantidGeometry/MDGeometry/IMDDimensionFactory.h"
 #include "MantidGeometry/MDGeometry/MDDimensionExtents.h"
@@ -27,6 +28,7 @@
 #include <nexus/NeXusException.hpp>
 #include <boost/algorithm/string.hpp>
 #include <boost/regex.hpp>
+#include <iostream>
 #include <vector>
 
 typedef std::unique_ptr<Mantid::API::IBoxControllerIO> file_holder_type;
diff --git a/Framework/MDAlgorithms/src/LoadSQW.cpp b/Framework/MDAlgorithms/src/LoadSQW.cpp
index dcda30704a79e32fb176c27ea7f6cd0ed19b16ee..b7d88df0e6fe3ad5d9d696d310ed148596ff714b 100644
--- a/Framework/MDAlgorithms/src/LoadSQW.cpp
+++ b/Framework/MDAlgorithms/src/LoadSQW.cpp
@@ -4,6 +4,7 @@
 #include "MantidAPI/Run.h"
 #include "MantidAPI/Sample.h"
 #include "MantidAPI/WorkspaceProperty.h"
+#include "MantidGeometry/Instrument/Goniometer.h"
 #include "MantidGeometry/MDGeometry/MDHistoDimensionBuilder.h"
 #include "MantidGeometry/Crystal/OrientedLattice.h"
 #include "MantidKernel/CPUTimer.h"
diff --git a/Framework/MDAlgorithms/src/MDNormDirectSC.cpp b/Framework/MDAlgorithms/src/MDNormDirectSC.cpp
index af8c4b43df728be47813e01d008209789402573b..d4d7a5a0733ce25e5be3fa6373bcded39537ae23 100644
--- a/Framework/MDAlgorithms/src/MDNormDirectSC.cpp
+++ b/Framework/MDAlgorithms/src/MDNormDirectSC.cpp
@@ -3,14 +3,18 @@
 #include "MantidAPI/CommonBinsValidator.h"
 #include "MantidAPI/InstrumentValidator.h"
 #include "MantidAPI/Run.h"
+#include "MantidAPI/SpectrumInfo.h"
+#include "MantidAPI/WorkspaceHistory.h"
 #include "MantidDataObjects/EventWorkspace.h"
 #include "MantidDataObjects/MDEventWorkspace.h"
 #include "MantidDataObjects/MDHistoWorkspace.h"
 #include "MantidGeometry/Instrument.h"
 #include "MantidKernel/CompositeValidator.h"
+#include "MantidKernel/Strings.h"
 #include "MantidKernel/TimeSeriesProperty.h"
 #include "MantidKernel/VectorHelper.h"
 #include "MantidKernel/ConfigService.h"
+#include "MantidKernel/PhysicalConstants.h"
 
 namespace Mantid {
 namespace MDAlgorithms {
@@ -118,8 +122,10 @@ void MDNormDirectSC::exec() {
   cacheInputs();
   auto outputWS = binInputWS();
   convention = Kernel::ConfigService::Instance().getString("Q.convention");
+  outputWS->setDisplayNormalization(Mantid::API::NoNormalization);
   setProperty<Workspace_sptr>("OutputWorkspace", outputWS);
   createNormalizationWS(*outputWS);
+  m_normWS->setDisplayNormalization(Mantid::API::NoNormalization);
   setProperty("OutputNormalizationWorkspace", m_normWS);
 
   // Check for other dimensions if we could measure anything in the original
@@ -437,14 +443,11 @@ void MDNormDirectSC::calculateNormalization(
   }
   const double protonCharge = exptInfoZero.run().getProtonCharge();
 
-  auto instrument = exptInfoZero.getInstrument();
-  std::vector<detid_t> detIDs = instrument->getDetectorIDs(true);
-  // Prune out those that are part of a group and simply leave the head of the
-  // group
-  detIDs = removeGroupedIDs(exptInfoZero, detIDs);
+  const SpectrumInfo spectrumInfo(exptInfoZero);
 
   // Mapping
-  const int64_t ndets = static_cast<int64_t>(detIDs.size());
+  const int64_t ndets =
+      static_cast<int64_t>(exptInfoZero.numberOfDetectorGroups());
   bool haveSA = false;
   API::MatrixWorkspace_const_sptr solidAngleWS =
       getProperty("SolidAngleWorkspace");
@@ -459,22 +462,15 @@ void MDNormDirectSC::calculateNormalization(
   for (int64_t i = 0; i < ndets; i++) {
     PARALLEL_START_INTERUPT_REGION
 
-    const auto detID = detIDs[i];
-    double theta(0.0), phi(0.0);
-    bool skip(false);
-    try {
-      auto spectrum = getThetaPhi(detID, exptInfoZero, theta, phi);
-      if (spectrum->isMonitor() || spectrum->isMasked())
-        continue;
-    } catch (
-        std::exception &) // detector might not exist or has no been included
-                          // in grouping
-    {
-      skip = true; // Intel compiler has a problem with continue inside a catch
-                   // inside openmp...
-    }
-    if (skip)
+    if (!spectrumInfo.hasDetectors(i) || spectrumInfo.isMonitor(i) ||
+        spectrumInfo.isMasked(i)) {
       continue;
+    }
+    const auto &detector = spectrumInfo.detector(i);
+    double theta = detector.getTwoTheta(m_samplePos, m_beamDir);
+    double phi = detector.getPhi();
+    // If the dtefctor is a group, this should be the ID of the first detector
+    const auto detID = detector.getID();
 
     // Intersections
     auto intersections = calculateIntersections(theta, phi);
@@ -533,64 +529,6 @@ void MDNormDirectSC::calculateNormalization(
   PARALLEL_CHECK_INTERUPT_REGION
 }
 
-/**
- * Checks for IDs that are actually part of the same group and just keeps one
- * from the group.
- * For a 1:1 map, none will be removed.
- * @param exptInfo An ExperimentInfo object that defines the grouping
- * @param detIDs A list of existing IDs
- * @return A new list of IDs
- */
-std::vector<detid_t>
-MDNormDirectSC::removeGroupedIDs(const ExperimentInfo &exptInfo,
-                                 const std::vector<detid_t> &detIDs) {
-  const size_t ntotal = detIDs.size();
-  std::vector<detid_t> singleIDs;
-  singleIDs.reserve(ntotal / 2); // reserve half. In the case of 1:1 it will
-                                 // double to the correct size once
-  std::set<detid_t> groupedIDs;
-
-  for (auto curID : detIDs) {
-    if (groupedIDs.count(curID) == 1)
-      continue; // Already been processed
-
-    try {
-      const auto &members = exptInfo.getGroupMembers(curID);
-      singleIDs.push_back(members.front());
-      std::copy(members.begin() + 1, members.end(),
-                std::inserter(groupedIDs, groupedIDs.begin()));
-    } catch (std::runtime_error &) {
-      singleIDs.push_back(curID);
-    }
-  }
-
-  g_log.debug() << "Found " << singleIDs.size() << " spectra from  "
-                << detIDs.size() << " IDs\n";
-  return singleIDs;
-}
-
-/**
- * Get the theta and phi angles for the given ID. If the detector was part of a
- * group,
- * as defined in the ExperimentInfo object, then the theta/phi are for the whole
- * set.
- * @param detID A reference to a single ID
- * @param exptInfo A reference to the ExperimentInfo that defines that
- * spectrum->detector mapping
- * @param theta [Output] Set to the theta angle for the detector (set)
- * @param phi [Output] Set to the phi angle for the detector (set)
- * @return A poiner to the Detector object for this spectrum as a whole
- *         (may be a single pixel or group)
- */
-Geometry::IDetector_const_sptr
-MDNormDirectSC::getThetaPhi(const detid_t detID, const ExperimentInfo &exptInfo,
-                            double &theta, double &phi) {
-  const auto spectrum = exptInfo.getDetectorByID(detID);
-  theta = spectrum->getTwoTheta(m_samplePos, m_beamDir);
-  phi = spectrum->getPhi();
-  return spectrum;
-}
-
 /**
  * Calculate the points of intersection for the given detector with cuboid
  * surrounding the
diff --git a/Framework/MDAlgorithms/src/MDNormSCD.cpp b/Framework/MDAlgorithms/src/MDNormSCD.cpp
index 99efceaf9c60422b9efa5850798b430cc6af508c..4d59359dfa0a8e0fa180ea11dd2dd3e05b67391d 100644
--- a/Framework/MDAlgorithms/src/MDNormSCD.cpp
+++ b/Framework/MDAlgorithms/src/MDNormSCD.cpp
@@ -3,12 +3,16 @@
 #include "MantidAPI/CommonBinsValidator.h"
 #include "MantidAPI/InstrumentValidator.h"
 #include "MantidAPI/Run.h"
+#include "MantidAPI/SpectrumInfo.h"
+#include "MantidAPI/WorkspaceHistory.h"
 #include "MantidAPI/WorkspaceUnitValidator.h"
 #include "MantidDataObjects/EventWorkspace.h"
 #include "MantidDataObjects/MDEventWorkspace.h"
 #include "MantidDataObjects/MDHistoWorkspace.h"
 #include "MantidGeometry/Instrument.h"
 #include "MantidKernel/CompositeValidator.h"
+#include "MantidKernel/ConfigService.h"
+#include "MantidKernel/Strings.h"
 #include "MantidKernel/TimeSeriesProperty.h"
 #include "MantidKernel/VectorHelper.h"
 
@@ -113,8 +117,10 @@ void MDNormSCD::exec() {
   cacheInputs();
   auto outputWS = binInputWS();
   convention = Kernel::ConfigService::Instance().getString("Q.convention");
+  outputWS->setDisplayNormalization(Mantid::API::NoNormalization);
   setProperty<Workspace_sptr>("OutputWorkspace", outputWS);
   createNormalizationWS(*outputWS);
+  m_normWS->setDisplayNormalization(Mantid::API::NoNormalization);
   setProperty("OutputNormalizationWorkspace", m_normWS);
 
   // Check for other dimensions if we could measure anything in the original
@@ -387,14 +393,11 @@ void MDNormSCD::calculateNormalization(
   }
   const double protonCharge = exptInfoZero.run().getProtonCharge();
 
-  auto instrument = exptInfoZero.getInstrument();
-  std::vector<detid_t> detIDs = instrument->getDetectorIDs(true);
-  // Prune out those that are part of a group and simply leave the head of the
-  // group
-  detIDs = removeGroupedIDs(exptInfoZero, detIDs);
+  const SpectrumInfo spectrumInfo(exptInfoZero);
 
   // Mappings
-  const int64_t ndets = static_cast<int64_t>(detIDs.size());
+  const int64_t ndets =
+      static_cast<int64_t>(exptInfoZero.numberOfDetectorGroups());
   const detid2index_map fluxDetToIdx =
       integrFlux->getDetectorIDToWorkspaceIndexMap();
   const detid2index_map solidAngDetToIdx =
@@ -405,22 +408,15 @@ void MDNormSCD::calculateNormalization(
   for (int64_t i = 0; i < ndets; i++) {
     PARALLEL_START_INTERUPT_REGION
 
-    const auto detID = detIDs[i];
-    double theta(0.0), phi(0.0);
-    bool skip(false);
-    try {
-      auto spectrum = getThetaPhi(detID, exptInfoZero, theta, phi);
-      if (spectrum->isMonitor() || spectrum->isMasked())
-        continue;
-    } catch (
-        std::exception &) // detector might not exist or has no been included
-                          // in grouping
-    {
-      skip = true; // Intel compiler has a problem with continue inside a catch
-                   // inside openmp...
-    }
-    if (skip)
+    if (!spectrumInfo.hasDetectors(i) || spectrumInfo.isMonitor(i) ||
+        spectrumInfo.isMasked(i)) {
       continue;
+    }
+    const auto &detector = spectrumInfo.detector(i);
+    double theta = detector.getTwoTheta(m_samplePos, m_beamDir);
+    double phi = detector.getPhi();
+    // If the dtefctor is a group, this should be the ID of the first detector
+    const auto detID = detector.getID();
 
     // Intersections
     auto intersections = calculateIntersections(theta, phi);
@@ -570,64 +566,6 @@ void MDNormSCD::calcIntegralsForIntersections(
   }
 }
 
-/**
- * Checks for IDs that are actually part of the same group and just keeps one
- * from the group.
- * For a 1:1 map, none will be removed.
- * @param exptInfo An ExperimentInfo object that defines the grouping
- * @param detIDs A list of existing IDs
- * @return A new list of IDs
- */
-std::vector<detid_t>
-MDNormSCD::removeGroupedIDs(const ExperimentInfo &exptInfo,
-                            const std::vector<detid_t> &detIDs) {
-  const size_t ntotal = detIDs.size();
-  std::vector<detid_t> singleIDs;
-  singleIDs.reserve(ntotal / 2); // reserve half. In the case of 1:1 it will
-                                 // double to the correct size once
-  std::set<detid_t> groupedIDs;
-
-  for (auto curID : detIDs) {
-    if (groupedIDs.count(curID) == 1)
-      continue; // Already been processed
-
-    try {
-      const auto &members = exptInfo.getGroupMembers(curID);
-      singleIDs.push_back(members.front());
-      std::copy(members.begin() + 1, members.end(),
-                std::inserter(groupedIDs, groupedIDs.begin()));
-    } catch (std::runtime_error &) {
-      singleIDs.push_back(curID);
-    }
-  }
-
-  g_log.debug() << "Found " << singleIDs.size() << " spectra from  "
-                << detIDs.size() << " IDs\n";
-  return singleIDs;
-}
-
-/**
- * Get the theta and phi angles for the given ID. If the detector was part of a
- * group,
- * as defined in the ExperimentInfo object, then the theta/phi are for the whole
- * set.
- * @param detID A reference to a single ID
- * @param exptInfo A reference to the ExperimentInfo that defines that
- * spectrum->detector mapping
- * @param theta [Output] Set to the theta angle for the detector (set)
- * @param phi [Output] Set to the phi angle for the detector (set)
- * @return A poiner to the Detector object for this spectrum as a whole
- *         (may be a single pixel or group)
- */
-Geometry::IDetector_const_sptr
-MDNormSCD::getThetaPhi(const detid_t detID, const ExperimentInfo &exptInfo,
-                       double &theta, double &phi) {
-  const auto spectrum = exptInfo.getDetectorByID(detID);
-  theta = spectrum->getTwoTheta(m_samplePos, m_beamDir);
-  phi = spectrum->getPhi();
-  return spectrum;
-}
-
 /**
  * Calculate the points of intersection for the given detector with cuboid
  * surrounding the
diff --git a/Framework/MDAlgorithms/src/MDWSDescription.cpp b/Framework/MDAlgorithms/src/MDWSDescription.cpp
index 442c5a2070a8522be22a5fb6582039fc707a2563..5c638c4b3925d6d24558de1e2a5dce19cffa72f5 100644
--- a/Framework/MDAlgorithms/src/MDWSDescription.cpp
+++ b/Framework/MDAlgorithms/src/MDWSDescription.cpp
@@ -11,6 +11,7 @@
 
 #include "MantidMDAlgorithms/MDTransfFactory.h"
 #include "MantidGeometry/MDGeometry/MDFrameFactory.h"
+#include "MantidGeometry/Instrument/Goniometer.h"
 
 #include <boost/lexical_cast.hpp>
 
@@ -321,7 +322,7 @@ void MDWSDescription::getMinMax(std::vector<double> &min,
 /** Method checks if the workspace is expected to be processed in powder mode */
 bool MDWSDescription::isPowder() const {
   return (this->AlgID == "|Q|") ||
-         (this->AlgID.size() == 0 && !m_InWS->sample().hasOrientedLattice());
+         (this->AlgID.empty() && !m_InWS->sample().hasOrientedLattice());
 }
 
 /** Returns symbolic representation of current Emode */
diff --git a/Framework/MDAlgorithms/src/MDWSTransform.cpp b/Framework/MDAlgorithms/src/MDWSTransform.cpp
index 8c3ed24ff0065754c5bf6ca3329702e81267934f..441fa7c6324e151be2dc4888bb12eea5cc6c9a85 100644
--- a/Framework/MDAlgorithms/src/MDWSTransform.cpp
+++ b/Framework/MDAlgorithms/src/MDWSTransform.cpp
@@ -6,6 +6,7 @@
 #include "MantidGeometry/MDGeometry/QLab.h"
 #include "MantidGeometry/MDGeometry/QSample.h"
 #include "MantidKernel/MDUnit.h"
+#include "MantidKernel/Tolerance.h"
 
 #include <cfloat>
 
diff --git a/Framework/MDAlgorithms/src/MergeMD.cpp b/Framework/MDAlgorithms/src/MergeMD.cpp
index bdcfb08fa19f636f73065f4945c8238fa8ec51f4..47725d5b9dffb64db5c1f2a5f700973d2096b041 100644
--- a/Framework/MDAlgorithms/src/MergeMD.cpp
+++ b/Framework/MDAlgorithms/src/MergeMD.cpp
@@ -4,6 +4,8 @@
 #include "MantidDataObjects/MDBoxIterator.h"
 #include "MantidKernel/CPUTimer.h"
 #include "MantidKernel/MandatoryValidator.h"
+#include "MantidKernel/Strings.h"
+#include "MantidAPI/WorkspaceGroup.h"
 
 using namespace Mantid::Kernel;
 using namespace Mantid::API;
@@ -16,7 +18,6 @@ namespace MDAlgorithms {
 // Register the algorithm into the AlgorithmFactory
 DECLARE_ALGORITHM(MergeMD)
 
-//----------------------------------------------------------------------------------------------
 /// Algorithm's name for identification. @see Algorithm::name
 const std::string MergeMD::name() const { return "MergeMD"; }
 
@@ -26,9 +27,6 @@ int MergeMD::version() const { return 1; }
 /// Algorithm's category for identification. @see Algorithm::category
 const std::string MergeMD::category() const { return "MDAlgorithms\\Creation"; }
 
-//----------------------------------------------------------------------------------------------
-
-//----------------------------------------------------------------------------------------------
 /** Initialize the algorithm's properties.
  */
 void MergeMD::init() {
@@ -48,7 +46,6 @@ void MergeMD::init() {
   this->initBoxControllerProps("2", 500, 16);
 }
 
-//----------------------------------------------------------------------------------------------
 /** Create the output MDWorkspace from a list of input
  *
  * @param inputs :: list of names of input MDWorkspaces
@@ -83,14 +80,14 @@ void MergeMD::createOutputWorkspace(std::vector<std::string> &inputs) {
   for (auto &ws : m_workspaces) {
     if (ws->getNumDims() != numDims)
       throw std::invalid_argument(
-          "Workspace " + ws->name() +
+          "Workspace " + ws->getName() +
           " does not match the number of dimensions of the others (" +
           Strings::toString(ws->getNumDims()) + ", expected " +
           Strings::toString(numDims) + ")");
 
     if (ws->getEventTypeName() != ws0->getEventTypeName())
       throw std::invalid_argument(
-          "Workspace " + ws->name() +
+          "Workspace " + ws->getName() +
           " does not match the MDEvent type of the others (" +
           ws->getEventTypeName() + ", expected " + ws0->getEventTypeName() +
           ")");
@@ -99,10 +96,11 @@ void MergeMD::createOutputWorkspace(std::vector<std::string> &inputs) {
       IMDDimension_const_sptr dim = ws->getDimension(d);
       IMDDimension_const_sptr dim0 = ws0->getDimension(d);
       if (dim->getName() != dim0->getName())
-        throw std::invalid_argument(
-            "Workspace " + ws->name() + " does not have the same dimension " +
-            Strings::toString(d) + " as the others (" + dim->getName() +
-            ", expected " + dim0->getName() + ")");
+        throw std::invalid_argument("Workspace " + ws->getName() +
+                                    " does not have the same dimension " +
+                                    Strings::toString(d) + " as the others (" +
+                                    dim->getName() + ", expected " +
+                                    dim0->getName() + ")");
 
       // Find the extents
       if (dim->getMaximum() > dimMax[d])
@@ -162,11 +160,10 @@ void MergeMD::createOutputWorkspace(std::vector<std::string> &inputs) {
  * @param ws ::  MDEventWorkspace to clone
  */
 template <typename MDE, size_t nd>
-void MergeMD::doPlus(typename MDEventWorkspace<MDE, nd>::sptr ws) {
+void MergeMD::doPlus(typename MDEventWorkspace<MDE, nd>::sptr ws2) {
   // CPUTimer tim;
   typename MDEventWorkspace<MDE, nd>::sptr ws1 =
       boost::dynamic_pointer_cast<MDEventWorkspace<MDE, nd>>(out);
-  typename MDEventWorkspace<MDE, nd>::sptr ws2 = ws;
   if (!ws1 || !ws2)
     throw std::runtime_error("Incompatible workspace types passed to MergeMD.");
 
@@ -256,9 +253,9 @@ void MergeMD::exec() {
   // Run PlusMD on each of the input workspaces, in order.
   double progStep = 1.0 / double(m_workspaces.size());
   for (size_t i = 0; i < m_workspaces.size(); i++) {
-    g_log.information() << "Adding workspace " << m_workspaces[i]->name()
+    g_log.information() << "Adding workspace " << m_workspaces[i]->getName()
                         << '\n';
-    progress(double(i) * progStep, m_workspaces[i]->name());
+    progress(double(i) * progStep, m_workspaces[i]->getName());
     CALL_MDEVENT_FUNCTION(doPlus, m_workspaces[i]);
   }
 
diff --git a/Framework/MDAlgorithms/src/MinusMD.cpp b/Framework/MDAlgorithms/src/MinusMD.cpp
index 91d846e94bfed80b43ee710483bdbad9ba71188f..c0c2cb8e91ac001e301bb50730f765f7f7d4a0fb 100644
--- a/Framework/MDAlgorithms/src/MinusMD.cpp
+++ b/Framework/MDAlgorithms/src/MinusMD.cpp
@@ -51,8 +51,7 @@ void MinusMD::checkInputs() {
  * @param ws ::  MDEventWorkspace being added to
  */
 template <typename MDE, size_t nd>
-void MinusMD::doMinus(typename MDEventWorkspace<MDE, nd>::sptr ws) {
-  typename MDEventWorkspace<MDE, nd>::sptr ws1 = ws;
+void MinusMD::doMinus(typename MDEventWorkspace<MDE, nd>::sptr ws1) {
   typename MDEventWorkspace<MDE, nd>::sptr ws2 =
       boost::dynamic_pointer_cast<MDEventWorkspace<MDE, nd>>(m_operand_event);
   if (!ws1 || !ws2)
diff --git a/Framework/MDAlgorithms/src/PlusMD.cpp b/Framework/MDAlgorithms/src/PlusMD.cpp
index 3beb2ec6044ae32e080b86d1f3b56831c9c054f1..1fbe4b1d6b00551f2cdaa3e45e25a33fc06f007e 100644
--- a/Framework/MDAlgorithms/src/PlusMD.cpp
+++ b/Framework/MDAlgorithms/src/PlusMD.cpp
@@ -25,8 +25,7 @@ DECLARE_ALGORITHM(PlusMD)
  * @param ws ::  MDEventWorkspace being added to
  */
 template <typename MDE, size_t nd>
-void PlusMD::doPlus(typename MDEventWorkspace<MDE, nd>::sptr ws) {
-  typename MDEventWorkspace<MDE, nd>::sptr ws1 = ws;
+void PlusMD::doPlus(typename MDEventWorkspace<MDE, nd>::sptr ws1) {
   typename MDEventWorkspace<MDE, nd>::sptr ws2 =
       boost::dynamic_pointer_cast<MDEventWorkspace<MDE, nd>>(m_operand_event);
   if (!ws1 || !ws2)
diff --git a/Framework/MDAlgorithms/src/PreprocessDetectorsToMD.cpp b/Framework/MDAlgorithms/src/PreprocessDetectorsToMD.cpp
index 20d9ba263b34ce4871f08399f388b23d070e7f15..f934df1598b7cdfe7ce7f7310d48f5234b9f8450 100644
--- a/Framework/MDAlgorithms/src/PreprocessDetectorsToMD.cpp
+++ b/Framework/MDAlgorithms/src/PreprocessDetectorsToMD.cpp
@@ -1,8 +1,10 @@
 #include "MantidMDAlgorithms/PreprocessDetectorsToMD.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/InstrumentValidator.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/NumericAxis.h"
 #include "MantidAPI/Run.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidGeometry/Instrument.h"
 #include "MantidKernel/CompositeValidator.h"
 #include "MantidKernel/PropertyWithValue.h"
@@ -241,6 +243,7 @@ void PreprocessDetectorsToMD::processDetectorsPositions(
   Mantid::API::Progress theProgress(this, 0, 1, nHist);
   //// Loop over the spectra
   uint32_t liveDetectorsCount(0);
+  const auto &spectrumInfo = inputWS->spectrumInfo();
   for (size_t i = 0; i < nHist; i++) {
     sp2detMap[i] = std::numeric_limits<uint64_t>::quiet_NaN();
     detId[i] = std::numeric_limits<int32_t>::quiet_NaN();
@@ -250,33 +253,26 @@ void PreprocessDetectorsToMD::processDetectorsPositions(
     Azimuthal[i] = std::numeric_limits<double>::quiet_NaN();
     //     detMask[i]  = true;
 
-    // get detector or detector group which corresponds to the spectra i
-    Geometry::IDetector_const_sptr spDet;
-    try {
-      spDet = inputWS->getDetector(i);
-    } catch (Kernel::Exception::NotFoundError &) {
-      continue;
-    }
-
-    // Check that we aren't dealing with monitor...
-    if (spDet->isMonitor())
+    if (!spectrumInfo.hasDetectors(i) || spectrumInfo.isMonitor(i))
       continue;
 
     // if masked detectors state is not used, masked detectors just ignored;
-    bool maskDetector = spDet->isMasked();
+    bool maskDetector = spectrumInfo.isMasked(i);
     if (m_getIsMasked)
       *(pMasksArray + liveDetectorsCount) = maskDetector ? 1 : 0;
     else if (maskDetector)
       continue;
 
+    const auto &spDet = spectrumInfo.detector(i);
+
     // calculate the requested values;
     sp2detMap[i] = liveDetectorsCount;
-    detId[liveDetectorsCount] = int32_t(spDet->getID());
+    detId[liveDetectorsCount] = int32_t(spDet.getID());
     detIDMap[liveDetectorsCount] = i;
-    L2[liveDetectorsCount] = spDet->getDistance(*sample);
+    L2[liveDetectorsCount] = spectrumInfo.l2(i);
 
-    double polar = inputWS->detectorTwoTheta(*spDet);
-    double azim = spDet->getPhi();
+    double polar = spectrumInfo.twoTheta(i);
+    double azim = spDet.getPhi();
     TwoTheta[liveDetectorsCount] = polar;
     Azimuthal[liveDetectorsCount] = azim;
 
@@ -297,7 +293,7 @@ void PreprocessDetectorsToMD::processDetectorsPositions(
     // defined;
     if (pEfixedArray) {
       try {
-        Geometry::Parameter_sptr par = pmap.getRecursive(spDet.get(), "eFixed");
+        Geometry::Parameter_sptr par = pmap.getRecursive(&spDet, "eFixed");
         if (par)
           Efi = par->value<double>();
       } catch (std::runtime_error &) {
@@ -340,21 +336,13 @@ void PreprocessDetectorsToMD::updateMasksState(
         " are inconsistent as have different numner of detectors");
 
   uint32_t liveDetectorsCount(0);
+  const auto &spectrumInfo = inputWS->spectrumInfo();
   for (size_t i = 0; i < nHist; i++) {
-    // get detector or detector group which corresponds to the spectra i
-    Geometry::IDetector_const_sptr spDet;
-    try {
-      spDet = inputWS->getDetector(i);
-    } catch (Kernel::Exception::NotFoundError &) {
-      continue;
-    }
-
-    // Check that we aren't dealing with monitor...
-    if (spDet->isMonitor())
+    if (!spectrumInfo.hasDetectors(i) || spectrumInfo.isMonitor(i))
       continue;
 
     // if masked detectors state is not used, masked detectors just ignored;
-    bool maskDetector = spDet->isMasked();
+    bool maskDetector = spectrumInfo.isMasked(i);
     *(pMasksArray + liveDetectorsCount) = maskDetector ? 1 : 0;
 
     liveDetectorsCount++;
diff --git a/Framework/MDAlgorithms/src/Quantification/Resolution/ModeratorChopperResolution.cpp b/Framework/MDAlgorithms/src/Quantification/Resolution/ModeratorChopperResolution.cpp
index e2d8d70fd70985d1eb25ad30af4bf689b60c4648..58f2358db5f31caa605201b3f4574735fdb0f43b 100644
--- a/Framework/MDAlgorithms/src/Quantification/Resolution/ModeratorChopperResolution.cpp
+++ b/Framework/MDAlgorithms/src/Quantification/Resolution/ModeratorChopperResolution.cpp
@@ -1,4 +1,3 @@
-// Includes
 #include "MantidMDAlgorithms/Quantification/Resolution/ModeratorChopperResolution.h"
 #include "MantidMDAlgorithms/Quantification/CachedExperimentInfo.h"
 
@@ -6,6 +5,7 @@
 #include "MantidAPI/ChopperModel.h"
 #include "MantidAPI/ModeratorModel.h"
 #include "MantidGeometry/Instrument.h"
+#include "MantidKernel/PhysicalConstants.h"
 
 namespace Mantid {
 namespace MDAlgorithms {
diff --git a/Framework/MDAlgorithms/src/QueryMDWorkspace.cpp b/Framework/MDAlgorithms/src/QueryMDWorkspace.cpp
index f550a26f303e0ced7257b84777620d96a66be572..6f7c4c4b8b86889f8cc95e5719199573399934d1 100644
--- a/Framework/MDAlgorithms/src/QueryMDWorkspace.cpp
+++ b/Framework/MDAlgorithms/src/QueryMDWorkspace.cpp
@@ -9,6 +9,7 @@
 #include "MantidKernel/BoundedValidator.h"
 #include "MantidKernel/EnabledWhenProperty.h"
 #include "MantidKernel/ListValidator.h"
+#include "MantidKernel/Strings.h"
 
 using namespace Mantid::API;
 using namespace Mantid::DataObjects;
diff --git a/Framework/MDAlgorithms/src/SaveMD.cpp b/Framework/MDAlgorithms/src/SaveMD.cpp
index 4d5c6a22fa55efbb2fb92a96f1b7c3c01c31e0e1..a547ff5dbcb27706f273a1ef9f2fc1dec717b8ed 100644
--- a/Framework/MDAlgorithms/src/SaveMD.cpp
+++ b/Framework/MDAlgorithms/src/SaveMD.cpp
@@ -1,7 +1,9 @@
 #include "MantidAPI/CoordTransform.h"
 #include "MantidAPI/FileProperty.h"
 #include "MantidAPI/IMDEventWorkspace.h"
+#include "MantidAPI/WorkspaceHistory.h"
 #include "MantidKernel/Matrix.h"
+#include "MantidKernel/Strings.h"
 #include "MantidKernel/System.h"
 #include "MantidDataObjects/MDBoxIterator.h"
 #include "MantidDataObjects/MDEventFactory.h"
diff --git a/Framework/MDAlgorithms/src/SaveMD2.cpp b/Framework/MDAlgorithms/src/SaveMD2.cpp
index 9a99a554f247c2fe7250b168d7486eae4e9c0507..22fb267dc2c8278a41480ae911ce906e6fefd0a7 100644
--- a/Framework/MDAlgorithms/src/SaveMD2.cpp
+++ b/Framework/MDAlgorithms/src/SaveMD2.cpp
@@ -1,7 +1,9 @@
 #include "MantidAPI/CoordTransform.h"
 #include "MantidAPI/FileProperty.h"
 #include "MantidAPI/IMDEventWorkspace.h"
+#include "MantidAPI/WorkspaceHistory.h"
 #include "MantidKernel/Matrix.h"
+#include "MantidKernel/Strings.h"
 #include "MantidKernel/System.h"
 #include "MantidDataObjects/MDBoxIterator.h"
 #include "MantidDataObjects/MDEventFactory.h"
diff --git a/Framework/MDAlgorithms/src/SaveZODS.cpp b/Framework/MDAlgorithms/src/SaveZODS.cpp
index 495b4d8fd9b8139c968de5cd6fefbef25e5f5402..c96478ff4597d16d9ca6fc3fad861e9601c700b7 100644
--- a/Framework/MDAlgorithms/src/SaveZODS.cpp
+++ b/Framework/MDAlgorithms/src/SaveZODS.cpp
@@ -1,6 +1,7 @@
 #include "MantidAPI/FileProperty.h"
 #include "MantidAPI/IMDHistoWorkspace.h"
 #include "MantidAPI/Sample.h"
+#include "MantidKernel/Strings.h"
 #include "MantidKernel/System.h"
 #include "MantidMDAlgorithms/SaveZODS.h"
 #include "MantidDataObjects/MDHistoWorkspace.h"
diff --git a/Framework/MDAlgorithms/src/SlicingAlgorithm.cpp b/Framework/MDAlgorithms/src/SlicingAlgorithm.cpp
index 05d6ee29d070ee276d31ccd2334ce312d75661d1..d0f50931975c02fbf4e536eda7ef6bd143f9683b 100644
--- a/Framework/MDAlgorithms/src/SlicingAlgorithm.cpp
+++ b/Framework/MDAlgorithms/src/SlicingAlgorithm.cpp
@@ -177,7 +177,7 @@ void SlicingAlgorithm::makeBasisVectorFromString(const std::string &str) {
 
   // Get the entire name
   std::string name = Strings::strip(input.substr(0, n_first_comma));
-  if (name.size() == 0)
+  if (name.empty())
     throw std::invalid_argument("name should not be blank.");
 
   // Now remove the name and comma
@@ -251,20 +251,19 @@ void SlicingAlgorithm::makeBasisVectorFromString(const std::string &str) {
   double binningScaling = double(numBins) / (lengthInInput);
 
   // Extract the arguments
-  std::string id = name;
   std::string units = Strings::strip(strs[0]);
 
   // Create the appropriate frame
   auto frame = createMDFrameForNonAxisAligned(units, basis);
 
   // Create the output dimension
-  MDHistoDimension_sptr out(
-      new MDHistoDimension(name, id, *frame, static_cast<coord_t>(min),
-                           static_cast<coord_t>(max), numBins));
+  auto out = boost::make_shared<MDHistoDimension>(
+      name, name, *frame, static_cast<coord_t>(min), static_cast<coord_t>(max),
+      numBins);
 
   // Put both in the algo for future use
   m_bases.push_back(basis);
-  m_binDimensions.push_back(out);
+  m_binDimensions.push_back(std::move(out));
   m_binningScaling.push_back(binningScaling);
   m_transformScaling.push_back(transformScaling);
 }
@@ -430,8 +429,7 @@ void SlicingAlgorithm::createGeneralTransform() {
   if (m_outD == inD) {
     // Can't reverse transform if you lost dimensions.
     auto ctTo = new DataObjects::CoordTransformAffine(inD, m_outD);
-    Matrix<coord_t> fromMatrix = ctFrom->getMatrix();
-    Matrix<coord_t> toMatrix = fromMatrix;
+    Matrix<coord_t> toMatrix = ctFrom->getMatrix();
     // Invert the affine matrix to get the reverse transformation
     toMatrix.Invert();
     ctTo->setMatrix(toMatrix);
@@ -490,7 +488,7 @@ void SlicingAlgorithm::makeAlignedDimensionFromString(const std::string &str) {
     Strings::convert(strs[0], min);
     Strings::convert(strs[1], max);
     Strings::convert(strs[2], numBins);
-    if (name.size() == 0)
+    if (name.empty())
       throw std::invalid_argument("Name should not be blank.");
     if (min >= max)
       throw std::invalid_argument("Min should be > max.");
diff --git a/Framework/MDAlgorithms/src/TransformMD.cpp b/Framework/MDAlgorithms/src/TransformMD.cpp
index f45c06b8905a9e0f14a65463b11d12876b1132d7..1ab5a51281d655b2f6df47e376e15431b6122ae0 100644
--- a/Framework/MDAlgorithms/src/TransformMD.cpp
+++ b/Framework/MDAlgorithms/src/TransformMD.cpp
@@ -2,6 +2,7 @@
 #include "MantidKernel/System.h"
 #include "MantidKernel/ArrayProperty.h"
 #include "MantidDataObjects/MDHistoWorkspace.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/IMDEventWorkspace.h"
 #include "MantidDataObjects/MDEventWorkspace.h"
 #include "MantidDataObjects/MDEventFactory.h"
diff --git a/Framework/MDAlgorithms/src/UnitsConversionHelper.cpp b/Framework/MDAlgorithms/src/UnitsConversionHelper.cpp
index bb0f135209a092850fab48332fcd31a7196b295d..192378101e7f5565c21f34219213cf16afc50692 100644
--- a/Framework/MDAlgorithms/src/UnitsConversionHelper.cpp
+++ b/Framework/MDAlgorithms/src/UnitsConversionHelper.cpp
@@ -91,7 +91,7 @@ void UnitsConversionHelper::initialize(const MDWSDescription &targetWSDescr,
   if (!pAxis)
     throw(std::invalid_argument(
         "Cannot retrieve numeric X axis from the input workspace: " +
-        inWS2D->name()));
+        inWS2D->getName()));
 
   std::string unitsFrom = inWS2D->getAxis(0)->unit()->unitID();
 
diff --git a/Framework/MDAlgorithms/test/AccumulateMDTest.h b/Framework/MDAlgorithms/test/AccumulateMDTest.h
index a92680b2e974dd347d62ca91d7430a4080393480..eb145a00780c6f1818966aceb4d8221bca1ddf06 100644
--- a/Framework/MDAlgorithms/test/AccumulateMDTest.h
+++ b/Framework/MDAlgorithms/test/AccumulateMDTest.h
@@ -98,7 +98,7 @@ public:
 
     // Create a cheap workspace
     std::string ws_name = "ACCUMULATEMDTEST_EXISTENTWORKSPACE";
-    auto bkg_ws = WorkspaceCreationHelper::Create1DWorkspaceRand(1);
+    auto bkg_ws = WorkspaceCreationHelper::create1DWorkspaceRand(1);
     // add to ADS (no choice but to use ADS here)
     AnalysisDataService::Instance().add(ws_name, bkg_ws);
 
diff --git a/Framework/MDAlgorithms/test/BinMDTest.h b/Framework/MDAlgorithms/test/BinMDTest.h
index a21293914cd5d14bc6c905cace094b2b361abac2..9f819982c4e7acd3e358acbe8f0fd2f8df2961d2 100644
--- a/Framework/MDAlgorithms/test/BinMDTest.h
+++ b/Framework/MDAlgorithms/test/BinMDTest.h
@@ -643,7 +643,7 @@ public:
 
     // Intermediate workspace (the MDHisto)
     TS_ASSERT_EQUALS(binned1->numOriginalWorkspaces(), 2);
-    TS_ASSERT_EQUALS(binned1->getOriginalWorkspace(1)->name(), "binned0");
+    TS_ASSERT_EQUALS(binned1->getOriginalWorkspace(1)->getName(), "binned0");
     // Transforms to/from the INTERMEDIATE workspace exist
     CoordTransform const *toIntermediate = binned1->getTransformToOriginal(1);
     CoordTransform const *fromIntermediate =
@@ -684,7 +684,7 @@ public:
 
     // Intermediate workspace (the MDHisto) is binned0
     TS_ASSERT_EQUALS(binned1->numOriginalWorkspaces(), 2);
-    TS_ASSERT_EQUALS(binned1->getOriginalWorkspace(1)->name(), "binned0");
+    TS_ASSERT_EQUALS(binned1->getOriginalWorkspace(1)->getName(), "binned0");
     // Transforms to/from the INTERMEDIATE workspace exist
     CoordTransform const *toIntermediate = binned1->getTransformToOriginal(1);
     CoordTransform const *fromIntermediate =
@@ -750,7 +750,7 @@ public:
 
     // Intermediate workspace (the MDHisto) is binned0
     TS_ASSERT_EQUALS(binned1->numOriginalWorkspaces(), 2);
-    TS_ASSERT_EQUALS(binned1->getOriginalWorkspace(1)->name(), "binned0");
+    TS_ASSERT_EQUALS(binned1->getOriginalWorkspace(1)->getName(), "binned0");
     // Transforms to/from the INTERMEDIATE workspace exist
     CoordTransform const *toIntermediate = binned1->getTransformToOriginal(1);
     CoordTransform const *fromIntermediate =
@@ -821,7 +821,7 @@ public:
 
     // Intermediate workspace (the MDHisto)
     TS_ASSERT_EQUALS(binned2->numOriginalWorkspaces(), 2);
-    TS_ASSERT_EQUALS(binned2->getOriginalWorkspace(1)->name(), "binned1");
+    TS_ASSERT_EQUALS(binned2->getOriginalWorkspace(1)->getName(), "binned1");
     // Transforms to/from the INTERMEDIATE workspace exist
     TS_ASSERT(binned2->getTransformToOriginal(1));
     TS_ASSERT(binned2->getTransformFromOriginal(1));
diff --git a/Framework/MDAlgorithms/test/BinaryOperationMDTest.h b/Framework/MDAlgorithms/test/BinaryOperationMDTest.h
index f1b857f6999a86e5db568872f88d1bf38d3aa20c..eef27e2ee8c0fad55df02a2a20bd72d4f3e4462a 100644
--- a/Framework/MDAlgorithms/test/BinaryOperationMDTest.h
+++ b/Framework/MDAlgorithms/test/BinaryOperationMDTest.h
@@ -65,7 +65,7 @@ public:
         MDEventsTestHelper::makeFakeMDHistoWorkspace(1.0, 3, 5, 10.0, 1.0);
     event_A = MDEventsTestHelper::makeMDEW<2>(3, 0.0, 10.0, 1);
     event_B = MDEventsTestHelper::makeMDEW<2>(3, 0.0, 10.0, 1);
-    scalar = WorkspaceCreationHelper::CreateWorkspaceSingleValue(2.5);
+    scalar = WorkspaceCreationHelper::createWorkspaceSingleValue(2.5);
     AnalysisDataService::Instance().addOrReplace("histo_A", histo_A);
     AnalysisDataService::Instance().addOrReplace("histo_B", histo_B);
     AnalysisDataService::Instance().addOrReplace("histo2d_100", histo2d_100);
diff --git a/Framework/MDAlgorithms/test/CalculateCoverageDGSTest.h b/Framework/MDAlgorithms/test/CalculateCoverageDGSTest.h
index 3fecfe997cae2a827423dc8bcccf5d27abc12ef2..cce9d3b1979a916d97a6d6f055207391246553be 100644
--- a/Framework/MDAlgorithms/test/CalculateCoverageDGSTest.h
+++ b/Framework/MDAlgorithms/test/CalculateCoverageDGSTest.h
@@ -44,7 +44,7 @@ public:
     std::string outWSName("CalculateCoverageDGSTest_OutputWS"),
         inputWSName("CalculateCoverageDGSTest_InputWS");
     MatrixWorkspace_sptr inputWorkspace =
-        WorkspaceCreationHelper::Create2DWorkspace(1, 1);
+        WorkspaceCreationHelper::create2DWorkspace(1, 1);
     std::vector<V3D> detectorPositions{{1, 1, 1}};
     V3D sampPos(0., 0., 0.), sourcePos(0, 0, -1.);
     WorkspaceCreationHelper::createInstrumentForWorkspaceWithDistances(
diff --git a/Framework/MDAlgorithms/test/ConvertCWPDMDToSpectraTest.h b/Framework/MDAlgorithms/test/ConvertCWPDMDToSpectraTest.h
index eb046c21c3b1ff4620b5dc8625111f5578d5c24e..4800659bf74b3aad88841519ecb5214e535631f5 100644
--- a/Framework/MDAlgorithms/test/ConvertCWPDMDToSpectraTest.h
+++ b/Framework/MDAlgorithms/test/ConvertCWPDMDToSpectraTest.h
@@ -5,6 +5,7 @@
 
 #include "MantidMDAlgorithms/ConvertCWPDMDToSpectra.h"
 #include "MantidMDAlgorithms/ConvertSpiceDataToRealSpace.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Axis.h"
 #include "MantidAPI/IMDEventWorkspace.h"
 #include "MantidAPI/MatrixWorkspace.h"
@@ -50,9 +51,9 @@ public:
 
     // Set properties
     TS_ASSERT_THROWS_NOTHING(
-        alg.setPropertyValue("InputWorkspace", m_dataMD->name()));
+        alg.setPropertyValue("InputWorkspace", m_dataMD->getName()));
     TS_ASSERT_THROWS_NOTHING(
-        alg.setPropertyValue("InputMonitorWorkspace", m_monitorMD->name()));
+        alg.setPropertyValue("InputMonitorWorkspace", m_monitorMD->getName()));
     TS_ASSERT_THROWS_NOTHING(
         alg.setPropertyValue("BinningParams", "0, 0.1, 120."));
     TS_ASSERT_THROWS_NOTHING(
@@ -112,9 +113,9 @@ public:
 
     // Set properties
     TS_ASSERT_THROWS_NOTHING(
-        alg.setPropertyValue("InputWorkspace", m_dataMD->name()));
+        alg.setPropertyValue("InputWorkspace", m_dataMD->getName()));
     TS_ASSERT_THROWS_NOTHING(
-        alg.setPropertyValue("InputMonitorWorkspace", m_monitorMD->name()));
+        alg.setPropertyValue("InputMonitorWorkspace", m_monitorMD->getName()));
     TS_ASSERT_THROWS_NOTHING(alg.setProperty("UnitOutput", "dSpacing"));
     TS_ASSERT_THROWS_NOTHING(
         alg.setPropertyValue("BinningParams", "0.5, 0.01, 5.0"));
@@ -158,9 +159,9 @@ public:
 
     // Set properties
     TS_ASSERT_THROWS_NOTHING(
-        alg.setPropertyValue("InputWorkspace", m_dataMD->name()));
+        alg.setPropertyValue("InputWorkspace", m_dataMD->getName()));
     TS_ASSERT_THROWS_NOTHING(
-        alg.setPropertyValue("InputMonitorWorkspace", m_monitorMD->name()));
+        alg.setPropertyValue("InputMonitorWorkspace", m_monitorMD->getName()));
     TS_ASSERT_THROWS_NOTHING(alg.setProperty("UnitOutput", "dSpacing"));
     TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("BinningParams", "0.01"));
     TS_ASSERT_THROWS_NOTHING(
@@ -246,8 +247,8 @@ public:
     TS_ASSERT(m_monitorMD);
 
     // Clean
-    AnalysisDataService::Instance().remove(datatablews->name());
-    AnalysisDataService::Instance().remove(parentlogws->name());
+    AnalysisDataService::Instance().remove(datatablews->getName());
+    AnalysisDataService::Instance().remove(parentlogws->getName());
   }
 
   //----------------------------------------------------------------------------------------------
@@ -265,9 +266,9 @@ public:
 
     // Set properties
     TS_ASSERT_THROWS_NOTHING(
-        alg.setPropertyValue("InputWorkspace", m_dataMD->name()));
+        alg.setPropertyValue("InputWorkspace", m_dataMD->getName()));
     TS_ASSERT_THROWS_NOTHING(
-        alg.setPropertyValue("InputMonitorWorkspace", m_monitorMD->name()));
+        alg.setPropertyValue("InputMonitorWorkspace", m_monitorMD->getName()));
     TS_ASSERT_THROWS_NOTHING(
         alg.setPropertyValue("BinningParams", "0, 0.1, 120."));
     TS_ASSERT_THROWS_NOTHING(
@@ -326,8 +327,8 @@ public:
   /** Clean the testing workspaces
    */
   void test_Clean() {
-    AnalysisDataService::Instance().remove(m_dataMD->name());
-    AnalysisDataService::Instance().remove(m_monitorMD->name());
+    AnalysisDataService::Instance().remove(m_dataMD->getName());
+    AnalysisDataService::Instance().remove(m_monitorMD->getName());
   }
 
 private:
diff --git a/Framework/MDAlgorithms/test/ConvertCWSDExpToMomentumTest.h b/Framework/MDAlgorithms/test/ConvertCWSDExpToMomentumTest.h
index 2c12b9bf3626246484e7133ce41b3eebe59d999e..f4d1d2d243bd2d0d039246d3093a80b6625114a9 100644
--- a/Framework/MDAlgorithms/test/ConvertCWSDExpToMomentumTest.h
+++ b/Framework/MDAlgorithms/test/ConvertCWSDExpToMomentumTest.h
@@ -4,6 +4,7 @@
 #include <cxxtest/TestSuite.h>
 
 #include "MantidMDAlgorithms/ConvertCWSDExpToMomentum.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/ITableWorkspace.h"
 #include "MantidAPI/TableRow.h"
 #include "MantidDataObjects/TableWorkspace.h"
diff --git a/Framework/MDAlgorithms/test/ConvertCWSDMDtoHKLTest.h b/Framework/MDAlgorithms/test/ConvertCWSDMDtoHKLTest.h
index f9dc99cd849e4db52ff349c735ddd68ae68ef18b..412817bec71017855efe5170c23f22aca5447dd1 100644
--- a/Framework/MDAlgorithms/test/ConvertCWSDMDtoHKLTest.h
+++ b/Framework/MDAlgorithms/test/ConvertCWSDMDtoHKLTest.h
@@ -43,7 +43,7 @@ public:
     alg.initialize();
 
     TS_ASSERT_THROWS_NOTHING(
-        alg.setPropertyValue("InputWorkspace", m_qsampleWS->name()));
+        alg.setPropertyValue("InputWorkspace", m_qsampleWS->getName()));
     TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue(
         "UBMatrix", "1.0, 0.5, 0., -0.2, 2.0, 0.4, 0., 1.11, 3.9"));
     TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("OutputWorkspace", "HKLMD"));
diff --git a/Framework/MDAlgorithms/test/ConvertEventsToMDTest.h b/Framework/MDAlgorithms/test/ConvertEventsToMDTest.h
index 12d0396783372586ff2da57c57f51739167e879a..f98c98e79a8b40d55a88d23dc599b5a50dfdff08 100644
--- a/Framework/MDAlgorithms/test/ConvertEventsToMDTest.h
+++ b/Framework/MDAlgorithms/test/ConvertEventsToMDTest.h
@@ -74,7 +74,7 @@ public:
     int numHist = 10;
     Mantid::API::MatrixWorkspace_sptr wsEv =
         boost::dynamic_pointer_cast<MatrixWorkspace>(
-            WorkspaceCreationHelper::CreateRandomEventWorkspace(100, numHist,
+            WorkspaceCreationHelper::createRandomEventWorkspace(100, numHist,
                                                                 0.1));
     wsEv->setInstrument(
         ComponentCreationHelper::createTestInstrumentCylindrical(numHist));
diff --git a/Framework/MDAlgorithms/test/ConvertMDHistoToMatrixWorkspaceTest.h b/Framework/MDAlgorithms/test/ConvertMDHistoToMatrixWorkspaceTest.h
index ae6baa36487e8434c0322a1273bb102baa055c43..5015e2cd5b18188243a967915f341d35c5a07e69 100644
--- a/Framework/MDAlgorithms/test/ConvertMDHistoToMatrixWorkspaceTest.h
+++ b/Framework/MDAlgorithms/test/ConvertMDHistoToMatrixWorkspaceTest.h
@@ -138,7 +138,7 @@ public:
 public:
   void test_input_workspace_must_be_imdhisto() {
     MatrixWorkspace_sptr ws =
-        WorkspaceCreationHelper::Create1DWorkspaceConstant(1, 1, 0);
+        WorkspaceCreationHelper::create1DWorkspaceConstant(1, 1, 0);
     ConvertMDHistoToMatrixWorkspace alg;
     alg.setRethrows(true);
     alg.initialize();
diff --git a/Framework/MDAlgorithms/test/ConvertSpiceDataToRealSpaceTest.h b/Framework/MDAlgorithms/test/ConvertSpiceDataToRealSpaceTest.h
index 5ed79dddd957c0a646c4a8c6f1e784c97109acb8..c9956ef5d6c958a1a371d48ff2e3bb476eba7ca7 100644
--- a/Framework/MDAlgorithms/test/ConvertSpiceDataToRealSpaceTest.h
+++ b/Framework/MDAlgorithms/test/ConvertSpiceDataToRealSpaceTest.h
@@ -4,6 +4,7 @@
 #include <cxxtest/TestSuite.h>
 
 #include "MantidMDAlgorithms/ConvertSpiceDataToRealSpace.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/IMDEventWorkspace.h"
 #include "MantidAPI/IMDIterator.h"
 #include "MantidAPI/ITableWorkspace.h"
diff --git a/Framework/MDAlgorithms/test/ConvertToMDComponentsTest.h b/Framework/MDAlgorithms/test/ConvertToMDComponentsTest.h
index 3ef04716e3125c55402befb3c0d6809be3b0bf08..7347bc2f7464341f10bbe7d92b755a9e7cf0254b 100644
--- a/Framework/MDAlgorithms/test/ConvertToMDComponentsTest.h
+++ b/Framework/MDAlgorithms/test/ConvertToMDComponentsTest.h
@@ -3,6 +3,8 @@
 // tests for different parts of ConvertToMD exec functions
 
 #include "MantidAPI/FrameworkManager.h"
+#include "MantidAPI/SpectrumInfo.h"
+#include "MantidGeometry/Instrument/Goniometer.h"
 #include "MantidMDAlgorithms/ConvertToMD.h"
 #include "MantidMDAlgorithms/MDWSTransform.h"
 #include "MantidTestHelpers/ComponentCreationHelper.h"
@@ -319,32 +321,12 @@ public:
     auto inputWS = boost::dynamic_pointer_cast<API::MatrixWorkspace>(
         API::AnalysisDataService::Instance().retrieve(wsName));
     const size_t nRows = inputWS->getNumberHistograms();
-
-    // build detectors ID list to mask
-    std::vector<detid_t> detectorList;
-    detectorList.reserve(nRows);
-    std::vector<size_t> indexLis;
-    indexLis.reserve(nRows);
+    auto &spectrumInfo = inputWS->mutableSpectrumInfo();
     for (size_t i = 0; i < nRows; i++) {
-      // get detector or detector group which corresponds to the spectra i
-      Geometry::IDetector_const_sptr spDet;
-      try {
-        spDet = inputWS->getDetector(i);
-      } catch (Kernel::Exception::NotFoundError &) {
-        continue;
-      }
-
-      // Check that we aren't dealing with monitor...
-      if (spDet->isMonitor())
+      if (!spectrumInfo.hasDetectors(i) || spectrumInfo.isMonitor(i))
         continue;
-
-      indexLis.push_back(i);
-      // detectorList.push_back(spDet->getID());
-    }
-
-    std::vector<size_t>::const_iterator wit;
-    for (wit = indexLis.begin(); wit != indexLis.end(); ++wit) {
-      inputWS->maskWorkspaceIndex(*wit);
+      inputWS->getSpectrum(i).clearData();
+      spectrumInfo.setMasked(i, true);
     }
   }
 };
diff --git a/Framework/MDAlgorithms/test/ConvertToMDMinMaxGlobalTest.h b/Framework/MDAlgorithms/test/ConvertToMDMinMaxGlobalTest.h
index 3329bddbebea70012b3d425ef0c8461bdadf2900..383395ba770910335d63f555b3a0b8446e6aff07 100644
--- a/Framework/MDAlgorithms/test/ConvertToMDMinMaxGlobalTest.h
+++ b/Framework/MDAlgorithms/test/ConvertToMDMinMaxGlobalTest.h
@@ -182,7 +182,7 @@ private:
                                                   double Ef) {
 
     Mantid::API::MatrixWorkspace_sptr ws =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(1, 100, xmin, dx);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(1, 100, xmin, dx);
 
     if ((Ei > 0 || Ef > 0) && deltaEUnits) {
       ws->getAxis(0)->setUnit("DeltaE");
@@ -192,7 +192,6 @@ private:
 
     Mantid::Geometry::Instrument_sptr testInst(
         new Mantid::Geometry::Instrument);
-    ws->setInstrument(testInst);
     // Define a source and sample position
     // Define a source component
     Mantid::Geometry::ObjComponent *source = new Mantid::Geometry::ObjComponent(
@@ -212,6 +211,7 @@ private:
     physicalPixel->setPos(0.5, 0, 5.0);
     testInst->add(physicalPixel);
     testInst->markAsDetector(physicalPixel);
+    ws->setInstrument(testInst);
 
     ws->getSpectrum(0).addDetectorID(physicalPixel->getID());
 
@@ -221,9 +221,8 @@ private:
     }
 
     if (Ef > 0) {
-      Mantid::Geometry::ParameterMap pmap(ws->instrumentParameters());
+      auto &pmap = ws->instrumentParameters();
       pmap.addDouble(physicalPixel, "Efixed", Ef);
-      ws->replaceInstrumentParameters(pmap);
     }
     Mantid::Geometry::OrientedLattice latt(2, 3, 4, 90, 90, 90);
     ws->mutableSample().setOrientedLattice(&latt);
diff --git a/Framework/MDAlgorithms/test/ConvertToMDMinMaxLocalTest.h b/Framework/MDAlgorithms/test/ConvertToMDMinMaxLocalTest.h
index 4b4fa3d45001d4f685a146e7933b0003824a3340..a44301f6cfcccc4958fab660a9541038e934bbca 100644
--- a/Framework/MDAlgorithms/test/ConvertToMDMinMaxLocalTest.h
+++ b/Framework/MDAlgorithms/test/ConvertToMDMinMaxLocalTest.h
@@ -202,7 +202,7 @@ private:
                                                   double Ef) {
 
     Mantid::API::MatrixWorkspace_sptr ws =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(1, 100, xmin, dx);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(1, 100, xmin, dx);
 
     if ((Ei > 0 || Ef > 0) && deltaEUnits) {
       ws->getAxis(0)->setUnit("DeltaE");
@@ -212,7 +212,6 @@ private:
 
     Mantid::Geometry::Instrument_sptr testInst(
         new Mantid::Geometry::Instrument);
-    ws->setInstrument(testInst);
     // Define a source and sample position
     // Define a source component
     Mantid::Geometry::ObjComponent *source = new Mantid::Geometry::ObjComponent(
@@ -232,6 +231,7 @@ private:
     physicalPixel->setPos(0.5, 0, 5.0);
     testInst->add(physicalPixel);
     testInst->markAsDetector(physicalPixel);
+    ws->setInstrument(testInst);
 
     ws->getSpectrum(0).addDetectorID(physicalPixel->getID());
 
@@ -240,11 +240,6 @@ private:
           new Mantid::Kernel::PropertyWithValue<double>("Ei", Ei));
     }
 
-    if (Ef > 0) {
-      Mantid::Geometry::ParameterMap pmap(ws->instrumentParameters());
-      pmap.addDouble(physicalPixel, "Efixed", Ef);
-      ws->replaceInstrumentParameters(pmap);
-    }
     Mantid::Geometry::OrientedLattice latt(2, 3, 4, 90, 90, 90);
     ws->mutableSample().setOrientedLattice(&latt);
 
diff --git a/Framework/MDAlgorithms/test/ConvertToMDTest.h b/Framework/MDAlgorithms/test/ConvertToMDTest.h
index 7adc9502125f931e4b1c716084003899b885adad..0ce60001178a404db8bc797ff0059775577b0d29 100644
--- a/Framework/MDAlgorithms/test/ConvertToMDTest.h
+++ b/Framework/MDAlgorithms/test/ConvertToMDTest.h
@@ -2,6 +2,7 @@
 #define MANTID_MD_CONVERT2_Q_NDANY_TEST_H_
 
 #include "MantidAPI/BoxController.h"
+#include "MantidGeometry/Instrument/Goniometer.h"
 #include "MantidMDAlgorithms/ConvertToMD.h"
 #include "MantidMDAlgorithms/ConvToMDSelector.h"
 #include "MantidMDAlgorithms/PreprocessDetectorsToMD.h"
@@ -730,7 +731,7 @@ public:
     numHist = 100 * 100;
     size_t nEvents = 1000;
     inWsEv = boost::dynamic_pointer_cast<MatrixWorkspace>(
-        WorkspaceCreationHelper::CreateRandomEventWorkspace(nEvents, numHist,
+        WorkspaceCreationHelper::createRandomEventWorkspace(nEvents, numHist,
                                                             0.1));
     inWsEv->setInstrument(
         ComponentCreationHelper::createTestInstrumentCylindrical(int(numHist)));
diff --git a/Framework/MDAlgorithms/test/ConvertToQ3DdETest.h b/Framework/MDAlgorithms/test/ConvertToQ3DdETest.h
index d87f587291bb36b6132eaad1b9d4f53c5fe511b7..00a48fb04ec7b2f9295f5f388fc2d6b3f474caa0 100644
--- a/Framework/MDAlgorithms/test/ConvertToQ3DdETest.h
+++ b/Framework/MDAlgorithms/test/ConvertToQ3DdETest.h
@@ -5,6 +5,7 @@
 #include "MantidAPI/Sample.h"
 #include "MantidDataObjects/EventWorkspace.h"
 #include "MantidGeometry/Crystal/OrientedLattice.h"
+#include "MantidGeometry/Instrument/Goniometer.h"
 #include "MantidKernel/make_unique.h"
 #include "MantidMDAlgorithms/ConvertToMD.h"
 #include "MantidMDAlgorithms/MDWSDescription.h"
@@ -39,7 +40,7 @@ public:
 
   void testExecThrow() {
     Mantid::API::MatrixWorkspace_sptr ws2D =
-        WorkspaceCreationHelper::CreateGroupedWorkspace2DWithRingsAndBoxes();
+        WorkspaceCreationHelper::createGroupedWorkspace2DWithRingsAndBoxes();
 
     AnalysisDataService::Instance().addOrReplace("testWSProcessed", ws2D);
 
diff --git a/Framework/MDAlgorithms/test/ConvertToReflectometryQTest.h b/Framework/MDAlgorithms/test/ConvertToReflectometryQTest.h
index 2bee175de5b0acacc481fa2d938cee0bcbfc86ca..5f44b55e93d9b9bb4cd01fa0cca8884624f1492c 100644
--- a/Framework/MDAlgorithms/test/ConvertToReflectometryQTest.h
+++ b/Framework/MDAlgorithms/test/ConvertToReflectometryQTest.h
@@ -9,6 +9,7 @@
 #include "MantidAPI/WorkspaceGroup.h"
 #include "MantidGeometry/Instrument/ReferenceFrame.h"
 #include "MantidKernel/PropertyWithValue.h"
+#include "MantidKernel/Unit.h"
 #include "MantidMDAlgorithms/ConvertToReflectometryQ.h"
 #include "MantidTestHelpers/WorkspaceCreationHelper.h"
 #include "MantidDataObjects/Workspace2D.h"
diff --git a/Framework/MDAlgorithms/test/CreateMDHistoWorkspaceTest.h b/Framework/MDAlgorithms/test/CreateMDHistoWorkspaceTest.h
index f08d607958349741cedbfb131289c930734e4449..85d0af7844fe4fe774bbe9617ad039a1dea2693a 100644
--- a/Framework/MDAlgorithms/test/CreateMDHistoWorkspaceTest.h
+++ b/Framework/MDAlgorithms/test/CreateMDHistoWorkspaceTest.h
@@ -6,6 +6,7 @@
 #include "MantidKernel/System.h"
 #include "MantidGeometry/MDGeometry/QSample.h"
 #include "MantidGeometry/MDGeometry/GeneralFrame.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidMDAlgorithms/CreateMDHistoWorkspace.h"
 
 using namespace Mantid;
diff --git a/Framework/MDAlgorithms/test/CreateMDTest.h b/Framework/MDAlgorithms/test/CreateMDTest.h
index aa9625455b3e360be9b3311be93b71914baeec9f..96a5d73e84a81f16e0d980b587554f28a2fde8fa 100644
--- a/Framework/MDAlgorithms/test/CreateMDTest.h
+++ b/Framework/MDAlgorithms/test/CreateMDTest.h
@@ -61,7 +61,7 @@ public:
   }
 
   void test_psi_right_size() {
-    auto sample_ws = WorkspaceCreationHelper::Create2DWorkspace(1, 1);
+    auto sample_ws = WorkspaceCreationHelper::create2DWorkspace(1, 1);
     Mantid::API::AnalysisDataService::Instance().add("__CreateMDTest_sample",
                                                      sample_ws);
 
@@ -87,7 +87,7 @@ public:
   }
 
   void test_gl_right_size() {
-    auto sample_ws = WorkspaceCreationHelper::Create2DWorkspace(1, 1);
+    auto sample_ws = WorkspaceCreationHelper::create2DWorkspace(1, 1);
     Mantid::API::AnalysisDataService::Instance().add("__CreateMDTest_sample",
                                                      sample_ws);
 
@@ -113,7 +113,7 @@ public:
   }
 
   void test_gs_right_size() {
-    auto sample_ws = WorkspaceCreationHelper::Create2DWorkspace(1, 1);
+    auto sample_ws = WorkspaceCreationHelper::create2DWorkspace(1, 1);
     Mantid::API::AnalysisDataService::Instance().add("__CreateMDTest_sample",
                                                      sample_ws);
 
@@ -251,4 +251,4 @@ public:
   }
 };
 
-#endif /* MANTID_MDALGORITHMS_CREATEMDTEST_H_ */
\ No newline at end of file
+#endif /* MANTID_MDALGORITHMS_CREATEMDTEST_H_ */
diff --git a/Framework/MDAlgorithms/test/CreateMDWorkspaceTest.h b/Framework/MDAlgorithms/test/CreateMDWorkspaceTest.h
index 94effdd105ff973de8968181706567d10058bbb9..2c3eddaf229a169c4f8dd2936165df7832c30699 100644
--- a/Framework/MDAlgorithms/test/CreateMDWorkspaceTest.h
+++ b/Framework/MDAlgorithms/test/CreateMDWorkspaceTest.h
@@ -1,6 +1,7 @@
 #ifndef MANTID_MDEVENTS_CREATEMDEVENTWORKSPACETEST_H_
 #define MANTID_MDEVENTS_CREATEMDEVENTWORKSPACETEST_H_
 
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/FrameworkManager.h"
 #include "MantidMDAlgorithms/CreateMDWorkspace.h"
 #include "MantidGeometry/MDGeometry/QSample.h"
@@ -10,12 +11,6 @@
 
 #include <Poco/File.h>
 
-//#include "MantidAPI/AnalysisDataService.h"
-//#include "MantidAPI/IMDEventWorkspace.h"
-//#include "MantidKernel/System.h"
-//#include "MantidKernel/Timer.h"
-//#include "MantidDataObjects/MDEventFactory.h"
-
 using namespace Mantid::API;
 using namespace Mantid::DataObjects;
 using namespace Mantid::Geometry;
diff --git a/Framework/MDAlgorithms/test/DisplayNormalizationSetterTest.h b/Framework/MDAlgorithms/test/DisplayNormalizationSetterTest.h
index a43bf6041bbba8f17e7e2a2f0f9b394c99ee32f9..afcf4618d272fdb98316e2f046dcedbe4fe5d42d 100644
--- a/Framework/MDAlgorithms/test/DisplayNormalizationSetterTest.h
+++ b/Framework/MDAlgorithms/test/DisplayNormalizationSetterTest.h
@@ -15,7 +15,7 @@ public:
     // Arrange
     auto isQ = true;
     auto eventWorkspace =
-        WorkspaceCreationHelper::CreateEventWorkspace2(10, 10);
+        WorkspaceCreationHelper::createEventWorkspace2(10, 10);
     auto mdHistoWorkspace =
         Mantid::DataObjects::MDEventsTestHelper::makeFakeMDHistoWorkspace(
             1.0, 1, 10);
@@ -31,7 +31,7 @@ public:
     // Arrange
     auto isQ = true;
     auto eventWorkspace =
-        WorkspaceCreationHelper::CreateEventWorkspace2(10, 10);
+        WorkspaceCreationHelper::createEventWorkspace2(10, 10);
     auto mdEventWorkspace =
         Mantid::DataObjects::MDEventsTestHelper::makeMDEW<3>(4, 0.0, 4.0, 1);
     auto emode = Mantid::Kernel::DeltaEMode::Elastic;
@@ -52,7 +52,7 @@ public:
     // Arrange
     auto isQ = true;
     auto eventWorkspace =
-        WorkspaceCreationHelper::CreateEventWorkspace2(10, 10);
+        WorkspaceCreationHelper::createEventWorkspace2(10, 10);
     auto mdEventWorkspace =
         Mantid::DataObjects::MDEventsTestHelper::makeMDEW<3>(4, 0.0, 4.0, 1);
     auto emode = Mantid::Kernel::DeltaEMode::Direct;
@@ -72,7 +72,7 @@ public:
   test_that_indirect_energy_mode_with_input_workspace2D_creates_num_event_normalization() {
     // Arrange
     auto isQ = true;
-    auto histoWorkspace = WorkspaceCreationHelper::Create2DWorkspace123(2, 2);
+    auto histoWorkspace = WorkspaceCreationHelper::create2DWorkspace123(2, 2);
     auto mdEventWorkspace =
         Mantid::DataObjects::MDEventsTestHelper::makeMDEW<3>(4, 0.0, 4.0, 1);
     auto emode = Mantid::Kernel::DeltaEMode::Direct;
@@ -91,7 +91,7 @@ public:
   void test_that_non_Q_creates_volume_normalization() {
     // Arrange
     auto isQ = false;
-    auto histoWorkspace = WorkspaceCreationHelper::Create2DWorkspace123(2, 2);
+    auto histoWorkspace = WorkspaceCreationHelper::create2DWorkspace123(2, 2);
     auto mdEventWorkspace =
         Mantid::DataObjects::MDEventsTestHelper::makeMDEW<3>(4, 0.0, 4.0, 1);
     auto emode = Mantid::Kernel::DeltaEMode::Direct;
@@ -108,4 +108,4 @@ public:
   }
 };
 
-#endif
\ No newline at end of file
+#endif
diff --git a/Framework/MDAlgorithms/test/DivideMDTest.h b/Framework/MDAlgorithms/test/DivideMDTest.h
index da0c61996aca83f817369e0172b232aa33a99238..611b11c15421192bfe87cac895d7ccf8a322eb27 100644
--- a/Framework/MDAlgorithms/test/DivideMDTest.h
+++ b/Framework/MDAlgorithms/test/DivideMDTest.h
@@ -4,6 +4,7 @@
 #include <cxxtest/TestSuite.h>
 #include "MantidKernel/Timer.h"
 #include "MantidKernel/System.h"
+#include "MantidAPI/AnalysisDataService.h"
 
 #include "MantidMDAlgorithms/DivideMD.h"
 #include "MantidTestHelpers/BinaryOperationMDTestHelper.h"
diff --git a/Framework/MDAlgorithms/test/EvaluateMDFunctionTest.h b/Framework/MDAlgorithms/test/EvaluateMDFunctionTest.h
index 27a13f9b49a714469f60966e7e1bd366158c01a9..12638da2054c185a5e46097cec6b935cb3a60106 100644
--- a/Framework/MDAlgorithms/test/EvaluateMDFunctionTest.h
+++ b/Framework/MDAlgorithms/test/EvaluateMDFunctionTest.h
@@ -5,6 +5,7 @@
 
 #include "MantidMDAlgorithms/EvaluateMDFunction.h"
 #include "MantidMDAlgorithms/CreateMDHistoWorkspace.h"
+#include "MantidAPI/AnalysisDataService.h"
 
 using Mantid::MDAlgorithms::EvaluateMDFunction;
 using Mantid::MDAlgorithms::CreateMDHistoWorkspace;
diff --git a/Framework/MDAlgorithms/test/FitMDTest.h b/Framework/MDAlgorithms/test/FitMDTest.h
index aa68c83bdeb9091e821687d27a1470fe5949ad42..50dba755b4a8e64de06a094af7411d399c749cd4 100644
--- a/Framework/MDAlgorithms/test/FitMDTest.h
+++ b/Framework/MDAlgorithms/test/FitMDTest.h
@@ -2,6 +2,7 @@
 #define CURVEFITTING_FITMDTEST_H_
 
 #include "MantidAPI/AlgorithmManager.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/FrameworkManager.h"
 #include "MantidAPI/IAlgorithm.h"
 #include "MantidAPI/IMDHistoWorkspace.h"
diff --git a/Framework/MDAlgorithms/test/FitResolutionConvolvedModelTest.h b/Framework/MDAlgorithms/test/FitResolutionConvolvedModelTest.h
index a6f3f52f6f57c350cb49529107101dbcaa860f3b..4c3bd1e4dd36ca63f5e953ea18de74e8d828774c 100644
--- a/Framework/MDAlgorithms/test/FitResolutionConvolvedModelTest.h
+++ b/Framework/MDAlgorithms/test/FitResolutionConvolvedModelTest.h
@@ -32,7 +32,7 @@ public:
     using namespace Mantid::API;
     IAlgorithm_sptr alg = createAlgorithm();
     MatrixWorkspace_sptr testMatrixWS =
-        WorkspaceCreationHelper::Create2DWorkspace(1, 10);
+        WorkspaceCreationHelper::create2DWorkspace(1, 10);
     Mantid::API::AnalysisDataService::Instance().addOrReplace(m_inputName,
                                                               testMatrixWS);
 
diff --git a/Framework/MDAlgorithms/test/GetSpiceDataRawCountsFromMDTest.h b/Framework/MDAlgorithms/test/GetSpiceDataRawCountsFromMDTest.h
index b54e27cf3328b81b8e4f8d246ed17df7c32ec0b7..990676c8c91c91f7c857ab54a0220b7c32f78175 100644
--- a/Framework/MDAlgorithms/test/GetSpiceDataRawCountsFromMDTest.h
+++ b/Framework/MDAlgorithms/test/GetSpiceDataRawCountsFromMDTest.h
@@ -6,6 +6,7 @@
 #include "MantidMDAlgorithms/GetSpiceDataRawCountsFromMD.h"
 #include "MantidDataHandling/LoadSpiceAscii.h"
 #include "MantidMDAlgorithms/ConvertSpiceDataToRealSpace.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/ITableWorkspace.h"
 #include "MantidAPI/IMDEventWorkspace.h"
 #include "MantidAPI/MatrixWorkspace.h"
@@ -196,8 +197,8 @@ public:
   /** Clean the testing workspaces
    */
   void test_Clean() {
-    AnalysisDataService::Instance().remove(m_dataMD->name());
-    AnalysisDataService::Instance().remove(m_monitorMD->name());
+    AnalysisDataService::Instance().remove(m_dataMD->getName());
+    AnalysisDataService::Instance().remove(m_monitorMD->getName());
   }
 
 private:
@@ -258,8 +259,8 @@ private:
     TS_ASSERT(m_monitorMD);
 
     // Clean
-    AnalysisDataService::Instance().remove(datatablews->name());
-    AnalysisDataService::Instance().remove(parentlogws->name());
+    AnalysisDataService::Instance().remove(datatablews->getName());
+    AnalysisDataService::Instance().remove(parentlogws->getName());
 
     return;
   }
diff --git a/Framework/MDAlgorithms/test/ImportMDEventWorkspaceTest.h b/Framework/MDAlgorithms/test/ImportMDEventWorkspaceTest.h
index f3fe10bf56d0d6c6f1ead411c99f6081855a6532..96a92ad40f3ff0454bc71e346b2e4b75d53d33f7 100644
--- a/Framework/MDAlgorithms/test/ImportMDEventWorkspaceTest.h
+++ b/Framework/MDAlgorithms/test/ImportMDEventWorkspaceTest.h
@@ -4,6 +4,7 @@
 #include "MantidGeometry/MDGeometry/IMDDimension.h"
 #include "MantidMDAlgorithms/ImportMDEventWorkspace.h"
 #include "MantidGeometry/MDGeometry/GeneralFrame.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidKernel/ConfigService.h"
 
 #include <cxxtest/TestSuite.h>
diff --git a/Framework/MDAlgorithms/test/ImportMDHistoWorkspaceTest.h b/Framework/MDAlgorithms/test/ImportMDHistoWorkspaceTest.h
index 234f4d166a8ab6bd7514ad446ab35c73214cc7cb..37c2318fa5352feee95277880e293b85f552eb71 100644
--- a/Framework/MDAlgorithms/test/ImportMDHistoWorkspaceTest.h
+++ b/Framework/MDAlgorithms/test/ImportMDHistoWorkspaceTest.h
@@ -1,6 +1,7 @@
 #ifndef MANTID_MDEVENTS_IMPORTMDHISTOWORKSPACETEST_H_
 #define MANTID_MDEVENTS_IMPORTMDHISTOWORKSPACETEST_H_
 
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/IMDHistoWorkspace.h"
 #include "MantidKernel/ConfigService.h"
 #include "MantidMDAlgorithms/ImportMDHistoWorkspace.h"
diff --git a/Framework/MDAlgorithms/test/IntegrateEllipsoidsTest.h b/Framework/MDAlgorithms/test/IntegrateEllipsoidsTest.h
index 78edba2c0623fd08d4d00746a240f284d2c414ed..256eea32928080d837ea029d7d01cc5f87be0ebe 100644
--- a/Framework/MDAlgorithms/test/IntegrateEllipsoidsTest.h
+++ b/Framework/MDAlgorithms/test/IntegrateEllipsoidsTest.h
@@ -236,6 +236,76 @@ public:
 
     do_test_n_peaks(integratedPeaksWS, 3 /*check first 3 peaks*/);
   }
+
+  void test_execution_events_adaptive() {
+
+    IntegrateEllipsoids alg;
+    alg.setChild(true);
+    alg.setRethrows(true);
+    alg.initialize();
+    alg.setProperty("InputWorkspace", m_eventWS);
+    alg.setProperty("PeaksWorkspace", m_peaksWS);
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("SpecifySize", true));
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("PeakSize", 0.20));
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("BackgroundInnerSize", 0.23));
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("BackgroundOuterSize", 0.26));
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("AdaptiveQMultiplier", 0.01));
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("AdaptiveQBackground", true));
+    alg.setPropertyValue("OutputWorkspace", "dummy");
+    alg.execute();
+    PeaksWorkspace_sptr integratedPeaksWS = alg.getProperty("OutputWorkspace");
+    TSM_ASSERT_EQUALS("Wrong number of peaks in output workspace",
+                      integratedPeaksWS->getNumberPeaks(),
+                      m_peaksWS->getNumberPeaks());
+
+    TSM_ASSERT_DELTA("Wrong intensity for peak 0",
+                     integratedPeaksWS->getPeak(0).getIntensity(), 2, 0.01);
+    TSM_ASSERT_DELTA("Wrong intensity for peak 1",
+                     integratedPeaksWS->getPeak(1).getIntensity(), 0.8, 0.01);
+    TSM_ASSERT_DELTA("Wrong intensity for peak 2",
+                     integratedPeaksWS->getPeak(2).getIntensity(), 2, 0.01);
+    TSM_ASSERT_DELTA("Wrong intensity for peak 3",
+                     integratedPeaksWS->getPeak(3).getIntensity(), 7, 0.01);
+    TSM_ASSERT_DELTA("Wrong intensity for peak 4",
+                     integratedPeaksWS->getPeak(4).getIntensity(), 0, 0.01);
+    TSM_ASSERT_DELTA("Wrong intensity for peak 5",
+                     integratedPeaksWS->getPeak(5).getIntensity(), 5.83, 0.01);
+  }
+
+  void test_execution_histograms_adaptive() {
+
+    IntegrateEllipsoids alg;
+    alg.setChild(true);
+    alg.setRethrows(true);
+    alg.initialize();
+    alg.setProperty("InputWorkspace", m_histoWS);
+    alg.setProperty("PeaksWorkspace", m_peaksWS);
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("SpecifySize", true));
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("PeakSize", 0.20));
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("BackgroundInnerSize", 0.23));
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("BackgroundOuterSize", 0.26));
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("AdaptiveQMultiplier", 0.01));
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("AdaptiveQBackground", true));
+    alg.setPropertyValue("OutputWorkspace", "dummy");
+    alg.execute();
+    PeaksWorkspace_sptr integratedPeaksWS = alg.getProperty("OutputWorkspace");
+    TSM_ASSERT_EQUALS("Wrong number of peaks in output workspace",
+                      integratedPeaksWS->getNumberPeaks(),
+                      m_peaksWS->getNumberPeaks());
+    TSM_ASSERT_DELTA("Wrong intensity for peak 0",
+                     integratedPeaksWS->getPeak(0).getIntensity(), 3, 0.01);
+    TSM_ASSERT_DELTA("Wrong intensity for peak 1",
+                     integratedPeaksWS->getPeak(1).getIntensity(), 3, 0.01);
+    TSM_ASSERT_DELTA("Wrong intensity for peak 2",
+                     integratedPeaksWS->getPeak(2).getIntensity(), 3, 0.01);
+    TSM_ASSERT_DELTA("Wrong intensity for peak 3",
+                     integratedPeaksWS->getPeak(3).getIntensity(), 10, 0.01);
+    TSM_ASSERT_DELTA("Wrong intensity for peak 4",
+                     integratedPeaksWS->getPeak(4).getIntensity(), 0, 0.01);
+    TSM_ASSERT_DELTA("Wrong intensity for peak 5",
+                     integratedPeaksWS->getPeak(5).getIntensity(), 9.94, 0.01);
+  }
+
   void test_execution_events_hkl() {
 
     IntegrateEllipsoids alg;
diff --git a/Framework/MDAlgorithms/test/IntegrateFluxTest.h b/Framework/MDAlgorithms/test/IntegrateFluxTest.h
index f3ec91a07a8420782a18b83fb7602ba0e1f4a284..488b3e155db693fd7af4e58df09615b1c39eb80f 100644
--- a/Framework/MDAlgorithms/test/IntegrateFluxTest.h
+++ b/Framework/MDAlgorithms/test/IntegrateFluxTest.h
@@ -5,6 +5,7 @@
 
 #include "MantidMDAlgorithms/IntegrateFlux.h"
 #include "MantidAPI/AlgorithmManager.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Axis.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/WorkspaceFactory.h"
diff --git a/Framework/MDAlgorithms/test/LoadMDTest.h b/Framework/MDAlgorithms/test/LoadMDTest.h
index 16a3868a00e2b339b4f22e05155363272f8a4157..41cd937c81aa115c12b9a563e54659a04b4215c1 100644
--- a/Framework/MDAlgorithms/test/LoadMDTest.h
+++ b/Framework/MDAlgorithms/test/LoadMDTest.h
@@ -4,8 +4,10 @@
 #include "SaveMDTest.h"
 #include "SaveMD2Test.h"
 
+#include "MantidKernel/Strings.h"
 #include "MantidAPI/IMDEventWorkspace.h"
 #include "MantidAPI/ExperimentInfo.h"
+#include "MantidAPI/WorkspaceHistory.h"
 #include "MantidDataObjects/MDBox.h"
 #include "MantidDataObjects/MDGridBox.h"
 #include "MantidDataObjects/MDEventFactory.h"
diff --git a/Framework/MDAlgorithms/test/LoadSQWTest.h b/Framework/MDAlgorithms/test/LoadSQWTest.h
index 6f0f7652e08fedeba998586e9c0b09f07072b306..0db94c63e4ec577ac14cf7ac82e19a1493ea3492 100644
--- a/Framework/MDAlgorithms/test/LoadSQWTest.h
+++ b/Framework/MDAlgorithms/test/LoadSQWTest.h
@@ -4,6 +4,7 @@
 #include "MantidMDAlgorithms/LoadSQW.h"
 #include "MantidGeometry/Crystal/OrientedLattice.h"
 #include "MantidDataObjects/MDBoxBase.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Sample.h"
 
 #include <cxxtest/TestSuite.h>
diff --git a/Framework/MDAlgorithms/test/MDTransfModQTest.h b/Framework/MDAlgorithms/test/MDTransfModQTest.h
index ebf41740f5dfafdee03778e5c20818cf9679eb6c..8d4abe7cf82e7fb93914711fd643705b8d906cbd 100644
--- a/Framework/MDAlgorithms/test/MDTransfModQTest.h
+++ b/Framework/MDAlgorithms/test/MDTransfModQTest.h
@@ -3,6 +3,7 @@
 
 #include "MantidMDAlgorithms/MDTransfQ3D.h"
 #include "MantidKernel/DeltaEMode.h"
+#include "MantidGeometry/Instrument/Goniometer.h"
 #include "MantidTestHelpers/WorkspaceCreationHelper.h"
 #include "MantidTestHelpers/MDEventsTestHelper.h"
 
diff --git a/Framework/MDAlgorithms/test/MDTransfQ3DTest.h b/Framework/MDAlgorithms/test/MDTransfQ3DTest.h
index af94840ef931be835f1b5c0c05cff7a5141b36af..cfe87617ea444c234a16e28025bdee3ea56d4565 100644
--- a/Framework/MDAlgorithms/test/MDTransfQ3DTest.h
+++ b/Framework/MDAlgorithms/test/MDTransfQ3DTest.h
@@ -2,6 +2,7 @@
 #define MANTID_MDALGORITHMS_MDTRANSFQ3D_H_
 
 #include "MantidKernel/DeltaEMode.h"
+#include "MantidGeometry/Instrument/Goniometer.h"
 #include "MantidMDAlgorithms/MDTransfQ3D.h"
 #include "MantidTestHelpers/WorkspaceCreationHelper.h"
 
diff --git a/Framework/MDAlgorithms/test/MDWSDescriptionTest.h b/Framework/MDAlgorithms/test/MDWSDescriptionTest.h
index 9fb059d6e736b0d8827ad398273a5e050cb5745a..2d7551bb66fe2dc2b919a2439c5304ca03d0c277 100644
--- a/Framework/MDAlgorithms/test/MDWSDescriptionTest.h
+++ b/Framework/MDAlgorithms/test/MDWSDescriptionTest.h
@@ -3,6 +3,7 @@
 
 #include "MantidKernel/SpecialCoordinateSystem.h"
 #include "MantidKernel/Exception.h"
+#include "MantidGeometry/Instrument/Goniometer.h"
 #include "MantidMDAlgorithms/MDWSDescription.h"
 #include "MantidTestHelpers/WorkspaceCreationHelper.h"
 
diff --git a/Framework/MDAlgorithms/test/MDWSTransfTest.h b/Framework/MDAlgorithms/test/MDWSTransfTest.h
index 3a2a7fb0a8250c1315631f856ef0c8c610a55f3a..ddf5e20a54a424ff579e466a57275dfdf1e7d397 100644
--- a/Framework/MDAlgorithms/test/MDWSTransfTest.h
+++ b/Framework/MDAlgorithms/test/MDWSTransfTest.h
@@ -2,6 +2,7 @@
 #define MANTID_MDWS_SLICE_H_
 
 #include "MantidGeometry/Crystal/OrientedLattice.h"
+#include "MantidGeometry/Instrument/Goniometer.h"
 #include "MantidMDAlgorithms/MDTransfAxisNames.h"
 #include "MantidMDAlgorithms/MDWSDescription.h"
 #include "MantidMDAlgorithms/MDWSTransform.h"
@@ -48,7 +49,7 @@ public:
   void testFindTargetFrame() {
     MDWSDescription TargWSDescription;
     Mantid::API::MatrixWorkspace_sptr spws =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(10, 10);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(10, 10);
     // Mantid::API::MatrixWorkspace_sptr spws
     // =WorkspaceCreationHelper::createProcessedWorkspaceWithCylComplexInstrument(4,10,true);
     std::vector<double> minVal(4, -3), maxVal(4, 3);
@@ -60,7 +61,7 @@ public:
     TS_ASSERT_EQUALS(CnvrtToMD::LabFrame,
                      Transf.findTargetFrame(TargWSDescription));
 
-    WorkspaceCreationHelper::SetGoniometer(spws, 0, 0, 0);
+    WorkspaceCreationHelper::setGoniometer(spws, 0, 0, 0);
     // spws->mutableRun().mutableGoniometer().setRotationAngle(0,20);
 
     TS_ASSERT_EQUALS(CnvrtToMD::SampleFrame,
@@ -74,7 +75,7 @@ public:
     MDWSDescription TargWSDescription;
 
     Mantid::API::MatrixWorkspace_sptr spws =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(10, 10);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(10, 10);
     std::vector<double> minVal(4, -3), maxVal(4, 3);
     TargWSDescription.setMinMax(minVal, maxVal);
     spws->mutableSample().setOrientedLattice(NULL);
@@ -95,7 +96,7 @@ public:
                       std::invalid_argument);
     spws->mutableSample().setOrientedLattice(pLattice);
 
-    WorkspaceCreationHelper::SetGoniometer(spws, 20, 0, 0);
+    WorkspaceCreationHelper::setGoniometer(spws, 20, 0, 0);
 
     // spws->mutableRun().mutableGoniometer().setRotationAngle(0,20);
 
@@ -377,7 +378,7 @@ public:
     std::vector<double> rot, sample(9, 0);
 
     Mantid::API::MatrixWorkspace_sptr spws =
-        WorkspaceCreationHelper::Create2DWorkspaceBinned(10, 10);
+        WorkspaceCreationHelper::create2DWorkspaceBinned(10, 10);
     // Mantid::API::MatrixWorkspace_sptr spws
     // =WorkspaceCreationHelper::createProcessedWorkspaceWithCylComplexInstrument(4,10,true);
     std::vector<double> minVal(2, 0), maxVal(2, 3);
diff --git a/Framework/MDAlgorithms/test/MergeMDFilesTest.h b/Framework/MDAlgorithms/test/MergeMDFilesTest.h
index e7fb5c6f6b319e451a43bd890e744a6608ec2999..b62604f3fb8ccaa6f4a1884afd06fc64c33b2f69 100644
--- a/Framework/MDAlgorithms/test/MergeMDFilesTest.h
+++ b/Framework/MDAlgorithms/test/MergeMDFilesTest.h
@@ -3,6 +3,7 @@
 
 #include "MantidMDAlgorithms/MergeMDFiles.h"
 #include "MantidDataObjects/MDEventFactory.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidTestHelpers/MDAlgorithmsTestHelper.h"
 #include "MantidGeometry/MDGeometry/QSample.h"
 
diff --git a/Framework/MDAlgorithms/test/MultiplyMDTest.h b/Framework/MDAlgorithms/test/MultiplyMDTest.h
index a28172002c3bc3cf2fa4bfce14265e93ca2e8f99..480a3576dff6bfa98ed06d8c863af1724f6d27bc 100644
--- a/Framework/MDAlgorithms/test/MultiplyMDTest.h
+++ b/Framework/MDAlgorithms/test/MultiplyMDTest.h
@@ -3,6 +3,7 @@
 
 #include "MantidDataObjects/MDHistoWorkspace.h"
 #include "MantidMDAlgorithms/MultiplyMD.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidTestHelpers/BinaryOperationMDTestHelper.h"
 
 #include <cxxtest/TestSuite.h>
diff --git a/Framework/MDAlgorithms/test/OneStepMDEWTest.h b/Framework/MDAlgorithms/test/OneStepMDEWTest.h
index 39232f2086b146ea4635d0d4508de511423ca8b8..5828764bfd7cfbddc10e2fc5e263c979ada62ab1 100644
--- a/Framework/MDAlgorithms/test/OneStepMDEWTest.h
+++ b/Framework/MDAlgorithms/test/OneStepMDEWTest.h
@@ -3,6 +3,7 @@
 
 #include <cxxtest/TestSuite.h>
 
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/IMDEventWorkspace.h"
 #include "MantidDataObjects/MDEventWorkspace.h"
 #include "MantidMDAlgorithms/OneStepMDEW.h"
diff --git a/Framework/MDAlgorithms/test/PreprocessDetectorsToMDTest.h b/Framework/MDAlgorithms/test/PreprocessDetectorsToMDTest.h
index d0dd6234c828c087c9732fd363e5e88b826b14e7..c13b00a06eb133353cadd58e2e587f4837f978fd 100644
--- a/Framework/MDAlgorithms/test/PreprocessDetectorsToMDTest.h
+++ b/Framework/MDAlgorithms/test/PreprocessDetectorsToMDTest.h
@@ -2,8 +2,10 @@
 #define MDALGORITHMS_PREPROCESS_DETECTORS2MD_TEST_H_
 
 #include <cxxtest/TestSuite.h>
+#include "MantidGeometry/Instrument/Goniometer.h"
 #include "MantidMDAlgorithms/PreprocessDetectorsToMD.h"
 #include "MantidTestHelpers/WorkspaceCreationHelper.h"
+#include "MantidAPI/SpectrumInfo.h"
 
 using namespace Mantid;
 using namespace Mantid::MDAlgorithms;
@@ -234,33 +236,15 @@ public:
         API::AnalysisDataService::Instance().retrieve("testMatrWS"));
     const size_t nRows = inputWS->getNumberHistograms();
 
-    // build detectors ID list to mask
-    std::vector<detid_t> detectorList;
-    detectorList.reserve(nRows);
-    std::vector<size_t> indexLis;
-    indexLis.reserve(nRows);
+    // Now mask all detectors in the workspace
+    auto &spectrumInfo = inputWS->mutableSpectrumInfo();
     for (size_t i = 0; i < nRows; i++) {
-      // get detector or detector group which corresponds to the spectra i
-      Geometry::IDetector_const_sptr spDet;
-      try {
-        spDet = inputWS->getDetector(i);
-      } catch (Kernel::Exception::NotFoundError &) {
-        continue;
-      }
-
-      // Check that we aren't dealing with monitor...
-      if (spDet->isMonitor())
+      if (!spectrumInfo.hasDetectors(i) || spectrumInfo.isMonitor(i))
         continue;
-
-      indexLis.push_back(i);
-      // detectorList.push_back(spDet->getID());
+      inputWS->getSpectrum(i).clearData();
+      spectrumInfo.setMasked(i, true);
     }
 
-    // Now mask all detectors in the workspace
-    std::vector<size_t>::const_iterator wit;
-    for (wit = indexLis.begin(); wit != indexLis.end(); ++wit) {
-      inputWS->maskWorkspaceIndex(*wit);
-    }
     // let's retrieve masks now
 
     TS_ASSERT_THROWS_NOTHING(pAlg->execute());
diff --git a/Framework/MDAlgorithms/test/SaveMD2Test.h b/Framework/MDAlgorithms/test/SaveMD2Test.h
index 6a036d06ad8b44bc833416c3f7eef27eb83ffd92..85c4b9e2704648910ab7cdb2ae05d6d314bba571 100644
--- a/Framework/MDAlgorithms/test/SaveMD2Test.h
+++ b/Framework/MDAlgorithms/test/SaveMD2Test.h
@@ -4,6 +4,7 @@
 #include "MantidAPI/IMDEventWorkspace.h"
 #include "MantidAPI/FrameworkManager.h"
 #include "MantidAPI/Run.h"
+#include "MantidGeometry/Instrument/Goniometer.h"
 #include "MantidDataObjects/MDEventFactory.h"
 #include "MantidMDAlgorithms/BinMD.h"
 #include "MantidMDAlgorithms/SaveMD2.h"
diff --git a/Framework/MDAlgorithms/test/SaveMDTest.h b/Framework/MDAlgorithms/test/SaveMDTest.h
index 3c4612a404b78d926c5dca2419a84c538c046e7d..a53feb583d2d2207db28d66eba17f118690075ff 100644
--- a/Framework/MDAlgorithms/test/SaveMDTest.h
+++ b/Framework/MDAlgorithms/test/SaveMDTest.h
@@ -5,6 +5,7 @@
 #include "MantidAPI/FrameworkManager.h"
 #include "MantidAPI/AlgorithmManager.h"
 #include "MantidAPI/Run.h"
+#include "MantidGeometry/Instrument/Goniometer.h"
 #include "MantidDataObjects/MDEventFactory.h"
 #include "MantidMDAlgorithms/BinMD.h"
 #include "MantidMDAlgorithms/SaveMD.h"
diff --git a/Framework/MDAlgorithms/test/SetMDFrameTest.h b/Framework/MDAlgorithms/test/SetMDFrameTest.h
index 19563b04a2832141dcb9d0869e4f8c6c365581aa..d03afaeea7e77f3ccc9dcbeaf193346e2018a0d2 100644
--- a/Framework/MDAlgorithms/test/SetMDFrameTest.h
+++ b/Framework/MDAlgorithms/test/SetMDFrameTest.h
@@ -30,7 +30,7 @@ public:
 
   void test_that_is_not_executed_when_non_mdevent_and_non_mdhisto() {
     // Arrange
-    auto inputWorkspace = WorkspaceCreationHelper::Create2DWorkspace(2, 5);
+    auto inputWorkspace = WorkspaceCreationHelper::create2DWorkspace(2, 5);
     SetMDFrame alg;
     alg.setChild(true);
     alg.setRethrows(true);
@@ -283,4 +283,4 @@ public:
   }
 };
 
-#endif /* MANTID_MDALGORITHMS_SetMDFrameTEST_H_ */
\ No newline at end of file
+#endif /* MANTID_MDALGORITHMS_SetMDFrameTEST_H_ */
diff --git a/Framework/MDAlgorithms/test/SliceMDTest.h b/Framework/MDAlgorithms/test/SliceMDTest.h
index aa243fa6925e8aa6e88fab28ed22998639b59462..b54159980af50b1032aae3d68ea8f5e3f82dc637 100644
--- a/Framework/MDAlgorithms/test/SliceMDTest.h
+++ b/Framework/MDAlgorithms/test/SliceMDTest.h
@@ -1,6 +1,7 @@
 #ifndef MANTID_MDEVENTS_SLICEMDTEST_H_
 #define MANTID_MDEVENTS_SLICEMDTEST_H_
 
+#include "MantidKernel/IPropertySettings.h"
 #include "MantidAPI/FrameworkManager.h"
 #include "MantidMDAlgorithms/SliceMD.h"
 #include "MantidDataObjects/CoordTransformAffine.h"
diff --git a/Framework/MDAlgorithms/test/ThresholdMDTest.h b/Framework/MDAlgorithms/test/ThresholdMDTest.h
index 794e5d1d12a2af54619c30e14c90fa8e35ae4a39..68887d2ea1053a08ec1267ae601cfbdfc9ae8c0d 100644
--- a/Framework/MDAlgorithms/test/ThresholdMDTest.h
+++ b/Framework/MDAlgorithms/test/ThresholdMDTest.h
@@ -1,6 +1,7 @@
 #ifndef MANTID_MDALGORITHMS_THRESHOLDMDTEST_H_
 #define MANTID_MDALGORITHMS_THRESHOLDMDTEST_H_
 
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidDataObjects/MDHistoWorkspace.h"
 #include "MantidGeometry/MDGeometry/MDHistoDimension.h"
 #include "MantidGeometry/MDGeometry/MDTypes.h"
diff --git a/Framework/MDAlgorithms/test/UnaryOperationMDTest.h b/Framework/MDAlgorithms/test/UnaryOperationMDTest.h
index dd3d073b678a2d4a13059230259a1477c5b35aa0..a7ffd215560eb79a79e90ae1481a61243a5267d5 100644
--- a/Framework/MDAlgorithms/test/UnaryOperationMDTest.h
+++ b/Framework/MDAlgorithms/test/UnaryOperationMDTest.h
@@ -48,7 +48,7 @@ public:
   void setUp() override {
     histo = MDEventsTestHelper::makeFakeMDHistoWorkspace(1.0, 2, 5, 10.0, 1.0);
     event = MDEventsTestHelper::makeMDEW<2>(3, 0.0, 10.0, 1);
-    scalar = WorkspaceCreationHelper::CreateWorkspaceSingleValue(2.5);
+    scalar = WorkspaceCreationHelper::createWorkspaceSingleValue(2.5);
     AnalysisDataService::Instance().addOrReplace("histo", histo);
     AnalysisDataService::Instance().addOrReplace("event", event);
     AnalysisDataService::Instance().addOrReplace("scalar", scalar);
diff --git a/Framework/MPIAlgorithms/src/GatherWorkspaces.cpp b/Framework/MPIAlgorithms/src/GatherWorkspaces.cpp
index 6c6e149ef693baa98ecdbe0cd2939950158dad54..8dc6cf18fdc3422ab7444ab7e0e463c89fbee3ea 100644
--- a/Framework/MPIAlgorithms/src/GatherWorkspaces.cpp
+++ b/Framework/MPIAlgorithms/src/GatherWorkspaces.cpp
@@ -263,7 +263,7 @@ void GatherWorkspaces::execEvent() {
                                                  numBins + hist, numBins));
     // Copy geometry over.
     API::WorkspaceFactory::Instance().initializeFromParent(
-        eventW, outputWorkspace, true);
+        *eventW, *outputWorkspace, true);
     setProperty("OutputWorkspace", outputWorkspace);
     ExperimentInfo_sptr inWS = inputWorkspace;
     outputWorkspace->copyExperimentInfoFrom(inWS.get());
diff --git a/Framework/Nexus/src/MuonNexusReader.cpp b/Framework/Nexus/src/MuonNexusReader.cpp
index eb509e51478132247055e62c9345fd9a58884b2b..8b70f0269315ce25d168f65032334511c3282b29 100644
--- a/Framework/Nexus/src/MuonNexusReader.cpp
+++ b/Framework/Nexus/src/MuonNexusReader.cpp
@@ -175,7 +175,6 @@ string MuonNexusReader::getInstrumentName() const {
 void MuonNexusReader::readLogData(const string &filename) {
   // reset the count of logs
   nexusLogCount = 0;
-  int nexusSampleCount = 0; // debug
 
   NeXus::File handle(filename, NXACC_READ);
   openFirstNXentry(handle);
@@ -203,7 +202,6 @@ void MuonNexusReader::readLogData(const string &filename) {
       handle.openGroup(nxname, nxclass);
       handle.readData("name", nexus_samplename);
       handle.closeGroup();
-      nexusSampleCount++; // debug
     }
     if (nxname == START_TIME) {
       handle.readData(START_TIME, startTime);
diff --git a/Framework/Nexus/src/NexusFileIO.cpp b/Framework/Nexus/src/NexusFileIO.cpp
index 9ac1e1f15139a72d8d2ce8f2c37ee808e75c1d86..f14de0749c6f9bfa93f380e7517ca53f7017f006 100644
--- a/Framework/Nexus/src/NexusFileIO.cpp
+++ b/Framework/Nexus/src/NexusFileIO.cpp
@@ -1,8 +1,5 @@
 // NexusFileIO
 // @author Ronald Fowler
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include <vector>
 #include <sstream>
 
@@ -19,6 +16,7 @@
 #include "MantidKernel/UnitFactory.h"
 #include "MantidKernel/ArrayProperty.h"
 #include "MantidAPI/NumericAxis.h"
+#include "MantidKernel/Unit.h"
 #include "MantidKernel/VectorHelper.h"
 #include "MantidDataObjects/TableWorkspace.h"
 #include "MantidDataObjects/PeaksWorkspace.h"
@@ -672,6 +670,11 @@ int NexusFileIO::writeNexusTableWorkspace(
         if (col->cell<std::string>(ii).size() > maxStr)
           maxStr = col->cell<std::string>(ii).size();
       }
+      // If the column is empty fill the data with spaces.
+      // Strings containing spaces only will be read back in as empty strings.
+      if (maxStr == 0) {
+        maxStr = 1;
+      }
       int dims_array[2] = {nRows, static_cast<int>(maxStr)};
       int asize[2] = {1, dims_array[1]};
 
diff --git a/Framework/Properties/Mantid.properties.template b/Framework/Properties/Mantid.properties.template
index 7921eb64b5010772538bd1e3fb3fc98a43ecdf12..b48c5203a4b1ea5cfccc37a75629c764d38df257 100644
--- a/Framework/Properties/Mantid.properties.template
+++ b/Framework/Properties/Mantid.properties.template
@@ -124,11 +124,13 @@ MultiThreaded.MaxCores = 0
 
 # Defines the area (in FWHM) on both sides of the peak centre within which peaks are calculated.
 # Outside this area peak functions return zero.
-curvefitting.peakRadius = 5
 curvefitting.defaultPeak=Gaussian
 curvefitting.findPeaksFWHM=7
 curvefitting.findPeaksTolerance=4
 
+#Defines whether or not the sliceViewer will show NonOrthogonal view as a default
+sliceviewer.nonorthogonal=false
+
 # Network Timeouts (in seconds for various uses within Mantid)
 network.default.timeout = 30
 network.scriptrepo.timeout = 5
diff --git a/Framework/PythonInterface/mantid/api/CMakeLists.txt b/Framework/PythonInterface/mantid/api/CMakeLists.txt
index 3756e81923482d6df7b86fc1bc8ec07889fbd65d..17a8ea2024cd65837afdf288e0dc596590c4c50a 100644
--- a/Framework/PythonInterface/mantid/api/CMakeLists.txt
+++ b/Framework/PythonInterface/mantid/api/CMakeLists.txt
@@ -13,6 +13,7 @@ set ( EXPORT_FILES
   src/Exports/AlgorithmHistory.cpp
   src/Exports/CatalogManager.cpp
   src/Exports/CatalogSession.cpp
+  src/Exports/DetectorInfo.cpp
   src/Exports/DeprecatedAlgorithmChecker.cpp
   src/Exports/Algorithm.cpp
   src/Exports/DataProcessorAlgorithm.cpp
@@ -61,6 +62,7 @@ set ( EXPORT_FILES
   src/Exports/Sample.cpp
   src/Exports/ScriptRepository.cpp
   src/Exports/ScriptRepositoryFactory.cpp
+  src/Exports/SpectrumInfo.cpp
   src/Exports/Run.cpp
   src/Exports/WorkspaceFactory.cpp
   src/Exports/IFunction.cpp
diff --git a/Framework/PythonInterface/mantid/api/src/Algorithms/RunPythonScript.cpp b/Framework/PythonInterface/mantid/api/src/Algorithms/RunPythonScript.cpp
index 547d3b1b32cb7b7c1d11830812e573ce7272c0b7..27680a1caeaa97485e2fec06d6342a2e118ebde8 100644
--- a/Framework/PythonInterface/mantid/api/src/Algorithms/RunPythonScript.cpp
+++ b/Framework/PythonInterface/mantid/api/src/Algorithms/RunPythonScript.cpp
@@ -1,3 +1,4 @@
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/FileProperty.h"
 #include "MantidPythonInterface/api/Algorithms/RunPythonScript.h"
 #include "MantidPythonInterface/api/ExtractWorkspace.h"
diff --git a/Framework/PythonInterface/mantid/api/src/Exports/BinaryOperations.cpp b/Framework/PythonInterface/mantid/api/src/Exports/BinaryOperations.cpp
index a0d1c6b4323cfe112806964152f6ad9391053d64..2e45ae9772c8989ff3c18583da88fa834fd9b977 100644
--- a/Framework/PythonInterface/mantid/api/src/Exports/BinaryOperations.cpp
+++ b/Framework/PythonInterface/mantid/api/src/Exports/BinaryOperations.cpp
@@ -5,7 +5,7 @@
 #include "MantidAPI/IMDHistoWorkspace.h"
 #include "MantidAPI/IMDWorkspace.h"
 #include "MantidAPI/MatrixWorkspace.h"
-#include "MantidAPI/WorkspaceGroup_fwd.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidAPI/WorkspaceOpOverloads.h"
 #include "MantidPythonInterface/kernel/Policies/AsType.h"
 
diff --git a/Framework/PythonInterface/mantid/api/src/Exports/DetectorInfo.cpp b/Framework/PythonInterface/mantid/api/src/Exports/DetectorInfo.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3ced363b91929fa7e0b7c61408f9b0d63d139a80
--- /dev/null
+++ b/Framework/PythonInterface/mantid/api/src/Exports/DetectorInfo.cpp
@@ -0,0 +1,19 @@
+#include "MantidAPI/DetectorInfo.h"
+#include <boost/python/class.hpp>
+
+using Mantid::API::DetectorInfo;
+using namespace boost::python;
+
+void export_DetectorInfo() {
+  class_<DetectorInfo, boost::noncopyable>("DetectorInfo", no_init)
+      .def("__len__", &DetectorInfo::size, (arg("self")),
+           "Returns the size of the DetectorInfo, i.e., the number of "
+           "detectors in the instrument.")
+      .def("size", &DetectorInfo::size, (arg("self")),
+           "Returns the size of the DetectorInfo, i.e., the number of "
+           "detectors in the instrument.")
+      .def("isMonitor", &DetectorInfo::isMonitor, (arg("self"), arg("index")),
+           "Returns True if the detector is a monitor.")
+      .def("isMasked", &DetectorInfo::isMasked, (arg("self"), arg("index")),
+           "Returns True if the detector is masked.");
+}
diff --git a/Framework/PythonInterface/mantid/api/src/Exports/ExperimentInfo.cpp b/Framework/PythonInterface/mantid/api/src/Exports/ExperimentInfo.cpp
index aa44a273b6f9b6bf1d67f20a8d2e2f5a76d157eb..ad8cbf506e2037d02f9c06d509d2ff79c999e244 100644
--- a/Framework/PythonInterface/mantid/api/src/Exports/ExperimentInfo.cpp
+++ b/Framework/PythonInterface/mantid/api/src/Exports/ExperimentInfo.cpp
@@ -1,4 +1,5 @@
 #include "MantidGeometry/IDTypes.h"
+#include "MantidAPI/DetectorInfo.h"
 #include "MantidAPI/ExperimentInfo.h"
 #include "MantidAPI/Run.h"
 #include "MantidAPI/Sample.h"
@@ -70,5 +71,9 @@ void export_ExperimentInfo() {
            args("self", "detId", "value"))
 
       .def("getEMode", &ExperimentInfo::getEMode, args("self"),
-           "Returns the energy mode.");
+           "Returns the energy mode.")
+
+      .def("detectorInfo", &ExperimentInfo::detectorInfo,
+           return_value_policy<reference_existing_object>(), args("self"),
+           "Return a const reference to the DetectorInfo object.");
 }
diff --git a/Framework/PythonInterface/mantid/api/src/Exports/IAlgorithm.cpp b/Framework/PythonInterface/mantid/api/src/Exports/IAlgorithm.cpp
index 3615761a57fa746af55722e8eaf3a327298a7f65..cc92119a4c67aa89fc64093d332f1f88962e56f5 100644
--- a/Framework/PythonInterface/mantid/api/src/Exports/IAlgorithm.cpp
+++ b/Framework/PythonInterface/mantid/api/src/Exports/IAlgorithm.cpp
@@ -186,7 +186,7 @@ std::string createDocString(IAlgorithm &self) {
   // Put in the quick overview message
   std::stringstream buffer;
   std::string temp = self.summary();
-  if (temp.size() > 0)
+  if (!temp.empty())
     buffer << temp << EOL << EOL;
 
   // get a sorted copy of the properties
diff --git a/Framework/PythonInterface/mantid/api/src/Exports/IMDHistoWorkspace.cpp b/Framework/PythonInterface/mantid/api/src/Exports/IMDHistoWorkspace.cpp
index a3744f7f4ec9ed9eacc5f29059fcc7e5e4de19c2..2a085a4a41b32ea1bc559e89bee5784a6308c1d4 100644
--- a/Framework/PythonInterface/mantid/api/src/Exports/IMDHistoWorkspace.cpp
+++ b/Framework/PythonInterface/mantid/api/src/Exports/IMDHistoWorkspace.cpp
@@ -1,4 +1,5 @@
 #include "MantidAPI/IMDHistoWorkspace.h"
+#include "MantidGeometry/MDGeometry/IMDDimension.h"
 #include "MantidPythonInterface/kernel/GetPointer.h"
 #include "MantidPythonInterface/kernel/NdArray.h"
 #include "MantidPythonInterface/kernel/Converters/NDArrayTypeIndex.h"
@@ -256,7 +257,13 @@ void export_IMDHistoWorkspace() {
       .def("getCenter", &IMDHistoWorkspace::getCenter,
            (arg("self"), arg("linear_index")),
            return_value_policy<return_by_value>(),
-           "Return the position of the center of a bin at a given position");
+           "Return the position of the center of a bin at a given position")
+
+      .def("setDisplayNormalization",
+           &IMDHistoWorkspace::setDisplayNormalization,
+           (arg("self"), arg("normalization")),
+           "Sets the visual normalization of"
+           " the workspace.");
 
   //-------------------------------------------------------------------------------------------------
 
diff --git a/Framework/PythonInterface/mantid/api/src/Exports/MDGeometry.cpp b/Framework/PythonInterface/mantid/api/src/Exports/MDGeometry.cpp
index 83d57c115566483a54f6dfdc0121d93f54073495..367fb90a81ba9daf2576dc05cf671526ef850c01 100644
--- a/Framework/PythonInterface/mantid/api/src/Exports/MDGeometry.cpp
+++ b/Framework/PythonInterface/mantid/api/src/Exports/MDGeometry.cpp
@@ -1,4 +1,5 @@
 #include "MantidAPI/MDGeometry.h"
+#include "MantidAPI/Workspace.h"
 #include "MantidPythonInterface/kernel/Policies/RemoveConst.h"
 #include "MantidPythonInterface/kernel/Policies/VectorToNumpy.h"
 #include <boost/python/class.hpp>
@@ -7,7 +8,6 @@
 #include <boost/python/return_value_policy.hpp>
 
 using Mantid::API::MDGeometry;
-using Mantid::Geometry::IMDDimension_const_sptr;
 using Mantid::PythonInterface::Policies::RemoveConstSharedPtr;
 using Mantid::PythonInterface::Policies::VectorToNumpy;
 using namespace boost::python;
diff --git a/Framework/PythonInterface/mantid/api/src/Exports/MatrixWorkspace.cpp b/Framework/PythonInterface/mantid/api/src/Exports/MatrixWorkspace.cpp
index 7de857936c62f46b12e6689c8b325cfbee77fc0e..8633f3568079fdb6403fd48710aa1191d1d101e6 100644
--- a/Framework/PythonInterface/mantid/api/src/Exports/MatrixWorkspace.cpp
+++ b/Framework/PythonInterface/mantid/api/src/Exports/MatrixWorkspace.cpp
@@ -1,6 +1,7 @@
 #include "MantidAPI/Axis.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/Run.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidAPI/WorkspaceOpOverloads.h"
 
 #include "MantidPythonInterface/api/CloneMatrixWorkspace.h"
@@ -241,6 +242,10 @@ void export_MatrixWorkspace() {
       .def("YUnitLabel", &MatrixWorkspace::YUnitLabel, arg("self"),
            "Returns the caption for the Y axis")
 
+      .def("spectrumInfo", &MatrixWorkspace::spectrumInfo,
+           return_value_policy<reference_existing_object>(), args("self"),
+           "Return a const reference to the SpectrumInfo object.")
+
       // Deprecated
       .def("getNumberBins", &getNumberBinsDeprecated, arg("self"),
            "Returns size of the Y data array (deprecated, use blocksize "
diff --git a/Framework/PythonInterface/mantid/api/src/Exports/SpectrumInfo.cpp b/Framework/PythonInterface/mantid/api/src/Exports/SpectrumInfo.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6f5deaba3df5beac2a1a812ed628d7269dbe4c9f
--- /dev/null
+++ b/Framework/PythonInterface/mantid/api/src/Exports/SpectrumInfo.cpp
@@ -0,0 +1,18 @@
+#include "MantidAPI/SpectrumInfo.h"
+#include <boost/python/class.hpp>
+
+using Mantid::API::SpectrumInfo;
+using namespace boost::python;
+
+void export_SpectrumInfo() {
+  class_<SpectrumInfo, boost::noncopyable>("SpectrumInfo", no_init)
+      .def("isMonitor", &SpectrumInfo::isMonitor, (arg("self"), arg("index")),
+           "Returns true if the detector(s) associated with the spectrum are "
+           "monitors.")
+      .def("isMasked", &SpectrumInfo::isMasked, (arg("self"), arg("index")),
+           "Returns true if the detector(s) associated with the spectrum are "
+           "masked.")
+      .def("hasDetectors", &SpectrumInfo::hasDetectors, (arg("self")),
+           "Returns true if the spectrum is associated with detectors in the "
+           "instrument.");
+}
diff --git a/Framework/PythonInterface/mantid/api/src/Exports/Workspace.cpp b/Framework/PythonInterface/mantid/api/src/Exports/Workspace.cpp
index 8419a41fa2966fac47df65dfbaa1a48566b1cb4d..faacde19ff31d9a84baa76bde567756055735a8e 100644
--- a/Framework/PythonInterface/mantid/api/src/Exports/Workspace.cpp
+++ b/Framework/PythonInterface/mantid/api/src/Exports/Workspace.cpp
@@ -1,4 +1,5 @@
 #include "MantidAPI/Workspace.h"
+#include "MantidAPI/WorkspaceHistory.h"
 
 #include "MantidPythonInterface/kernel/GetPointer.h"
 #include "MantidPythonInterface/kernel/Registry/RegisterWorkspacePtrToPython.h"
@@ -30,10 +31,22 @@ BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(Workspace_isDirtyOverloads,
 ///@endcond
 }
 
+//--------------------------------------------------------------------------------------
+// Deprecated function
+//--------------------------------------------------------------------------------------
+/**
+ * @param self Reference to the calling object
+ * @return name of the workspace.
+ */
+std::string getName(Workspace &self) {
+  PyErr_Warn(PyExc_DeprecationWarning,
+             ".getName() is deprecated. Use .name() instead.");
+  return self.getName();
+}
+
 void export_Workspace() {
   class_<Workspace, bases<DataItem>, boost::noncopyable>("Workspace", no_init)
-      .def("getName", &Workspace::getName,
-           return_value_policy<copy_const_reference>(), arg("self"),
+      .def("getName", &getName, arg("self"),
            "Returns the name of the workspace. This could be an empty string")
       .def("getTitle", &Workspace::getTitle, arg("self"),
            "Returns the title of the workspace")
diff --git a/Framework/PythonInterface/mantid/api/src/Exports/WorkspaceGroupProperty.cpp b/Framework/PythonInterface/mantid/api/src/Exports/WorkspaceGroupProperty.cpp
index 58834332b90e591fc2447ef868fe01ed48974dec..5522dfe1b2a2a39f10f6800988dcddd9b95709d0 100644
--- a/Framework/PythonInterface/mantid/api/src/Exports/WorkspaceGroupProperty.cpp
+++ b/Framework/PythonInterface/mantid/api/src/Exports/WorkspaceGroupProperty.cpp
@@ -1,6 +1,6 @@
 #include "MantidPythonInterface/api/WorkspacePropertyExporter.h"
 #include "MantidPythonInterface/kernel/GetPointer.h"
-#include "MantidAPI/WorkspaceGroup_fwd.h"
+#include "MantidAPI/WorkspaceGroup.h"
 
 using Mantid::API::WorkspaceGroup;
 using Mantid::API::WorkspaceProperty;
diff --git a/Framework/PythonInterface/mantid/api/src/Exports/WorkspaceProperty.cpp b/Framework/PythonInterface/mantid/api/src/Exports/WorkspaceProperty.cpp
index 291079ff6a0594dc77bf4c318b60b74d81efaad1..53f5e602d291c7f3c2c5da307211066c445b1dec 100644
--- a/Framework/PythonInterface/mantid/api/src/Exports/WorkspaceProperty.cpp
+++ b/Framework/PythonInterface/mantid/api/src/Exports/WorkspaceProperty.cpp
@@ -1,6 +1,6 @@
 #include "MantidPythonInterface/api/WorkspacePropertyExporter.h"
 #include "MantidPythonInterface/kernel/GetPointer.h"
-#include "MantidAPI/Workspace_fwd.h"
+#include "MantidAPI/Workspace.h"
 #include <boost/python/enum.hpp>
 
 using Mantid::API::Workspace;
diff --git a/Framework/PythonInterface/mantid/geometry/CMakeLists.txt b/Framework/PythonInterface/mantid/geometry/CMakeLists.txt
index 88e26b3d792ac1a475a040158dd2fa24a3efea77..a05a9c2d6f0634f4a4b2e9ee280b91c383704c3d 100644
--- a/Framework/PythonInterface/mantid/geometry/CMakeLists.txt
+++ b/Framework/PythonInterface/mantid/geometry/CMakeLists.txt
@@ -82,6 +82,7 @@ set_target_output_directory ( PythonGeometryModule ${OUTPUT_DIR} .pyd )
 target_link_libraries ( PythonGeometryModule LINK_PRIVATE ${TCMALLOC_LIBRARIES_LINKTIME}
             PythonKernelModule
             Geometry
+            Beamline
             Kernel
             ${PYTHON_LIBRARIES}
             ${POCO_LIBRARIES}
diff --git a/Framework/PythonInterface/mantid/geometry/src/Exports/Detector.cpp b/Framework/PythonInterface/mantid/geometry/src/Exports/Detector.cpp
index 2353466249dca674ca34c2341d6de80640576063..7cea81813650e989a866be12213250826e32578d 100644
--- a/Framework/PythonInterface/mantid/geometry/src/Exports/Detector.cpp
+++ b/Framework/PythonInterface/mantid/geometry/src/Exports/Detector.cpp
@@ -1,4 +1,6 @@
 #include "MantidGeometry/Instrument/Detector.h"
+#include "MantidGeometry/Instrument/ParameterMap.h"
+#include "MantidBeamline/DetectorInfo.h"
 #include <boost/python/class.hpp>
 
 using Mantid::Geometry::Detector;
@@ -6,11 +8,33 @@ using Mantid::Geometry::IDetector;
 using Mantid::Geometry::ObjComponent;
 using namespace boost::python;
 
+namespace {
+bool isMaskedDeprecated(const Detector &self) {
+  PyErr_Warn(PyExc_DeprecationWarning, "'Detector::isMasked' is deprecated, "
+                                       "use 'DetectorInfo::isMasked' instead.");
+  const auto &detInfo = self.parameterMap().detectorInfo();
+  return detInfo.isMasked(self.index());
+}
+
+bool isMonitorDeprecated(const Detector &self) {
+  PyErr_Warn(PyExc_DeprecationWarning,
+             "'Detector::isMonitor' is deprecated, "
+             "use 'DetectorInfo::isMonitor' instead.");
+  const auto &detInfo = self.parameterMap().detectorInfo();
+  return detInfo.isMonitor(self.index());
+}
+}
+
 /**
  * Enables boost.python to automatically "cast" an object up to the
  * appropriate Detector leaf type
  */
 void export_Detector() {
   class_<Detector, bases<IDetector, ObjComponent>, boost::noncopyable>(
-      "Detector", no_init);
+      "Detector", no_init)
+      .def("isMasked", &isMaskedDeprecated, arg("self"),
+           "Returns the value of the masked flag. True means ignore this "
+           "detector")
+      .def("isMonitor", &isMonitorDeprecated, arg("self"),
+           "Returns True if the detector is marked as a monitor in the IDF");
 }
diff --git a/Framework/PythonInterface/mantid/geometry/src/Exports/DetectorGroup.cpp b/Framework/PythonInterface/mantid/geometry/src/Exports/DetectorGroup.cpp
index 2a9be545cbb2fc04e75905bdc732db599aa5869b..37aad3f10b754060012b57ede9231f519ce58bcd 100644
--- a/Framework/PythonInterface/mantid/geometry/src/Exports/DetectorGroup.cpp
+++ b/Framework/PythonInterface/mantid/geometry/src/Exports/DetectorGroup.cpp
@@ -1,13 +1,48 @@
 #include "MantidGeometry/Instrument/DetectorGroup.h"
+#include "MantidGeometry/Instrument/ParameterMap.h"
+#include "MantidBeamline/DetectorInfo.h"
 #include <boost/python/class.hpp>
 
 using Mantid::Geometry::DetectorGroup;
 using Mantid::Geometry::IDetector;
 using namespace boost::python;
 
+namespace {
+bool isMaskedDeprecated(const DetectorGroup &self) {
+  PyErr_Warn(PyExc_DeprecationWarning,
+             "'DetectorGroup::isMasked' is deprecated, "
+             "use 'SpectrumInfo::isMasked' instead.");
+  const auto &dets = self.getDetectors();
+  bool masked = true;
+  for (const auto &det : dets) {
+    const auto &detInfo = det->parameterMap().detectorInfo();
+    masked &= detInfo.isMasked(det->index());
+  }
+  return masked;
+}
+
+bool isMonitorDeprecated(const DetectorGroup &self) {
+  PyErr_Warn(PyExc_DeprecationWarning, "'DetectorGroup::isMonitor' is "
+                                       "deprecated, use "
+                                       "'SpectrumInfo::isMonitor' instead.");
+  const auto &dets = self.getDetectors();
+  for (const auto &det : dets) {
+    const auto &detInfo = det->parameterMap().detectorInfo();
+    if (!detInfo.isMonitor(det->index()))
+      return false;
+  }
+  return true;
+}
+}
+
 void export_DetectorGroup() {
   class_<DetectorGroup, bases<IDetector>, boost::noncopyable>("DetectorGroup",
                                                               no_init)
+      .def("isMasked", &isMaskedDeprecated, arg("self"),
+           "Returns the value of the masked flag. True means ignore this "
+           "detector")
+      .def("isMonitor", &isMonitorDeprecated, arg("self"),
+           "Returns True if the detector is marked as a monitor in the IDF")
       .def("getDetectorIDs", &DetectorGroup::getDetectorIDs, arg("self"),
            "Returns the list of detector IDs within this group")
       .def("getNameSeparator", &DetectorGroup::getNameSeparator, arg("self"),
diff --git a/Framework/PythonInterface/mantid/geometry/src/Exports/IDetector.cpp b/Framework/PythonInterface/mantid/geometry/src/Exports/IDetector.cpp
index 2285a227b0b4b2a304754b459353d8bfdd14605d..cdee3880daf59941d5f8b25c4925f5aadbb29085 100644
--- a/Framework/PythonInterface/mantid/geometry/src/Exports/IDetector.cpp
+++ b/Framework/PythonInterface/mantid/geometry/src/Exports/IDetector.cpp
@@ -15,11 +15,6 @@ void export_IDetector() {
   class_<IDetector, bases<IObjComponent>, boost::noncopyable>("IDetector",
                                                               no_init)
       .def("getID", &IDetector::getID, arg("self"), "Returns the detector ID")
-      .def("isMasked", &IDetector::isMasked, arg("self"),
-           "Returns the value of the masked flag. True means ignore this "
-           "detector")
-      .def("isMonitor", &IDetector::isMonitor, arg("self"),
-           "Returns True if the detector is marked as a monitor in the IDF")
       .def("solidAngle", &IDetector::solidAngle, (arg("self"), arg("observer")),
            "Return the solid angle in steradians between this "
            "detector and an observer")
diff --git a/Framework/PythonInterface/mantid/geometry/src/Exports/IMDDimension.cpp b/Framework/PythonInterface/mantid/geometry/src/Exports/IMDDimension.cpp
index 842822eb26f73507f8c630d988becd1be1b2da66..adf9656457e51a1be01359569f732fe4490978b6 100644
--- a/Framework/PythonInterface/mantid/geometry/src/Exports/IMDDimension.cpp
+++ b/Framework/PythonInterface/mantid/geometry/src/Exports/IMDDimension.cpp
@@ -38,13 +38,29 @@ boost::shared_ptr<MDFrame> getMDFrame(const IMDDimension &self) {
 }
 }
 
+//--------------------------------------------------------------------------------------
+// Deprecated function
+//--------------------------------------------------------------------------------------
+/**
+ * @param self Reference to the calling object
+ * @return name of the dimension.
+ */
+std::string getName(IMDDimension &self) {
+  PyErr_Warn(PyExc_DeprecationWarning,
+             ".getName() is deprecated. Use .name instead.");
+  return self.getName();
+}
+
 void export_IMDDimension() {
   register_ptr_to_python<boost::shared_ptr<IMDDimension>>();
 
   class_<IMDDimension, boost::noncopyable>("IMDDimension", no_init)
-      .def("getName", &IMDDimension::getName, arg("self"),
-           "Return the name of the dimension as can be displayed "
-           "along the axis")
+      .def("getName", &getName, arg("self"), "Return the name of the dimension "
+                                             "as can be displayed along the "
+                                             "axis")
+      .add_property("name", &IMDDimension::getName,
+                    "Return the name of the dimension as can be displayed "
+                    "along the axis")
       .def("getMaximum", &IMDDimension::getMaximum, arg("self"),
            "Return the maximum extent of this dimension")
       .def("getMinimum", &IMDDimension::getMinimum, arg("self"),
@@ -55,6 +71,7 @@ void export_IMDDimension() {
       .def("getX", &IMDDimension::getX, (arg("self"), arg("ind")),
            "Return coordinate of the axis at the given index")
       .def("getDimensionId", &IMDDimension::getDimensionId, arg("self"),
+           return_value_policy<copy_const_reference>(),
            "Return a short name which identify the dimension among other "
            "dimension."
            "A dimension can be usually find by its ID and various  ")
diff --git a/Framework/PythonInterface/mantid/kernel/CMakeLists.txt b/Framework/PythonInterface/mantid/kernel/CMakeLists.txt
index 18723bc4f63fbc1f47d1b4b311055bf5afb2d42b..4eefde94841e99753ceb812dd871ac650e3c02b4 100644
--- a/Framework/PythonInterface/mantid/kernel/CMakeLists.txt
+++ b/Framework/PythonInterface/mantid/kernel/CMakeLists.txt
@@ -31,6 +31,7 @@ set ( EXPORT_FILES
   src/Exports/DateAndTime.cpp
   src/Exports/InstrumentInfo.cpp
   src/Exports/FacilityInfo.cpp
+  src/Exports/LiveListenerInfo.cpp
   src/Exports/NullValidator.cpp
   src/Exports/ListValidator.cpp
   src/Exports/ArrayLengthValidator.cpp
diff --git a/Framework/PythonInterface/mantid/kernel/funcinspect.py b/Framework/PythonInterface/mantid/kernel/funcinspect.py
index 99b65d64c2ed30b8138a3b00b87b8358766a1859..599981fd17c0b3fd75edda97bd5dda82262a5253 100644
--- a/Framework/PythonInterface/mantid/kernel/funcinspect.py
+++ b/Framework/PythonInterface/mantid/kernel/funcinspect.py
@@ -11,6 +11,8 @@ from __future__ import (absolute_import, division,
 import opcode
 import inspect
 import sys
+import dis
+from six import PY3
 
 #-------------------------------------------------------------------------------
 def replace_signature(func, varnames):
@@ -57,19 +59,6 @@ def customise_func(func, name, signature, docstring):
     replace_signature(func, signature)
     return func
 
-#-------------------------------------------------------------------------------
-
-if sys.version_info[0] >= 3:
-  def opcode_from_bytecode(bc):
-      """Return the opcode from the given single bytecode
-      """
-      return bc
-else:
-  def opcode_from_bytecode(bc):
-      """Return the opcode from the given single bytecode str
-      """
-      return ord(bc)
-
 #-------------------------------------------------------------------------------
 def decompile(code_object):
     """
@@ -91,7 +80,7 @@ def decompile(code_object):
 
     Outputs:
     =========     =====================================================================
-    instructions  a list of offsets, op_codes, names, arguments, argument_type,
+    instructions  a list of offsets, op_codes, names, arguments,
                   argument_value which can be deconstructed to find out various things
                   about a function call.
 
@@ -101,49 +90,46 @@ def decompile(code_object):
     i = f.f_lasti  # index of the last attempted instruction in byte code
     ins = decompile(f.f_code)
     """
-    code = code_object.co_code
-    variables = code_object.co_cellvars + code_object.co_freevars
     instructions = []
-    n = len(code)
-    i = 0
-    e = 0
-    while i < n:
-        i_offset = i
-        i_opcode = opcode_from_bytecode(code[i])
-        i = i + 1
-        if i_opcode >= opcode.HAVE_ARGUMENT:
-            i_argument = opcode_from_bytecode(code[i]) + (opcode_from_bytecode(code[i+1]) << (4*2)) + e
-            i = i + 2
-            if i_opcode == opcode.EXTENDED_ARG:
-                e = iarg << 16
-            else:
-                e = 0
-            if i_opcode in opcode.hasconst:
-                i_arg_value = repr(code_object.co_consts[i_argument])
-                i_arg_type = 'CONSTANT'
-            elif i_opcode in opcode.hasname:
-                i_arg_value = code_object.co_names[i_argument]
-                i_arg_type = 'GLOBAL VARIABLE'
-            elif i_opcode in opcode.hasjrel:
-                i_arg_value = repr(i + i_argument)
-                i_arg_type = 'RELATIVE JUMP'
-            elif i_opcode in opcode.haslocal:
-                i_arg_value = code_object.co_varnames[i_argument]
-                i_arg_type = 'LOCAL VARIABLE'
-            elif i_opcode in opcode.hascompare:
-                i_arg_value = opcode.cmp_op[i_argument]
-                i_arg_type = 'COMPARE OPERATOR'
-            elif i_opcode in opcode.hasfree:
-                i_arg_value = variables[i_argument]
-                i_arg_type = 'FREE VARIABLE'
+
+    if PY3:
+        for ins in dis.get_instructions(code_object):
+            instructions.append( (ins.offset, ins.opcode, ins.opname, ins.arg, ins.argval) )
+    else:
+        code = code_object.co_code
+        variables = code_object.co_cellvars + code_object.co_freevars
+        n = len(code)
+        i = 0
+        e = 0
+        while i < n:
+            i_offset = i
+            i_opcode = ord(code[i])
+            i = i + 1
+            if i_opcode >= opcode.HAVE_ARGUMENT:
+                i_argument = ord(code[i]) + (ord(code[i+1]) << (4*2)) + e
+                i = i + 2
+                if i_opcode == opcode.EXTENDED_ARG:
+                    e = i_argument << 16
+                else:
+                    e = 0
+                if i_opcode in opcode.hasconst:
+                    i_arg_value = repr(code_object.co_consts[i_argument])
+                elif i_opcode in opcode.hasname:
+                    i_arg_value = code_object.co_names[i_argument]
+                elif i_opcode in opcode.hasjrel:
+                    i_arg_value = repr(i + i_argument)
+                elif i_opcode in opcode.haslocal:
+                    i_arg_value = code_object.co_varnames[i_argument]
+                elif i_opcode in opcode.hascompare:
+                    i_arg_value = opcode.cmp_op[i_argument]
+                elif i_opcode in opcode.hasfree:
+                    i_arg_value = variables[i_argument]
+                else:
+                    i_arg_value = i_argument
             else:
-                i_arg_value = i_argument
-                i_arg_type = 'OTHER'
-        else:
-            i_argument = None
-            i_arg_value = None
-            i_arg_type = None
-        instructions.append( (i_offset, i_opcode, opcode.opname[i_opcode], i_argument, i_arg_type, i_arg_value) )
+                i_argument = None
+                i_arg_value = None
+            instructions.append( (i_offset, i_opcode, opcode.opname[i_opcode], i_argument, i_arg_value) )
     return instructions
 
 #-------------------------------------------------------------------------------
@@ -161,7 +147,8 @@ __operator_names = set(['CALL_FUNCTION', 'CALL_FUNCTION_VAR', 'CALL_FUNCTION_KW'
                         'INPLACE_TRUE_DIVIDE','INPLACE_FLOOR_DIVIDE',
                         'INPLACE_MODULO', 'INPLACE_ADD', 'INPLACE_SUBTRACT',
                         'INPLACE_LSHIFT','INPLACE_RSHIFT','INPLACE_AND', 'INPLACE_XOR',
-                        'INPLACE_OR', 'COMPARE_OP'])
+                        'INPLACE_OR', 'COMPARE_OP',
+                        'CALL_FUNCTION_EX'])
 #--------------------------------------------------------------------------------------
 
 def process_frame(frame):
@@ -187,13 +174,13 @@ def process_frame(frame):
     start_offset = 0
 
     for index, instruction in enumerate(ins_stack):
-        (offset, op, name, argument, argtype, argvalue) = instruction
+        (offset, op, name, argument, argvalue) = instruction
         if name in __operator_names:
             call_function_locs[start_offset] = (start_index, index)
             start_index = index
             start_offset = offset
 
-    (offset, op, name, argument, argtype, argvalue) = ins_stack[-1]
+    (offset, op, name, argument, argvalue) = ins_stack[-1]
     # Append the index of the last entry to form the last boundary
     call_function_locs[start_offset] = (start_index, len(ins_stack)-1)
 
@@ -212,14 +199,14 @@ def process_frame(frame):
     output_var_names = []
     max_returns = []
     last_func_offset = call_function_locs[last_i][0]
-    (offset, op, name, argument, argtype, argvalue) = ins_stack[last_func_offset + 1]
+    (offset, op, name, argument, argvalue) = ins_stack[last_func_offset + 1]
     if name == 'POP_TOP':  # no return values
         pass
     if name == 'STORE_FAST' or name == 'STORE_NAME': # one return value
         output_var_names.append(argvalue)
     if name == 'UNPACK_SEQUENCE': # Many Return Values, One equal sign
         for index in range(argvalue):
-            (offset_, op_, name_, argument_, argtype_, argvalue_) = ins_stack[last_func_offset + 2 +index]
+            (offset_, op_, name_, argument_, argvalue_) = ins_stack[last_func_offset + 2 +index]
             output_var_names.append(argvalue_)
     max_returns = len(output_var_names)
     if name == 'DUP_TOP': # Many Return Values, Many equal signs
@@ -231,13 +218,13 @@ def process_frame(frame):
         count = 0
         max_returns = 0 # Must count the max_returns ourselves in this case
         while count < len(ins_stack[call_function_locs[i][0]:call_function_locs[i][1]]):
-            (offset_, op_, name_, argument_, argtype_, argvalue_) = ins[call_function_locs[i][0]+count]
+            (offset_, op_, name_, argument_, argvalue_) = ins[call_function_locs[i][0]+count]
             if name_ == 'UNPACK_SEQUENCE': # Many Return Values, One equal sign
                 hold = []
                 if argvalue_ > max_returns:
                     max_returns = argvalue_
                 for index in range(argvalue_):
-                    (_offset_, _op_, _name_, _argument_, _argtype_, _argvalue_) = ins[call_function_locs[i][0] + count+1+index]
+                    (_offset_, _op_, _name_, _argument_, _argvalue_) = ins[call_function_locs[i][0] + count+1+index]
                     hold.append(_argvalue_)
                 count = count + argvalue_
                 output_var_names.append(hold)
diff --git a/Framework/PythonInterface/mantid/kernel/src/Exports/DataItem.cpp b/Framework/PythonInterface/mantid/kernel/src/Exports/DataItem.cpp
index f5d1d6b85361a75aae0ee127a2bfeae4f00ff17e..58cba608d7710d222b9f26de5b27813081aaca61 100644
--- a/Framework/PythonInterface/mantid/kernel/src/Exports/DataItem.cpp
+++ b/Framework/PythonInterface/mantid/kernel/src/Exports/DataItem.cpp
@@ -2,7 +2,9 @@
 #include "MantidKernel/DataItem.h"
 
 #include <boost/python/class.hpp>
+#include <boost/python/copy_const_reference.hpp>
 #include <boost/python/register_ptr_to_python.hpp>
+#include <boost/python/return_value_policy.hpp>
 
 using Mantid::Kernel::DataItem;
 using namespace boost::python;
@@ -14,13 +16,15 @@ void export_DataItem() {
 
   class_<DataItem, boost::noncopyable>("DataItem", no_init)
       .def("id", &DataItem::id, arg("self"), "The string ID of the class")
-      .def("name", &DataItem::name, arg("self"), "The name of the object")
+      .def("name", &DataItem::getName, arg("self"), "The name of the object",
+           return_value_policy<copy_const_reference>())
       .def("threadSafe", &DataItem::threadSafe, arg("self"),
            "Returns true if the object "
            "can be accessed safely from "
            "multiple threads")
-      .def("__str__", &DataItem::name, arg("self"),
-           "Returns the string name of the object if it has been stored")
+      .def("__str__", &DataItem::getName, arg("self"),
+           "Returns the string name of the object if it has been stored",
+           return_value_policy<copy_const_reference>())
       .def("__repr__", &DataItem::toString, arg("self"),
            "Returns a description of the object");
 }
diff --git a/Framework/PythonInterface/mantid/kernel/src/Exports/FacilityInfo.cpp b/Framework/PythonInterface/mantid/kernel/src/Exports/FacilityInfo.cpp
index 907c51778cf610aba31d1a672e6df9a6a320a04e..c1b175e05bef42ed2d80f7443cbb5a4965bdb22f 100644
--- a/Framework/PythonInterface/mantid/kernel/src/Exports/FacilityInfo.cpp
+++ b/Framework/PythonInterface/mantid/kernel/src/Exports/FacilityInfo.cpp
@@ -61,10 +61,6 @@ void export_FacilityInfo() {
            return_value_policy<copy_const_reference>(),
            "Returns the instrument with the given name")
 
-      .def("liveListener", &FacilityInfo::liveListener, arg("self"),
-           return_value_policy<copy_const_reference>(),
-           "Returns the name of the default live listener")
-
       .def("computeResources", &FacilityInfo::computeResources, arg("self"),
            "Returns a vector of the available compute resources");
 }
diff --git a/Framework/PythonInterface/mantid/kernel/src/Exports/IPropertyManager.cpp b/Framework/PythonInterface/mantid/kernel/src/Exports/IPropertyManager.cpp
index b9405b89eb507eb404d6fe833116e096ac4567fd..89ad48a464a106017c125eadb557e080a618ceb1 100644
--- a/Framework/PythonInterface/mantid/kernel/src/Exports/IPropertyManager.cpp
+++ b/Framework/PythonInterface/mantid/kernel/src/Exports/IPropertyManager.cpp
@@ -1,4 +1,5 @@
 #include "MantidKernel/IPropertyManager.h"
+#include "MantidKernel/IPropertySettings.h"
 #include "MantidPythonInterface/kernel/GetPointer.h"
 #include "MantidPythonInterface/kernel/Registry/TypeRegistry.h"
 #include "MantidPythonInterface/kernel/Registry/PropertyValueHandler.h"
diff --git a/Framework/PythonInterface/mantid/kernel/src/Exports/InstrumentInfo.cpp b/Framework/PythonInterface/mantid/kernel/src/Exports/InstrumentInfo.cpp
index d72da5eea64e8dc3adddb0ec6e846008889996a8..d13456c623d141c2fbc2b6a94756be9f653cb8b4 100644
--- a/Framework/PythonInterface/mantid/kernel/src/Exports/InstrumentInfo.cpp
+++ b/Framework/PythonInterface/mantid/kernel/src/Exports/InstrumentInfo.cpp
@@ -1,8 +1,10 @@
 #include "MantidKernel/InstrumentInfo.h"
 #include "MantidKernel/FacilityInfo.h"
 #include "MantidPythonInterface/kernel/StlExportDefinitions.h"
+
 #include <boost/python/class.hpp>
 #include <boost/python/copy_const_reference.hpp>
+#include <boost/python/overloads.hpp>
 
 using Mantid::Kernel::InstrumentInfo;
 using namespace boost::python;
@@ -46,10 +48,36 @@ void export_InstrumentInfo() {
            return_value_policy<copy_const_reference>(),
            "Returns the facility that contains this instrument.")
 
+      .def("liveListener", &InstrumentInfo::liveListener,
+           (arg("self"), arg("name") = ""),
+           "Returns the name of the specific LiveListener class that is used "
+           "by the given connection name. If no name is provided, the default "
+           "connection is used.")
+
+      // Unclear why this is named "instdae", leaving in case legacy req'd
       .def("instdae", &InstrumentInfo::liveDataAddress, arg("self"),
-           return_value_policy<copy_const_reference>(),
            "Returns the host name and the port of the machine hosting DAE and "
            "providing port to connect to for a live data stream")
 
+      .def("liveDataAddress", &InstrumentInfo::liveDataAddress,
+           (arg("self"), arg("name") = ""),
+           "Returns the Address string of a live data connection on this "
+           "instrument. If no connection name is provided, the default "
+           "connection is used.")
+
+      .def("liveListenerInfo", &InstrumentInfo::liveListenerInfo,
+           (arg("self"), arg("name") = ""),
+           return_value_policy<copy_const_reference>(),
+           "Returns a LiveListenerInfo instance for this instrument. If "
+           "no connection name is specified, the default is used.")
+
+      .def("hasLiveListenerInfo", &InstrumentInfo::hasLiveListenerInfo,
+           arg("self"),
+           "Returns true if this instrument has at least one LiveListenerInfo")
+
+      .def("liveListenerInfoList", &InstrumentInfo::liveListenerInfoList,
+           arg("self"), return_value_policy<copy_const_reference>(),
+           "Returns all available LiveListenerInfo instances as a vector")
+
       ;
 }
diff --git a/Framework/PythonInterface/mantid/kernel/src/Exports/LiveListenerInfo.cpp b/Framework/PythonInterface/mantid/kernel/src/Exports/LiveListenerInfo.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c67c230caef303200ed335d1ec1d09d34f331e77
--- /dev/null
+++ b/Framework/PythonInterface/mantid/kernel/src/Exports/LiveListenerInfo.cpp
@@ -0,0 +1,27 @@
+#include "MantidKernel/LiveListenerInfo.h"
+#include "MantidKernel/InstrumentInfo.h"
+#include "MantidPythonInterface/kernel/StlExportDefinitions.h"
+
+#include <boost/python/class.hpp>
+#include <boost/python/copy_const_reference.hpp>
+
+using Mantid::Kernel::LiveListenerInfo;
+using namespace boost::python;
+
+void export_LiveListenerInfo() {
+  using namespace Mantid::PythonInterface;
+  std_vector_exporter<LiveListenerInfo>::wrap("std_vector_LiveListenerInfo");
+
+  class_<LiveListenerInfo>("LiveListenerInfo", no_init)
+      .def("name", &LiveListenerInfo::name, arg("self"),
+           return_value_policy<copy_const_reference>(),
+           "Returns the name of this LiveListener connection")
+
+      .def("address", &LiveListenerInfo::address, arg("self"),
+           return_value_policy<copy_const_reference>(),
+           "Returns the address of this LiveListener connection")
+
+      .def("listener", &LiveListenerInfo::listener, arg("self"),
+           return_value_policy<copy_const_reference>(),
+           "Returns the name of the specific LiveListener class used");
+}
diff --git a/Framework/PythonInterface/mantid/kernel/src/Exports/UnitConversion.cpp b/Framework/PythonInterface/mantid/kernel/src/Exports/UnitConversion.cpp
index f2f7ea98ad5f94a21f9d019ad326588dc0e50232..8027b450a63954212624079bed9b825313198e52 100644
--- a/Framework/PythonInterface/mantid/kernel/src/Exports/UnitConversion.cpp
+++ b/Framework/PythonInterface/mantid/kernel/src/Exports/UnitConversion.cpp
@@ -9,13 +9,13 @@ void export_UnitConversion() {
   // Function pointer typedef
   typedef double (*StringVersion)(
       const std::string &src, const std::string &dest, const double srcValue,
-      const double l1, const double l2, const double twoTheta,
+      const double l1, const double l2, const double theta,
       const DeltaEMode::Type emode, const double efixed);
 
   class_<UnitConversion, boost::noncopyable>("UnitConversion", no_init)
       .def("run", (StringVersion)&UnitConversion::run,
            (arg("src"), arg("dest"), arg("srcValue"), arg("l1"), arg("l2"),
-            arg("twoTheta"), arg("emode"), arg("efixed")),
+            arg("theta"), arg("emode"), arg("efixed")),
            "Performs a unit conversion on a single value.")
       .staticmethod("run");
 }
diff --git a/Framework/PythonInterface/plugins/algorithms/AlignComponents.py b/Framework/PythonInterface/plugins/algorithms/AlignComponents.py
index 576981d32fc526f120137c94a72d84e711bc884f..fda95bd0c683a72d06d32aca40e3f46d5c580070 100644
--- a/Framework/PythonInterface/plugins/algorithms/AlignComponents.py
+++ b/Framework/PythonInterface/plugins/algorithms/AlignComponents.py
@@ -206,7 +206,7 @@ class AlignComponents(PythonAlgorithm):
 
         # Need to get instrument in order to check components are valid
         if self.getProperty("Workspace").value is not None:
-            wks_name = self.getProperty("Workspace").value.getName()
+            wks_name = self.getProperty("Workspace").value.name()
         else:
             inputFilename = self.getProperty("InstrumentFilename").value
             if inputFilename == "":
@@ -254,18 +254,16 @@ class AlignComponents(PythonAlgorithm):
         calWS = api.SortTableWorkspace(calWS, Columns='detid')
         maskWS = self.getProperty("MaskWorkspace").value
 
+        difc = calWS.column('difc')
         if maskWS is not None:
             self._masking = True
             mask = maskWS.extractY().flatten()
-
-        difc = calWS.column('difc')
-        if self._masking:
             difc = np.ma.masked_array(difc, mask)
 
         detID = calWS.column('detid')
 
         if self.getProperty("Workspace").value is not None:
-            wks_name = self.getProperty("Workspace").value.getName()
+            wks_name = self.getProperty("Workspace").value.name()
         else:
             wks_name = "alignedWorkspace"
             api.LoadEmptyInstrument(Filename=self.getProperty("InstrumentFilename").value,
@@ -303,18 +301,11 @@ class AlignComponents(PythonAlgorithm):
                 # Set up x0 and bounds lists
                 x0List = []
                 boundsList = []
-                if self._optionsDict["Xposition"]:
-                    x0List.append(self._initialPos[0])
-                    boundsList.append((self._initialPos[0] + self.getProperty("MinXposition").value,
-                                       self._initialPos[0] + self.getProperty("MaxXposition").value))
-                if self._optionsDict["Yposition"]:
-                    x0List.append(self._initialPos[1])
-                    boundsList.append((self._initialPos[1] + self.getProperty("MinYposition").value,
-                                       self._initialPos[1] + self.getProperty("MaxYposition").value))
-                if self._optionsDict["Zposition"]:
-                    x0List.append(self._initialPos[2])
-                    boundsList.append((self._initialPos[2] + self.getProperty("MinZposition").value,
-                                       self._initialPos[2] + self.getProperty("MaxZposition").value))
+                for iopt,opt in enumerate(self._optionsList[:3]):
+                    if self._optionsDict[opt]:
+                        x0List.append(self._initialPos[iopt])
+                        boundsList.append((self._initialPos[iopt] + self.getProperty("Min"+opt).value,
+                                           self._initialPos[iopt] + self.getProperty("Max"+opt).value))
 
                 results = minimize(self._minimisation_func, x0=x0List,
                                    method='L-BFGS-B',
@@ -347,11 +338,9 @@ class AlignComponents(PythonAlgorithm):
         for opt in self._optionsList:
             self._optionsDict[opt] = self.getProperty(opt).value
 
-        if self._optionsDict["Xposition"] or self._optionsDict["Yposition"] or self._optionsDict["Zposition"]:
-            self._move = True
+        self._move = (self._optionsDict["Xposition"] or self._optionsDict["Yposition"] or self._optionsDict["Zposition"])
 
-        if self._optionsDict["AlphaRotation"] or self._optionsDict["BetaRotation"] or self._optionsDict["GammaRotation"]:
-            self._rotate = True
+        self._rotate = (self._optionsDict["AlphaRotation"] or self._optionsDict["BetaRotation"] or self._optionsDict["GammaRotation"])
 
         prog = Progress(self, start=0, end=1, nreports=len(components))
         for component in components:
@@ -383,30 +372,11 @@ class AlignComponents(PythonAlgorithm):
             else:
                 mask_out = None
 
-            if self._optionsDict["Xposition"]:
-                x0List.append(self._initialPos[0])
-                boundsList.append((self._initialPos[0] + self.getProperty("MinXposition").value,
-                                   self._initialPos[0] + self.getProperty("MaxXposition").value))
-            if self._optionsDict["Yposition"]:
-                x0List.append(self._initialPos[1])
-                boundsList.append((self._initialPos[1] + self.getProperty("MinYposition").value,
-                                   self._initialPos[1] + self.getProperty("MaxYposition").value))
-            if self._optionsDict["Zposition"]:
-                x0List.append(self._initialPos[2])
-                boundsList.append((self._initialPos[2] + self.getProperty("MinZposition").value,
-                                   self._initialPos[2] + self.getProperty("MaxZposition").value))
-            if self._optionsDict["AlphaRotation"]:
-                x0List.append(self._initialPos[3])
-                boundsList.append((self._initialPos[3] + self.getProperty("MinAlphaRotation").value,
-                                   self._initialPos[3] + self.getProperty("MaxAlphaRotation").value))
-            if self._optionsDict["BetaRotation"]:
-                x0List.append(self._initialPos[4])
-                boundsList.append((self._initialPos[4] + self.getProperty("MinBetaRotation").value,
-                                   self._initialPos[4] + self.getProperty("MaxBetaRotation").value))
-            if self._optionsDict["GammaRotation"]:
-                x0List.append(self._initialPos[5])
-                boundsList.append((self._initialPos[5] + self.getProperty("MinGammaRotation").value,
-                                   self._initialPos[5] + self.getProperty("MaxGammaRotation").value))
+            for iopt,opt in enumerate(self._optionsList):
+                if self._optionsDict[opt]:
+                    x0List.append(self._initialPos[iopt])
+                    boundsList.append((self._initialPos[iopt] + self.getProperty("Min"+opt).value,
+                                       self._initialPos[iopt] + self.getProperty("Max"+opt).value))
 
             results = minimize(self._minimisation_func, x0=x0List,
                                method='L-BFGS-B',
diff --git a/Framework/PythonInterface/plugins/algorithms/AngularAutoCorrelationsTwoAxes.py b/Framework/PythonInterface/plugins/algorithms/AngularAutoCorrelationsTwoAxes.py
index 7177bd93d33e151c468fc20c1c92127c95110e90..4ce5753eb67eaa551bbf4ab4195b25c872b06d99 100644
--- a/Framework/PythonInterface/plugins/algorithms/AngularAutoCorrelationsTwoAxes.py
+++ b/Framework/PythonInterface/plugins/algorithms/AngularAutoCorrelationsTwoAxes.py
@@ -39,9 +39,9 @@ class AngularAutoCorrelationsTwoAxes(PythonAlgorithm):
         file_name=self.getPropertyValue("InputFile")
 
         # Get the user-specified species
-        type1=self.getPropertyValue("SpeciesOne")
-        type2=self.getPropertyValue("SpeciesTwo")
-        type3=self.getPropertyValue("SpeciesThree")
+        types=[self.getPropertyValue("SpeciesOne").lower(),
+               self.getPropertyValue("SpeciesTwo").lower(),
+               self.getPropertyValue("SpeciesThree").lower()]
 
         # Load trajectory file
         trajectory=netcdf.netcdf_file(file_name,mode="r")
@@ -82,12 +82,9 @@ class AngularAutoCorrelationsTwoAxes(PythonAlgorithm):
             atoms_to_species[key]=str(element)
 
         # Check wether user-specified species present in the trajectory file
-        if type1.lower() not in elements:
-            raise RuntimeError('Species one not found in the trajectory file. Please try again...')
-        if type2.lower() not in elements:
-            raise RuntimeError('Species two not found in the trajectory file. Please try again...')
-        if type3.lower() not in elements:
-            raise RuntimeError('Species three not found in the trajectory file. Please try again...')
+        for i in range(3):
+            if types[i] not in elements:
+                raise RuntimeError('Species '+['one','two','three'][i]+' not found in the trajectory file. Please try again...')
 
         # Initialise lists in the species_to_particles dictionary
         for j in elements:
@@ -177,11 +174,11 @@ class AngularAutoCorrelationsTwoAxes(PythonAlgorithm):
             species_two=[]
             species_three=[]
             for j in temp:
-                if atoms_to_species[j]==type1.lower():
+                if atoms_to_species[j]==types[0]:
                     species_one.append(j)
-                if atoms_to_species[j]==type2.lower():
+                if atoms_to_species[j]==types[1]:
                     species_two.append(j)
-                if atoms_to_species[j]==type3.lower():
+                if atoms_to_species[j]==types[2]:
                     species_three.append(j)
             # Find the average positions of species one and two
             sum_position_species_one=np.zeros((n_timesteps,n_dimensions))
diff --git a/Framework/PythonInterface/plugins/algorithms/BinWidthAtX.py b/Framework/PythonInterface/plugins/algorithms/BinWidthAtX.py
new file mode 100644
index 0000000000000000000000000000000000000000..a16a9ce75f0dd02d95127fa62cda21005de4c42f
--- /dev/null
+++ b/Framework/PythonInterface/plugins/algorithms/BinWidthAtX.py
@@ -0,0 +1,86 @@
+from __future__ import (absolute_import, division, print_function)
+
+from mantid.api import AlgorithmFactory, HistogramValidator,\
+    MatrixWorkspaceProperty, PythonAlgorithm
+from mantid.kernel import Direction
+import numpy
+import roundinghelper
+
+
+class BinWidthAtX(PythonAlgorithm):
+
+    _PROP_BIN_WIDTH = 'BinWidth'
+    _PROP_INPUT_WS = 'InputWorkspace'
+    _PROP_X_VALUE = 'X'
+
+    def category(self):
+        '''
+        Return algorithm's category.
+        '''
+        return 'Utility\\Calculation'
+
+    def name(self):
+        '''
+        Return algorithm's name.
+        '''
+        return 'BinWidthAtX'
+
+    def summary(self):
+        '''
+        Return algorithm's summary.
+        '''
+        return 'Calculates the bin width at X, averaged over all histograms.'
+
+    def version(self):
+        '''
+        Return algorithm's version.
+        '''
+        return 1
+
+    def PyInit(self):
+        '''
+        Declares algorithm's properties.
+        '''
+        self.declareProperty(
+            MatrixWorkspaceProperty(name=self._PROP_INPUT_WS,
+                                    defaultValue='',
+                                    validator=HistogramValidator(),
+                                    direction=Direction.Input),
+            doc='A workspace containing the input histograms')
+        self.declareProperty(
+            name=self._PROP_X_VALUE, defaultValue=0.0,
+            direction=Direction.Input, doc='The x value of the bin to use.')
+        roundinghelper.declare_rounding_property(self)
+        self.declareProperty(
+            name=self._PROP_BIN_WIDTH, defaultValue=0.0,
+            direction=Direction.Output, doc='The averaged bin width')
+
+    def PyExec(self):
+        '''
+        Averages the bin widths at X.
+        '''
+        inputWs = self.getProperty(self._PROP_INPUT_WS).value
+        x = self.getProperty(self._PROP_X_VALUE).value
+        roundingMode = self.getProperty(
+            roundinghelper.PROP_NAME_ROUNDING_MODE).value
+        n = inputWs.getNumberHistograms()
+        widths = numpy.empty(n)
+        for wsIndex in range(n):
+            xs = inputWs.readX(wsIndex)
+            lowerBound = xs[0]
+            upperBound = xs[-1]
+            if lowerBound > upperBound:
+                lowerBound, upperBound = upperBound, lowerBound
+            if x <= lowerBound or x > upperBound:
+                raise RuntimeError(
+                    self._PROP_X_VALUE +
+                    ' = {0} out of range for workspace index {1}'
+                    .format(x, wsIndex))
+            binIndex = inputWs.binIndexOf(x, wsIndex)
+            dx = xs[binIndex + 1] - xs[binIndex]
+            widths[wsIndex] = dx
+        binWidth = numpy.mean(widths)
+        binWidth = roundinghelper.round(binWidth, roundingMode)
+        self.setProperty(self._PROP_BIN_WIDTH, numpy.abs(binWidth))
+
+AlgorithmFactory.subscribe(BinWidthAtX)
diff --git a/Framework/PythonInterface/plugins/algorithms/CalibrateRectangularDetectors.py b/Framework/PythonInterface/plugins/algorithms/CalibrateRectangularDetectors.py
index cdc4acc40aadfc5bcd5b0cea0a4ece3fc48cab17..a0398453361f1bc970c4da016e07cf457d13b97a 100644
--- a/Framework/PythonInterface/plugins/algorithms/CalibrateRectangularDetectors.py
+++ b/Framework/PythonInterface/plugins/algorithms/CalibrateRectangularDetectors.py
@@ -385,6 +385,37 @@ class CalibrateRectangularDetectors(PythonAlgorithm):
         wksp = Rebin(InputWorkspace=wksp, OutputWorkspace=wksp.name(), Params=self._binning)
         return wksp
 
+    def _initCCpars(self):
+        self._peakpos1 = self._peakpos[0]
+        self._peakpos2 = 0
+        self._peakpos3 = 0
+        self._lastpixel = 0
+        self._lastpixel2 = 0
+        self._lastpixel3 = 0
+        peakhalfwidth = self.getProperty("PeakHalfWidth").value
+        self._peakmin = self._peakpos1-peakhalfwidth
+        self._peakmax = self._peakpos1+peakhalfwidth
+        if len(self._peakpos) >= 2:
+            self._peakpos2 = self._peakpos[1]
+            self._peakmin2 = self._peakpos2-peakhalfwidth
+            self._peakmax2 = self._peakpos2+peakhalfwidth
+        if len(self._peakpos) >= 3:
+            self._peakpos3 = self._peakpos[2]
+            self._peakmin3 = self._peakpos3-peakhalfwidth
+            self._peakmax3 = self._peakpos3+peakhalfwidth
+        detectors = self.getProperty("DetectorsPeaks").value
+        if len(detectors) == 0:
+            detectors = [0]
+        if detectors[0]:
+            self._lastpixel = int(detectors[0])
+            self._lastpixel3 = self._lastpixel
+        if len(detectors) >= 2:
+            self._lastpixel2 = self._lastpixel+int(detectors[1])
+            self._lastpixel3 = self._lastpixel2
+        if len(detectors) >= 3:
+            self._lastpixel3 = self._lastpixel2+int(detectors[2])
+        self._ccnumber = self.getProperty("CrossCorrelationPoints").value
+
     #pylint: disable=too-many-branches
     def PyExec(self):
         # get generic information
@@ -401,35 +432,7 @@ class CalibrateRectangularDetectors(PythonAlgorithm):
         self._smoothGroups = self.getProperty("SmoothGroups").value
         self._peakpos = self.getProperty("PeakPositions").value
         if self.getProperty("CrossCorrelation").value:
-            self._peakpos1 = self._peakpos[0]
-            self._peakpos2 = 0
-            self._peakpos3 = 0
-            self._lastpixel = 0
-            self._lastpixel2 = 0
-            self._lastpixel3 = 0
-            peakhalfwidth = self.getProperty("PeakHalfWidth").value
-            self._peakmin = self._peakpos1-peakhalfwidth
-            self._peakmax = self._peakpos1+peakhalfwidth
-            if len(self._peakpos) >= 2:
-                self._peakpos2 = self._peakpos[1]
-                self._peakmin2 = self._peakpos2-peakhalfwidth
-                self._peakmax2 = self._peakpos2+peakhalfwidth
-            if len(self._peakpos) >= 3:
-                self._peakpos3 = self._peakpos[2]
-                self._peakmin3 = self._peakpos3-peakhalfwidth
-                self._peakmax3 = self._peakpos3+peakhalfwidth
-            detectors = self.getProperty("DetectorsPeaks").value
-            if len(detectors) == 0:
-                detectors = [0]
-            if detectors[0]:
-                self._lastpixel = int(detectors[0])
-                self._lastpixel3 = self._lastpixel
-            if len(detectors) >= 2:
-                self._lastpixel2 = self._lastpixel+int(detectors[1])
-                self._lastpixel3 = self._lastpixel2
-            if len(detectors) >= 3:
-                self._lastpixel3 = self._lastpixel2+int(detectors[2])
-            self._ccnumber = self.getProperty("CrossCorrelationPoints").value
+            self._initCCpars()
         self._maxoffset = self.getProperty("MaxOffset").value
         self._diffractionfocus = self.getProperty("DiffractionFocusWorkspace").value
         self._filterBadPulses = self.getProperty("FilterBadPulses").value
@@ -467,12 +470,12 @@ class CalibrateRectangularDetectors(PythonAlgorithm):
 
             LRef = self.getProperty("UnwrapRef").value
             DIFCref = self.getProperty("LowResRef").value
-            if (LRef > 0.) or (DIFCref > 0.): # super special Jason stuff
-                if LRef > 0:
-                    UnwrapSNS(InputWorkspace=samRun, OutputWorkspace=samRun, LRef=LRef)
-                if DIFCref > 0:
-                    RemoveLowResTOF(InputWorkspace=samRun, OutputWorkspace=samRun,
-                                    ReferenceDIFC=DIFCref)
+            # super special Jason stuff
+            if LRef > 0:
+                UnwrapSNS(InputWorkspace=samRun, OutputWorkspace=samRun, LRef=LRef)
+            if DIFCref > 0:
+                RemoveLowResTOF(InputWorkspace=samRun, OutputWorkspace=samRun,
+                                ReferenceDIFC=DIFCref)
 
             ConvertUnits(InputWorkspace=samRun, OutputWorkspace=samRun, Target="dSpacing")
 
@@ -494,13 +497,13 @@ class CalibrateRectangularDetectors(PythonAlgorithm):
                 samRun = self._loadData(samNum, filterWall)
                 LRef = self.getProperty("UnwrapRef").value
                 DIFCref = self.getProperty("LowResRef").value
-                if (LRef > 0.) or (DIFCref > 0.): # super special Jason stuff
-                    if LRef > 0:
-                        samRun = UnwrapSNS(InputWorkspace=samRun, OutputWorkspace=samRun,
-                                           LRef=LRef)
-                    if DIFCref > 0:
-                        samRun = RemoveLowResTOF(InputWorkspace=samRun, OutputWorkspace=samRun,
-                                                 ReferenceDIFC=DIFCref)
+                # super special Jason stuff
+                if LRef > 0:
+                    samRun = UnwrapSNS(InputWorkspace=samRun, OutputWorkspace=samRun,
+                                       LRef=LRef)
+                if DIFCref > 0:
+                    samRun = RemoveLowResTOF(InputWorkspace=samRun, OutputWorkspace=samRun,
+                                             ReferenceDIFC=DIFCref)
             else:
                 samRun = ConvertUnits(InputWorkspace=samRun, OutputWorkspace=samRun,
                                       Target="TOF")
diff --git a/Framework/PythonInterface/plugins/algorithms/CollectHB3AExperimentInfo.py b/Framework/PythonInterface/plugins/algorithms/CollectHB3AExperimentInfo.py
index 094213968ef0dcc86767a301bda4a619e5fd7f12..2ee26e43abc642dabc6acc4276bb8b6ae48d5b82 100644
--- a/Framework/PythonInterface/plugins/algorithms/CollectHB3AExperimentInfo.py
+++ b/Framework/PythonInterface/plugins/algorithms/CollectHB3AExperimentInfo.py
@@ -326,7 +326,7 @@ class CollectHB3AExperimentInfo(PythonAlgorithm):
                     dataws = self._loadHB3ADetCountFile(scannumber, ptnumber)
 
                     # write each detector's position and ID to table workspace
-                    maxdetid = 0
+                    maxdetid = -1
                     for iws in range(dataws.getNumberHistograms()):
                         detector = dataws.getDetector(iws)
                         detpos = detector.getPos()
diff --git a/Framework/PythonInterface/plugins/algorithms/ComputeCalibrationCoefVan.py b/Framework/PythonInterface/plugins/algorithms/ComputeCalibrationCoefVan.py
index 905ef1818e5378073963ac722f9fcbfa197b2df6..afd3e072fc0bfade66fce29a398303ff158b21d5 100644
--- a/Framework/PythonInterface/plugins/algorithms/ComputeCalibrationCoefVan.py
+++ b/Framework/PythonInterface/plugins/algorithms/ComputeCalibrationCoefVan.py
@@ -1,14 +1,17 @@
 from __future__ import (absolute_import, division, print_function)
 
-from mantid.api import PythonAlgorithm, AlgorithmFactory, MatrixWorkspaceProperty, Progress, InstrumentValidator, ITableWorkspaceProperty
-from mantid.kernel import Direction
+from mantid.api import (PythonAlgorithm, AlgorithmFactory,
+                        MatrixWorkspaceProperty, Progress, InstrumentValidator,
+                        ITableWorkspaceProperty)
+from mantid.kernel import Direction, FloatBoundedValidator, Property
 import numpy as np
 from scipy import integrate
 import scipy as sp
 
 
 class ComputeCalibrationCoefVan(PythonAlgorithm):
-    """ Calculate coefficients to normalize by Vanadium and correct Debye Waller factor
+    """ Calculate coefficients to normalize by Vanadium and correct Debye
+        Waller factor
     """
 
     def __init__(self):
@@ -32,36 +35,56 @@ class ComputeCalibrationCoefVan(PythonAlgorithm):
         return "ComputeCalibrationCoefVan"
 
     def summary(self):
-        return "Calculate coefficients for detector efficiency correction using the Vanadium data."
+        return ("Calculate coefficients for detector efficiency correction " +
+                "using the Vanadium data.")
 
     def PyInit(self):
         """ Declare properties
         """
-        self.declareProperty(MatrixWorkspaceProperty("VanadiumWorkspace", "", direction=Direction.Input,
-                                                     validator=InstrumentValidator()),
+        self.declareProperty(MatrixWorkspaceProperty(
+                             "VanadiumWorkspace", "",
+                             direction=Direction.Input,
+                             validator=InstrumentValidator()),
                              "Input Vanadium workspace")
-        self.declareProperty(ITableWorkspaceProperty("EPPTable", "", direction=Direction.Input),
-                             "Input EPP table. May be produced by FindEPP algorithm.")
-        self.declareProperty(MatrixWorkspaceProperty("OutputWorkspace", "", direction=Direction.Output),
-                             "Name the workspace that will contain the calibration coefficients")
+        self.declareProperty(ITableWorkspaceProperty("EPPTable", "",
+                             direction=Direction.Input),
+                             ("Input EPP table. May be produced by FindEPP " +
+                              "algorithm."))
+        self.declareProperty(MatrixWorkspaceProperty("OutputWorkspace", "",
+                             direction=Direction.Output),
+                             ("Name the workspace that will contain the " +
+                              "calibration coefficients"))
+        self.declareProperty("Temperature",
+                             defaultValue=Property.EMPTY_DBL,
+                             validator=FloatBoundedValidator(lower=0.0),
+                             direction=Direction.Input,
+                             doc=("Temperature during the experiment (in " +
+                                  "Kelvins) if the 'temperature' sample log " +
+                                  "is missing or needs to be overriden."))
         return
 
     def validateInputs(self):
+        """ Validate the inputs
+        """
         issues = dict()
         inws = self.getProperty("VanadiumWorkspace").value
         run = inws.getRun()
 
         if not run.hasProperty('wavelength'):
-            issues['VanadiumWorkspace'] = "Input workspace must have wavelength sample log."
+            issues['VanadiumWorkspace'] = ("Input workspace must have " +
+                                           "wavelength sample log.")
         else:
             try:
                 float(run.getProperty('wavelength').value)
             except ValueError:
-                issues['VanadiumWorkspace'] = "Invalid value for wavelength sample log. Wavelength must be a number."
+                issues['VanadiumWorkspace'] = ("Invalid value for " +
+                                               "wavelength sample log. " +
+                                               "Wavelength must be a number.")
 
         table = self.getProperty("EPPTable").value
         if table.rowCount() != inws.getNumberHistograms():
-            issues['EPPTable'] = "Number of rows in the table must match to the input workspace dimension."
+            issues['EPPTable'] = ("Number of rows in the table must match " +
+                                  "to the input workspace dimension.")
         # table must have 'PeakCentre' and 'Sigma' columns
         if 'PeakCentre' not in table.getColumnNames():
             issues['EPPTable'] = "EPP Table must have the PeakCentre column."
@@ -71,20 +94,23 @@ class ComputeCalibrationCoefVan(PythonAlgorithm):
         return issues
 
     def get_temperature(self):
+        """Return the temperature
         """
-        tries to get temperature from the sample logs
-        in the case of fail, default value is returned
-        """
+        if not self.getProperty("Temperature").isDefault:
+            return self.getProperty("Temperature").value
         run = self.vanaws.getRun()
         if not run.hasProperty('temperature'):
-            self.log().warning("Temperature sample log is not present in " + self.vanaws.getName() +
+            self.log().warning("No Temperature given and the 'temperature' " +
+                               "sample log is not present in " +
+                               self.vanaws.name() +
                                " T=293K is assumed for Debye-Waller factor.")
             return self.defaultT
         try:
             temperature = float(run.getProperty('temperature').value)
         except ValueError as err:
-            self.log().warning("Error of getting temperature: " + err +
-                               " T=293K is assumed for Debye-Waller factor.")
+            self.log().warning("Error of getting temperature from the " +
+                               "sample log " + err + " T=293K is assumed " +
+                               "for Debye-Waller factor.")
             return self.defaultT
 
         return temperature
@@ -93,8 +119,10 @@ class ComputeCalibrationCoefVan(PythonAlgorithm):
         """ Main execution body
         """
 
-        self.vanaws = self.getProperty("VanadiumWorkspace").value       # returns workspace instance
-        outws_name = self.getPropertyValue("OutputWorkspace")           # returns workspace name (string)
+        # returns workspace instance
+        self.vanaws = self.getProperty("VanadiumWorkspace").value
+        # returns workspace name (string)
+        outws_name = self.getPropertyValue("OutputWorkspace")
         eppws = self.getProperty("EPPTable").value
         nhist = self.vanaws.getNumberHistograms()
         prog_reporter = Progress(self, start=0.0, end=1.0, nreports=nhist+1)
@@ -107,16 +135,14 @@ class ComputeCalibrationCoefVan(PythonAlgorithm):
         dataX = self.vanaws.readX(0)
         coefY = np.zeros(nhist)
         coefE = np.zeros(nhist)
-        instrument = self.vanaws.getInstrument()
-        detID_offset = self.get_detID_offset()
         peak_centre = eppws.column('PeakCentre')
         sigma = eppws.column('Sigma')
 
+        specInfo = self.vanaws.spectrumInfo()
         for idx in range(nhist):
             prog_reporter.report("Setting %dth spectrum" % idx)
             dataY = self.vanaws.readY(idx)
-            det = instrument.getDetector(idx + detID_offset)
-            if np.max(dataY) == 0 or det.isMasked():
+            if np.max(dataY) == 0 or specInfo.isMasked(idx):
                 coefY[idx] = 0.
                 coefE[idx] = 0.
             else:
@@ -125,7 +151,8 @@ class ComputeCalibrationCoefVan(PythonAlgorithm):
                 idxmin = (np.fabs(dataX-peak_centre[idx]+3.*fwhm)).argmin()
                 idxmax = (np.fabs(dataX-peak_centre[idx]-3.*fwhm)).argmin()
                 coefY[idx] = dwf[idx]*sum(dataY[idxmin:idxmax+1])
-                coefE[idx] = dwf[idx]*sum(dataE[idxmin:idxmax+1])
+                coefE[idx] = dwf[idx]*np.sqrt(sum(
+                    np.square(dataE[idxmin:idxmax+1])))
 
         # create X array, X data are the same for all detectors, so
         coefX = np.zeros(nhist)
@@ -164,20 +191,25 @@ class ComputeCalibrationCoefVan(PythonAlgorithm):
 
         for i in range(nhist):
             det = instrument.getDetector(i + detID_offset)
-            thetasort[i] = 0.5*np.sign(np.cos(det.getPhi()))*self.vanaws.detectorTwoTheta(det)
-            # thetasort[i] = 0.5*self.vanaws.detectorSignedTwoTheta(det) # gives opposite sign for detectors 0-24
-
-        temperature = self.get_temperature()                    # T in K
-        wlength = float(run.getLogData('wavelength').value)     # Wavelength, Angstrom
-        mass_vana = 0.001*self.Mvan/sp.constants.N_A            # Vanadium mass, kg
+            thetasort[i] = 0.5 * np.sign(np.cos(det.getPhi())) * \
+                self.vanaws.detectorTwoTheta(det)
+
+        # T in K
+        temperature = self.get_temperature()
+        # Wavelength, Angstrom
+        wlength = float(run.getLogData('wavelength').value)
+        # Vanadium mass, kg
+        mass_vana = 0.001*self.Mvan/sp.constants.N_A
         temp_ratio = temperature/self.DebyeT
 
         if temp_ratio < 1.e-3:
             integral = 0.5
         else:
-            integral = integrate.quad(lambda x: x/sp.tanh(0.5*x/temp_ratio), 0, 1)[0]
+            integral = \
+                integrate.quad(lambda x: x/sp.tanh(0.5*x/temp_ratio), 0, 1)[0]
 
-        msd = 3.*sp.constants.hbar**2/(2.*mass_vana*sp.constants.k * self.DebyeT)*integral*1.e20
+        msd = 3.*sp.constants.hbar**2 / \
+            (2.*mass_vana*sp.constants.k * self.DebyeT)*integral*1.e20
         return np.exp(-msd*(4.*sp.pi*sp.sin(thetasort)/wlength)**2)
 
 
diff --git a/Framework/PythonInterface/plugins/algorithms/ComputeIncoherentDOS.py b/Framework/PythonInterface/plugins/algorithms/ComputeIncoherentDOS.py
index 22a37db34ac813da369f3fb18ac5de30a6bc5153..0dc371067f2725218970fa4401ffb8d9dc7774e6 100644
--- a/Framework/PythonInterface/plugins/algorithms/ComputeIncoherentDOS.py
+++ b/Framework/PythonInterface/plugins/algorithms/ComputeIncoherentDOS.py
@@ -44,7 +44,8 @@ class ComputeIncoherentDOS(PythonAlgorithm):
         return 'ComputeIncoherentDOS'
 
     def summary(self):
-        return 'Calculates the neutron weighted generalised phonon density of states in the incoherent approximation from a measured powder INS MatrixWorkspace'
+        return 'Calculates the neutron weighted generalised phonon density of states '+\
+               'in the incoherent approximation from a measured powder INS MatrixWorkspace'
 
     def PyInit(self):
         validators = CompositeValidator()
diff --git a/Framework/PythonInterface/plugins/algorithms/DNSComputeDetEffCorrCoefs.py b/Framework/PythonInterface/plugins/algorithms/DNSComputeDetEffCorrCoefs.py
index 30d4332df42d0bd76b02231df9baf8452e3a233c..502bcb5886670ab19f6a9f329ada3310df4ce14d 100644
--- a/Framework/PythonInterface/plugins/algorithms/DNSComputeDetEffCorrCoefs.py
+++ b/Framework/PythonInterface/plugins/algorithms/DNSComputeDetEffCorrCoefs.py
@@ -168,11 +168,9 @@ class DNSComputeDetEffCorrCoefs(PythonAlgorithm):
         returns number of not masked detectors
         """
         num = 0
-        instrument = workspace.getInstrument()
-        offset = workspace.getSpectrum(0).getDetectorIDs()[0]
+        spectrumInfo = workspace.spectrumInfo()
         for idx in range(workspace.getNumberHistograms()):
-            det = instrument.getDetector(idx + offset)        # for DNS first det ID=1
-            if not det.isMasked():
+            if not spectrumInfo.isMasked(idx):
                 num += 1
         return num
 
@@ -215,13 +213,13 @@ class DNSComputeDetEffCorrCoefs(PythonAlgorithm):
 
         # compute vmean
         _mean_ws_ = api.Mean(",".join(list(total.values())))     # Mean takes string
-        self.toremove.append(_mean_ws_.getName())
+        self.toremove.append(_mean_ws_.name())
         num =  self._get_notmasked_detectors_number(_mean_ws_)
         if num == 0:
             self.cleanup(self.toremove)
             raise RuntimeError("All detectors are masked! Cannot compute coefficients.")
         _vana_mean_ = api.SumSpectra(_mean_ws_)/num
-        self.toremove.append(_vana_mean_.getName())
+        self.toremove.append(_vana_mean_.name())
 
         # compute coefficients k_i = (VSF_i + VNSF_i)/Vmean
         outws_name = self.getPropertyValue("OutputWorkspace")
diff --git a/Framework/PythonInterface/plugins/algorithms/DNSFlippingRatioCorr.py b/Framework/PythonInterface/plugins/algorithms/DNSFlippingRatioCorr.py
index 186c51d7a9f5902c5a5fc33a85f42d04c5b64ff3..8fb0a436f7f504abab1645550a659d9b7b2c507c 100644
--- a/Framework/PythonInterface/plugins/algorithms/DNSFlippingRatioCorr.py
+++ b/Framework/PythonInterface/plugins/algorithms/DNSFlippingRatioCorr.py
@@ -75,7 +75,7 @@ class DNSFlippingRatioCorr(PythonAlgorithm):
             wks = api.AnalysisDataService.retrieve(self.input_workspaces[key])
             run = wks.getRun()
             if not run.hasProperty('flipper'):
-                message = "Workspace " + wks.getName() + " does not have flipper sample log!"
+                message = "Workspace " + wks.name() + " does not have flipper sample log!"
                 self.log().error(message)
                 raise RuntimeError(message)
             flipper = run.getProperty('flipper').value
@@ -84,7 +84,7 @@ class DNSFlippingRatioCorr(PythonAlgorithm):
             else:
                 needed = 'ON'
             if flipper != needed:
-                message = "Workspace " + wks.getName() + " must have flipper " + needed + ", but it is " + flipper
+                message = "Workspace " + wks.name() + " must have flipper " + needed + ", but it is " + flipper
                 self.log().error(message)
                 raise RuntimeError(message)
 
@@ -136,9 +136,9 @@ class DNSFlippingRatioCorr(PythonAlgorithm):
 
         # 2. subtract background from NiCr
         _sf_nicr_bg_ = sf_nicr - sf_bkgr
-        wslist.append(_sf_nicr_bg_.getName())
+        wslist.append(_sf_nicr_bg_.name())
         _nsf_nicr_bg_ = nsf_nicr - nsf_bkgr
-        wslist.append(_nsf_nicr_bg_.getName())
+        wslist.append(_nsf_nicr_bg_.name())
         # check negative values, throw exception
         sf_arr = np.array(_sf_nicr_bg_.extractY()).flatten()
         nsf_arr = np.array(_nsf_nicr_bg_.extractY()).flatten()
@@ -152,13 +152,13 @@ class DNSFlippingRatioCorr(PythonAlgorithm):
 
         # 3. calculate flipping ratio F - 1 = (NiCr - Bkg)NSF/(NiCr - Bkg)SF - 1
         _coef_ws_ = api.Divide(LHSWorkspace=_nsf_nicr_bg_, RHSWorkspace=_sf_nicr_bg_, WarnOnZeroDivide=True) - 1.0
-        wslist.append(_coef_ws_.getName())
+        wslist.append(_coef_ws_.name())
         # 4. apply correction raw data
         sf_data_ws = api.AnalysisDataService.retrieve(self.input_workspaces['SF_Data'])
         nsf_data_ws = api.AnalysisDataService.retrieve(self.input_workspaces['NSF_Data'])
         # NSF_corr[i] = NSF[i] + (NSF[i] - SF[i])/(F[i] - 1)
         _diff_ws_ = nsf_data_ws - sf_data_ws
-        wslist.append(_diff_ws_.getName())
+        wslist.append(_diff_ws_.name())
         _tmp_ws_ = api.Divide(LHSWorkspace=_diff_ws_, RHSWorkspace=_coef_ws_, WarnOnZeroDivide=True)
         _tmp_ws_.setYUnit(nsf_data_ws.YUnit())
         api.Plus(LHSWorkspace=nsf_data_ws, RHSWorkspace=_tmp_ws_, OutputWorkspace=self.nsf_outws_name)
diff --git a/Framework/PythonInterface/plugins/algorithms/DakotaChiSquared.py b/Framework/PythonInterface/plugins/algorithms/DakotaChiSquared.py
index 4f5fbe6807399bdf01e903064e1874bbf686f18b..852607a5bc1a495034e796d8886a0c6d2757ab5f 100644
--- a/Framework/PythonInterface/plugins/algorithms/DakotaChiSquared.py
+++ b/Framework/PythonInterface/plugins/algorithms/DakotaChiSquared.py
@@ -82,10 +82,10 @@ class DakotaChiSquared(PythonAlgorithm):
         self.setProperty("ChiSquared",chisquared)
 
             #cleanup
-        mantid.simpleapi.DeleteWorkspace(__w1.getName())
-        mantid.simpleapi.DeleteWorkspace(__w2.getName())
-        mantid.simpleapi.DeleteWorkspace(__soe2.getName())
+        mantid.simpleapi.DeleteWorkspace(__w1.name())
+        mantid.simpleapi.DeleteWorkspace(__w2.name())
+        mantid.simpleapi.DeleteWorkspace(__soe2.name())
         if len(soeName)==0:
-            mantid.simpleapi.DeleteWorkspace(__soe.getName())
+            mantid.simpleapi.DeleteWorkspace(__soe.name())
 
 AlgorithmFactory.subscribe(DakotaChiSquared)
diff --git a/Framework/PythonInterface/plugins/algorithms/EnggFitPeaks.py b/Framework/PythonInterface/plugins/algorithms/EnggFitPeaks.py
index 4630e5e4d6d4876668af6741b591c0c454f197ce..56098e9e38e3106032fdb9e7ee042ef93bbf585a 100644
--- a/Framework/PythonInterface/plugins/algorithms/EnggFitPeaks.py
+++ b/Framework/PythonInterface/plugins/algorithms/EnggFitPeaks.py
@@ -66,7 +66,7 @@ class EnggFitPeaks(PythonAlgorithm):
 
         # Get expected peaks in TOF for the detector
         in_wks = self.getProperty("InputWorkspace").value
-        dimType = in_wks.getXDimension().getName()
+        dimType = in_wks.getXDimension().name
         if self.EXPECTED_DIM_TYPE != dimType:
             raise ValueError("This algorithm expects a workspace with %s X dimension, but "
                              "the X dimension of the input workspace is: '%s'" % (self.EXPECTED_DIM_TYPE, dimType))
@@ -306,10 +306,10 @@ class EnggFitPeaks(PythonAlgorithm):
         run = in_wks.getRun()
         if 1 == in_wks.getNumberHistograms() and run.hasProperty('difc'):
             difc = run.getLogData('difc').value
-            if run.hasProperty('difa'):
-                _difa = run.getLogData('difa').value
-            else:
-                _difa = 0
+            #if run.hasProperty('difa'):
+            #    _difa = run.getLogData('difa').value
+            #else:
+            #    _difa = 0
             if run.hasProperty('tzero'):
                 tzero = run.getLogData('tzero').value
             else:
diff --git a/Framework/PythonInterface/plugins/algorithms/EnggVanadiumCorrections.py b/Framework/PythonInterface/plugins/algorithms/EnggVanadiumCorrections.py
index 96e05c8282c09f4e4987f83675a3a8d6b67dc82f..aeb973f2ef6a5fae4be062d7c20d76d74a99c780 100644
--- a/Framework/PythonInterface/plugins/algorithms/EnggVanadiumCorrections.py
+++ b/Framework/PythonInterface/plugins/algorithms/EnggVanadiumCorrections.py
@@ -193,7 +193,7 @@ class EnggVanadiumCorrections(PythonAlgorithm):
         with one row per spectrum
         """
         expectedDim = 'Time-of-flight'
-        dimType = vanWS.getXDimension().getName()
+        dimType = vanWS.getXDimension().name
         if expectedDim != dimType:
             raise ValueError("This algorithm expects a workspace with %s X dimension, but "
                              "the X dimension of the input workspace is: '%s'" % (expectedDim, dimType))
@@ -256,7 +256,7 @@ class EnggVanadiumCorrections(PythonAlgorithm):
         workspace, and the Y values simulated from the fitted curve
         """
         expectedDim = 'd-Spacing'
-        dimType = vanWS.getXDimension().getName()
+        dimType = vanWS.getXDimension().name
         if expectedDim != dimType:
             raise ValueError("This algorithm expects a workspace with %s X dimension, but "
                              "the X dimension of the input workspace is: '%s'" % (expectedDim, dimType))
diff --git a/Framework/PythonInterface/plugins/algorithms/ExportSpectraMask.py b/Framework/PythonInterface/plugins/algorithms/ExportSpectraMask.py
index 33c24ca00b31e842829198e2d9ea31e33166de4e..69310ca255d518d027b0690d75a58c8ccfc724d7 100644
--- a/Framework/PythonInterface/plugins/algorithms/ExportSpectraMask.py
+++ b/Framework/PythonInterface/plugins/algorithms/ExportSpectraMask.py
@@ -28,11 +28,12 @@ def export_masks(ws,fileName='',returnMasksOnly=False):
     else:
         pws = ws
 
-    ws_name=pws.getName()
+    ws_name=pws.name()
     nhist = pws.getNumberHistograms()
 
     no_detectors = 0
     masks = []
+    specInfo = pws.spectrumInfo()
     for i in range(nhist):
         # set provisional spectra ID
         ms = i+1
@@ -46,14 +47,13 @@ def export_masks(ws,fileName='',returnMasksOnly=False):
             masks.append(ms)
             continue
         try:
-            det = pws.getDetector(i)
+            if specInfo.isMasked(i):
+                masks.append(ms)
 #pylint: disable=W0703
         except Exception:
             no_detectors = no_detectors +1
             masks.append(ms)
             continue
-        if det.isMasked():
-            masks.append(ms)
 
     filename=''
     if len(fileName)==0 :
diff --git a/Framework/PythonInterface/plugins/algorithms/ExtractMonitors.py b/Framework/PythonInterface/plugins/algorithms/ExtractMonitors.py
index feb6cb70d5db1439c56caef78e9a2b9b0c5b7a40..4f6a81f2c62c303647683c1e0dd17bdbb99962aa 100644
--- a/Framework/PythonInterface/plugins/algorithms/ExtractMonitors.py
+++ b/Framework/PythonInterface/plugins/algorithms/ExtractMonitors.py
@@ -56,34 +56,35 @@ class ExtractMonitors(DataProcessorAlgorithm):
 
         monitors = []
         detectors = []
+        spectrumInfo = in_ws.spectrumInfo()
         for i in range(in_ws.getNumberHistograms()):
             try:
-                monitors.append(i) if in_ws.getDetector(i).isMonitor() else detectors.append(i)
+                monitors.append(i) if spectrumInfo.isMonitor(i) else detectors.append(i)
             except RuntimeError:
                 self.log().warning("Missing detector at " + str(i))
 
         if detector_ws_name:
             if detectors:
-                detector_ws = ExtractSpectra(InputWorkspace=in_ws,
-                                             WorkspaceIndexList=detectors)
+                extract_alg = self.createChildAlgorithm("ExtractSpectra")
+                extract_alg.setProperty("InputWorkspace", in_ws)
+                extract_alg.setProperty("WorkspaceIndexList", detectors)
+                extract_alg.execute()
+                detector_ws = extract_alg.getProperty("OutputWorkspace").value
+                self.setProperty("DetectorWorkspace", detector_ws)
             else:
                 self.log().error("No detectors found in input workspace. No detector output workspace created.")
 
         if monitor_ws_name:
             if monitors:
-                monitor_ws = ExtractSpectra(InputWorkspace=in_ws,
-                                            WorkspaceIndexList=monitors)
+                extract_alg = self.createChildAlgorithm("ExtractSpectra")
+                extract_alg.setProperty("InputWorkspace", in_ws)
+                extract_alg.setProperty("WorkspaceIndexList", monitors)
+                extract_alg.execute()
+                monitor_ws = extract_alg.getProperty("OutputWorkspace").value
+                self.setProperty("MonitorWorkspace", monitor_ws)
             else:
                 self.log().error("No monitors found in input workspace. No monitor output workspace created.")
 
-        if detector_ws_name and detectors:
-            self.setProperty("DetectorWorkspace", detector_ws)
-            DeleteWorkspace(detector_ws)
-
-        if monitor_ws_name and monitors:
-            self.setProperty("MonitorWorkspace", monitor_ws)
-            DeleteWorkspace(monitor_ws)
-
         if detector_ws_name and detectors and monitor_ws_name and monitors:
             detector_ws.setMonitorWorkspace(monitor_ws)
 
diff --git a/Framework/PythonInterface/plugins/algorithms/FindEPP.py b/Framework/PythonInterface/plugins/algorithms/FindEPP.py
index 44be8317995b78d03cef85b23b7e5b8063612e06..e2f5613bf5da3e553f542c47f48cc03f90a71060 100644
--- a/Framework/PythonInterface/plugins/algorithms/FindEPP.py
+++ b/Framework/PythonInterface/plugins/algorithms/FindEPP.py
@@ -48,7 +48,7 @@ class FindEPP(PythonAlgorithm):
 
         # check for zero or negative signal
         if height <= 0.:
-            self.log().warning("Workspace %s, detector %d has maximum <= 0" % (self.workspace.getName(), index))
+            self.log().warning("Workspace %s, detector %d has maximum <= 0" % (self.workspace.name(), index))
             return result
 
         # Get the positions around the max, where the y value first drops down 0.5*height
@@ -75,7 +75,7 @@ class FindEPP(PythonAlgorithm):
         self.log().debug("(spectrum %d) : FWHM lower edge is %d, upper edge is %d" % (index,fwhm_neg,fwhm_pos))
 
         if fwhm_pos - fwhm_neg + 1 < 3:
-            self.log().warning("Spectrum " + str(index) + " in workspace " + self.workspace.getName() +
+            self.log().warning("Spectrum " + str(index) + " in workspace " + self.workspace.name() +
                                " has a too narrow peak. Cannot guess sigma. Check your data.")
             return result
 
diff --git a/Framework/PythonInterface/plugins/algorithms/FitGaussian.py b/Framework/PythonInterface/plugins/algorithms/FitGaussian.py
index 6dc36405d72eff27086d4116b3d7a6f59d8ce432..aaf8ccfc15e1a9d1730e9883fcd77a1a05b3b876 100644
--- a/Framework/PythonInterface/plugins/algorithms/FitGaussian.py
+++ b/Framework/PythonInterface/plugins/algorithms/FitGaussian.py
@@ -44,7 +44,7 @@ class FitGaussian(PythonAlgorithm):
         # index must be in <0,nhist)
         if index >= nhist:
             self._error("Index " + str(index) +
-                        " is out of range for the workspace " + workspace.getName())
+                        " is out of range for the workspace " + workspace.name())
 
         x_values = np.array(workspace.readX(index))
         y_values = np.array(workspace.readY(index))
@@ -55,7 +55,7 @@ class FitGaussian(PythonAlgorithm):
 
         # check for zero or negative signal
         if height <= 0.:
-            self._warning("Workspace %s, detector %d has maximum <= 0" % (workspace.getName(), index))
+            self._warning("Workspace %s, detector %d has maximum <= 0" % (workspace.name(), index))
             return
 
         # guess sigma (assume the signal is sufficiently smooth)
@@ -65,7 +65,7 @@ class FitGaussian(PythonAlgorithm):
         nentries = len(indices)
 
         if nentries < 3:
-            self._warning("Spectrum " + str(index) + " in workspace " + workspace.getName() +
+            self._warning("Spectrum " + str(index) + " in workspace " + workspace.name() +
                           " has a too narrow peak. Cannot guess sigma. Check your data.")
             return
 
@@ -89,7 +89,7 @@ class FitGaussian(PythonAlgorithm):
             StartX=startX, EndX=endX)
 
         if not 'success' == fitStatus:
-            self._warning("For detector " + str(index) + " in workspace " + workspace.getName() +
+            self._warning("For detector " + str(index) + " in workspace " + workspace.name() +
                           "fit was not successful. Input guess parameters were " + str(fitFun))
             return
 
diff --git a/Framework/PythonInterface/plugins/algorithms/GenerateGroupingSNSInelastic.py b/Framework/PythonInterface/plugins/algorithms/GenerateGroupingSNSInelastic.py
index 6a04305d538f759653c1a43cb72572222c479f7f..9a6563e7ce983e1f079a44cf09a20aaee8c315d5 100644
--- a/Framework/PythonInterface/plugins/algorithms/GenerateGroupingSNSInelastic.py
+++ b/Framework/PythonInterface/plugins/algorithms/GenerateGroupingSNSInelastic.py
@@ -56,7 +56,8 @@ class GenerateGroupingSNSInelastic(mantid.api.PythonAlgorithm):
         __w = mantid.simpleapi.LoadEmptyInstrument(Filename=IDF)
 
         i=0
-        while __w.getDetector(i).isMonitor():
+        spectrumInfo = __w.spectrumInfo()
+        while spectrumInfo.isMonitor(i):
             i += 1
         #i is the index of the first true detector
         #now, crop the workspace of the monitors
@@ -91,7 +92,7 @@ class GenerateGroupingSNSInelastic(mantid.api.PythonAlgorithm):
                     groupnum += 1
         f.write('</detector-grouping>')
         f.close()
-        mantid.simpleapi.DeleteWorkspace(__w.getName())
+        mantid.simpleapi.DeleteWorkspace(__w.name())
         return
 
 mantid.api.AlgorithmFactory.subscribe(GenerateGroupingSNSInelastic)
diff --git a/Framework/PythonInterface/plugins/algorithms/IndirectTransmission.py b/Framework/PythonInterface/plugins/algorithms/IndirectTransmission.py
index 5a26872144296b5629d20580ca63b46780c2ad01..fb73444843cb41188ff71966a591921778977711 100644
--- a/Framework/PythonInterface/plugins/algorithms/IndirectTransmission.py
+++ b/Framework/PythonInterface/plugins/algorithms/IndirectTransmission.py
@@ -35,7 +35,7 @@ class IndirectTransmission(PythonAlgorithm):
 
     def PyInit(self):
         self.declareProperty(name='Instrument', defaultValue='IRIS',
-                             validator=StringListValidator(['IRIS', 'OSIRIS', 'TOSCA', 'BASIS', 'VISION']),
+                             validator=StringListValidator(['IRIS', 'OSIRIS', 'TOSCA', 'BASIS', 'VISION', 'IN16B']),
                              doc='Instrument')
 
         self.declareProperty(name='Analyser', defaultValue='graphite',
@@ -43,7 +43,7 @@ class IndirectTransmission(PythonAlgorithm):
                              doc='Analyser')
 
         self.declareProperty(name='Reflection', defaultValue='002',
-                             validator=StringListValidator(['002', '004', '006', '111']),
+                             validator=StringListValidator(['002', '004', '006', '111', '311']),
                              doc='Reflection')
 
         self.declareProperty(name='ChemicalFormula', defaultValue='', validator=StringMandatoryValidator(),
diff --git a/Framework/PythonInterface/plugins/algorithms/LoadVesuvio.py b/Framework/PythonInterface/plugins/algorithms/LoadVesuvio.py
index 7f65a16302ea5095b464943d854d08692a8750cd..8e087d58bbf93ee1392b7d443c4fbcc65884a0ba 100644
--- a/Framework/PythonInterface/plugins/algorithms/LoadVesuvio.py
+++ b/Framework/PythonInterface/plugins/algorithms/LoadVesuvio.py
@@ -1,6 +1,3 @@
-#pylint: disable=no-init, unused-variable, too-many-lines
-# we need to disable unused_variable because ws.dataY(n) returns a reference  to the underlying c++ object
-# that can be modified inplace
 from __future__ import (absolute_import, division, print_function)
 from mantid.kernel import *
 from mantid.api import *
@@ -34,8 +31,6 @@ FORWARD = 1
 # Child Algorithm logging
 _LOGGING_ = False
 
-#pylint: disable=too-many-instance-attributes
-
 
 class LoadVesuvio(LoadEmptyVesuvio):
 
@@ -319,23 +314,27 @@ class LoadVesuvio(LoadEmptyVesuvio):
         """
         Execution path when a single foil state is requested
         """
+
         runs = self._get_runs()
-        if len(runs) > 1:
-            raise RuntimeError("Single foil state mode does not currently support summing "
-                               "multiple files")
 
-        isis = config.getFacility("ISIS")
-        inst_prefix = isis.instrument("VESUVIO").shortName()
+        all_spectra = [item for sublist in self._spectra for item in sublist]
 
-        try:
-            run_str = inst_prefix + runs[0]
-        except ValueError:
-            run_str = runs[0]
+        if len(runs) > 1:
+            self._set_spectra_type(all_spectra[0])
+            self._setup_raw(all_spectra)
+        else:
+            isis = config.getFacility("ISIS")
+            inst_prefix = isis.instrument("VESUVIO").shortName()
 
-        self._raise_error_period_scatter(run_str, self._back_scattering)
-        all_spectra = [item for sublist in self._spectra for item in sublist]
+            try:
+                run_str = inst_prefix + runs[0] +'.raw'
+            except ValueError:
+                run_str = runs[0]
+
+            self._raise_error_period_scatter(run_str, self._back_scattering)
+            all_spectra = [item for sublist in self._spectra for item in sublist]
 
-        self._load_single_run_spec_and_mon(all_spectra, run_str)
+            self._load_single_run_spec_and_mon(all_spectra, run_str)
 
         raw_group = mtd[SUMMED_WS]
         self._nperiods = raw_group.size()
@@ -358,7 +357,7 @@ class LoadVesuvio(LoadEmptyVesuvio):
             elif self._diff_opt == "FoilInOut":
                 raw_grp_indices = list(range(0, self._nperiods))
             else:
-                raise RuntimeError("Unknown single foil mode: %s." % (self._diff_opt))
+                raise RuntimeError("Unknown single foil mode: %s." % self._diff_opt)
 
             dataY = foil_out.dataY(ws_index)
             dataE = foil_out.dataE(ws_index)
@@ -368,6 +367,38 @@ class LoadVesuvio(LoadEmptyVesuvio):
             np.sqrt(dataE, dataE)
             foil_out.setX(ws_index, x_values)
 
+            if len(runs) > 1:
+                # Create monitor workspace for normalisation
+                first_mon_ws = self._raw_monitors[0]
+                nmonitor_bins = first_mon_ws.blocksize()
+                nhists = first_ws.getNumberHistograms()
+                data_kwargs = {'NVectors': nhists, 'XLength': nmonitor_bins, 'YLength': nmonitor_bins}
+                mon_out = WorkspaceFactory.create(first_mon_ws, **data_kwargs)
+
+                mon_raw_t = self._raw_monitors[0].readX(0)
+                delay = mon_raw_t[2] - mon_raw_t[1]
+                # The original EVS loader, raw.for/rawb.for, does this. Done here to match results
+                mon_raw_t = mon_raw_t - delay
+                self.mon_pt_times = mon_raw_t[1:]
+
+                if self._nperiods == 6 and self._spectra_type == FORWARD:
+                    mon_periods = (5, 6)
+                    raw_grp_indices = foil_map.get_indices(spectrum_no, mon_periods)
+
+                outY = mon_out.dataY(ws_index)
+                for grp_index in raw_grp_indices:
+                    raw_ws = self._raw_monitors[grp_index]
+                    outY += raw_ws.readY(self._mon_index)
+
+                # Normalise by monitor
+                indices_in_range = np.where((self.mon_pt_times >= self._mon_norm_start) & (self.mon_pt_times < self._mon_norm_end))
+                mon_values = mon_out.readY(ws_index)
+                mon_values_sum = np.sum(mon_values[indices_in_range])
+                foil_state = foil_out.dataY(ws_index)
+                foil_state *= (self._mon_scale/mon_values_sum)
+                err = foil_out.dataE(ws_index)
+                err *= (self._mon_scale/mon_values_sum)
+
         ip_file = self.getPropertyValue(INST_PAR_PROP)
         if len(ip_file) > 0:
             self.foil_out = self._load_ip_file(self.foil_out, ip_file)
@@ -377,18 +408,21 @@ class LoadVesuvio(LoadEmptyVesuvio):
 
         ms.DeleteWorkspace(Workspace=SUMMED_WS)
         self._store_results()
+        self._cleanup_raw()
 
 #----------------------------------------------------------------------------------------
 
     def _load_single_run_spec_and_mon(self, all_spectra, run_str):
         # check if the monitor spectra are already in the spectra list
         filtered_spectra = sorted([i for i in all_spectra if i <= self._mon_spectra[-1]])
+        mons_in_ws = False
         if filtered_spectra == self._mon_spectra and self._load_monitors:
             # Load monitors in workspace if defined by user
             self._load_monitors = False
+            mons_in_ws = True
             logger.warning("LoadMonitors is true while monitor spectra are defined in the spectra list.")
             logger.warning("Monitors have been loaded into the data workspace not separately.")
-        if not self._load_monitors:
+        if mons_in_ws:
             ms.LoadRaw(Filename=run_str, OutputWorkspace=SUMMED_WS, SpectrumList=all_spectra,
                        EnableLogging=_LOGGING_)
         else:
@@ -396,17 +430,17 @@ class LoadVesuvio(LoadEmptyVesuvio):
             all_spec_inc_mon.extend(all_spectra)
             ms.LoadRaw(Filename=run_str, OutputWorkspace=SUMMED_WS, SpectrumList=all_spec_inc_mon,
                        LoadMonitors='Separate', EnableLogging=_LOGGING_)
-            monitor_group = mtd[SUMMED_WS +'_monitors']
-            mon_out_name = self.getPropertyValue(WKSP_PROP) + "_monitors"
-            clone = self.createChildAlgorithm("CloneWorkspace", False)
-            clone.setProperty("InputWorkspace", monitor_group.getItem(0))
-            clone.setProperty("OutputWorkspace", mon_out_name)
-            clone.execute()
-            self._load_monitors_workspace = clone.getProperty("OutputWorkspace").value
-            self._load_monitors_workspace = self._sum_monitors_in_group(monitor_group,
-                                                                        self._load_monitors_workspace)
-            ms.DeleteWorkspace(Workspace=monitor_group)
-
+            if self._load_monitors:
+                monitor_group = mtd[SUMMED_WS +'_monitors']
+                mon_out_name = self.getPropertyValue(WKSP_PROP) + "_monitors"
+                clone = self.createChildAlgorithm("CloneWorkspace", False)
+                clone.setProperty("InputWorkspace", monitor_group.getItem(0))
+                clone.setProperty("OutputWorkspace", mon_out_name)
+                clone.execute()
+                self._load_monitors_workspace = clone.getProperty("OutputWorkspace").value
+                self._load_monitors_workspace = self._sum_monitors_in_group(monitor_group,
+                                                                            self._load_monitors_workspace)
+            self._raw_monitors = mtd[SUMMED_WS +'_monitors']
 #----------------------------------------------------------------------------------------
 
     def _load_common_inst_parameters(self):
@@ -454,7 +488,7 @@ class LoadVesuvio(LoadEmptyVesuvio):
         def to_range_tuple(str_range):
             """Return a list of 2 floats giving the lower,upper range"""
             elements = str_range.split("-")
-            return (float(elements[0]),float(elements[1]))
+            return float(elements[0]), float(elements[1])
 
         self._back_mon_norm = to_range_tuple(self.backward_monitor_norm)
         self._back_period_sum1 = to_range_tuple(self.backward_period_sum1)
@@ -589,15 +623,16 @@ class LoadVesuvio(LoadEmptyVesuvio):
                 ms.DeleteWorkspace(out_mon, EnableLogging=_LOGGING_)
 
         # Check to see if extra data needs to be loaded to normalise in data
-        x_max = self._tof_max
-        if self._foil_out_norm_end > self._tof_max:
-            x_max = self._foil_out_norm_end
-            self._crop_required = True
+        if "Difference" in self._diff_opt:
+            x_max = self._tof_max
+            if self._foil_out_norm_end > self._tof_max:
+                x_max = self._foil_out_norm_end
+                self._crop_required = True
 
-        ms.CropWorkspace(Inputworkspace= SUMMED_WS,
-                         OutputWorkspace=SUMMED_WS,
-                         XMax=x_max,
-                         EnableLogging=_LOGGING_)
+            ms.CropWorkspace(Inputworkspace= SUMMED_WS,
+                             OutputWorkspace=SUMMED_WS,
+                             XMax=x_max,
+                             EnableLogging=_LOGGING_)
 
         summed_data, summed_mon = mtd[SUMMED_WS], mtd[SUMMED_WS + '_monitors']
 
@@ -611,8 +646,8 @@ class LoadVesuvio(LoadEmptyVesuvio):
             self._load_monitors_workspace = clone.getProperty("OutputWorkspace").value
             self._load_monitors_workspace = self._sum_monitors_in_group(summed_mon,
                                                                         self._load_monitors_workspace)
-
-        self._load_diff_mode_parameters(summed_data)
+        if "Difference" in self._diff_opt:
+            self._load_diff_mode_parameters(summed_data)
         return summed_data, summed_mon
 
 
@@ -623,7 +658,7 @@ class LoadVesuvio(LoadEmptyVesuvio):
         Sums together all the monitors for one run
         @param monitor_group    :: All the monitor workspaces for a single run
         @param output_ws        :: The workspace that will contain the summed monitor data
-        @return                 :: The workspace contianing the summed monitor data
+        @return                 :: The workspace containing the summed monitor data
         """
 
         for mon_index in range(1, monitor_group.getNumberOfEntries()):
@@ -680,16 +715,14 @@ class LoadVesuvio(LoadEmptyVesuvio):
 #----------------------------------------------------------------------------------------
 
     def _is_back_scattering(self, spectrum_no):
-        return spectrum_no >= self._backward_spectra_list[0] and \
-            spectrum_no <= self._backward_spectra_list[-1]
+        return self._backward_spectra_list[0] <= spectrum_no <= self._backward_spectra_list[-1]
 
-#----------------------------------------------------------------------------------------
+    #----------------------------------------------------------------------------------------
 
     def _is_fwd_scattering(self, spectrum_no):
-        return spectrum_no >= self._forward_spectra_list[0] and \
-            spectrum_no <= self._forward_spectra_list[-1]
+        return self._forward_spectra_list[0] <= spectrum_no <= self._forward_spectra_list[-1]
 
-#----------------------------------------------------------------------------------------
+    #----------------------------------------------------------------------------------------
 
     def _integrate_periods(self):
         """
@@ -816,7 +849,6 @@ class LoadVesuvio(LoadEmptyVesuvio):
 
 #----------------------------------------------------------------------------------------
 
-    #pylint: disable=too-many-arguments
     def _sum_foils(self, foil_ws, mon_ws, sum_index, foil_periods, mon_periods=None):
         """
         Sums the counts from the given foil periods in the raw data group
@@ -1043,7 +1075,7 @@ class LoadVesuvio(LoadEmptyVesuvio):
         self.setProperty(WKSP_PROP, self.foil_out)
         # Add OutputWorkspace property for Monitors
         if self._load_monitors:
-            # Check property is not being re-decalred
+            # Check property is not being re-declared
             if not self.existsProperty(WKSP_PROP_LOAD_MON):
                 mon_out_name = self.getPropertyValue(WKSP_PROP) + '_monitors'
                 self.declareProperty(WorkspaceProperty(WKSP_PROP_LOAD_MON, mon_out_name, Direction.Output),
@@ -1072,7 +1104,7 @@ class SpectraToFoilPeriodMap(object):
     one_to_one          :: Only used in back scattering where there is a single
                            static foil
     odd_even/even_odd   :: Only used in forward scatter models when the foil
-                           is/isn't infront of each detector. First bank 135-142
+                           is/isn't in front of each detector. First bank 135-142
                            is odd_even, second (143-150) is even_odd and so on.
     """
 
@@ -1145,10 +1177,10 @@ class SpectraToFoilPeriodMap(object):
 
         if spectrum_no < 135:
             foil_periods = [1,2,3]
-        elif (spectrum_no >= 135 and spectrum_no <= 142) or \
-             (spectrum_no >= 151 and spectrum_no <= 158) or \
-             (spectrum_no >= 167 and spectrum_no <= 174) or \
-             (spectrum_no >= 183 and spectrum_no <= 190):
+        elif (135 <= spectrum_no <= 142) or \
+             (151 <= spectrum_no <= 158) or \
+             (167 <= spectrum_no <= 174) or \
+             (183 <= spectrum_no <= 190):
             foil_periods = [2,4,6] if foil_out else [1,3,5]
         else:
             foil_periods = [1,3,5] if foil_out else [2,4,6]
@@ -1161,7 +1193,7 @@ class SpectraToFoilPeriodMap(object):
         Returns a tuple of indices that can be used to access the Workspace within
         a WorkspaceGroup that corresponds to the foil state numbers given
         @param spectrum_no :: A spectrum number (1->nspectra)
-        @param foil_state_no :: A number between 1 & 6(inclusive) that defines which foil
+        @param foil_state_numbers :: A number between 1 & 6(inclusive) that defines which foil
                                 state is required
         @returns A tuple of indices in a WorkspaceGroup that gives the associated Workspace
         """
@@ -1187,10 +1219,10 @@ class SpectraToFoilPeriodMap(object):
         # For the back scattering banks or foil states > 6 then there is a 1:1 map
         if foil_state_no > 6 or spectrum_no < 135:
             foil_periods = self._one_to_one
-        elif (spectrum_no >= 135 and spectrum_no <= 142) or \
-             (spectrum_no >= 151 and spectrum_no <= 158) or \
-             (spectrum_no >= 167 and spectrum_no <= 174) or \
-             (spectrum_no >= 183 and spectrum_no <= 190):
+        elif (135 <= spectrum_no <= 142) or \
+             (151 <= spectrum_no <= 158) or \
+             (167 <= spectrum_no <= 174) or \
+             (183 <= spectrum_no <= 190):
              # For each alternating forward scattering bank :: foil_in = 1,3,5, foil out = 2,4,6
             foil_periods = self._odd_even
         else:
diff --git a/Framework/PythonInterface/plugins/algorithms/MaskAngle.py b/Framework/PythonInterface/plugins/algorithms/MaskAngle.py
index 5d73ec1a1057a09d5e11a061fedac4441840e9ca..0128b109359c5bac44d46b9f6e356b752f70aedf 100644
--- a/Framework/PythonInterface/plugins/algorithms/MaskAngle.py
+++ b/Framework/PythonInterface/plugins/algorithms/MaskAngle.py
@@ -66,9 +66,10 @@ class MaskAngle(mantid.api.PythonAlgorithm):
         numspec = ws.getNumberHistograms()
         source=ws.getInstrument().getSource().getPos()
         sample=ws.getInstrument().getSample().getPos()
+        spectrumInfo = ws.spectrumInfo()
         for i in range(numspec):
-            det=ws.getDetector(i)
-            if not det.isMonitor():
+            if not spectrumInfo.isMonitor(i):
+                det = ws.getDetector(i)
                 tt=numpy.degrees(det.getTwoTheta(sample,sample-source))
                 if tt>= ttmin and tt<= ttmax:
                     detlist.append(det.getID())
diff --git a/Framework/PythonInterface/plugins/algorithms/MaskBTP.py b/Framework/PythonInterface/plugins/algorithms/MaskBTP.py
index 59137c083a5c1271aaa41427ff7b1e8ccf182bb0..0e93960a78db86a52b9b533c8ab40e30ceac9c30 100644
--- a/Framework/PythonInterface/plugins/algorithms/MaskBTP.py
+++ b/Framework/PythonInterface/plugins/algorithms/MaskBTP.py
@@ -52,9 +52,6 @@ class MaskBTP(mantid.api.PythonAlgorithm):
         tubeString = self.getProperty("Tube").value
         pixelString = self.getProperty("Pixel").value
 
-        if self.instname == "" and ws is None:
-            raise ValueError("No workspace or instrument were selected" )
-
         if ws is not None:
             self.instrument = ws.getInstrument()
             self.instname = self.instrument.getName()
@@ -77,12 +74,10 @@ class MaskBTP(mantid.api.PythonAlgorithm):
         try:
             instrumentList.index(self.instname)
         except:
-            raise ValueError("Instrument "+self.instname+" not in the allowed list")
+            raise ValueError("Instrument '"+self.instname+"' not in the allowed list")
 
         if self.instrument is None:
             IDF=mantid.api.ExperimentInfo.getInstrumentFilename(self.instname)
-            if mantid.mtd.doesExist(self.instname+"MaskBTP"):
-                mantid.simpleapi.DeleteWorkspace(self.instname+"MaskBTP")
             ws=mantid.simpleapi.LoadEmptyInstrument(IDF,OutputWorkspace=self.instname+"MaskBTP")
             self.instrument=ws.getInstrument()
 
@@ -169,15 +164,6 @@ class MaskBTP(mantid.api.PythonAlgorithm):
                 return self.instrument.getComponentByName("T row")[banknum-78][0]
             else:
                 raise ValueError("Out of range index for ARCS instrument bank numbers")
-        elif self.instname=="CORELLI":
-            if self.bankmin[self.instname]<=banknum<= 29:
-                return self.instrument.getComponentByName("A row")[banknum-1][0]
-            elif 30<=banknum<=62:
-                return self.instrument.getComponentByName("B row")[banknum-30][0]
-            elif 63<=banknum<=self.bankmax[self.instname]:
-                return self.instrument.getComponentByName("C row")[banknum-63][0]
-            else:
-                raise ValueError("Out of range index for CORELLI instrument bank numbers")
         elif self.instname=="SEQUOIA":
             if self.bankmin[self.instname]<=banknum<= 74:
                 return self.instrument.getComponentByName("B row")[banknum-38][0]
@@ -187,7 +173,7 @@ class MaskBTP(mantid.api.PythonAlgorithm):
                 return self.instrument.getComponentByName("D row")[banknum-114][0]
             else:
                 raise ValueError("Out of range index for SEQUOIA instrument bank numbers")
-        elif self.instname=="CNCS" or self.instname=="HYSPEC":
+        elif self.instname in ["CNCS", "CORELLI","HYSPEC"]:
             if self.bankmin[self.instname]<=banknum<= self.bankmax[self.instname]:
                 return self.instrument.getComponentByName("bank"+str(banknum))[0]
             else:
diff --git a/Framework/PythonInterface/plugins/algorithms/MaskWorkspaceToCalFile.py b/Framework/PythonInterface/plugins/algorithms/MaskWorkspaceToCalFile.py
index 600a5d4a039e2a107f0c067f5b13e06ac568fb91..7e311bed9f7c5c74c1c1a084b574e2376f981eea 100644
--- a/Framework/PythonInterface/plugins/algorithms/MaskWorkspaceToCalFile.py
+++ b/Framework/PythonInterface/plugins/algorithms/MaskWorkspaceToCalFile.py
@@ -8,14 +8,14 @@ from mantid.simpleapi import *
 
 
 class QueryFlag(object):
-    def isMasked(self, detector, dummy_yValue):
-        return detector.isMasked()
+    def isMasked(self, specInfo, index, dummy_yValue):
+        return specInfo.isMasked(index)
 
 #pylint: disable=too-few-public-methods
 
 
 class QueryValue(object):
-    def isMasked(self, dummy_detector, yValue):
+    def isMasked(self, dummy_specInfo, dummy_index, yValue):
         return yValue == 1
 
 
@@ -64,11 +64,12 @@ class MaskWorkspaceToCalFile(PythonAlgorithm):
         calFile.write('# '+instrumentName+' detector file\n')
         calFile.write('# Format: number      UDET       offset       select    group\n')
         #save the grouping
+        specInfo = inputWorkspace.spectrumInfo()
         for i in range(inputWorkspace.getNumberHistograms()):
             try:
                 det = inputWorkspace.getDetector(i)
                 y_value = inputWorkspace.readY(i)[0]
-                if mask_query.isMasked(det, y_value): #check if masked
+                if mask_query.isMasked(specInfo, i, y_value): #check if masked
                     group = masking_flag
                 else:
                     group = not_masking_flag
diff --git a/Framework/PythonInterface/plugins/algorithms/MatchPeaks.py b/Framework/PythonInterface/plugins/algorithms/MatchPeaks.py
index aa10dc1f96e7883af043d3ae2acafad7f8fa5cb6..e2f8887125afbcb6076283f60ea3f3c41dbf848a 100644
--- a/Framework/PythonInterface/plugins/algorithms/MatchPeaks.py
+++ b/Framework/PythonInterface/plugins/algorithms/MatchPeaks.py
@@ -147,7 +147,6 @@ class MatchPeaks(PythonAlgorithm):
         output_ws = CloneWorkspace(InputWorkspace=mtd[self._input_ws], OutputWorkspace=self._output_ws)
 
         size = mtd[self._input_ws].blocksize()
-
         mid_bin = int(size / 2)
 
         # Find peak positions in input workspace
@@ -208,7 +207,6 @@ class MatchPeaks(PythonAlgorithm):
             bin_range = CreateEmptyTableWorkspace(OutputWorkspace=self._output_bin_range)
             bin_range.addColumn(type="double", name='MinBin')
             bin_range.addColumn(type="double", name='MaxBin')
-
             bin_range.addRow({'MinBin': min_bin, 'MaxBin': max_bin})
             self.setProperty('BinRangeTable', bin_range)
 
@@ -233,53 +231,60 @@ class MatchPeaks(PythonAlgorithm):
 
         # Mid bin number
         mid_bin = int(mtd[self._input_ws].blocksize() / 2)
-
         # Initialisation
         peak_bin = np.ones(mtd[self._input_ws].getNumberHistograms()) * mid_bin
-        peak_plus_error = np.zeros(mtd[self._input_ws].getNumberHistograms())
-
         # Bin range: difference between mid bin and peak bin should be in this range
         tolerance = int(mid_bin / 2)
-
         x_values = mtd[self._input_ws].readX(0)
 
         for i in range(mtd[self._input_ws].getNumberHistograms()):
             fit = fit_table.row(i)
-
             # Bin number, where Y has its maximum
             y_values = mtd[self._input_ws].readY(i)
-
-            peak_pos_error = fit["PeakCentreError"] + fit["PeakCentre"]
-
-            if peak_pos_error >= x_values[0]:
-                if peak_pos_error <= x_values[-1]:
-                    if fit["FitStatus"] == 'success':
-                        peak_plus_error[i] = mtd[self._input_ws].binIndexOf(peak_pos_error)
-                        if abs(peak_plus_error[i] - mid_bin) < tolerance:
-                            peak_bin[i] = mtd[self._input_ws].binIndexOf(fit["PeakCentre"])
-                            logger.debug('Fit success, peak inside tolerance')
-                        else:
-                            logger.debug('Peak outside tolerance, do not shift spectrum')
-                    elif abs(np.argmax(y_values) - mid_bin) < tolerance:
-                        peak_bin[i] = np.argmax(y_values)
-                        logger.debug('Take maximum peak position {0}'.format(peak_bin[i]))
-                    else:
-                        logger.debug('Fit failed and peak outside tolerance, do not shift spectrum')
+            max_pos = np.argmax(y_values)
+            peak_plus_error = abs(fit["PeakCentreError"]) + abs(fit["PeakCentre"])
+
+            if peak_plus_error > x_values[0] and peak_plus_error < x_values[-1]:
+                peak_plus_error_bin = mtd[self._input_ws].binIndexOf(peak_plus_error)
+                if abs(peak_plus_error_bin - mid_bin) < tolerance and fit["FitStatus"] == 'success':
+                    # fit succeeded, and fitted peak is within acceptance range, take it
+                    peak_bin[i] = mtd[self._input_ws].binIndexOf(fit["PeakCentre"])
+                    logger.debug('Fit successfull, peak inside tolerance')
+                elif abs(max_pos - mid_bin) < tolerance:
+                    # fit not reliable, take the maximum if within acceptance
+                    peak_bin[i] = max_pos
+                    logger.debug('Fit outside the trusted range, take the maximum position')
                 else:
-                    logger.debug('Peak x-value {0} > x-end {1}, do not shift spectrum'.format(peak_pos_error,
-                                                                                              x_values[-1]))
+                    # do not shift
+                    logger.debug('Both the fit and the max are outside the trusted range. '
+                                 'Do not shift the spectrum.')
+
+            elif abs(max_pos - mid_bin) < tolerance:
+                # fit not reliable, take the maximum if within acceptance
+                peak_bin[i] = max_pos
+                logger.debug('Fit outside the x-range, take the maximum position')
+
             else:
-                logger.debug('Peak x-value {0} < x-begin {1}, do not shift spectrum'.format(peak_pos_error,
-                                                                                            x_values[0]))
+                # do not shift
+                logger.debug('Both the fit and the max are outside the trusted range. '
+                             'Do not shift the spectrum.')
 
-        # Clean-up unused TableWorkspaces
-        if mtd['EPPfit_Parameters']:
-            DeleteWorkspace('EPPfit_Parameters')
+            logger.debug('Spectrum {0} will be shifted to bin {1}'.format(i,peak_bin[i]))
 
-        if mtd['EPPfit_NormalisedCovarianceMatrix']:
+        # Clean-up unused TableWorkspaces in try-catch
+        # Direct deletion causes problems when running in parallel for too many workspaces
+        try:
+            DeleteWorkspace('EPPfit_Parameters')
+        except ValueError:
+            logger.debug('Fit parameters workspace already deleted')
+        try:
             DeleteWorkspace('EPPfit_NormalisedCovarianceMatrix')
-
-        DeleteWorkspace(fit_table)
+        except ValueError:
+            logger.debug('Fit covariance matrix already deleted')
+        try:
+            DeleteWorkspace(fit_table)
+        except ValueError:
+            logger.debug('Fit table already deleted')
 
         return peak_bin
 
diff --git a/Framework/PythonInterface/plugins/algorithms/MedianBinWidth.py b/Framework/PythonInterface/plugins/algorithms/MedianBinWidth.py
new file mode 100644
index 0000000000000000000000000000000000000000..9a73de87be4094769695c7012c341712057d7813
--- /dev/null
+++ b/Framework/PythonInterface/plugins/algorithms/MedianBinWidth.py
@@ -0,0 +1,70 @@
+from __future__ import (absolute_import, division, print_function)
+
+from mantid.api import AlgorithmFactory, HistogramValidator,\
+    MatrixWorkspaceProperty, PythonAlgorithm
+from mantid.kernel import Direction
+import numpy
+import roundinghelper
+
+
+class MedianBinWidth(PythonAlgorithm):
+
+    _PROP_BIN_WIDTH = 'BinWidth'
+    _PROP_INPUT_WS = 'InputWorkspace'
+
+    def category(self):
+        '''
+        Return algorithm's category.
+        '''
+        return 'Utility\\Calculation'
+
+    def name(self):
+        '''
+        Return algorithm's name.
+        '''
+        return 'MedianBinWidth'
+
+    def summary(self):
+        '''
+        Return algorithm's summary.
+        '''
+        return ("Calculates the average of workspace's histograms'"
+                " median bin widths.")
+
+    def version(self):
+        '''
+        Return algorithm's version.
+        '''
+        return 1
+
+    def PyInit(self):
+        '''
+        Declares algorithm's properties.
+        '''
+        self.declareProperty(
+            MatrixWorkspaceProperty(name=self._PROP_INPUT_WS,
+                                    defaultValue='',
+                                    validator=HistogramValidator(),
+                                    direction=Direction.Input),
+            doc='The workspace containing the input data')
+        roundinghelper.declare_rounding_property(self)
+        self.declareProperty(self._PROP_BIN_WIDTH,
+                             defaultValue=0.0,
+                             direction=Direction.Output,
+                             doc='The averaged median bin width')
+
+    def PyExec(self):
+        '''
+        Averages the median bin widths of the input workspace.
+        '''
+        inputWs = self.getProperty(self._PROP_INPUT_WS).value
+        roundingMode = self.getProperty(
+            roundinghelper.PROP_NAME_ROUNDING_MODE).value
+        xs = inputWs.extractX()
+        dxs = numpy.diff(xs)
+        medians = numpy.median(dxs, axis=1)
+        binWidth = numpy.mean(medians)
+        binWidth = roundinghelper.round(binWidth, roundingMode)
+        self.setProperty(self._PROP_BIN_WIDTH, numpy.abs(binWidth))
+
+AlgorithmFactory.subscribe(MedianBinWidth)
diff --git a/Framework/PythonInterface/plugins/algorithms/MuscatSofQW.py b/Framework/PythonInterface/plugins/algorithms/MuscatSofQW.py
index d31ca5b66c073e75256459da88a73b4bc2de24ac..1e60cce760b7b6f977c68bd78f6c2c03a5b4ce88 100644
--- a/Framework/PythonInterface/plugins/algorithms/MuscatSofQW.py
+++ b/Framework/PythonInterface/plugins/algorithms/MuscatSofQW.py
@@ -81,7 +81,8 @@ class MuscatSofQW(DataProcessorAlgorithm):
         pk_1 = '(composite=Convolution,FixResolution=true,NumDeriv=true;name=Resolution, Workspace="{0}"'.format(self._res_rebin)
 
         if self._lor >= 1:
-            lor_fun = 'composite=ProductFunction,NumDeriv=false;name=Lorentzian,Amplitude={0},PeakCentre=0.0,FWHM={1}'.format(l_height_1[peak_idx], l_width_1[peak_idx])
+            lor_fun = 'composite=ProductFunction,NumDeriv=false;name=Lorentzian,'+\
+                      'Amplitude={0},PeakCentre=0.0,FWHM={1}'.format(l_height_1[peak_idx], l_width_1[peak_idx])
         elif self._lor == 2:
             funcIndex = 1 if self._delta else 0
             lor_2 = 'name=Lorentzian,Amplitude='+str(l_height_2[peak_idx])+',PeakCentre=0.0,FWHM='+str(l_width_2[peak_idx])
diff --git a/Framework/PythonInterface/plugins/algorithms/NMoldyn4Interpolation.py b/Framework/PythonInterface/plugins/algorithms/NMoldyn4Interpolation.py
index adeb0e7035fd2be99d5bc1ace3f491431b566434..34ac38f598f0e77f03d78a03ae562268dada9ea1 100644
--- a/Framework/PythonInterface/plugins/algorithms/NMoldyn4Interpolation.py
+++ b/Framework/PythonInterface/plugins/algorithms/NMoldyn4Interpolation.py
@@ -124,7 +124,7 @@ class NMoldyn4Interpolation(PythonAlgorithm):
         osiris = mtd[ws_name]
         Q_values = []
         for i in range(osiris.getNumberHistograms()):
-            Q_values.append(self.get_Q_for_workspace_index(osiris.getName(), i, e_fixed))
+            Q_values.append(self.get_Q_for_workspace_index(osiris.name(), i, e_fixed))
         X_values = osiris.readX(0)
         X_diff = np.diff(X_values) / 2
         X_bins = [X_values[i] + X_diff[i] for i in range(len(X_diff))]
diff --git a/Framework/PythonInterface/plugins/algorithms/RefinePowderDiffProfileSeq.py b/Framework/PythonInterface/plugins/algorithms/RefinePowderDiffProfileSeq.py
index b0442c806c7d38f98608335b3c0f645c2db3976e..6487144b001d714e4709dfd39e250d7b608dc681 100644
--- a/Framework/PythonInterface/plugins/algorithms/RefinePowderDiffProfileSeq.py
+++ b/Framework/PythonInterface/plugins/algorithms/RefinePowderDiffProfileSeq.py
@@ -921,7 +921,7 @@ class RefineProfileParameters(object):
                 UseInputPeakHeights             = False,
                 PeakRadius                      ='8',
                 Minimizer                       = 'Levenberg-Marquardt',
-                MCSetupWorkspace                = str(wsname),
+                MCSetupWorkspace                = tablews,
                 Damping                         = '5.0',
                 RandomSeed                      = 0,
                 AnnealingTemperature            = 100.0,
diff --git a/Framework/PythonInterface/plugins/algorithms/RetrieveRunInfo.py b/Framework/PythonInterface/plugins/algorithms/RetrieveRunInfo.py
index 3797f4da1789223b0ba0ff26537c64a8ba141dc9..490adca6296f714b2804e85f25ab22bcab6e62ab 100644
--- a/Framework/PythonInterface/plugins/algorithms/RetrieveRunInfo.py
+++ b/Framework/PythonInterface/plugins/algorithms/RetrieveRunInfo.py
@@ -92,7 +92,7 @@ class Intervals(object):
 def sumWsList(wsList, summedWsName = None):
     if len(wsList) == 1:
         if summedWsName is not None:
-            CloneWorkspace(InputWorkspace=wsList[0].getName(), OutputWorkspace=summedWsName)
+            CloneWorkspace(InputWorkspace=wsList[0].name(), OutputWorkspace=summedWsName)
             return mtd[summedWsName]
         return wsList[0]
 
@@ -103,9 +103,9 @@ def sumWsList(wsList, summedWsName = None):
             sumws += wsList[i]
 
     if summedWsName is None:
-        summedWsName = "_PLUS_".join([ws.getName() for ws in wsList])
+        summedWsName = "_PLUS_".join([ws.name() for ws in wsList])
 
-    RenameWorkspace(InputWorkspace=sumws.getName(), OutputWorkspace=summedWsName)
+    RenameWorkspace(InputWorkspace=sumws.name(), OutputWorkspace=summedWsName)
 
     return mtd[summedWsName]
 
@@ -199,7 +199,8 @@ class RetrieveRunInfo(PythonAlgorithm):
             StringMandatoryValidator(),
             doc='The range of runs to retrieve the run info for. E.g. "100-105".')
         self.declareProperty(ITableWorkspaceProperty("OutputWorkspace", "", Direction.Output),
-                             doc= """The name of the TableWorkspace that will be created. '''You must specify a name that does not already exist.''' """)
+                             doc= """The name of the TableWorkspace that will be created.
+                                     '''You must specify a name that does not already exist.''' """)
 
     def PyExec(self):
         PROP_NAMES = ["inst_abrv", "run_number", "user_name", "run_title",
@@ -235,9 +236,9 @@ class RetrieveRunInfo(PythonAlgorithm):
         ws_iter = FileBackedWsIterator(filenames)
         for ws in ws_iter:
             # Create a single row table for each file.
-            temp_table_name = ws.getName() + "_INFO"
+            temp_table_name = ws.name() + "_INFO"
             CreateLogPropertyTable(
-                InputWorkspaces=ws.getName(),
+                InputWorkspaces=ws.name(),
                 LogPropertyNames=', '.join(PROP_NAMES),
                 GroupPolicy="First", # Include only the 1st child of any groups.
                 OutputWorkspace=temp_table_name)
diff --git a/Framework/PythonInterface/plugins/algorithms/SNAPReduce.py b/Framework/PythonInterface/plugins/algorithms/SNAPReduce.py
new file mode 100644
index 0000000000000000000000000000000000000000..496ec44b5e5ee8c6cdce740b3fd15ef806b7bba7
--- /dev/null
+++ b/Framework/PythonInterface/plugins/algorithms/SNAPReduce.py
@@ -0,0 +1,444 @@
+# pylint: disable=invalid-name,no-init,too-many-lines
+from __future__ import (absolute_import, division, print_function)
+from mantid.kernel import Direction, FloatArrayProperty, IntArrayBoundedValidator, \
+    IntArrayProperty, StringListValidator
+from mantid.api import AlgorithmFactory, DataProcessorAlgorithm, FileAction, FileProperty, \
+    PropertyMode, WorkspaceProperty
+from mantid.simpleapi import AlignDetectors, CloneWorkspace, CompressEvents, \
+    ConvertUnits, CreateGroupingWorkspace, CropWorkspace, DeleteWorkspace, DiffractionFocussing, \
+    Divide, EditInstrumentGeometry, GetIPTS, Load, LoadMask, LoadNexusProcessed, \
+    LoadPreNexusLive, MaskDetectors, NormaliseByCurrent, PreprocessDetectorsToMD, Rebin, \
+    RenameWorkspace, ReplaceSpecialValues, RemovePromptPulse, SaveAscii, SaveFocusedXYE, \
+    SaveGSS, SaveNexusProcessed, mtd
+import os
+import numpy as np
+
+
+class SNAPReduce(DataProcessorAlgorithm):
+    IPTS_dir = None
+
+    def get_IPTS_Local(self, run):
+        if self.IPTS_dir is None:
+            self.IPTS_dir = GetIPTS(Instrument='SNAP',
+                                    RunNumber=str(run))
+        return self.IPTS_dir
+
+    def smooth(self, data, order):
+        # This smooths data based on linear weigthed average around
+        # point i for example for an order of 7 the i point is
+        # weighted 4, i=/- 1 weighted 3, i+/-2 weighted 2 and i+/-3
+        # weighted 1 this input is only the y values
+        sm = np.zeros(len(data))
+        factor = order / 2 + 1
+
+        for i in range(len(data)):
+            temp = 0
+            ave = 0
+            for r in range(max(0, i - int(order / 2)),
+                           min(i + int(order / 2), len(data) - 1) + 1):
+                temp = temp + (factor - abs(r - i)) * data[r]
+                ave = ave + factor - abs(r - i)
+            sm[i] = temp / ave
+
+        return sm
+
+    def LLS_transformation(self, input):
+        # this transforms data to be more sensitive to weak peaks. The
+        # function is reversed by the Inv_LLS function below
+        out = np.log(np.log((input + 1)**0.5 + 1) + 1)
+
+        return out
+
+    def Inv_LLS_transformation(self, input):
+        # See Function LLS function above
+        out = (np.exp(np.exp(input) - 1) - 1)**2 - 1
+
+        return out
+
+    def peak_clip(self, data, win=30, decrese=True, LLS=True, smooth_window=0):
+        start_data = np.copy(data)
+
+        window = win
+        self.log().information(str(smooth_window))
+
+        if smooth_window > 0:
+            data = self.smooth(data, smooth_window)
+
+        if LLS:
+            data = self.LLS_transformation(data)
+
+        temp = data.copy()
+
+        if decrese:
+            scan = list(range(window + 1, 0, -1))
+        else:
+            scan = list(range(1, window + 1))
+
+        for w in scan:
+            for i in range(len(temp)):
+                if i < w or i > (len(temp) - w - 1):
+                    continue
+                else:
+                    win_array = temp[i - w:i + w + 1].copy()
+                    win_array_reversed = win_array[::-1]
+                    average = (win_array + win_array_reversed) / 2
+                    temp[i] = np.min(average[:len(average) / 2])
+
+        if LLS:
+            temp = self.Inv_LLS_transformation(temp)
+
+        self.log().information(str(min(start_data - temp)))
+
+        index = np.where((start_data - temp) == min(start_data - temp))[0][0]
+
+        output = temp * (start_data[index] / temp[index])
+
+        return output
+
+    def category(self):
+        return "Diffraction\\Reduction"
+
+    def PyInit(self):
+
+        validator = IntArrayBoundedValidator()
+        validator.setLower(0)
+        self.declareProperty(IntArrayProperty("RunNumbers", values=[0], direction=Direction.Input,
+                                              validator=validator),
+                             "Run numbers to process, comma separated")
+
+        self.declareProperty("LiveData", False,
+                             "Read live data - requires a saved run in the current IPTS "
+                             + "with the same Instrument configuration as the live run")
+
+        mask = ["None", "Horizontal", "Vertical",
+                "Masking Workspace", "Custom - xml masking file"]
+        self.declareProperty("Masking", "None", StringListValidator(mask),
+                             "Mask to be applied to the data")
+
+        self.declareProperty(WorkspaceProperty("MaskingWorkspace", "",
+                                               Direction.Input, PropertyMode.Optional),
+                             "The workspace containing the mask.")
+
+        self.declareProperty(FileProperty(name="MaskingFilename", defaultValue="",
+                                          direction=Direction.Input,
+                                          action=FileAction.OptionalLoad),
+                             doc="The file containing the xml mask.")
+
+        self.declareProperty(name="Calibration", defaultValue="Convert Units",
+                             validator=StringListValidator(
+                                 ["Convert Units", "Calibration File"]),
+                             direction=Direction.Input,
+                             doc="The type of conversion to d_spacing to be used.")
+
+        self.declareProperty(FileProperty(name="CalibrationFilename", defaultValue="",
+                                          direction=Direction.Input,
+                                          action=FileAction.OptionalLoad),
+                             doc="The calibration file to convert to d_spacing.")
+
+        self.declareProperty(FloatArrayProperty("Binning", [0.5, -0.004, 7.0]),
+                             "Min, Step, and Max of d-space bins.  Logarithmic binning is used if Step is negative.")
+
+        nor_corr = ["None", "From Workspace",
+                    "From Processed Nexus", "Extracted from Data"]
+        self.declareProperty("Normalization", "None", StringListValidator(nor_corr),
+                             "If needed what type of input to use as normalization, Extracted from "
+                             + "Data uses a background determination that is peak independent.This "
+                             + "implemantation can be tested in algorithm SNAP Peak Clipping Background")
+
+        self.declareProperty(FileProperty(name="NormalizationFilename", defaultValue="",
+                                          direction=Direction.Input,
+                                          action=FileAction.OptionalLoad),
+                             doc="The file containing the processed nexus for normalization.")
+
+        self.declareProperty(WorkspaceProperty("NormalizationWorkspace", "",
+                                               Direction.Input, PropertyMode.Optional),
+                             "The workspace containing the normalization data.")
+
+        self.declareProperty("PeakClippingWindowSize", 10,
+                             "Read live data - requires a saved run in the current "
+                             + "IPTS with the same Instrumnet configuration")
+
+        self.declareProperty("SmoothingRange", 10,
+                             "Read live data - requires a saved run in the "
+                             + "current IPTS with the same Instrumnet configuration")
+
+        grouping = ["All", "Column", "Banks", "Modules", "2_4 Grouping"]
+        self.declareProperty("GroupDetectorsBy", "All", StringListValidator(grouping),
+                             "Detector groups to use for future focussing: "
+                             + "All detectors as one group, Groups (East,West for "
+                             + "SNAP), Columns for SNAP, detector banks")
+
+        mode = ["Set-Up", "Production"]
+        self.declareProperty("ProcessingMode", "Production", StringListValidator(mode),
+                             "Set-Up Mode is used for establishing correct parameters. Production "
+                             + "Mode only Normalized workspace is kept for each run.")
+
+        self.declareProperty(name="OptionalPrefix", defaultValue="",
+                             direction=Direction.Input,
+                             doc="Optional Prefix to be added to workspaces and output filenames")
+
+        self.declareProperty("SaveData", False,
+                             "Save data in the following formats: Ascii- "
+                             + "d-spacing ,Nexus Processed,GSAS and Fullprof")
+
+        self.declareProperty(FileProperty(name="OutputDirectory", defaultValue="",
+                                          action=FileAction.OptionalDirectory),
+                             doc='Default value is proposal shared directory')
+
+    def validateInputs(self):
+        issues = dict()
+
+        # cross check masking
+        masking = self.getProperty("Masking").value
+        if masking in ("None", "Horizontal", "Vertical"):
+            pass
+        elif masking in ("Custom - xml masking file"):
+            filename = self.getProperty("MaskingFilename").value
+            if len(filename) <= 0:
+                issues[
+                    "MaskingFilename"] = "Masking=\"%s\" requires a filename" % masking
+        elif masking == "Masking Workspace":
+            mask_workspace = self.getPropertyValue("MaskingWorkspace")
+            if mask_workspace is None or len(mask_workspace) <= 0:
+                issues["MaskingWorkspace"] = "Must supply masking workspace"
+        else:
+            raise RuntimeError("Masking value \"%s\" not supported" % masking)
+
+        # cross check normalization
+        normalization = self.getProperty("Normalization").value
+        if normalization in ("None", "Extracted from Data"):
+            pass
+        elif normalization == "From Workspace":
+            norm_workspace = self.getPropertyValue("NormalizationWorkspace")
+            if norm_workspace is None:
+                issues['NormalizationWorkspace'] = 'Cannot be unset'
+        elif normalization == "From Processed Nexus":
+            filename = self.getProperty("NormalizationFilename").value
+            if len(filename) <= 0:
+                issues["NormalizationFilename"] = "Normalization=\"%s\" requires a filename" \
+                                                  % normalization
+        else:
+            raise RuntimeError(
+                "Normalization value \"%s\" not supported" % normalization)
+
+        return issues
+
+    def _getMaskWSname(self):
+        masking = self.getProperty("Masking").value
+        maskWSname = None
+        maskFile = None
+
+        # none and workspace are special
+        if masking == 'None':
+            pass
+        elif masking == "Masking Workspace":
+            maskWSname = str(self.getProperty("MaskingWorkspace").value)
+
+        # deal with files
+        elif masking == 'Custom - xml masking file':
+            maskWSname = 'CustomMask'
+            maskFile = self.getProperty('MaskingFilename').value
+        elif masking == 'Horizontal' or masking == 'Vertical':
+            maskWSname = masking + 'Mask' # append the work 'Mask' for the wksp name
+            if not mtd.doesExist(maskWSname): # only load if it isn't already loaded
+                maskFile = '/SNS/SNAP/shared/libs/%s_Mask.xml' % masking
+
+        if maskFile is not None:
+            LoadMask(InputFile=maskFile, Instrument='SNAP', OutputWorkspace=maskWSname)
+
+        return maskWSname
+
+    def _generateNormalization(self, WS, normType, normWS):
+        if normType == 'None':
+            return None
+        elif normType == "Extracted from Data":
+            window = self.getProperty("PeakClippingWindowSize").value
+
+            smooth_range = self.getProperty("SmoothingRange").value
+
+            peak_clip_WS = CloneWorkspace(WS)
+            n_histo = peak_clip_WS.getNumberHistograms()
+
+            x = peak_clip_WS.extractX()
+            y = peak_clip_WS.extractY()
+            e = peak_clip_WS.extractE()
+
+            for h in range(n_histo):
+                peak_clip_WS.setX(h, x[h])
+                peak_clip_WS.setY(h, self.peak_clip(y[h], win=window, decrese=True,
+                                                    LLS=True, smooth_window=smooth_range))
+                peak_clip_WS.setE(h, e[h])
+            return peak_clip_WS
+        else: # other values are already held in normWS
+            return normWS
+
+    def _save(self, runnumber, basename, norm):
+        if not self.getProperty("SaveData").value:
+            return
+
+        saveDir = self.getProperty("OutputDirectory").value.strip()
+        if len(saveDir) <= 0:
+            self.log().notice('Using default save location')
+            saveDir = os.path.join(
+                self.get_IPTS_Local(runnumber), 'shared', 'data')
+        self.log().notice('Writing to \'' + saveDir + '\'')
+
+        if norm == 'None':
+            SaveNexusProcessed(InputWorkspace='WS_red',
+                               Filename=os.path.join(saveDir, 'nexus', basename + '.nxs'))
+            SaveAscii(InputWorkspace='WS_red',
+                      Filename=os.path.join(saveDir, 'd_spacing', basename + '.dat'))
+            ConvertUnits(InputWorkspace='WS_red', OutputWorkspace='WS_tof',
+                         Target="TOF", AlignBins=False)
+        else:
+            SaveNexusProcessed(InputWorkspace='WS_nor',
+                               Filename=os.path.join(saveDir, 'nexus', basename + '.nxs'))
+            SaveAscii(InputWorkspace='WS_nor',
+                      Filename=os.path.join(saveDir, 'd_spacing', basename + '.dat'))
+            ConvertUnits(InputWorkspace='WS_nor', OutputWorkspace='WS_tof',
+                         Target="TOF", AlignBins=False)
+
+        SaveGSS(InputWorkspace='WS_tof',
+                Filename=os.path.join(saveDir, 'gsas', basename + '.gsa'),
+                Format='SLOG', SplitFiles=False, Append=False, ExtendedHeader=True)
+        SaveFocusedXYE(InputWorkspace='WS_tof',
+                       Filename=os.path.join(
+                           saveDir, 'fullprof', basename + '.dat'),
+                       SplitFiles=True, Append=False)
+        DeleteWorkspace(Workspace='WS_tof')
+
+    def PyExec(self):
+        # Retrieve all relevant notice
+
+        in_Runs = self.getProperty("RunNumbers").value
+
+        maskWSname = self._getMaskWSname()
+
+        calib = self.getProperty("Calibration").value
+        if calib == "Calibration File":
+            cal_File = self.getProperty("CalibrationFilename").value
+
+        params = self.getProperty("Binning").value
+        norm = self.getProperty("Normalization").value
+
+        if norm == "From Processed Nexus":
+            norm_File = self.getProperty("Normalization filename").value
+            normWS = LoadNexusProcessed(Filename=norm_File)
+        elif norm == "From Workspace":
+            normWS = self.getProperty("NormalizationWorkspace").value
+        else:
+            normWS = None
+
+        group_to_real = {'Banks':'Group', 'Modules':'bank', '2_4 Grouping':'2_4Grouping'}
+        group = self.getProperty('GroupDetectorsBy').value
+        real_name = group_to_real.get(group, group)
+
+        if not mtd.doesExist(group):
+            if group == '2_4 Grouping':
+                group = '2_4_Grouping'
+            CreateGroupingWorkspace(InstrumentName='SNAP', GroupDetectorsBy=real_name,
+                                    OutputWorkspace=group)
+
+        Process_Mode = self.getProperty("ProcessingMode").value
+
+        prefix = self.getProperty("OptionalPrefix").value
+
+        # --------------------------- REDUCE DATA -----------------------------
+
+        Tag = 'SNAP'
+        for r in in_Runs:
+            self.log().notice("processing run %s" % r)
+            self.log().information(str(self.get_IPTS_Local(r)))
+            if self.getProperty("LiveData").value:
+                Tag = 'Live'
+                WS = LoadPreNexusLive(Instrument='SNAP')
+            else:
+                WS = Load(Filename='SNAP' + str(r), Outputworkspace='WS')
+                WS = NormaliseByCurrent(InputWorkspace=WS,
+                                        Outputworkspace='WS')
+
+            WS = CompressEvents(InputWorkspace=WS, Outputworkspace='WS')
+            WS = CropWorkspace(InputWorkspace='WS',
+                               OutputWorkspace='WS', XMax=50000)
+            WS = RemovePromptPulse(InputWorkspace=WS, OutputWorkspace='WS',
+                                   Width='1600', Frequency='60.4')
+
+            if maskWSname is not None:
+                WS = MaskDetectors(Workspace=WS, MaskedWorkspace=maskWSname)
+
+            if calib == "Convert Units":
+                WS_d = ConvertUnits(InputWorkspace='WS',
+                                    Target='dSpacing', Outputworkspace='WS_d')
+            else:
+                self.log().notice("\n calibration file : %s" % cal_File)
+                WS_d = AlignDetectors(
+                    InputWorkspace='WS', CalibrationFile=cal_File, Outputworkspace='WS_d')
+
+            WS_d = Rebin(InputWorkspace=WS_d, Params=params,
+                         Outputworkspace='WS_d')
+
+            WS_red = DiffractionFocussing(InputWorkspace=WS_d, GroupingWorkspace=group,
+                                          PreserveEvents=False)
+
+            normWS = self._generateNormalization(WS_red, norm, normWS)
+            WS_nor = None
+            if normWS is not None:
+                WS_nor = Divide(LHSWorkspace=WS_red, RHSWorkspace=normWS)
+                WS_nor = ReplaceSpecialValues(Inputworkspace=WS_nor,
+                                              NaNValue='0', NaNError='0',
+                                              InfinityValue='0', InfinityError='0')
+
+            new_Tag = Tag
+            if len(prefix) > 0:
+                new_Tag += '_' + prefix
+
+            # Edit instrument geomety to make final workspace smaller on disk
+            det_table = PreprocessDetectorsToMD(Inputworkspace='WS_red',
+                                                OutputWorkspace='__SNAP_det_table')
+            polar = np.degrees(det_table.column('TwoTheta'))
+            azi = np.degrees(det_table.column('Azimuthal'))
+            EditInstrumentGeometry(Workspace="WS_red", L2=det_table.column('L2'),
+                                   Polar=polar, Azimuthal=azi)
+            if WS_nor is not None:
+                EditInstrumentGeometry(Workspace="WS_nor", L2=det_table.column('L2'),
+                                       Polar=polar, Azimuthal=azi)
+            mtd.remove('__SNAP_det_table')
+
+            # Save requested formats
+            basename = '%s_%s_%s' % (new_Tag, r, group)
+            self._save(r, basename, norm)
+
+            # temporary workspace no longer needed
+            DeleteWorkspace(Workspace='WS')
+
+            # rename everything as appropriate and determine output workspace name
+            RenameWorkspace(Inputworkspace='WS_d',
+                            OutputWorkspace='%s_%s_d' % (new_Tag, r))
+            RenameWorkspace(Inputworkspace='WS_red',
+                            OutputWorkspace=basename + '_red')
+            if norm == 'None':
+                outputWksp = basename + '_red'
+            else:
+                outputWksp = basename + '_nor'
+                RenameWorkspace(Inputworkspace='WS_nor',
+                                OutputWorkspace=basename + '_nor')
+            if norm == "Extracted from Data":
+                RenameWorkspace(Inputworkspace='peak_clip_WS',
+                                OutputWorkspace='%s_%s_normalizer' % (new_Tag, r))
+
+            # delte some things in production
+            if Process_Mode == "Production":
+                DeleteWorkspace(Workspace='%s_%s_d' % (new_Tag, r)) # was 'WS_d'
+
+                if norm != "None":
+                    DeleteWorkspace(Workspace=basename + '_red') # was 'WS_red'
+
+                if norm == "Extracted from Data":
+                    DeleteWorkspace(Workspace='%s_%s_normalizer' % (new_Tag, r)) # was 'peak_clip_WS'
+
+            propertyName = 'OutputWorkspace_'+str(outputWksp)
+            self.declareProperty(WorkspaceProperty(
+                propertyName, outputWksp, Direction.Output))
+            self.setProperty(propertyName, outputWksp)
+
+AlgorithmFactory.subscribe(SNAPReduce)
diff --git a/Framework/PythonInterface/plugins/algorithms/SNSPowderReduction.py b/Framework/PythonInterface/plugins/algorithms/SNSPowderReduction.py
index 50e0f297f729ae216ec0b830f672ebc46f10b33d..376a9d879ae6551219b96aeb8a30d95f90c5149c 100644
--- a/Framework/PythonInterface/plugins/algorithms/SNSPowderReduction.py
+++ b/Framework/PythonInterface/plugins/algorithms/SNSPowderReduction.py
@@ -95,6 +95,8 @@ def allEventWorkspaces(*args):
 
 
 def getBasename(filename):
+    if type(filename) == list:
+        filename = filename[0]
     name = os.path.split(filename)[-1]
     for extension in EXTENSIONS_NXS:
         name = name.replace(extension, '')
@@ -268,6 +270,11 @@ class SNSPowderReduction(DataProcessorAlgorithm):
         self._outTypes = self.getProperty("SaveAs").value.lower()
 
         samRuns = self.getProperty("Filename").value
+        if type(samRuns[0]) == list:
+            linearizedRuns = []
+            for item in samRuns:
+                linearizedRuns.extend(item)
+            samRuns = linearizedRuns[:] # deep copy
         self._determineInstrument(samRuns[0])
 
         preserveEvents = self.getProperty("PreserveEvents").value
@@ -973,24 +980,22 @@ class SNSPowderReduction(DataProcessorAlgorithm):
         # Determine characterization
         if mtd.doesExist("characterizations"):
             # get the correct row of the table if table workspace 'charactersizations' exists
-
-            #pylint: disable=unused-variable
-            charac = api.PDDetermineCharacterizations(InputWorkspace=wksp_name,
-                                                      Characterizations="characterizations",
-                                                      ReductionProperties="__snspowderreduction",
-                                                      BackRun=self.getProperty("BackgroundNumber").value,
-                                                      NormRun=self.getProperty("VanadiumNumber").value,
-                                                      NormBackRun=self.getProperty("VanadiumBackgroundNumber").value,
-                                                      FrequencyLogNames=self.getProperty("FrequencyLogNames").value,
-                                                      WaveLengthLogNames=self.getProperty("WaveLengthLogNames").value)
+            api.PDDetermineCharacterizations(InputWorkspace=wksp_name,
+                                             Characterizations="characterizations",
+                                             ReductionProperties="__snspowderreduction",
+                                             BackRun=self.getProperty("BackgroundNumber").value,
+                                             NormRun=self.getProperty("VanadiumNumber").value,
+                                             NormBackRun=self.getProperty("VanadiumBackgroundNumber").value,
+                                             FrequencyLogNames=self.getProperty("FrequencyLogNames").value,
+                                             WaveLengthLogNames=self.getProperty("WaveLengthLogNames").value)
         else:
-            charac = api.PDDetermineCharacterizations(InputWorkspace=wksp_name,
-                                                      ReductionProperties="__snspowderreduction",
-                                                      BackRun=self.getProperty("BackgroundNumber").value,
-                                                      NormRun=self.getProperty("VanadiumNumber").value,
-                                                      NormBackRun=self.getProperty("VanadiumBackgroundNumber").value,
-                                                      FrequencyLogNames=self.getProperty("FrequencyLogNames").value,
-                                                      WaveLengthLogNames=self.getProperty("WaveLengthLogNames").value)
+            api.PDDetermineCharacterizations(InputWorkspace=wksp_name,
+                                             ReductionProperties="__snspowderreduction",
+                                             BackRun=self.getProperty("BackgroundNumber").value,
+                                             NormRun=self.getProperty("VanadiumNumber").value,
+                                             NormBackRun=self.getProperty("VanadiumBackgroundNumber").value,
+                                             FrequencyLogNames=self.getProperty("FrequencyLogNames").value,
+                                             WaveLengthLogNames=self.getProperty("WaveLengthLogNames").value)
 
         # convert the result into a dict
         return PropertyManagerDataService.retrieve("__snspowderreduction")
@@ -1244,7 +1249,7 @@ class SNSPowderReduction(DataProcessorAlgorithm):
                 van_run_ws_name = self._loadAndSum([van_run_number], van_run_ws_name, **vanFilterWall)
 
             # load the vanadium background (if appropriate)
-            van_bkgd_run_number_list = self._info["empty"].value
+            van_bkgd_run_number_list = self._info["vanadium_background"].value
             van_bkgd_run_number_list = ['%s_%d' % (self._instrument, value)
                                         for value in van_bkgd_run_number_list]
             if not noRunSpecified(van_bkgd_run_number_list):
diff --git a/Framework/PythonInterface/plugins/algorithms/SavePlot1DAsJson.py b/Framework/PythonInterface/plugins/algorithms/SavePlot1DAsJson.py
index ba4b9d21553df71c87f801906a65d8dc5c92c8f5..6e4a62e6e0c60ec27fb9283e22c3ac24d39b22aa 100644
--- a/Framework/PythonInterface/plugins/algorithms/SavePlot1DAsJson.py
+++ b/Framework/PythonInterface/plugins/algorithms/SavePlot1DAsJson.py
@@ -78,7 +78,7 @@ class SavePlot1DAsJson(PythonAlgorithm):
         return
 
     def _serialize(self, workspace, plotname):
-        pname = plotname or workspace.getName()
+        pname = plotname or workspace.name()
         # init dictionary
         ishist = workspace.isHistogramData()
         plottype = "histogram" if ishist else "point"
diff --git a/Framework/PythonInterface/plugins/algorithms/SaveVulcanGSS.py b/Framework/PythonInterface/plugins/algorithms/SaveVulcanGSS.py
index 53782a893abd52a7abdf4c807202faf85a4dc553..e4514e137556fb7a1326aa85ce673ec5281a0345 100644
--- a/Framework/PythonInterface/plugins/algorithms/SaveVulcanGSS.py
+++ b/Framework/PythonInterface/plugins/algorithms/SaveVulcanGSS.py
@@ -1,6 +1,6 @@
 #pylint: disable=no-init,invalid-name
 from __future__ import (absolute_import, division, print_function)
-from six.moves import range #pylint: disable=redefined-builtin
+from six.moves import range  #pylint: disable=redefined-builtin
 import mantid.simpleapi as api
 from mantid.api import *
 from mantid.kernel import *
@@ -29,10 +29,10 @@ class SaveVulcanGSS(PythonAlgorithm):
         """ Declare properties
         """
         self.declareProperty(MatrixWorkspaceProperty("InputWorkspace", "", Direction.Input),
-                             "Focussed diffraction workspace to be exported to GSAS file. ")
+                             "Focused diffraction workspace to be exported to GSAS file. ")
 
-        self.declareProperty(FileProperty("BinFilename","", FileAction.Load, ['.dat']),
-                             "Name of a data file containing the bin boundaries in Log(TOF). ")
+        self.declareProperty(FileProperty("BinFilename", "", FileAction.OptionalLoad, ['.dat']),
+                             "Name of a data file containing the bin boundaries in Log(TOF).")
 
         self.declareProperty(MatrixWorkspaceProperty("OutputWorkspace", "", Direction.Output),
                              "Name of rebinned matrix workspace. ")
@@ -50,13 +50,13 @@ class SaveVulcanGSS(PythonAlgorithm):
         """ Main Execution Body
         """
         # Properties
-        inputwsname = self.getPropertyValue("InputWorkspace")
-        logtoffilename = self.getPropertyValue("BinFilename")
+        input_workspace = self.getPropertyValue("InputWorkspace")
+        log_tof_file_name = self.getPropertyValue("BinFilename")
         outgssfilename = self.getPropertyValue("GSSFilename")
         outputwsname = self.getPropertyValue("OutputWorkspace")
 
         # Check properties
-        inputws = AnalysisDataService.retrieve(inputwsname)
+        inputws = AnalysisDataService.retrieve(input_workspace)
         if inputws is None:
             raise NotImplementedError("Inputworkspace does not exist.")
         if inputws.getAxis(0).getUnit().unitID() != "TOF":
@@ -64,23 +64,28 @@ class SaveVulcanGSS(PythonAlgorithm):
         if inputws.isHistogramData() is False:
             raise NotImplementedError("InputWorkspace must be histogram, but not point data.")
 
-        # Load reference bin file
-        vec_refT = self._loadRefLogBinFile(logtoffilename)
+        # rebin the input workspace if TOF binning file is given
+        if len(log_tof_file_name) > 0:
+            # Load reference bin file
+            vec_refT = self._loadRefLogBinFile(log_tof_file_name)
 
-        # Rebin
-        gsaws = self._rebinVdrive(inputws, vec_refT, outputwsname)
+            # Rebin
+            gsa_ws = self._rebinVdrive(inputws, vec_refT, outputwsname)
+        else:
+            # no binning file is specified. do nothing
+            gsa_ws = inputws
 
         # Generate GSAS file
-        outputws = self._saveGSAS(gsaws, outgssfilename)
+        output_ws = self._saveGSAS(gsa_ws, outgssfilename)
 
         # Convert header and bank information
         ipts = self.getPropertyValue("IPTS")
-        parmfname = self.getPropertyValue("GSSParmFileName")
-        newheader = self._genVulcanGSSHeader(outputws, outgssfilename, ipts, parmfname)
-        self._rewriteGSSFile(outgssfilename, newheader)
+        parm_file_name = self.getPropertyValue("GSSParmFileName")
+        new_header = self._generate_vulcan_gda_header(output_ws, outgssfilename, ipts, parm_file_name)
+        self._rewrite_gda_file(outgssfilename, new_header)
 
         # Set property
-        self.setProperty("OutputWorkspace", outputws)
+        self.setProperty("OutputWorkspace", output_ws)
 
         return
 
@@ -125,6 +130,7 @@ class SaveVulcanGSS(PythonAlgorithm):
         """
         # Create a complicated bin parameter
         params = []
+        dx = None
         for ibin in range(len(vec_refT)-1):
             x0 = vec_refT[ibin]
             xf = vec_refT[ibin+1]
@@ -133,6 +139,7 @@ class SaveVulcanGSS(PythonAlgorithm):
             params.append(dx)
 
         # last bin
+        assert dx is not None, 'Vector of refT has less than 2 values.  It is not supported.'
         x0 = vec_refT[-1]
         xf = 2*dx + x0
         params.extend([x0, 2*dx, xf])
@@ -173,8 +180,12 @@ class SaveVulcanGSS(PythonAlgorithm):
 
         return gsaws
 
-    def _rewriteGSSFile(self, gssfilename, newheader):
-        """ Re-write GSAS file including header and header for each bank
+    def _rewrite_gda_file(self, gssfilename, newheader):
+        """
+        Re-write GSAS file including header and header for each bank
+        :param gssfilename:
+        :param newheader:
+        :return:
         """
         # Get all lines
         gfile = open(gssfilename, "r")
@@ -223,7 +234,7 @@ class SaveVulcanGSS(PythonAlgorithm):
 
         return
 
-    def _genVulcanGSSHeader(self, ws, gssfilename, ipts, parmfname):
+    def _generate_vulcan_gda_header(self, ws, gssfilename, ipts, parmfname):
         """
         """
         from datetime import datetime
@@ -255,7 +266,7 @@ class SaveVulcanGSS(PythonAlgorithm):
                 total_nanosecond_start =  int(delta.total_seconds()*int(1.0E9)) + int(runstart_ns)
             except AttributeError:
                 total_seconds = delta.days*24*3600 + delta.seconds
-                total_nanosecond_start = total_seconds * int(1.0E9)  + int(runstart_ns)
+                total_nanosecond_start = total_seconds * int(1.0E9) + int(runstart_ns)
             total_nanosecond_stop = total_nanosecond_start + int(duration*1.0E9)
         else:
             # not both property is found
@@ -269,21 +280,21 @@ class SaveVulcanGSS(PythonAlgorithm):
 
         if len(title) > 80:
             title = title[0:80]
-        newheader += "%-80s\n" % (title)
+        newheader += "%-80s\n" % title
 
-        newheader += "%-80s\n" % ( "Instrument parameter file: %s" %(parmfname) )
+        newheader += "%-80s\n" % ("Instrument parameter file: %s" % parmfname)
 
-        newheader += "%-80s\n" % ( "#IPTS: %s" % (str(ipts)) )
+        newheader += "%-80s\n" % ("#IPTS: %s" % str(ipts))
 
-        newheader += "%-80s\n" % ( "#binned by: Mantid" )
+        newheader += "%-80s\n" % "#binned by: Mantid"
 
-        newheader += "%-80s\n" % ( "#GSAS file name: %s" % (os.path.basename(gssfilename)) )
+        newheader += "%-80s\n" % ("#GSAS file name: %s" % os.path.basename(gssfilename))
 
-        newheader += "%-80s\n" % ( "#GSAS IPARM file: %s" % (parmfname) )
+        newheader += "%-80s\n" % ("#GSAS IPARM file: %s" % parmfname)
 
-        newheader += "%-80s\n" % ( "#Pulsestart:    %d" % (total_nanosecond_start) )
+        newheader += "%-80s\n" % ("#Pulsestart:    %d" % total_nanosecond_start)
 
-        newheader += "%-80s\n" % ( "#Pulsestop:     %d" % (total_nanosecond_stop) )
+        newheader += "%-80s\n" % ("#Pulsestop:     %d" % total_nanosecond_stop)
 
         return newheader
 
diff --git a/Framework/PythonInterface/plugins/algorithms/SelectPowderDiffPeaks.py b/Framework/PythonInterface/plugins/algorithms/SelectPowderDiffPeaks.py
deleted file mode 100644
index aa579690980709cda05e0a25c69e6246627d82d3..0000000000000000000000000000000000000000
--- a/Framework/PythonInterface/plugins/algorithms/SelectPowderDiffPeaks.py
+++ /dev/null
@@ -1,233 +0,0 @@
-# pylint: disable=no-init,invalid-name
-from __future__ import (absolute_import, division, print_function)
-from six.moves import range  # pylint: disable=redefined-builtin
-from mantid.api import PythonAlgorithm, AlgorithmFactory, ITableWorkspaceProperty, WorkspaceFactory
-from mantid.kernel import Direction
-import warnings
-
-_OUTPUTLEVEL = "NOOUTPUT"
-
-
-class SelectPowderDiffPeaks(PythonAlgorithm):
-    """ Algorithm to select the powder diffraction peaks for Le Bail Fit
-    """
-
-    mPeaks = None
-
-    def category(self):
-        """
-        """
-        return "Diffraction\\Fitting"
-
-    def name(self):
-        """
-        """
-        return "SelectPowderDiffPeaks"
-
-    def summary(self):
-        return "Select the powder diffraction peaks for Le Bail Fit"
-
-    def PyInit(self):
-        """ Declare properties
-        """
-        self.declareProperty(ITableWorkspaceProperty("BraggPeakParameterWorkspace", "", Direction.Input),
-                             "Name of Table Workspace containing peak parameters.")
-
-        self.declareProperty(ITableWorkspaceProperty("ZscoreWorkspace", "", Direction.Input),
-                             "Name of Table Workspace containing z-score for the peak parametrs.")
-
-        self.declareProperty(ITableWorkspaceProperty("OutputBraggPeakParameterWorkspace", "", Direction.Output),
-                             "Name of Table Workspace containing the filtered peaks' parameters.")
-
-        self.declareProperty("MinimumPeakHeight", 0.0, "Minimum peak height allowed for the peaks to fit. ")
-
-        self.declareProperty("ZscoreFilter", "", "Filter on the Zscore of the peak parameters.")
-
-        return
-
-    def PyExec(self):
-        """ Main Execution Body
-        """
-        warnings.warn("A message", ModuleDeprecationWarning)
-
-        # 1. Get Input properties
-        inppeakws = self.getProperty("BraggPeakParameterWorkspace").value
-        inpzscows = self.getProperty("ZscoreWorkspace").value
-
-        minpeakheight = float(self.getPropertyValue("MinimumPeakHeight"))
-        zscorefilterstr = self.getPropertyValue("ZscoreFilter")
-
-        print("Input: PeakParameterWorkspace = %s;  ZscoreWorkspace = %s" % (inppeakws.name, inpzscows.name))
-        print("       Minimum peak height = %f" % (minpeakheight))
-        print("       Zscore filter: %s" % (zscorefilterstr))
-
-        # 3. Parse Zscore table and peak parameters
-        self.mPeaks = {}
-
-        zscoredict = self.parseBraggPeakParameterTable(inpzscows)
-        self.mPeaks = self.parseBraggPeakParameterTable(inppeakws)
-
-        # 4. Filter by peak height
-        self.filterByPeakHeight(minpeakheight)
-
-        # 5. Filter by zscore
-        zscorefilterdict = self.parseZscoreFilter(zscorefilterstr)
-        self.filterByZscore(zscoredict, zscorefilterdict)
-
-        # 6. Generate the output
-        paramWS = WorkspaceFactory.createTable()
-        self.genBraggPeakParameterWorkspace(paramWS)
-        self.setProperty("OutputBraggPeakParameterWorkspace", paramWS)
-
-        return
-
-    def genBraggPeakParameterWorkspace(self, tablews):
-        """ Create TableWorkspace containing peak parameters
-        """
-        # 1. Create an empty workspace and set the column
-        tablews.addColumn("int", "H")
-        tablews.addColumn("int", "K")
-        tablews.addColumn("int", "L")
-        tablews.addColumn("double", "d_h")
-        tablews.addColumn("double", "TOF_h")
-        tablews.addColumn("double", "Height")
-        tablews.addColumn("double", "Alpha")
-        tablews.addColumn("double", "Beta")
-        tablews.addColumn("double", "Sigma")
-
-        # 2. Sort the dictionary by d-spacing
-        dspdict = {}
-        for hkl in self.mPeaks:
-            dsp = self.mPeaks[hkl]["d_h"]
-            dspdict[dsp] = hkl
-        dhs = list(dspdict.keys())
-        dhs = sorted(dhs)
-
-        # 3. Add peaks
-        for dsp in dhs:
-            hkl = dspdict[dsp]
-
-            h = hkl[0]
-            k = hkl[1]
-            l = hkl[2]
-
-            tof_h = self.mPeaks[hkl]["TOF_h"]
-            height = self.mPeaks[hkl]["Height"]
-            alpha = self.mPeaks[hkl]["Alpha"]
-            beta = self.mPeaks[hkl]["Beta"]
-            sigma = self.mPeaks[hkl]["Sigma"]
-
-            tablews.addRow([h, k, l, dsp, tof_h, height, alpha, beta, sigma])
-        # ENDFOR
-
-        return tablews
-
-    def parseBraggPeakParameterTable(self, tablews):
-        """ Parse Zscore parameter table workspace
-        Return: zscoredict
-        """
-        numrows = tablews.rowCount()
-        numcols = tablews.columnCount()
-        colnames = tablews.getColumnNames()
-
-        peakparameterdict = {}
-
-        for irow in range(numrows):
-            ppdict = {}
-            for icol in range(numcols):
-                colname = colnames[icol]
-                value = tablews.cell(irow, icol)
-                ppdict[colname] = value
-            # ENDFOR Column
-            h = ppdict["H"]
-            k = ppdict["K"]
-            l = ppdict["L"]
-
-            peakparameterdict[(h, k, l)] = ppdict
-        # ENDFOR
-
-        return peakparameterdict
-
-    def filterByPeakHeight(self, minpeakheight):
-        """ Filter by peak height
-        """
-        for hkl in self.mPeaks:
-            height = self.mPeaks[hkl]["Height"]
-            wbuf = "Peak %d %d %d:  Height = %f " % (hkl[0], hkl[1], hkl[2], height)
-            if height < minpeakheight:
-                self.mPeaks.pop(hkl)
-                wbuf += "Removed due to height < %f" % (minpeakheight)
-            else:
-                # wbuf += "Kept due to height > %f" % (minpeakheight)
-                pass
-
-            print(wbuf)
-        # ENDFOR
-
-        return
-
-    def filterByZscore(self, zscoredict, zscorefilter):
-        """ Filter by zscore
-        """
-        # 1. Loop over peaks
-        for hkl in self.mPeaks:
-
-            zscores = zscoredict[hkl]
-
-            deletethispeak = False
-            errmsgout = False
-
-            # 2. Loop over zscore filters
-            for parname in zscorefilter:
-                # Maximum allowed Z score
-                maxzscore = zscorefilter[parname]
-                # Convert to regular parameter name to parameter name in Zcore workspace
-                zparname = "Z_" + parname
-                if zparname in zscores:
-                    # Zscore table has this parameter's zscore
-                    zscore = zscores[zparname]
-                    if zscore > maxzscore:
-                        deletethispeak = True
-                        break
-                        # ENDIF
-                else:
-                    # Zscore table has no such parameter
-                    print("Warning! Zscore table has no parameter %s (from %s)" % (zparname, parname))
-                    errmsgout = True
-                    # ENDIF
-            # ENDFOR Fitler
-
-            # 3. Delete if
-            if deletethispeak is True:
-                self.mPeaks.pop(hkl)
-
-            if errmsgout is True:
-                msg = "Parameters (keys):\t\t"
-                for key in zscores:
-                    msg += "%s,\t\t" % (key)
-                print(msg)
-
-        # ENDFOR Each Peak
-
-        return
-
-    def parseZscoreFilter(self, zscorefilterstr):
-        """ Parse Zscore filter string
-        Return: zscore filter dictionary Parameter Name: Maximum Allowed
-        """
-        zscorefilter = {}
-
-        terms = zscorefilterstr.split(',')
-        if len(terms) % 2 == 1:
-            raise NotImplementedError("Zscore filter is not defined correct.  It must have string and float in pair.")
-
-        for i in range(len(terms) / 2):
-            parname = terms[2 * i].strip()
-            maxzscore = float(terms[2 * i + 1])
-            zscorefilter[parname] = maxzscore
-
-        return zscorefilter
-
-
-# Register algorithm with Mantid
-AlgorithmFactory.subscribe(SelectPowderDiffPeaks)
diff --git a/Framework/PythonInterface/plugins/algorithms/SetDetScale.py b/Framework/PythonInterface/plugins/algorithms/SetDetScale.py
index 2f5f11ef6c3d3994663ced466318bc07d48220d7..914c5699b7e3dd05e4050cc41320865d38bdf47b 100644
--- a/Framework/PythonInterface/plugins/algorithms/SetDetScale.py
+++ b/Framework/PythonInterface/plugins/algorithms/SetDetScale.py
@@ -1,6 +1,6 @@
 from __future__ import (absolute_import, division, print_function)
 
-from mantid.api import PythonAlgorithm, AlgorithmFactory, WorkspaceProperty, InstrumentValidator
+from mantid.api import PythonAlgorithm, AlgorithmFactory, WorkspaceProperty, InstrumentValidator, FileProperty, FileAction
 from mantid.kernel import Direction, StringArrayProperty
 import mantid.simpleapi as api
 
@@ -40,6 +40,11 @@ class SetDetScale(PythonAlgorithm):
                                                  direction=Direction.Input),
                              doc="Comma separated list detectorNumbers:detScales eg. 13:1.046504,14:1.259293")
 
+        self.declareProperty(FileProperty(name="DetScaleFile", defaultValue="",
+                                          action=FileAction.OptionalLoad,
+                                          extensions=["txt"]),
+                             "Optional text file with detector number and its scale on each line separated by spaces")
+
     def PyExec(self):
         ws = self.getProperty("Workspace").value
 
@@ -47,9 +52,26 @@ class SetDetScale(PythonAlgorithm):
         components = self.getProperty("DetScaleList").value
 
         listParse = []
+        scaleDict = {}
+
+        #Read scales from file
+        sc_filename = self.getProperty("DetScaleFile").value
+        if sc_filename:
+            scfile = open(sc_filename, "r")
+            lines = scfile.readlines()
+            for line in lines:
+                columns = line.split() # splits on whitespace characters
+                key = columns[0]
+                scaleDict[key] = columns[1]
+
+        #Overwrite any scales given in file
         for component in components:
             comp, value = component.split(":")
-            listParse.append({"ParameterName":"detScale"+comp, "Value":value})
+            key = comp
+            scaleDict[key] = value
+
+        for key in scaleDict.keys():
+            listParse.append({"ParameterName":"detScale"+key, "Value":scaleDict[key]})
 
         for dList in listParse:
             api.SetInstrumentParameter(Workspace=ws,ParameterType="Number",**dList)
diff --git a/Framework/PythonInterface/plugins/algorithms/UpdatePeakParameterTableValue.py b/Framework/PythonInterface/plugins/algorithms/UpdatePeakParameterTableValue.py
index 13a1d28b8663676671a1cd0a61afe482d5ae64de..3ccd01c33615c0221f4185ddf562a153cb028352 100644
--- a/Framework/PythonInterface/plugins/algorithms/UpdatePeakParameterTableValue.py
+++ b/Framework/PythonInterface/plugins/algorithms/UpdatePeakParameterTableValue.py
@@ -169,7 +169,7 @@ class UpdatePeakParameterTableValue(mantid.api.PythonAlgorithm):
         # 2. Take in the case that there is no match
         if len(rownumbers) == 0:
             # No Match
-            logger.warning("Warning! There is no match for parameter %s" % (parnametofit))
+            mantid.logger.warning("Warning! There is no match for parameter %s" % (parnametofit))
             rownumbers.append(-1000)
         # ENDIFELSE
 
diff --git a/Framework/PythonInterface/plugins/algorithms/VisionLoadDetectorTable.py b/Framework/PythonInterface/plugins/algorithms/VisionLoadDetectorTable.py
deleted file mode 100644
index c637316e76acb79dc236e3aa6440fafce838c5da..0000000000000000000000000000000000000000
--- a/Framework/PythonInterface/plugins/algorithms/VisionLoadDetectorTable.py
+++ /dev/null
@@ -1,49 +0,0 @@
-#pylint: disable=no-init,invalid-name
-from __future__ import (absolute_import, division, print_function)
-
-from mantid.api import *
-from mantid.simpleapi import *
-from mantid.kernel import *
-import numpy as np
-
-
-class VisionLoadDetectorTable(PythonAlgorithm):
-
-    def category(self):
-        return "Utility\\Development"
-
-    def summary(self):
-        return "Warning - This is under development - Algorithm to load detector parameters for VISION."
-
-    def PyInit(self):
-        self.declareProperty(WorkspaceProperty("OutputWorkspace", "", Direction.Output),
-                             doc="Name of Output Workspace")
-
-        self.declareProperty(FileProperty("DetectorFile", "", action=FileAction.Load, extensions=['csv']),
-                             doc="Name of detector file to load.")
-
-    def PyExec(self):
-        filename = self.getPropertyValue("DetectorFile")
-        output_ws_name = self.getPropertyValue("OutputWorkspace")
-
-        # Open File and read parameters
-        spectra,l1,l2,twotheta,efixed,emode = np.genfromtxt(filename, delimiter=',', unpack=True)
-
-        # Setup the output table
-        output_workspace = CreateEmptyTableWorkspace(OutputWorkspace=output_ws_name)
-        output_workspace.addColumn("int", "spectra")
-        output_workspace.addColumn("double", "l1")
-        output_workspace.addColumn("double", "l2")
-        output_workspace.addColumn("double", "twotheta")
-        output_workspace.addColumn("double", "efixed")
-        output_workspace.addColumn("int", "emode")
-
-        # Write the values
-        for i in range(len(spectra)):
-            output_workspace.addRow([int(spectra[i]),float(l1[i]),float(l2[i]),
-                                     float(twotheta[i]),float(efixed[i]),int(emode[i])])
-
-        # Set the output workspace
-        self.setProperty("OutputWorkspace", output_workspace)
-
-AlgorithmFactory.subscribe(VisionLoadDetectorTable)
diff --git a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ElasticWindowMultiple.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ElasticWindowMultiple.py
index f3ad42addd96ff22857b4cfe8a019293916174a0..a911f07c447a7982591a8e4aa66e70b42113204c 100644
--- a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ElasticWindowMultiple.py
+++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ElasticWindowMultiple.py
@@ -1,4 +1,3 @@
-#pylint: disable=no-init,too-many-instance-attributes,too-many-branches
 from __future__ import (absolute_import, division, print_function)
 
 from mantid.simpleapi import *
@@ -13,18 +12,17 @@ def _normalize_to_lowest_temp(elt_ws_name):
     @param elt_ws_name Name of the ELT workspace
     """
 
-    num_hist = mtd[elt_ws_name].getNumberHistograms()
+    num_hist = elt_ws_name.getNumberHistograms()
 
     # Normalize each spectrum in the workspace
     for idx in range(0, num_hist):
-        y_vals = mtd[elt_ws_name].readY(idx)
+        y_vals = elt_ws_name.readY(idx)
         scale = 1.0 / y_vals[0]
         y_vals_scaled = scale * y_vals
-        mtd[elt_ws_name].setY(idx, y_vals_scaled)
+        elt_ws_name.setY(idx, y_vals_scaled)
 
 
 class ElasticWindowMultiple(DataProcessorAlgorithm):
-
     _sample_log_name = None
     _sample_log_value = None
     _input_workspaces = None
@@ -99,8 +97,6 @@ class ElasticWindowMultiple(DataProcessorAlgorithm):
         # Do setup
         self._setup()
 
-        logger.debug('in_ws:'+str(type(self._input_workspaces)))
-
         # Get input workspaces
         input_workspace_names = self._input_workspaces.getNames()
 
@@ -108,88 +104,92 @@ class ElasticWindowMultiple(DataProcessorAlgorithm):
         q_workspaces = list()
         q2_workspaces = list()
         run_numbers = list()
-        temperatures = list()
+        sample_param = list()
+
+        progress = Progress(self, 0.0, 0.05, 3)
 
         # Perform the ElasticWindow algorithms
         for input_ws in input_workspace_names:
+
             logger.information('Running ElasticWindow for workspace: %s' % input_ws)
+            progress.report('ElasticWindow for workspace: %s' % input_ws)
 
             q_ws = '__' + input_ws + '_q'
             q2_ws = '__' + input_ws + '_q2'
 
+            elwin_alg = self.createChildAlgorithm("ElasticWindow", enableLogging=False)
+            elwin_alg.setProperty("InputWorkspace", input_ws)
+            elwin_alg.setProperty("IntegrationRangeStart", self._integration_range_start)
+            elwin_alg.setProperty("IntegrationRangeEnd", self._integration_range_end)
+            elwin_alg.setProperty("OutputInQ", q_ws)
+            elwin_alg.setProperty("OutputInQSquared", q2_ws)
+
             if self._background_range_start != Property.EMPTY_DBL and self._background_range_end != Property.EMPTY_DBL:
-                ElasticWindow(InputWorkspace=input_ws,
-                              OutputInQ=q_ws,
-                              OutputInQSquared=q2_ws,
-                              IntegrationRangeStart=self._integration_range_start,
-                              IntegrationRangeEnd=self._integration_range_end,
-                              BackgroundRangeStart=self._background_range_start,
-                              BackgroundRangeEnd=self._background_range_end)
-            else:
-                ElasticWindow(InputWorkspace=input_ws,
-                              OutputInQ=q_ws,
-                              OutputInQSquared=q2_ws,
-                              IntegrationRangeStart=self._integration_range_start,
-                              IntegrationRangeEnd=self._integration_range_end)
+                elwin_alg.setProperty("BackgroundRangeStart", self._background_range_start)
+                elwin_alg.setProperty("BackgroundRangeEnd", self._background_range_end)
+
+            elwin_alg.execute()
 
-            Logarithm(InputWorkspace=q2_ws,
-                      OutputWorkspace=q2_ws)
+            log_alg = self.createChildAlgorithm("Logarithm", enableLogging=False)
+            log_alg.setProperty("InputWorkspace", elwin_alg.getProperty("OutputInQSquared").value)
+            log_alg.setProperty("OutputWorkspace", q2_ws)
+            log_alg.execute()
 
-            q_workspaces.append(q_ws)
-            q2_workspaces.append(q2_ws)
+            q_workspaces.append(elwin_alg.getProperty("OutputInQ").value)
+            q2_workspaces.append(log_alg.getProperty("OutputWorkspace").value)
 
             # Get the run number
             run_no = getInstrRun(input_ws)[1]
             run_numbers.append(run_no)
 
-            # Get the sample temperature
-            temp = self._get_temperature(input_ws)
-            if temp is not None:
-                temperatures.append(temp)
+            # Get the sample environment unit
+            sample, unit = self._get_sample_units(input_ws)
+            if sample is not None:
+                sample_param.append(sample)
             else:
-                # No need to output a tmperature workspace if there are no temperatures
+                # No need to output a temperature workspace if there are no temperatures
                 self._elt_workspace = ''
 
         logger.information('Creating Q and Q^2 workspaces')
+        progress.report('Creating Q workspaces')
 
         if len(input_workspace_names) == 1:
             # Just rename single workspaces
-            RenameWorkspace(InputWorkspace=q_workspaces[0],
-                            OutputWorkspace=self._q_workspace)
-            RenameWorkspace(InputWorkspace=q2_workspaces[0],
-                            OutputWorkspace=self._q2_workspace)
+            self._q_workspace = elwin_alg.getProperty("OutputInQ").value
+            self._q2_workspace = log_alg.getProperty("OutputWorkspace").value
         else:
             # Append the spectra of the first two workspaces
-            AppendSpectra(InputWorkspace1=q_workspaces[0],
-                          InputWorkspace2=q_workspaces[1],
-                          OutputWorkspace=self._q_workspace)
-            AppendSpectra(InputWorkspace1=q2_workspaces[0],
-                          InputWorkspace2=q2_workspaces[1],
-                          OutputWorkspace=self._q2_workspace)
+            append_alg = self.createChildAlgorithm("AppendSpectra", enableLogging=False)
+            append_alg.setProperty("InputWorkspace1", q_workspaces[0])
+            append_alg.setProperty("InputWorkspace2", q_workspaces[1])
+            append_alg.setProperty("OutputWorkspace", self._q_workspace)
+            append_alg.execute()
+            self._q_workspace = append_alg.getProperty("OutputWorkspace").value
+            append_alg.setProperty("InputWorkspace1", q2_workspaces[0])
+            append_alg.setProperty("InputWorkspace2", q2_workspaces[1])
+            append_alg.setProperty("OutputWorkspace", self._q2_workspace)
+            append_alg.execute()
+            self._q2_workspace = append_alg.getProperty("OutputWorkspace").value
 
             # Append to the spectra of each remaining workspace
             for idx in range(2, len(input_workspace_names)):
-                AppendSpectra(InputWorkspace1=self._q_workspace,
-                              InputWorkspace2=q_workspaces[idx],
-                              OutputWorkspace=self._q_workspace)
-                AppendSpectra(InputWorkspace1=self._q2_workspace,
-                              InputWorkspace2=q2_workspaces[idx],
-                              OutputWorkspace=self._q2_workspace)
-
-            # Delete the output workspaces from the ElasticWindow algorithms
-            for q_ws in q_workspaces:
-                DeleteWorkspace(q_ws)
-            for q2_ws in q2_workspaces:
-                DeleteWorkspace(q2_ws)
-
-        logger.information('Setting vertical axis units and values')
-
-        # Set the verical axis units
-        v_axis_is_temp = len(input_workspace_names) == len(temperatures)
-
-        if v_axis_is_temp:
-            logger.notice('Vertical axis is in temperature')
-            unit = ('Temperature', 'K')
+                append_alg.setProperty("InputWorkspace1", self._q_workspace)
+                append_alg.setProperty("InputWorkspace2", q_workspaces[idx])
+                append_alg.setProperty("OutputWorkspace", self._q_workspace)
+                append_alg.execute()
+                self._q_workspace = append_alg.getProperty("OutputWorkspace").value
+                append_alg.setProperty("InputWorkspace1", self._q2_workspace)
+                append_alg.setProperty("InputWorkspace2", q2_workspaces[idx])
+                append_alg.setProperty("OutputWorkspace", self._q2_workspace)
+                append_alg.execute()
+                self._q2_workspace = append_alg.getProperty("OutputWorkspace").value
+
+        # Set the vertical axis units
+        v_axis_is_sample = len(input_workspace_names) == len(sample_param)
+
+        if v_axis_is_sample:
+            logger.notice('Vertical axis is in units of %s' % unit)
+            unit = (self._sample_log_name, unit)
         else:
             logger.notice('Vertical axis is in run number')
             unit = ('Run No', 'last 3 digits')
@@ -203,27 +203,33 @@ class ElasticWindowMultiple(DataProcessorAlgorithm):
 
         # Set the vertical axis values
         for idx in range(0, len(input_workspace_names)):
-            if v_axis_is_temp:
-                q_ws_axis.setValue(idx, float(temperatures[idx]))
-                q2_ws_axis.setValue(idx, float(temperatures[idx]))
+            if v_axis_is_sample:
+                q_ws_axis.setValue(idx, float(sample_param[idx]))
+                q2_ws_axis.setValue(idx, float(sample_param[idx]))
             else:
                 q_ws_axis.setValue(idx, float(run_numbers[idx][-3:]))
                 q2_ws_axis.setValue(idx, float(run_numbers[idx][-3:]))
 
         # Add the new vertical axis to each workspace
-        mtd[self._q_workspace].replaceAxis(1, q_ws_axis)
-        mtd[self._q2_workspace].replaceAxis(1, q2_ws_axis)
+        self._q_workspace.replaceAxis(1, q_ws_axis)
+        self._q2_workspace.replaceAxis(1, q2_ws_axis)
 
+        progress.report('Creating ELF workspaces')
+        transpose_alg = self.createChildAlgorithm("Transpose", enableLogging=False)
+        transpose_alg.setAlwaysStoreInADS(True)
+        sort_alg = self.createChildAlgorithm("SortXAxis", enableLogging=False)
         # Process the ELF workspace
         if self._elf_workspace != '':
             logger.information('Creating ELF workspace')
+            transpose_alg.setProperty("InputWorkspace", self._q_workspace)
+            transpose_alg.setProperty("OutputWorkspace", self._elf_workspace)
+            transpose_alg.execute()
 
-            Transpose(InputWorkspace=self._q_workspace,
-                      OutputWorkspace=self._elf_workspace)
-            SortXAxis(InputWorkspace=self._elf_workspace,
-                      OutputWorkspace=self._elf_workspace)
+            sort_alg.setProperty("InputWorkspace", self._elf_workspace)
+            sort_alg.setProperty("OutputWorkspace", self._elf_workspace)
+            sort_alg.execute()
 
-            self.setProperty('OutputELF', self._elf_workspace)
+            self.setProperty('OutputELF', sort_alg.getProperty("OutputWorkspace").value)
 
         # Do temperature normalisation
         if self._elt_workspace != '':
@@ -232,13 +238,19 @@ class ElasticWindowMultiple(DataProcessorAlgorithm):
             # If the ELT workspace was not already created then create it here,
             # otherwise just clone it
             if self._elf_workspace == '':
-                Transpose(InputWorkspace=self._q_workspace,
-                          OutputWorkspace=self._elt_workspace)
-                SortXAxis(InputWorkspace=self._elt_workspace,
-                          OutputWorkspace=self._elt_workspace)
+                transpose_alg.setProperty("InputWorkspace", self._q_workspace)
+                transpose_alg.setProperty("OutputWorkspace", self._elt_workspace)
+                transpose_alg.execute()
+                sort_alg.setProperty("InputWorkspace", self._elt_workspace)
+                sort_alg.setProperty("OutputWorkspace", self._elt_workspace)
+                sort_alg.execute()
+                self._elt_workspace = sort_alg.getProperty("OutputWorkspace").value
             else:
-                CloneWorkspace(InputWorkspace=self._elf_workspace,
-                               OutputWorkspace=self._elt_workspace)
+                clone_alg = self.createChildAlgorithm("CloneWorkspace", enableLogging=False)
+                clone_alg.setProperty("InputWorkspace", self._elf_workspace)
+                clone_alg.setProperty("OutputWorkspace", self._elt_workspace)
+                clone_alg.execute()
+                self._elt_workspace = clone_alg.getProperty("OutputWorkspace").value
 
             _normalize_to_lowest_temp(self._elt_workspace)
 
@@ -268,12 +280,12 @@ class ElasticWindowMultiple(DataProcessorAlgorithm):
         self._background_range_start = self.getProperty('BackgroundRangeStart').value
         self._background_range_end = self.getProperty('BackgroundRangeEnd').value
 
-    def _get_temperature(self, ws_name):
+    def _get_sample_units(self, ws_name):
         """
-        Gets the sample temperature for a given workspace.
+        Gets the sample environment units for a given workspace.
 
         @param ws_name Name of workspace
-        @returns Temperature in Kelvin or None if not found
+        @returns sample in given units or None if not found
         """
         from IndirectCommon import getInstrRun
 
@@ -289,13 +301,14 @@ class ElasticWindowMultiple(DataProcessorAlgorithm):
         run = mtd[ws_name].getRun()
 
         if self._sample_log_name in run:
-            # Look for temperature in logs in workspace
+            # Look for sample unit in logs in workspace
             tmp = run[self._sample_log_name].value
-            value_action = {'last_value': lambda x: x[len(x)-1],
+            value_action = {'last_value': lambda x: x[len(x) - 1],
                             'average': lambda x: x.mean()}
-            temp = value_action[self._sample_log_value](tmp)
-            logger.debug('Temperature %d K found for run: %s' % (temp, run_name))
-            return temp
+            sample = value_action[self._sample_log_value](tmp)
+            unit = run[self._sample_log_name].units
+            logger.debug('%d %s found for run: %s' % (sample, unit, run_name))
+            return sample, unit
 
         else:
             # Logs not in workspace, try loading from file
@@ -308,17 +321,18 @@ class ElasticWindowMultiple(DataProcessorAlgorithm):
                 run_logs = mtd[ws_name].getRun()
                 if self._sample_log_name in run_logs:
                     tmp = run_logs[self._sample_log_name].value
-                    temp = tmp[len(tmp) - 1]
-                    logger.debug('Temperature %d K found for run: %s' % (temp, run_name))
-                    return temp
+                    sample = tmp[len(tmp) - 1]
+                    unit = run[self._sample_log_name].units
+                    logger.debug('%d %s found for run: %s' % (sample, unit, run_name))
+                    return sample, unit
                 else:
                     logger.warning('Log entry %s for run %s not found' % (self._sample_log_name, run_name))
             else:
                 logger.warning('Log file for run %s not found' % run_name)
 
         # Can't find log file
-        logger.warning('No temperature found for run: %s' % run_name)
-        return None
+        logger.warning('No sample units found for run: %s' % run_name)
+        return None, None
 
 
 # Register algorithm with Mantid
diff --git a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/EnergyWindowScan.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/EnergyWindowScan.py
new file mode 100644
index 0000000000000000000000000000000000000000..a91f667616048bd71fe546757134d222d66b6db1
--- /dev/null
+++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/EnergyWindowScan.py
@@ -0,0 +1,327 @@
+from mantid.api import *
+from mantid.kernel import *
+from mantid import config
+
+import os
+
+
+def _str_or_none(s):
+    if s != '':
+        return s
+    else:
+        return None
+
+
+def _ws_or_none(s):
+    if s != '':
+        return mtd[s]
+    else:
+        return None
+
+
+def _elems_or_none(l):
+    if len(l) != 0:
+        return l
+    else:
+        return None
+
+
+class EnergyWindowScan(DataProcessorAlgorithm):
+    _data_files = None
+    _sum_files = None
+    _load_logs = None
+    _calibration_ws = None
+    _instrument_name = None
+    _analyser = None
+    _reflection = None
+    _efixed = None
+    _spectra_range = None
+    _background_range = None
+    _elastic_range = None
+    _inelastic_range = None
+    _rebin_string = None
+    _detailed_balance = None
+    _grouping_method = None
+    _grouping_ws = None
+    _grouping_map_file = None
+    _output_ws = None
+    _output_x_units = None
+    _ipf_filename = None
+    _sample_log_name = None
+    _sample_log_value = None
+    _scan_ws = None
+
+    def category(self):
+        return 'Workflow\\Inelastic;Inelastic\\Indirect;Workflow\\MIDAS'
+
+    def summary(self):
+        return 'Runs an energy transfer reduction for an inelastic indirect geometry instrument.'
+
+    def PyInit(self):
+        # Input properties
+        self.declareProperty(StringArrayProperty(name='InputFiles'),
+                             doc='Comma separated list of input files')
+
+        self.declareProperty(name='LoadLogFiles', defaultValue=True,
+                             doc='Load log files when loading runs')
+
+        self.declareProperty(WorkspaceProperty('CalibrationWorkspace', '',
+                                               direction=Direction.Input,
+                                               optional=PropertyMode.Optional),
+                             doc='Workspace containing calibration data')
+
+        # Instrument configuration properties
+        self.declareProperty(name='Instrument', defaultValue='',
+                             validator=StringListValidator(['IRIS', 'OSIRIS']),
+                             doc='Instrument used during run.')
+        self.declareProperty(name='Analyser', defaultValue='',
+                             validator=StringListValidator(['graphite', 'mica', 'fmica']),
+                             doc='Analyser bank used during run.')
+        self.declareProperty(name='Reflection', defaultValue='',
+                             validator=StringListValidator(['002', '004', '006']),
+                             doc='Reflection number for instrument setup during run.')
+
+        self.declareProperty(IntArrayProperty(name='SpectraRange', values=[0, 1],
+                                              validator=IntArrayMandatoryValidator()),
+                             doc='Comma separated range of spectra number to use.')
+        self.declareProperty(FloatArrayProperty(name='ElasticRange'),
+                             doc='Energy range for the elastic component')
+        self.declareProperty(FloatArrayProperty(name='InelasticRange'),
+                             doc='Energy range for the inelastic component.')
+        self.declareProperty(name='DetailedBalance', defaultValue=Property.EMPTY_DBL,
+                             doc='Apply the detailed balance correction')
+
+        # Spectra grouping options
+        self.declareProperty(name='GroupingMethod', defaultValue='Individual',
+                             validator=StringListValidator(['Individual', 'All', 'File', 'Workspace', 'IPF']),
+                             doc='Method used to group spectra.')
+        self.declareProperty(WorkspaceProperty('GroupingWorkspace', '',
+                                               direction=Direction.Input,
+                                               optional=PropertyMode.Optional),
+                             doc='Workspace containing spectra grouping.')
+        self.declareProperty(FileProperty('MapFile', '',
+                                          action=FileAction.OptionalLoad,
+                                          extensions=['.map']),
+                             doc='File containing spectra grouping.')
+
+        self.declareProperty(name='SampleEnvironmentLogName', defaultValue='sample',
+                             doc='Name of the sample environment log entry')
+
+        sampEnvLogVal_type = ['last_value', 'average']
+        self.declareProperty('SampleEnvironmentLogValue', 'last_value',
+                             StringListValidator(sampEnvLogVal_type),
+                             doc='Value selection of the sample environment log entry')
+
+        self.declareProperty(name='MSDFit', defaultValue=False,
+                             doc='Perform an MSDFit')
+
+        self.declareProperty(name='SumFiles', defaultValue=False,
+                             doc='Toggle input file summing or sequential processing')
+        # Output properties
+        self.declareProperty(name='ReducedWorkspace', defaultValue='Reduced',
+                             doc='Workspace group for the resulting workspaces.')
+        self.declareProperty(name='ScanWorkspace', defaultValue='Scan',
+                             doc='Workspace for the scan results.')
+
+    def PyExec(self):
+
+        self._setup()
+
+        process_prog = Progress(self, start=0.1, end=0.9, nreports=4)
+        process_prog.report("Energy Transfer")
+        scan_alg = self.createChildAlgorithm("ISISIndirectEnergyTransfer", 0.05, 0.95)
+        scan_alg.setProperty('InputFiles', self._data_files)
+        scan_alg.setProperty('SumFiles', self._sum_files)
+        scan_alg.setProperty('LoadLogFiles', self._load_logs)
+        scan_alg.setProperty('CalibrationWorkspace', self._calibration_ws)
+        scan_alg.setProperty('Instrument', self._instrument_name)
+        scan_alg.setProperty('Analyser', self._analyser)
+        scan_alg.setProperty('Reflection', self._reflection)
+        scan_alg.setProperty('Efixed', self._efixed)
+        scan_alg.setProperty('SpectraRange', self._spectra_range)
+        scan_alg.setProperty('BackgroundRange', self._background_range)
+        scan_alg.setProperty('RebinString', self._rebin_string)
+        scan_alg.setProperty('DetailedBalance', self._detailed_balance)
+        scan_alg.setProperty('ScaleFactor', self._scale_factor)
+        scan_alg.setProperty('FoldMultipleFrames', self._fold_multiple_frames)
+        scan_alg.setProperty('GroupingMethod', self._grouping_method)
+        scan_alg.setProperty('GroupingWorkspace', self._grouping_ws)
+        scan_alg.setProperty('MapFile', self._grouping_map_file)
+        scan_alg.setProperty('UnitX', self._output_x_units)
+        scan_alg.setProperty('OutputWorkspace', self._output_ws)
+        scan_alg.execute()
+
+        logger.information('OutputWorkspace : %s' % self._output_ws)
+        logger.information('ScanWorkspace : %s' % self._scan_ws)
+
+        elwin_prog = Progress(self, start=0.9, end=1.0, nreports=4)
+        delete_alg = self.createChildAlgorithm("DeleteWorkspace", enableLogging=False)
+        divide_alg = self.createChildAlgorithm("Divide", enableLogging=False)
+        elwin_alg = self.createChildAlgorithm("ElasticWindowMultiple", enableLogging=False)
+        elwin_prog.report('Elastic window')
+        elwin_alg.setProperty("InputWorkspaces", self._output_ws)
+        elwin_alg.setProperty("IntegrationRangeStart", self._elastic_range[0])
+        elwin_alg.setProperty("IntegrationRangeEnd", self._elastic_range[1])
+        elwin_alg.setProperty("SampleEnvironmentLogName", self._sample_log_name)
+        elwin_alg.setProperty("SampleEnvironmentLogValue", self._sample_log_value)
+        elwin_alg.setAlwaysStoreInADS(True)
+        elwin_alg.setProperty("OutputInQ", self._scan_ws + '_el_eq1')
+        elwin_alg.setProperty("OutputInQSquared", self._scan_ws + '_el_eq2')
+        elwin_alg.setProperty("OutputELF", self._scan_ws + '_el_elf')
+        elwin_alg.setProperty("OutputELT", self._scan_ws + '_el_elt')
+        elwin_alg.execute()
+
+        elwin_prog.report('Inelastic window')
+        elwin_alg.setProperty("InputWorkspaces", self._output_ws)
+        elwin_alg.setProperty("IntegrationRangeStart", self._inelastic_range[0])
+        elwin_alg.setProperty("IntegrationRangeEnd", self._inelastic_range[1])
+        elwin_alg.setProperty("SampleEnvironmentLogName", self._sample_log_name)
+        elwin_alg.setProperty("SampleEnvironmentLogValue", self._sample_log_value)
+        elwin_alg.setAlwaysStoreInADS(True)
+        elwin_alg.setProperty("OutputInQ", self._scan_ws + '_inel_eq1')
+        elwin_alg.setProperty("OutputInQSquared", self._scan_ws + '_inel_eq2')
+        elwin_alg.setProperty("OutputELF", self._scan_ws + '_inel_elf')
+        elwin_alg.setProperty("OutputELT", self._scan_ws + '_inel_elt')
+        elwin_alg.execute()
+
+        divide_alg.setProperty("LHSWorkspace", self._scan_ws + '_el_eq1')
+        divide_alg.setProperty("RHSWorkspace", self._scan_ws + '_inel_eq1')
+        divide_alg.setProperty("OutputWorkspace", self._scan_ws + '_eisf')
+        divide_alg.execute()
+        mtd.addOrReplace(self._scan_ws + '_eisf', divide_alg.getProperty("OutputWorkspace").value)
+
+        delete_alg.setProperty("Workspace", self._scan_ws + '_el_elf')
+        delete_alg.execute()
+        delete_alg.setProperty("Workspace", self._scan_ws + '_inel_elf')
+        delete_alg.execute()
+
+        x_values = mtd[self._scan_ws + '_el_eq2'].readX(0)
+        num_hist = mtd[self._scan_ws + '_el_eq2'].getNumberHistograms()
+        if len(x_values) < 2:
+            logger.error("Unable to perform MSDFit")
+            self._msdfit = False
+
+        if self._msdfit:
+            msdfit_prog = Progress(self, start=0.9, end=1.0, nreports=4)
+            msdfit_prog.report('msdFit')
+            msd_alg = self.createChildAlgorithm("MSDFit", enableLogging=False)
+            msd_alg.setProperty("InputWorkspace", self._scan_ws + '_el_eq2')
+            msd_alg.setProperty("Xstart", x_values[0])
+            msd_alg.setProperty("XEnd", x_values[len(x_values) - 1])
+            msd_alg.setProperty("SpecMin", 0)
+            msd_alg.setProperty("SpecMax", num_hist - 1)
+            msd_alg.setProperty("OutputWorkspace", self._scan_ws + '_msd')
+            msd_alg.setProperty("FitWorkspaces", self._scan_ws + '_msd_fit')
+            msd_alg.execute()
+            mtd.addOrReplace(self._scan_ws + '_msd', msd_alg.getProperty("OutputWorkspace").value)
+            mtd.addOrReplace(self._scan_ws + '_msd_fit', msd_alg.getProperty("FitWorkspaces").value)
+
+    def validateInputs(self):
+        """
+        Validates algorithm properties.
+        """
+        issues = dict()
+
+        # Validate the instrument configuration by checking if a parameter file exists
+        instrument_name = self.getPropertyValue('Instrument')
+        analyser = self.getPropertyValue('Analyser')
+        reflection = self.getPropertyValue('Reflection')
+
+        ipf_filename = os.path.join(config['instrumentDefinition.directory'],
+                                    instrument_name + '_' + analyser + '_' + reflection + '_Parameters.xml')
+
+        if not os.path.exists(ipf_filename):
+            error_message = 'Invalid instrument configuration'
+            issues['Instrument'] = error_message
+            issues['Analyser'] = error_message
+            issues['Reflection'] = error_message
+
+        # Validate spectra range
+
+        spectra_range = self.getProperty('SpectraRange').value
+        if len(spectra_range) != 2:
+            issues['SpectraRange'] = 'Range must contain exactly two items'
+        elif spectra_range[0] > spectra_range[1]:
+            issues['SpectraRange'] = 'Range must be in format: lower,upper'
+
+        # Validate ranges
+        elastic_range = self.getProperty('ElasticRange').value
+        if elastic_range is not None:
+            if len(elastic_range) != 2:
+                issues['ElasticRange'] = 'Range must contain exactly two items'
+            elif elastic_range[0] > elastic_range[1]:
+                issues['ElasticRange'] = 'Range must be in format: lower,upper'
+        inelastic_range = self.getProperty('InelasticRange').value
+        if inelastic_range is not None:
+            if len(inelastic_range) != 2:
+                issues['InelasticRange'] = 'Range must contain exactly two items'
+            elif inelastic_range[0] > inelastic_range[1]:
+                issues['InelasticRange'] = 'Range must be in format: lower,upper'
+
+        # Validate grouping method
+        grouping_method = self.getPropertyValue('GroupingMethod')
+        grouping_ws = _ws_or_none(self.getPropertyValue('GroupingWorkspace'))
+
+        if grouping_method == 'Workspace' and grouping_ws is None:
+            issues['GroupingWorkspace'] = 'Must select a grouping workspace for current GroupingWorkspace'
+
+        return issues
+
+    def _setup(self):
+        """
+        Gets algorithm properties.
+        """
+
+        # Get properties
+        self._data_files = self.getProperty('InputFiles').value
+        self._sum_files = self.getProperty('SumFiles').value
+        self._load_logs = self.getProperty('LoadLogFiles').value
+        self._calibration_ws = ''
+
+        self._instrument_name = self.getPropertyValue('Instrument')
+        self._analyser = self.getPropertyValue('Analyser')
+        self._reflection = self.getPropertyValue('Reflection')
+        self._efixed = Property.EMPTY_DBL
+
+        self._spectra_range = self.getProperty('SpectraRange').value
+        self._background_range = ''
+        self._rebin_string = ''
+        self._detailed_balance = self.getProperty('DetailedBalance').value
+        self._scale_factor = 1.0
+        self._fold_multiple_frames = False
+        self._elastic_range = self.getProperty('ElasticRange').value
+        self._inelastic_range = self.getProperty('InelasticRange').value
+
+        self._grouping_method = self.getPropertyValue('GroupingMethod')
+        self._grouping_ws = ''
+        self._grouping_map_file = ''
+
+        self._output_x_units = 'DeltaE'
+
+        self._msdfit = self.getProperty('MSDFit').value
+
+        self._output_ws = self.getPropertyValue('ReducedWorkspace')
+        self._sample_log_name = self.getPropertyValue('SampleEnvironmentLogName')
+        self._sample_log_value = self.getPropertyValue('SampleEnvironmentLogValue')
+
+        self._scan_ws = self.getPropertyValue('ScanWorkspace')
+
+        # Disable sum files if there is only one file
+        if (len(self._data_files) == 1) & self._sum_files:
+            logger.warning('SumFiles disabled when only one input file is provided.')
+            self._sum_files = False
+
+        # Get the IPF filename
+        self._ipf_filename = os.path.join(config['instrumentDefinition.directory'],
+                                          self._instrument_name + '_' + self._analyser + '_' + self._reflection + '_Parameters.xml')
+        logger.information('Instrument parameter file: %s' % self._ipf_filename)
+
+        # Warn when grouping options are to be ignored
+        if self._grouping_method != 'Workspace' and self._grouping_ws is not None:
+            logger.warning('GroupingWorkspace will be ignored by selected GroupingMethod')
+
+        if self._grouping_method != 'File' and self._grouping_map_file is not None:
+            logger.warning('MapFile will be ignored by selected GroupingMethod')
+
+# Register algorithm with Mantid
+AlgorithmFactory.subscribe(EnergyWindowScan)
diff --git a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ILLIN16BCalibration.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ILLIN16BCalibration.py
index 9eec2b0a0bdd79c55bd3aaa26ddbc4c0efa2146f..c7b035698f9bbb2dfd8111bf86ae80af1aa91374 100644
--- a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ILLIN16BCalibration.py
+++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ILLIN16BCalibration.py
@@ -20,7 +20,8 @@ class ILLIN16BCalibration(DataProcessorAlgorithm):
         return 'Workflow\\Inelastic;Inelastic\\Calibration'
 
     def summary(self):
-        return 'Creates a calibration workspace in energy trnasfer for IN16B.'
+        return 'Creates a calibration workspace in energy trnasfer for IN16B.' \
+               'This algorithm is deprecated (20-Nov-2016). Use IndirectILLReductionQENS instead.'
 
     def PyInit(self):
         self.declareProperty(FileProperty(name='Run', defaultValue='',
@@ -47,6 +48,8 @@ class ILLIN16BCalibration(DataProcessorAlgorithm):
                              doc='Output workspace for calibration data')
 
     def PyExec(self):
+        self.log().error('This algorithm is deprecated (20-Nov-2016). '
+                         'Use IndirectILLReductionQENS instead.')
         self._setup()
 
         temp_raw = '__raw'
diff --git a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/IndirectILLEnergyTransfer.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/IndirectILLEnergyTransfer.py
new file mode 100644
index 0000000000000000000000000000000000000000..4afc57ee57343ea304e569ddab931bffd9c1f469
--- /dev/null
+++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/IndirectILLEnergyTransfer.py
@@ -0,0 +1,414 @@
+from __future__ import (absolute_import, division, print_function)
+
+import numpy as np
+from mantid.simpleapi import *  # noqa
+from mantid.kernel import *  # noqa
+from mantid.api import *  # noqa
+from mantid import config, mtd, logger
+
+
+def _ws_or_none(s):
+    return mtd[s] if s != '' else None
+
+
+def extract_workspace(ws, ws_out, x_start, x_end):
+    """
+    Extracts a part of the workspace and
+    shifts the x-axis to start from 0
+    @param  ws      :: input workspace name
+    @param  ws_out  :: output workspace name
+    @param  x_start :: start bin of workspace to be extracted
+    @param  x_end   :: end bin of workspace to be extracted
+    """
+    CropWorkspace(InputWorkspace=ws, OutputWorkspace=ws_out, XMin=x_start, XMax=x_end)
+    ScaleX(InputWorkspace=ws_out, OutputWorkspace=ws_out, Factor=-x_start, Operation='Add')
+
+
+class IndirectILLEnergyTransfer(PythonAlgorithm):
+
+    _run_file = None
+    _map_file = None
+    _parameter_file = None
+    _reduction_type = None
+    _mirror_sense = None
+    _doppler_energy = None
+    _velocity_profile = None
+    _instrument_name = None
+    _instrument = None
+    _analyser = None
+    _reflection = None
+    _dead_channels = None
+    _ws = None
+    _red_ws = None
+    _psd_int_range = None
+    _use_map_file = None
+
+    def category(self):
+        return "Workflow\\MIDAS;Workflow\\Inelastic;Inelastic\\Indirect;Inelastic\\Reduction"
+
+    def summary(self):
+        return 'Performs energy transfer reduction for ILL indirect geometry data, instrument IN16B.'
+
+    def name(self):
+        return "IndirectILLEnergyTransfer"
+
+    def PyInit(self):
+
+        self.declareProperty(MultipleFileProperty('Run', extensions=['nxs']),
+                             doc='File path of run (s).')
+
+        self.declareProperty(FileProperty('MapFile', '',
+                                          action=FileAction.OptionalLoad,
+                                          extensions=['map','xml']),
+                             doc='Filename of the detector grouping map file to use. \n'
+                                 'By default all the pixels will be summed per each tube. \n'
+                                 'Use .map or .xml file (see GroupDetectors documentation) '
+                                 'only if different range is needed for each tube.')
+
+        self.declareProperty(name='ManualPSDIntegrationRange',defaultValue=[1,128],
+                             doc='Integration range of vertical pixels in each PSD tube. \n'
+                                 'By default all the pixels will be summed per each tube. \n'
+                                 'Use this option if the same range (other than default) '
+                                 'is needed for all the tubes.')
+
+        self.declareProperty(name='Analyser',
+                             defaultValue='silicon',
+                             validator=StringListValidator(['silicon']),
+                             doc='Analyser crystal.')
+
+        self.declareProperty(name='Reflection',
+                             defaultValue='111',
+                             validator=StringListValidator(['111', '311']),
+                             doc='Analyser reflection.')
+
+        self.declareProperty(name='CropDeadMonitorChannels',defaultValue=False,
+                             doc='Whether or not to exclude the first and last few channels '
+                                 'with 0 monitor count in the energy transfer formula.')
+
+        self.declareProperty(WorkspaceGroupProperty('OutputWorkspace', '',
+                                                    direction=Direction.Output),
+                             doc='Group name for the reduced workspace(s).')
+
+    def validateInputs(self):
+
+        issues = dict()
+
+        self._psd_int_range = self.getProperty('ManualPSDIntegrationRange').value
+
+        if not self.getPropertyValue('MapFile'):
+            if len(self._psd_int_range) != 2:
+                issues['ManualPSDIntegrationRange'] = 'Specify comma separated pixel range, e.g. 1,128'
+            elif self._psd_int_range[0] < 1 or self._psd_int_range[1] > 128 \
+                    or self._psd_int_range[0] >= self._psd_int_range[1]:
+                issues['ManualPSDIntegrationRange'] = 'Start or end pixel number out is of range [1-128], or has wrong order'
+
+        return issues
+
+    def setUp(self):
+
+        self._run_file = self.getPropertyValue('Run').replace(',','+') # automatic summing
+        self._analyser = self.getPropertyValue('Analyser')
+        self._map_file = self.getPropertyValue('MapFile')
+        self._reflection = self.getPropertyValue('Reflection')
+        self._dead_channels = self.getProperty('CropDeadMonitorChannels').value
+        self._red_ws = self.getPropertyValue('OutputWorkspace')
+
+        if self._map_file or (self._psd_int_range[0] == 1 and self._psd_int_range[1] == 128):
+            self._use_map_file = True
+        else:
+            self._use_map_file = False
+
+    def _load_map_file(self):
+        """
+        Loads the detector grouping map file
+        @throws RuntimeError :: if neither the user defined nor the default file is found
+        """
+
+        self._instrument_name = self._instrument.getName()
+        self._analyser = self.getPropertyValue('Analyser')
+        self._reflection = self.getPropertyValue('Reflection')
+        idf_directory = config['instrumentDefinition.directory']
+        ipf_name = self._instrument_name + '_' + self._analyser + '_' + self._reflection + '_Parameters.xml'
+        self._parameter_file = os.path.join(idf_directory, ipf_name)
+        self.log().information('Set parameter file : {0}'.format(self._parameter_file))
+
+        if self._use_map_file:
+            if self._map_file == '':
+                # path name for default map file
+                if self._instrument.hasParameter('Workflow.GroupingFile'):
+                    grouping_filename = self._instrument.getStringParameter('Workflow.GroupingFile')[0]
+                    self._map_file = os.path.join(config['groupingFiles.directory'], grouping_filename)
+                else:
+                    raise RuntimeError("Failed to find default detector grouping file. Please specify manually.")
+
+            self.log().information('Set detector map file : {0}'.format(self._map_file))
+
+    def _mask(self, ws, xstart, xend):
+        """
+        Masks the first and last bins
+        @param   ws           :: input workspace name
+        @param   xstart       :: MaskBins between x[0] and x[xstart]
+        @param   xend         :: MaskBins between x[xend] and x[-1]
+        """
+        x_values = mtd[ws].readX(0)
+
+        if xstart > 0:
+            logger.debug('Mask bins smaller than {0}'.format(xstart))
+            MaskBins(InputWorkspace=ws, OutputWorkspace=ws, XMin=x_values[0], XMax=x_values[xstart])
+
+        if xend < len(x_values) - 1:
+            logger.debug('Mask bins larger than {0}'.format(xend))
+            MaskBins(InputWorkspace=ws, OutputWorkspace=ws, XMin=x_values[xend + 1], XMax=x_values[-1])
+
+    def _convert_to_energy(self, ws, n_crop):
+        """
+        Converts the x-axis from raw channel number to energy transfer
+        @param ws :: input workspace name
+        @param ws :: number of cropped bins
+        """
+
+        x = mtd[ws].readX(0)
+        size = mtd[ws].blocksize()
+        mid = (x[-1] + x[0])/ 2.
+        scale = 1000.  # from micro ev to mili ev
+
+        factor = (size + n_crop)/(size - 1)
+
+        if self._doppler_energy != 0:
+            formula = '(x/{0} - 1)*{1}'.format(mid, (self._doppler_energy / scale) * factor)
+        else:
+            # Center the data for elastic fixed window scan, for integration over the elastic peak
+            formula = '(x-{0})*{1}'.format(mid-0.5, 1. / scale)
+            self.log().notice('The only energy value is 0 meV. Ignore the x-axis.')
+
+        self.log().information('Energy conversion formula is: {0}'.format(formula))
+
+        ConvertAxisByFormula(InputWorkspace=ws, OutputWorkspace=ws, Axis='X', Formula=formula, AxisUnits = 'DeltaE')
+
+    def _monitor_max_range(self, ws):
+        """
+        Gives the bin indices of the first and last peaks in the monitor
+        @param ws :: input workspace name
+        return    :: [xmin,xmax]
+        """
+
+        y = mtd[ws].readY(0)
+        size = len(y)
+        mid = int(size / 2)
+        imin = np.nanargmax(y[0:mid])
+        imax = np.nanargmax(y[mid:size]) + mid
+        return imin, imax
+
+    def _monitor_zero_range(self, ws):
+        """
+        Gives the bin indices of the first and last non-zero bins in monitor
+        @param ws :: input workspace name
+        return    :: [start,end]
+        """
+
+        y = mtd[ws].readY(0)
+        nonzero = np.argwhere(y!=0)
+        start = nonzero[0][0] if nonzero.any() else 0
+        end = nonzero[-1][0] if nonzero.any() else len(y)
+        return start,end
+
+    def _setup_run_properties(self):
+        """
+        Sets up the doppler properties, and deduces the reduction type
+        @throws RuntimeError :: If anyone of the 3 required entries is missing
+        """
+
+        run = mtd[self._ws].getRun()
+
+        message = 'is not defined. Check your data.'
+
+        if run.hasProperty('Doppler.mirror_sense'):
+            self._mirror_sense = run.getLogData('Doppler.mirror_sense').value
+        else:
+            raise RuntimeError('Mirror sense '+ message)
+
+        if run.hasProperty('Doppler.maximum_delta_energy'):
+            self._doppler_energy = run.getLogData('Doppler.maximum_delta_energy').value
+        else:
+            raise RuntimeError('Maximum delta energy '+ message)
+
+        if run.hasProperty('Doppler.velocity_profile'):
+            self._velocity_profile = run.getLogData('Doppler.velocity_profile').value
+        else:
+            raise RuntimeError('Velocity profile '+ message)
+
+        if self._doppler_energy == 0.:
+            self._reduction_type = 'EFWS'
+        else:
+            if self._velocity_profile == 0:
+                self._reduction_type = 'QENS'
+            else:
+                self._reduction_type = 'IFWS'
+
+    def PyExec(self):
+
+        self.setUp()
+
+        self._progress = Progress(self, start=0.0, end=1.0, nreports=self._run_file.count('+'))
+
+        # This is faster than Load, moreover MergeRuns handles the metadata correctly
+        run_files = self._run_file.split('+')
+        for i, item in enumerate(run_files):
+            runnumber = os.path.basename(item).split('.')[0]
+            ws_name = '__' + runnumber
+            self._progress.report("Loading run #"+runnumber)
+            if i == 0:
+                LoadILLIndirect(Filename=item,OutputWorkspace=self._red_ws)
+            if i > 0:
+                LoadILLIndirect(Filename=item, OutputWorkspace=ws_name)
+                MergeRuns(InputWorkspaces=[self._red_ws,ws_name],OutputWorkspace=self._red_ws)
+                DeleteWorkspace(ws_name)
+
+        self._instrument = mtd[self._red_ws].getInstrument()
+
+        self._load_map_file()
+
+        run = '{0:06d}'.format(mtd[self._red_ws].getRunNumber())
+
+        self._ws = self._red_ws + '_' + run
+
+        if len(run_files) > 1:  # multiple summed files
+            self._ws += '_multiple'
+
+        RenameWorkspace(InputWorkspace=self._red_ws, OutputWorkspace=self._ws)
+
+        LoadParameterFile(Workspace=self._ws, Filename=self._parameter_file)
+
+        self._setup_run_properties()
+
+        if self._mirror_sense == 14:      # two wings, extract left and right
+
+            size = mtd[self._ws].blocksize()
+            left = self._ws + '_left'
+            right = self._ws + '_right'
+            extract_workspace(self._ws, left, 0, int(size/2))
+            extract_workspace(self._ws, right, int(size/2), size)
+            DeleteWorkspace(self._ws)
+            self._reduce_one_wing(left)
+            self._reduce_one_wing(right)
+            GroupWorkspaces(InputWorkspaces=[left,right],OutputWorkspace=self._red_ws)
+
+        elif self._mirror_sense == 16:    # one wing
+
+            self._reduce_one_wing(self._ws)
+            GroupWorkspaces(InputWorkspaces=[self._ws],OutputWorkspace=self._red_ws)
+
+        self.setProperty('OutputWorkspace',self._red_ws)
+
+    def _reduce_one_wing(self, ws):
+        """
+        Reduces given workspace assuming it is one wing already
+        @param ws :: input workspace name
+        """
+
+        mon = '__mon_'+ws
+
+        ExtractSingleSpectrum(InputWorkspace=ws, OutputWorkspace=mon, WorkspaceIndex=0)
+
+        if self._use_map_file:
+            GroupDetectors(InputWorkspace=ws, OutputWorkspace=ws, MapFile=self._map_file)
+        else:
+            self._group_detectors_with_range(ws)
+
+        xmin, xmax = self._monitor_zero_range(mon)
+
+        self._normalise_to_monitor(ws, mon)
+
+        n_cropped_bins = 0
+
+        if self._reduction_type == 'QENS':
+            if self._dead_channels:
+                CropWorkspace(InputWorkspace=ws,OutputWorkspace=ws,XMin=float(xmin),XMax=float(xmax+1.))
+                n_cropped_bins = mtd[mon].blocksize() - mtd[ws].blocksize() - 1
+            else:
+                self._mask(ws, xmin, xmax)
+
+        DeleteWorkspace(mon)
+
+        self._convert_to_energy(ws, n_cropped_bins)
+
+    def _group_detectors_with_range(self, ws):
+        """
+        Groups (sums) the multi-detector's pixels according to given range
+        @param ws :: input workspace name
+        """
+        pattern = ''
+
+        for tube in range(1,17):
+            pattern += str((tube - 1) * 128 + self._psd_int_range[0])
+            pattern += '-'
+            pattern += str((tube - 1) * 128 + self._psd_int_range[1])
+            pattern += ','
+
+        num_single_det = mtd[ws].getNumberHistograms()-16*128-1
+
+        for single_det in range(num_single_det):
+            sd_index = 16*128 + single_det + 1
+            pattern += str(sd_index)
+            pattern += ','
+
+        pattern = pattern.rstrip(',')
+
+        self.log().information("Grouping the detectors with pattern:\n {0}"
+                               .format(pattern))
+
+        GroupDetectors(InputWorkspace=ws,OutputWorkspace=ws,GroupingPattern=pattern)
+
+    def _normalise_to_monitor(self, ws, mon):
+        """
+        Normalises the ws to the monitor dependent on the reduction type
+        @param ws :: input workspace name
+        @param ws :: ws's monitor
+        """
+        x = mtd[ws].readX(0)
+
+        if self._reduction_type == 'QENS':
+            # Normalise bin-to-bin, do not use NormaliseToMonitor, it uses scaling that we don't want
+            Divide(LHSWorkspace=ws,OutputWorkspace=ws,RHSWorkspace=mon)
+
+        elif self._reduction_type == 'EFWS':
+            # Integrate over the whole range
+
+            int = '__integral1_' + ws
+            Integration(InputWorkspace=mon, OutputWorkspace=int,
+                        RangeLower=x[0], RangeUpper=x[-1])
+
+            if mtd[int].readY(0)[0] !=0: # this needs to be checked
+                Scale(InputWorkspace=ws, OutputWorkspace=ws, Factor=1. / mtd[int].readY(0)[0])
+
+            DeleteWorkspace(int)
+
+        elif self._reduction_type == 'IFWS':
+            # Integrate over the two peaks at the beginning and at the end and sum
+            size = mtd[ws].blocksize()
+            x_start, x_end = self._monitor_max_range(mon)
+
+            i1 = '__integral1_' + ws
+            i2 = '__integral2_' + ws
+            int = '__integral_' + ws
+
+            Integration(InputWorkspace=mon, OutputWorkspace=i1,
+                        RangeLower=x[0], RangeUpper=x[2*x_start])
+
+            Integration(InputWorkspace=mon, OutputWorkspace=i2,
+                        RangeLower=x[-2*(size - x_end)], RangeUpper=x[-1])
+
+            Plus(LHSWorkspace=i1,RHSWorkspace=i2,OutputWorkspace=int)
+
+            if mtd[int].readY(0)[0] != 0: # this needs to be checked
+                Scale(InputWorkspace = ws, OutputWorkspace = ws, Factor = 1./mtd[int].readY(0)[0])
+
+            DeleteWorkspace(i1)
+            DeleteWorkspace(i2)
+            DeleteWorkspace(int)
+
+        ReplaceSpecialValues(InputWorkspace=ws, OutputWorkspace=ws,
+                             NaNValue=0, NaNError=0, InfinityValue=0, InfinityError=0)
+
+# Register algorithm with Mantid
+AlgorithmFactory.subscribe(IndirectILLEnergyTransfer)
diff --git a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/IndirectILLReduction.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/IndirectILLReduction.py
index 4c1240fca22f9d3e6bab2e2a589cafc70dc4653e..1df079b09245b3c698b1107bb546c5a7cf1f5b51 100644
--- a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/IndirectILLReduction.py
+++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/IndirectILLReduction.py
@@ -34,9 +34,11 @@ class IndirectILLReduction(DataProcessorAlgorithm):
         return "Workflow\\MIDAS;Inelastic\\Reduction"
 
     def summary(self):
-        return 'Performs an energy transfer reduction for ILL indirect inelastic data.'
+        return 'Performs an energy transfer reduction for ILL indirect inelastic data.' \
+               'This algorithm is deprecated (20-Nov-2016). Use IndirectILLReductionQENS instead.'
 
     def PyInit(self):
+
         # Input options
         self.declareProperty(FileProperty('Run', '',
                                           action=FileAction.Load,
@@ -108,6 +110,9 @@ class IndirectILLReduction(DataProcessorAlgorithm):
         return issues
 
     def PyExec(self):
+        self.log().error('This algorithm is deprecated (20-Nov-2016). '
+                         'Use IndirectILLReductionQENS instead.')
+
         self.log().information('IndirectILLreduction')
 
         run_path = self.getPropertyValue('Run')
@@ -122,7 +127,7 @@ class IndirectILLReduction(DataProcessorAlgorithm):
         self._save = self.getProperty('Save').value
         self._plot = self.getProperty('Plot').value
 
-        LoadILLIndirect(FileName=run_path, OutputWorkspace=self._raw_workspace)
+        LoadILLIndirect(FileName=run_path, OutputWorkspace=self._raw_workspace, Version=1)
 
         instrument = mtd[self._raw_workspace].getInstrument()
         self._instrument_name = instrument.getName()
diff --git a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/IndirectILLReductionFWS.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/IndirectILLReductionFWS.py
new file mode 100644
index 0000000000000000000000000000000000000000..0c0ef2d461fcfaa7773fe93fb518591893dfc2cf
--- /dev/null
+++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/IndirectILLReductionFWS.py
@@ -0,0 +1,538 @@
+from __future__ import (absolute_import, division, print_function)
+
+
+from mantid.simpleapi import *  # noqa
+from mantid.kernel import *  # noqa
+from mantid.api import *  # noqa
+from mantid import mtd
+import numpy as np
+import time
+
+
+def _insert_energy_value(ws_name, energy):
+    return ws_name.replace('_red', '_' + str(energy) + '_red')
+
+
+class IndirectILLReductionFWS(PythonAlgorithm):
+
+    _SAMPLE = 'sample'
+    _BACKGROUND = 'background'
+    _CALIBRATION = 'calibration'
+
+    _sample_files = None
+    _background_files = None
+    _calibration_files = None
+    _observable = None
+    _sortX = None
+    _red_ws = None
+    _back_scaling = None
+    _criteria = None
+    _progress = None
+    _back_option = None
+    _calib_option = None
+    _common_args = {}
+    _all_runs = None
+
+    def category(self):
+        return "Workflow\\MIDAS;Workflow\\Inelastic;Inelastic\\Indirect;Inelastic\\Reduction"
+
+    def summary(self):
+        return 'Performs fixed-window scan (FWS) multiple file reduction (both elastic and inelastic) ' \
+               'for ILL indirect geometry data, instrument IN16B.'
+
+    def name(self):
+        return "IndirectILLReductionFWS"
+
+    def PyInit(self):
+
+        self.declareProperty(MultipleFileProperty('Run', extensions=['nxs']),
+                             doc='Run number(s) of sample run(s).')
+
+        self.declareProperty(MultipleFileProperty('BackgroundRun',
+                                                  action=FileAction.OptionalLoad,
+                                                  extensions=['nxs']),
+                             doc='Run number(s) of background (empty can) run(s).')
+
+        self.declareProperty(MultipleFileProperty('CalibrationRun',
+                                                  action=FileAction.OptionalLoad,
+                                                  extensions=['nxs']),
+                             doc='Run number(s) of vanadium calibration run(s).')
+
+        self.declareProperty(name='Observable',
+                             defaultValue='sample.temperature',
+                             doc='Scanning observable, a Sample Log entry\n')
+
+        self.declareProperty(name='SortXAxis',
+                             defaultValue=False,
+                             doc='Whether or not to sort the x-axis\n')
+
+        self.declareProperty(name='BackgroundScalingFactor', defaultValue=1.,
+                             validator=FloatBoundedValidator(lower=0),
+                             doc='Scaling factor for background subtraction')
+
+        self.declareProperty(name='BackgroundOption',
+                             defaultValue='Sum',
+                             validator=StringListValidator(['Sum','Interpolate']),
+                             doc='Whether to sum or interpolate the background runs.')
+
+        self.declareProperty(name='CalibrationOption',
+                             defaultValue='Sum',
+                             validator=StringListValidator(['Sum', 'Interpolate']),
+                             doc='Whether to sum or interpolate the calibration runs.')
+
+        self.declareProperty(FileProperty('MapFile', '',
+                                          action=FileAction.OptionalLoad,
+                                          extensions=['map','xml']),
+                             doc='Filename of the detector grouping map file to use. \n'
+                                 'By default all the pixels will be summed per each tube. \n'
+                                 'Use .map or .xml file (see GroupDetectors documentation) '
+                                 'only if different range is needed for each tube.')
+
+        self.declareProperty(name='ManualPSDIntegrationRange',defaultValue=[1,128],
+                             doc='Integration range of vertical pixels in each PSD tube. \n'
+                                 'By default all the pixels will be summed per each tube. \n'
+                                 'Use this option if the same range (other than default) '
+                                 'is needed for all the tubes.')
+
+        self.declareProperty(name='Analyser',
+                             defaultValue='silicon',
+                             validator=StringListValidator(['silicon']),
+                             doc='Analyser crystal.')
+
+        self.declareProperty(name='Reflection',
+                             defaultValue='111',
+                             validator=StringListValidator(['111', '311']),
+                             doc='Analyser reflection.')
+
+        self.declareProperty(WorkspaceGroupProperty('OutputWorkspace', '',
+                                                    direction=Direction.Output),
+                             doc='Output workspace group')
+
+    def validateInputs(self):
+
+        issues = dict()
+
+        return issues
+
+    def setUp(self):
+
+        self._sample_files = self.getPropertyValue('Run')
+        self._background_files = self.getPropertyValue('BackgroundRun')
+        self._calibration_files = self.getPropertyValue('CalibrationRun')
+        self._observable = self.getPropertyValue('Observable')
+        self._sortX = self.getProperty('SortXAxis').value
+        self._back_scaling = self.getProperty('BackgroundScalingFactor').value
+        self._back_option = self.getPropertyValue('BackgroundOption')
+        self._calib_option = self.getPropertyValue('CalibrationOption')
+
+        # arguments to pass to IndirectILLEnergyTransfer
+        self._common_args['MapFile'] = self.getPropertyValue('MapFile')
+        self._common_args['Analyser'] = self.getPropertyValue('Analyser')
+        self._common_args['Reflection'] = self.getPropertyValue('Reflection')
+        self._common_args['ManualPSDIntegrationRange'] = self.getProperty('ManualPSDIntegrationRange').value
+
+        self._red_ws = self.getPropertyValue('OutputWorkspace') + '_red'
+
+        # Nexus metadata criteria for FWS type of data (both EFWS and IFWS)
+        self._criteria = '($/entry0/instrument/Doppler/maximum_delta_energy$ == 0. or ' \
+                         '$/entry0/instrument/Doppler/velocity_profile$ == 1)'
+
+        # make sure observable entry also exists (value is not important)
+        self._criteria += ' and ($/entry0/' + self._observable.replace('.', '/') + '$ or True)'
+
+        # force sort x-axis, if interpolation is requested
+        if ((self._back_option == 'Interpolate' and self._background_files) or
+                (self._calib_option == 'Interpolate' and self._calibration_files)) \
+                and not self._sortX:
+            self.log().warning('Interpolation option requested, X-axis will be sorted.')
+            self._sortX = True
+
+        # empty dictionary to keep track of all runs (ws names)
+        self._all_runs = dict()
+
+    def _filter_files(self, files, label):
+        '''
+        Filters the given list of files according to nexus criteria
+        @param  files :: list of input files (i.e. , and + separated string)
+        @param  label :: label of error message if nothing left after filtering
+        @throws RuntimeError :: when nothing left after filtering
+        @return :: the list of input files that passsed the criteria
+        '''
+
+        files = SelectNexusFilesByMetadata(files, self._criteria)
+
+        if not files:
+            raise RuntimeError('None of the {0} runs satisfied the FWS and Observable criteria.'.format(label))
+        else:
+            self.log().information('Filtered {0} runs are: {0} \\n'.format(label, files.replace(',', '\\n')))
+
+        return files
+
+    def _ifws_peak_bins(self, ws):
+        '''
+        Gives the bin indices of the first and last peaks (of spectra 0) in the IFWS
+        @param ws :: input workspace
+        return    :: [xmin,xmax]
+        '''
+
+        y = mtd[ws].readY(0)
+        size = len(y)
+        mid = int(size / 2)
+        imin = np.nanargmax(y[0:mid])
+        imax = np.nanargmax(y[mid:size]) + mid
+        return imin, imax
+
+    def _ifws_integrate(self, wsgroup):
+        '''
+        Integrates IFWS over two peaks at the beginning and end
+        @param ws :: input workspace group
+        '''
+
+        for item in mtd[wsgroup]:
+            ws = item.getName()
+            size = item.blocksize()
+            imin, imax = self._ifws_peak_bins(ws)
+            x_values = item.readX(0)
+            int1 = '__int1_' + ws
+            int2 = '__int2_' + ws
+            Integration(InputWorkspace=ws, OutputWorkspace=int1,
+                        RangeLower=x_values[0], RangeUpper=x_values[2*imin])
+            Integration(InputWorkspace=ws, OutputWorkspace=int2,
+                        RangeLower=x_values[-2*(size-imax)], RangeUpper=x_values[-1])
+            Plus(LHSWorkspace=int1, RHSWorkspace=int2, OutputWorkspace=ws)
+            DeleteWorkspace(int1)
+            DeleteWorkspace(int2)
+
+    def _perform_unmirror(self, groupws):
+        '''
+        Sums the integrals of left and right for two wings, or returns the integral of one wing
+        @param ws :: group workspace containing one ws for one wing, and two ws for two wing data
+        '''
+        if mtd[groupws].getNumberOfEntries() == 2:  # two wings, sum
+            left = mtd[groupws].getItem(0).getName()
+            right = mtd[groupws].getItem(1).getName()
+            sum = '__sum_'+groupws
+            Plus(LHSWorkspace=left, RHSWorkspace=right, OutputWorkspace=sum)
+            DeleteWorkspace(left)
+            DeleteWorkspace(right)
+            RenameWorkspace(InputWorkspace=sum, OutputWorkspace=groupws)
+        else:
+            RenameWorkspace(InputWorkspace=mtd[groupws].getItem(0), OutputWorkspace=groupws)
+
+    def PyExec(self):
+
+        self.setUp()
+
+        # total number of (unsummed) runs
+        total = self._sample_files.count(',')+self._background_files.count(',')+self._calibration_files.count(',')
+
+        self._progress = Progress(self, start=0.0, end=1.0, nreports=total)
+
+        self._reduce_multiple_runs(self._sample_files, self._SAMPLE)
+
+        if self._background_files:
+
+            self._reduce_multiple_runs(self._background_files, self._BACKGROUND)
+
+            back_ws = self._red_ws + '_' + self._BACKGROUND
+
+            Scale(InputWorkspace=back_ws, Factor=self._back_scaling, OutputWorkspace=back_ws)
+
+            if self._back_option == 'Sum':
+                self._integrate(self._BACKGROUND)
+            else:
+                self._interpolate(self._BACKGROUND)
+
+            self._subtract_background()
+
+            DeleteWorkspace(back_ws)
+
+        if self._calibration_files:
+
+            self._reduce_multiple_runs(self._calibration_files, self._CALIBRATION)
+
+            if self._calib_option == 'Sum':
+                self._integrate(self._CALIBRATION)
+            else:
+                self._interpolate(self._CALIBRATION)
+
+            self._calibrate()
+
+            DeleteWorkspace(self._red_ws + '_' + self._CALIBRATION)
+
+        self.log().debug('Run files map is :'+str(self._all_runs))
+
+        self.setProperty('OutputWorkspace',self._red_ws)
+
+    def _reduce_multiple_runs(self, files, label):
+        '''
+        Filters and reduces multiple files
+        @param files :: list of run paths
+        @param label :: output ws name
+        '''
+
+        files = self._filter_files(files, label)
+
+        for run in files.split(','):
+            self._reduce_run(run, label)
+
+        self._create_matrices(label)
+
+    def _reduce_run(self, run, label):
+        '''
+        Reduces the given (single or summed multiple) run
+        @param run :: run path
+        @param  label :: sample, background or calibration
+        '''
+
+        runs_list = run.split('+')
+
+        runnumber = os.path.basename(runs_list[0]).split('.')[0]
+
+        ws = '__' + runnumber
+
+        if (len(runs_list) > 1):
+            ws += '_multiple'
+
+        ws += '_' + label
+
+        self._progress.report("Reducing run #" + runnumber)
+
+        IndirectILLEnergyTransfer(Run=run, OutputWorkspace=ws, **self._common_args)
+
+        energy = round(mtd[ws].getItem(0).getRun().getLogData('Doppler.maximum_delta_energy').value, 2)
+
+        if energy == 0.:
+            # Elastic, integrate over full energy range
+            Integration(InputWorkspace=ws, OutputWorkspace=ws)
+        else:
+            # Inelastic, do something more complex
+            self._ifws_integrate(ws)
+
+        self._perform_unmirror(ws)
+
+        self._subscribe_run(ws, energy, label)
+
+    def _subscribe_run(self, ws, energy, label):
+        '''
+        Subscribes the given ws name to the map for given energy and label
+        @param ws     :: workspace name
+        @param energy :: energy value
+        @param label  :: sample, calibration or background
+        '''
+
+        if label in self._all_runs:
+            if energy in self._all_runs[label]:
+                self._all_runs[label][energy].append(ws)
+            else:
+                self._all_runs[label][energy] = [ws]
+        else:
+            self._all_runs[label] = dict()
+            self._all_runs[label][energy] = [ws]
+
+    def _integrate(self, label):
+        '''
+        Averages the background or calibration intensities over all observable points at given energy
+        @param label  :: calibration or background
+        '''
+
+        for energy in self._all_runs[self._SAMPLE]:
+            if energy in self._all_runs[label]:
+                ws = _insert_energy_value(self._red_ws, energy) + '_' + label
+                x_range = mtd[ws].readX(0)[-1] - mtd[ws].readX(0)[0]
+                if mtd[ws].blocksize() > 1:
+                    Integration(InputWorkspace=ws, OutputWorkspace=ws)
+                    Scale(InputWorkspace=ws,OutputWorkspace=ws,Factor=1./x_range)
+
+    def _interpolate(self, label):
+        '''
+        Interpolates the background or calibration intensities to
+        all observable points existing in sample at a given energy
+        @param label  :: calibration or background
+        '''
+
+        for energy in self._all_runs[self._SAMPLE]:
+            if energy in self._all_runs[label]:
+                ref = _insert_energy_value(self._red_ws, energy)
+                ws = ref + '_' + label
+                if mtd[ws].blocksize() > 1:
+                    SplineInterpolation(WorkspaceToInterpolate=ws,
+                                        WorkspaceToMatch=ref,
+                                        OutputWorkspace=ws)
+                    # add Linear2Point=True, when ready
+
+    def _subtract_background(self):
+        '''
+        Subtracts the background per each energy if background run is available
+        '''
+
+        for energy in self._all_runs[self._SAMPLE]:
+            if energy in self._all_runs[self._BACKGROUND]:
+                sample_ws = _insert_energy_value(self._red_ws, energy)
+                back_ws = sample_ws + '_' + self._BACKGROUND
+                Minus(LHSWorkspace=sample_ws, RHSWorkspace=back_ws, OutputWorkspace=sample_ws)
+            else:
+                self.log().warning('No background subtraction can be performed for doppler energy of {0} microEV, '
+                                   'since no background run was provided for the same energy value.'.format(energy))
+
+    def _calibrate(self):
+        '''
+        Performs calibration per each energy if calibration run is available
+        '''
+
+        for energy in self._all_runs[self._SAMPLE]:
+            if energy in self._all_runs[self._CALIBRATION]:
+                sample_ws = _insert_energy_value(self._red_ws, energy)
+                calib_ws = sample_ws + '_' + self._CALIBRATION
+                Divide(LHSWorkspace=sample_ws, RHSWorkspace=calib_ws, OutputWorkspace=sample_ws)
+                self._scale_calibration(sample_ws,calib_ws)
+            else:
+                self.log().warning('No calibration can be performed for doppler energy of {0} microEV, '
+                                   'since no calibration run was provided for the same energy value.'.format(energy))
+
+    def _scale_calibration(self, sample, calib):
+        '''
+        Scales sample workspace after calibration up by the maximum of integral intensity
+        in calibration run for each observable point
+        @param sample  :: sample workspace after calibration
+        @param calib   :: calibration workspace
+        '''
+
+        if mtd[calib].blocksize() == 1:
+            scale = np.max(mtd[calib].extractY()[:,0])
+            Scale(InputWorkspace=sample,Factor=scale,OutputWorkspace=sample,Operation='Multiply')
+        else:
+            # here calib and sample have the same size already
+            for column in range(mtd[sample].blocksize()):
+                scale = np.max(mtd[calib].extractY()[:,column])
+                for spectrum in range(mtd[sample].getNumberHistograms()):
+                    y = mtd[sample].dataY(spectrum)[column]
+                    e = mtd[sample].dataE(spectrum)[column]
+                    y *= scale
+                    e *= scale
+
+    def _get_observable_values(self, ws_list):
+        '''
+        Retrieves the needed sample log values for the given list of workspaces
+        @param ws_list :: list of workspaces
+        @returns :: array of observable values
+        @throws  :: ValueError if the log entry is not a number nor time-stamp
+        '''
+
+        result = []
+
+        zero_time = 0
+
+        pattern = '%Y-%m-%dT%H:%M:%S'
+
+        for i,ws in enumerate(ws_list):
+
+            log = mtd[ws].getRun().getLogData(self._observable)
+            value = log.value
+
+            if log.type == 'number':
+                value = float(value)
+            else:
+                try:
+                    value = time.mktime(time.strptime(value, pattern))
+                except ValueError:
+                    raise ValueError("Invalid observable. "
+                                     "Provide a numeric (sample.*, run_number, etc.) or time-stamp "
+                                     "like string (e.g. start_time) log.")
+                if i == 0:
+                    zero_time = value
+
+                value = value - zero_time
+
+            result.append(value)
+
+        return result
+
+    def _create_matrices(self, label):
+        '''
+        For each reduction type concatenates the workspaces putting the given sample log value as x-axis
+        Creates a group workspace for the given label, that contains 2D workspaces for each distinct energy value
+        @param label :: sample, background or calibration
+        '''
+
+        togroup = []
+
+        groupname = self._red_ws
+
+        if label != self._SAMPLE:
+            groupname += '_' + label
+
+        for energy in sorted(self._all_runs[label]):
+
+            ws_list = self._all_runs[label][energy]
+            size = len(self._all_runs[label][energy])
+
+            wsname = _insert_energy_value(groupname, energy)
+
+            togroup.append(wsname)
+            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)
+
+            CreateWorkspace(DataX=x_values, DataY=y_values, DataE=e_values, NSpec=nspectra,
+                            WorkspaceTitle=wsname, Distribution=True, ParentWorkspace=mtd[ws_list[0]],
+                            OutputWorkspace=wsname)
+
+            run_list = ''  # to set to sample logs
+
+            for ws in ws_list:
+                run = mtd[ws].getRun()
+
+                if run.hasProperty('run_number_list'):
+                    run_list += run.getLogData('run_number_list').value.replace(', ', '+') + ','
+                else:
+                    run_list += str(run.getLogData('run_number').value) + ','
+
+            AddSampleLog(Workspace=wsname, LogName='ReducedRunsList', LogText=run_list.rstrip(','))
+
+            for spectrum in range(nspectra):
+
+                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)
+
+            self._set_x_label(wsname)
+
+        for energy, ws_list in iteritems(self._all_runs[label]):
+            for ws in ws_list:
+                DeleteWorkspace(ws)
+
+        GroupWorkspaces(InputWorkspaces=togroup, OutputWorkspace=groupname)
+
+    def _set_x_label(self, ws):
+        '''
+        Sets the x-axis label
+        @param ws :: input workspace
+        '''
+
+        axis = mtd[ws].getAxis(0)
+        if self._observable == 'sample.temperature':
+            axis.setUnit("Label").setLabel('Temperature', 'K')
+        elif self._observable == 'sample.pressure':
+            axis.setUnit("Label").setLabel('Pressure', 'P')
+        elif 'time' in self._observable:
+            axis.setUnit("Label").setLabel('Time', 'seconds')
+        else:
+            axis.setUnit("Label").setLabel(self._observable, '')
+
+# Register algorithm with Mantid
+AlgorithmFactory.subscribe(IndirectILLReductionFWS)
diff --git a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/IndirectILLReductionQENS.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/IndirectILLReductionQENS.py
new file mode 100644
index 0000000000000000000000000000000000000000..dd6bc424226ccdcd397f24ca1e2bd07fffcbc6ad
--- /dev/null
+++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/IndirectILLReductionQENS.py
@@ -0,0 +1,449 @@
+from __future__ import (absolute_import, division, print_function)
+
+from mantid.simpleapi import *  # noqa
+from mantid.kernel import *  # noqa
+from mantid.api import *  # noqa
+from mantid import mtd
+import numpy
+
+
+class IndirectILLReductionQENS(PythonAlgorithm):
+
+    _sample_files = None
+    _alignment_files = None
+    _background_files = None
+    _calibration_files = None
+    _sum_all_runs = None
+    _unmirror_option = None
+    _back_scaling = None
+    _criteria = None
+    _progress = None
+    _red_ws = None
+    _common_args = {}
+    _peak_range = []
+    _runs = None
+
+    def category(self):
+        return "Workflow\\MIDAS;Workflow\\Inelastic;Inelastic\\Indirect;Inelastic\\Reduction"
+
+    def summary(self):
+        return 'Performs quasi-elastic neutron scattering (QENS) multiple file reduction ' \
+               'for ILL indirect geometry data, instrument IN16B.'
+
+    def name(self):
+        return "IndirectILLReductionQENS"
+
+    def PyInit(self):
+
+        self.declareProperty(MultipleFileProperty('Run', extensions=['nxs']),
+                             doc='Run number(s) of sample run(s).')
+
+        self.declareProperty(MultipleFileProperty('BackgroundRun',
+                                                  action=FileAction.OptionalLoad,
+                                                  extensions=['nxs']),
+                             doc='Run number(s) of background (empty can) run(s).')
+
+        self.declareProperty(MultipleFileProperty('CalibrationRun',
+                                                  action=FileAction.OptionalLoad,
+                                                  extensions=['nxs']),
+                             doc='Run number(s) of vanadium calibration run(s).')
+
+        self.declareProperty(MultipleFileProperty('AlignmentRun',
+                                                  action=FileAction.OptionalLoad,
+                                                  extensions=['nxs']),
+                             doc='Run number(s) of vanadium run(s) used for '
+                                 'peak alignment for UnmirrorOption=[5, 7]')
+
+        self.declareProperty(name='SumRuns',
+                             defaultValue=False,
+                             doc='Whether to sum all the input runs.')
+
+        self.declareProperty(name='CropDeadMonitorChannels', defaultValue=False,
+                             doc='Whether or not to exclude the first and last few channels '
+                                 'with 0 monitor count in the energy transfer formula.')
+
+        self.declareProperty(name='UnmirrorOption', defaultValue=6,
+                             validator=IntBoundedValidator(lower=0, upper=7),
+                             doc='Unmirroring options : \n'
+                                 '0 no unmirroring\n'
+                                 '1 sum of left and right\n'
+                                 '2 left\n'
+                                 '3 right\n'
+                                 '4 shift right according to left and sum\n'
+                                 '5 like 4, but use alignment run for peak positions\n'
+                                 '6 center both left and right at zero and sum\n'
+                                 '7 like 6, but use alignment run for peak positions')
+
+        self.declareProperty(name='BackgroundScalingFactor', defaultValue=1.,
+                             validator=FloatBoundedValidator(lower=0),
+                             doc='Scaling factor for background subtraction')
+
+        self.declareProperty(name='CalibrationPeakRange', defaultValue=[-0.003,0.003],
+                             validator=FloatArrayMandatoryValidator(),
+                             doc='Peak range for integration over calibration file peak (in mev)')
+
+        self.declareProperty(FileProperty('MapFile', '',
+                                          action=FileAction.OptionalLoad,
+                                          extensions=['map','xml']),
+                             doc='Filename of the detector grouping map file to use. \n'
+                                 'By default all the pixels will be summed per each tube. \n'
+                                 'Use .map or .xml file (see GroupDetectors documentation) '
+                                 'only if different range is needed for each tube.')
+
+        self.declareProperty(name='ManualPSDIntegrationRange',defaultValue=[1,128],
+                             doc='Integration range of vertical pixels in each PSD tube. \n'
+                                 'By default all the pixels will be summed per each tube. \n'
+                                 'Use this option if the same range (other than default) '
+                                 'is needed for all the tubes.')
+
+        self.declareProperty(name='Analyser',
+                             defaultValue='silicon',
+                             validator=StringListValidator(['silicon']),
+                             doc='Analyser crystal.')
+
+        self.declareProperty(name='Reflection',
+                             defaultValue='111',
+                             validator=StringListValidator(['111', '311']),
+                             doc='Analyser reflection.')
+
+        self.declareProperty(WorkspaceGroupProperty('OutputWorkspace', '',
+                                                    direction=Direction.Output),
+                             doc='Group name for the reduced workspace(s).')
+
+    def validateInputs(self):
+
+        issues = dict()
+
+        uo = self.getProperty('UnmirrorOption').value
+
+        if (uo == 5 or uo == 7) and not self.getPropertyValue('AlignmentRun'):
+            issues['AlignmentRun'] = 'Given UnmirrorOption requires alignment run to be set'
+
+        if self.getPropertyValue('CalibrationRun'):
+            range = self.getProperty('CalibrationPeakRange').value
+            if len(range) != 2:
+                issues['CalibrationPeakRange'] = 'Please provide valid calibration range ' \
+                                                 '(comma separated 2 energy values).'
+            elif range[0] >= range[1]:
+                issues['CalibrationPeakRange'] = 'Please provide valid calibration range. ' \
+                                                 'Start energy is bigger than end energy.'
+
+        return issues
+
+    def setUp(self):
+
+        self._sample_file = self.getPropertyValue('Run')
+        self._alignment_file = self.getPropertyValue('AlignmentRun').replace(',', '+') # automatic summing
+        self._background_file = self.getPropertyValue('BackgroundRun').replace(',', '+') # automatic summing
+        self._calibration_file = self.getPropertyValue('CalibrationRun').replace(',', '+') # automatic summing
+        self._sum_all_runs = self.getProperty('SumRuns').value
+        self._unmirror_option = self.getProperty('UnmirrorOption').value
+        self._back_scaling = self.getProperty('BackgroundScalingFactor').value
+        self._peak_range = self.getProperty('CalibrationPeakRange').value
+
+        self._red_ws = self.getPropertyValue('OutputWorkspace') + '_red'
+
+        # arguments to pass to IndirectILLEnergyTransfer
+        self._common_args['MapFile'] = self.getPropertyValue('MapFile')
+        self._common_args['Analyser'] = self.getPropertyValue('Analyser')
+        self._common_args['Reflection'] = self.getPropertyValue('Reflection')
+        self._common_args['ManualPSDIntegrationRange'] = self.getProperty('ManualPSDIntegrationRange').value
+        self._common_args['CropDeadMonitorChannels'] = self.getProperty('CropDeadMonitorChannels').value
+
+        if self._sum_all_runs is True:
+            self.log().notice('All the sample runs will be summed')
+            self._sample_file = self._sample_file.replace(',', '+')
+
+        # Nexus metadata criteria for QENS type of data
+        self._criteria = '$/entry0/instrument/Doppler/maximum_delta_energy$ != 0. and ' \
+                         '$/entry0/instrument/Doppler/velocity_profile$ == 0'
+
+        # empty list to store all final workspaces to group
+        self._ws_list = []
+
+    def _mask(self, ws, xstart, xend):
+        """
+        Masks the first and last bins
+        @param   ws           :: input workspace name
+        @param   xstart       :: MaskBins between x[0] and x[xstart]
+        @param   xend         :: MaskBins between x[xend] and x[-1]
+        """
+        x_values = mtd[ws].readX(0)
+
+        if xstart > 0:
+            self.log().debug('Mask bins smaller than {0}'.format(xstart))
+            MaskBins(InputWorkspace=ws, OutputWorkspace=ws, XMin=x_values[0], XMax=x_values[xstart])
+
+        if xend < len(x_values) - 1:
+            self.log().debug('Mask bins larger than {0}'.format(xend))
+            MaskBins(InputWorkspace=ws, OutputWorkspace=ws, XMin=x_values[xend + 1], XMax=x_values[-1])
+
+    def _filter_files(self, files, label):
+        '''
+        Filters the given list of files according to nexus criteria
+        @param  files :: list of input files (i.e. , and + separated string)
+        @param  label :: label of error message if nothing left after filtering
+        @throws RuntimeError :: when nothing left after filtering
+        @return :: the list of input files that passsed the criteria
+        '''
+
+        files = SelectNexusFilesByMetadata(files, self._criteria)
+
+        if not files:
+            raise RuntimeError('None of the {0} runs are of QENS type.'
+                               'Check the files or reduction type.'.format(label))
+        else:
+            self.log().information('Filtered {0} runs are: {0} \\n'.format(label,files.replace(',','\\n')))
+
+        return files
+
+    def _filter_all_input_files(self):
+        '''
+        Filters all the lists of input files needed for the reduction.
+        '''
+
+        self._sample_file = self._filter_files(self._sample_file,'sample')
+
+        if self._background_file:
+            self._background_file = self._filter_files(self._background_file, 'background')
+
+        if self._calibration_file:
+            self._calibration_file = self._filter_files(self._calibration_file, 'calibration')
+
+        if self._alignment_file:
+            self._alignment_file = self._filter_files(self._alignment_file, 'alignment')
+
+    def _warn_negative_integral(self, ws, message):
+        '''
+        Raises an error if an integral of the given workspace is <= 0
+        @param ws :: input workspace name
+        @param message :: message suffix for the error
+        @throws RuntimeError :: on non-positive integral found
+        '''
+
+        tmp_int = '__tmp_int'+ws
+        Integration(InputWorkspace=ws,OutputWorkspace=tmp_int)
+
+        for item in mtd[tmp_int]:
+            for index in range(item.getNumberHistograms()):
+                if item.readY(index)[0] <= 0:
+                    raise RuntimeError('Negative or 0 integral in spectrum #{0} {1}'.format(index,message))
+
+        DeleteWorkspace(tmp_int)
+
+    def PyExec(self):
+
+        self.setUp()
+
+        self._filter_all_input_files()
+
+        if self._background_file:
+            background = '__background_'+self._red_ws
+            IndirectILLEnergyTransfer(Run = self._background_file, OutputWorkspace = background, **self._common_args)
+            Scale(InputWorkspace=background ,Factor=self._back_scaling,OutputWorkspace=background)
+
+        if self._calibration_file:
+            calibration = '__calibration_'+self._red_ws
+            IndirectILLEnergyTransfer(Run = self._calibration_file, OutputWorkspace = calibration, **self._common_args)
+            MatchPeaks(InputWorkspace=calibration,OutputWorkspace=calibration,MaskBins=True)
+            Integration(InputWorkspace=calibration,RangeLower=self._peak_range[0],RangeUpper=self._peak_range[1],
+                        OutputWorkspace=calibration)
+            self._warn_negative_integral(calibration,'in calibration run.')
+
+        if self._unmirror_option == 5 or self._unmirror_option == 7:
+            alignment = '__alignment_'+self._red_ws
+            IndirectILLEnergyTransfer(Run = self._alignment_file, OutputWorkspace = alignment, **self._common_args)
+
+        runs = self._sample_file.split(',')
+
+        self._progress = Progress(self, start=0.0, end=1.0, nreports=len(runs))
+
+        for run in runs:
+            self._reduce_run(run)
+
+        if self._background_file:
+            DeleteWorkspace(background)
+
+        if self._calibration_file:
+            DeleteWorkspace(calibration)
+
+        if self._unmirror_option == 5 or self._unmirror_option == 7:
+            DeleteWorkspace(alignment)
+
+        GroupWorkspaces(InputWorkspaces=self._ws_list,OutputWorkspace=self._red_ws)
+
+        # unhide the final workspaces, i.e. remove __ prefix
+        for ws in mtd[self._red_ws]:
+            RenameWorkspace(InputWorkspace=ws,OutputWorkspace=ws.getName()[2:])
+
+        self.setProperty('OutputWorkspace',self._red_ws)
+
+    def _reduce_run(self,run):
+        '''
+        Reduces the given (single or summed multiple) run
+        @param run :: run path
+        '''
+
+        runs_list = run.split('+')
+
+        runnumber = os.path.basename(runs_list[0]).split('.')[0]
+
+        self._progress.report("Reducing run #" + runnumber)
+
+        ws = '__' + runnumber
+
+        if (len(runs_list) > 1):
+            ws += '_multiple'
+
+        ws += '_' + self._red_ws
+
+        back_ws = '__background_'+self._red_ws
+
+        calib_ws = '__calibration_'+self._red_ws
+
+        IndirectILLEnergyTransfer(Run = run, OutputWorkspace = ws, **self._common_args)
+
+        wings = mtd[ws].getNumberOfEntries()
+
+        if self._background_file:
+            if wings == mtd[back_ws].getNumberOfEntries():
+                Minus(LHSWorkspace=ws, RHSWorkspace=back_ws, OutputWorkspace=ws)
+                self._warn_negative_integral(ws,'after background subtraction.')
+            else:
+                raise RuntimeError('Inconsistent mirror sense in background run. Unable to perform subtraction.')
+
+        if self._calibration_file:
+            if wings == mtd[calib_ws].getNumberOfEntries():
+                Divide(LHSWorkspace=ws, RHSWorkspace=calib_ws, OutputWorkspace=ws)
+                self._scale_calibration(ws, calib_ws)
+            else:
+                raise RuntimeError('Inconsistent mirror sense in calibration run. Unable to perform calibration.')
+
+        self._perform_unmirror(ws,runnumber)
+
+        # register to reduced runs list
+        self._ws_list.append(ws)
+
+    def _scale_calibration(self, ws, calib_ws):
+        '''
+        Scales the wings of calibrated sample ws with the maximum
+        of the integrated intensities in each wing of calib ws
+        @param ws       :: calibrated sample workspace
+        @param calib_ws :: calibration workspace
+        '''
+
+        # number of wings are checked to be the same in ws and calib_ws here already
+
+        for wing in range(mtd[ws].getNumberOfEntries()):
+            sample = mtd[ws].getItem(wing).getName()
+            integral = mtd[calib_ws].getItem(wing).getName()
+            scale = numpy.max(mtd[integral].extractY()[:,0])
+            self.log().information("Wing {0} will be scaled up with {1} after calibration"
+                                   .format(wing,scale))
+            Scale(InputWorkspace=sample,Factor=scale,OutputWorkspace=sample,Operation='Multiply')
+
+    def _perform_unmirror(self, ws, run):
+        '''
+        Performs unmirroring, i.e. summing of left and right wings
+        for two-wing data or centering the one wing data
+        @param ws  :: workspace
+        @param run :: runnumber
+        '''
+
+        outname = ws + '_tmp'
+
+        wings = mtd[ws].getNumberOfEntries()
+
+        self.log().information('Unmirroring workspace {0} with option {1}'
+                               .format(ws,self._unmirror_option))
+
+        alignment = '__alignment_'+self._red_ws
+
+        # make sure the sample and alignment runs have the same mirror sense for unmirror 5,7
+        if self._unmirror_option == 5 or self._unmirror_option == 7:
+            if wings != mtd[alignment].getNumberOfEntries():
+                raise RuntimeError('Inconsistent mirror sense in alignment run. Unable to perform unmirror.')
+
+        if wings == 1:   # one wing
+
+            name = mtd[ws].getItem(0).getName()
+
+            if self._unmirror_option < 6:  # do unmirror 0, i.e. nothing
+                CloneWorkspace(InputWorkspace = name, OutputWorkspace = outname)
+            elif self._unmirror_option == 6:
+                MatchPeaks(InputWorkspace = name, OutputWorkspace = outname, MaskBins = True)
+            elif self._unmirror_option == 7:
+                MatchPeaks(InputWorkspace = name, InputWorkspace2 = mtd[alignment].getItem(0).getName(),
+                           MatchInput2ToCenter = True, OutputWorkspace = outname, MaskBins = True)
+
+        elif wings == 2:  # two wing
+
+            left = mtd[ws].getItem(0).getName()
+            right = mtd[ws].getItem(1).getName()
+
+            mask_min = 0
+            mask_max = mtd[left].blocksize()
+
+            if self._unmirror_option == 0:
+                left_out = '__'+run+'_'+self._red_ws+'_left'
+                right_out = '__'+run+'_'+self._red_ws+'_right'
+                CloneWorkspace(InputWorkspace=left, OutputWorkspace=left_out)
+                CloneWorkspace(InputWorkspace=right, OutputWorkspace=right_out)
+                GroupWorkspaces(InputWorkspaces=[left_out,right_out],OutputWorkspace=outname)
+            elif self._unmirror_option == 1:
+                Plus(LHSWorkspace=left, RHSWorkspace=right, OutputWorkspace=outname)
+                Scale(InputWorkspace=outname, OutputWorkspace=outname, Factor=0.5)
+            elif self._unmirror_option == 2:
+                CloneWorkspace(InputWorkspace=left, OutputWorkspace=outname)
+            elif self._unmirror_option == 3:
+                CloneWorkspace(InputWorkspace=right, OutputWorkspace=outname)
+            elif self._unmirror_option == 4:
+                bin_range_table = '__um4_'+right
+                MatchPeaks(InputWorkspace=right, InputWorkspace2=left, OutputWorkspace=right,
+                           MaskBins = True, BinRangeTable = bin_range_table)
+                mask_min = mtd[bin_range_table].row(0)['MinBin']
+                mask_max = mtd[bin_range_table].row(0)['MaxBin']
+                DeleteWorkspace(bin_range_table)
+            elif self._unmirror_option == 5:
+                bin_range_table = '__um5_' + right
+                MatchPeaks(InputWorkspace=right, InputWorkspace2=mtd[alignment].getItem(0).getName(),
+                           InputWorkspace3=mtd[alignment].getItem(1).getName(), OutputWorkspace=right,
+                           MaskBins = True, BinRangeTable = bin_range_table)
+                mask_min = mtd[bin_range_table].row(0)['MinBin']
+                mask_max = mtd[bin_range_table].row(0)['MaxBin']
+                DeleteWorkspace(bin_range_table)
+            elif self._unmirror_option == 6:
+                bin_range_table_left = '__um6_' + left
+                bin_range_table_right = '__um6_' + right
+                MatchPeaks(InputWorkspace=left, OutputWorkspace=left, MaskBins = True,
+                           BinRangeTable = bin_range_table_left)
+                MatchPeaks(InputWorkspace=right, OutputWorkspace=right, MaskBins = True,
+                           BinRangeTable=bin_range_table_right)
+                mask_min = max(mtd[bin_range_table_left].row(0)['MinBin'],mtd[bin_range_table_right].row(0)['MinBin'])
+                mask_max = min(mtd[bin_range_table_left].row(0)['MaxBin'],mtd[bin_range_table_right].row(0)['MaxBin'])
+                DeleteWorkspace(bin_range_table_left)
+                DeleteWorkspace(bin_range_table_right)
+            elif self._unmirror_option == 7:
+                bin_range_table_left = '__um7_' + left
+                bin_range_table_right = '__um7_' + right
+                MatchPeaks(InputWorkspace=left, InputWorkspace2=mtd[alignment].getItem(0).getName(),
+                           OutputWorkspace=left,MatchInput2ToCenter=True,
+                           MaskBins = True, BinRangeTable=bin_range_table_left)
+                MatchPeaks(InputWorkspace=right, InputWorkspace2=mtd[alignment].getItem(1).getName(),
+                           OutputWorkspace=right, MatchInput2ToCenter=True,
+                           MaskBins = True, BinRangeTable=bin_range_table_right)
+                mask_min = max(mtd[bin_range_table_left].row(0)['MinBin'], mtd[bin_range_table_right].row(0)['MinBin'])
+                mask_max = min(mtd[bin_range_table_left].row(0)['MaxBin'], mtd[bin_range_table_right].row(0)['MaxBin'])
+                DeleteWorkspace(bin_range_table_left)
+                DeleteWorkspace(bin_range_table_right)
+
+            if self._unmirror_option > 3:
+                Plus(LHSWorkspace=left, RHSWorkspace=right, OutputWorkspace=outname)
+                Scale(InputWorkspace=outname, OutputWorkspace=outname, Factor=0.5)
+                self._mask(outname, mask_min, mask_max)
+
+        DeleteWorkspace(ws)
+        RenameWorkspace(InputWorkspace=outname,OutputWorkspace=ws)
+
+# Register algorithm with Mantid
+AlgorithmFactory.subscribe(IndirectILLReductionQENS)
diff --git a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/IndirectQuickRun.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/IndirectQuickRun.py
new file mode 100644
index 0000000000000000000000000000000000000000..0fb35475bb708ac01eb89fa7fe59fc43b7ccc34e
--- /dev/null
+++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/IndirectQuickRun.py
@@ -0,0 +1,283 @@
+
+from mantid.api import *
+from mantid.kernel import *
+from mantid import config
+
+import os
+
+
+class IndirectQuickRun(DataProcessorAlgorithm):
+    _chopped_data = None
+    _data_files = None
+    _load_logs = None
+    _calibration_ws = None
+    _instrument_name = None
+    _analyser = None
+    _reflection = None
+    _efixed = None
+    _spectra_range = None
+    _background_range = None
+    _rebin_string = None
+    _detailed_balance = None
+    _grouping_method = None
+    _grouping_ws = None
+    _grouping_map_file = None
+    _output_ws = None
+    _ipf_filename = None
+    _workspace_names = None
+
+    def category(self):
+        return 'Workflow\\Inelastic;Inelastic\\Indirect;Workflow\\MIDAS'
+
+    def summary(self):
+        return 'Runs an energy transfer reduction for an inelastic indirect geometry instrument.'
+
+    def PyInit(self):
+        # Input properties
+        self.declareProperty(StringArrayProperty(name='RunNumbers'),
+                             doc='List of input runs')
+
+        self.declareProperty(name='LoadLogFiles', defaultValue=True,
+                             doc='Load log files when loading runs')
+
+        # Instrument configuration properties
+        self.declareProperty(name='Instrument', defaultValue='',
+                             validator=StringListValidator(['IRIS', 'OSIRIS']),
+                             doc='Instrument used during run.')
+        self.declareProperty(name='Analyser', defaultValue='',
+                             validator=StringListValidator(['graphite', 'mica', 'fmica']),
+                             doc='Analyser bank used during run.')
+        self.declareProperty(name='Reflection', defaultValue='',
+                             validator=StringListValidator(['002', '004', '006']),
+                             doc='Reflection number for instrument setup during run.')
+
+        self.declareProperty(IntArrayProperty(name='SpectraRange', values=[0, 1],
+                                              validator=IntArrayMandatoryValidator()),
+                             doc='Comma separated range of spectra number to use.')
+        self.declareProperty(FloatArrayProperty(name='ElasticRange'),
+                             doc='Range of background to subtract from raw data in time of flight.')
+        self.declareProperty(FloatArrayProperty(name='InelasticRange'),
+                             doc='Range of background to subtract from raw data in time of flight.')
+        self.declareProperty(name='DetailedBalance', defaultValue=Property.EMPTY_DBL,
+                             doc='')
+
+        # Spectra grouping options
+        self.declareProperty(name='GroupingMethod', defaultValue='Individual',
+                             validator=StringListValidator(['Individual', 'All', 'File']),
+                             doc='Method used to group spectra.')
+
+        self.declareProperty(name='SampleEnvironmentLogName', defaultValue='sample',
+                             doc='Name of the sample environment log entry')
+
+        sampEnvLogVal_type = ['last_value', 'average']
+        self.declareProperty('SampleEnvironmentLogValue', 'last_value',
+                             StringListValidator(sampEnvLogVal_type),
+                             doc='Value selection of the sample environment log entry')
+
+        self.declareProperty(name='MSDFit', defaultValue=False,
+                             doc='Perform an MSDFit, do not use with GroupingMethod as "All"')
+
+        self.declareProperty(name='SumFiles', defaultValue=False,
+                             doc='Toggle input file summing or sequential processing')
+
+        self.declareProperty(name='Plot', defaultValue=False,
+                             doc='Switch Plot Off/On')
+        self.declareProperty(name='Save', defaultValue=False,
+                             doc='Switch Save result to nxs file Off/On')
+
+    # pylint: disable=too-many-locals
+    def PyExec(self):
+        setup_progress = Progress(self, 0.0, 0.05, 3)
+        setup_progress.report('Getting Parameters')
+        self._setup()
+
+        scan_alg = self.createChildAlgorithm("EnergyWindowScan", 0.05, 0.95)
+        scan_alg.setProperty('InputFiles', self._data_files)
+        scan_alg.setProperty('LoadLogFiles', self._load_logs)
+        scan_alg.setProperty('CalibrationWorkspace', self._calibration_ws)
+        scan_alg.setProperty('Instrument', self._instrument_name)
+        scan_alg.setProperty('Analyser', self._analyser)
+        scan_alg.setProperty('Reflection', self._reflection)
+        scan_alg.setProperty('SpectraRange', self._spectra_range)
+        scan_alg.setProperty('ElasticRange', self._elastic_range)
+        scan_alg.setProperty('InelasticRange', self._inelastic_range)
+        scan_alg.setProperty('DetailedBalance', self._detailed_balance)
+        scan_alg.setProperty('GroupingMethod', self._grouping_method)
+        scan_alg.setProperty('SampleEnvironmentLogName', self._sample_log_name)
+        scan_alg.setProperty('SampleEnvironmentLogValue', self._sample_log_value)
+        scan_alg.setProperty('MSDFit', self._msdfit)
+        scan_alg.setProperty('ReducedWorkspace', self._output_ws)
+        scan_alg.setProperty('ScanWorkspace', self._scan_ws)
+        scan_alg.execute()
+
+        logger.information('OutputWorkspace : %s' % self._output_ws)
+        logger.information('ScanWorkspace : %s' % self._scan_ws)
+
+        post_progress = Progress(self, 0.95, 1.0, 3)
+        if self._plot:
+            post_progress.report('Plotting')
+            self._plot_result()
+
+        if self._save:
+            post_progress.report('Saving')
+            self._save_output()
+
+        post_progress.report('Algorithm Complete')
+
+    def validateInputs(self):
+        """
+        Validates algorithm properties.
+        """
+        issues = dict()
+
+        # Validate the instrument configuration by checking if a parameter file exists
+        instrument_name = self.getPropertyValue('Instrument')
+        analyser = self.getPropertyValue('Analyser')
+        reflection = self.getPropertyValue('Reflection')
+
+        ipf_filename = os.path.join(config['instrumentDefinition.directory'],
+                                    instrument_name + '_' + analyser + '_' + reflection + '_Parameters.xml')
+
+        if not os.path.exists(ipf_filename):
+            error_message = 'Invalid instrument configuration'
+            issues['Instrument'] = error_message
+            issues['Analyser'] = error_message
+            issues['Reflection'] = error_message
+
+        # Validate spectra range
+        spectra_range = self.getProperty('SpectraRange').value
+        if len(spectra_range) != 2:
+            issues['SpectraRange'] = 'Range must contain exactly two items'
+        elif spectra_range[0] > spectra_range[1]:
+            issues['SpectraRange'] = 'Range must be in format: lower,upper'
+
+        # Validate ranges
+        elastic_range = self.getProperty('ElasticRange').value
+        if elastic_range is not None:
+            if len(elastic_range) != 2:
+                issues['ElasticRange'] = 'Range must contain exactly two items'
+            elif elastic_range[0] > elastic_range[1]:
+                issues['ElasticRange'] = 'Range must be in format: lower,upper'
+        inelastic_range = self.getProperty('InelasticRange').value
+        if inelastic_range is not None:
+            if len(inelastic_range) != 2:
+                issues['InelasticRange'] = 'Range must contain exactly two items'
+            elif inelastic_range[0] > inelastic_range[1]:
+                issues['InelasticRange'] = 'Range must be in format: lower,upper'
+
+        return issues
+
+    def _setup(self):
+        """
+        Gets algorithm properties.
+        """
+
+        # Get properties
+        self._instrument_name = self.getPropertyValue('Instrument')
+
+        runs = self.getProperty('RunNumbers').value
+        self._data_files = []
+        self._format_runs(runs)
+        first_file = self._data_files[0]
+        self._sum_files = self.getProperty('SumFiles').value
+        self._load_logs = self.getProperty('LoadLogFiles').value
+        self._calibration_ws = ''
+
+        self._analyser = self.getPropertyValue('Analyser')
+        self._reflection = self.getPropertyValue('Reflection')
+
+        self._spectra_range = self.getProperty('SpectraRange').value
+        self._elastic_range = self.getProperty('ElasticRange').value
+        self._inelastic_range = self.getProperty('InelasticRange').value
+        self._detailed_balance = self.getProperty('DetailedBalance').value
+
+        self._grouping_method = self.getPropertyValue('GroupingMethod')
+        self._grouping_ws = ''
+        self._grouping_map_file = ''
+
+        self._sample_log_name = self.getPropertyValue('SampleEnvironmentLogName')
+        self._sample_log_value = self.getPropertyValue('SampleEnvironmentLogValue')
+
+        self._msdfit = self.getProperty('msdFit').value
+        if self._msdfit and (self._grouping_method == 'All'):
+            logger.warning("MSDFit will not run if GroupingMethod is 'All'")
+            self._msdfit = False
+
+        self._output_ws = first_file + '_ew_scan_red'
+        self._scan_ws = first_file + '_ew_scan'
+
+        self._plot = self.getProperty('Plot').value
+        self._save = self.getProperty('Save').value
+
+        # Get the IPF filename
+        self._ipf_filename = os.path.join(config['instrumentDefinition.directory'],
+                                          self._instrument_name + '_' + self._analyser + '_' + self._reflection + '_Parameters.xml')
+        logger.information('Instrument parameter file: %s' % self._ipf_filename)
+
+        # Warn when grouping options are to be ignored
+        if self._grouping_method != 'Workspace' and self._grouping_ws is not None:
+            logger.warning('GroupingWorkspace will be ignored by selected GroupingMethod')
+
+        if self._grouping_method != 'File' and self._grouping_map_file is not None:
+            logger.warning('MapFile will be ignored by selected GroupingMethod')
+
+    def _save_output(self):
+        from mantid.simpleapi import SaveNexusProcessed
+        workdir = config['defaultsave.directory']
+        el_eq1_path = os.path.join(workdir, self._scan_ws + '_el_eq1.nxs')
+        logger.information('Creating file : %s' % el_eq1_path)
+        SaveNexusProcessed(InputWorkspace=self._scan_ws + '_el_eq1',
+                           Filename=el_eq1_path)
+        el_eq2_path = os.path.join(workdir, self._scan_ws + '_el_eq2.nxs')
+        logger.information('Creating file : %s' % el_eq2_path)
+        SaveNexusProcessed(InputWorkspace=self._scan_ws + '_el_eq2',
+                           Filename=el_eq2_path)
+
+        inel_eq1_path = os.path.join(workdir, self._scan_ws + '_inel_eq1.nxs')
+        logger.information('Creating file : %s' % inel_eq1_path)
+        SaveNexusProcessed(InputWorkspace=self._scan_ws + '_inel_eq1',
+                           Filename=inel_eq1_path)
+        inel_eq2_path = os.path.join(workdir, self._scan_ws + '_inel_eq2.nxs')
+        logger.information('Creating file : %s' % inel_eq2_path)
+        SaveNexusProcessed(InputWorkspace=self._scan_ws + '_inel_eq2',
+                           Filename=inel_eq2_path)
+
+        eisf_path = os.path.join(workdir, self._scan_ws + '_eisf.nxs')
+        logger.information('Creating file : %s' % eisf_path)
+        SaveNexusProcessed(InputWorkspace=self._scan_ws + '_eisf',
+                           Filename=eisf_path)
+
+        if self._msdfit:
+            msd_path = os.path.join(workdir, self._scan_ws + '_msd.nxs')
+            logger.information('Creating file : %s' % msd_path)
+            SaveNexusProcessed(InputWorkspace=self._scan_ws + '_msd',
+                               Filename=msd_path)
+            msd_fit_path = os.path.join(workdir, self._scan_ws + '_msd_fit.nxs')
+            logger.information('Creating file : %s' % msd_fit_path)
+            SaveNexusProcessed(InputWorkspace=self._scan_ws + '_msd_fit',
+                               Filename=msd_fit_path)
+
+    def _plot_result(self):
+        import mantidplot as mp
+        mp.plotSpectrum(self._scan_ws + '_el_eq1', 0, error_bars=True)
+        mp.plotSpectrum(self._scan_ws + '_inel_eq1', 0, error_bars=True)
+        mp.plotSpectrum(self._scan_ws + '_el_eq2', 0, error_bars=True)
+        mp.plotSpectrum(self._scan_ws + '_inel_eq2', 0, error_bars=True)
+        mp.plotSpectrum(self._scan_ws + '_eisf', 0, error_bars=True)
+        if self._msdfit:
+            mp.plotSpectrum(self._scan_ws + '_msd', 1, error_bars=True)
+
+    def _format_runs(self, runs):
+        run_list = []
+        for run in runs:
+            if '-' in run:
+                a, b = run.split('-')
+                run_list.extend(range(int(a), int(b)+1))
+            else:
+                run_list.append(int(run))
+        for idx in run_list:
+            self._data_files.append(self._instrument_name.lower() + str(idx))
+
+
+# Register algorithm with Mantid
+AlgorithmFactory.subscribe(IndirectQuickRun)
diff --git a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/IndirectResolution.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/IndirectResolution.py
index accc5160f35cb2f846e1edabe6a18a979aca580a..3c02e89dd771886717b6a60df2dcc486ceaefe33 100644
--- a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/IndirectResolution.py
+++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/IndirectResolution.py
@@ -74,7 +74,7 @@ class IndirectResolution(DataProcessorAlgorithm):
         iet_alg.execute()
 
         group_ws = iet_alg.getProperty('OutputWorkspace').value
-        icon_ws = group_ws.getItem(0).getName()
+        icon_ws = group_ws.getItem(0).name()
 
         workflow_prog = Progress(self, start=0.7, end=0.9, nreports=4)
 
diff --git a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/IndirectTransmissionMonitor.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/IndirectTransmissionMonitor.py
index 52924a1df1b667b704bdf09cc707cfbcbbc67483..43c9ffa72e6545fc8f5b9aa6fee1fd7bd65e5636 100644
--- a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/IndirectTransmissionMonitor.py
+++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/IndirectTransmissionMonitor.py
@@ -96,8 +96,9 @@ class IndirectTransmissionMonitor(PythonAlgorithm):
 
         except IndexError:
             # If that fails just get the first spectrum which is a detector
+            spectrumInfo = workspace.spectrumInfo()
             for spec_idx in range(workspace.getNumberHistograms()):
-                if not workspace.getDetector(spec_idx).isMonitor():
+                if not spectrumInfo.isMonitor(spec_idx):
                     detector_1_idx = spec_idx
                     logger.information('Got index of first detector in workspace: %d' % (detector_1_idx))
                     break
diff --git a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/IqtFitSequential.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/IqtFitSequential.py
index 81b66494b90f522e66d0abc92e10b61dbfe3065a..6c043795c42aa09485a5e57bcd43c881b514ffcd 100644
--- a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/IqtFitSequential.py
+++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/IqtFitSequential.py
@@ -120,7 +120,7 @@ class IqtFitSequential(PythonAlgorithm):
             self._spec_max = num_hist - 1
 
         # Name stem for generated workspace
-        output_workspace = '%sIqtFit_%s_s%d_to_%d' % (getWSprefix(self._input_ws.getName()),
+        output_workspace = '%sIqtFit_%s_s%d_to_%d' % (getWSprefix(self._input_ws.name()),
                                                       self._fit_type, self._spec_min,
                                                       self._spec_max)
 
@@ -216,14 +216,14 @@ class IqtFitSequential(PythonAlgorithm):
         copy_log_alg.setProperty("OutputWorkspace", self._fit_group_name)
         copy_log_alg.execute()
         copy_log_alg.setProperty("InputWorkspace", self._input_ws)
-        copy_log_alg.setProperty("OutputWorkspace", self._result_ws.getName())
+        copy_log_alg.setProperty("OutputWorkspace", self._result_ws.name())
         copy_log_alg.execute()
 
         log_names = [item for item in sample_logs]
         log_values = [sample_logs[item] for item in sample_logs]
 
         add_sample_log_multi = self.createChildAlgorithm("AddSampleLogMultiple")
-        add_sample_log_multi.setProperty("Workspace", self._result_ws.getName())
+        add_sample_log_multi.setProperty("Workspace", self._result_ws.name())
         add_sample_log_multi.setProperty("LogNames", log_names)
         add_sample_log_multi.setProperty("LogValues", log_values)
         add_sample_log_multi.execute()
diff --git a/Framework/PythonInterface/plugins/algorithms/MSDFit.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/MSDFit.py
similarity index 64%
rename from Framework/PythonInterface/plugins/algorithms/MSDFit.py
rename to Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/MSDFit.py
index b7bb1ad3bccdfd735676d15edcd47730e4f586e9..0cabaada969696f1d0b8bd7f0189abc385c8b905 100644
--- a/Framework/PythonInterface/plugins/algorithms/MSDFit.py
+++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/MSDFit.py
@@ -1,9 +1,9 @@
-#pylint: disable=no-init
+# pylint: disable=no-init
 from __future__ import (absolute_import, division, print_function)
-from mantid.simpleapi import *
+from mantid.simpleapi import PlotPeakByLogValue, ConvertTableToMatrixWorkspace, SortXAxis, AppendSpectra
 from mantid.api import *
 from mantid.kernel import *
-from six.moves import range #pylint: disable=redefined-builtin
+from six.moves import range
 
 
 class MSDFit(DataProcessorAlgorithm):
@@ -21,7 +21,7 @@ class MSDFit(DataProcessorAlgorithm):
         return 'Fits log(intensity) vs Q-squared to obtain the mean squared displacement.'
 
     def PyInit(self):
-        self.declareProperty(MatrixWorkspaceProperty('InputWorkspace', '',direction=Direction.Input),
+        self.declareProperty(MatrixWorkspaceProperty('InputWorkspace', '', direction=Direction.Input),
                              doc='Sample input workspace')
 
         self.declareProperty(name='XStart', defaultValue=0.0,
@@ -34,7 +34,7 @@ class MSDFit(DataProcessorAlgorithm):
         self.declareProperty(name='SpecMax', defaultValue=0,
                              doc='End of spectra range to be fit')
 
-        self.declareProperty(WorkspaceGroupProperty('OutputWorkspace', '',direction=Direction.Output),
+        self.declareProperty(MatrixWorkspaceProperty('OutputWorkspace', '', direction=Direction.Output),
                              doc='Output mean squared displacement')
 
         self.declareProperty(ITableWorkspaceProperty('ParameterWorkspace', '',
@@ -68,7 +68,7 @@ class MSDFit(DataProcessorAlgorithm):
         if x_max > x_data[-1]:
             issues['XEnd'] = 'Must be less than maximum X value in workspace'
 
-        # Validate specta fitting range
+        # Validate spectra fitting range
         spec_min = self.getProperty('SpecMin').value
         spec_max = self.getProperty('SpecMax').value
 
@@ -101,10 +101,15 @@ class MSDFit(DataProcessorAlgorithm):
                            FitType='Sequential',
                            CreateOutput=True)
 
-        DeleteWorkspace(self._output_msd_ws + '_NormalisedCovarianceMatrices')
-        DeleteWorkspace(self._output_msd_ws + '_Parameters')
-        RenameWorkspace(self._output_msd_ws,
-                        OutputWorkspace=self._output_param_ws)
+        delete_alg = self.createChildAlgorithm("DeleteWorkspace", enableLogging=False)
+        delete_alg.setProperty("Workspace", self._output_msd_ws + '_NormalisedCovarianceMatrices')
+        delete_alg.execute()
+        delete_alg.setProperty("Workspace", self._output_msd_ws + '_Parameters')
+        delete_alg.execute()
+        rename_alg = self.createChildAlgorithm("RenameWorkspace", enableLogging=False)
+        rename_alg.setProperty("InputWorkspace", self._output_msd_ws)
+        rename_alg.setProperty("OutputWorkspace", self._output_param_ws)
+        rename_alg.execute()
 
         params_table = mtd[self._output_param_ws]
 
@@ -119,33 +124,63 @@ class MSDFit(DataProcessorAlgorithm):
         # A0 workspace
         ws_name = self._output_msd_ws + '_A0'
         parameter_ws_group.append(ws_name)
-        ConvertTableToMatrixWorkspace(self._output_param_ws, OutputWorkspace=ws_name,
-                                      ColumnX='axis-1', ColumnY='A0', ColumnE='A0_Err')
+        ConvertTableToMatrixWorkspace(self._output_param_ws,
+                                      OutputWorkspace=ws_name,
+                                      ColumnX='axis-1',
+                                      ColumnY='A0',
+                                      ColumnE='A0_Err',
+                                      EnableLogging=False)
         xunit = mtd[ws_name].getAxis(0).setUnit('Label')
         xunit.setLabel('Temperature', 'K')
+        SortXAxis(InputWorkspace=ws_name,
+                  OutputWorkspace=ws_name,
+                  EnableLogging=False)
 
         # A1 workspace
         ws_name = self._output_msd_ws + '_A1'
         parameter_ws_group.append(ws_name)
-        ConvertTableToMatrixWorkspace(self._output_param_ws, OutputWorkspace=ws_name,
-                                      ColumnX='axis-1', ColumnY='A1', ColumnE='A1_Err')
+        ConvertTableToMatrixWorkspace(self._output_param_ws,
+                                      OutputWorkspace=ws_name,
+                                      ColumnX='axis-1',
+                                      ColumnY='A1',
+                                      ColumnE='A1_Err',
+                                      EnableLogging=False)
         xunit = mtd[ws_name].getAxis(0).setUnit('Label')
         xunit.setLabel('Temperature', 'K')
-        SortXAxis(ws_name, OutputWorkspace=ws_name)
-
-        # Group parameter workspaces
-        GroupWorkspaces(InputWorkspaces=','.join(parameter_ws_group),
-                        OutputWorkspace=self._output_msd_ws)
+        SortXAxis(InputWorkspace=ws_name,
+                  OutputWorkspace=ws_name,
+                  EnableLogging=False)
+
+        AppendSpectra(InputWorkspace1=self._output_msd_ws + '_A0',
+                      InputWorkspace2=self._output_msd_ws + '_A1',
+                      ValidateInputs=False,
+                      OutputWorkspace=self._output_msd_ws,
+                      EnableLogging=False)
+        delete_alg.setProperty("Workspace", self._output_msd_ws + '_A0')
+        delete_alg.execute()
+        delete_alg.setProperty("Workspace", self._output_msd_ws + '_A1')
+        delete_alg.execute()
+        # Create a new vertical axis for the Q and Q**2 workspaces
+        y_axis = NumericAxis.create(2)
+        for idx in range(1):
+            y_axis.setValue(idx, idx)
+        mtd[self._output_msd_ws].replaceAxis(1, y_axis)
 
         # Rename fit workspace group
         original_fit_ws_name = self._output_msd_ws + '_Workspaces'
         if original_fit_ws_name != self._output_fit_ws:
-            RenameWorkspace(InputWorkspace=self._output_msd_ws + '_Workspaces',
-                            OutputWorkspace=self._output_fit_ws)
+            rename_alg.setProperty("InputWorkspace", self._output_msd_ws + '_Workspaces')
+            rename_alg.setProperty("OutputWorkspace", self._output_fit_ws)
+            rename_alg.execute()
 
         # Add sample logs to output workspace
-        CopyLogs(InputWorkspace=self._input_ws, OutputWorkspace=self._output_msd_ws)
-        CopyLogs(InputWorkspace=self._output_msd_ws + '_A0', OutputWorkspace=self._output_fit_ws)
+        copy_alg = self.createChildAlgorithm("CopyLogs", enableLogging=False)
+        copy_alg.setProperty("InputWorkspace", self._input_ws)
+        copy_alg.setProperty("OutputWorkspace", self._output_msd_ws)
+        copy_alg.execute()
+        copy_alg.setProperty("InputWorkspace", self._input_ws)
+        copy_alg.setProperty("OutputWorkspace", self._output_fit_ws)
+        copy_alg.execute()
 
         self.setProperty('OutputWorkspace', self._output_msd_ws)
         self.setProperty('ParameterWorkspace', self._output_param_ws)
@@ -172,4 +207,5 @@ class MSDFit(DataProcessorAlgorithm):
         self._spec_range = [self.getProperty('SpecMin').value,
                             self.getProperty('SpecMax').value]
 
+
 AlgorithmFactory.subscribe(MSDFit)
diff --git a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/PoldiDataAnalysis.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/PoldiDataAnalysis.py
index f6df0b3970011a4caa1b35eec9d036740ef04897..a527e0d957c149ae1d2ba22e324ea828867d688a 100644
--- a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/PoldiDataAnalysis.py
+++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/PoldiDataAnalysis.py
@@ -121,7 +121,7 @@ class PoldiDataAnalysis(PythonAlgorithm):
         outputWs = GroupWorkspaces(self.outputWorkspaces[0])
 
         for ws in self.outputWorkspaces[1:]:
-            outputWs.add(ws.getName())
+            outputWs.add(ws.name())
 
         RenameWorkspace(outputWs, self.getProperty("OutputWorkspace").valueAsStr)
 
@@ -225,7 +225,7 @@ class PoldiDataAnalysis(PythonAlgorithm):
         pawleyFit = self.getProperty('PawleyFit').value
         removeUnindexed = self.getProperty('RemoveUnindexedPeaksFor2DFit').value
         if removeUnindexed or pawleyFit:
-            indexedPeaks.remove(unindexedPeaks.getName())
+            indexedPeaks.remove(unindexedPeaks.name())
 
         self._removeEmptyTablesFromGroup(indexedPeaks)
 
@@ -283,7 +283,7 @@ class PoldiDataAnalysis(PythonAlgorithm):
         for i in range(groupWorkspace.getNumberOfEntries()):
             ws = groupWorkspace.getItem(i)
             if ws.rowCount() == 0:
-                deleteNames.append(ws.getName())
+                deleteNames.append(ws.name())
         for name in deleteNames:
             DeleteWorkspace(name)
 
diff --git a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ReactorSANSResolution.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ReactorSANSResolution.py
index b29aedb56185c5a1a5c09f0bc5a43f36e5ff9e4c..8386bd6e2c803e131e73f635cec57a7400f9b548 100644
--- a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ReactorSANSResolution.py
+++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ReactorSANSResolution.py
@@ -42,7 +42,9 @@ class ReactorSANSResolution(PythonAlgorithm):
             wvl = input_ws.getRun().getProperty("wavelength").value
 
         d_wvl = None
-        if input_ws.getRun().hasProperty("wavelength-spread"):
+        if input_ws.getRun().hasProperty("wavelength-spread-ratio"):
+            d_wvl = input_ws.getRun().getProperty("wavelength-spread-ratio").value
+        elif input_ws.getRun().hasProperty("wavelength-spread"):
             d_wvl = input_ws.getRun().getProperty("wavelength-spread").value
 
         source_apert_radius = None
@@ -67,7 +69,7 @@ class ReactorSANSResolution(PythonAlgorithm):
                 and source_apert_radius is not None and sample_apert_radius is not None \
                 and source_sample_distance is not None and sample_detector_distance is not None:
             k = 2.0*math.pi/wvl
-            res_factor = math.pow(k*source_apert_radius/source_sample_distance, 2)
+            res_factor = math.pow(k*source_apert_radius/source_sample_distance, 2)/4.0
             res_factor += (math.pow(k*sample_apert_radius*(source_sample_distance+sample_detector_distance)/
                                     (source_sample_distance*sample_detector_distance), 2)/4.0)
             res_factor += math.pow(k*pixel_size_x/sample_detector_distance, 2)/12.0
diff --git a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ResNorm2.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ResNorm2.py
index 52c883265c0e3dd28333a870941f42a571ee1407..ceb7d579c0b6d6f2bf462003b80d8f3fb474e4a9 100644
--- a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ResNorm2.py
+++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ResNorm2.py
@@ -113,7 +113,7 @@ class ResNorm(PythonAlgorithm):
             input_str += '%s,i%d;' % (padded_res_ws, idx)
             prog_namer.report('Generating PlotPeak input string')
 
-        base_name = padded_res_ws.getName()
+        base_name = padded_res_ws.name()
         out_name = '%sResNorm_Fit' % (base_name[:-3])
         function = 'name=TabulatedFunction,Workspace=%s,Scaling=1,Shift=0,XScaling=1,ties=(Shift=0)' % self._van_ws
 
diff --git a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANSBeamSpreaderTransmission.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANSBeamSpreaderTransmission.py
index 4faf02d4a7a599a3cc7cde9afd68306ce507a753..5507e453b26a956505c462365a1363c0d2603665 100644
--- a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANSBeamSpreaderTransmission.py
+++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANSBeamSpreaderTransmission.py
@@ -175,7 +175,7 @@ class SANSBeamSpreaderTransmission(PythonAlgorithm):
         input_ws_name = self.getPropertyValue("InputWorkspace")
         if not AnalysisDataService.doesExist(input_ws_name):
             Logger("SANSBeamSpreaderTransmission").error("Could not find input workspace")
-        workspace = AnalysisDataService.retrieve(input_ws_name).getName()
+        workspace = AnalysisDataService.retrieve(input_ws_name).name()
 
         # Clone workspace to make boost-python happy
         api.CloneWorkspace(InputWorkspace=workspace,
diff --git a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANSDarkRunBackgroundCorrection.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANSDarkRunBackgroundCorrection.py
index 509ed637581b307cfcb6692d7723c4e19df610e0..11018387d54f6eec1b61d216009c09502e98742b 100644
--- a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANSDarkRunBackgroundCorrection.py
+++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANSDarkRunBackgroundCorrection.py
@@ -294,9 +294,10 @@ class DarkRunMonitorAndDetectorRemover(object):
         # pylint: disable=bare-except
         try:
             num_histograms = dark_run.getNumberHistograms()
+            spectrumInfo = dark_run.spectrumInfo()
             for index in range(0, num_histograms):
-                det = dark_run.getDetector(index)
-                if det.isMonitor():
+                if spectrumInfo.isMonitor(index):
+                    det = dark_run.getDetector(index)
                     det_id_list.append(det.getID())
                     monitor_list.append(index)
         except:
diff --git a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANSFitShiftScale.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANSFitShiftScale.py
index 1c572a48061ede943d79ca227cfadda9f131e1c4..44bd88d2c05df90ce206b190c0c61451a2e0abd6 100644
--- a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANSFitShiftScale.py
+++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANSFitShiftScale.py
@@ -144,7 +144,15 @@ class SANSFitShiftScale(DataProcessorAlgorithm):
                                                                                          front_data=q_high_angle,
                                                                                          q_min=q_min, q_max=q_max)
 
-        fit = self.createChildAlgorithm('Fit')
+        # The front_data_corrected data set is used as the fit model. Setting the IgnoreInvalidData on the Fit algorithm
+        # will not have any ignore Nans in the model, but only in the data. Hence this will lead to unreadable
+        # error messages of the fit algorithm. We need to catch this before the algorithm starts
+        y_model = front_data_corrected.dataY(0)
+        y_data = rear_data_corrected.dataY(0)
+        if any([np.isnan(element) for element in y_model]) or any([np.isnan(element) for element in y_data]):
+            raise RuntimeError("Trying to merge the two reduced data sets for HAB and LAB failed. "
+                               "You seem to have Nan values in your reduced HAB or LAB data set. This is most likely "
+                               "caused by a too small Q binning. Try to increase the Q bin width.")
 
         # We currently have to put the front_data into the ADS so that the TabulatedFunction has access to it
         front_data_corrected = AnalysisDataService.addOrReplace('front_data_corrected', front_data_corrected)
@@ -153,6 +161,7 @@ class SANSFitShiftScale(DataProcessorAlgorithm):
         function = 'name=TabulatedFunction, Workspace="' + str(
             front_in_ads.name()) + '"' + ";name=FlatBackground"
 
+        fit = self.createChildAlgorithm('Fit')
         fit.setProperty('Function', function)
         fit.setProperty('InputWorkspace', rear_data_corrected)
 
@@ -279,4 +288,5 @@ class ErrorTransferFromModelToData(object):
         comment.setProperty('Text', message)
         comment.execute()
 
+
 AlgorithmFactory.subscribe(SANSFitShiftScale)
diff --git a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANSPatchSensitivity.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANSPatchSensitivity.py
index 4ea35add8b688aa50e718da6c70d220d65d825e2..79b8267025011dd3d8ab77b9f4e19e8cc058ebfc 100644
--- a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANSPatchSensitivity.py
+++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANSPatchSensitivity.py
@@ -97,15 +97,17 @@ class SANSPatchSensitivity(PythonAlgorithm):
         # Array that will be fit
         id_to_fit =[]
 
+        patchDetInfo = patch_ws.detectorInfo()
+        inputDetInfo = in_ws.detectorInfo()
         for pixel_idx in range(tube_in_input_ws.nelements()):
             pixel_in_input_ws = tube_in_input_ws[pixel_idx]
             # ID will be the same in both WS
             detector_id = pixel_in_input_ws.getID()
-            pixel_in_patch_ws  = patch_ws.getInstrument().getDetector(detector_id)
+            detector_idx = detector_id - 1 # See note on hack below
 
-            if pixel_in_patch_ws.isMasked():
+            if patchDetInfo.isMasked(detector_idx):
                 id_to_fit.append(detector_id)
-            elif not pixel_in_input_ws.isMasked():
+            elif not inputDetInfo.isMasked(detector_idx):
                 id_to_calculate_fit.append(detector_id)
                 y_to_calculate_fit.append(in_ws.readY(detector_id).sum())
                 e_to_calculate_fit.append(in_ws.readE(detector_id).sum())
diff --git a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANSStitch.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANSStitch.py
index 70dde02ac4fef3e66367c2e0df2c351d2ed68bfb..40dc0bd69689b55c7c9c41b0e900dd8ece238669 100644
--- a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANSStitch.py
+++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANSStitch.py
@@ -178,7 +178,7 @@ class SANSStitch(DataProcessorAlgorithm):
 
         if ws.getNumberHistograms() != 1:
             # Strip zeros is only possible on 1D workspaces
-            return
+            return ws
 
         y_vals = ws.readY(0)
         length = len(y_vals)
diff --git a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SavePlot1D.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SavePlot1D.py
index 38eca1aa6587961d96690d1f5119b0b9d90a2de7..81d42bcb724061c530cbbedaf997edfcc801ea9c 100644
--- a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SavePlot1D.py
+++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SavePlot1D.py
@@ -3,7 +3,7 @@ from __future__ import (absolute_import, division, print_function)
 from six.moves import range
 
 import mantid
-from mantid.kernel import Direction, StringArrayProperty, StringListValidator
+from mantid.kernel import Direction, IntArrayProperty, StringArrayProperty, StringListValidator
 import sys
 
 try:
@@ -54,6 +54,8 @@ class SavePlot1D(mantid.api.PythonAlgorithm):
                              'Label on the X axis. If empty, it will be taken from workspace')
         self.declareProperty('YLabel', '',
                              'Label on the Y axis. If empty, it will be taken from workspace')
+        self.declareProperty(IntArrayProperty('SpectraList', [], direction=Direction.Input),
+                             'Which spectra to plot')
         self.declareProperty(StringArrayProperty('SpectraNames', [], direction=Direction.Input),
                              'Override with custom names for spectra')
         self.declareProperty('Result', '', Direction.Output)
@@ -75,6 +77,8 @@ class SavePlot1D(mantid.api.PythonAlgorithm):
         self._wksp = self.getProperty("InputWorkspace").value
         outputType = self.getProperty('OutputType').value
 
+        self.visibleSpectra = self.getProperty('SpectraList').value
+
         if outputType == 'image':
             result = self.saveImage()
         else:
@@ -104,6 +108,15 @@ class SavePlot1D(mantid.api.PythonAlgorithm):
 
         return (x, y, label)
 
+    def showSpectrum(self, ws, wkspIndex):
+        spectraNum = ws.getSpectrum(wkspIndex).getSpectrumNo()
+
+        # user not specifying which spectra means show them all
+        if len(self.visibleSpectra) <= 0:
+            return True
+
+        return spectraNum in self.visibleSpectra
+
     def getAxesLabels(self, ws, utf8=False):
         xlabel = self.getProperty('XLabel').value
         if xlabel == '':
@@ -170,7 +183,12 @@ class SavePlot1D(mantid.api.PythonAlgorithm):
                 (x, y, label) = self.getData(wksp, i, spectraNames[i])
             else:
                 (x, y, label) = self.getData(wksp, i)
-            data.append(go.Scatter(x=x, y=y, name=label))
+
+            visible = True
+            if not self.showSpectrum(wksp, i):
+                visible = 'legendonly'
+
+            data.append(go.Scatter(x=x, y=y, name=label, visible=visible))
 
         (xlabel, ylabel) = self.getAxesLabels(wksp, utf8=True)
 
@@ -222,6 +240,9 @@ class SavePlot1D(mantid.api.PythonAlgorithm):
                                             nreports=spectra)
 
         for j in range(spectra):
+            if not self.showSpectrum(ws, j):
+                continue
+
             (x, y, plotlabel) = self.getData(ws, j)
 
             ax.plot(x, y, label=plotlabel)
diff --git a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SimulatedDensityOfStates.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SimulatedDensityOfStates.py
index 7c167c50b9ca607f32e1adcf784228e2ac1e92eb..52a8d0a013186261d258eb8645643cfc14ceba14 100644
--- a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SimulatedDensityOfStates.py
+++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SimulatedDensityOfStates.py
@@ -357,7 +357,7 @@ class SimulatedDensityOfStates(PythonAlgorithm):
 
         else:
             s_api.DeleteWorkspace(sum_workspace)
-            partial_ws_names = [ws.getName() for ws in partial_workspaces]
+            partial_ws_names = [ws.name() for ws in partial_workspaces]
             # Sort workspaces
             if calc_ion_index:
                 # Sort by index after '_'
diff --git a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SofQWMoments.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SofQWMoments.py
index 75939d3a5664fcb3393de86e6a0b9faab6f32318..be70021d5ac19fcff57b770effe69f1759d5b17d 100644
--- a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SofQWMoments.py
+++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SofQWMoments.py
@@ -1,10 +1,6 @@
-#pylint: disable=no-init,invalid-name
 # Algorithm to start Bayes programs
-from __future__ import (absolute_import, division, print_function)
-
 from mantid.simpleapi import *
-from mantid.api import DataProcessorAlgorithm, AlgorithmFactory, MatrixWorkspaceProperty, \
-                       WorkspaceGroupProperty, Progress
+from mantid.api import DataProcessorAlgorithm, AlgorithmFactory, MatrixWorkspaceProperty, NumericAxis, Progress
 from mantid.kernel import Direction
 from mantid import logger
 
@@ -12,121 +8,286 @@ import numpy as np
 
 
 class SofQWMoments(DataProcessorAlgorithm):
-
     def category(self):
         return "Workflow\\MIDAS"
 
-    def summary (self):
+    def summary(self):
         return "Calculates the nth moment of y(q,w)"
 
     def PyInit(self):
-        self.declareProperty(MatrixWorkspaceProperty("Sample", "", Direction.Input),
-                             doc="Sample to use.")
+        self.declareProperty(MatrixWorkspaceProperty("InputWorkspace", "", Direction.Input),
+                             doc="Input workspace to use.")
         self.declareProperty(name='EnergyMin', defaultValue=-0.5,
                              doc='Minimum energy for fit. Default=-0.5')
         self.declareProperty(name='EnergyMax', defaultValue=0.5,
                              doc='Maximum energy for fit. Default=0.5')
         self.declareProperty(name='Scale', defaultValue=1.0,
                              doc='Scale factor to multiply y(Q,w). Default=1.0')
-        self.declareProperty(WorkspaceGroupProperty("OutputWorkspace", "", Direction.Output),
-                             doc="group_workspace workspace that includes all calculated moments.")
+        self.declareProperty(MatrixWorkspaceProperty("OutputWorkspace", "", Direction.Output),
+                             doc="Workspace that includes all calculated moments.")
 
-    #pylint: disable=too-many-locals
     def PyExec(self):
-        from IndirectCommon import CheckHistZero, CheckElimits
 
         workflow_prog = Progress(self, start=0.0, end=1.0, nreports=20)
-        workflow_prog.report('Setting up algorithm')
-        sample_workspace = self.getPropertyValue('Sample')
-        output_workspace = self.getPropertyValue('OutputWorkspace')
-        factor = self.getProperty('Scale').value
-        emin = self.getProperty('EnergyMin').value
-        emax = self.getProperty('EnergyMax').value
-        erange = [emin, emax]
-        workflow_prog.report('Validating input')
-        num_spectra,num_w = CheckHistZero(sample_workspace)
+        self._setup()
 
-        logger.information('Sample %s has %d Q values & %d w values' % (sample_workspace, num_spectra, num_w))
-
-        x_data = np.asarray(mtd[sample_workspace].readX(0))
-        CheckElimits(erange,x_data)
+        workflow_prog.report('Validating input')
+        input_workspace = mtd[self._input_ws]
+        num_spectra, num_w = self._CheckHistZero(self._input_ws)
+        logger.information('Sample %s has %d Q values & %d w values' % (self._input_ws, num_spectra, num_w))
+        self._CheckElimits([self._energy_min, self._energy_max], self._input_ws)
 
         workflow_prog.report('Cropping Workspace')
-        samWS = '__temp_sqw_moments_cropped'
-        CropWorkspace(InputWorkspace=sample_workspace, OutputWorkspace=samWS,
-                      XMin=erange[0], XMax=erange[1])
+        input_ws = '__temp_sqw_moments_cropped'
+        crop_alg = self.createChildAlgorithm("CropWorkspace", enableLogging=False)
+        crop_alg.setProperty("InputWorkspace", input_workspace)
+        crop_alg.setProperty("XMin", self._energy_min)
+        crop_alg.setProperty("XMax", self._energy_max)
+        crop_alg.setProperty("OutputWorkspace", input_ws)
+        crop_alg.execute()
+        mtd.addOrReplace(input_ws, crop_alg.getProperty("OutputWorkspace").value)
 
-        logger.information('Energy range is %f to %f' % (erange[0], erange[1]))
+        logger.information('Energy range is %f to %f' % (self._energy_min, self._energy_max))
 
-        if factor > 0.0:
-            workflow_prog.report('Scaling Workspace by factor %f' % factor)
-            Scale(InputWorkspace=samWS, OutputWorkspace=samWS, Factor=factor, Operation='Multiply')
-            logger.information('y(q,w) scaled by %f' % factor)
+        if self._factor > 0.0:
+            workflow_prog.report('Scaling Workspace by factor %f' % self._factor)
+            scale_alg = self.createChildAlgorithm("Scale", enableLogging=False)
+            scale_alg.setProperty("InputWorkspace", input_ws)
+            scale_alg.setProperty("Factor", self._factor)
+            scale_alg.setProperty("Operation", 'Multiply')
+            scale_alg.setProperty("OutputWorkspace", input_ws)
+            scale_alg.execute()
+            logger.information('y(q,w) scaled by %f' % self._factor)
 
-        #calculate delta x
+        # calculate delta x
         workflow_prog.report('Converting to point data')
-        ConvertToPointData(InputWorkspace=samWS, OutputWorkspace=samWS)
-        x_data = np.asarray(mtd[samWS].readX(0))
+        convert_point_alg = self.createChildAlgorithm("ConvertToPointData", enableLogging=False)
+        convert_point_alg.setProperty("InputWorkspace", input_ws)
+        convert_point_alg.setProperty("OutputWorkspace", input_ws)
+        convert_point_alg.execute()
+        mtd.addOrReplace(input_ws, convert_point_alg.getProperty("OutputWorkspace").value)
+        x_data = np.asarray(mtd[input_ws].readX(0))
         workflow_prog.report('Creating temporary data workspace')
-        x_workspace = CreateWorkspace(OutputWorkspace="__temp_sqw_moments_x",
-                                      DataX=x_data, DataY=x_data, UnitX="DeltaE")
+        x_workspace = "__temp_sqw_moments_x"
+        create_alg = self.createChildAlgorithm("CreateWorkspace", enableLogging=False)
+        create_alg.setProperty("DataX", x_data)
+        create_alg.setProperty("DataY", x_data)
+        create_alg.setProperty("UnitX", "DeltaE")
+        create_alg.setProperty("OutputWorkspace", x_workspace)
+        create_alg.execute()
+        mtd.addOrReplace(x_workspace, create_alg.getProperty("OutputWorkspace").value)
 
-        #calculate moments
-        moments_0 = output_workspace + '_M0'
-        moments_1 = output_workspace + '_M1'
-        moments_2 = output_workspace + '_M2'
-        moments_3 = output_workspace + '_M3'
-        moments_4 = output_workspace + '_M4'
+        # calculate moments
+        multiply_alg = self.createChildAlgorithm("Multiply", enableLogging=False)
 
         workflow_prog.report('Multiplying Workspaces by moments')
-        Multiply(x_workspace, samWS, OutputWorkspace=moments_1)
-        Multiply(x_workspace, moments_1, OutputWorkspace=moments_2)
-        Multiply(x_workspace, moments_2, OutputWorkspace=moments_3)
-        Multiply(x_workspace, moments_3, OutputWorkspace=moments_4)
-        DeleteWorkspace(moments_3)
+        moments_0 = self._output_ws + '_M0'
+        moments_1 = self._output_ws + '_M1'
+        multiply_alg.setProperty("LHSWorkspace", x_workspace)
+        multiply_alg.setProperty("RHSWorkspace", input_ws)
+        multiply_alg.setProperty("OutputWorkspace", moments_1)
+        multiply_alg.execute()
+        mtd.addOrReplace(moments_1, multiply_alg.getProperty("OutputWorkspace").value)
+
+        moments_2 = self._output_ws + '_M2'
+        multiply_alg.setProperty("LHSWorkspace", x_workspace)
+        multiply_alg.setProperty("RHSWorkspace", moments_1)
+        multiply_alg.setProperty("OutputWorkspace", moments_2)
+        multiply_alg.execute()
+        mtd.addOrReplace(moments_2, multiply_alg.getProperty("OutputWorkspace").value)
+
+        moments_3 = self._output_ws + '_M3'
+        multiply_alg.setProperty("LHSWorkspace", x_workspace)
+        multiply_alg.setProperty("RHSWorkspace", moments_2)
+        multiply_alg.setProperty("OutputWorkspace", moments_3)
+        multiply_alg.execute()
+        mtd.addOrReplace(moments_3, multiply_alg.getProperty("OutputWorkspace").value)
+
+        moments_4 = self._output_ws + '_M4'
+        multiply_alg.setProperty("LHSWorkspace", x_workspace)
+        multiply_alg.setProperty("RHSWorkspace", moments_3)
+        multiply_alg.setProperty("OutputWorkspace", moments_4)
+        multiply_alg.execute()
+        mtd.addOrReplace(moments_4, multiply_alg.getProperty("OutputWorkspace").value)
 
         workflow_prog.report('Converting to Histogram')
-        ConvertToHistogram(InputWorkspace=samWS, OutputWorkspace=samWS)
-        workflow_prog.report('Intergrating result')
-        Integration(samWS, OutputWorkspace=moments_0)
+        convert_hist_alg = self.createChildAlgorithm("ConvertToHistogram", enableLogging=False)
+        convert_hist_alg.setProperty("InputWorkspace", input_ws)
+        convert_hist_alg.setProperty("OutputWorkspace", input_ws)
+        convert_hist_alg.execute()
+
+        workflow_prog.report('Integrating result')
+        integration_alg = self.createChildAlgorithm("Integration", enableLogging=False)
+        integration_alg.setProperty("InputWorkspace", convert_hist_alg.getProperty("OutputWorkspace").value)
+        integration_alg.setProperty("OutputWorkspace", moments_0)
+        integration_alg.execute()
+        mtd.addOrReplace(moments_0, integration_alg.getProperty("OutputWorkspace").value)
 
-        moments = [moments_1, moments_2, moments_4]
+        moments = [moments_1, moments_2, moments_3, moments_4]
+        divide_alg = self.createChildAlgorithm("Divide", enableLogging=False)
         for moment_ws in moments:
             workflow_prog.report('Processing workspace %s' % moment_ws)
-            ConvertToHistogram(InputWorkspace=moment_ws, OutputWorkspace=moment_ws)
-            Integration(moment_ws, OutputWorkspace=moment_ws)
-            Divide(moment_ws, moments_0, OutputWorkspace=moment_ws)
+            convert_hist_alg.setProperty("InputWorkspace", moment_ws)
+            convert_hist_alg.setProperty("OutputWorkspace", moment_ws)
+            convert_hist_alg.execute()
+
+            integration_alg.setProperty("InputWorkspace", convert_hist_alg.getProperty("OutputWorkspace").value)
+            integration_alg.setProperty("OutputWorkspace", moment_ws)
+            integration_alg.execute()
+
+            divide_alg.setProperty("LHSWorkspace", integration_alg.getProperty("OutputWorkspace").value)
+            divide_alg.setProperty("RHSWorkspace", moments_0)
+            divide_alg.setProperty("OutputWorkspace", moment_ws)
+            divide_alg.execute()
+            mtd.addOrReplace(moment_ws, divide_alg.getProperty("OutputWorkspace").value)
 
         workflow_prog.report('Deleting Workspaces')
-        DeleteWorkspace(samWS)
-        DeleteWorkspace(x_workspace)
+        delete_alg = self.createChildAlgorithm("DeleteWorkspace", enableLogging=False)
+        delete_alg.setProperty("Workspace", input_ws)
+        delete_alg.execute()
+        delete_alg.setProperty("Workspace", x_workspace)
+        delete_alg.execute()
 
-        #create output workspace
-        extensions = ['_M0', '_M1', '_M2', '_M4']
+        # create output workspace
+        extensions = ['_M0', '_M1', '_M2', '_M3', '_M4']
+        transpose_alg = self.createChildAlgorithm("Transpose", enableLogging=False)
+        convert_hist_alg = self.createChildAlgorithm("ConvertToHistogram", enableLogging=False)
+        convert_units_alg = self.createChildAlgorithm("ConvertUnits", enableLogging=False)
         for ext in extensions:
-            ws_name = output_workspace+ext
+            ws_name = self._output_ws + ext
             workflow_prog.report('Processing Workspace %s' % ext)
-            Transpose(InputWorkspace=ws_name, OutputWorkspace=ws_name)
-            ConvertToHistogram(InputWorkspace=ws_name, OutputWorkspace=ws_name)
-            ConvertUnits(InputWorkspace=ws_name, OutputWorkspace=ws_name,
-                         Target='MomentumTransfer', EMode='Indirect')
+            transpose_alg.setProperty("InputWorkspace", ws_name)
+            transpose_alg.setProperty("OutputWorkspace", ws_name)
+            transpose_alg.execute()
+            convert_hist_alg.setProperty("InputWorkspace", transpose_alg.getProperty("OutputWorkspace").value)
+            convert_hist_alg.setProperty("OutputWorkspace", ws_name)
+            convert_hist_alg.execute()
+            convert_units_alg.setProperty("InputWorkspace", convert_hist_alg.getProperty("OutputWorkspace").value)
+            convert_units_alg.setProperty("Target", 'MomentumTransfer')
+            convert_units_alg.setProperty("EMode", 'Indirect')
+            convert_units_alg.setProperty("OutputWorkspace", ws_name)
+            convert_units_alg.execute()
+            mtd.addOrReplace(ws_name, convert_units_alg.getProperty("OutputWorkspace").value)
 
-            CopyLogs(InputWorkspace=sample_workspace, OutputWorkspace=ws_name)
             workflow_prog.report('Adding Sample logs to %s' % ws_name)
-            AddSampleLog(Workspace=ws_name, LogName="energy_min",
-                         LogType="Number", LogText=str(emin))
-            AddSampleLog(Workspace=ws_name, LogName="energy_max",
-                         LogType="Number", LogText=str(emax))
-            AddSampleLog(Workspace=ws_name, LogName="scale_factor",
-                         LogType="Number", LogText=str(factor))
+            copy_alg = self.createChildAlgorithm("CopyLogs", enableLogging=False)
+            copy_alg.setProperty("InputWorkspace", input_workspace)
+            copy_alg.setProperty("OutputWorkspace", ws_name)
+            copy_alg.execute()
+            add_sample_log_alg = self.createChildAlgorithm("AddSampleLog", enableLogging=False)
+            add_sample_log_alg.setProperty("Workspace", ws_name)
+            add_sample_log_alg.setProperty("LogName", "energy_min")
+            add_sample_log_alg.setProperty("LogType", "Number")
+            add_sample_log_alg.setProperty("LogText", str(self._energy_min))
+            add_sample_log_alg.execute()
+            add_sample_log_alg.setProperty("Workspace", ws_name)
+            add_sample_log_alg.setProperty("LogName", "energy_max")
+            add_sample_log_alg.setProperty("LogType", "Number")
+            add_sample_log_alg.setProperty("LogText", str(self._energy_max))
+            add_sample_log_alg.execute()
+            add_sample_log_alg.setProperty("Workspace", ws_name)
+            add_sample_log_alg.setProperty("LogName", "scale_factor")
+            add_sample_log_alg.setProperty("LogType", "Number")
+            add_sample_log_alg.setProperty("LogText", str(self._factor))
+            add_sample_log_alg.execute()
 
         # Group output workspace
-        workflow_prog.report('Grouping OutputWorkspace')
-        group_workspaces = ','.join([output_workspace+ext for ext in extensions])
-        GroupWorkspaces(InputWorkspaces=group_workspaces, OutputWorkspace=output_workspace)
+        workflow_prog.report('Appending moments')
+        append_alg = self.createChildAlgorithm("AppendSpectra", enableLogging=False)
+        append_alg.setProperty("InputWorkspace1", self._output_ws + '_M0')
+        append_alg.setProperty("InputWorkspace2", self._output_ws + '_M1')
+        append_alg.setProperty("ValidateInputs", False)
+        append_alg.setProperty("OutputWorkspace", self._output_ws)
+        append_alg.execute()
+        append_alg.setProperty("InputWorkspace1", append_alg.getProperty("OutputWorkspace").value)
+        append_alg.setProperty("InputWorkspace2", self._output_ws + '_M2')
+        append_alg.setProperty("ValidateInputs", False)
+        append_alg.setProperty("OutputWorkspace", self._output_ws)
+        append_alg.execute()
+        append_alg.setProperty("InputWorkspace1", append_alg.getProperty("OutputWorkspace").value)
+        append_alg.setProperty("InputWorkspace2", self._output_ws + '_M3')
+        append_alg.setProperty("ValidateInputs", False)
+        append_alg.setProperty("OutputWorkspace", self._output_ws)
+        append_alg.execute()
+        append_alg.setProperty("InputWorkspace1", append_alg.getProperty("OutputWorkspace").value)
+        append_alg.setProperty("InputWorkspace2", self._output_ws + '_M4')
+        append_alg.setProperty("ValidateInputs", False)
+        append_alg.setProperty("OutputWorkspace", self._output_ws)
+        append_alg.execute()
+        mtd.addOrReplace(self._output_ws, append_alg.getProperty("OutputWorkspace").value)
+        delete_alg.setProperty("Workspace", self._output_ws + '_M0')
+        delete_alg.execute()
+        delete_alg.setProperty("Workspace", self._output_ws + '_M1')
+        delete_alg.execute()
+        delete_alg.setProperty("Workspace", self._output_ws + '_M2')
+        delete_alg.execute()
+        delete_alg.setProperty("Workspace", self._output_ws + '_M3')
+        delete_alg.execute()
+        delete_alg.setProperty("Workspace", self._output_ws + '_M4')
+        delete_alg.execute()
+
+        # Create a new vertical axis for the Q and Q**2 workspaces
+        y_axis = NumericAxis.create(5)
+        for idx in range(5):
+            y_axis.setValue(idx, idx)
+        mtd[self._output_ws].replaceAxis(1, y_axis)
+
+        self.setProperty("OutputWorkspace", self._output_ws)
+
+    def _setup(self):
+        """
+        Gets algorithm properties.
+        """
+
+        self._input_ws = self.getPropertyValue('InputWorkspace')
+        self._factor = self.getProperty('Scale').value
+        self._energy_min = self.getProperty('EnergyMin').value
+        self._energy_max = self.getProperty('EnergyMax').value
+        self._output_ws = self.getPropertyValue('OutputWorkspace')
+
+    def _CheckHistZero(self, ws):
+        """
+        Retrieves basic info on a workspace
+
+        Checks the workspace is not empty, then returns the number of histogram and
+        the number of X-points, which is the number of bin boundaries minus one
+
+        Args:
+          @param ws  2D workspace
+
+        Returns:
+          @return num_hist - number of histograms in the workspace
+          @return ntc - number of X-points in the first histogram, which is the number of bin
+           boundaries minus one. It is assumed all histograms have the same
+           number of X-points.
+
+        Raises:
+          @exception ValueError - Workspace has no histograms
+        """
+        num_hist = mtd[ws].getNumberHistograms()  # no. of hist/groups in WS
+        if num_hist == 0:
+            raise ValueError('Workspace %s has NO histograms' % ws)
+        x_in = mtd[ws].readX(0)
+        ntc = len(x_in) - 1  # no. points from length of x array
+        if ntc == 0:
+            raise ValueError('Workspace %s has NO points' % ws)
+        return num_hist, ntc
+
+    def _CheckElimits(self, erange, ws):
+        import math
+        x_data = np.asarray(mtd[ws].readX(0))
+        len_x = len(x_data) - 1
 
-        self.setProperty("OutputWorkspace", output_workspace)
-        workflow_prog.report('Algorithm complete')
+        if math.fabs(erange[0]) < 1e-5:
+            raise ValueError('Elimits - input emin (%f) is Zero' % (erange[0]))
+        if erange[0] < x_data[0]:
+            raise ValueError('Elimits - input emin (%f) < data emin (%f)' % (erange[0], x_data[0]))
+        if math.fabs(erange[1]) < 1e-5:
+            raise ValueError('Elimits - input emax (%f) is Zero' % (erange[1]))
+        if erange[1] > x_data[len_x]:
+            raise ValueError('Elimits - input emax (%f) > data emax (%f)' % (erange[1], x_data[len_x]))
+        if erange[1] < erange[0]:
+            raise ValueError('Elimits - input emax (%f) < emin (%f)' % (erange[1], erange[0]))
 
 
 # Register algorithm with Mantid
diff --git a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SofQWMomentsScan.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SofQWMomentsScan.py
new file mode 100644
index 0000000000000000000000000000000000000000..22ffc67b46f9ce75e2f874356a009da663be4ca9
--- /dev/null
+++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SofQWMomentsScan.py
@@ -0,0 +1,485 @@
+from mantid.kernel import *
+from mantid.api import *
+from mantid.simpleapi import *
+from mantid import config
+
+import os
+import numpy as np
+
+
+class SofQWMomentsScan(DataProcessorAlgorithm):
+    _data_files = None
+    _sum_files = None
+    _load_logs = None
+    _calibration_ws = None
+    _instrument_name = None
+    _analyser = None
+    _reflection = None
+    _efixed = None
+    _resolution = None
+    _spectra_range = None
+    _background_range = None
+    _rebin_string = None
+    _detailed_balance = None
+    _grouping_method = None
+    _grouping_ws = None
+    _grouping_map_file = None
+    _output_x_units = None
+    _ipf_filename = None
+    _sample_log_name = None
+    _sample_log_value = None
+    _workspace_names = None
+
+    def category(self):
+        return 'Workflow\\Inelastic;Inelastic\\Indirect;Workflow\\MIDAS'
+
+    def summary(self):
+        return 'Runs an energy transfer reduction for an inelastic indirect geometry instrument.'
+
+    def PyInit(self):
+        # Input properties
+        self.declareProperty(StringArrayProperty(name='InputFiles'),
+                             doc='Comma separated list of input files')
+
+        self.declareProperty(name='LoadLogFiles', defaultValue=True,
+                             doc='Load log files when loading runs')
+
+        self.declareProperty(WorkspaceProperty('CalibrationWorkspace', '',
+                                               direction=Direction.Input,
+                                               optional=PropertyMode.Optional),
+                             doc='Workspace containing calibration data')
+
+        # Instrument configuration properties
+        self.declareProperty(name='Instrument', defaultValue='',
+                             validator=StringListValidator(['IRIS', 'OSIRIS']),
+                             doc='Instrument used during run.')
+        self.declareProperty(name='Analyser', defaultValue='',
+                             validator=StringListValidator(['graphite', 'mica', 'fmica']),
+                             doc='Analyser bank used during run.')
+        self.declareProperty(name='Reflection', defaultValue='',
+                             validator=StringListValidator(['002', '004', '006']),
+                             doc='Reflection number for instrument setup during run.')
+
+        self.declareProperty(IntArrayProperty(name='SpectraRange', values=[0, 1],
+                                              validator=IntArrayMandatoryValidator()),
+                             doc='Comma separated range of spectra number to use.')
+        self.declareProperty(FloatArrayProperty(name='QRange'),
+                             doc='Range of background to subtract from raw data in time of flight.')
+        self.declareProperty(FloatArrayProperty(name='EnergyRange'),
+                             doc='Range of background to subtract from raw data in time of flight.')
+        self.declareProperty(name='DetailedBalance', defaultValue=Property.EMPTY_DBL,
+                             doc='Apply the detailed balance correction')
+
+        # Spectra grouping options
+        self.declareProperty(name='GroupingMethod', defaultValue='Individual',
+                             validator=StringListValidator(['Individual', 'All', 'File', 'Workspace', 'IPF']),
+                             doc='Method used to group spectra.')
+        self.declareProperty(WorkspaceProperty('GroupingWorkspace', '',
+                                               direction=Direction.Input,
+                                               optional=PropertyMode.Optional),
+                             doc='Workspace containing spectra grouping.')
+        self.declareProperty(FileProperty('MapFile', '',
+                                          action=FileAction.OptionalLoad,
+                                          extensions=['.map']),
+                             doc='File containing spectra grouping.')
+
+        self.declareProperty(name='SampleEnvironmentLogName', defaultValue='sample',
+                             doc='Name of the sample environment log entry')
+
+        sampEnvLogVal_type = ['last_value', 'average']
+        self.declareProperty('SampleEnvironmentLogValue', 'last_value',
+                             StringListValidator(sampEnvLogVal_type),
+                             doc='Value selection of the sample environment log entry')
+
+        # Output properties
+        self.declareProperty('ReducedWorkspace', defaultValue='Reduced',
+                             doc='The output reduced workspace.')
+        self.declareProperty('SqwWorkspace', defaultValue='Sqw',
+                             doc='The output Sqw workspace.')
+        self.declareProperty(name='MomentWorkspace', defaultValue='Moment',
+                             doc='The output Moment workspace.')
+
+    def PyExec(self):
+
+        self._setup()
+        progress = Progress(self, 0.0, 0.05, 3)
+
+        progress.report('Energy transfer')
+        scan_alg = self.createChildAlgorithm("ISISIndirectEnergyTransfer", 0.05, 0.95)
+        scan_alg.setProperty('InputFiles', self._data_files)
+        scan_alg.setProperty('SumFiles', self._sum_files)
+        scan_alg.setProperty('LoadLogFiles', self._load_logs)
+        scan_alg.setProperty('CalibrationWorkspace', self._calibration_ws)
+        scan_alg.setProperty('Instrument', self._instrument_name)
+        scan_alg.setProperty('Analyser', self._analyser)
+        scan_alg.setProperty('Reflection', self._reflection)
+        scan_alg.setProperty('Efixed', self._efixed)
+        scan_alg.setProperty('SpectraRange', self._spectra_range)
+        scan_alg.setProperty('BackgroundRange', self._background_range)
+        scan_alg.setProperty('RebinString', self._rebin_string)
+        scan_alg.setProperty('DetailedBalance', self._detailed_balance)
+        scan_alg.setProperty('ScaleFactor', self._scale_factor)
+        scan_alg.setProperty('FoldMultipleFrames', self._fold_multiple_frames)
+        scan_alg.setProperty('GroupingMethod', self._grouping_method)
+        scan_alg.setProperty('GroupingWorkspace', self._grouping_ws)
+        scan_alg.setProperty('MapFile', self._grouping_map_file)
+        scan_alg.setProperty('UnitX', self._output_x_units)
+        scan_alg.setProperty('OutputWorkspace', self._red_ws)
+        scan_alg.execute()
+        logger.information('ReducedWorkspace : %s' % self._red_ws)
+
+        Rebin(InputWorkspace=self._red_ws,
+              OutputWorkspace=self._red_ws,
+              Params=self._energy_range,
+              EnableLogging=False)
+
+        input_workspace_names = mtd[self._red_ws].getNames()
+
+        inst = mtd[input_workspace_names[0]].getInstrument()
+        if inst.hasParameter('analyser'):
+            analyser_name = inst.getStringParameter('analyser')[0]
+            analyser_comp = inst.getComponentByName(analyser_name)
+            if analyser_comp is not None and analyser_comp.hasParameter('resolution'):
+                self._resolution = float(analyser_comp.getNumberParameter('resolution')[0])
+            else:
+                self._resolution = 0.01
+        logger.information('Resolution = %d' % self._resolution)
+
+        output_workspaces = list()
+        temperatures = list()
+        run_numbers = list()
+        sofqw_alg = self.createChildAlgorithm("SofQW", enableLogging=False)
+        group_alg = self.createChildAlgorithm("GroupWorkspaces", enableLogging=False)
+
+        for input_ws in input_workspace_names:
+            progress.report('SofQW for workspace: %s' % input_ws)
+            sofqw_alg.setProperty("InputWorkspace", input_ws)
+            sofqw_alg.setProperty("QAxisBinning", self._q_range)
+            sofqw_alg.setProperty("EMode", 'Indirect')
+            sofqw_alg.setProperty("ReplaceNaNs", True)
+            sofqw_alg.setProperty("Method", 'Polygon')
+            sofqw_alg.setProperty("OutputWorkspace", input_ws + '_sqw')
+            sofqw_alg.execute()
+            mtd.addOrReplace(input_ws + '_sqw', sofqw_alg.getProperty("OutputWorkspace").value)
+            output_workspaces.append(input_ws + '_sqw')
+
+            # Get the sample temperature
+            temp = self._get_temperature(input_ws + '_sqw')
+            if temp is not None:
+                temperatures.append(temp)
+            else:
+                # Get the run number
+                run_no = self._get_InstrRun(input_ws)[1]
+                run_numbers.append(run_no)
+
+        y_axis = mtd[input_workspace_names[0] + '_sqw'].getAxis(1)
+        y_values = y_axis.extractValues()
+        q = list()
+        for idx in range(len(y_values)):
+            q.append(y_values[idx])
+        group_alg.setProperty("InputWorkspaces", output_workspaces)
+        group_alg.setProperty("OutputWorkspace", self._sqw_ws)
+        group_alg.execute()
+        mtd.addOrReplace(self._sqw_ws, group_alg.getProperty("OutputWorkspace").value)
+        logger.information('Sqw Workspace : %s' % self._sqw_ws)
+
+        # Get input workspaces
+        input_workspace_names = mtd[self._sqw_ws].getNames()
+        output_workspaces = list()
+        width_workspaces = list()
+
+        delete_alg = self.createChildAlgorithm("DeleteWorkspace", enableLogging=False)
+        create_alg = self.createChildAlgorithm("CreateWorkspace", enableLogging=False)
+        for input_ws in input_workspace_names:
+            progress.report('SofQWMoments for workspace: %s' % input_ws)
+            SofQWMoments(InputWorkspace=input_ws,
+                         EnergyMin=self._energy_range[0],
+                         EnergyMax=self._energy_range[2],
+                         Scale=self._scale_factor,
+                         OutputWorkspace=input_ws + '_mom',
+                         EnableLogging=False)
+            output_workspaces.append(input_ws + '_mom')
+            progress.report('Fitting workspace: %s' % input_ws)
+            num_hist = mtd[input_ws].getNumberHistograms()
+            result = '__result'
+            params_table = '__result_Parameters'
+            dataX = list()
+            dataY = list()
+            dataE = list()
+            func = 'name=Lorentzian,Amplitude=1.0,PeakCentre=0.0,FWHM=0.01'
+            func += ',constraint=(Amplitude>0.0,FWHM>0.0)'
+            for idx in range(num_hist):
+                Fit(InputWorkspace=input_ws,
+                    Function=func,
+                    DomainType='Simple',
+                    WorkspaceIndex=idx,
+                    Minimizer='Levenberg-Marquardt',
+                    MaxIterations=500,
+                    CreateOutput=True,
+                    Output=result,
+                    OutputParametersOnly=False,
+                    EnableLogging=False)
+                dataX.append(q[idx])
+                para_y = np.asarray(mtd[params_table].column('Value'))
+                dataY.append(para_y[2])
+                para_e = np.asarray(mtd[params_table].column('Error'))
+                dataE.append(para_e[2])
+            progress.report('Creating width workspace')
+            width_ws = input_ws + '_width'
+            create_alg.setProperty("OutputWorkspace", width_ws)
+            create_alg.setProperty("DataX", dataX)
+            create_alg.setProperty("DataY", dataY)
+            create_alg.setProperty("DataE", dataE)
+            create_alg.setProperty("NSpec", 1)
+            create_alg.setProperty("UnitX", 'MomentumTransfer')
+            create_alg.setProperty("YUnitLabel", 'FWHM')
+            create_alg.execute()
+            mtd.addOrReplace(width_ws, create_alg.getProperty("OutputWorkspace").value)
+            width_workspaces.append(width_ws)
+            delete_alg.setProperty("Workspace", params_table)
+            delete_alg.execute()
+            delete_alg.setProperty("Workspace", result + '_NormalisedCovarianceMatrix')
+            delete_alg.execute()
+            delete_alg.setProperty("Workspace", result + '_Workspace')
+            delete_alg.execute()
+        logger.information('Moment Workspace : %s' % self._moment_ws)
+
+        width_workspace = self._sqw_ws + '_width'
+        clone_alg = self.createChildAlgorithm("CloneWorkspace", enableLogging=True)
+        append_alg = self.createChildAlgorithm("AppendSpectra", enableLogging=True)
+        for idx in range(len(width_workspaces)):
+            if idx == 0:
+                clone_alg.setProperty("InputWorkspace", width_workspaces[0])
+                clone_alg.setProperty("OutputWorkspace", width_workspace)
+                clone_alg.execute()
+                mtd.addOrReplace(width_workspace, clone_alg.getProperty("OutputWorkspace").value)
+            else:
+                append_alg.setProperty("InputWorkspace1", width_workspace)
+                append_alg.setProperty("InputWorkspace2", width_workspaces[idx])
+                append_alg.setProperty("OutputWorkspace", width_workspace)
+                append_alg.execute()
+                mtd.addOrReplace(width_workspace, append_alg.getProperty("OutputWorkspace").value)
+        logger.information('Width Workspace : %s' % width_workspace)
+
+        numb_temp = len(temperatures)
+        x_axis_is_temp = len(input_workspace_names) == numb_temp
+
+        if x_axis_is_temp:
+            logger.information('X axis is in temperature')
+            unit = ('Temperature', 'K')
+        else:
+            logger.information('X axis is in run number')
+            unit = ('Run No', 'last 3 digits')
+
+        xdat = list()
+        ydat = list()
+        edat = list()
+        for idx in range(len(temperatures)):
+            x = mtd[width_workspace].readX(idx)
+            y = mtd[width_workspace].readY(idx)
+            e = mtd[width_workspace].readE(idx)
+            if x_axis_is_temp:
+                xdat.append(float(temperatures[idx]))
+            else:
+                xdat.append(float(run_numbers[idx][-3:]))
+            ydat.append(y[5] / x[5])
+            edat.append(e[5] / x[5])
+        diffusion_workspace = self._sqw_ws + '_diffusion'
+        create_alg = self.createChildAlgorithm("CreateWorkspace", enableLogging=False)
+        create_alg.setProperty("OutputWorkspace", diffusion_workspace)
+        create_alg.setProperty("DataX", xdat)
+        create_alg.setProperty("DataY", ydat)
+        create_alg.setProperty("DataE", edat)
+        create_alg.setProperty("NSpec", 1)
+        create_alg.setProperty("YUnitLabel", 'Diffusion')
+        create_alg.execute()
+        mtd.addOrReplace(diffusion_workspace, create_alg.getProperty("OutputWorkspace").value)
+        unitx = mtd[diffusion_workspace].getAxis(0).setUnit("Label")
+        unitx.setLabel(unit[0], unit[1])
+        logger.information('Diffusion Workspace : %s' % diffusion_workspace)
+
+    def validateInputs(self):
+        """
+        Validates algorithm properties.
+        """
+        issues = dict()
+
+        # Validate the instrument configuration by checking if a parameter file exists
+        instrument_name = self.getPropertyValue('Instrument')
+        analyser = self.getPropertyValue('Analyser')
+        reflection = self.getPropertyValue('Reflection')
+
+        ipf_filename = os.path.join(config['instrumentDefinition.directory'],
+                                    instrument_name + '_' + analyser + '_' + reflection + '_Parameters.xml')
+
+        if not os.path.exists(ipf_filename):
+            error_message = 'Invalid instrument configuration'
+            issues['Instrument'] = error_message
+            issues['Analyser'] = error_message
+            issues['Reflection'] = error_message
+
+        # Validate spectra range
+        spectra_range = self.getProperty('SpectraRange').value
+        if len(spectra_range) != 2:
+            issues['SpectraRange'] = 'Range must contain exactly two items'
+        elif spectra_range[0] > spectra_range[1]:
+            issues['SpectraRange'] = 'Range must be in format: lower,upper'
+
+        # Validate ranges
+        q_range = self.getProperty('QRange').value
+        if q_range is not None:
+            if len(q_range) != 3:
+                issues['QRange'] = 'Range must contain exactly two items'
+            elif q_range[0] > q_range[2]:
+                issues['QRange'] = 'Range must be in format: lower,upper'
+        energy_range = self.getProperty('EnergyRange').value
+        if energy_range is not None:
+            if len(energy_range) != 3:
+                issues['EnergyRange'] = 'Range must contain exactly two items'
+            elif energy_range[0] > energy_range[2]:
+                issues['EnergyRange'] = 'Range must be in format: lower,upper'
+
+        return issues
+
+    def _setup(self):
+        """
+        Gets algorithm properties.
+        """
+
+        # Get properties
+        self._data_files = self.getProperty('InputFiles').value
+        self._sum_files = False
+        self._load_logs = self.getProperty('LoadLogFiles').value
+        self._calibration_ws = ''
+
+        self._instrument_name = self.getPropertyValue('Instrument')
+        self._analyser = self.getPropertyValue('Analyser')
+        self._reflection = self.getPropertyValue('Reflection')
+        self._efixed = Property.EMPTY_DBL
+
+        self._spectra_range = self.getProperty('SpectraRange').value
+        self._background_range = ''
+        self._rebin_string = ''
+        self._detailed_balance = self.getProperty('DetailedBalance').value
+        self._scale_factor = 1.0
+        self._fold_multiple_frames = False
+        self._q_range = self.getProperty('QRange').value
+        self._energy_range = self.getProperty('EnergyRange').value
+
+        self._grouping_method = self.getPropertyValue('GroupingMethod')
+        self._grouping_ws = ''
+        self._grouping_map_file = ''
+
+        self._output_x_units = 'DeltaE'
+
+        self._sample_log_name = self.getPropertyValue('SampleEnvironmentLogName')
+        self._sample_log_value = self.getPropertyValue('SampleEnvironmentLogValue')
+
+        self._red_ws = self.getPropertyValue('ReducedWorkspace')
+        self._sqw_ws = self.getPropertyValue('SqwWorkspace')
+        self._moment_ws = self.getProperty('MomentWorkspace').value
+
+        # Disable sum files if there is only one file
+        if len(self._data_files) == 1:
+            if self._sum_files:
+                logger.warning('SumFiles disabled when only one input file is provided.')
+            self._sum_files = False
+
+        # Get the IPF filename
+        self._ipf_filename = os.path.join(config['instrumentDefinition.directory'],
+                                          self._instrument_name + '_' + self._analyser + '_' + self._reflection + '_Parameters.xml')
+        logger.information('Instrument parameter file: %s' % self._ipf_filename)
+
+        # Warn when grouping options are to be ignored
+        if self._grouping_method != 'Workspace' and self._grouping_ws is not None:
+            logger.warning('GroupingWorkspace will be ignored by selected GroupingMethod')
+
+        if self._grouping_method != 'File' and self._grouping_map_file is not None:
+            logger.warning('MapFile will be ignored by selected GroupingMethod')
+
+        # The list of workspaces being processed
+        self._workspace_names = []
+
+    def _get_temperature(self, ws_name):
+        """
+        Gets the sample temperature for a given workspace.
+
+        @param ws_name Name of workspace
+        @returns Temperature in Kelvin or None if not found
+        """
+        instr, run_number = self._get_InstrRun(ws_name)
+
+        facility = config.getFacility()
+        pad_num = facility.instrument(instr).zeroPadding(int(run_number))
+        zero_padding = '0' * (pad_num - len(run_number))
+
+        run_name = instr + zero_padding + run_number
+        log_filename = run_name.upper() + '.log'
+
+        run = mtd[ws_name].getRun()
+
+        if self._sample_log_name in run:
+            # Look for temperature in logs in workspace
+            tmp = run[self._sample_log_name].value
+            value_action = {'last_value': lambda x: x[len(x) - 1],
+                            'average': lambda x: x.mean()
+                            }
+            temp = value_action[self._sample_log_value](tmp)
+            logger.debug('Temperature %d K found for run: %s' % (temp, run_name))
+            return temp
+
+        else:
+            # Logs not in workspace, try loading from file
+            logger.information('Log parameter not found in workspace. Searching for log file.')
+            log_path = FileFinder.getFullPath(log_filename)
+
+            if log_path != '':
+                # Get temperature from log file
+                LoadLog(Workspace=ws_name, Filename=log_path)
+                run_logs = mtd[ws_name].getRun()
+                if self._sample_log_name in run_logs:
+                    tmp = run_logs[self._sample_log_name].value
+                    temp = tmp[len(tmp) - 1]
+                    logger.debug('Temperature %d K found for run: %s' % (temp, run_name))
+                    return temp
+                else:
+                    logger.warning('Log entry %s for run %s not found' % (self._sample_log_name, run_name))
+            else:
+                logger.warning('Log file for run %s not found' % run_name)
+
+        # Can't find log file
+        logger.warning('No temperature found for run: %s' % run_name)
+        return None
+
+    def _get_InstrRun(self, ws_name):
+        """
+        Get the instrument name and run number from a workspace.
+
+        @param ws_name - name of the workspace
+        @return tuple of form (instrument, run number)
+        """
+
+        run_number = str(mtd[ws_name].getRunNumber())
+        if run_number == '0':
+            # Attempt to parse run number off of name
+            match = re.match(r'([a-zA-Z]+)([0-9]+)', ws_name)
+            if match:
+                run_number = match.group(2)
+            else:
+                raise RuntimeError("Could not find run number associated with workspace.")
+
+        instrument = mtd[ws_name].getInstrument().getName()
+        if instrument != '':
+            for facility in config.getFacilities():
+                try:
+                    instrument = facility.instrument(instrument).filePrefix(int(run_number))
+                    instrument = instrument.lower()
+                    break
+                except RuntimeError:
+                    continue
+
+        return instrument, run_number
+
+
+# Register algorithm with Mantid
+AlgorithmFactory.subscribe(SofQWMomentsScan)
diff --git a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/TimeSlice.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/TimeSlice.py
index 8932bfe3d642bbf563e634fdd88bc9ebc5e67121..441becd92311edba49574dc8e107268f0e207c70 100644
--- a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/TimeSlice.py
+++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/TimeSlice.py
@@ -15,15 +15,13 @@ def _count_monitors(raw_file):
 
     raw_file = mtd[raw_file]
     num_hist = raw_file.getNumberHistograms()
-    detector = raw_file.getDetector(0)
     mon_count = 1
 
-    if detector.isMonitor():
+    spectrumInfo = raw_file.spectrumInfo()
+    if spectrumInfo.isMonitor(0):
         # Monitors are at the start
         for i in range(1, num_hist):
-            detector = raw_file.getDetector(i)
-
-            if detector.isMonitor():
+            if spectrumInfo.isMonitor(i):
                 mon_count += 1
             else:
                 break
@@ -31,16 +29,12 @@ def _count_monitors(raw_file):
         return mon_count, True
     else:
         # Monitors are at the end
-        detector = raw_file.getDetector(num_hist)
-
-        if not detector.isMonitor():
+        if not spectrumInfo.isMonitor(num_hist):
             #if it's not, we don't have any monitors!
             return 0, True
 
         for i in range(num_hist, 0, -1):
-            detector = raw_file.getDetector(i)
-
-            if detector.isMonitor():
+            if spectrumInfo.isMonitor(i):
                 mon_count += 1
             else:
                 break
diff --git a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/VesuvioDiffractionReduction.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/VesuvioDiffractionReduction.py
index 364ccb844e8a0eea1445d69c431f0f8cb09e99b2..f5d6537868e933bff15846ce797350590d0872dd 100644
--- a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/VesuvioDiffractionReduction.py
+++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/VesuvioDiffractionReduction.py
@@ -1,4 +1,3 @@
-#pylint: disable=no-init, too-many-instance-attributes
 from __future__ import (absolute_import, division, print_function)
 from mantid.simpleapi import *
 from mantid.api import *
@@ -9,7 +8,6 @@ import os
 
 
 class VesuvioDiffractionReduction(DataProcessorAlgorithm):
-
     _workspace_names = None
     _chopped_data = None
     _output_ws = None
@@ -94,11 +92,22 @@ class VesuvioDiffractionReduction(DataProcessorAlgorithm):
         load_opts = dict()
         load_opts['Mode'] = 'FoilOut'
         load_opts['InstrumentParFile'] = self._par_filename
+        # Load monitors as True so monitors will not be loaded separately in LoadVesuvio
+        load_opts['LoadMonitors'] = True
 
         prog_reporter = Progress(self, start=0.0, end=1.0, nreports=1)
 
         prog_reporter.report("Loading Files")
 
+        # Split up runs as LoadVesuvio sums multiple runs
+        input_files = self._data_files
+        for run in input_files:
+            try:
+                number_generator = IntArrayProperty('array_generator', run)
+                self._data_files = number_generator.value.tolist()
+            except RuntimeError:
+                raise RuntimeError("Could not generate run numbers from this input: " + run)
+
         self._workspace_names, self._chopped_data = load_files(self._data_files,
                                                                ipf_filename=self._ipf_filename,
                                                                spec_min=self._spectra_range[0],
@@ -195,7 +204,7 @@ class VesuvioDiffractionReduction(DataProcessorAlgorithm):
         self._ipf_filename = self._instrument_name + '_diffraction_' + self._mode + '_Parameters.xml'
         if not os.path.exists(self._ipf_filename):
             self._ipf_filename = os.path.join(config['instrumentDefinition.directory'], self._ipf_filename)
-        logger.information('IPF filename is: %s' % (self._ipf_filename))
+        logger.information('IPF filename is: %s' % self._ipf_filename)
 
         # Only enable sum files if we actually have more than one file
         sum_files = self.getProperty('SumFiles').value
diff --git a/Framework/PythonInterface/plugins/algorithms/roundinghelper.py b/Framework/PythonInterface/plugins/algorithms/roundinghelper.py
new file mode 100644
index 0000000000000000000000000000000000000000..57139197c85e3d01b2c7e970b3063100b4a69aa4
--- /dev/null
+++ b/Framework/PythonInterface/plugins/algorithms/roundinghelper.py
@@ -0,0 +1,38 @@
+from __future__ import (absolute_import, division, print_function)
+from mantid.kernel import Direction, StringListValidator
+import numpy
+
+'''
+This file contains functions which deal with rounding in algorithms
+such as BinWidthAtX and MedianBinWidth.
+
+'''
+
+# Name of the rounding mode property
+PROP_NAME_ROUNDING_MODE = 'Rounding'
+
+# Available rounding modes.
+ROUNDING_NONE = 'None'
+ROUNDING_TEN_TO_INT = '10^n'
+
+
+def declare_rounding_property(o):
+    '''
+    Declares the properties needed for rounding.
+    '''
+    rounding = StringListValidator()
+    rounding.addAllowedValue(ROUNDING_NONE)
+    rounding.addAllowedValue(ROUNDING_TEN_TO_INT)
+    o.declareProperty(name=PROP_NAME_ROUNDING_MODE,
+                      defaultValue=ROUNDING_NONE, validator=rounding,
+                      direction=Direction.Input, doc='Bin width rounding')
+
+
+def round(x, mode):
+    '''
+    Rounds x depending on the rounding mode selected.
+    '''
+    if mode == ROUNDING_TEN_TO_INT:
+        rounded = 10.0**numpy.floor(numpy.log10(numpy.abs(x)))
+        return numpy.copysign(rounded, x)
+    return x
diff --git a/Framework/PythonInterface/test/python/mantid/SimpleAPILoadTest.py b/Framework/PythonInterface/test/python/mantid/SimpleAPILoadTest.py
index f8903293ad317046bf0579cb57330c535c8c2467..0dcfba3f1980c5b712d510fa6478cb85ee27608f 100644
--- a/Framework/PythonInterface/test/python/mantid/SimpleAPILoadTest.py
+++ b/Framework/PythonInterface/test/python/mantid/SimpleAPILoadTest.py
@@ -88,7 +88,7 @@ class SimpleAPILoadTest(unittest.TestCase):
                 self.fail("Dialog function raised the correct exception type but the message was wrong")
 
     def _do_name_check(self, wkspace, expected_name):
-        self.assertEqual(wkspace.getName(), expected_name)
+        self.assertEqual(wkspace.name(), expected_name)
         self.assertTrue(expected_name in mtd)
 
 if __name__ == '__main__':
diff --git a/Framework/PythonInterface/test/python/mantid/SimpleAPITest.py b/Framework/PythonInterface/test/python/mantid/SimpleAPITest.py
index 18233ab24c228b691fb8d4cb410e02e03f1adadc..7fded88ab8622055292bdc899b326d67eca2fa9f 100644
--- a/Framework/PythonInterface/test/python/mantid/SimpleAPITest.py
+++ b/Framework/PythonInterface/test/python/mantid/SimpleAPITest.py
@@ -40,6 +40,8 @@ Params(Input:req) *dbl list*       A comma separated list of first bin boundary,
 PreserveEvents(Input) *boolean*       Keep the output workspace as an EventWorkspace, if the input has events. If the input and output EventWorkspace names are the same, only the X bins are set, which is very quick. If false, then the workspace gets converted to a Workspace2D histogram.
 
 FullBinsOnly(Input) *boolean*       Omit the final bin if it's width is smaller than the step size
+
+IgnoreBinErrors(Input) *boolean*       Ignore errors related to zero/negative bin widths in input/output workspaces. When ignored, the signal and errors are set to zero
 """
         doc = simpleapi.rebin.__doc__
         self.assertTrue(len(doc) > 0 )
diff --git a/Framework/PythonInterface/test/python/mantid/api/AnalysisDataServiceTest.py b/Framework/PythonInterface/test/python/mantid/api/AnalysisDataServiceTest.py
index b3e4e815dcc8d8d3b56866e62a9e2511bcb08f8a..5512b949bd0e3c61a6d1e51fa46f2360e8ec5d2d 100644
--- a/Framework/PythonInterface/test/python/mantid/api/AnalysisDataServiceTest.py
+++ b/Framework/PythonInterface/test/python/mantid/api/AnalysisDataServiceTest.py
@@ -68,7 +68,7 @@ class AnalysisDataServiceTest(unittest.TestCase):
 
     def do_check_for_matrix_workspace_type(self, workspace):
         self.assertTrue(isinstance(workspace, MatrixWorkspace))
-        self.assertNotEquals(workspace.getName(), '')
+        self.assertNotEquals(workspace.name(), '')
         self.assertTrue(hasattr(workspace, 'getNumberHistograms'))
         self.assertTrue(hasattr(workspace, 'getMemorySize'))
 
diff --git a/Framework/PythonInterface/test/python/mantid/api/CMakeLists.txt b/Framework/PythonInterface/test/python/mantid/api/CMakeLists.txt
index 32ef42ce2a60ae3ffb2fd25f8afdf5604a9d1a59..ec02457d0a012869f20e9968d680309b78c97a06 100644
--- a/Framework/PythonInterface/test/python/mantid/api/CMakeLists.txt
+++ b/Framework/PythonInterface/test/python/mantid/api/CMakeLists.txt
@@ -14,6 +14,7 @@ set ( TEST_PY_FILES
   CompositeFunctionTest.py
   DataProcessorAlgorithmTest.py
   DeprecatedAlgorithmCheckerTest.py
+  DetectorInfoTest.py
   ExperimentInfoTest.py
   FilePropertyTest.py
   FileFinderTest.py
@@ -42,6 +43,7 @@ set ( TEST_PY_FILES
   RunPythonScriptTest.py
   RunTest.py
   SampleTest.py
+  SpectrumInfoTest.py
   WorkspaceFactoryTest.py
   WorkspaceTest.py
   WorkspaceGroupTest.py
diff --git a/Framework/PythonInterface/test/python/mantid/api/DetectorInfoTest.py b/Framework/PythonInterface/test/python/mantid/api/DetectorInfoTest.py
new file mode 100644
index 0000000000000000000000000000000000000000..efac03965c6f05761ee13ee2361994f4eec67f16
--- /dev/null
+++ b/Framework/PythonInterface/test/python/mantid/api/DetectorInfoTest.py
@@ -0,0 +1,29 @@
+from __future__ import (absolute_import, division, print_function)
+
+import unittest
+from testhelpers import WorkspaceCreationHelper
+
+class DetectorInfoTest(unittest.TestCase):
+
+    _ws = None
+
+    def setUp(self):
+        if self.__class__._ws is None:
+            self.__class__._ws = WorkspaceCreationHelper.create2DWorkspaceWithFullInstrument(2, 1, False) # no monitors
+            self.__class__._ws.getSpectrum(0).clearDetectorIDs()
+
+    def test_len(self):
+        info = self._ws.detectorInfo()
+        self.assertEquals(len(info), 2)
+
+    def test_size(self):
+        info = self._ws.detectorInfo()
+        self.assertEquals(info.size(), 2)
+
+    def test_isMasked(self):
+        info = self._ws.detectorInfo()
+        self.assertEquals(info.isMasked(0), False)
+        self.assertEquals(info.isMasked(1), False)
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/Framework/PythonInterface/test/python/mantid/api/ExperimentInfoTest.py b/Framework/PythonInterface/test/python/mantid/api/ExperimentInfoTest.py
index a3dcb89eebae4a2a4dde7a75f72f03ebb23d9ea2..2a6a947c94c6d316f9568aaed39957c77d1d4448 100644
--- a/Framework/PythonInterface/test/python/mantid/api/ExperimentInfoTest.py
+++ b/Framework/PythonInterface/test/python/mantid/api/ExperimentInfoTest.py
@@ -38,6 +38,11 @@ class ExperimentInfoTest(unittest.TestCase):
         emode = self._expt_ws.getEMode()
         self.assertEquals(emode, 0)
 
+    def test_detectorInfo(self):
+        detInfo = self._expt_ws.detectorInfo()
+        # No instrument in test workspace, so size is 0.
+        self.assertEquals(detInfo.size(), 0)
+
 #    def test_set_and_get_efixed(self):
 #      ws = WorkspaceCreationHelper.create2DWorkspaceWithFullInstrument(1, 5, False, False)
 #        ws.setEFixed(1, pi)
diff --git a/Framework/PythonInterface/test/python/mantid/api/IEventWorkspaceTest.py b/Framework/PythonInterface/test/python/mantid/api/IEventWorkspaceTest.py
index 3d15adc37df27b4af48a8e8bff91aa6cad719c39..e50cfbb3dbe49f5ca12593b5b499a5f8c0004e64 100644
--- a/Framework/PythonInterface/test/python/mantid/api/IEventWorkspaceTest.py
+++ b/Framework/PythonInterface/test/python/mantid/api/IEventWorkspaceTest.py
@@ -16,7 +16,7 @@ class IEventWorkspaceTest(unittest.TestCase):
     def setUp(self):
         if self._test_ws is None:
             self.__class__._test_ws = \
-              WorkspaceCreationHelper.CreateEventWorkspace2(self._npixels, self._nbins)
+              WorkspaceCreationHelper.createEventWorkspace2(self._npixels, self._nbins)
 
     def test_that_it_cannot_be_directly_instantiated(self):
         self.assertFalse(can_be_instantiated(IEventWorkspace))
diff --git a/Framework/PythonInterface/test/python/mantid/api/MatrixWorkspaceTest.py b/Framework/PythonInterface/test/python/mantid/api/MatrixWorkspaceTest.py
index 4cb7a3ef526e11f10f0ed24b62eb770747c7ceaa..259a088152c1f3a9e667ac2df01a508f3ee1eec7 100644
--- a/Framework/PythonInterface/test/python/mantid/api/MatrixWorkspaceTest.py
+++ b/Framework/PythonInterface/test/python/mantid/api/MatrixWorkspaceTest.py
@@ -68,7 +68,6 @@ class MatrixWorkspaceTest(unittest.TestCase):
         det = self._test_ws.getDetector(0)
         self.assertTrue(isinstance(det, Detector))
         self.assertEquals(det.getID(), 1)
-        self.assertFalse(det.isMasked())
         self.assertAlmostEqual(math.pi, det.getTwoTheta(V3D(0,0,11), V3D(0,0,1)))
 
     def test_spectrum_retrieval(self):
@@ -344,7 +343,7 @@ class MatrixWorkspaceTest(unittest.TestCase):
         comment = 'Some comment on this workspace.'
         ws1.setComment(comment)
         self.assertEquals(comment, ws1.getComment())
-        AnalysisDataService.remove(ws1.getName())
+        AnalysisDataService.remove(ws1.name())
 
     def test_setGetMonitorWS(self):
         run_algorithm('CreateWorkspace', OutputWorkspace='ws1',DataX=[1.,2.,3.], DataY=[2.,3.], DataE=[2.,3.],UnitX='TOF')
@@ -385,6 +384,11 @@ class MatrixWorkspaceTest(unittest.TestCase):
             pass
         self.assertTrue(allFine)
 
+    def test_spectrumInfo(self):
+        specInfo = self._test_ws.spectrumInfo()
+        self.assertEquals(specInfo.isMasked(0), False)
+        self.assertEquals(specInfo.isMasked(1), False)
+
 if __name__ == '__main__':
     unittest.main()
     #Testing particular test from Mantid
diff --git a/Framework/PythonInterface/test/python/mantid/api/SpectrumInfoTest.py b/Framework/PythonInterface/test/python/mantid/api/SpectrumInfoTest.py
new file mode 100644
index 0000000000000000000000000000000000000000..920386145e0c2366b3d724c2b16ac535edd81575
--- /dev/null
+++ b/Framework/PythonInterface/test/python/mantid/api/SpectrumInfoTest.py
@@ -0,0 +1,25 @@
+from __future__ import (absolute_import, division, print_function)
+
+import unittest
+from testhelpers import WorkspaceCreationHelper
+
+class SpectrumInfoTest(unittest.TestCase):
+
+    _ws = None
+
+    def setUp(self):
+        if self.__class__._ws is None:
+            self.__class__._ws = WorkspaceCreationHelper.create2DWorkspaceWithFullInstrument(2, 1, False) # no monitors
+            self.__class__._ws.getSpectrum(0).clearDetectorIDs()
+
+    def test_hasDetectors(self):
+        info = self._ws.spectrumInfo()
+        self.assertEquals(info.hasDetectors(0), False)
+        self.assertEquals(info.hasDetectors(1), True)
+
+    def test_isMasked(self):
+        info = self._ws.spectrumInfo()
+        self.assertEquals(info.isMasked(1), False)
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/Framework/PythonInterface/test/python/mantid/api/WorkspaceGroupTest.py b/Framework/PythonInterface/test/python/mantid/api/WorkspaceGroupTest.py
index 8e71bae0c726ea43fa62e1c4a09dffd95ac7e1ec..ad11b6b3dbd1983006ab2212bd441c4bb5188e57 100644
--- a/Framework/PythonInterface/test/python/mantid/api/WorkspaceGroupTest.py
+++ b/Framework/PythonInterface/test/python/mantid/api/WorkspaceGroupTest.py
@@ -60,7 +60,7 @@ class WorkspaceGroupTest(unittest.TestCase):
         run_algorithm('CreateWorkspace', OutputWorkspace='Second',DataX=[1.,2.,3.], DataY=[2.,3.], DataE=[2.,3.],UnitX='TOF')
         run_algorithm('GroupWorkspaces',InputWorkspaces='First,Second',OutputWorkspace='group')
         group = mtd['group']
-        self.assertEquals(group.getName(), "group")
+        self.assertEquals(group.name(), "group")
         self.assertEquals(type(group), WorkspaceGroup)
         try:
             w = Scale(group, 1.5)
diff --git a/Framework/PythonInterface/test/python/mantid/kernel/CMakeLists.txt b/Framework/PythonInterface/test/python/mantid/kernel/CMakeLists.txt
index 09f142957477ef35b5d8365b119fbb793785691d..d0928e72b0e0391548856c27f66ab25179bcf123 100644
--- a/Framework/PythonInterface/test/python/mantid/kernel/CMakeLists.txt
+++ b/Framework/PythonInterface/test/python/mantid/kernel/CMakeLists.txt
@@ -16,6 +16,7 @@ set ( TEST_PY_FILES
   InstrumentInfoTest.py
   IPropertySettingsTest.py
   ListValidatorTest.py
+  LiveListenerInfoTest.py
   LogFilterTest.py
   LoggerTest.py
   MandatoryValidatorTest.py
diff --git a/Framework/PythonInterface/test/python/mantid/kernel/FacilityInfoTest.py b/Framework/PythonInterface/test/python/mantid/kernel/FacilityInfoTest.py
index 92295a915efd4dc03c02d04883eb6d130c398231..c26dc1d6941a33dfa76e997d14e1509681777ce7 100644
--- a/Framework/PythonInterface/test/python/mantid/kernel/FacilityInfoTest.py
+++ b/Framework/PythonInterface/test/python/mantid/kernel/FacilityInfoTest.py
@@ -3,6 +3,7 @@ from __future__ import (absolute_import, division, print_function)
 import unittest
 from mantid.kernel import FacilityInfo, InstrumentInfo, ConfigService
 
+
 class FacilityInfoTest(unittest.TestCase):
 
     def test_construction_raies_an_error(self):
@@ -23,7 +24,8 @@ class FacilityInfoTest(unittest.TestCase):
         self.assertTrue(len(test_facility.instruments()) > 30)
         self.assertTrue(len(test_facility.instruments("Neutron Diffraction"))> 10)
         self.assertTrue(isinstance(test_facility.instrument("WISH"), InstrumentInfo))
-        self.assertEquals(test_facility.liveListener(), "ISISHistoDataListener")
+
 
 if __name__ == '__main__':
     unittest.main()
+
diff --git a/Framework/PythonInterface/test/python/mantid/kernel/InstrumentInfoTest.py b/Framework/PythonInterface/test/python/mantid/kernel/InstrumentInfoTest.py
index cb840530d5bce21c7a39807c1d6c4ecc4dfadbe8..dbd30304e1d59791da9950bd864a2bad418e52f0 100644
--- a/Framework/PythonInterface/test/python/mantid/kernel/InstrumentInfoTest.py
+++ b/Framework/PythonInterface/test/python/mantid/kernel/InstrumentInfoTest.py
@@ -3,16 +3,39 @@ from __future__ import (absolute_import, division, print_function)
 import unittest
 from mantid.kernel import InstrumentInfo, ConfigService
 
-class InstrumentInfoTest(object):
+
+class InstrumentInfoTest(unittest.TestCase):
+    def _get_test_instrument(self):
+        facility = ConfigService.getFacility("ISIS")
+        return facility.instrument("CRISP")
 
     def test_construction_raies_an_error(self):
         self.assertRaises(RuntimeError, InstrumentInfo)
 
-    def test_instrument_name(self):
-        pass
+    def test_instrument_attributes(self):
+        inst = self._get_test_instrument()
+
+        # Just testing functionality; values can be updated if needed
+        self.assertEquals(inst.name(), "CRISP")
+        self.assertEquals(inst.shortName(), "CSP")
+        self.assertEquals(str(inst), "CSP")
+        self.assertEquals(inst.zeroPadding(99777), 5)
+        self.assertEquals(inst.zeroPadding(99778), 8)
+        self.assertEquals(inst.filePrefix(99777), "CSP")
+        self.assertEquals(inst.filePrefix(99778), "CRISP")
+        self.assertEquals(inst.delimiter(), "")
+        self.assertEquals(str(inst.techniques()), "set('Reflectometry')")
+        self.assertEquals(inst.facility().name(), "ISIS")
+        self.assertEquals(inst.liveListener(), "ISISHistoDataListener")
+        self.assertEquals(inst.liveListener("histo"), "ISISHistoDataListener")
+        self.assertRaises(RuntimeError, inst.liveListener, "invalid_name")
+        self.assertEquals(inst.liveDataAddress(), "NDXCRISP:6789")
+        self.assertEquals(inst.liveDataAddress("histo"), "NDXCRISP:6789")
+        self.assertRaises(RuntimeError, inst.liveDataAddress, "invalid_name")
+        self.assertTrue(inst.hasLiveListenerInfo())
+        self.assertEqual(len(inst.liveListenerInfoList()), 1)
 
-    def test_instrument_shortName(self):
-        pass
 
 if __name__ == '__main__':
     unittest.main()
+
diff --git a/Framework/PythonInterface/test/python/mantid/kernel/LiveListenerInfoTest.py b/Framework/PythonInterface/test/python/mantid/kernel/LiveListenerInfoTest.py
new file mode 100644
index 0000000000000000000000000000000000000000..9511132114bd5360707f812e5056d6acc81d7d09
--- /dev/null
+++ b/Framework/PythonInterface/test/python/mantid/kernel/LiveListenerInfoTest.py
@@ -0,0 +1,26 @@
+from __future__ import (absolute_import, division, print_function)
+
+import unittest
+from mantid.kernel import LiveListenerInfo, ConfigService
+
+
+class LiveListenerInfoTest(unittest.TestCase):
+    def _get_test_listener(self):
+        facility = ConfigService.getFacility("ISIS")
+        return facility.instrument("CRISP").liveListenerInfo()
+
+    def test_construction_raies_an_error(self):
+        self.assertRaises(RuntimeError, LiveListenerInfo)
+
+    def test_listener_attributes(self):
+        info = self._get_test_listener()
+
+        # Just testing functionality; values can be updated if needed
+        self.assertEquals(info.name(), "histo")
+        self.assertEquals(info.listener(), "ISISHistoDataListener")
+        self.assertEquals(info.address(), "NDXCRISP:6789")
+
+
+if __name__ == '__main__':
+    unittest.main()
+
diff --git a/Framework/PythonInterface/test/python/mantid/kernel/UnitConversionTest.py b/Framework/PythonInterface/test/python/mantid/kernel/UnitConversionTest.py
index ac689a6b25575355612c08ab4616ea895c222b38..7d9e4ca4f1170dd9ec9e0fe8d7bfce2784f8410e 100644
--- a/Framework/PythonInterface/test/python/mantid/kernel/UnitConversionTest.py
+++ b/Framework/PythonInterface/test/python/mantid/kernel/UnitConversionTest.py
@@ -11,11 +11,11 @@ class UnitConversionTest(unittest.TestCase):
         src_value = 1.5
         dest_unit = "Momentum"
 
-        l1 = l2 = twoTheta = efixed = 0.0
+        l1 = l2 = theta = efixed = 0.0
         emode = DeltaEModeType.Indirect;
         expected = 2.0*math.pi/src_value
 
-        result = UnitConversion.run(src_unit, dest_unit, src_value, l1, l2, twoTheta, emode, efixed)
+        result = UnitConversion.run(src_unit, dest_unit, src_value, l1, l2, theta, emode, efixed)
         self.assertAlmostEqual(result, expected, 12)
 
 if __name__ == '__main__':
diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/BinWidthAtXTest.py b/Framework/PythonInterface/test/python/plugins/algorithms/BinWidthAtXTest.py
new file mode 100644
index 0000000000000000000000000000000000000000..acd520ce090849653fe8a5ede1fa6acd878dd903
--- /dev/null
+++ b/Framework/PythonInterface/test/python/plugins/algorithms/BinWidthAtXTest.py
@@ -0,0 +1,104 @@
+from __future__ import (absolute_import, division, print_function)
+
+from mantid.simpleapi import CreateWorkspace, DeleteWorkspace
+import numpy
+import sys
+import testhelpers
+import unittest
+
+
+class BinWidthAtXTest(unittest.TestCase):
+
+    def _make_algorithm_params(self, ws, x, rounding='None'):
+        return {
+            'InputWorkspace': ws,
+            'X': x,
+            'rethrow': True,  # Let exceptions through for testing.
+            'Rounding': rounding
+        }
+
+    def _make_boundaries(self, xBegin, binWidths):
+        return numpy.cumsum(numpy.append(numpy.array([xBegin]), binWidths))
+
+    def _make_single_histogram_ws(self):
+        # X-axis width is a multiple of the final bin width so rebinning
+        # creates full bins only.
+        binWidths = numpy.array([0.13, 0.23, 0.05, 0.27, 0.42])
+        xBegin = -0.11
+        xs = self._make_boundaries(xBegin, binWidths)
+        ys = numpy.zeros(len(xs) - 1)
+        ws = CreateWorkspace(DataX=xs, DataY=ys)
+        i = len(binWidths) / 2
+        middleBinWidth = binWidths[i]
+        middleBinX = xs[i] + 0.5 * middleBinWidth
+        return ws, middleBinX, middleBinWidth
+
+    def _run_algorithm(self, params):
+        algorithm = testhelpers.create_algorithm('BinWidthAtX', **params)
+        testhelpers.assertRaisesNothing(self, algorithm.execute)
+        self.assertTrue(algorithm.isExecuted())
+        return algorithm.getProperty('BinWidth').value
+
+    def test_success_single_histogram(self):
+        ws, X, expectedWidth = self._make_single_histogram_ws()
+        params = self._make_algorithm_params(ws, X)
+        binWidth = self._run_algorithm(params)
+        self.assertAlmostEqual(binWidth, expectedWidth)
+        DeleteWorkspace(ws)
+
+    def test_average_over_multiple_histograms(self):
+        # Two histograms, center bin boundaries are aligned at -0.12.
+        # X-axis widths are multiples of the final bin width so
+        # rebinning results in full bins only.
+        binWidths = numpy.array([0.3, 0.1, 0.8, 0.9, 0.2, 0.4])
+        xs1 = self._make_boundaries(-0.42, binWidths[:3])
+        xs2 = self._make_boundaries(-1.02, binWidths[3:])
+        xs = numpy.concatenate((xs1, xs2))
+        ys = numpy.zeros(len(xs) - 2)
+        ws = CreateWorkspace(DataX=xs, DataY=ys, NSpec=2)
+        X = -0.1
+        params = self._make_algorithm_params(ws, X)
+        binWidth = self._run_algorithm(params)
+        expectedWidth = 0.5 * (binWidths[1] + binWidths[-2])  # Average!
+        self.assertAlmostEqual(binWidth, expectedWidth)
+        DeleteWorkspace(ws)
+
+    def test_rounding(self):
+        ws, X, unused = self._make_single_histogram_ws()
+        params = self._make_algorithm_params(ws, X, '10^n')
+        binWidth = self._run_algorithm(params)
+        expectedWidth = 0.01
+        self.assertAlmostEqual(binWidth, expectedWidth)
+        DeleteWorkspace(ws)
+
+    def test_failure_X_out_of_bounds(self):
+        ws, unused, unused = self._make_single_histogram_ws()
+        X = sys.float_info.max
+        params = self._make_algorithm_params(ws, X)
+        algorithm = testhelpers.create_algorithm('BinWidthAtX', **params)
+        self.assertRaises(RuntimeError, algorithm.execute)
+        self.assertFalse(algorithm.isExecuted())
+        DeleteWorkspace(ws)
+
+    def test_throws_on_non_histogram_input(self):
+        xs = numpy.array([-2.2, -1.2, 0.1, 0.9])
+        ys = numpy.zeros(len(xs))
+        ws = CreateWorkspace(DataX=xs, DataY=ys)
+        X = -0.3
+        params = self._make_algorithm_params(ws, X)
+        self.assertRaises(ValueError, testhelpers.create_algorithm,
+                          'BinWidthAtX', **params)
+        DeleteWorkspace(ws)
+
+    def test_positive_output_even_if_descending_x(self):
+        xs = numpy.array([110.0, 60.0, 40.0, -10.0])
+        ys = numpy.zeros(len(xs) - 1)
+        ws = CreateWorkspace(DataX=xs, DataY=ys)
+        params = self._make_algorithm_params(ws, 50.0)
+        binWidth = self._run_algorithm(params)
+        expectedBinWidth = 20.0
+        self.assertAlmostEqual(binWidth, expectedBinWidth)
+        DeleteWorkspace(ws)
+
+if __name__ == "__main__":
+    unittest.main()
diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/CMakeLists.txt b/Framework/PythonInterface/test/python/plugins/algorithms/CMakeLists.txt
index 8942872c7347d72249207d3063f89585561483c8..18868027fd95161b69fe69e80d920d04fb93be22 100644
--- a/Framework/PythonInterface/test/python/plugins/algorithms/CMakeLists.txt
+++ b/Framework/PythonInterface/test/python/plugins/algorithms/CMakeLists.txt
@@ -10,6 +10,7 @@ set ( TEST_PY_FILES
   ApplyPaalmanPingsCorrectionTest.py
   BayesQuasiTest.py
   BayesStretchTest.py
+  BinWidthAtXTest.py
   CalculateSampleTransmissionTest.py
   CheckForSampleLogsTest.py
   ConjoinSpectraTest.py
@@ -27,6 +28,7 @@ set ( TEST_PY_FILES
   DNSMergeRunsTest.py
   DNSFlippingRatioCorrTest.py
   DSFinterpTest.py
+  EnergyWindowScanTest.py
   EnggCalibrateFullTest.py
   EnggCalibrateTest.py
   EnggFitDIFCFromPeaksTest.py
@@ -43,14 +45,17 @@ set ( TEST_PY_FILES
   GSASIIRefineFitPeaksTest.py
   GetEiT0atSNSTest.py
   GetNegMuMuonicXRDTest.py
+  ILLIN16BCalibrationTest.py
   IndirectAnnulusAbsorptionTest.py
   IndirectCylinderAbsorptionTest.py
   IndirectFlatPlateAbsorptionTest.py
+  IndirectILLEnergyTransferTest.py
   IndirectILLReductionTest.py
+  IndirectILLReductionFWSTest.py
+  IndirectILLReductionQENSTest.py
   IndirectResolutionTest.py
   IndirectTransmissionTest.py
   IndirectTransmissionMonitorTest.py
-  ILLIN16BCalibrationTest.py
   IqtFitMultipleTest.py
   IqtFitSequentialTest.py
   ISISIndirectDiffractionReductionTest.py
@@ -69,6 +74,7 @@ set ( TEST_PY_FILES
   MaskWorkspaceToCalFileTest.py
   MatchPeaksTest.py
   MeanTest.py
+  MedianBinWidthTest.py
   MergeCalFilesTest.py
   MolDynTest.py
   MSDFitTest.py
@@ -78,6 +84,7 @@ set ( TEST_PY_FILES
   OSIRISDiffractionReductionTest.py
   ResNorm2Test.py
   RetrieveRunInfoTest.py
+  SANSStitchTest.py
   SANSFitShiftScaleTest.py
   SANSWideAngleCorrectionTest.py
   SaveNexusPDTest.py
@@ -89,6 +96,7 @@ set ( TEST_PY_FILES
   SimulatedDensityOfStatesTest.py
   SortByQVectorsTest.py
   SofQWMomentsTest.py
+  SofQWMomentsScanTest.py
   SortDetectorsTest.py
   SortXAxisTest.py
   StatisticsOfTableWorkspaceTest.py
diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/ComputeCalibrationCoefVanTest.py b/Framework/PythonInterface/test/python/plugins/algorithms/ComputeCalibrationCoefVanTest.py
index 0ee5388029b7e073a8380dcba67b83f77adb0bae..bb847088f2164e183a4f1ad54f6ed5f32221a068 100644
--- a/Framework/PythonInterface/test/python/plugins/algorithms/ComputeCalibrationCoefVanTest.py
+++ b/Framework/PythonInterface/test/python/plugins/algorithms/ComputeCalibrationCoefVanTest.py
@@ -1,8 +1,9 @@
 from __future__ import (absolute_import, division, print_function)
 
 import unittest
-from mantid.simpleapi import DeleteWorkspace, CreateSampleWorkspace, AddSampleLog, EditInstrumentGeometry,\
-    CloneWorkspace, CheckWorkspacesMatch, FindEPP
+from mantid.simpleapi import (DeleteWorkspace, CreateSampleWorkspace,
+                              AddSampleLog, EditInstrumentGeometry,
+                              CloneWorkspace, CheckWorkspacesMatch, FindEPP)
 from testhelpers import run_algorithm
 from mantid.api import AnalysisDataService
 from scipy.constants import N_A, hbar, k
@@ -11,18 +12,23 @@ import numpy as np
 
 class ComputeCalibrationCoefVanTest(unittest.TestCase):
     def setUp(self):
-        input_ws = CreateSampleWorkspace(Function="User Defined",
-                                         UserDefinedFunction="name=LinearBackground, A0=0.3;name=Gaussian, \
-                                         PeakCentre=5, Height=10, Sigma=0.3", NumBanks=2, BankPixelWidth=1,
-                                         XMin=0, XMax=10, BinWidth=0.1, BankDistanceFromSample=4.0)
+        input_ws = CreateSampleWorkspace(
+            Function="User Defined",
+            UserDefinedFunction="name=LinearBackground, " +
+            "A0=0.3;name=Gaussian, PeakCentre=5, Height=10, Sigma=0.3",
+            NumBanks=2, BankPixelWidth=1, XMin=0, XMax=10, BinWidth=0.1,
+            BankDistanceFromSample=4.0)
         self._input_ws = input_ws
         self._table = FindEPP(input_ws, OutputWorkspace="table")
-        AddSampleLog(self._input_ws, LogName='wavelength', LogText='4.0', LogType='Number', LogUnit='Angstrom')
+        AddSampleLog(self._input_ws, LogName='wavelength', LogText='4.0',
+                     LogType='Number', LogUnit='Angstrom')
 
     def test_output(self):
         outputWorkspaceName = "output_ws"
-        alg_test = run_algorithm("ComputeCalibrationCoefVan", VanadiumWorkspace=self._input_ws,
-                                 EPPTable=self._table, OutputWorkspace=outputWorkspaceName)
+        alg_test = run_algorithm("ComputeCalibrationCoefVan",
+                                 VanadiumWorkspace=self._input_ws,
+                                 EPPTable=self._table,
+                                 OutputWorkspace=outputWorkspaceName)
         self.assertTrue(alg_test.isExecuted())
         wsoutput = AnalysisDataService.retrieve(outputWorkspaceName)
 
@@ -31,58 +37,115 @@ class ComputeCalibrationCoefVanTest(unittest.TestCase):
                          self._input_ws.getRun().getLogData('run_title').value)
 
         # Size of output workspace
-        self.assertEqual(wsoutput.getNumberHistograms(), self._input_ws.getNumberHistograms())
+        self.assertEqual(wsoutput.getNumberHistograms(),
+                         self._input_ws.getNumberHistograms())
 
         DeleteWorkspace(wsoutput)
         return
 
     def test_sum(self):
         outputWorkspaceName = "output_ws"
-        alg_test = run_algorithm("ComputeCalibrationCoefVan", VanadiumWorkspace=self._input_ws,
-                                 EPPTable=self._table, OutputWorkspace=outputWorkspaceName)
+        alg_test = run_algorithm("ComputeCalibrationCoefVan",
+                                 VanadiumWorkspace=self._input_ws,
+                                 EPPTable=self._table,
+                                 OutputWorkspace=outputWorkspaceName)
         self.assertTrue(alg_test.isExecuted())
         wsoutput = AnalysisDataService.retrieve(outputWorkspaceName)
 
         # check whether sum is calculated correctly, for theta=0, dwf=1
         y_sum = sum(self._input_ws.readY(0)[27:75])
+        e_sum = np.sqrt(sum(np.square(self._input_ws.readE(0)[27:75])))
         self.assertAlmostEqual(y_sum, wsoutput.readY(0)[0])
+        self.assertAlmostEqual(e_sum, wsoutput.readE(0)[0])
 
         DeleteWorkspace(wsoutput)
 
-    def test_dwf(self):
+    def test_dwf_using_default_temperature(self):
         outputWorkspaceName = "output_ws"
 
         # change theta to make dwf != 1
-        EditInstrumentGeometry(self._input_ws, L2="4,8", Polar="0,15", Azimuthal="0,0", DetectorIDs="1,2")
-        alg_test = run_algorithm("ComputeCalibrationCoefVan", VanadiumWorkspace=self._input_ws,
-                                 EPPTable=self._table, OutputWorkspace=outputWorkspaceName)
+        EditInstrumentGeometry(self._input_ws, L2="4,8", Polar="0,15",
+                               Azimuthal="0,0", DetectorIDs="1,2")
+        alg_test = run_algorithm("ComputeCalibrationCoefVan",
+                                 VanadiumWorkspace=self._input_ws,
+                                 EPPTable=self._table,
+                                 OutputWorkspace=outputWorkspaceName)
         self.assertTrue(alg_test.isExecuted())
         wsoutput = AnalysisDataService.retrieve(outputWorkspaceName)
 
-        # check dwf calculation
-        y_sum = sum(self._input_ws.readY(1)[27:75])
-        mvan = 0.001*50.942/N_A
-        Bcoef = 4.736767162094296*1e+20*hbar*hbar/(2.0*mvan*k*389.0)
-        dwf = np.exp(-1.0*Bcoef*(4.0*np.pi*np.sin(0.5*np.radians(15.0))/4.0)**2)
-        self.assertAlmostEqual(y_sum*dwf, wsoutput.readY(1)[0])
+        self._checkDWF(wsoutput, 293.0)
+
+        DeleteWorkspace(wsoutput)
+
+    def test_temperature_from_sample_log(self):
+        self._input_ws.mutableRun().addProperty('temperature', 0.0, True)
+        outputWorkspaceName = "output_ws"
+        EditInstrumentGeometry(self._input_ws, L2="4,8", Polar="0,15",
+                               Azimuthal="0,0", DetectorIDs="1,2")
+        alg_test = run_algorithm("ComputeCalibrationCoefVan",
+                                 VanadiumWorkspace=self._input_ws,
+                                 EPPTable=self._table,
+                                 OutputWorkspace=outputWorkspaceName)
+        self.assertTrue(alg_test.isExecuted())
+        wsoutput = AnalysisDataService.retrieve(outputWorkspaceName)
+
+        self._checkDWF(wsoutput, 0.0)
+
+        DeleteWorkspace(wsoutput)
+
+    def test_temperature_input_overrides_sample_log(self):
+        self._input_ws.mutableRun().addProperty('temperature', 567.0, True)
+        outputWorkspaceName = "output_ws"
+        EditInstrumentGeometry(self._input_ws, L2="4,8", Polar="0,15",
+                               Azimuthal="0,0", DetectorIDs="1,2")
+        alg_test = run_algorithm("ComputeCalibrationCoefVan",
+                                 VanadiumWorkspace=self._input_ws,
+                                 EPPTable=self._table,
+                                 OutputWorkspace=outputWorkspaceName,
+                                 Temperature=0.0)
+        self.assertTrue(alg_test.isExecuted())
+        wsoutput = AnalysisDataService.retrieve(outputWorkspaceName)
+
+        self._checkDWF(wsoutput, 0.0)
 
         DeleteWorkspace(wsoutput)
 
     def test_input_not_modified(self):
         backup = CloneWorkspace(self._input_ws)
         outputWorkspaceName = "output_ws"
-        alg_test = run_algorithm("ComputeCalibrationCoefVan", VanadiumWorkspace=self._input_ws,
-                                 EPPTable=self._table, OutputWorkspace=outputWorkspaceName)
+        alg_test = run_algorithm("ComputeCalibrationCoefVan",
+                                 VanadiumWorkspace=self._input_ws,
+                                 EPPTable=self._table,
+                                 OutputWorkspace=outputWorkspaceName)
         self.assertTrue(alg_test.isExecuted())
-        self.assertEqual("Success!", CheckWorkspacesMatch(backup, self._input_ws))
+        self.assertEqual("Success!", CheckWorkspacesMatch(backup,
+                         self._input_ws))
         DeleteWorkspace(backup)
 
     def tearDown(self):
-        if AnalysisDataService.doesExist(self._input_ws.getName()):
+        if AnalysisDataService.doesExist(self._input_ws.name()):
             DeleteWorkspace(self._input_ws)
 
-        if AnalysisDataService.doesExist(self._table.getName()):
+        if AnalysisDataService.doesExist(self._table.name()):
             DeleteWorkspace(self._table)
 
+    def _checkDWF(self, wsoutput, temperature):
+        if temperature == 0.0:
+            integral = 0.5
+        elif temperature == 293.0:
+            integral = 4.736767162094296 / 3.0
+        else:
+            raise RuntimeError("Unsupported temperature supplied to " +
+                               "_checkDWF(). Use 0K or 293K only.")
+        y_sum = sum(self._input_ws.readY(1)[27:75])
+        e_sum = np.sqrt(sum(np.square(self._input_ws.readE(1)[27:75])))
+        mvan = 0.001*50.942/N_A
+        Bcoef = 3.0*integral*1e+20*hbar*hbar/(2.0*mvan*k*389.0)
+        dwf = np.exp(
+            -1.0*Bcoef*(4.0*np.pi*np.sin(0.5*np.radians(15.0))/4.0)**2)
+        self.assertAlmostEqual(y_sum*dwf, wsoutput.readY(1)[0])
+        self.assertAlmostEqual(e_sum*dwf, wsoutput.readE(1)[0])
+
+
 if __name__ == "__main__":
     unittest.main()
diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/DNSComputeDetEffCorrCoefsTest.py b/Framework/PythonInterface/test/python/plugins/algorithms/DNSComputeDetEffCorrCoefsTest.py
index 83ca1d85b3071f72d996189a6b593992ed2afff5..358a87ab2a907065e79a064642a685c929b813ef 100644
--- a/Framework/PythonInterface/test/python/plugins/algorithms/DNSComputeDetEffCorrCoefsTest.py
+++ b/Framework/PythonInterface/test/python/plugins/algorithms/DNSComputeDetEffCorrCoefsTest.py
@@ -31,8 +31,8 @@ class DNSComputeDetEffCorrCoefsTest(unittest.TestCase):
 
     def test_DNSVanadiumCorrection(self):
         outputWorkspaceName = "DNSComputeDetCorrCoefsTest_Test1"
-        vanalist = [self.sfvanaws.getName(), self.nsfvanaws.getName()]
-        bglist = [self.sfbkgrws.getName(), self.nsfbkgrws.getName()]
+        vanalist = [self.sfvanaws.name(), self.nsfvanaws.name()]
+        bglist = [self.sfbkgrws.name(), self.nsfbkgrws.name()]
         alg_test = run_algorithm("DNSComputeDetEffCorrCoefs", VanadiumWorkspaces=vanalist,
                                  BackgroundWorkspaces=bglist, OutputWorkspace=outputWorkspaceName)
 
@@ -52,16 +52,16 @@ class DNSComputeDetEffCorrCoefsTest(unittest.TestCase):
 
     def test_NegativeValues(self):
         outputWorkspaceName = "DNSComputeDetCorrCoefsTest_Test2"
-        vanalist = [self.sfvanaws.getName(), self.nsfvanaws.getName()]
-        bglist = [self.sfbkgrws.getName(), self.nsfbkgrws.getName()]
+        vanalist = [self.sfvanaws.name(), self.nsfvanaws.name()]
+        bglist = [self.sfbkgrws.name(), self.nsfbkgrws.name()]
         self.assertRaises(RuntimeError, DNSComputeDetEffCorrCoefs, VanadiumWorkspaces=bglist,
                           BackgroundWorkspaces=vanalist, OutputWorkspace=outputWorkspaceName)
         return
 
     def test_DNSVanadiumCorrection_Masked(self):
         outputWorkspaceName = "DNSComputeDetCorrCoefsTest_Test3"
-        vanalist = [self.sfvanaws.getName(), self.nsfvanaws.getName()]
-        bglist = [self.sfbkgrws.getName(), self.nsfbkgrws.getName()]
+        vanalist = [self.sfvanaws.name(), self.nsfvanaws.name()]
+        bglist = [self.sfbkgrws.name(), self.nsfbkgrws.name()]
         MaskDetectors(self.sfvanaws, DetectorList=[1])
         MaskDetectors(self.nsfvanaws, DetectorList=[1])
 
diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/DNSFlippingRatioCorrTest.py b/Framework/PythonInterface/test/python/plugins/algorithms/DNSFlippingRatioCorrTest.py
index fda177339670e3b5858da450846a09b93a0326c1..f8aeeb7ac9d8e24ced8604c18aa89b288ac8810f 100644
--- a/Framework/PythonInterface/test/python/plugins/algorithms/DNSFlippingRatioCorrTest.py
+++ b/Framework/PythonInterface/test/python/plugins/algorithms/DNSFlippingRatioCorrTest.py
@@ -42,20 +42,20 @@ class DNSFlippingRatioCorrTest(unittest.TestCase):
 
     def test_DNSFlipperValid(self):
         outputWorkspaceName = "DNSFlippingRatioCorrTest_Test2"
-        self.assertRaises(RuntimeError, DNSFlippingRatioCorr, SFDataWorkspace=self.__nsf_nicrws.getName(),
-                          NSFDataWorkspace=self.__nsf_nicrws.getName(), SFNiCrWorkspace=self.__sf_nicrws.getName(),
-                          NSFNiCrWorkspace=self.__nsf_nicrws.getName(), SFBkgrWorkspace=self.__sf_bkgrws.getName(),
-                          NSFBkgrWorkspace=self.__nsf_bkgrws.getName(), SFOutputWorkspace=outputWorkspaceName+'SF',
+        self.assertRaises(RuntimeError, DNSFlippingRatioCorr, SFDataWorkspace=self.__nsf_nicrws.name(),
+                          NSFDataWorkspace=self.__nsf_nicrws.name(), SFNiCrWorkspace=self.__sf_nicrws.name(),
+                          NSFNiCrWorkspace=self.__nsf_nicrws.name(), SFBkgrWorkspace=self.__sf_bkgrws.name(),
+                          NSFBkgrWorkspace=self.__nsf_bkgrws.name(), SFOutputWorkspace=outputWorkspaceName+'SF',
                           NSFOutputWorkspace=outputWorkspaceName+'NSF')
         return
 
     def test_DNSPolarisationValid(self):
         outputWorkspaceName = "DNSFlippingRatioCorrTest_Test3"
         api.AddSampleLog(Workspace=self.__nsf_nicrws, LogName='polarisation', LogText='y', LogType='String')
-        self.assertRaises(RuntimeError, DNSFlippingRatioCorr, SFDataWorkspace=self.__sf_nicrws.getName(),
-                          NSFDataWorkspace=self.__nsf_nicrws.getName(), SFNiCrWorkspace=self.__sf_nicrws.getName(),
-                          NSFNiCrWorkspace=self.__nsf_nicrws.getName(), SFBkgrWorkspace=self.__sf_bkgrws.getName(),
-                          NSFBkgrWorkspace=self.__nsf_bkgrws.getName(), SFOutputWorkspace=outputWorkspaceName+'SF',
+        self.assertRaises(RuntimeError, DNSFlippingRatioCorr, SFDataWorkspace=self.__sf_nicrws.name(),
+                          NSFDataWorkspace=self.__nsf_nicrws.name(), SFNiCrWorkspace=self.__sf_nicrws.name(),
+                          NSFNiCrWorkspace=self.__nsf_nicrws.name(), SFBkgrWorkspace=self.__sf_bkgrws.name(),
+                          NSFBkgrWorkspace=self.__nsf_bkgrws.name(), SFOutputWorkspace=outputWorkspaceName+'SF',
                           NSFOutputWorkspace=outputWorkspaceName+'NSF')
         return
 
@@ -65,9 +65,9 @@ class DNSFlippingRatioCorrTest(unittest.TestCase):
         dataws_sf = self.__sf_nicrws - self.__sf_bkgrws
         dataws_nsf = self.__nsf_nicrws - self.__nsf_bkgrws
         alg_test = run_algorithm("DNSFlippingRatioCorr", SFDataWorkspace=dataws_sf,
-                                 NSFDataWorkspace=dataws_nsf, SFNiCrWorkspace=self.__sf_nicrws.getName(),
-                                 NSFNiCrWorkspace=self.__nsf_nicrws.getName(), SFBkgrWorkspace=self.__sf_bkgrws.getName(),
-                                 NSFBkgrWorkspace=self.__nsf_bkgrws.getName(), SFOutputWorkspace=outputWorkspaceName+'SF',
+                                 NSFDataWorkspace=dataws_nsf, SFNiCrWorkspace=self.__sf_nicrws.name(),
+                                 NSFNiCrWorkspace=self.__nsf_nicrws.name(), SFBkgrWorkspace=self.__sf_bkgrws.name(),
+                                 NSFBkgrWorkspace=self.__nsf_bkgrws.name(), SFOutputWorkspace=outputWorkspaceName+'SF',
                                  NSFOutputWorkspace=outputWorkspaceName+'NSF')
 
         self.assertTrue(alg_test.isExecuted())
@@ -112,9 +112,9 @@ class DNSFlippingRatioCorrTest(unittest.TestCase):
         api.RotateInstrumentComponent(self.__nsf_bkgrws, "bank0", X=0, Y=1, Z=0, Angle=-8.54)
         # apply correction
         alg_test = run_algorithm("DNSFlippingRatioCorr", SFDataWorkspace=dataws_sf,
-                                 NSFDataWorkspace=dataws_nsf, SFNiCrWorkspace=self.__sf_nicrws.getName(),
-                                 NSFNiCrWorkspace=self.__nsf_nicrws.getName(), SFBkgrWorkspace=self.__sf_bkgrws.getName(),
-                                 NSFBkgrWorkspace=self.__nsf_bkgrws.getName(), SFOutputWorkspace=outputWorkspaceName+'SF',
+                                 NSFDataWorkspace=dataws_nsf, SFNiCrWorkspace=self.__sf_nicrws.name(),
+                                 NSFNiCrWorkspace=self.__nsf_nicrws.name(), SFBkgrWorkspace=self.__sf_bkgrws.name(),
+                                 NSFBkgrWorkspace=self.__nsf_bkgrws.name(), SFOutputWorkspace=outputWorkspaceName+'SF',
                                  NSFOutputWorkspace=outputWorkspaceName+'NSF')
 
         self.assertTrue(alg_test.isExecuted())
@@ -155,9 +155,9 @@ class DNSFlippingRatioCorrTest(unittest.TestCase):
         dataws_sf = __sf_vanaws - self.__sf_bkgrws
         dataws_nsf = __nsf_vanaws - self.__nsf_bkgrws
         alg_test = run_algorithm("DNSFlippingRatioCorr", SFDataWorkspace=dataws_sf,
-                                 NSFDataWorkspace=dataws_nsf, SFNiCrWorkspace=self.__sf_nicrws.getName(),
-                                 NSFNiCrWorkspace=self.__nsf_nicrws.getName(), SFBkgrWorkspace=self.__sf_bkgrws.getName(),
-                                 NSFBkgrWorkspace=self.__nsf_bkgrws.getName(), SFOutputWorkspace=outputWorkspaceName+'SF',
+                                 NSFDataWorkspace=dataws_nsf, SFNiCrWorkspace=self.__sf_nicrws.name(),
+                                 NSFNiCrWorkspace=self.__nsf_nicrws.name(), SFBkgrWorkspace=self.__sf_bkgrws.name(),
+                                 NSFBkgrWorkspace=self.__nsf_bkgrws.name(), SFOutputWorkspace=outputWorkspaceName+'SF',
                                  NSFOutputWorkspace=outputWorkspaceName+'NSF')
 
         self.assertTrue(alg_test.isExecuted())
diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/DakotaChiSquaredTest.py b/Framework/PythonInterface/test/python/plugins/algorithms/DakotaChiSquaredTest.py
index 92b56ce0104d1217c43e8cf95fc0c81c5142c4ee..89da8d25fd3b183c7ee66cf6134b7164c8dbf0f9 100644
--- a/Framework/PythonInterface/test/python/plugins/algorithms/DakotaChiSquaredTest.py
+++ b/Framework/PythonInterface/test/python/plugins/algorithms/DakotaChiSquaredTest.py
@@ -87,14 +87,14 @@ class DakotaChiSquaredTest(unittest.TestCase):
     		alg=mantid.simpleapi.DakotaChiSquared(self.datafile,self.simfile,self.chifile)
     		self.assertEquals(len(alg),2)
     		self.assertEquals(alg[0],4.5)
-    		self.assertEquals(alg[1].getName(),"alg")
+    		self.assertEquals(alg[1].name(),"alg")
     		self.assertEquals(alg[1].blocksize(),5)
     		self.assertEquals(alg[1].getNumberHistograms(),1)
     		self.assertEquals(alg[1].dataY(0)[3],1.5)
     		mantid.api.AnalysisDataService.remove("alg")
     		alg1=mantid.simpleapi.DakotaChiSquared(self.datafile,self.simfile,self.chifile,ResidualsWorkspace="res")
     		self.assertEquals(alg1[0],4.5)
-    		self.assertEquals(alg1[1].getName(),"res")
+    		self.assertEquals(alg1[1].name(),"res")
     		mantid.api.AnalysisDataService.remove("res")
     	except:
     		assert False, "Raised an exception"
diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/EnergyWindowScanTest.py b/Framework/PythonInterface/test/python/plugins/algorithms/EnergyWindowScanTest.py
new file mode 100644
index 0000000000000000000000000000000000000000..f6304b866be1188ed18effcd8a9bd7f965327009
--- /dev/null
+++ b/Framework/PythonInterface/test/python/plugins/algorithms/EnergyWindowScanTest.py
@@ -0,0 +1,35 @@
+from __future__ import (absolute_import, division, print_function)
+
+import unittest
+from mantid.simpleapi import EnergyWindowScan
+from mantid.api import mtd
+
+
+class EnergyWindowScanTest(unittest.TestCase):
+    def test_IRIS(self):
+        EnergyWindowScan(InputFiles="IRS26176.RAW, IRS26173.RAW", Instrument='IRIS', Analyser='graphite',
+                         Reflection='002', SpectraRange='3, 50', ElasticRange='-0.5, 0',
+                         InelasticRange='0, 0.5', GroupingMethod='All')
+        scan_ws = mtd['Scan_eisf']
+        self.assertEqual(round(scan_ws.readY(0)[0], 7), 0.9737326)
+        self.assertEqual(round(scan_ws.readY(1)[0], 7), 1.0528091)
+
+    def test_OSIRIS(self):
+        EnergyWindowScan(InputFiles="osi89757.raw", Instrument='OSIRIS', Analyser='graphite',
+                         Reflection='002', SpectraRange='963, 1004', ElasticRange='-1.0, 0',
+                         InelasticRange='0, 1.5', GroupingMethod='All')
+
+        self.assertEqual(round(mtd['Scan_el_eq1'].readY(0)[0], 7), 0)
+        self.assertEqual(round(mtd['Scan_inel_eq2'].readY(0)[0], 7), -6.8454638)
+
+    def test_MSDFit(self):
+        EnergyWindowScan(InputFiles="IRS26176.RAW", Instrument='IRIS', Analyser='graphite',
+                         Reflection='002', SpectraRange='3, 50', ElasticRange='-0.5, 0',
+                         InelasticRange='0, 0.5', GroupingMethod='Individual', MSDFit=True)
+        scan_ws = mtd['Scan_el_eq2_0_Workspace']
+        self.assertEqual(round(scan_ws.readY(0)[0], 7), -2.4719849)
+        self.assertEqual(round(scan_ws.readY(0)[1], 7), -2.3400994)
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/EnggFitPeaksTest.py b/Framework/PythonInterface/test/python/plugins/algorithms/EnggFitPeaksTest.py
index e75e160b2509463f77af38ccf65adc2b68ebfa09..9a6129bbcfb55d1f012889821646cde9a0cbd01d 100644
--- a/Framework/PythonInterface/test/python/plugins/algorithms/EnggFitPeaksTest.py
+++ b/Framework/PythonInterface/test/python/plugins/algorithms/EnggFitPeaksTest.py
@@ -82,7 +82,7 @@ class EnggFitPeaksTest(unittest.TestCase):
         cell00, cell01, cell10, cell14 = cells
         # it has ben created
         tbl = mtd[tbl_name]
-        self.assertEquals(tbl.getName(), tbl_name)
+        self.assertEquals(tbl.name(), tbl_name)
         self.assertTrue(isinstance(tbl, ITableWorkspace),
                         'The output workspace of fitted peaks should be a table workspace.')
 
diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/EnggFocusTest.py b/Framework/PythonInterface/test/python/plugins/algorithms/EnggFocusTest.py
index 4e0287de591d3edb99debef92a55dc199ffe447b..02e649f3db1e44e3fdf4b7b04032d1c65b8db98a 100644
--- a/Framework/PythonInterface/test/python/plugins/algorithms/EnggFocusTest.py
+++ b/Framework/PythonInterface/test/python/plugins/algorithms/EnggFocusTest.py
@@ -126,11 +126,11 @@ class EnggFocusTest(unittest.TestCase):
         self.assertEqual(wks.YUnit(), 'Counts')
         dimX = wks.getXDimension()
         self.assertAlmostEqual( dimX.getMaximum(), 36938.078125)
-        self.assertEqual(dimX.getName(), 'Time-of-flight')
+        self.assertEqual(dimX.name, 'Time-of-flight')
         self.assertEqual(dimX.getUnits(), 'microsecond')
         dimY = wks.getYDimension()
         self.assertEqual(dimY.getMaximum(), y_dim_max)
-        self.assertEqual(dimY.getName(), 'Spectrum')
+        self.assertEqual(dimY.name, 'Spectrum')
         self.assertEqual(dimY.getUnits(), '')
 
         if yvalues is None:
diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/ExtractMonitorsTest.py b/Framework/PythonInterface/test/python/plugins/algorithms/ExtractMonitorsTest.py
index f3bed3318fee01e3368d6f63c6bc8a8f45472edf..70750022f8ed2c8c88811f7dc2e22122961c2898 100644
--- a/Framework/PythonInterface/test/python/plugins/algorithms/ExtractMonitorsTest.py
+++ b/Framework/PythonInterface/test/python/plugins/algorithms/ExtractMonitorsTest.py
@@ -83,11 +83,13 @@ class ExtractMonitorsTest(unittest.TestCase):
         self.assertEquals(monitors.getNumberHistograms(), 3)
         self.assertEquals(detectors.getMonitorWorkspace().name(), "mon")
 
+        spectrumInfo = monitors.spectrumInfo()
         for i in range(monitors.getNumberHistograms()):
-            self.assertTrue(monitors.getDetector(i).isMonitor())
+            self.assertTrue(spectrumInfo.isMonitor(i))
 
+        spectrumInfo = detectors.spectrumInfo()
         for i in range(detectors.getNumberHistograms()):
-            self.assertFalse(detectors.getDetector(i).isMonitor())
+            self.assertFalse(spectrumInfo.isMonitor(i))
 
 if __name__=="__main__":
     unittest.main()
diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/ILLIN16BCalibrationTest.py b/Framework/PythonInterface/test/python/plugins/algorithms/ILLIN16BCalibrationTest.py
index fc23abe86d918a1a707c57550ace69a84d7d0cda..b9ecdf5d8ddebb2320dd23b279558fcf09b4f54a 100644
--- a/Framework/PythonInterface/test/python/plugins/algorithms/ILLIN16BCalibrationTest.py
+++ b/Framework/PythonInterface/test/python/plugins/algorithms/ILLIN16BCalibrationTest.py
@@ -24,7 +24,7 @@ class ILLIN16BCalibrationTest(unittest.TestCase):
                                        MirrorMode=False,
                                        PeakRange=[-0.001, 0.002])
 
-        self.assertEqual(calib_ws.getNumberHistograms(), 24)
+        self.assertEqual(calib_ws.getNumberHistograms(), 18)
         self.assertEqual(calib_ws.blocksize(), 1)
 
 
@@ -33,7 +33,7 @@ class ILLIN16BCalibrationTest(unittest.TestCase):
                                        MirrorMode=True,
                                        PeakRange=[-0.001, 0.002])
 
-        self.assertEqual(calib_ws.getNumberHistograms(), 24)
+        self.assertEqual(calib_ws.getNumberHistograms(), 18)
         self.assertEqual(calib_ws.blocksize(), 1)
 
 
diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/IndirectILLEnergyTransferTest.py b/Framework/PythonInterface/test/python/plugins/algorithms/IndirectILLEnergyTransferTest.py
new file mode 100644
index 0000000000000000000000000000000000000000..e666e353815b51c272cb49c7589b89bc8acd97a3
--- /dev/null
+++ b/Framework/PythonInterface/test/python/plugins/algorithms/IndirectILLEnergyTransferTest.py
@@ -0,0 +1,115 @@
+from __future__ import (absolute_import, division, print_function)
+
+import os
+import unittest
+from mantid.simpleapi import *
+from mantid.api import MatrixWorkspace,WorkspaceGroup
+from mantid import config
+
+
+class IndirectILLEnergyTransferTest(unittest.TestCase):
+
+    _runs = dict([('one_wing_QENS', '090661'),
+                  ('one_wing_EFWS', '083072'),
+                  ('one_wing_IFWS', '083073'),
+                  ('two_wing_QENS', '136558-136559'),
+                  ('two_wing_EFWS', '143720'),
+                  ('two_wing_IFWS', '170300')])
+
+    # cache the def instrument and data search dirs
+    _def_fac = config['default.facility']
+    _def_inst = config['default.instrument']
+    _data_dirs = config['datasearch.directories']
+
+    def setUp(self):
+        # set instrument and append datasearch directory
+        config['default.facility'] = 'ILL'
+        config['default.instrument'] = 'IN16B'
+        config.appendDataSearchSubDir('ILL/IN16B/')
+
+    def tearDown(self):
+        # set cached facility and datasearch directory
+        config['default.facility'] = self._def_fac
+        config['default.instrument'] = self._def_inst
+        config['datasearch.directories'] = self._data_dirs
+
+    def test_complete_options(self):
+        # Tests for map file, no verbose, multiple runs, and crop dead channels for two wing QENS data
+
+        # manually get name of grouping file from parameter file
+        idf = os.path.join(config['instrumentDefinition.directory'], "IN16B_Definition.xml")
+        ipf = os.path.join(config['instrumentDefinition.directory'], "IN16B_Parameters.xml")
+        ws = LoadEmptyInstrument(Filename=idf)
+        LoadParameterFile(ws, Filename=ipf)
+        instrument = ws.getInstrument()
+        grouping_filename = instrument.getStringParameter('Workflow.GroupingFile')[0]
+        DeleteWorkspace(ws)
+
+        args = {'Run': self._runs['two_wing_QENS'],
+                'MapFile': os.path.join(config['groupingFiles.directory'], grouping_filename),
+                'CropDeadMonitorChannels': True,
+                'OutputWorkspace': 'red'}
+
+        IndirectILLEnergyTransfer(**args)
+
+        self._check_workspace_group(mtd['red'], 2, 18, 1017)
+
+    def test_one_wing_QENS(self):
+        # tests one wing QENS with PSD range
+        args = {'Run': self._runs['one_wing_QENS'],
+                'ManualPSDIntegrationRange': [20,100]}
+        res = IndirectILLEnergyTransfer(**args)
+        self._check_workspace_group(res, 1, 18, 1024)
+
+    def test_one_wing_EFWS(self):
+        args = {'Run': self._runs['one_wing_EFWS']}
+        res = IndirectILLEnergyTransfer(**args)
+        self._check_workspace_group(res, 1, 18, 256)
+
+    def test_one_wing_IFWS(self):
+        args = {'Run': self._runs['one_wing_IFWS']}
+        res = IndirectILLEnergyTransfer(**args)
+        self._check_workspace_group(res, 1, 18, 256)
+
+    def test_two_wing_EFWS(self):
+        args = {'Run': self._runs['two_wing_EFWS']}
+        res = IndirectILLEnergyTransfer(**args)
+        self._check_workspace_group(res, 2, 18, 8)
+
+    def test_two_wing_IFWS(self):
+        args = {'Run': self._runs['two_wing_IFWS']}
+        res = IndirectILLEnergyTransfer(**args)
+        self._check_workspace_group(res, 2, 18, 512)
+
+    def _check_workspace_group(self, wsgroup, nentries, nspectra, nbins):
+
+        self.assertTrue(isinstance(wsgroup, WorkspaceGroup),
+                        "{0} should be a group workspace".format(wsgroup.getName()))
+
+        self.assertEquals(wsgroup.getNumberOfEntries(),nentries,
+                          "{0} should contain {1} workspaces".format(wsgroup.getName(),nentries))
+
+        item = wsgroup.getItem(0)
+
+        name = item.getName()
+
+        self.assertTrue(isinstance(item, MatrixWorkspace),
+                        "{0} should be a matrix workspace".format(name))
+
+        self.assertEqual(item.getAxis(0).getUnit().unitID(), "DeltaE",
+                         "{0} should have DeltaE units in X-axis".format(name))
+
+        self.assertEquals(item.getNumberHistograms(),nspectra,
+                          "{0} should contain {1} spectra".format(name,nspectra))
+
+        self.assertEquals(item.blocksize(), nbins,
+                          "{0} should contain {1} bins".format(name, nbins))
+
+        self.assertTrue(item.getSampleDetails(),
+                        "{0} should have sample logs".format(name))
+
+        self.assertTrue(item.getHistory().lastAlgorithm(),
+                        "{0} should have history".format(name))
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/IndirectILLReductionFWSTest.py b/Framework/PythonInterface/test/python/plugins/algorithms/IndirectILLReductionFWSTest.py
new file mode 100644
index 0000000000000000000000000000000000000000..953476be04de4b5e10c2ec24fd61ae056d5e5a0a
--- /dev/null
+++ b/Framework/PythonInterface/test/python/plugins/algorithms/IndirectILLReductionFWSTest.py
@@ -0,0 +1,93 @@
+from __future__ import (absolute_import, division, print_function)
+
+import unittest
+from mantid.simpleapi import mtd
+from testhelpers import run_algorithm
+from mantid.api import WorkspaceGroup, MatrixWorkspace
+from mantid import config
+
+
+class IndirectILLReductionFWS(unittest.TestCase):
+
+    # cache the def instrument and data search dirs
+    _def_fac = config['default.facility']
+    _def_inst = config['default.instrument']
+    _data_dirs = config['datasearch.directories']
+
+    # EFWS+IFWS, two wing
+    _run_two_wing_mixed = '170299:170304'
+
+    # EFWS+IFWS, one wing
+    _run_one_wing_mixed = '083072:083077'
+
+    def setUp(self):
+        # set instrument and append datasearch directory
+        config['default.facility'] = 'ILL'
+        config['default.instrument'] = 'IN16B'
+        config.appendDataSearchSubDir('ILL/IN16B/')
+
+    def tearDown(self):
+        # set cached facility and datasearch directory
+        config['default.facility'] = self._def_fac
+        config['default.instrument'] = self._def_inst
+        config['datasearch.directories'] = self._data_dirs
+
+    def test_two_wing(self):
+
+        args = {'Run': self._run_two_wing_mixed,
+                'OutputWorkspace': 'out'}
+
+        alg_test = run_algorithm('IndirectILLReductionFWS', **args)
+
+        self.assertTrue(alg_test.isExecuted(), "IndirectILLReductionFWS not executed")
+
+        self._check_workspace_group(mtd['out_red'], 2, 18, 3)
+
+        runs_log1 = mtd['out_red'].getItem(0).getRun().getLogData('ReducedRunsList').value
+
+        runs_log2 = mtd['out_red'].getItem(1).getRun().getLogData('ReducedRunsList').value
+
+        self.assertEquals(runs_log1,'170299,170301,170303',"Reduced runs list mismatch.")
+
+        self.assertEquals(runs_log2,'170300,170302,170304',"Reduced runs list mismatch.")
+
+    def test_one_wing(self):
+
+        args = {'Run': self._run_one_wing_mixed,
+                'OutputWorkspace': 'out'}
+
+        alg_test = run_algorithm('IndirectILLReductionFWS', **args)
+
+        self.assertTrue(alg_test.isExecuted(), "IndirectILLReductionFWS not executed")
+
+        self._check_workspace_group(mtd['out_red'], 3, 18, 2)
+
+    def _check_workspace_group(self, wsgroup, nentries, nspectra, nbins):
+
+        self.assertTrue(isinstance(wsgroup, WorkspaceGroup),
+                        "{0} should be a group workspace".format(wsgroup.getName()))
+
+        self.assertEquals(wsgroup.getNumberOfEntries(), nentries,
+                          "{0} should contain {1} workspaces".format(wsgroup.getName(), nentries))
+
+        item = wsgroup.getItem(0)
+
+        name = item.getName()
+
+        self.assertTrue(isinstance(item, MatrixWorkspace),
+                        "{0} should be a matrix workspace".format(name))
+
+        self.assertEquals(item.getNumberHistograms(), nspectra,
+                          "{0} should contain {1} spectra".format(name, nspectra))
+
+        self.assertEquals(item.blocksize(), nbins,
+                          "{0} should contain {1} bins".format(name, nbins))
+
+        self.assertTrue(item.getSampleDetails(),
+                        "{0} should have sample logs".format(name))
+
+        self.assertTrue(item.getHistory().lastAlgorithm(),
+                        "{0} should have history".format(name))
+
+if __name__ == "__main__":
+    unittest.main()
diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/IndirectILLReductionQENSTest.py b/Framework/PythonInterface/test/python/plugins/algorithms/IndirectILLReductionQENSTest.py
new file mode 100644
index 0000000000000000000000000000000000000000..b337a729836d2c1b4914c6dac0fa3865573b6d1b
--- /dev/null
+++ b/Framework/PythonInterface/test/python/plugins/algorithms/IndirectILLReductionQENSTest.py
@@ -0,0 +1,100 @@
+from __future__ import (absolute_import, division, print_function)
+
+import unittest
+from mantid.simpleapi import *
+from mantid.api import MatrixWorkspace, WorkspaceGroup
+from mantid import config
+from testhelpers import run_algorithm
+
+
+class IndirectILLReductionQENSTest(unittest.TestCase):
+
+    _run_one_wing = '090661'
+
+    _runs_two_wing_multi = '136558,136559'
+
+    # cache the def instrument and data search dirs
+    _def_fac = config['default.facility']
+    _def_inst = config['default.instrument']
+    _data_dirs = config['datasearch.directories']
+
+    def setUp(self):
+        # set instrument and append datasearch directory
+        config['default.facility'] = 'ILL'
+        config['default.instrument'] = 'IN16B'
+        config.appendDataSearchSubDir('ILL/IN16B/')
+
+    def tearDown(self):
+        # set cached facility and datasearch directory
+        config['default.facility'] = self._def_fac
+        config['default.instrument'] = self._def_inst
+        config['datasearch.directories'] = self._data_dirs
+
+    def test_two_wing_multi(self):
+
+        args = {'Run': self._runs_two_wing_multi,
+                'OutputWorkspace': 'out'}
+
+        alg_test = run_algorithm('IndirectILLReductionQENS', **args)
+
+        self.assertTrue(alg_test.isExecuted(), "IndirectILLReductionQENS not executed")
+
+        self._check_workspace_group(mtd['out_red'], 2, 18, 1024)
+
+        alg_test = run_algorithm('IndirectILLReductionQENS', **args)
+
+        self.assertTrue(alg_test.isExecuted(), "IndirectILLReductionQENS not executed")
+
+        self._check_workspace_group(mtd['out_red'], 2, 18, 1024)
+
+        args['SumRuns'] = True
+
+        alg_test = run_algorithm('IndirectILLReductionQENS', **args)
+
+        self.assertTrue(alg_test.isExecuted(), "IndirectILLReductionQENS not executed")
+
+        self._check_workspace_group(mtd['out_red'], 1, 18, 1024)
+
+    def test_one_wing(self):
+
+        args = {'Run': self._run_one_wing,
+                'OutputWorkspace': 'out'}
+
+        alg_test = run_algorithm('IndirectILLReductionQENS', **args)
+
+        self.assertTrue(alg_test.isExecuted(), "IndirectILLReductionQENS not executed")
+
+        self._check_workspace_group(mtd['out_red'], 1, 18, 1024)
+
+    def _check_workspace_group(self, wsgroup, nentries, nspectra, nbins):
+
+        self.assertTrue(isinstance(wsgroup, WorkspaceGroup),
+                        "{0} should be a group workspace".format(wsgroup.getName()))
+
+        self.assertEquals(wsgroup.getNumberOfEntries(),nentries,
+                          "{0} should contain {1} workspaces".format(wsgroup.getName(),nentries))
+
+        item = wsgroup.getItem(0)
+
+        name = item.getName()
+
+        self.assertTrue(isinstance(item, MatrixWorkspace),
+                        "{0} should be a matrix workspace".format(name))
+
+        self.assertEqual(item.getAxis(0).getUnit().unitID(), "DeltaE",
+                         "{0} should have DeltaE units in X-axis".format(name))
+
+        self.assertEquals(item.getNumberHistograms(),nspectra,
+                          "{0} should contain {1} spectra".format(name,nspectra))
+
+        self.assertEquals(item.blocksize(), nbins,
+                          "{0} should contain {1} bins".format(name, nbins))
+
+        self.assertTrue(item.getSampleDetails(),
+                        "{0} should have sample logs".format(name))
+
+        self.assertTrue(item.getHistory().lastAlgorithm(),
+                        "{0} should have history".format(name))
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/IndirectILLReductionTest.py b/Framework/PythonInterface/test/python/plugins/algorithms/IndirectILLReductionTest.py
index 12c48ede099b22481f9fcc06d6d8d61775a9f88d..ad012b321baf1ab6add8ed80ea9c812d948746c8 100644
--- a/Framework/PythonInterface/test/python/plugins/algorithms/IndirectILLReductionTest.py
+++ b/Framework/PythonInterface/test/python/plugins/algorithms/IndirectILLReductionTest.py
@@ -112,7 +112,7 @@ class IndirectILLReductionTest(unittest.TestCase):
 
         IndirectILLReduction(**self.kwargs)
         red_workspace = mtd[self.kwargs['ReducedWorkspace']]
-        self.assertEqual(24, red_workspace.getNumberHistograms())
+        self.assertEqual(18, red_workspace.getNumberHistograms())
 
 
 if __name__ == '__main__':
diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/MSDFitTest.py b/Framework/PythonInterface/test/python/plugins/algorithms/MSDFitTest.py
index 35872a3e6046b1ad407a85bd678dfc4a1ccd6757..19f9c3efb1b81e372b07ed91162c6f4640a027f3 100644
--- a/Framework/PythonInterface/test/python/plugins/algorithms/MSDFitTest.py
+++ b/Framework/PythonInterface/test/python/plugins/algorithms/MSDFitTest.py
@@ -1,23 +1,22 @@
 from __future__ import (absolute_import, division, print_function)
 
 import unittest
-from mantid.simpleapi import *
+from mantid.simpleapi import CreateSampleWorkspace, MSDFit
 from mantid.api import *
 
-class MSDFitTest(unittest.TestCase):
 
+class MSDFitTest(unittest.TestCase):
     def setUp(self):
         """
         Creates a sample workspace for testing.
         """
 
         sample = CreateSampleWorkspace(Function='User Defined',
-                        UserDefinedFunction='name=ExpDecay,Height=1,Lifetime=6',
-                        NumBanks=5, BankPixelWidth=1, XUnit='QSquared', XMin=0.0,
-                        XMax=5.0, BinWidth=0.1)
+                                       UserDefinedFunction='name=ExpDecay,Height=1,Lifetime=6',
+                                       NumBanks=5, BankPixelWidth=1, XUnit='QSquared', XMin=0.0,
+                                       XMax=5.0, BinWidth=0.1)
         self._ws = sample
 
-
     def _validate_workspaces(self, msd_ws, param_ws, fit_ws):
         """
         Validates the various workspaces produced by MSDFit.
@@ -28,20 +27,16 @@ class MSDFitTest(unittest.TestCase):
         """
 
         # First validate workspace types
-        self.assertTrue(isinstance(msd_ws, WorkspaceGroup), 'MSD workspace should be a WorkspaceGroup')
+        self.assertTrue(isinstance(msd_ws, MatrixWorkspace), 'MSD workspace should be a MatrixWorkspace')
         self.assertTrue(isinstance(param_ws, ITableWorkspace), 'Fit parameter workspace should be a TableWorkspace')
         self.assertTrue(isinstance(fit_ws, WorkspaceGroup), 'Fit workspace should be a WorkspaceGroup')
 
         # Validate number of items in groups
-        self.assertEqual(msd_ws.getNumberOfEntries(), 2)
         self.assertEqual(fit_ws.getNumberOfEntries(), 5)
 
         # Validate MSD property workspaces
-        self.assertEqual(msd_ws[0].name(), 'msd_A0')
-        self.assertEqual(msd_ws[1].name(), 'msd_A1')
-        self.assertEqual(len(msd_ws[0].readX(0)), 5)
-        self.assertEqual(len(msd_ws[1].readX(0)), 5)
-
+        self.assertEqual(len(msd_ws.readX(0)), 5)
+        self.assertEqual(len(msd_ws.readX(1)), 5)
 
     def test_basic_run(self):
         """
@@ -57,7 +52,6 @@ class MSDFitTest(unittest.TestCase):
         self.assertTrue(mtd.doesExist('msd_Workspaces'), 'Should have a fit WS with the default name')
         self._validate_workspaces(mtd['msd'], mtd['msd_Parameters'], mtd['msd_Workspaces'])
 
-
     def test_basic_run_given_names(self):
         """
         Tests a basic run providing names of all output workspaces.
@@ -69,7 +63,6 @@ class MSDFitTest(unittest.TestCase):
 
         self._validate_workspaces(msd, param, fit)
 
-
     def test_fail_spec_min(self):
         """
         Tests validation for SpecMin >= 0.
@@ -80,7 +73,6 @@ class MSDFitTest(unittest.TestCase):
                                      XStart=0.0, XEnd=5.0,
                                      SpecMin=-1, SpecMax=0)
 
-
     def test_fail_spec_min(self):
         """
         Tests validation for SpecMin >= num histograms.
@@ -93,10 +85,9 @@ class MSDFitTest(unittest.TestCase):
                           SpecMin=0, SpecMax=20,
                           OutputWorkspace='msd')
 
-
     def test_fail_spec_range(self):
         """
-        Test svalidation for SpecMax >= SpecMin.
+        Tests validation for SpecMax >= SpecMin.
         """
 
         self.assertRaises(RuntimeError,
@@ -106,7 +97,6 @@ class MSDFitTest(unittest.TestCase):
                           SpecMin=1, SpecMax=0,
                           OutputWorkspace='msd')
 
-
     def test_fail_x_range(self):
         """
         Tests validation for XStart < XEnd.
@@ -119,7 +109,6 @@ class MSDFitTest(unittest.TestCase):
                           SpecMin=0, SpecMax=0,
                           OutputWorkspace='msd')
 
-
     def test_fail_x_range_ws(self):
         """
         Tests validation for X range in workspace range
diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/MaskAngleTest.py b/Framework/PythonInterface/test/python/plugins/algorithms/MaskAngleTest.py
index 44b7eaa7b13d5fdc3bef0c64db687ae8403d7688..8056afe9f1896b09491af8bd870f903ec67b6f45 100644
--- a/Framework/PythonInterface/test/python/plugins/algorithms/MaskAngleTest.py
+++ b/Framework/PythonInterface/test/python/plugins/algorithms/MaskAngleTest.py
@@ -12,11 +12,12 @@ class MaskAngleTest(unittest.TestCase):
         w=WorkspaceCreationHelper.create2DWorkspaceWithFullInstrument(30,5,False,False)
         AnalysisDataService.add('w',w)
         masklist = MaskAngle(w,10,20)
-        for i in arange(w.getNumberHistograms())+1:
-            if (i<10) or (i>19):
-                self.assertTrue(not w.getInstrument().getDetector(int(i)).isMasked())
+        detInfo = w.detectorInfo()
+        for i in arange(w.getNumberHistograms()):
+            if (i<9) or (i>18):
+                self.assertFalse(detInfo.isMasked(int(i)))
             else:
-                self.assertTrue(w.getInstrument().getDetector(int(i)).isMasked())
+                self.assertTrue(detInfo.isMasked(int(i)))
         DeleteWorkspace(w)
         self.assertTrue(array_equal(masklist,arange(10)+10))
 
@@ -30,11 +31,12 @@ class MaskAngleTest(unittest.TestCase):
         MaskAngle(group, 10, 20)
 
         for w in group:
-            for i in arange(w.getNumberHistograms())+1:
-                if(i<10) or (i>19):
-                    self.assertTrue(not w.getInstrument().getDetector(int(i)).isMasked())
+            detInfo = w.detectorInfo()
+            for i in arange(w.getNumberHistograms()):
+                if(i<9) or (i>18):
+                    self.assertFalse(detInfo.isMasked(int(i)))
                 else:
-                    self.assertTrue(w.getInstrument().getDetector(int(i)).isMasked())
+                    self.assertTrue(detInfo.isMasked(int(i)))
 
         DeleteWorkspace(group)
 
diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/MaskBTPTest.py b/Framework/PythonInterface/test/python/plugins/algorithms/MaskBTPTest.py
index d6d0fe7248fe44f4fa134e571fb80b19554e7181..05f9f0bf60b1ff61ab7849818b5a23ad91fd079b 100644
--- a/Framework/PythonInterface/test/python/plugins/algorithms/MaskBTPTest.py
+++ b/Framework/PythonInterface/test/python/plugins/algorithms/MaskBTPTest.py
@@ -51,16 +51,17 @@ class MaskBTPTest(unittest.TestCase):
         self.assertTrue(array_equal(m3,concatenate((b5t3,b5t3+1024,b5t3+2048))))
         #check whether some pixels are masked when they should
         w=mtd['CNCSMaskBTP']
-        self.assertTrue(w.getInstrument().getDetector(29696).isMasked()) #pixel1
-        self.assertTrue(w.getInstrument().getDetector(29697).isMasked()) #pixel2
-        self.assertTrue(w.getInstrument().getDetector(29698).isMasked()) #pixel3
-        self.assertTrue(not w.getInstrument().getDetector(29699).isMasked()) #pixel4
-        self.assertTrue(w.getInstrument().getDetector(29700).isMasked()) #pixel5
+        detInfo = w.detectorInfo()
+        self.assertTrue(detInfo.isMasked(29699)) #pixel1 (detID 29696)
+        self.assertTrue(detInfo.isMasked(29700)) #pixel2 (detID 29697)
+        self.assertTrue(detInfo.isMasked(29701)) #pixel3 (detID 29698)
+        self.assertFalse(detInfo.isMasked(29702)) #pixel4 (detID 29699)
+        self.assertTrue(detInfo.isMasked(29703)) #pixel5 (detID 29700)
 
-        self.assertTrue(w.getInstrument().getDetector(1020).isMasked()) #bank 1
-        self.assertTrue(not w.getInstrument().getDetector(3068).isMasked()) #bank3, tube 8
+        self.assertTrue(detInfo.isMasked(1023)) #bank1 (detID 1020)
+        self.assertFalse(detInfo.isMasked(3071)) #bank3, tube 8 (detID 3068)
 
-        self.assertTrue(w.getInstrument().getDetector(4400).isMasked()) #bank5, tube 3
+        self.assertTrue(detInfo.isMasked(4403)) #bank5, tube 3 (detID 4400)
         DeleteWorkspace(w)
 
 if __name__ == '__main__':
diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/MedianBinWidthTest.py b/Framework/PythonInterface/test/python/plugins/algorithms/MedianBinWidthTest.py
new file mode 100644
index 0000000000000000000000000000000000000000..3b2fa09efca05a2ae4f0f93bb7709143d0856f59
--- /dev/null
+++ b/Framework/PythonInterface/test/python/plugins/algorithms/MedianBinWidthTest.py
@@ -0,0 +1,83 @@
+from __future__ import (absolute_import, division, print_function)
+
+from mantid.simpleapi import CreateWorkspace, DeleteWorkspace
+import numpy
+import testhelpers
+import unittest
+
+
+class MedianBinWidthTest(unittest.TestCase):
+
+    def _make_algorithm_params(self, ws, rounding='None'):
+        return {
+            'InputWorkspace': ws,
+            'rethrow': True,  # Let exceptions through for testing.
+            'Rounding': rounding
+        }
+
+    def _make_boundaries(self, xBegin, binWidths):
+        return numpy.cumsum(numpy.append(numpy.array([xBegin]), binWidths))
+
+    def _run_algorithm(self, params):
+        algorithm = testhelpers.create_algorithm('MedianBinWidth', **params)
+        testhelpers.assertRaisesNothing(self, algorithm.execute)
+        self.assertTrue(algorithm.isExecuted())
+        return algorithm.getProperty('BinWidth').value
+
+    def test_success_single_histogram(self):
+        binWidths = numpy.array([0.5, 0.5, 2.3, 2.3, 2.3, 5.9])
+        xs = self._make_boundaries(-3.33, binWidths)
+        ys = numpy.zeros(len(xs) - 1)
+        ws = CreateWorkspace(DataX=xs, DataY=ys)
+        params = self._make_algorithm_params(ws)
+        binWidth = self._run_algorithm(params)
+        expectedBinWidth = numpy.median(binWidths)
+        self.assertAlmostEqual(binWidth, expectedBinWidth)
+        DeleteWorkspace(ws)
+
+    def test_average_over_multiple_histograms(self):
+        binWidths = numpy.array([0.5, 0.5, 2.3, 2.3, 2.3, 6.5,
+                                 0.4, 1.3, 0.4, 1.3, 2.5, 1.3])
+        xs1 = self._make_boundaries(-6.6, binWidths[:6])
+        xs2 = self._make_boundaries(99.6, binWidths[6:])
+        xs = numpy.concatenate((xs1, xs2))
+        ys = numpy.zeros(len(xs) - 2)
+        ws = CreateWorkspace(DataX=xs, DataY=ys, NSpec=2)
+        params = self._make_algorithm_params(ws)
+        binWidth = self._run_algorithm(params)
+        expectedBinWidth = 0.5 * (2.3 + 1.3)
+        self.assertAlmostEqual(binWidth, expectedBinWidth)
+        DeleteWorkspace(ws)
+
+    def test_rounding(self):
+        binWidths = numpy.array([0.5, 6.1, 2.3, 0.5, 2.3, 2.3])
+        xs = self._make_boundaries(-3.33, binWidths)
+        ys = numpy.zeros(len(xs) - 1)
+        ws = CreateWorkspace(DataX=xs, DataY=ys)
+        params = self._make_algorithm_params(ws, rounding='10^n')
+        binWidth = self._run_algorithm(params)
+        expectedBinWidth = 1.0
+        self.assertAlmostEqual(binWidth, expectedBinWidth)
+        DeleteWorkspace(ws)
+
+    def test_throws_on_non_histogram_input(self):
+        xs = numpy.array([-0.7, 0.7, 1.1, 1.8, 2.2])
+        ys = numpy.zeros(len(xs))
+        ws = CreateWorkspace(DataX=xs, DataY=ys, Distribution=True)
+        params = self._make_algorithm_params(ws)
+        self.assertRaises(ValueError, testhelpers.create_algorithm,
+                          'BinWidthAtX', **params)
+        DeleteWorkspace(ws)
+
+    def test_positive_output_even_if_descending_x(self):
+        xs = numpy.array([110.0, 60.0, 40.0, -10.0])
+        ys = numpy.zeros(len(xs) - 1)
+        ws = CreateWorkspace(DataX=xs, DataY=ys)
+        params = self._make_algorithm_params(ws)
+        binWidth = self._run_algorithm(params)
+        expectedBinWidth = 50.0
+        self.assertAlmostEqual(binWidth, expectedBinWidth)
+        DeleteWorkspace(ws)
+
+if __name__ == "__main__":
+    unittest.main()
diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/SANSFitShiftScaleTest.py b/Framework/PythonInterface/test/python/plugins/algorithms/SANSFitShiftScaleTest.py
index a473fd211772d995c1ef4cd440d425ca9286177d..25235500bae3751de944ab6543ccf64fd976d863 100644
--- a/Framework/PythonInterface/test/python/plugins/algorithms/SANSFitShiftScaleTest.py
+++ b/Framework/PythonInterface/test/python/plugins/algorithms/SANSFitShiftScaleTest.py
@@ -173,7 +173,7 @@ class SANSFitShiftScaleTest(unittest.TestCase):
         self.assertEquals(out_scale_factor, 1.0)
         self.assertEquals(out_shift_factor, -5.0)
 
-    def test_scale_both(self):
+    def do_test_scale_both(self, hab_range):
         create_alg = AlgorithmManager.create('CreateWorkspace')
         create_alg.setChild(True)
         create_alg.initialize()
@@ -183,14 +183,14 @@ class SANSFitShiftScaleTest(unittest.TestCase):
         create_alg.setProperty('DataX', range(0, 10))
 
         # HAB as linear function y=x+5
-        create_alg.setProperty('DataY', range(5, 14))
+        create_alg.setProperty('DataY', hab_range)
         create_alg.execute()
         hab_workspace = create_alg.getProperty('OutputWorkspace').value
 
         # LAB as linear function y=x+0
         create_alg.setProperty('DataY', range(0, 9))
         create_alg.execute()
-        lab_workspace= create_alg.getProperty('OutputWorkspace').value
+        lab_workspace = create_alg.getProperty('OutputWorkspace').value
 
         # FLAT NORM
         create_alg.setProperty('DataY', [1] * 9)
@@ -213,6 +213,17 @@ class SANSFitShiftScaleTest(unittest.TestCase):
         self.assertEquals(out_scale_factor, 1.0)
         self.assertEquals(out_shift_factor, -5.0)
 
+    def test_scale_both(self):
+        hab_range = range(5, 14)
+        self.do_test_scale_both(hab_range)
+
+    def test_scale_both_with_nan(self):
+        hab_range = list(range(5, 14))
+        hab_range[6] = np.nan
+        hab_range[7] = np.nan
+        self.assertRaises(RuntimeError, self.do_test_scale_both, hab_range)
+
+
 class TestErrorTransferFromModelToData(unittest.TestCase):
     def _createWorkspace(self, x1, y1, err1, x2, y2, err2):
         create_alg = AlgorithmManager.create('CreateWorkspace')
diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/SANSStitchTest.py b/Framework/PythonInterface/test/python/plugins/algorithms/SANSStitchTest.py
index 19a7b41c6b4259060acde99610d735ff4a4fddfa..2166df92d96a039ea20c1c13ba0e4709df305df8 100644
--- a/Framework/PythonInterface/test/python/plugins/algorithms/SANSStitchTest.py
+++ b/Framework/PythonInterface/test/python/plugins/algorithms/SANSStitchTest.py
@@ -6,6 +6,7 @@ import numpy as np
 
 from SANSStitch import QErrorCorrectionForMergedWorkspaces
 
+
 class SANSStitchTest(unittest.TestCase):
     def test_initalize(self):
         alg = AlgorithmManager.create('SANSStitch')
@@ -50,7 +51,7 @@ class SANSStitchTest(unittest.TestCase):
         errors = alg.validateInputs()
         self.assertTrue('ScaleFactor' in errors)
 
-    def test_workspace_entries_must_be_q1d(self):
+    def test_workspace_entries_must_be_q1d_if_fitting_is_enabled(self):
         # create an input workspace that has multiple spectra
         create_alg = AlgorithmManager.create('CreateWorkspace')
         create_alg.setChild(True)
@@ -107,7 +108,6 @@ class SANSStitchTest(unittest.TestCase):
         self.assertTrue('HABNormCan' in errors)
         self.assertTrue('LABNormCan' in errors)
 
-
     def test_stitch_2d_restricted_to_none(self):
         # create an input workspace that has multiple spectra
         create_alg = AlgorithmManager.create('CreateWorkspace')
@@ -162,7 +162,6 @@ class SANSStitchTest(unittest.TestCase):
         errors = alg.validateInputs()
         self.assertEqual(0, len(errors))
 
-
     def test_scale_none(self):
         create_alg = AlgorithmManager.create('CreateWorkspace')
         create_alg.setChild(True)
@@ -230,8 +229,6 @@ class SANSStitchTest(unittest.TestCase):
         # This would throw at the point of fitting in NaNs or infs where present
         alg.execute()
 
-
-
     def test_scale_none_with_can(self):
         create_alg = AlgorithmManager.create('CreateWorkspace')
         create_alg.setChild(True)
@@ -369,7 +366,6 @@ class SANSStitchTest(unittest.TestCase):
         self.assertTrue(all(map(lambda element: element in y_array, expected_y_array)),
                         msg='All data should be scaled and shifted to the LAB scale=1 shift=-5')
 
-
     def test_scale_only_without_can(self):
         create_alg = AlgorithmManager.create('CreateWorkspace')
         create_alg.setChild(True)
@@ -387,7 +383,7 @@ class SANSStitchTest(unittest.TestCase):
         # LAB as linear function y=x+0
         create_alg.setProperty('DataY', range(0, 9))
         create_alg.execute()
-        lab_workspace= create_alg.getProperty('OutputWorkspace').value
+        lab_workspace = create_alg.getProperty('OutputWorkspace').value
 
         # FLAT NORM
         create_alg.setProperty('DataY', [1] * 9)
@@ -415,6 +411,67 @@ class SANSStitchTest(unittest.TestCase):
         self.assertTrue(all(map(lambda element: element in y_array, expected_y_array)),
                         msg='All data should be scaled and shifted to the LAB scale=1 shift=-5')
 
+    def test_that_can_merge_2D_reduction_when_fitting_set_to_none(self):
+        # create an input workspace that has multiple spectra
+        create_alg = AlgorithmManager.create('CreateWorkspace')
+        create_alg.setChild(True)
+        create_alg.initialize()
+        create_alg.setProperty('DataX', range(0, 2))
+        create_alg.setProperty('NSpec', 2)
+        create_alg.setProperty('UnitX', 'MomentumTransfer')
+        create_alg.setProperty('VerticalAxisUnit', 'MomentumTransfer')
+        create_alg.setProperty('VerticalAxisValues', range(0, 2))
+
+        # hab counts
+        create_alg.setProperty('DataY', [1, 1, 1, 1])
+        create_alg.setPropertyValue('OutputWorkspace', 'out_ws')
+        create_alg.execute()
+        hab_counts = create_alg.getProperty('OutputWorkspace').value
+
+        # hab norm
+        create_alg.setProperty('DataY', [2, 2, 2, 2])
+        create_alg.setPropertyValue('OutputWorkspace', 'out_ws')
+        create_alg.execute()
+        hab_norm = create_alg.getProperty('OutputWorkspace').value
+
+        # lab counts
+        create_alg.setProperty('DataY', [3, 3, 3, 3])
+        create_alg.setPropertyValue('OutputWorkspace', 'out_ws')
+        create_alg.execute()
+        lab_counts = create_alg.getProperty('OutputWorkspace').value
+
+        # lab norm
+        create_alg.setProperty('DataY', [4, 4, 4, 4])
+        create_alg.setPropertyValue('OutputWorkspace', 'out_ws')
+        create_alg.execute()
+        lab_norm = create_alg.getProperty('OutputWorkspace').value
+
+        # Basic algorithm setup
+        alg = AlgorithmManager.create('SANSStitch')
+        alg.setChild(True)
+        alg.initialize()
+        alg.setProperty('HABCountsSample', hab_counts)
+        alg.setProperty('LABCountsSample', lab_counts)
+        alg.setProperty('HABNormSample', hab_norm)
+        alg.setProperty('LABNormSample', lab_norm)
+        alg.setProperty('ProcessCan', False)
+        alg.setProperty('ShiftFactor', 0.0)
+        alg.setProperty('ScaleFactor', 1.0)
+        alg.setProperty('Mode', 'None')
+        alg.setProperty('OutputWorkspace', 'dummy_name')
+        errors = alg.validateInputs()
+        self.assertEqual(0, len(errors))
+
+        alg.execute()
+        out_ws = alg.getProperty('OutputWorkspace').value
+        self.assertTrue(isinstance(out_ws, MatrixWorkspace))
+        self.assertTrue(out_ws.getNumberHistograms() == 2)
+        expected_entries = (1. + 3.) /(2. + 4.)
+        delta = 1e-5
+        for index in range(0, 2):
+            for element in out_ws.dataY(index):
+                self.assertTrue(abs(expected_entries - element) < delta)
+
 
 class TestQErrorCorrectionForMergedWorkspaces(unittest.TestCase):
     def _provide_workspace_with_x_errors(self, workspace_name, use_xerror = True, nspec = 1,
diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/SaveVulcanGSSTest.py b/Framework/PythonInterface/test/python/plugins/algorithms/SaveVulcanGSSTest.py
index 4b1e4ec7d2bcf96f212e23979e1c9f496e6eec2b..2290a52b780fa0dd476f3d348b4525b7718250bd 100644
--- a/Framework/PythonInterface/test/python/plugins/algorithms/SaveVulcanGSSTest.py
+++ b/Framework/PythonInterface/test/python/plugins/algorithms/SaveVulcanGSSTest.py
@@ -43,6 +43,35 @@ class SaveVulcanGSSTest(unittest.TestCase):
 
         return
 
+    def test_saveGSS_no_binning(self):
+        """ Test to Save a GSAS file without rebin to Vdrive's standard binning
+        """
+        # Create a test data file and workspace
+        binfilename = "testbin.dat"
+        self._createBinFile(binfilename)
+
+        datawsname = "TestInputWorkspace"
+        self._createDataWorkspace(datawsname)
+
+        # Execute
+        alg_test = run_algorithm("SaveVulcanGSS", 
+                InputWorkspace = datawsname,
+                OutputWorkspace = datawsname+"_rebinned",
+                GSSFilename = "tempout.gda")
+
+        self.assertTrue(alg_test.isExecuted())
+
+        # Verify ....
+        outputws = AnalysisDataService.retrieve(datawsname+"_rebinned")
+        #self.assertEqual(4, tablews.rowCount())
+
+        # Delete the test hkl file
+        os.remove(binfilename)
+        AnalysisDataService.remove("InputWorkspace")
+        AnalysisDataService.remove(datawsname+"_rebinned")
+
+        return
+
     def _createBinFile(self, binfilename):
         """ Create a bin file
         """
diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/SetDetScaleTest.py b/Framework/PythonInterface/test/python/plugins/algorithms/SetDetScaleTest.py
index 8095afcc38e9eaa5640b26c568857dd537a7ffa6..37d1cb2e454b4c0924cff36ea7f69e35582426ea 100644
--- a/Framework/PythonInterface/test/python/plugins/algorithms/SetDetScaleTest.py
+++ b/Framework/PythonInterface/test/python/plugins/algorithms/SetDetScaleTest.py
@@ -1,6 +1,7 @@
 from __future__ import (absolute_import, division, print_function)
 
 import unittest
+import os
 from mantid.simpleapi import *
 from mantid.api import *
 
@@ -19,5 +20,26 @@ class SetDetScaleTest(unittest.TestCase):
         self.assertEqual(x, 1.0)
         self.assertEqual(y, 2.0)
 
+        # create file for test
+        filename = 'testDetScale.txt'
+        hklfile = open(filename, "w")
+        hklfile.write("  17  0.5\n")
+        hklfile.write("  49  1.5\n")
+        hklfile.close()
+
+        SetDetScale(Workspace=w, DetScaleFile=filename)
+        x = w.getInstrument().getNumberParameter("detScale17")[0]
+        y = w.getInstrument().getNumberParameter("detScale49")[0]
+        self.assertEqual(x, 0.5)
+        self.assertEqual(y, 1.5)
+        
+        # test both input
+        SetDetScale(Workspace=w, DetScaleList='17:1.0,49:2.0', DetScaleFile=filename)
+        x = w.getInstrument().getNumberParameter("detScale17")[0]
+        y = w.getInstrument().getNumberParameter("detScale49")[0]
+        self.assertEqual(x, 1.0)
+        self.assertEqual(y, 2.0)
+        os.remove(filename)
+
 if __name__ == '__main__':
     unittest.main()
diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/SimulatedDensityOfStatesTest.py b/Framework/PythonInterface/test/python/plugins/algorithms/SimulatedDensityOfStatesTest.py
index 65891f5b5bd18948069a88e819c3a7b4657106d7..19f35c449d1e3416f040388d407f3f3765bb9c67 100644
--- a/Framework/PythonInterface/test/python/plugins/algorithms/SimulatedDensityOfStatesTest.py
+++ b/Framework/PythonInterface/test/python/plugins/algorithms/SimulatedDensityOfStatesTest.py
@@ -326,7 +326,7 @@ def _perform_group_name_search(wks_group, name_to_find):
     """
 
     for workspace in wks_group:
-        if workspace.getName() == name_to_find:
+        if workspace.name() == name_to_find:
             return workspace
 
 if __name__=="__main__":
diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/SofQWMomentsScanTest.py b/Framework/PythonInterface/test/python/plugins/algorithms/SofQWMomentsScanTest.py
new file mode 100644
index 0000000000000000000000000000000000000000..f7fcae343d1f01d17e2c9240f96abc9590454c9e
--- /dev/null
+++ b/Framework/PythonInterface/test/python/plugins/algorithms/SofQWMomentsScanTest.py
@@ -0,0 +1,29 @@
+import unittest
+from mantid.simpleapi import *
+from mantid import mtd
+
+
+class SofQWMomentsScanTest(unittest.TestCase):
+
+    def test_sqw_moments_scan(self):
+        SofQWMomentsScan(InputFiles='OSIRIS100320', Instrument='OSIRIS', Analyser='graphite', Reflection='002',
+                                        SpectraRange='963,1004', QRange='0,0.1,2', EnergyRange='-0.4,0.01,0.4')
+
+        sqw = mtd['Sqw'][0]
+        self.assertEqual(sqw.getNumberHistograms(), 20)
+        self.assertEqual(sqw.blocksize(), 80)
+
+    def test_multiple_scan(self):
+        SofQWMomentsScan(InputFiles='OSIRIS100320, OSIRIS100321', Instrument='OSIRIS', Analyser='graphite', Reflection='002',
+                         SpectraRange='963,1004', QRange='0,0.1,2', EnergyRange='-0.4,0.01,0.4')
+
+    def tearDown(self):
+        """
+        Remove workspaces from ADS.
+        """
+
+        DeleteWorkspace(mtd['reduced'])
+        DeleteWorkspace(mtd['sqw'])
+
+if __name__ == "__main__":
+    unittest.main()
diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/SofQWMomentsTest.py b/Framework/PythonInterface/test/python/plugins/algorithms/SofQWMomentsTest.py
index e7ad26d2a5509dbb771310fceaf9a4d3d62d625b..0f749e03ff3c834ce2a87918de82aa58d7b6f991 100644
--- a/Framework/PythonInterface/test/python/plugins/algorithms/SofQWMomentsTest.py
+++ b/Framework/PythonInterface/test/python/plugins/algorithms/SofQWMomentsTest.py
@@ -23,13 +23,10 @@ class SofQWMomentsTest(unittest.TestCase):
         ws = SofQW(ws, '0.4, 0.1, 1.8', EMode='Indirect', EFixed='1.845')
         ws = SofQWMoments(ws)
 
-        workspaces = ws.getNames()
-        self.assertEquals(len(workspaces), 4)
+        nHists = ws.getNumberHistograms()
+        self.assertEquals(nHists, 5)
 
-        for wsname in workspaces:
-            ws = mtd[wsname]
-            self.assertEquals(ws.getNumberHistograms(), 1)
-            self.assertEquals(ws.blocksize(), 14)
+        self.assertEquals(ws.blocksize(), 14)
 
 if __name__=="__main__":
     unittest.main()
diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/TOSCABankCorrectionTest.py b/Framework/PythonInterface/test/python/plugins/algorithms/TOSCABankCorrectionTest.py
index 0200db03404bbe9aa5dca72e758bd0e47af4ebf3..a445a4efbed93a7264e1d05ec884941238b49f7a 100644
--- a/Framework/PythonInterface/test/python/plugins/algorithms/TOSCABankCorrectionTest.py
+++ b/Framework/PythonInterface/test/python/plugins/algorithms/TOSCABankCorrectionTest.py
@@ -34,9 +34,9 @@ class TOSCABankCorrectionTest(unittest.TestCase):
         corrected_reduction, peak_position, scale_factor_1, scale_factor_2 = \
           TOSCABankCorrection(InputWorkspace=self._original)
 
-        self.assertAlmostEqual(peak_position, 1077.47222328)
-        self.assertAlmostEqual(scale_factor_1, 1.0059271)
-        self.assertAlmostEqual(scale_factor_2, 0.9941423)
+        self.assertAlmostEqual(peak_position, 1079.84991188)
+        self.assertAlmostEqual(scale_factor_1, 1.0060389)
+        self.assertAlmostEqual(scale_factor_2, 0.9940331)
 
 
     def test_automatic_peak_in_range(self):
@@ -48,9 +48,9 @@ class TOSCABankCorrectionTest(unittest.TestCase):
           TOSCABankCorrection(InputWorkspace=self._original,
                               SearchRange=[200, 800])
 
-        self.assertAlmostEqual(peak_position, 713.20080359)
-        self.assertAlmostEqual(scale_factor_1, 1.006076146)
-        self.assertAlmostEqual(scale_factor_2, 0.993996806)
+        self.assertAlmostEqual(peak_position, 714.008962427)
+        self.assertAlmostEqual(scale_factor_1, 1.004949468)
+        self.assertAlmostEqual(scale_factor_2, 0.995099045)
 
 
     def test_manual_peak_selection(self):
@@ -62,9 +62,9 @@ class TOSCABankCorrectionTest(unittest.TestCase):
           TOSCABankCorrection(InputWorkspace=self._original,
                               PeakPosition='715')
 
-        self.assertAlmostEqual(peak_position, 713.4430671)
-        self.assertAlmostEqual(scale_factor_1, 1.00611439)
-        self.assertAlmostEqual(scale_factor_2, 0.99395947)
+        self.assertAlmostEqual(peak_position, 714.29114157)
+        self.assertAlmostEqual(scale_factor_1, 1.00491105)
+        self.assertAlmostEqual(scale_factor_2, 0.99513671)
 
 
     def test_manual_peak_not_found(self):
diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/VesuvioDiffractionReductionTest.py b/Framework/PythonInterface/test/python/plugins/algorithms/VesuvioDiffractionReductionTest.py
index f58198afe6c65875c0ecaa1d491ce7bd941581ed..ac9f1751be6f8221e30df813c09695ce83240f39 100644
--- a/Framework/PythonInterface/test/python/plugins/algorithms/VesuvioDiffractionReductionTest.py
+++ b/Framework/PythonInterface/test/python/plugins/algorithms/VesuvioDiffractionReductionTest.py
@@ -13,7 +13,7 @@ class VesuvioDiffractionReductionTest(unittest.TestCase):
         Sanity test to ensure the most basic reduction actually completes.
         """
 
-        wks = VesuvioDiffractionReduction(InputFiles=['EVS15289.raw'],
+        wks = VesuvioDiffractionReduction(InputFiles=['15289'],
                                       InstrumentParFIle='IP0005.dat')
 
         self.assertTrue(isinstance(wks, WorkspaceGroup), 'Result workspace should be a workspace group.')
@@ -30,7 +30,7 @@ class VesuvioDiffractionReductionTest(unittest.TestCase):
         Test setting individual grouping, one spectrum per detector.
         """
 
-        wks = VesuvioDiffractionReduction(InputFiles=['EVS15289.raw'],
+        wks = VesuvioDiffractionReduction(InputFiles=['15289'],
                                       GroupingPolicy='Individual',
                                       InstrumentParFIle='IP0005.dat')
 
diff --git a/Framework/PythonInterface/test/testhelpers/WorkspaceCreationHelperModule.cpp b/Framework/PythonInterface/test/testhelpers/WorkspaceCreationHelperModule.cpp
index 88d084d250d3ac088a667713e15cda63c73c97c2..7b7a6953d819ad4cc4f707b118e72e6638035a1c 100644
--- a/Framework/PythonInterface/test/testhelpers/WorkspaceCreationHelperModule.cpp
+++ b/Framework/PythonInterface/test/testhelpers/WorkspaceCreationHelperModule.cpp
@@ -66,9 +66,9 @@ BOOST_PYTHON_MODULE(WorkspaceCreationHelper) {
   //=================================== Event Workspaces
   //===================================
 
-  def("CreateEventWorkspace", (EventWorkspace_sptr (*)())CreateEventWorkspace,
+  def("createEventWorkspace", (EventWorkspace_sptr (*)())createEventWorkspace,
       return_value_policy<AsType<Workspace_sptr>>());
-  def("CreateEventWorkspace2", &CreateEventWorkspace2,
+  def("createEventWorkspace2", &createEventWorkspace2,
       return_value_policy<AsType<Workspace_sptr>>());
 
   //=================================== Peak Workspaces
diff --git a/Framework/RemoteAlgorithms/inc/MantidRemoteAlgorithms/AbortRemoteJob.h b/Framework/RemoteAlgorithms/inc/MantidRemoteAlgorithms/AbortRemoteJob.h
index b29855cca9b3f23f50ababad0eeee5e4a75bf004..1649fc0a178655f177cb862f9792ac40a75b494e 100644
--- a/Framework/RemoteAlgorithms/inc/MantidRemoteAlgorithms/AbortRemoteJob.h
+++ b/Framework/RemoteAlgorithms/inc/MantidRemoteAlgorithms/AbortRemoteJob.h
@@ -2,12 +2,17 @@
 #define ABORTREMOTEJOB_H_
 
 #include "MantidAPI/Algorithm.h"
+#include "MantidAPI/DeprecatedAlgorithm.h"
 
 namespace Mantid {
 namespace RemoteAlgorithms {
 
-class DLLExport AbortRemoteJob : public Mantid::API::Algorithm {
+class DLLExport AbortRemoteJob : public Mantid::API::Algorithm,
+                                 public API::DeprecatedAlgorithm {
 public:
+  /// Default constructor
+  AbortRemoteJob();
+
   /// Algorithm's name
   const std::string name() const override { return "AbortRemoteJob"; }
   /// Summary of algorithms purpose
diff --git a/Framework/RemoteAlgorithms/inc/MantidRemoteAlgorithms/Authenticate.h b/Framework/RemoteAlgorithms/inc/MantidRemoteAlgorithms/Authenticate.h
index 36214bd12c83e1b48005d33ec1e4fed9ba1b22b9..28a39de187a7e0b5e3c482a7d579f0f14b5643e3 100644
--- a/Framework/RemoteAlgorithms/inc/MantidRemoteAlgorithms/Authenticate.h
+++ b/Framework/RemoteAlgorithms/inc/MantidRemoteAlgorithms/Authenticate.h
@@ -2,6 +2,7 @@
 #define AUTHENTICATE_H_
 
 #include "MantidAPI/Algorithm.h"
+#include "MantidAPI/DeprecatedAlgorithm.h"
 
 namespace Mantid {
 namespace RemoteAlgorithms {
@@ -46,8 +47,12 @@ namespace RemoteAlgorithms {
     Code Documentation is available at: <http://doxygen.mantidproject.org>
     */
 
-class DLLExport Authenticate : public Mantid::API::Algorithm {
+class DLLExport Authenticate : public Mantid::API::Algorithm,
+                               public API::DeprecatedAlgorithm {
 public:
+  /// Default constructor
+  Authenticate();
+
   /// Algorithm's name
   const std::string name() const override { return "Authenticate"; }
   /// Summary of algorithms purpose
diff --git a/Framework/RemoteAlgorithms/inc/MantidRemoteAlgorithms/DownloadRemoteFile.h b/Framework/RemoteAlgorithms/inc/MantidRemoteAlgorithms/DownloadRemoteFile.h
index 5ec945e6ac14810e01977c705f4fe337783f2420..b0729796f47a00fd79df00f9faa65ed71075ba07 100644
--- a/Framework/RemoteAlgorithms/inc/MantidRemoteAlgorithms/DownloadRemoteFile.h
+++ b/Framework/RemoteAlgorithms/inc/MantidRemoteAlgorithms/DownloadRemoteFile.h
@@ -2,12 +2,17 @@
 #define DOWNLOADREMOTEFILE_H_
 
 #include "MantidAPI/Algorithm.h"
+#include "MantidAPI/DeprecatedAlgorithm.h"
 
 namespace Mantid {
 namespace RemoteAlgorithms {
 
-class DLLExport DownloadRemoteFile : public Mantid::API::Algorithm {
+class DLLExport DownloadRemoteFile : public Mantid::API::Algorithm,
+                                     public API::DeprecatedAlgorithm {
 public:
+  /// constructor
+  DownloadRemoteFile();
+
   /// Algorithm's name
   const std::string name() const override { return "DownloadRemoteFile"; }
   /// Summary of algorithms purpose
diff --git a/Framework/RemoteAlgorithms/inc/MantidRemoteAlgorithms/QueryAllRemoteJobs.h b/Framework/RemoteAlgorithms/inc/MantidRemoteAlgorithms/QueryAllRemoteJobs.h
index 9bbbde5a8e18a364cd4c03ba15fef4988a256627..12c93d12278d53ad3800342a7cf14338ec33885e 100644
--- a/Framework/RemoteAlgorithms/inc/MantidRemoteAlgorithms/QueryAllRemoteJobs.h
+++ b/Framework/RemoteAlgorithms/inc/MantidRemoteAlgorithms/QueryAllRemoteJobs.h
@@ -2,12 +2,17 @@
 #define QUERYALLREMOTEJOBS_H_
 
 #include "MantidAPI/Algorithm.h"
+#include "MantidAPI/DeprecatedAlgorithm.h"
 
 namespace Mantid {
 namespace RemoteAlgorithms {
 
-class DLLExport QueryAllRemoteJobs : public Mantid::API::Algorithm {
+class DLLExport QueryAllRemoteJobs : public Mantid::API::Algorithm,
+                                     public API::DeprecatedAlgorithm {
 public:
+  /// Constructor
+  QueryAllRemoteJobs() { this->useAlgorithm("QueryAllRemoteJobs", 2); }
+
   /// Algorithm's name
   const std::string name() const override { return "QueryAllRemoteJobs"; }
   /// Summary of algorithms purpose
diff --git a/Framework/RemoteAlgorithms/inc/MantidRemoteAlgorithms/QueryRemoteFile.h b/Framework/RemoteAlgorithms/inc/MantidRemoteAlgorithms/QueryRemoteFile.h
index 934ba5523da89ae45f3772a7970bcdbb802b9a7a..a1f3a79ae28da21868d5b9a26cb411c19ff60dc8 100644
--- a/Framework/RemoteAlgorithms/inc/MantidRemoteAlgorithms/QueryRemoteFile.h
+++ b/Framework/RemoteAlgorithms/inc/MantidRemoteAlgorithms/QueryRemoteFile.h
@@ -2,12 +2,17 @@
 #define QUERYREMOTEFILE_H_
 
 #include "MantidAPI/Algorithm.h"
+#include "MantidAPI/DeprecatedAlgorithm.h"
 
 namespace Mantid {
 namespace RemoteAlgorithms {
 
-class DLLExport QueryRemoteFile : public Mantid::API::Algorithm {
+class DLLExport QueryRemoteFile : public Mantid::API::Algorithm,
+                                  public API::DeprecatedAlgorithm {
 public:
+  /// Constructor
+  QueryRemoteFile() { this->useAlgorithm("QueryRemoteFile", 2); }
+
   /// Algorithm's name
   const std::string name() const override { return "QueryRemoteFile"; }
   /// Summary of algorithms purpose
diff --git a/Framework/RemoteAlgorithms/inc/MantidRemoteAlgorithms/QueryRemoteJob.h b/Framework/RemoteAlgorithms/inc/MantidRemoteAlgorithms/QueryRemoteJob.h
index 512f3779fcb5de1d19d42d4a013abdf111a3464c..a0fa1fd23e1856a36c367202c2c3602a71e0ddba 100644
--- a/Framework/RemoteAlgorithms/inc/MantidRemoteAlgorithms/QueryRemoteJob.h
+++ b/Framework/RemoteAlgorithms/inc/MantidRemoteAlgorithms/QueryRemoteJob.h
@@ -2,12 +2,17 @@
 #define QUERYREMOTEJOB_H_
 
 #include "MantidAPI/Algorithm.h"
+#include "MantidAPI/DeprecatedAlgorithm.h"
 
 namespace Mantid {
 namespace RemoteAlgorithms {
 
-class DLLExport QueryRemoteJob : public Mantid::API::Algorithm {
+class DLLExport QueryRemoteJob : public Mantid::API::Algorithm,
+                                 public API::DeprecatedAlgorithm {
 public:
+  /// Constructor
+  QueryRemoteJob() { this->useAlgorithm("QueryRemoteJob", 2); }
+
   /// Algorithm's name
   const std::string name() const override { return "QueryRemoteJob"; }
   /// Summary of algorithms purpose
diff --git a/Framework/RemoteAlgorithms/inc/MantidRemoteAlgorithms/StartRemoteTransaction.h b/Framework/RemoteAlgorithms/inc/MantidRemoteAlgorithms/StartRemoteTransaction.h
index d9fa5e7114572286d8ae87dc8da64f946941a103..617da32c37395daa9b89c561b0b5db4b49256bdf 100644
--- a/Framework/RemoteAlgorithms/inc/MantidRemoteAlgorithms/StartRemoteTransaction.h
+++ b/Framework/RemoteAlgorithms/inc/MantidRemoteAlgorithms/StartRemoteTransaction.h
@@ -2,12 +2,17 @@
 #define STARTREMOTETRANSACTION_H_
 
 #include "MantidAPI/Algorithm.h"
+#include "MantidAPI/DeprecatedAlgorithm.h"
 
 namespace Mantid {
 namespace RemoteAlgorithms {
 
-class DLLExport StartRemoteTransaction : public Mantid::API::Algorithm {
+class DLLExport StartRemoteTransaction : public Mantid::API::Algorithm,
+                                         public API::DeprecatedAlgorithm {
 public:
+  /// Constructor
+  StartRemoteTransaction() { this->useAlgorithm("StartRemoteTransaction", 2); }
+
   /// Algorithm's name
   const std::string name() const override { return "StartRemoteTransaction"; }
   /// Summary of algorithms purpose
diff --git a/Framework/RemoteAlgorithms/inc/MantidRemoteAlgorithms/StopRemoteTransaction.h b/Framework/RemoteAlgorithms/inc/MantidRemoteAlgorithms/StopRemoteTransaction.h
index 2880b63cd12e96ce8ede9c69faac3967564ea50c..4b0bc049300139a7dabc7ededa4c731b7b556c7b 100644
--- a/Framework/RemoteAlgorithms/inc/MantidRemoteAlgorithms/StopRemoteTransaction.h
+++ b/Framework/RemoteAlgorithms/inc/MantidRemoteAlgorithms/StopRemoteTransaction.h
@@ -2,12 +2,17 @@
 #define STOPREMOTETRANSACTION_H_
 
 #include "MantidAPI/Algorithm.h"
+#include "MantidAPI/DeprecatedAlgorithm.h"
 
 namespace Mantid {
 namespace RemoteAlgorithms {
 
-class DLLExport StopRemoteTransaction : public Mantid::API::Algorithm {
+class DLLExport StopRemoteTransaction : public Mantid::API::Algorithm,
+                                        public API::DeprecatedAlgorithm {
 public:
+  /// Constructor
+  StopRemoteTransaction() { this->useAlgorithm("StopRemoteTransaction", 2); }
+
   /// Algorithm's name
   const std::string name() const override { return "StopRemoteTransaction"; }
   /// Summary of algorithms purpose
diff --git a/Framework/RemoteAlgorithms/inc/MantidRemoteAlgorithms/SubmitRemoteJob.h b/Framework/RemoteAlgorithms/inc/MantidRemoteAlgorithms/SubmitRemoteJob.h
index fa885fa430bd3a03e82980e287a7039e3f7f7de1..f68fc274de37b820a3a9b166dc4ac08c3f8aa067 100644
--- a/Framework/RemoteAlgorithms/inc/MantidRemoteAlgorithms/SubmitRemoteJob.h
+++ b/Framework/RemoteAlgorithms/inc/MantidRemoteAlgorithms/SubmitRemoteJob.h
@@ -2,6 +2,7 @@
 #define SUBMITREMOTEJOB_H_
 
 #include "MantidAPI/Algorithm.h"
+#include "MantidAPI/DeprecatedAlgorithm.h"
 
 namespace Mantid {
 namespace RemoteAlgorithms {
@@ -54,8 +55,12 @@ namespace RemoteAlgorithms {
     Code Documentation is available at: <http://doxygen.mantidproject.org>
     */
 
-class DLLExport SubmitRemoteJob : public Mantid::API::Algorithm {
+class DLLExport SubmitRemoteJob : public Mantid::API::Algorithm,
+                                  public API::DeprecatedAlgorithm {
 public:
+  /// Constructor
+  SubmitRemoteJob() { this->useAlgorithm("SubmitRemoteJob", 2); }
+
   /// Algorithm's name
   const std::string name() const override { return "SubmitRemoteJob"; }
   /// Summary of algorithms purpose
diff --git a/Framework/RemoteAlgorithms/inc/MantidRemoteAlgorithms/UploadRemoteFile.h b/Framework/RemoteAlgorithms/inc/MantidRemoteAlgorithms/UploadRemoteFile.h
index 715ab726a8fbed248228afc90c1a0132e3598cca..aad5a199479e2eacffdc3e2370343d5f2cf7deba 100644
--- a/Framework/RemoteAlgorithms/inc/MantidRemoteAlgorithms/UploadRemoteFile.h
+++ b/Framework/RemoteAlgorithms/inc/MantidRemoteAlgorithms/UploadRemoteFile.h
@@ -2,6 +2,8 @@
 #define UPLOADREMOTEFILE_H_
 
 #include "MantidAPI/Algorithm.h"
+#include "MantidAPI/DeprecatedAlgorithm.h"
+
 namespace Mantid {
 namespace RemoteAlgorithms {
 /*** Upload a file to a remote compute resource
@@ -49,10 +51,15 @@ namespace RemoteAlgorithms {
     Code Documentation is available at: <http://doxygen.mantidproject.org>
     */
 
-class DLLExport UploadRemoteFile : public API::Algorithm {
+class DLLExport UploadRemoteFile : public API::Algorithm,
+                                   public API::DeprecatedAlgorithm {
 public:
+  /// Constructor
+  UploadRemoteFile() { this->useAlgorithm("UploadRemoteFile", 2); }
+
   /// Algorithm's name
   const std::string name() const override { return "UploadRemoteFile"; }
+
   /// Summary of algorithms purpose
   const std::string summary() const override {
     return "Uploads a file to the specified compute resource.";
diff --git a/Framework/RemoteAlgorithms/src/AbortRemoteJob.cpp b/Framework/RemoteAlgorithms/src/AbortRemoteJob.cpp
index 22b798d54d3fa5f80caf0a0e2d7c950cc8b16efb..4f6b07e27460ba0d07a887f7a587a8ca7937545d 100644
--- a/Framework/RemoteAlgorithms/src/AbortRemoteJob.cpp
+++ b/Framework/RemoteAlgorithms/src/AbortRemoteJob.cpp
@@ -1,4 +1,5 @@
 #include "MantidRemoteAlgorithms/AbortRemoteJob.h"
+#include "MantidKernel/ConfigService.h"
 #include "MantidKernel/MandatoryValidator.h"
 #include "MantidKernel/NullValidator.h"
 #include "MantidKernel/FacilityInfo.h"
@@ -19,6 +20,9 @@ using namespace Mantid::API;
 
 // A reference to the logger is provided by the base class, it is called g_log.
 
+/// Empty constructor
+AbortRemoteJob::AbortRemoteJob() { this->useAlgorithm("AbortRemoteJob", 2); }
+
 void AbortRemoteJob::init() {
   // Unlike most algorithms, this one doesn't deal with workspaces....
 
diff --git a/Framework/RemoteAlgorithms/src/AbortRemoteJob2.cpp b/Framework/RemoteAlgorithms/src/AbortRemoteJob2.cpp
index 21495674d8ccdbc83ed7f65195cf77dd74eb1a79..b6db986ecc744fa525d812addd74e16980190718 100644
--- a/Framework/RemoteAlgorithms/src/AbortRemoteJob2.cpp
+++ b/Framework/RemoteAlgorithms/src/AbortRemoteJob2.cpp
@@ -1,4 +1,5 @@
 #include "MantidAPI/RemoteJobManagerFactory.h"
+#include "MantidKernel/ConfigService.h"
 #include "MantidKernel/FacilityInfo.h"
 #include "MantidKernel/ListValidator.h"
 #include "MantidKernel/MandatoryValidator.h"
diff --git a/Framework/RemoteAlgorithms/src/Authenticate.cpp b/Framework/RemoteAlgorithms/src/Authenticate.cpp
index b02d1f1a5ba497093d9d34538541d8c16079a5b1..30b203e830f41fccb3f053c3afcb9ab7853d9687 100644
--- a/Framework/RemoteAlgorithms/src/Authenticate.cpp
+++ b/Framework/RemoteAlgorithms/src/Authenticate.cpp
@@ -1,4 +1,5 @@
 #include "MantidRemoteAlgorithms/Authenticate.h"
+#include "MantidKernel/ConfigService.h"
 #include "MantidKernel/MandatoryValidator.h"
 #include "MantidKernel/FacilityInfo.h"
 #include "MantidKernel/Exception.h"
@@ -23,6 +24,8 @@ using namespace Mantid::Kernel;
 
 // A reference to the logger is provided by the base class, it is called g_log.
 
+Authenticate::Authenticate() { this->useAlgorithm("Authenticate", 2); }
+
 void Authenticate::init() {
   // Unlike most algorithms, this wone doesn't deal with workspaces....
 
diff --git a/Framework/RemoteAlgorithms/src/Authenticate2.cpp b/Framework/RemoteAlgorithms/src/Authenticate2.cpp
index 7dffd71f3e2dd4526155a10de7304c4f32d28b2d..70ae5c13fe557e333bb9cf9472380a6af41fa850 100644
--- a/Framework/RemoteAlgorithms/src/Authenticate2.cpp
+++ b/Framework/RemoteAlgorithms/src/Authenticate2.cpp
@@ -1,4 +1,5 @@
 #include "MantidAPI/RemoteJobManagerFactory.h"
+#include "MantidKernel/ConfigService.h"
 #include "MantidKernel/FacilityInfo.h"
 #include "MantidKernel/ListValidator.h"
 #include "MantidKernel/MandatoryValidator.h"
diff --git a/Framework/RemoteAlgorithms/src/DownloadRemoteFile.cpp b/Framework/RemoteAlgorithms/src/DownloadRemoteFile.cpp
index 2ba710096fb7ac1278ad0d04dada1cdfce26b8a1..d40f8825c399c3892f806ca9f78d6846a00979cf 100644
--- a/Framework/RemoteAlgorithms/src/DownloadRemoteFile.cpp
+++ b/Framework/RemoteAlgorithms/src/DownloadRemoteFile.cpp
@@ -1,4 +1,5 @@
 #include "MantidRemoteAlgorithms/DownloadRemoteFile.h"
+#include "MantidKernel/ConfigService.h"
 #include "MantidKernel/MandatoryValidator.h"
 #include "MantidKernel/FacilityInfo.h"
 #include "MantidKernel/MaskedProperty.h"
@@ -21,6 +22,10 @@ using namespace Mantid::API;
 
 // A reference to the logger is provided by the base class, it is called g_log.
 
+DownloadRemoteFile::DownloadRemoteFile() {
+  this->useAlgorithm("DownloadRemoteFile", 2);
+}
+
 void DownloadRemoteFile::init() {
   // Unlike most algorithms, this one doesn't deal with workspaces....
 
diff --git a/Framework/RemoteAlgorithms/src/DownloadRemoteFile2.cpp b/Framework/RemoteAlgorithms/src/DownloadRemoteFile2.cpp
index 2ad5e560315e99fac8d9b820b6f359d61ba2a288..c62d6acf8b315d77ce3f7508912b089e8a2eeca1 100644
--- a/Framework/RemoteAlgorithms/src/DownloadRemoteFile2.cpp
+++ b/Framework/RemoteAlgorithms/src/DownloadRemoteFile2.cpp
@@ -1,4 +1,5 @@
 #include "MantidAPI/RemoteJobManagerFactory.h"
+#include "MantidKernel/ConfigService.h"
 #include "MantidKernel/MandatoryValidator.h"
 #include "MantidKernel/FacilityInfo.h"
 #include "MantidKernel/ListValidator.h"
diff --git a/Framework/RemoteAlgorithms/src/Logout2.cpp b/Framework/RemoteAlgorithms/src/Logout2.cpp
index d658077fd582eaabe03a6c02a4e6d9dbe33bacf3..186b01140ba6107230abae98614c8a54b1010eb6 100644
--- a/Framework/RemoteAlgorithms/src/Logout2.cpp
+++ b/Framework/RemoteAlgorithms/src/Logout2.cpp
@@ -1,4 +1,5 @@
 #include "MantidAPI/RemoteJobManagerFactory.h"
+#include "MantidKernel/ConfigService.h"
 #include "MantidKernel/FacilityInfo.h"
 #include "MantidKernel/ListValidator.h"
 #include "MantidKernel/MandatoryValidator.h"
diff --git a/Framework/RemoteAlgorithms/src/QueryAllRemoteJobs.cpp b/Framework/RemoteAlgorithms/src/QueryAllRemoteJobs.cpp
index 8b42ffa356d1dbce625638aeb0c72d484975d8cd..31add85d6c27f199b1983b9384629caf224e4042 100644
--- a/Framework/RemoteAlgorithms/src/QueryAllRemoteJobs.cpp
+++ b/Framework/RemoteAlgorithms/src/QueryAllRemoteJobs.cpp
@@ -1,4 +1,5 @@
 #include "MantidRemoteAlgorithms/QueryAllRemoteJobs.h"
+#include "MantidKernel/ConfigService.h"
 #include "MantidKernel/NullValidator.h"
 #include "MantidKernel/ArrayProperty.h"
 #include "MantidKernel/FacilityInfo.h"
diff --git a/Framework/RemoteAlgorithms/src/QueryAllRemoteJobs2.cpp b/Framework/RemoteAlgorithms/src/QueryAllRemoteJobs2.cpp
index 0f44b47bfa0c24fbfdb2f212d2852eca785d865a..fb98f50efb9f8b9565b3329c9b218bebd7e96c74 100644
--- a/Framework/RemoteAlgorithms/src/QueryAllRemoteJobs2.cpp
+++ b/Framework/RemoteAlgorithms/src/QueryAllRemoteJobs2.cpp
@@ -1,5 +1,6 @@
 #include "MantidAPI/RemoteJobManagerFactory.h"
 #include "MantidKernel/ArrayProperty.h"
+#include "MantidKernel/ConfigService.h"
 #include "MantidKernel/FacilityInfo.h"
 #include "MantidKernel/ListValidator.h"
 #include "MantidKernel/NullValidator.h"
diff --git a/Framework/RemoteAlgorithms/src/QueryRemoteFile.cpp b/Framework/RemoteAlgorithms/src/QueryRemoteFile.cpp
index bfee5091379de00936ea3de8e4403ab600cd9e77..2534932143d3b02198b292aa85c9356ef52902ed 100644
--- a/Framework/RemoteAlgorithms/src/QueryRemoteFile.cpp
+++ b/Framework/RemoteAlgorithms/src/QueryRemoteFile.cpp
@@ -1,4 +1,5 @@
 #include "MantidRemoteAlgorithms/QueryRemoteFile.h"
+#include "MantidKernel/ConfigService.h"
 #include "MantidKernel/MandatoryValidator.h"
 #include "MantidKernel/ArrayProperty.h"
 #include "MantidKernel/FacilityInfo.h"
diff --git a/Framework/RemoteAlgorithms/src/QueryRemoteFile2.cpp b/Framework/RemoteAlgorithms/src/QueryRemoteFile2.cpp
index 22517b7f0acab54c47c9a1f96e05aaef1b8184e4..a416b3676f66a79173fb8071120a8dc8792c192a 100644
--- a/Framework/RemoteAlgorithms/src/QueryRemoteFile2.cpp
+++ b/Framework/RemoteAlgorithms/src/QueryRemoteFile2.cpp
@@ -1,5 +1,6 @@
 #include "MantidAPI/RemoteJobManagerFactory.h"
 #include "MantidKernel/ArrayProperty.h"
+#include "MantidKernel/ConfigService.h"
 #include "MantidKernel/FacilityInfo.h"
 #include "MantidKernel/ListValidator.h"
 #include "MantidKernel/MandatoryValidator.h"
diff --git a/Framework/RemoteAlgorithms/src/QueryRemoteJob.cpp b/Framework/RemoteAlgorithms/src/QueryRemoteJob.cpp
index 29a8a3253cf11f1bbc4a7c0d5df6b78011a8d53b..1f0812c08885075f3f6561187ad5ec08cea20b4a 100644
--- a/Framework/RemoteAlgorithms/src/QueryRemoteJob.cpp
+++ b/Framework/RemoteAlgorithms/src/QueryRemoteJob.cpp
@@ -1,4 +1,5 @@
 #include "MantidRemoteAlgorithms/QueryRemoteJob.h"
+#include "MantidKernel/ConfigService.h"
 #include "MantidKernel/MandatoryValidator.h"
 #include "MantidKernel/NullValidator.h"
 #include "MantidKernel/FacilityInfo.h"
diff --git a/Framework/RemoteAlgorithms/src/QueryRemoteJob2.cpp b/Framework/RemoteAlgorithms/src/QueryRemoteJob2.cpp
index efb0fa30101bd1c1e383db3e3fcdee5080f725d8..d94a74ae2b13ca0a9c59f7a046a6450063bb5865 100644
--- a/Framework/RemoteAlgorithms/src/QueryRemoteJob2.cpp
+++ b/Framework/RemoteAlgorithms/src/QueryRemoteJob2.cpp
@@ -1,4 +1,5 @@
 #include "MantidAPI/RemoteJobManagerFactory.h"
+#include "MantidKernel/ConfigService.h"
 #include "MantidKernel/FacilityInfo.h"
 #include "MantidKernel/ListValidator.h"
 #include "MantidKernel/NullValidator.h"
diff --git a/Framework/RemoteAlgorithms/src/SCARFTomoReconstruction.cpp b/Framework/RemoteAlgorithms/src/SCARFTomoReconstruction.cpp
index 4b95f5de96ab2c5eaae91d49f66b3ce977df06e8..78c7e4df5728289b624e9083ad6aafb7137298d0 100644
--- a/Framework/RemoteAlgorithms/src/SCARFTomoReconstruction.cpp
+++ b/Framework/RemoteAlgorithms/src/SCARFTomoReconstruction.cpp
@@ -4,6 +4,7 @@
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidAPI/WorkspaceProperty.h"
 #include "MantidKernel/ArrayProperty.h"
+#include "MantidKernel/ConfigService.h"
 #include "MantidKernel/FacilityInfo.h"
 #include "MantidKernel/InternetHelper.h"
 #include "MantidKernel/ListValidator.h"
@@ -22,6 +23,8 @@
 #include <Poco/Net/HTTPRequest.h>
 #include <Poco/StreamCopier.h>
 
+#include <boost/algorithm/string/replace.hpp>
+
 namespace Mantid {
 namespace RemoteAlgorithms {
 
@@ -1348,12 +1351,11 @@ void SCARFTomoReconstruction::getOneJobFile(const std::string &jobId,
       {"Content-Type", "application/xml"},
       {"Cookie", token},
       {"Accept", m_acceptType}};
-  std::string body = remotePath;
   int code;
   std::stringstream ss;
   try {
-    code = doSendRequestGetResponse(httpsURL, ss, headers,
-                                    Poco::Net::HTTPRequest::HTTP_GET, body);
+    code = doSendRequestGetResponse(
+        httpsURL, ss, headers, Poco::Net::HTTPRequest::HTTP_GET, remotePath);
   } catch (Kernel::Exception::InternetError &ie) {
     throw std::runtime_error(
         "Error while sending HTTP request to download a file: " +
diff --git a/Framework/RemoteAlgorithms/src/SimpleJSON.cpp b/Framework/RemoteAlgorithms/src/SimpleJSON.cpp
index 717da9b0cc1be054b38639d0c049872f401e03c1..61cd6ece6193a85cff1347af1bc5bb873c7dd5df 100644
--- a/Framework/RemoteAlgorithms/src/SimpleJSON.cpp
+++ b/Framework/RemoteAlgorithms/src/SimpleJSON.cpp
@@ -662,11 +662,8 @@ string readUntilCloseChar(istream &istr) {
       throw JSONParseException(
           "Stream unexpectedly ended without a closing char.");
     }
-
-    if ((value.size() > 0) ||
-        (!isspace(
-             next))) // don't add white space to the start of the value string
-    {
+    if (!value.empty() || !isspace(next)) {
+      // don't add white space to the start of the value string
       value += next;
     }
     istr.get(); // consume the char from the stream
diff --git a/Framework/RemoteAlgorithms/src/StartRemoteTransaction.cpp b/Framework/RemoteAlgorithms/src/StartRemoteTransaction.cpp
index d806aaafc15397b9bbeb47c621f9533083bcf165..1aa30c27e69a6aee9c039caf2eb299797790965f 100644
--- a/Framework/RemoteAlgorithms/src/StartRemoteTransaction.cpp
+++ b/Framework/RemoteAlgorithms/src/StartRemoteTransaction.cpp
@@ -1,5 +1,6 @@
 #include "MantidRemoteAlgorithms/StartRemoteTransaction.h"
 #include "MantidRemoteAlgorithms/SimpleJSON.h"
+#include "MantidKernel/ConfigService.h"
 #include "MantidKernel/FacilityInfo.h"
 #include "MantidKernel/ListValidator.h"
 
diff --git a/Framework/RemoteAlgorithms/src/StartRemoteTransaction2.cpp b/Framework/RemoteAlgorithms/src/StartRemoteTransaction2.cpp
index 35ff73b6c8630488a6041126051dc178a58bab07..dc539883f27389a7372a021c3eba21a171a145ce 100644
--- a/Framework/RemoteAlgorithms/src/StartRemoteTransaction2.cpp
+++ b/Framework/RemoteAlgorithms/src/StartRemoteTransaction2.cpp
@@ -1,4 +1,5 @@
 #include "MantidAPI/RemoteJobManagerFactory.h"
+#include "MantidKernel/ConfigService.h"
 #include "MantidKernel/FacilityInfo.h"
 #include "MantidKernel/ListValidator.h"
 #include "MantidRemoteAlgorithms/StartRemoteTransaction2.h"
diff --git a/Framework/RemoteAlgorithms/src/StopRemoteTransaction.cpp b/Framework/RemoteAlgorithms/src/StopRemoteTransaction.cpp
index 1311ece17b59be4de5e2e5ad77bc076dd91891a2..2a67d8cfb9edc2478fa7697b358c96281eb65150 100644
--- a/Framework/RemoteAlgorithms/src/StopRemoteTransaction.cpp
+++ b/Framework/RemoteAlgorithms/src/StopRemoteTransaction.cpp
@@ -1,5 +1,6 @@
 #include "MantidRemoteAlgorithms/StopRemoteTransaction.h"
 #include "MantidRemoteAlgorithms/SimpleJSON.h"
+#include "MantidKernel/ConfigService.h"
 #include "MantidKernel/MandatoryValidator.h"
 #include "MantidKernel/FacilityInfo.h"
 #include "MantidKernel/ListValidator.h"
diff --git a/Framework/RemoteAlgorithms/src/StopRemoteTransaction2.cpp b/Framework/RemoteAlgorithms/src/StopRemoteTransaction2.cpp
index b64e27c911f90ab8b0cc711ca48b3157b6a8430b..48eadefe72497ad3a3c0f0f08997898b2bb6a58f 100644
--- a/Framework/RemoteAlgorithms/src/StopRemoteTransaction2.cpp
+++ b/Framework/RemoteAlgorithms/src/StopRemoteTransaction2.cpp
@@ -1,5 +1,6 @@
 #include "MantidAPI/RemoteJobManagerFactory.h"
 #include "MantidRemoteAlgorithms/SimpleJSON.h"
+#include "MantidKernel/ConfigService.h"
 #include "MantidKernel/MandatoryValidator.h"
 #include "MantidKernel/FacilityInfo.h"
 #include "MantidKernel/ListValidator.h"
diff --git a/Framework/RemoteAlgorithms/src/SubmitRemoteJob.cpp b/Framework/RemoteAlgorithms/src/SubmitRemoteJob.cpp
index a7611e27f9c7a180ee6b4aa79b778343e2683e78..ef2ad0b76641315d940630897d7ae9892035e9bb 100644
--- a/Framework/RemoteAlgorithms/src/SubmitRemoteJob.cpp
+++ b/Framework/RemoteAlgorithms/src/SubmitRemoteJob.cpp
@@ -1,5 +1,6 @@
 #include "MantidRemoteAlgorithms/SubmitRemoteJob.h"
 #include "MantidKernel/BoundedValidator.h"
+#include "MantidKernel/ConfigService.h"
 #include "MantidKernel/MandatoryValidator.h"
 #include "MantidKernel/FacilityInfo.h"
 #include "MantidKernel/Exception.h"
diff --git a/Framework/RemoteAlgorithms/src/SubmitRemoteJob2.cpp b/Framework/RemoteAlgorithms/src/SubmitRemoteJob2.cpp
index 0180d31f7197e73ff3217d83ad71029a99749c77..e8715d05976e5b7c31e1c13863de3b864ef1d1fd 100644
--- a/Framework/RemoteAlgorithms/src/SubmitRemoteJob2.cpp
+++ b/Framework/RemoteAlgorithms/src/SubmitRemoteJob2.cpp
@@ -1,5 +1,6 @@
 #include "MantidAPI/RemoteJobManagerFactory.h"
 #include "MantidKernel/BoundedValidator.h"
+#include "MantidKernel/ConfigService.h"
 #include "MantidKernel/MandatoryValidator.h"
 #include "MantidKernel/FacilityInfo.h"
 #include "MantidKernel/ListValidator.h"
diff --git a/Framework/RemoteAlgorithms/src/UploadRemoteFile.cpp b/Framework/RemoteAlgorithms/src/UploadRemoteFile.cpp
index c716a512c5f6c3334249985441e86b4803743fc3..f8e1e8d15b4d9e7f21d018ec638ffd7029a6f5be 100644
--- a/Framework/RemoteAlgorithms/src/UploadRemoteFile.cpp
+++ b/Framework/RemoteAlgorithms/src/UploadRemoteFile.cpp
@@ -1,4 +1,5 @@
 #include "MantidRemoteAlgorithms/UploadRemoteFile.h"
+#include "MantidKernel/ConfigService.h"
 #include "MantidKernel/MandatoryValidator.h"
 #include "MantidKernel/FacilityInfo.h"
 #include "MantidKernel/RemoteJobManager.h"
diff --git a/Framework/RemoteAlgorithms/src/UploadRemoteFile2.cpp b/Framework/RemoteAlgorithms/src/UploadRemoteFile2.cpp
index 6081847bb9ceb1fbc808869411501bae74bc2b8c..df3324377bfef0d686a0a1b9cd9f88b27fa015b6 100644
--- a/Framework/RemoteAlgorithms/src/UploadRemoteFile2.cpp
+++ b/Framework/RemoteAlgorithms/src/UploadRemoteFile2.cpp
@@ -1,4 +1,5 @@
 #include "MantidAPI/RemoteJobManagerFactory.h"
+#include "MantidKernel/ConfigService.h"
 #include "MantidKernel/FacilityInfo.h"
 #include "MantidKernel/ListValidator.h"
 #include "MantidKernel/MandatoryValidator.h"
diff --git a/Framework/RemoteAlgorithms/test/SCARFTomoReconstructionTest.h b/Framework/RemoteAlgorithms/test/SCARFTomoReconstructionTest.h
index 45c9c9a36cf44a6ce6aaf96b49c1329e6f675f10..207592a1dcd5007785c54d3115ba14262dd0dc78 100644
--- a/Framework/RemoteAlgorithms/test/SCARFTomoReconstructionTest.h
+++ b/Framework/RemoteAlgorithms/test/SCARFTomoReconstructionTest.h
@@ -4,6 +4,7 @@
 #include <cxxtest/TestSuite.h>
 
 #include "MantidAPI/ITableWorkspace.h"
+#include "MantidKernel/ConfigService.h"
 #include "MantidKernel/FacilityInfo.h"
 #include "MantidRemoteAlgorithms/SCARFTomoReconstruction.h"
 
diff --git a/Framework/RemoteJobManagers/src/LSFJobManager.cpp b/Framework/RemoteJobManagers/src/LSFJobManager.cpp
index d2b137a95de34929eb619ea5d018f4b343584063..cbedc1178227127ed7743d2b046e89e471345128 100644
--- a/Framework/RemoteJobManagers/src/LSFJobManager.cpp
+++ b/Framework/RemoteJobManagers/src/LSFJobManager.cpp
@@ -1125,12 +1125,11 @@ void LSFJobManager::getOneJobFile(const std::string &jobId,
   const Poco::URI fullURL = makeFullURI(t.m_url, g_downloadOneBasePath, jobId);
   const StringToStringMap headers =
       makeHeaders(std::string("application/xml"), token, g_acceptType);
-  const std::string body = remotePath;
   int code = 0;
   std::stringstream ss;
   try {
-    code = doSendRequestGetResponse(fullURL, ss, headers,
-                                    Poco::Net::HTTPRequest::HTTP_GET, body);
+    code = doSendRequestGetResponse(
+        fullURL, ss, headers, Poco::Net::HTTPRequest::HTTP_GET, remotePath);
   } catch (Kernel::Exception::InternetError &ie) {
     throw std::runtime_error(
         "Error while sending HTTP request to download a file: " +
diff --git a/Framework/RemoteJobManagers/src/MantidWebServiceAPIHelper.cpp b/Framework/RemoteJobManagers/src/MantidWebServiceAPIHelper.cpp
index 48a4c64186a2109292f7071e59d8b4025bf1130f..cc887c1618b4b161f70e12c79b31ef8e060e487d 100644
--- a/Framework/RemoteJobManagers/src/MantidWebServiceAPIHelper.cpp
+++ b/Framework/RemoteJobManagers/src/MantidWebServiceAPIHelper.cpp
@@ -211,7 +211,7 @@ void MantidWebServiceAPIHelper::initHTTPRequest(Poco::Net::HTTPRequest &req,
   path += extraPath;
 
   uri.setPath(path);
-  if (method == Poco::Net::HTTPRequest::HTTP_GET && queryString.size() > 0) {
+  if (method == Poco::Net::HTTPRequest::HTTP_GET && !queryString.empty()) {
     uri.setQuery(queryString);
   }
 
diff --git a/Framework/RemoteJobManagers/src/MantidWebServiceAPIJobManager.cpp b/Framework/RemoteJobManagers/src/MantidWebServiceAPIJobManager.cpp
index ba53b73cd36280c297152f15dd2cf9273d9f6487..beb5de2fe487c257d36d7f2de6d0dc2562670300 100644
--- a/Framework/RemoteJobManagers/src/MantidWebServiceAPIJobManager.cpp
+++ b/Framework/RemoteJobManagers/src/MantidWebServiceAPIJobManager.cpp
@@ -369,8 +369,7 @@ std::string MantidWebServiceAPIJobManager::startRemoteTransaction() {
  * (remote) compute resource.
  */
 void MantidWebServiceAPIJobManager::stopRemoteTransaction(
-    const std::string &transactionID) {
-  std::string transId = transactionID;
+    const std::string &transId) {
   std::istream &respStream =
       httpGet("/transaction", std::string("Action=Stop&TransID=") + transId);
 
@@ -420,9 +419,8 @@ std::string MantidWebServiceAPIJobManager::submitRemoteJob(
   postData[runnable] = param;
 
   // Job name is optional
-  std::string jobName = taskName;
-  if (jobName.length() > 0) {
-    postData["JobName"] = jobName;
+  if (taskName.length() > 0) {
+    postData["JobName"] = taskName;
   }
 
   std::istream &respStream = httpPost("/submit", postData);
diff --git a/Framework/RemoteJobManagers/src/SimpleJSON.cpp b/Framework/RemoteJobManagers/src/SimpleJSON.cpp
index 0e422f961ee2754ca843962c183b1b38000f17a6..01c76fd203ed15331b7bed8a90e2015a679ac060 100644
--- a/Framework/RemoteJobManagers/src/SimpleJSON.cpp
+++ b/Framework/RemoteJobManagers/src/SimpleJSON.cpp
@@ -663,10 +663,8 @@ string readUntilCloseChar(istream &istr) {
           "Stream unexpectedly ended without a closing char.");
     }
 
-    if ((value.size() > 0) ||
-        (!isspace(
-             next))) // don't add white space to the start of the value string
-    {
+    if (!value.empty() || !isspace(next)) {
+      // don't add white space to the start of the value string
       value += next;
     }
     istr.get(); // consume the char from the stream
diff --git a/Framework/SINQ/inc/MantidSINQ/PoldiFitPeaks1D2.h b/Framework/SINQ/inc/MantidSINQ/PoldiFitPeaks1D2.h
index f8587bd7d3b894e5b24f813ed1078d5e30df9138..f9dc4155e5d1c9ba448bdf111f7c208756a17ffc 100644
--- a/Framework/SINQ/inc/MantidSINQ/PoldiFitPeaks1D2.h
+++ b/Framework/SINQ/inc/MantidSINQ/PoldiFitPeaks1D2.h
@@ -10,6 +10,7 @@
 #include "MantidDataObjects/Workspace2D.h"
 #include "MantidDataObjects/TableWorkspace.h"
 #include "MantidAPI/TableRow.h"
+#include "MantidAPI/WorkspaceGroup_fwd.h"
 
 namespace Mantid {
 namespace Poldi {
diff --git a/Framework/SINQ/inc/MantidSINQ/PoldiUtilities/PoldiDeadWireDecorator.h b/Framework/SINQ/inc/MantidSINQ/PoldiUtilities/PoldiDeadWireDecorator.h
index 34593fc70c2a18da4dd438b3f3abca92d5c16332..4c6abeb74f98b067b38179c6b973e0e57ccdae3c 100644
--- a/Framework/SINQ/inc/MantidSINQ/PoldiUtilities/PoldiDeadWireDecorator.h
+++ b/Framework/SINQ/inc/MantidSINQ/PoldiUtilities/PoldiDeadWireDecorator.h
@@ -3,12 +3,13 @@
 
 #include "MantidKernel/System.h"
 
-#include "MantidGeometry/Instrument.h"
-
 #include "MantidSINQ/DllConfig.h"
 #include "MantidSINQ/PoldiUtilities/PoldiDetectorDecorator.h"
 
 namespace Mantid {
+namespace API {
+class DetectorInfo;
+}
 namespace Poldi {
 
 /** PoldiDeadWireDecorator :
@@ -47,7 +48,7 @@ public:
   PoldiDeadWireDecorator(std::set<int> deadWires,
                          boost::shared_ptr<PoldiAbstractDetector> detector =
                              boost::shared_ptr<PoldiAbstractDetector>());
-  PoldiDeadWireDecorator(Geometry::Instrument_const_sptr poldiInstrument,
+  PoldiDeadWireDecorator(const API::DetectorInfo &poldiDetectorInfo,
                          boost::shared_ptr<PoldiAbstractDetector> detector =
                              boost::shared_ptr<PoldiAbstractDetector>());
 
@@ -61,8 +62,6 @@ protected:
   void detectorSetHook() override;
   std::vector<int> getGoodElements(std::vector<int> rawElements);
 
-  static bool detectorIsNotMasked(Geometry::Instrument_const_sptr instrument,
-                                  detid_t detectorId);
   bool isDeadElement(int index);
 
   std::set<int> m_deadWireSet;
diff --git a/Framework/SINQ/inc/MantidSINQ/PoldiUtilities/UncertainValueIO.h b/Framework/SINQ/inc/MantidSINQ/PoldiUtilities/UncertainValueIO.h
index 7b049d62bfa1853b344bdde96953a175a30039c5..86e4431667632c06c404df078de5c7791b47a6eb 100644
--- a/Framework/SINQ/inc/MantidSINQ/PoldiUtilities/UncertainValueIO.h
+++ b/Framework/SINQ/inc/MantidSINQ/PoldiUtilities/UncertainValueIO.h
@@ -50,7 +50,7 @@ public:
   }
 
   static UncertainValue fromString(const std::string &uncertainValueString) {
-    if (uncertainValueString.size() == 0) {
+    if (uncertainValueString.empty()) {
       return UncertainValue();
     }
 
diff --git a/Framework/SINQ/inc/MantidSINQ/SINQTranspose3D.h b/Framework/SINQ/inc/MantidSINQ/SINQTranspose3D.h
index 15dd0a61632420e8855ef96d887966c5bb7af291..52d9b8611a60b992c547b6fb3254059e52e8d34b 100644
--- a/Framework/SINQ/inc/MantidSINQ/SINQTranspose3D.h
+++ b/Framework/SINQ/inc/MantidSINQ/SINQTranspose3D.h
@@ -37,10 +37,15 @@
 
 #include "MantidSINQ/DllConfig.h"
 #include "MantidAPI/Algorithm.h"
+#include "MantidAPI/DeprecatedAlgorithm.h"
 #include "MantidAPI/IMDHistoWorkspace_fwd.h"
 
-class MANTID_SINQ_DLL SINQTranspose3D : public Mantid::API::Algorithm {
+class MANTID_SINQ_DLL SINQTranspose3D
+    : public Mantid::API::Algorithm,
+      public Mantid::API::DeprecatedAlgorithm {
 public:
+  /// Constructor
+  SINQTranspose3D() { this->useAlgorithm("TransposeMD", 1); }
   /// Algorithm's name
   const std::string name() const override { return "Transpose3D"; }
   /// Summary of algorithms purpose
diff --git a/Framework/SINQ/src/MDHistoToWorkspace2D.cpp b/Framework/SINQ/src/MDHistoToWorkspace2D.cpp
index ab000d19c5432b076990d9b1199dbbcd43392fbf..9a0d1068c8512d4c8a2658c2bb720aaaa2430bbd 100644
--- a/Framework/SINQ/src/MDHistoToWorkspace2D.cpp
+++ b/Framework/SINQ/src/MDHistoToWorkspace2D.cpp
@@ -13,8 +13,10 @@
 
 #include "MantidAPI/IMDHistoWorkspace.h"
 #include "MantidAPI/WorkspaceFactory.h"
+#include "MantidGeometry/MDGeometry/IMDDimension.h"
 
 #include <cmath>
+#include <iostream>
 
 // Register the algorithm into the AlgorithmFactory
 DECLARE_ALGORITHM(MDHistoToWorkspace2D)
diff --git a/Framework/SINQ/src/PoldiAnalyseResiduals.cpp b/Framework/SINQ/src/PoldiAnalyseResiduals.cpp
index 70670b14988ec38e333a23a88497ff79c2808d73..50f3f6143d8109f9afd6453f35601805df7ff34e 100644
--- a/Framework/SINQ/src/PoldiAnalyseResiduals.cpp
+++ b/Framework/SINQ/src/PoldiAnalyseResiduals.cpp
@@ -199,7 +199,7 @@ void PoldiAnalyseResiduals::exec() {
       boost::make_shared<PoldiInstrumentAdapter>(measured);
   // Dead wires need to be taken into account
   PoldiAbstractDetector_sptr deadWireDetector =
-      boost::make_shared<PoldiDeadWireDecorator>(measured->getInstrument(),
+      boost::make_shared<PoldiDeadWireDecorator>(measured->detectorInfo(),
                                                  poldiInstrument->detector());
 
   // Since the valid workspace indices are required for some calculations, we
diff --git a/Framework/SINQ/src/PoldiAutoCorrelation5.cpp b/Framework/SINQ/src/PoldiAutoCorrelation5.cpp
index c43f02d4c9c9802e03e8e821bdf7ee86e2e910c7..ba2c2c4954343cb8609384764f3fefc7087cab22 100644
--- a/Framework/SINQ/src/PoldiAutoCorrelation5.cpp
+++ b/Framework/SINQ/src/PoldiAutoCorrelation5.cpp
@@ -83,7 +83,7 @@ void PoldiAutoCorrelation5::exec() {
 
   PoldiAbstractDetector_sptr detector = instrumentAdapter.detector();
   boost::shared_ptr<PoldiDeadWireDecorator> cleanDetector(
-      new PoldiDeadWireDecorator(localWorkspace->getInstrument(), detector));
+      new PoldiDeadWireDecorator(localWorkspace->detectorInfo(), detector));
 
   // log configuration information
   logConfigurationInformation(cleanDetector, chopper);
diff --git a/Framework/SINQ/src/PoldiFitPeaks2D.cpp b/Framework/SINQ/src/PoldiFitPeaks2D.cpp
index 6f91161bcbf10be04aa9c1079581b97ad4af9aa8..2996cdf60e1d0b1906cfac437a9b7c8febabde7d 100644
--- a/Framework/SINQ/src/PoldiFitPeaks2D.cpp
+++ b/Framework/SINQ/src/PoldiFitPeaks2D.cpp
@@ -9,6 +9,7 @@
 #include "MantidAPI/MultiDomainFunction.h"
 #include "MantidAPI/TableRow.h"
 #include "MantidAPI/WorkspaceFactory.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidDataObjects/Workspace2D.h"
 #include "MantidDataObjects/TableWorkspace.h"
 #include "MantidGeometry/Crystal/UnitCell.h"
@@ -857,7 +858,7 @@ MatrixWorkspace_sptr PoldiFitPeaks2D::get1DSpectrum(
   }
 
   PoldiAbstractDetector_sptr detector(new PoldiDeadWireDecorator(
-      workspace->getInstrument(), m_poldiInstrument->detector()));
+      workspace->detectorInfo(), m_poldiInstrument->detector()));
   std::vector<int> indices = detector->availableElements();
 
   // Create the grid for the diffractogram and corresponding domain/values
diff --git a/Framework/SINQ/src/PoldiUtilities/PoldiAutoCorrelationCore.cpp b/Framework/SINQ/src/PoldiUtilities/PoldiAutoCorrelationCore.cpp
index 4911e091580115b3a7cbdac6c93d2c07bfaad3e1..a7565e4e10211adfb88a7ba4f114dac630b65f24 100644
--- a/Framework/SINQ/src/PoldiUtilities/PoldiAutoCorrelationCore.cpp
+++ b/Framework/SINQ/src/PoldiUtilities/PoldiAutoCorrelationCore.cpp
@@ -6,6 +6,7 @@
 #include "boost/bind.hpp"
 #include "MantidAPI/Axis.h"
 #include "MantidAPI/WorkspaceFactory.h"
+#include "MantidKernel/Logger.h"
 #include "MantidKernel/MultiThreaded.h"
 
 #include "MantidSINQ/PoldiUtilities/PoldiDGrid.h"
diff --git a/Framework/SINQ/src/PoldiUtilities/PoldiDeadWireDecorator.cpp b/Framework/SINQ/src/PoldiUtilities/PoldiDeadWireDecorator.cpp
index 566f7e0b72aaa036bf792e2c739bc5dc8daef37a..440c0f75248f3f0fe58f0438f894f967ad3327e5 100644
--- a/Framework/SINQ/src/PoldiUtilities/PoldiDeadWireDecorator.cpp
+++ b/Framework/SINQ/src/PoldiUtilities/PoldiDeadWireDecorator.cpp
@@ -1,3 +1,4 @@
+#include "MantidAPI/DetectorInfo.h"
 #include "MantidSINQ/PoldiUtilities/PoldiDeadWireDecorator.h"
 
 #include <algorithm>
@@ -17,18 +18,19 @@ PoldiDeadWireDecorator::PoldiDeadWireDecorator(
 }
 
 PoldiDeadWireDecorator::PoldiDeadWireDecorator(
-    Instrument_const_sptr poldiInstrument,
+    const API::DetectorInfo &poldiDetectorInfo,
     boost::shared_ptr<PoldiAbstractDetector> detector)
     : PoldiDetectorDecorator(detector), m_deadWireSet(), m_goodElements() {
   setDecoratedDetector(detector);
 
-  std::vector<detid_t> allDetectorIds = poldiInstrument->getDetectorIDs();
+  std::vector<detid_t> allDetectorIds = poldiDetectorInfo.detectorIDs();
   std::vector<detid_t> deadDetectorIds(allDetectorIds.size());
 
   auto endIterator = std::remove_copy_if(
       allDetectorIds.begin(), allDetectorIds.end(), deadDetectorIds.begin(),
-      boost::bind<bool>(&PoldiDeadWireDecorator::detectorIsNotMasked,
-                        poldiInstrument, _1));
+      [&](const detid_t detID) -> bool {
+        return !poldiDetectorInfo.isMasked(poldiDetectorInfo.indexOf(detID));
+      });
   deadDetectorIds.resize(std::distance(deadDetectorIds.begin(), endIterator));
 
   setDeadWires(std::set<int>(deadDetectorIds.begin(), deadDetectorIds.end()));
@@ -76,11 +78,6 @@ PoldiDeadWireDecorator::getGoodElements(std::vector<int> rawElements) {
   return rawElements;
 }
 
-bool PoldiDeadWireDecorator::detectorIsNotMasked(
-    Instrument_const_sptr instrument, detid_t detectorId) {
-  return !instrument->isDetectorMasked(detectorId);
-}
-
 bool PoldiDeadWireDecorator::isDeadElement(int index) {
   return m_deadWireSet.count(index) != 0;
 }
diff --git a/Framework/SINQ/src/PoldiUtilities/PoldiResidualCorrelationCore.cpp b/Framework/SINQ/src/PoldiUtilities/PoldiResidualCorrelationCore.cpp
index 08e4c82fdc7c58dedf1d4ffe42c8c78eac105c14..5fa777bf2511044f8a9bbdd60962ce3a83cdb995 100644
--- a/Framework/SINQ/src/PoldiUtilities/PoldiResidualCorrelationCore.cpp
+++ b/Framework/SINQ/src/PoldiUtilities/PoldiResidualCorrelationCore.cpp
@@ -1,4 +1,5 @@
 #include "MantidSINQ/PoldiUtilities/PoldiResidualCorrelationCore.h"
+#include "MantidKernel/Logger.h"
 #include <algorithm>
 #include <numeric>
 
diff --git a/Framework/SINQ/src/SINQHMListener.cpp b/Framework/SINQ/src/SINQHMListener.cpp
index 6f3af35f32452b52edc3789add83ce9e0b8177ed..ec05ce5a808407a428784333c373241ce7fa2528 100644
--- a/Framework/SINQ/src/SINQHMListener.cpp
+++ b/Framework/SINQ/src/SINQHMListener.cpp
@@ -18,6 +18,8 @@
 #include <Poco/Net/HTTPBasicCredentials.h>
 #include <Poco/StreamCopier.h>
 
+#include <boost/algorithm/string/trim.hpp>
+
 using namespace Mantid::API;
 using namespace Mantid::DataObjects;
 using namespace Mantid::Geometry;
diff --git a/Framework/SINQ/test/PoldiAnalyseResidualsTest.h b/Framework/SINQ/test/PoldiAnalyseResidualsTest.h
index bc828c685f004ac5feb35cc1f9c3c119512ea7d9..e935e38e54a12b3d6188478c599418196f6b1e51 100644
--- a/Framework/SINQ/test/PoldiAnalyseResidualsTest.h
+++ b/Framework/SINQ/test/PoldiAnalyseResidualsTest.h
@@ -32,7 +32,7 @@ public:
     TestablePoldiAnalyseResiduals alg;
 
     Workspace2D_sptr testWorkspace =
-        WorkspaceCreationHelper::Create2DWorkspaceWhereYIsWorkspaceIndex(2, 2);
+        WorkspaceCreationHelper::create2DWorkspaceWhereYIsWorkspaceIndex(2, 2);
     TS_ASSERT_EQUALS(alg.sumCounts(testWorkspace, std::vector<int>(1, 1)), 2.0);
     TS_ASSERT_EQUALS(alg.sumCounts(testWorkspace, std::vector<int>(1, 0)), 0.0);
 
@@ -44,7 +44,7 @@ public:
     TestablePoldiAnalyseResiduals alg;
 
     Workspace2D_sptr testWorkspace =
-        WorkspaceCreationHelper::Create2DWorkspaceWhereYIsWorkspaceIndex(2, 2);
+        WorkspaceCreationHelper::create2DWorkspaceWhereYIsWorkspaceIndex(2, 2);
     TS_ASSERT_EQUALS(alg.numberOfPoints(testWorkspace, std::vector<int>(1, 1)),
                      2);
     TS_ASSERT_EQUALS(alg.numberOfPoints(testWorkspace, std::vector<int>(1, 0)),
@@ -58,7 +58,7 @@ public:
     TestablePoldiAnalyseResiduals alg;
 
     Workspace2D_sptr testWorkspace =
-        WorkspaceCreationHelper::Create2DWorkspaceWhereYIsWorkspaceIndex(2, 2);
+        WorkspaceCreationHelper::create2DWorkspaceWhereYIsWorkspaceIndex(2, 2);
     TS_ASSERT_THROWS_NOTHING(
         alg.addValue(testWorkspace, 3.0, std::vector<int>(1, 1)));
     TS_ASSERT_THROWS_NOTHING(
@@ -77,9 +77,9 @@ public:
     TestablePoldiAnalyseResiduals alg;
 
     Workspace2D_sptr measured =
-        WorkspaceCreationHelper::Create2DWorkspace123(2, 2);
+        WorkspaceCreationHelper::create2DWorkspace123(2, 2);
     Workspace2D_sptr calculated =
-        WorkspaceCreationHelper::Create2DWorkspace154(2, 2);
+        WorkspaceCreationHelper::create2DWorkspace154(2, 2);
 
     TS_ASSERT_THROWS_NOTHING(
         alg.calculateResidualWorkspace(measured, calculated));
@@ -103,7 +103,7 @@ public:
     TestablePoldiAnalyseResiduals alg;
 
     Workspace2D_sptr testWorkspace =
-        WorkspaceCreationHelper::Create2DWorkspace123(2, 2);
+        WorkspaceCreationHelper::create2DWorkspace123(2, 2);
     TS_ASSERT_THROWS_NOTHING(
         alg.normalizeResiduals(testWorkspace, std::vector<int>(1, 1)));
 
@@ -120,7 +120,7 @@ public:
     TestablePoldiAnalyseResiduals alg;
 
     Workspace2D_sptr testWorkspace =
-        WorkspaceCreationHelper::Create2DWorkspaceWhereYIsWorkspaceIndex(2, 2);
+        WorkspaceCreationHelper::create2DWorkspaceWhereYIsWorkspaceIndex(2, 2);
     TS_ASSERT_EQUALS(alg.relativeCountChange(testWorkspace, 10.0), 0.0);
 
     alg.addValue(testWorkspace, 10.0, std::vector<int>(1, 0));
@@ -132,9 +132,9 @@ public:
     TestablePoldiAnalyseResiduals alg;
 
     Workspace2D_sptr lhs =
-        WorkspaceCreationHelper::Create2DWorkspaceWhereYIsWorkspaceIndex(2, 2);
+        WorkspaceCreationHelper::create2DWorkspaceWhereYIsWorkspaceIndex(2, 2);
     Workspace2D_sptr rhs =
-        WorkspaceCreationHelper::Create2DWorkspaceWhereYIsWorkspaceIndex(2, 2);
+        WorkspaceCreationHelper::create2DWorkspaceWhereYIsWorkspaceIndex(2, 2);
 
     Workspace2D_sptr sum = alg.addWorkspaces(lhs, rhs);
 
diff --git a/Framework/SINQ/test/PoldiAutoCorrelationCoreTest.h b/Framework/SINQ/test/PoldiAutoCorrelationCoreTest.h
index 032b397b089c9a02a40df2e444f02e4406fa3844..e42039031d523c569a22b7e207869f8a9dfcfedd 100644
--- a/Framework/SINQ/test/PoldiAutoCorrelationCoreTest.h
+++ b/Framework/SINQ/test/PoldiAutoCorrelationCoreTest.h
@@ -219,7 +219,7 @@ public:
 
   void testgetCounts() {
     Workspace2D_sptr testWorkspace =
-        WorkspaceCreationHelper::Create2DWorkspaceWhereYIsWorkspaceIndex(2, 2);
+        WorkspaceCreationHelper::create2DWorkspaceWhereYIsWorkspaceIndex(2, 2);
 
     TestablePoldiAutoCorrelationCore autoCorrelationCore(m_log);
     autoCorrelationCore.setCountData(testWorkspace);
@@ -234,7 +234,7 @@ public:
 
   void testgetNormCounts() {
     Workspace2D_sptr testWorkspace =
-        WorkspaceCreationHelper::Create2DWorkspaceWhereYIsWorkspaceIndex(2, 2);
+        WorkspaceCreationHelper::create2DWorkspaceWhereYIsWorkspaceIndex(2, 2);
 
     TestablePoldiAutoCorrelationCore autoCorrelationCore(m_log);
     autoCorrelationCore.setNormCountData(testWorkspace);
@@ -247,7 +247,7 @@ public:
 
   void testgetSumOfCounts() {
     Workspace2D_sptr testWorkspace =
-        WorkspaceCreationHelper::Create2DWorkspaceWhereYIsWorkspaceIndex(2, 2);
+        WorkspaceCreationHelper::create2DWorkspaceWhereYIsWorkspaceIndex(2, 2);
 
     TestablePoldiAutoCorrelationCore autoCorrelationCore(m_log);
     autoCorrelationCore.setCountData(testWorkspace);
@@ -265,7 +265,7 @@ public:
         boost::dynamic_pointer_cast<MockChopper>(autoCorrelationCore.m_chopper);
 
     Workspace2D_sptr testWorkspace =
-        WorkspaceCreationHelper::Create2DWorkspaceWhereYIsWorkspaceIndex(2, 2);
+        WorkspaceCreationHelper::create2DWorkspaceWhereYIsWorkspaceIndex(2, 2);
     autoCorrelationCore.setCountData(testWorkspace);
     autoCorrelationCore.setNormCountData(testWorkspace);
 
diff --git a/Framework/SINQ/test/PoldiCreatePeaksFromCellTest.h b/Framework/SINQ/test/PoldiCreatePeaksFromCellTest.h
index 9aa3471403b7ed31c895a9488a1921c9c02011b8..f63d7b76a495122e458801fc046a330ef4abb3ce 100644
--- a/Framework/SINQ/test/PoldiCreatePeaksFromCellTest.h
+++ b/Framework/SINQ/test/PoldiCreatePeaksFromCellTest.h
@@ -4,6 +4,7 @@
 #include <cxxtest/TestSuite.h>
 
 #include "MantidSINQ/PoldiCreatePeaksFromCell.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/ITableWorkspace.h"
 
 using Mantid::Poldi::PoldiCreatePeaksFromCell;
diff --git a/Framework/SINQ/test/PoldiFitPeaks1D2Test.h b/Framework/SINQ/test/PoldiFitPeaks1D2Test.h
index 6d57b9ca2099e0d544105d58430377909bc4f2f2..febeb266721c0bedfa8556b8b0119a8360ee2d9c 100644
--- a/Framework/SINQ/test/PoldiFitPeaks1D2Test.h
+++ b/Framework/SINQ/test/PoldiFitPeaks1D2Test.h
@@ -309,7 +309,7 @@ private:
 
     // put it into a workspace
     Workspace2D_sptr ws =
-        WorkspaceCreationHelper::Create1DWorkspaceConstant(50, 0.0, 1.0);
+        WorkspaceCreationHelper::create1DWorkspaceConstant(50, 0.0, 1.0);
     std::vector<double> &x = ws->dataX(0);
     std::vector<double> &y = ws->dataY(0);
 
diff --git a/Framework/SINQ/test/PoldiFitPeaks2DTest.h b/Framework/SINQ/test/PoldiFitPeaks2DTest.h
index eaad0b225685d6cfb73078127b9a50347550382f..7d8ae7847115a19590b94ed985d9a5b8f1c542d3 100644
--- a/Framework/SINQ/test/PoldiFitPeaks2DTest.h
+++ b/Framework/SINQ/test/PoldiFitPeaks2DTest.h
@@ -59,7 +59,7 @@ public:
   }
 
   void testSetDeltaTFromWorkspace() {
-    MatrixWorkspace_sptr ws = WorkspaceCreationHelper::Create2DWorkspace(1, 10);
+    MatrixWorkspace_sptr ws = WorkspaceCreationHelper::create2DWorkspace(1, 10);
     for (size_t i = 0; i <= 10; ++i) {
       ws->dataX(0)[i] = static_cast<double>(i);
     }
@@ -69,7 +69,7 @@ public:
     TS_ASSERT_EQUALS(spectrumCalculator.m_deltaT, 1.0);
 
     MatrixWorkspace_sptr invalidWs =
-        WorkspaceCreationHelper::Create2DWorkspace123(1, 1);
+        WorkspaceCreationHelper::create2DWorkspace123(1, 1);
     TS_ASSERT_THROWS(spectrumCalculator.setDeltaTFromWorkspace(invalidWs),
                      std::invalid_argument);
   }
diff --git a/Framework/SINQ/test/PoldiIndexKnownCompoundsTest.h b/Framework/SINQ/test/PoldiIndexKnownCompoundsTest.h
index 4154e7fd2241b1bce4e200ecc29b74ebea023c7c..9541840e11ce5775cd96f518491c187edb28b2c5 100644
--- a/Framework/SINQ/test/PoldiIndexKnownCompoundsTest.h
+++ b/Framework/SINQ/test/PoldiIndexKnownCompoundsTest.h
@@ -5,6 +5,7 @@
 
 #include "MantidSINQ/PoldiIndexKnownCompounds.h"
 #include "MantidAPI/FrameworkManager.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidSINQ/PoldiUtilities/PoldiMockInstrumentHelpers.h"
 #include "MantidTestHelpers/WorkspaceCreationHelper.h"
 #include "MantidKernel/V3D.h"
@@ -238,7 +239,7 @@ public:
     std::vector<Workspace_sptr> badWorkspaces;
     badWorkspaces.push_back(
         PoldiPeakCollectionHelpers::createPoldiPeakTableWorkspace());
-    badWorkspaces.push_back(WorkspaceCreationHelper::Create1DWorkspaceRand(10));
+    badWorkspaces.push_back(WorkspaceCreationHelper::create1DWorkspaceRand(10));
 
     TS_ASSERT_THROWS(alg.getPeakCollections(badWorkspaces),
                      std::invalid_argument);
@@ -669,7 +670,7 @@ private:
   void storeRandomWorkspaces(const std::vector<std::string> &wsNames) {
     for (auto it = wsNames.begin(); it != wsNames.end(); ++it) {
       WorkspaceCreationHelper::storeWS(
-          *it, WorkspaceCreationHelper::Create1DWorkspaceRand(10));
+          *it, WorkspaceCreationHelper::create1DWorkspaceRand(10));
     }
   }
 
diff --git a/Framework/SINQ/test/PoldiPeakCollectionTest.h b/Framework/SINQ/test/PoldiPeakCollectionTest.h
index e2a309f48fad566a21c0c2373504f67a40e9fb25..5f91b3dd074c82498e01c6d166a53d0f2e802f8f 100644
--- a/Framework/SINQ/test/PoldiPeakCollectionTest.h
+++ b/Framework/SINQ/test/PoldiPeakCollectionTest.h
@@ -15,6 +15,7 @@
 #include "MantidGeometry/Crystal/BraggScattererFactory.h"
 #include "MantidGeometry/Crystal/ReflectionGenerator.h"
 
+#include <boost/bind.hpp>
 #include <stdexcept>
 
 using namespace Mantid::Poldi;
diff --git a/Framework/SINQ/test/PoldiResidualCorrelationCoreTest.h b/Framework/SINQ/test/PoldiResidualCorrelationCoreTest.h
index 8f12f7167c296db98122eebaaed60d959b48277c..bfefe641186bd9b64342979b15c9a865de32520c 100644
--- a/Framework/SINQ/test/PoldiResidualCorrelationCoreTest.h
+++ b/Framework/SINQ/test/PoldiResidualCorrelationCoreTest.h
@@ -39,7 +39,7 @@ public:
 
     // test data with all 0s except (0, 0) - it's -1.0
     Mantid::DataObjects::Workspace2D_sptr testWorkspace =
-        WorkspaceCreationHelper::Create2DWorkspaceWhereYIsWorkspaceIndex(2, 2);
+        WorkspaceCreationHelper::create2DWorkspaceWhereYIsWorkspaceIndex(2, 2);
     testWorkspace->dataY(0)[0] = -1.0;
 
     core.setNormCountData(testWorkspace);
@@ -63,7 +63,7 @@ public:
     TestablePoldiResidualCorrelationCore core(m_log);
 
     Mantid::DataObjects::Workspace2D_sptr testWorkspace =
-        WorkspaceCreationHelper::Create2DWorkspaceWhereYIsWorkspaceIndex(2, 2);
+        WorkspaceCreationHelper::create2DWorkspaceWhereYIsWorkspaceIndex(2, 2);
     core.setCountData(testWorkspace);
 
     TS_ASSERT_EQUALS(testWorkspace->dataY(0)[0], 0.0);
@@ -98,7 +98,7 @@ public:
     TestablePoldiResidualCorrelationCore core(m_log);
 
     Mantid::DataObjects::Workspace2D_sptr testWorkspace =
-        WorkspaceCreationHelper::Create2DWorkspaceWhereYIsWorkspaceIndex(2, 2);
+        WorkspaceCreationHelper::create2DWorkspaceWhereYIsWorkspaceIndex(2, 2);
     core.setCountData(testWorkspace);
     core.m_timeBinCount = 2;
     core.m_detectorElements = {0, 1};
diff --git a/Framework/SINQ/test/PoldiSpectrumConstantBackgroundTest.h b/Framework/SINQ/test/PoldiSpectrumConstantBackgroundTest.h
index 03cd8399f10a2bfb68c5c4d0be1ee79aa4e83dab..099dc86190fd48005e95136bcbf061c1825fb4f9 100644
--- a/Framework/SINQ/test/PoldiSpectrumConstantBackgroundTest.h
+++ b/Framework/SINQ/test/PoldiSpectrumConstantBackgroundTest.h
@@ -37,7 +37,7 @@ public:
         "PoldiSpectrumConstantBackground");
     TS_ASSERT(function);
     MatrixWorkspace_sptr ws =
-        WorkspaceCreationHelper::Create2DWorkspaceWhereYIsWorkspaceIndex(20, 2);
+        WorkspaceCreationHelper::create2DWorkspaceWhereYIsWorkspaceIndex(20, 2);
 
     TS_ASSERT_THROWS_NOTHING(function->setWorkspace(ws));
     function->setParameter(0, 10.0);
@@ -56,7 +56,7 @@ public:
         "PoldiSpectrumConstantBackground");
     TS_ASSERT(function);
     MatrixWorkspace_sptr ws =
-        WorkspaceCreationHelper::Create2DWorkspace123(20, 2);
+        WorkspaceCreationHelper::create2DWorkspace123(20, 2);
 
     TS_ASSERT_THROWS_NOTHING(function->setWorkspace(ws));
     function->setParameter(0, 10.0);
diff --git a/Framework/SINQ/test/PoldiSpectrumLinearBackgroundTest.h b/Framework/SINQ/test/PoldiSpectrumLinearBackgroundTest.h
index d3b29c1bd97e1710726fce9226fddd5703d8e117..71120c01cec2eda4f37ceea05983abd52f553caa 100644
--- a/Framework/SINQ/test/PoldiSpectrumLinearBackgroundTest.h
+++ b/Framework/SINQ/test/PoldiSpectrumLinearBackgroundTest.h
@@ -66,7 +66,7 @@ public:
 
     // valid workspace with 10 bins
     MatrixWorkspace_sptr ws =
-        WorkspaceCreationHelper::Create2DWorkspace123(1, 10);
+        WorkspaceCreationHelper::create2DWorkspace123(1, 10);
     TS_ASSERT_THROWS_NOTHING(castedFunction->setWorkspace(ws));
     TS_ASSERT_EQUALS(castedFunction->getTimeBinCount(), 10);
   }
@@ -116,7 +116,7 @@ public:
     /* Luckily, these are exactly the data described by this function,
      * using A1 = 1.0, so this is used as a test */
     MatrixWorkspace_sptr ws =
-        WorkspaceCreationHelper::Create2DWorkspaceWhereYIsWorkspaceIndex(20, 2);
+        WorkspaceCreationHelper::create2DWorkspaceWhereYIsWorkspaceIndex(20, 2);
 
     IFunction_sptr function = FunctionFactory::Instance().createFunction(
         "PoldiSpectrumLinearBackground");
diff --git a/Framework/SINQ/test/PoldiSpectrumPawleyFunctionTest.h b/Framework/SINQ/test/PoldiSpectrumPawleyFunctionTest.h
index 0efdb4737a8e50569c9bfbdfb12c3efcf81e94c5..e12511644860ddeda60f632cea15e982bc22ce50 100644
--- a/Framework/SINQ/test/PoldiSpectrumPawleyFunctionTest.h
+++ b/Framework/SINQ/test/PoldiSpectrumPawleyFunctionTest.h
@@ -109,7 +109,7 @@ public:
     fn.setDecoratedFunction("MockPawleyFunction");
 
     MatrixWorkspace_const_sptr ws =
-        WorkspaceCreationHelper::Create2DWorkspace123(4, 10);
+        WorkspaceCreationHelper::create2DWorkspace123(4, 10);
 
     // Make sure the setMatrixWorkspace method can be called directly.
     IPawleyFunction_sptr pFn = fn.getPawleyFunction();
diff --git a/Framework/SINQ/test/PoldiTruncateDataTest.h b/Framework/SINQ/test/PoldiTruncateDataTest.h
index fd304040c424971abefeb2580c237233f9e55c75..6a4fe84a6ce60d11bc10e37b62c7412f409d880d 100644
--- a/Framework/SINQ/test/PoldiTruncateDataTest.h
+++ b/Framework/SINQ/test/PoldiTruncateDataTest.h
@@ -70,7 +70,7 @@ public:
   void testSetTimeBinWidthFromWorkspace() {
     // workspace with delta x = 1.0, 3 bins (= 4 boundaries)
     MatrixWorkspace_sptr matrixWs =
-        WorkspaceCreationHelper::Create2DWorkspaceWhereYIsWorkspaceIndex(1, 3);
+        WorkspaceCreationHelper::create2DWorkspaceWhereYIsWorkspaceIndex(1, 3);
 
     TestablePoldiTruncateData truncate;
     TS_ASSERT_THROWS_NOTHING(truncate.setTimeBinWidthFromWorkspace(matrixWs));
@@ -83,7 +83,7 @@ public:
 
     // matrix workspace with one bin
     MatrixWorkspace_sptr invalidBins =
-        WorkspaceCreationHelper::Create2DWorkspace123(1, 1);
+        WorkspaceCreationHelper::create2DWorkspace123(1, 1);
 
     TS_ASSERT_THROWS(truncate.setTimeBinWidthFromWorkspace(invalidBins),
                      std::invalid_argument);
@@ -293,7 +293,7 @@ private:
     }
 
     MatrixWorkspace_sptr workspace =
-        WorkspaceCreationHelper::Create2DWorkspace123(histograms, binCount);
+        WorkspaceCreationHelper::create2DWorkspace123(histograms, binCount);
 
     for (size_t i = 0; i < histograms; ++i) {
       std::vector<double> &xData = workspace->dataX(i);
diff --git a/Framework/TestHelpers/inc/MantidTestHelpers/ComponentCreationHelper.h b/Framework/TestHelpers/inc/MantidTestHelpers/ComponentCreationHelper.h
index 45737dfed3b9811aeb2b267df0d408a32f8499dc..ab8328fa4cc360b7a12824a7ca82e3479223e171 100644
--- a/Framework/TestHelpers/inc/MantidTestHelpers/ComponentCreationHelper.h
+++ b/Framework/TestHelpers/inc/MantidTestHelpers/ComponentCreationHelper.h
@@ -123,10 +123,7 @@ boost::shared_ptr<Mantid::Geometry::DetectorGroup>
 createRingOfCylindricalDetectors(const double R_min = 4.5,
                                  const double R_max = 5,
                                  const double z000000000000000 = 4);
-/**
- * Create a group of two monitors
- */
-boost::shared_ptr<Mantid::Geometry::DetectorGroup> createGroupOfTwoMonitors();
+
 /** create instrument with cylindrical detectors located in specific angular
  * positions */
 Mantid::Geometry::Instrument_sptr
diff --git a/Framework/TestHelpers/inc/MantidTestHelpers/FakeObjects.h b/Framework/TestHelpers/inc/MantidTestHelpers/FakeObjects.h
index 7b79e385dacb40cd639112f62096ea3d40225e32..0ff3dbd316a8cd2aa217714737be61e12d619538 100644
--- a/Framework/TestHelpers/inc/MantidTestHelpers/FakeObjects.h
+++ b/Framework/TestHelpers/inc/MantidTestHelpers/FakeObjects.h
@@ -32,7 +32,6 @@
 #include "MantidKernel/cow_ptr.h"
 
 using namespace Mantid::API;
-using namespace Mantid::Kernel;
 using namespace Mantid;
 
 //===================================================================================================================
@@ -52,13 +51,13 @@ public:
     m_histogram.setCountStandardDeviations(0);
   }
 
-  void setX(const cow_ptr<HistogramData::HistogramX> &X) override {
+  void setX(const Kernel::cow_ptr<HistogramData::HistogramX> &X) override {
     m_histogram.setX(X);
   }
   MantidVec &dataX() override { return m_histogram.dataX(); }
   const MantidVec &dataX() const override { return m_histogram.dataX(); }
   const MantidVec &readX() const override { return m_histogram.readX(); }
-  cow_ptr<HistogramData::HistogramX> ptrX() const override {
+  Kernel::cow_ptr<HistogramData::HistogramX> ptrX() const override {
     return m_histogram.ptrX();
   }
 
@@ -128,6 +127,21 @@ public:
     m_axes[0] = new Mantid::API::RefAxis(j, this);
     m_axes[1] = new Mantid::API::SpectraAxis(this);
   }
+  void init(const size_t &numspec,
+            const HistogramData::Histogram &histogram) override {
+    spec = numspec;
+    vec.resize(spec, SpectrumTester(histogram.xMode(), histogram.yMode()));
+    for (size_t i = 0; i < spec; i++) {
+      vec[i].setHistogram(histogram);
+      vec[i].addDetectorID(detid_t(i));
+      vec[i].setSpectrumNo(specnum_t(i + 1));
+    }
+
+    // Put an 'empty' axis in to test the getAxis method
+    m_axes.resize(2);
+    m_axes[0] = new Mantid::API::RefAxis(histogram.x().size(), this);
+    m_axes[1] = new Mantid::API::SpectraAxis(this);
+  }
   size_t size() const override { return vec.size() * blocksize(); }
   size_t blocksize() const override {
     return vec.empty() ? 0 : vec[0].dataY().size();
@@ -147,6 +161,9 @@ private:
   WorkspaceTester *doClone() const override {
     return new WorkspaceTester(*this);
   }
+  WorkspaceTester *doCloneEmpty() const override {
+    throw std::runtime_error("Cloning of WorkspaceTester is not implemented.");
+  }
   std::vector<SpectrumTester> vec;
   size_t spec;
 };
@@ -243,7 +260,7 @@ public:
     throw std::runtime_error("find not implemented");
   }
 
-  void find(V3D, size_t &, const size_t &) override {
+  void find(Kernel::V3D, size_t &, const size_t &) override {
     throw std::runtime_error("find not implemented");
   }
 
diff --git a/Framework/TestHelpers/inc/MantidTestHelpers/WorkspaceCreationHelper.h b/Framework/TestHelpers/inc/MantidTestHelpers/WorkspaceCreationHelper.h
index f0144963c8e90db0ab192c33c9009d81b0f0b492..64e4d5e91a289561cfa64ad4e314bc87c38b7e8f 100644
--- a/Framework/TestHelpers/inc/MantidTestHelpers/WorkspaceCreationHelper.h
+++ b/Framework/TestHelpers/inc/MantidTestHelpers/WorkspaceCreationHelper.h
@@ -10,19 +10,24 @@
  *********************************************************************************/
 #ifndef WORKSPACECREATIONHELPER_H_
 #define WORKSPACECREATIONHELPER_H_
-//------------------------------------------------------------------------------
-// Includes
-//------------------------------------------------------------------------------
-#include "MantidDataObjects/EventWorkspace.h"
-#include "MantidDataObjects/RebinnedOutput.h"
-#include "MantidDataObjects/Workspace2D.h"
-#include "MantidDataObjects/WorkspaceSingleValue.h"
-#include "MantidDataObjects/TableWorkspace.h"
+
 #include "MantidAPI/Algorithm.h"
+#include "MantidAPI/AnalysisDataService.h"
+#include "MantidAPI/ITableWorkspace_fwd.h"
 #include "MantidAPI/Run.h"
 #include "MantidAPI/MatrixWorkspace_fwd.h"
+#include "MantidAPI/Run.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidAPI/WorkspaceGroup_fwd.h"
+#include "MantidDataObjects/EventWorkspace.h"
+#include "MantidDataObjects/RebinnedOutput.h"
+#include "MantidDataObjects/Workspace2D.h"
+#include "MantidDataObjects/WorkspaceSingleValue.h"
+#include "MantidDataObjects/EventWorkspace.h"
+#include "MantidDataObjects/RebinnedOutput.h"
+#include "MantidDataObjects/TableWorkspace.h"
+#include "MantidDataObjects/Workspace2D.h"
+#include "MantidDataObjects/WorkspaceSingleValue.h"
 #include "MantidGeometry/Instrument/Detector.h"
 #include "MantidKernel/make_unique.h"
 
@@ -52,9 +57,9 @@ class MockAlgorithm : public Mantid::API::Algorithm {
 public:
   MockAlgorithm(size_t nSteps = 100);
   /// Algorithm's name for identification
-  const std::string name() const override { return "MockAlgorithm"; };
+  const std::string name() const override { return "MockAlgorithm"; }
   /// Algorithm's version for identification
-  int version() const override { return 1; };
+  int version() const override { return 1; }
   /// Algorithm's category for identification
   const std::string category() const override { return "Test"; }
   /// Algorithm's summary.
@@ -69,14 +74,34 @@ public:
   }
 
 private:
-  void init() override{};
-  void exec() override{};
+  void init() override {}
+  void exec() override {}
 
   std::unique_ptr<Mantid::API::Progress> m_Progress;
   /// logger -> to provide logging,
   static Mantid::Kernel::Logger &g_log;
 };
 
+/// A struct containing the cells of an EPP table row.
+struct EPPTableRow {
+  /// FindEPP algorithm fitting success status.
+  enum class FitStatus { SUCCESS, FAILURE };
+
+  /// Construct a row with the default values.
+  EPPTableRow() = default;
+  /// Construct a row with errors set to zero.
+  EPPTableRow(const double peakCentre, const double sigma, const double height,
+              const FitStatus fitStatus);
+  double peakCentre = 0;
+  double peakCentreError = 0;
+  double sigma = 0;
+  double sigmaError = 0;
+  double height = 0;
+  double heightError = 0;
+  double chiSq = 0;
+  FitStatus fitStatus = FitStatus::SUCCESS;
+};
+
 /// Adds a workspace to the ADS
 void storeWS(const std::string &name, Mantid::API::Workspace_sptr ws);
 /// Deletes a workspce
@@ -86,25 +111,24 @@ template <typename T> boost::shared_ptr<T> getWS(const std::string &name) {
   return Mantid::API::AnalysisDataService::Instance().retrieveWS<T>(name);
 }
 
-Mantid::DataObjects::Workspace2D_sptr Create1DWorkspaceRand(int size);
+Mantid::DataObjects::Workspace2D_sptr create1DWorkspaceRand(int size);
 Mantid::DataObjects::Workspace2D_sptr
-Create1DWorkspaceConstant(int size, double value, double error);
-Mantid::DataObjects::Workspace2D_sptr Create1DWorkspaceFib(int size);
+create1DWorkspaceConstant(int size, double value, double error);
+Mantid::DataObjects::Workspace2D_sptr create1DWorkspaceFib(int size);
 Mantid::DataObjects::Workspace2D_sptr
-Create1DWorkspaceConstantWithXerror(int size, double value, double error,
+create1DWorkspaceConstantWithXerror(int size, double value, double error,
                                     double xError);
-Mantid::DataObjects::Workspace2D_sptr Create2DWorkspace(
-    int nhist,
-    int numBoundariesundariesundariesundariesundariesundariesundariesundariesundariesundariesundariesundariesundaries);
+Mantid::DataObjects::Workspace2D_sptr create2DWorkspace(int nhist,
+                                                        int numBoundaries);
 Mantid::DataObjects::Workspace2D_sptr
-Create2DWorkspaceWhereYIsWorkspaceIndex(int nhist, int numBoundaries);
-Mantid::DataObjects::Workspace2D_sptr Create2DWorkspace123(
-    int64_t nHist, int64_t nBinsssssssssssss, bool isHist = false,
+create2DWorkspaceWhereYIsWorkspaceIndex(int nhist, int numBoundaries);
+Mantid::DataObjects::Workspace2D_sptr create2DWorkspace123(
+    int64_t nHist, int64_t nBins, bool isHist = false,
     const std::set<int64_t> &maskedWorkspaceIndices = std::set<int64_t>());
-Mantid::DataObjects::Workspace2D_sptr Create2DWorkspace154(
+Mantid::DataObjects::Workspace2D_sptr create2DWorkspace154(
     int64_t nHist, int64_t nBins, bool isHist = false,
     const std::set<int64_t> &maskedWorkspaceIndices = std::set<int64_t>());
-Mantid::DataObjects::Workspace2D_sptr Create2DWorkspaceWithValuesAndXerror(
+Mantid::DataObjects::Workspace2D_sptr create2DWorkspaceWithValuesAndXerror(
     int64_t nHist, int64_t nBins, bool isHist, double xVal, double yVal,
     double eVal, double dxVal,
     const std::set<int64_t> &maskedWorkspaceIndices = std::set<int64_t>());
@@ -114,25 +138,23 @@ maskSpectra(Mantid::DataObjects::Workspace2D_sptr workspace,
 /**
  * Create a WorkspaceGroup with N workspaces and the specified parameters
  */
-Mantid::API::WorkspaceGroup_sptr CreateWorkspaceGroup(int nEntries, int nHist,
+Mantid::API::WorkspaceGroup_sptr createWorkspaceGroup(int nEntries, int nHist,
                                                       int nBins,
                                                       const std::string &stem);
 /** Create a 2D workspace with this many histograms and bins.
  * Filled with Y = 2.0 and E = sqrt(2.0)w
  */
 Mantid::DataObjects::Workspace2D_sptr
-Create2DWorkspaceBinned(int nhist, int nbins, double x0 = 0.0,
+create2DWorkspaceBinned(int nhist, int nbins, double x0 = 0.0,
                         double deltax = 1.0);
 
 /** Create a 2D workspace with this many histograms and bins. The bins are
  * assumed to be non-uniform and given by the input array
  * Filled with Y = 2.0 and E = sqrt(2.0)w
  */
-Mantid::DataObjects::Workspace2D_sptr Create2DWorkspaceBinned(
-    int nhist,
-    const int
-        numBoundariesundariesundariesundariesundariesundariesundariesundariesundariesundariesundariesundariesundaries,
-    const double xBoundaries[]);
+Mantid::DataObjects::Workspace2D_sptr
+create2DWorkspaceBinned(int nhist, const int numBoundaries,
+                        const double xBoundaries[]);
 
 /**
  * Creates a 2D workspace from taking the function values from the input
@@ -147,7 +169,7 @@ Mantid::DataObjects::Workspace2D_sptr Create2DWorkspaceBinned(
  */
 template <typename Func>
 Mantid::DataObjects::Workspace2D_sptr
-Create2DWorkspaceFromFunction(Func f, int nSpec, double x0, double x1,
+create2DWorkspaceFromFunction(Func f, int nSpec, double x0, double x1,
                               double dx, bool isHist = false) {
   int nX = int((x1 - x0) / dx) + 1;
   int nY = nX - (isHist ? 1 : 0);
@@ -225,16 +247,16 @@ Mantid::DataObjects::EventWorkspace_sptr
 createEventWorkspaceWithNonUniformInstrument(int numBanks, bool clearEvents);
 
 Mantid::DataObjects::WorkspaceSingleValue_sptr
-CreateWorkspaceSingleValue(double value);
+createWorkspaceSingleValue(double value);
 Mantid::DataObjects::WorkspaceSingleValue_sptr
-CreateWorkspaceSingleValueWithError(double value, double error);
+createWorkspaceSingleValueWithError(double value, double error);
 /** Perform some finalization on event workspace stuff */
-void EventWorkspace_Finalize(Mantid::DataObjects::EventWorkspace_sptr ew);
+void eventWorkspace_Finalize(Mantid::DataObjects::EventWorkspace_sptr ew);
 /** Create event workspace with:
  * 500 pixels
  * 1000 histogrammed bins.
  */
-Mantid::DataObjects::EventWorkspace_sptr CreateEventWorkspace();
+Mantid::DataObjects::EventWorkspace_sptr createEventWorkspace();
 
 /** Create event workspace with:
  * 50 pixels
@@ -243,50 +265,50 @@ Mantid::DataObjects::EventWorkspace_sptr CreateEventWorkspace();
  * PulseTime = 1 second, 2 seconds, etc.
  */
 Mantid::DataObjects::EventWorkspace_sptr
-CreateEventWorkspace2(int numPixels = 50, int numBins = 100);
+createEventWorkspace2(int numPixels = 50, int numBins = 100);
 
 Mantid::DataObjects::EventWorkspace_sptr
-CreateEventWorkspace(int numPixels, int numBins, int numEvents = 100,
+createEventWorkspace(int numPixels, int numBins, int numEvents = 100,
                      double x0 = 0.0, double binDelta = 1.0,
                      int eventPattern = 1, int start_at_pixelID = 0);
 
-Mantid::DataObjects::EventWorkspace_sptr CreateEventWorkspaceWithStartTime(
+Mantid::DataObjects::EventWorkspace_sptr createEventWorkspaceWithStartTime(
     int numPixels, int numBins, int numEvents = 100, double x0 = 0.0,
     double binDelta = 1.0, int eventPattern = 1, int start_at_pixelID = 0,
     Mantid::Kernel::DateAndTime run_start =
         Mantid::Kernel::DateAndTime("2010-01-01T00:00:00"));
 
 Mantid::DataObjects::EventWorkspace_sptr
-CreateGroupedEventWorkspace(std::vector<std::vector<int>> groups, int numBins,
+createGroupedEventWorkspace(std::vector<std::vector<int>> groups, int numBins,
                             double binDelta = 1., double xOffset = 0.);
 
 Mantid::DataObjects::EventWorkspace_sptr
-CreateRandomEventWorkspace(size_t numbins, size_t numpixels,
+createRandomEventWorkspace(size_t numbins, size_t numpixels,
                            double bin_delta = 1.0);
 
 Mantid::API::MatrixWorkspace_sptr
-CreateGroupedWorkspace2D(size_t numHist, int numBins, double binDelta);
+createGroupedWorkspace2D(size_t numHist, int numBins, double binDelta);
 // grouped workspace with detectors arranges in rings in center and into boxes
 // outside
-Mantid::API::MatrixWorkspace_sptr CreateGroupedWorkspace2DWithRingsAndBoxes(
+Mantid::API::MatrixWorkspace_sptr createGroupedWorkspace2DWithRingsAndBoxes(
     size_t RootOfNumHist = 10, int numBins = 10, double binDelta = 1.0);
 // not strictly creating a workspace, but really helpful to see what one
 // contains
-void DisplayDataY(const Mantid::API::MatrixWorkspace_sptr ws);
+void displayDataY(const Mantid::API::MatrixWorkspace_sptr ws);
 // not strictly creating a workspace, but really helpful to see what one
 // contains
-void DisplayData(const Mantid::API::MatrixWorkspace_sptr ws);
+void displayData(const Mantid::API::MatrixWorkspace_sptr ws);
 // not strictly creating a workspace, but really helpful to see what one
 // contains
-void DisplayDataX(const Mantid::API::MatrixWorkspace_sptr ws);
+void displayDataX(const Mantid::API::MatrixWorkspace_sptr ws);
 // not strictly creating a workspace, but really helpful to see what one
 // contains
-void DisplayDataE(const Mantid::API::MatrixWorkspace_sptr ws);
+void displayDataE(const Mantid::API::MatrixWorkspace_sptr ws);
 
-void AddTSPEntry(Mantid::API::Run &runInfo, std::string name, double val);
-void SetOrientedLattice(Mantid::API::MatrixWorkspace_sptr ws, double a,
+void addTSPEntry(Mantid::API::Run &runInfo, std::string name, double val);
+void setOrientedLattice(Mantid::API::MatrixWorkspace_sptr ws, double a,
                         double b, double c);
-void SetGoniometer(Mantid::API::MatrixWorkspace_sptr ws, double phi, double chi,
+void setGoniometer(Mantid::API::MatrixWorkspace_sptr ws, double phi, double chi,
                    double omega);
 
 // create workspace which should be result of homering (transform to energy in
@@ -307,7 +329,7 @@ createEventWorkspace3(Mantid::DataObjects::EventWorkspace_const_sptr sourceWS,
                       std::string wsname, Mantid::API::Algorithm *alg);
 
 /// Function to create a fixed RebinnedOutput workspace
-Mantid::DataObjects::RebinnedOutput_sptr CreateRebinnedOutputWorkspace();
+Mantid::DataObjects::RebinnedOutput_sptr createRebinnedOutputWorkspace();
 
 /// Create a simple peaks workspace containing the given number of peaks
 boost::shared_ptr<Mantid::DataObjects::PeaksWorkspace>
@@ -333,6 +355,11 @@ void createInstrumentForWorkspaceWithDistances(
     const Mantid::Kernel::V3D &samplePosition,
     const Mantid::Kernel::V3D &sourcePosition,
     const std::vector<Mantid::Kernel::V3D> &detectorPositions);
-}
+
+/// Create a table workspace corresponding to what the FindEPP algorithm gives.
+Mantid::API::ITableWorkspace_sptr
+createEPPTableWorkspace(const std::vector<EPPTableRow> &rows);
+
+} // namespace WorkspaceCreationHelper
 
 #endif /*WORKSPACECREATIONHELPER_H_*/
diff --git a/Framework/TestHelpers/src/BinaryOperationMDTestHelper.cpp b/Framework/TestHelpers/src/BinaryOperationMDTestHelper.cpp
index 9ad38437ee3b99078478bb735d90c9e1c0e7127f..fbb8e2a80f232976c569a7af0b767c817f603277 100644
--- a/Framework/TestHelpers/src/BinaryOperationMDTestHelper.cpp
+++ b/Framework/TestHelpers/src/BinaryOperationMDTestHelper.cpp
@@ -38,7 +38,7 @@ void setUpBinaryOperationMDTestHelper() {
       MDEventsTestHelper::makeFakeMDHistoWorkspace(0.0, 2, 5, 10.0, 0.0);
   event_A = MDEventsTestHelper::makeMDEW<2>(3, 0.0, 10.0, 1);
   event_B = MDEventsTestHelper::makeMDEW<2>(3, 0.0, 10.0, 1);
-  scalar = WorkspaceCreationHelper::CreateWorkspaceSingleValue(3.0);
+  scalar = WorkspaceCreationHelper::createWorkspaceSingleValue(3.0);
   AnalysisDataService::Instance().addOrReplace("histo_A", histo_A);
   AnalysisDataService::Instance().addOrReplace("histo_B", histo_B);
   AnalysisDataService::Instance().addOrReplace("histo_masked", histo_masked);
@@ -97,7 +97,7 @@ MDHistoWorkspace_sptr doTest(std::string algoName, std::string inName,
   IMDEventWorkspace_sptr event =
       MDEventsTestHelper::makeMDEW<2>(3, 0.0, 10.0, 1);
   WorkspaceSingleValue_sptr scalar =
-      WorkspaceCreationHelper::CreateWorkspaceSingleValue(2.5);
+      WorkspaceCreationHelper::createWorkspaceSingleValue(2.5);
   AnalysisDataService::Instance().addOrReplace("histo", histo);
   AnalysisDataService::Instance().addOrReplace("event", event);
   AnalysisDataService::Instance().addOrReplace("scalar", scalar);
diff --git a/Framework/TestHelpers/src/ComponentCreationHelper.cpp b/Framework/TestHelpers/src/ComponentCreationHelper.cpp
index cd2484c2ab96931bd4612d9e1fe5e8d349966548..a4ee33d4f1dfb590c39d967cfff09fdf35f696e7 100644
--- a/Framework/TestHelpers/src/ComponentCreationHelper.cpp
+++ b/Framework/TestHelpers/src/ComponentCreationHelper.cpp
@@ -174,7 +174,7 @@ createDetectorGroupWith5CylindricalDetectors() {
     groupMembers[i] = det;
   }
 
-  return boost::make_shared<DetectorGroup>(groupMembers, false);
+  return boost::make_shared<DetectorGroup>(groupMembers);
 }
 
 //----------------------------------------------------------------------------------------------
@@ -197,7 +197,7 @@ createDetectorGroupWithNCylindricalDetectorsWithGaps(unsigned int nDet,
     groupMembers[i] = det;
   }
 
-  return boost::make_shared<DetectorGroup>(groupMembers, false);
+  return boost::make_shared<DetectorGroup>(groupMembers);
 }
 
 //----------------------------------------------------------------------------------------------
@@ -240,28 +240,9 @@ createRingOfCylindricalDetectors(const double R_min, const double R_max,
       ic++;
     }
   }
-  return boost::make_shared<DetectorGroup>(groupMembers, false);
+  return boost::make_shared<DetectorGroup>(groupMembers);
 }
 
-//----------------------------------------------------------------------------------------------
-/**
- * Create a group of two monitors
- */
-boost::shared_ptr<DetectorGroup> createGroupOfTwoMonitors() {
-  const int ndets(2);
-  std::vector<boost::shared_ptr<const IDetector>> groupMembers(ndets);
-  for (int i = 0; i < ndets; ++i) {
-    std::ostringstream os;
-    os << "m" << i;
-    auto det = boost::make_shared<Detector>(os.str(), i + 1, nullptr);
-    det->setPos(static_cast<double>(i + 1), 2.0, 2.0);
-    det->markAsMonitor();
-    groupMembers[i] = det;
-  }
-  return boost::make_shared<DetectorGroup>(groupMembers, false);
-}
-
-//----------------------------------------------------------------------------------------------
 Instrument_sptr createTestInstrumentCylindrical(
     int num_banks, const Mantid::Kernel::V3D &sourcePos,
     const Mantid::Kernel::V3D &samplePos, const double cylRadius,
@@ -286,7 +267,7 @@ Instrument_sptr createTestInstrumentCylindrical(
     for (int i = -1; i < 2; ++i) {
       for (int j = -1; j < 2; ++j) {
         std::ostringstream lexer;
-        lexer << "pixel-(" << j << "," << i << ")";
+        lexer << "pixel-(" << j << ";" << i << ")";
         Detector *physicalPixel =
             new Detector(lexer.str(), pixelID, pixelShape, bank);
         const double xpos = j * (cylRadius * 2.0);
diff --git a/Framework/TestHelpers/src/FakeObjects.cpp b/Framework/TestHelpers/src/FakeObjects.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..dfcf040c0092231bc8dd61b5ef6e1129e22bced5
--- /dev/null
+++ b/Framework/TestHelpers/src/FakeObjects.cpp
@@ -0,0 +1,21 @@
+#include "MantidTestHelpers/FakeObjects.h"
+
+// Property implementations
+#include "MantidKernel/PropertyWithValue.tcc"
+#include "MantidAPI/WorkspaceProperty.tcc"
+
+namespace Mantid {
+namespace Kernel {
+///@cond TEMPLATE
+template class DLLExport PropertyWithValue<boost::shared_ptr<WorkspaceTester>>;
+template class DLLExport
+    PropertyWithValue<boost::shared_ptr<TableWorkspaceTester>>;
+///@endcond TEMPLATE
+} // namespace Kernel
+namespace API {
+///@cond TEMPLATE
+template class DLLExport Mantid::API::WorkspaceProperty<WorkspaceTester>;
+template class DLLExport Mantid::API::WorkspaceProperty<TableWorkspaceTester>;
+///@endcond TEMPLATE
+} // namespace API
+} // namespace Mantid
diff --git a/Framework/TestHelpers/src/InstrumentCreationHelper.cpp b/Framework/TestHelpers/src/InstrumentCreationHelper.cpp
index cdf9f76f888d2133deb80fce1a0d899f7b027d20..6b90c7f69fdd6121cf0c4bf103da34fbdc99db38 100644
--- a/Framework/TestHelpers/src/InstrumentCreationHelper.cpp
+++ b/Framework/TestHelpers/src/InstrumentCreationHelper.cpp
@@ -18,7 +18,6 @@ void addFullInstrumentToWorkspace(MatrixWorkspace &workspace,
   auto instrument = boost::make_shared<Instrument>(instrumentName);
   instrument->setReferenceFrame(
       boost::make_shared<ReferenceFrame>(Y, Z, Right, ""));
-  workspace.setInstrument(instrument);
 
   const double pixelRadius(0.05);
   Object_sptr pixelShape = ComponentCreationHelper::createCappedCylinder(
@@ -87,5 +86,6 @@ void addFullInstrumentToWorkspace(MatrixWorkspace &workspace,
   Component *chop_pos = new Component("chopper-position",
                                       Kernel::V3D(0, 0, -10), instrument.get());
   instrument->add(chop_pos);
+  workspace.setInstrument(instrument);
 }
 }
diff --git a/Framework/TestHelpers/src/MDEventsTestHelper.cpp b/Framework/TestHelpers/src/MDEventsTestHelper.cpp
index 63d708ccfbe2652f6933c4f5d8607e0d3ac0b25a..0011f7534351588a6440ad51344af7ebccd3688c 100644
--- a/Framework/TestHelpers/src/MDEventsTestHelper.cpp
+++ b/Framework/TestHelpers/src/MDEventsTestHelper.cpp
@@ -100,8 +100,8 @@ createDiffractionEventWorkspace(int numEvents, int numPixels, int numBins) {
   retVal->getAxis(0)->setUnit("TOF");
 
   // Give it a crystal and goniometer
-  WorkspaceCreationHelper::SetGoniometer(retVal, 0., 0., 0.);
-  WorkspaceCreationHelper::SetOrientedLattice(retVal, 1., 1., 1.);
+  WorkspaceCreationHelper::setGoniometer(retVal, 0., 0., 0.);
+  WorkspaceCreationHelper::setOrientedLattice(retVal, 1., 1., 1.);
 
   // Some sanity checks
   if (retVal->getInstrument()->getName() != "MINITOPAZ")
diff --git a/Framework/TestHelpers/src/SANSInstrumentCreationHelper.cpp b/Framework/TestHelpers/src/SANSInstrumentCreationHelper.cpp
index e367ec58f3609ae10c83512e401ba2dc2ff48254..d761925f43fb7755d5839f53f9e920e294511d53 100644
--- a/Framework/TestHelpers/src/SANSInstrumentCreationHelper.cpp
+++ b/Framework/TestHelpers/src/SANSInstrumentCreationHelper.cpp
@@ -40,7 +40,7 @@ Workspace2D_sptr SANSInstrumentCreationHelper::createSANSInstrumentWorkspace(
     std::string workspace) {
   // Create a test workspace with test data with a well defined peak
   // The test instrument has two monitor channels
-  Workspace2D_sptr ws = WorkspaceCreationHelper::Create2DWorkspace123(
+  Workspace2D_sptr ws = WorkspaceCreationHelper::create2DWorkspace123(
       nBins * nBins + nMonitors, 1, 1);
   AnalysisDataService::Instance().addOrReplace(workspace, ws);
   ws->getAxis(0)->unit() =
diff --git a/Framework/TestHelpers/src/WorkspaceCreationHelper.cpp b/Framework/TestHelpers/src/WorkspaceCreationHelper.cpp
index 0ea9ef83badb5e07d2e60b93ef199e088799f6ed..4755e8842de3d4dbd50dcf3ac03201a41368d1a5 100644
--- a/Framework/TestHelpers/src/WorkspaceCreationHelper.cpp
+++ b/Framework/TestHelpers/src/WorkspaceCreationHelper.cpp
@@ -16,11 +16,15 @@
 #include "MantidAPI/Run.h"
 #include "MantidAPI/IAlgorithm.h"
 #include "MantidAPI/Algorithm.h"
+#include "MantidAPI/DetectorInfo.h"
 #include "MantidAPI/Sample.h"
 #include "MantidAPI/SpectraAxis.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidAPI/NumericAxis.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidDataObjects/PeaksWorkspace.h"
 #include "MantidGeometry/Instrument/Detector.h"
+#include "MantidGeometry/Instrument/Goniometer.h"
 #include "MantidGeometry/Instrument/ParameterMap.h"
 #include "MantidGeometry/Instrument/ReferenceFrame.h"
 #include "MantidGeometry/Instrument/Component.h"
@@ -49,6 +53,11 @@ MockAlgorithm::MockAlgorithm(size_t nSteps) {
   m_Progress = Mantid::Kernel::make_unique<API::Progress>(this, 0, 1, nSteps);
 }
 
+EPPTableRow::EPPTableRow(const double peakCentre_, const double sigma_,
+                         const double height_, const FitStatus fitStatus_)
+    : peakCentre(peakCentre_), peakCentreError(0), sigma(sigma_), sigmaError(0),
+      height(height_), heightError(0), chiSq(0), fitStatus(fitStatus_) {}
+
 /**
  * @param name :: The name of the workspace
  * @param ws :: The workspace object
@@ -65,7 +74,7 @@ void removeWS(const std::string &name) {
   Mantid::API::AnalysisDataService::Instance().remove(name);
 }
 
-Workspace2D_sptr Create1DWorkspaceRand(int size) {
+Workspace2D_sptr create1DWorkspaceRand(int size) {
   MantidVec y1(size);
   MantidVec e1(size);
 
@@ -83,7 +92,7 @@ Workspace2D_sptr Create1DWorkspaceRand(int size) {
   return retVal;
 }
 
-Workspace2D_sptr Create1DWorkspaceConstant(int size, double value,
+Workspace2D_sptr create1DWorkspaceConstant(int size, double value,
                                            double error) {
   MantidVec y1(size, value);
   MantidVec e1(size, error);
@@ -95,16 +104,16 @@ Workspace2D_sptr Create1DWorkspaceConstant(int size, double value,
   return retVal;
 }
 
-Workspace2D_sptr Create1DWorkspaceConstantWithXerror(int size, double value,
+Workspace2D_sptr create1DWorkspaceConstantWithXerror(int size, double value,
                                                      double error,
                                                      double xError) {
-  auto ws = Create1DWorkspaceConstant(size, value, error);
+  auto ws = create1DWorkspaceConstant(size, value, error);
   auto dx1 = Kernel::make_cow<HistogramData::HistogramDx>(size, xError);
   ws->setSharedDx(0, dx1);
   return ws;
 }
 
-Workspace2D_sptr Create1DWorkspaceFib(int size) {
+Workspace2D_sptr create1DWorkspaceFib(int size) {
   MantidVec y1(size);
   MantidVec e1(size);
   std::generate(y1.begin(), y1.end(), FibSeries<double>());
@@ -116,8 +125,8 @@ Workspace2D_sptr Create1DWorkspaceFib(int size) {
   return retVal;
 }
 
-Workspace2D_sptr Create2DWorkspace(int nhist, int numBoundaries) {
-  return Create2DWorkspaceBinned(nhist, numBoundaries);
+Workspace2D_sptr create2DWorkspace(int nhist, int numBoundaries) {
+  return create2DWorkspaceBinned(nhist, numBoundaries);
 }
 
 /** Create a Workspace2D where the Y value at each bin is
@@ -126,9 +135,9 @@ Workspace2D_sptr Create2DWorkspace(int nhist, int numBoundaries) {
  * @param numBoundaries :: # of bins
  * @return Workspace2D
  */
-Workspace2D_sptr Create2DWorkspaceWhereYIsWorkspaceIndex(int nhist,
+Workspace2D_sptr create2DWorkspaceWhereYIsWorkspaceIndex(int nhist,
                                                          int numBoundaries) {
-  Workspace2D_sptr out = Create2DWorkspaceBinned(nhist, numBoundaries);
+  Workspace2D_sptr out = create2DWorkspaceBinned(nhist, numBoundaries);
   for (int wi = 0; wi < nhist; wi++)
     for (int x = 0; x < numBoundaries; x++)
       out->dataY(wi)[x] = wi * 1.0;
@@ -137,7 +146,7 @@ Workspace2D_sptr Create2DWorkspaceWhereYIsWorkspaceIndex(int nhist,
 
 Workspace2D_sptr create2DWorkspaceThetaVsTOF(int nHist, int nBins) {
 
-  Workspace2D_sptr outputWS = Create2DWorkspaceBinned(nHist, nBins);
+  Workspace2D_sptr outputWS = create2DWorkspaceBinned(nHist, nBins);
   auto const newAxis = new NumericAxis(nHist);
   outputWS->replaceAxis(1, newAxis);
   newAxis->unit() = boost::make_shared<Units::Degrees>();
@@ -149,7 +158,7 @@ Workspace2D_sptr create2DWorkspaceThetaVsTOF(int nHist, int nBins) {
 }
 
 Workspace2D_sptr
-Create2DWorkspaceWithValues(int64_t nHist, int64_t nBins, bool isHist,
+create2DWorkspaceWithValues(int64_t nHist, int64_t nBins, bool isHist,
                             const std::set<int64_t> &maskedWorkspaceIndices,
                             double xVal, double yVal, double eVal) {
   auto x1 = Kernel::make_cow<HistogramData::HistogramX>(
@@ -169,11 +178,11 @@ Create2DWorkspaceWithValues(int64_t nHist, int64_t nBins, bool isHist,
   return retVal;
 }
 
-Workspace2D_sptr Create2DWorkspaceWithValuesAndXerror(
+Workspace2D_sptr create2DWorkspaceWithValuesAndXerror(
     int64_t nHist, int64_t nBins, bool isHist, double xVal, double yVal,
     double eVal, double dxVal,
     const std::set<int64_t> &maskedWorkspaceIndices) {
-  auto ws = Create2DWorkspaceWithValues(
+  auto ws = create2DWorkspaceWithValues(
       nHist, nBins, isHist, maskedWorkspaceIndices, xVal, yVal, eVal);
   PointStandardDeviations dx1(nBins, dxVal);
   for (int i = 0; i < nHist; i++) {
@@ -183,16 +192,16 @@ Workspace2D_sptr Create2DWorkspaceWithValuesAndXerror(
 }
 
 Workspace2D_sptr
-Create2DWorkspace123(int64_t nHist, int64_t nBins, bool isHist,
+create2DWorkspace123(int64_t nHist, int64_t nBins, bool isHist,
                      const std::set<int64_t> &maskedWorkspaceIndices) {
-  return Create2DWorkspaceWithValues(nHist, nBins, isHist,
+  return create2DWorkspaceWithValues(nHist, nBins, isHist,
                                      maskedWorkspaceIndices, 1.0, 2.0, 3.0);
 }
 
 Workspace2D_sptr
-Create2DWorkspace154(int64_t nHist, int64_t nBins, bool isHist,
+create2DWorkspace154(int64_t nHist, int64_t nBins, bool isHist,
                      const std::set<int64_t> &maskedWorkspaceIndices) {
-  return Create2DWorkspaceWithValues(nHist, nBins, isHist,
+  return create2DWorkspaceWithValues(nHist, nBins, isHist,
                                      maskedWorkspaceIndices, 1.0, 5.0, 4.0);
 }
 
@@ -221,25 +230,21 @@ Workspace2D_sptr maskSpectra(Workspace2D_sptr workspace,
     workspace->setInstrument(instrument);
   }
 
-  ParameterMap &pmap = workspace->instrumentParameters();
-  for (int i = 0; i < nhist; ++i) {
-    if (maskedWorkspaceIndices.find(i) != maskedWorkspaceIndices.end()) {
-      IDetector_const_sptr det = workspace->getDetector(i);
-      pmap.addBool(det.get(), "masked", true);
-    }
-  }
+  auto &spectrumInfo = workspace->mutableSpectrumInfo();
+  for (const auto index : maskedWorkspaceIndices)
+    spectrumInfo.setMasked(index, true);
   return workspace;
 }
 
 /**
  * Create a group with nEntries. It is added to the ADS with the given stem
  */
-WorkspaceGroup_sptr CreateWorkspaceGroup(int nEntries, int nHist, int nBins,
+WorkspaceGroup_sptr createWorkspaceGroup(int nEntries, int nHist, int nBins,
                                          const std::string &stem) {
   auto group = boost::make_shared<WorkspaceGroup>();
   AnalysisDataService::Instance().add(stem, group);
   for (int i = 0; i < nEntries; ++i) {
-    Workspace2D_sptr ws = Create2DWorkspace(nHist, nBins);
+    Workspace2D_sptr ws = create2DWorkspace(nHist, nBins);
     std::ostringstream os;
     os << stem << "_" << i;
     AnalysisDataService::Instance().add(os.str(), ws);
@@ -251,7 +256,7 @@ WorkspaceGroup_sptr CreateWorkspaceGroup(int nEntries, int nHist, int nBins,
 /** Create a 2D workspace with this many histograms and bins.
  * Filled with Y = 2.0 and E = M_SQRT2w
  */
-Workspace2D_sptr Create2DWorkspaceBinned(int nhist, int nbins, double x0,
+Workspace2D_sptr create2DWorkspaceBinned(int nhist, int nbins, double x0,
                                          double deltax) {
   BinEdges x(nbins + 1, LinearGenerator(x0, deltax));
   Counts y(nbins, 2);
@@ -270,7 +275,7 @@ Workspace2D_sptr Create2DWorkspaceBinned(int nhist, int nbins, double x0,
  * assumed to be non-uniform and given by the input array
  * Filled with Y = 2.0 and E = M_SQRT2w
  */
-Workspace2D_sptr Create2DWorkspaceBinned(int nhist, const int numBoundaries,
+Workspace2D_sptr create2DWorkspaceBinned(int nhist, const int numBoundaries,
                                          const double xBoundaries[]) {
   BinEdges x(xBoundaries, xBoundaries + numBoundaries);
   const int numBins = numBoundaries - 1;
@@ -326,10 +331,10 @@ create2DWorkspaceWithFullInstrument(int nhist, int nbins, bool includeMonitors,
 
   Workspace2D_sptr space;
   if (isHistogram)
-    space = Create2DWorkspaceBinned(
+    space = create2DWorkspaceBinned(
         nhist, nbins); // A 1:1 spectra is created by default
   else
-    space = Create2DWorkspace123(nhist, nbins, false);
+    space = create2DWorkspace123(nhist, nbins, false);
   space->setTitle(
       "Test histogram"); // actually adds a property call run_title to the logs
   space->getAxis(0)->setUnit("TOF");
@@ -358,7 +363,7 @@ create2DWorkspaceWithRectangularInstrument(int numBanks, int numPixels,
       ComponentCreationHelper::createTestInstrumentRectangular(numBanks,
                                                                numPixels);
   Workspace2D_sptr ws =
-      Create2DWorkspaceBinned(numBanks * numPixels * numPixels, numBins);
+      create2DWorkspaceBinned(numBanks * numPixels * numPixels, numBins);
   ws->setInstrument(inst);
   ws->getAxis(0)->setUnit("dSpacing");
   for (size_t wi = 0; wi < ws->getNumberHistograms(); wi++) {
@@ -387,7 +392,7 @@ createEventWorkspaceWithFullInstrument(int numBanks, int numPixels,
       ComponentCreationHelper::createTestInstrumentRectangular(numBanks,
                                                                numPixels);
   EventWorkspace_sptr ws =
-      CreateEventWorkspace2(numBanks * numPixels * numPixels, 100);
+      createEventWorkspace2(numBanks * numPixels * numPixels, 100);
   ws->setInstrument(inst);
 
   // Set the X axes
@@ -421,7 +426,7 @@ createEventWorkspaceWithNonUniformInstrument(int numBanks, bool clearEvents) {
       ComponentCreationHelper::createTestInstrumentCylindrical(
           numBanks, srcPos, samplePos, 0.0025, 0.005);
   EventWorkspace_sptr ws =
-      CreateEventWorkspace2(numBanks * DETECTORS_PER_BANK, 100);
+      createEventWorkspace2(numBanks * DETECTORS_PER_BANK, 100);
   ws->setInstrument(inst);
 
   std::vector<detid_t> detectorIds = inst->getDetectorIDs();
@@ -477,7 +482,7 @@ create2DWorkspaceWithReflectometryInstrument(double startX) {
   const int nSpectra = 2;
   const int nBins = 100;
   const double deltaX = 2000; // TOF
-  auto workspace = Create2DWorkspaceBinned(nSpectra, nBins, startX, deltaX);
+  auto workspace = create2DWorkspaceBinned(nSpectra, nBins, startX, deltaX);
 
   workspace->setTitle(
       "Test histogram"); // actually adds a property call run_title to the logs
@@ -507,8 +512,6 @@ void createInstrumentForWorkspaceWithDistances(
   instrument->add(sample);
   instrument->markAsSamplePos(sample);
 
-  workspace->setInstrument(instrument);
-
   for (int i = 0; i < static_cast<int>(detectorPositions.size()); ++i) {
     std::stringstream buffer;
     buffer << "detector_" << i;
@@ -521,20 +524,21 @@ void createInstrumentForWorkspaceWithDistances(
     workspace->getSpectrum(i).clearDetectorIDs();
     workspace->getSpectrum(i).addDetectorID(det->getID());
   }
+  workspace->setInstrument(instrument);
 }
 
 //================================================================================================================
-WorkspaceSingleValue_sptr CreateWorkspaceSingleValue(double value) {
+WorkspaceSingleValue_sptr createWorkspaceSingleValue(double value) {
   return boost::make_shared<WorkspaceSingleValue>(value, sqrt(value));
 }
 
-WorkspaceSingleValue_sptr CreateWorkspaceSingleValueWithError(double value,
+WorkspaceSingleValue_sptr createWorkspaceSingleValueWithError(double value,
                                                               double error) {
   return boost::make_shared<WorkspaceSingleValue>(value, error);
 }
 
 /** Perform some finalization on event workspace stuff */
-void EventWorkspace_Finalize(EventWorkspace_sptr ew) {
+void eventWorkspace_Finalize(EventWorkspace_sptr ew) {
   // get a proton charge
   ew->mutableRun().integrateProtonCharge();
 }
@@ -543,8 +547,8 @@ void EventWorkspace_Finalize(EventWorkspace_sptr ew) {
  * 500 pixels
  * 1000 histogrammed bins.
  */
-EventWorkspace_sptr CreateEventWorkspace() {
-  return CreateEventWorkspace(500, 1001, 100, 1000);
+EventWorkspace_sptr createEventWorkspace() {
+  return createEventWorkspace(500, 1001, 100, 1000);
 }
 
 /** Create event workspace with:
@@ -553,17 +557,17 @@ EventWorkspace_sptr CreateEventWorkspace() {
  * 200 events; two in each bin, at time 0.5, 1.5, etc.
  * PulseTime = 0 second x2, 1 second x2, 2 seconds x2, etc. after 2010-01-01
  */
-EventWorkspace_sptr CreateEventWorkspace2(int numPixels, int numBins) {
-  return CreateEventWorkspace(numPixels, numBins, 100, 0.0, 1.0, 2);
+EventWorkspace_sptr createEventWorkspace2(int numPixels, int numBins) {
+  return createEventWorkspace(numPixels, numBins, 100, 0.0, 1.0, 2);
 }
 
 /** Create event workspace
  */
-EventWorkspace_sptr CreateEventWorkspace(int numPixels, int numBins,
+EventWorkspace_sptr createEventWorkspace(int numPixels, int numBins,
                                          int numEvents, double x0,
                                          double binDelta, int eventPattern,
                                          int start_at_pixelID) {
-  return CreateEventWorkspaceWithStartTime(
+  return createEventWorkspaceWithStartTime(
       numPixels, numBins, numEvents, x0, binDelta, eventPattern,
       start_at_pixelID, DateAndTime("2010-01-01T00:00:00"));
 }
@@ -572,7 +576,7 @@ EventWorkspace_sptr CreateEventWorkspace(int numPixels, int numBins,
  * Create event workspace with defined start date time
  */
 EventWorkspace_sptr
-CreateEventWorkspaceWithStartTime(int numPixels, int numBins, int numEvents,
+createEventWorkspaceWithStartTime(int numPixels, int numBins, int numEvents,
                                   double x0, double binDelta, int eventPattern,
                                   int start_at_pixelID, DateAndTime run_start) {
 
@@ -622,7 +626,7 @@ CreateEventWorkspaceWithStartTime(int numPixels, int numBins, int numEvents,
 /** Create event workspace, with several detector IDs in one event list.
  */
 EventWorkspace_sptr
-CreateGroupedEventWorkspace(std::vector<std::vector<int>> groups, int numBins,
+createGroupedEventWorkspace(std::vector<std::vector<int>> groups, int numBins,
                             double binDelta, double xOffset) {
 
   auto retVal = boost::make_shared<EventWorkspace>();
@@ -660,7 +664,7 @@ CreateGroupedEventWorkspace(std::vector<std::vector<int>> groups, int numBins,
  * @param bin_delta :: a constant offset to shift the bin bounds by
  * @return EventWorkspace
  */
-EventWorkspace_sptr CreateRandomEventWorkspace(size_t numbins, size_t numpixels,
+EventWorkspace_sptr createRandomEventWorkspace(size_t numbins, size_t numpixels,
                                                double bin_delta) {
   auto retVal = boost::make_shared<EventWorkspace>();
   retVal->initialize(numpixels, numbins, numbins - 1);
@@ -698,9 +702,9 @@ EventWorkspace_sptr CreateRandomEventWorkspace(size_t numbins, size_t numpixels,
 /** Create Workspace2d, with numHist spectra, each with 9 detectors,
  * with IDs 1-9, 10-18, 19-27
  */
-MatrixWorkspace_sptr CreateGroupedWorkspace2D(size_t numHist, int numBins,
+MatrixWorkspace_sptr createGroupedWorkspace2D(size_t numHist, int numBins,
                                               double binDelta) {
-  Workspace2D_sptr retVal = Create2DWorkspaceBinned(static_cast<int>(numHist),
+  Workspace2D_sptr retVal = create2DWorkspaceBinned(static_cast<int>(numHist),
                                                     numBins, 0.0, binDelta);
   retVal->setInstrument(
       ComponentCreationHelper::createTestInstrumentCylindrical(
@@ -718,10 +722,10 @@ MatrixWorkspace_sptr CreateGroupedWorkspace2D(size_t numHist, int numBins,
 // =====================================================================================
 // RootOfNumHist == square root of hystohram number;
 MatrixWorkspace_sptr
-CreateGroupedWorkspace2DWithRingsAndBoxes(size_t RootOfNumHist, int numBins,
+createGroupedWorkspace2DWithRingsAndBoxes(size_t RootOfNumHist, int numBins,
                                           double binDelta) {
   size_t numHist = RootOfNumHist * RootOfNumHist;
-  Workspace2D_sptr retVal = Create2DWorkspaceBinned(static_cast<int>(numHist),
+  Workspace2D_sptr retVal = create2DWorkspaceBinned(static_cast<int>(numHist),
                                                     numBins, 0.0, binDelta);
   retVal->setInstrument(
       ComponentCreationHelper::createTestInstrumentCylindrical(
@@ -737,7 +741,7 @@ CreateGroupedWorkspace2DWithRingsAndBoxes(size_t RootOfNumHist, int numBins,
 
 // not strictly creating a workspace, but really helpfull to see what one
 // contains
-void DisplayDataY(const MatrixWorkspace_sptr ws) {
+void displayDataY(const MatrixWorkspace_sptr ws) {
   const size_t numHists = ws->getNumberHistograms();
   for (size_t i = 0; i < numHists; ++i) {
     std::cout << "Histogram " << i << " = ";
@@ -747,11 +751,11 @@ void DisplayDataY(const MatrixWorkspace_sptr ws) {
     std::cout << '\n';
   }
 }
-void DisplayData(const MatrixWorkspace_sptr ws) { DisplayDataX(ws); }
+void displayData(const MatrixWorkspace_sptr ws) { displayDataX(ws); }
 
 // not strictly creating a workspace, but really helpfull to see what one
 // contains
-void DisplayDataX(const MatrixWorkspace_sptr ws) {
+void displayDataX(const MatrixWorkspace_sptr ws) {
   const size_t numHists = ws->getNumberHistograms();
   for (size_t i = 0; i < numHists; ++i) {
     std::cout << "Histogram " << i << " = ";
@@ -764,7 +768,7 @@ void DisplayDataX(const MatrixWorkspace_sptr ws) {
 
 // not strictly creating a workspace, but really helpfull to see what one
 // contains
-void DisplayDataE(const MatrixWorkspace_sptr ws) {
+void displayDataE(const MatrixWorkspace_sptr ws) {
   const size_t numHists = ws->getNumberHistograms();
   for (size_t i = 0; i < numHists; ++i) {
     std::cout << "Histogram " << i << " = ";
@@ -782,7 +786,7 @@ void DisplayDataE(const MatrixWorkspace_sptr ws) {
  * @param name :: property name
  * @param val :: value
  */
-void AddTSPEntry(Run &runInfo, std::string name, double val) {
+void addTSPEntry(Run &runInfo, std::string name, double val) {
   TimeSeriesProperty<double> *tsp;
   tsp = new TimeSeriesProperty<double>(name);
   tsp->addValue("2011-05-24T00:00:00", val);
@@ -798,7 +802,7 @@ void AddTSPEntry(Run &runInfo, std::string name, double val) {
  * @param b :: lattice length
  * @param c :: lattice length
  */
-void SetOrientedLattice(Mantid::API::MatrixWorkspace_sptr ws, double a,
+void setOrientedLattice(Mantid::API::MatrixWorkspace_sptr ws, double a,
                         double b, double c) {
   auto latt =
       Mantid::Kernel::make_unique<OrientedLattice>(a, b, c, 90., 90., 90.);
@@ -813,11 +817,11 @@ void SetOrientedLattice(Mantid::API::MatrixWorkspace_sptr ws, double a,
  * @param chi :: +X rotation angle (deg)
  * @param omega :: +Y rotation angle (deg)
  */
-void SetGoniometer(Mantid::API::MatrixWorkspace_sptr ws, double phi, double chi,
+void setGoniometer(Mantid::API::MatrixWorkspace_sptr ws, double phi, double chi,
                    double omega) {
-  AddTSPEntry(ws->mutableRun(), "phi", phi);
-  AddTSPEntry(ws->mutableRun(), "chi", chi);
-  AddTSPEntry(ws->mutableRun(), "omega", omega);
+  addTSPEntry(ws->mutableRun(), "phi", phi);
+  addTSPEntry(ws->mutableRun(), "chi", chi);
+  addTSPEntry(ws->mutableRun(), "omega", omega);
   Mantid::Geometry::Goniometer gm;
   gm.makeUniversalGoniometer();
   ws->mutableRun().setGoniometer(gm, true);
@@ -833,7 +837,7 @@ createProcessedWorkspaceWithCylComplexInstrument(size_t numPixels,
     rHist++;
 
   Mantid::API::MatrixWorkspace_sptr ws =
-      CreateGroupedWorkspace2DWithRingsAndBoxes(rHist, 10, 0.1);
+      createGroupedWorkspace2DWithRingsAndBoxes(rHist, 10, 0.1);
   auto pAxis0 = new NumericAxis(numBins);
   for (size_t i = 0; i < numBins; i++) {
     double dE = -1.0 + static_cast<double>(i) * 0.8;
@@ -846,9 +850,9 @@ createProcessedWorkspaceWithCylComplexInstrument(size_t numPixels,
         Mantid::Kernel::make_unique<OrientedLattice>(1, 1, 1, 90., 90., 90.);
     ws->mutableSample().setOrientedLattice(latt.release());
 
-    AddTSPEntry(ws->mutableRun(), "phi", 0);
-    AddTSPEntry(ws->mutableRun(), "chi", 0);
-    AddTSPEntry(ws->mutableRun(), "omega", 0);
+    addTSPEntry(ws->mutableRun(), "phi", 0);
+    addTSPEntry(ws->mutableRun(), "chi", 0);
+    addTSPEntry(ws->mutableRun(), "omega", 0);
     Mantid::Geometry::Goniometer gm;
     gm.makeUniversalGoniometer();
     ws->mutableRun().setGoniometer(gm, true);
@@ -876,7 +880,7 @@ createProcessedInelasticWS(const std::vector<double> &L2,
   size_t numPixels = L2.size();
 
   Mantid::API::MatrixWorkspace_sptr ws =
-      Create2DWorkspaceWithValues(uint64_t(numPixels), uint64_t(numBins), true,
+      create2DWorkspaceWithValues(uint64_t(numPixels), uint64_t(numBins), true,
                                   maskedWorkspaceIndices, 0, 1, 0.1);
 
   // detectors at L2, sample at 0 and source at -L2_min
@@ -928,9 +932,9 @@ createProcessedInelasticWS(const std::vector<double> &L2,
   ws->mutableRun().addProperty(new PropertyWithValue<double>("Ei", Ei), true);
   // these properties have to be different -> specific for processed ws, as time
   // now should be reconciled
-  AddTSPEntry(ws->mutableRun(), "phi", 0);
-  AddTSPEntry(ws->mutableRun(), "chi", 0);
-  AddTSPEntry(ws->mutableRun(), "omega", 0);
+  addTSPEntry(ws->mutableRun(), "phi", 0);
+  addTSPEntry(ws->mutableRun(), "chi", 0);
+  addTSPEntry(ws->mutableRun(), "omega", 0);
   Mantid::Geometry::Goniometer gm;
   gm.makeUniversalGoniometer();
   ws->mutableRun().setGoniometer(gm, true);
@@ -995,8 +999,9 @@ createEventWorkspace3(Mantid::DataObjects::EventWorkspace_const_sptr sourceWS,
 
   // c) Pad all the pixels and Set to zero
   size_t workspaceIndex = 0;
+  const auto &detectorInfo = outputWS->detectorInfo();
   for (it = detector_map.begin(); it != detector_map.end(); ++it) {
-    if (!it->second->isMonitor()) {
+    if (!detectorInfo.isMonitor(detectorInfo.indexOf(it->first))) {
       auto &spec = outputWS->getSpectrum(workspaceIndex);
       spec.addDetectorID(it->first);
       // Start the spectrum number at 1
@@ -1008,7 +1013,7 @@ createEventWorkspace3(Mantid::DataObjects::EventWorkspace_const_sptr sourceWS,
   return outputWS;
 }
 
-RebinnedOutput_sptr CreateRebinnedOutputWorkspace() {
+RebinnedOutput_sptr createRebinnedOutputWorkspace() {
   RebinnedOutput_sptr outputWS =
       Mantid::DataObjects::RebinnedOutput_sptr(new RebinnedOutput());
   // outputWS->setName("rebinTest");
@@ -1234,6 +1239,7 @@ void processDetectorsPositions(const API::MatrixWorkspace_const_sptr &inputWS,
   size_t nHist = targWS->rowCount();
   //// Loop over the spectra
   uint32_t liveDetectorsCount(0);
+  const auto &spectrumInfo = inputWS->spectrumInfo();
   for (size_t i = 0; i < nHist; i++) {
     sp2detMap[i] = std::numeric_limits<size_t>::quiet_NaN();
     detId[i] = std::numeric_limits<int32_t>::quiet_NaN();
@@ -1242,26 +1248,17 @@ void processDetectorsPositions(const API::MatrixWorkspace_const_sptr &inputWS,
     TwoTheta[i] = std::numeric_limits<double>::quiet_NaN();
     Azimuthal[i] = std::numeric_limits<double>::quiet_NaN();
 
-    // get detector or detector group which corresponds to the spectra i
-    Geometry::IDetector_const_sptr spDet;
-    try {
-      spDet = inputWS->getDetector(i);
-    } catch (Kernel::Exception::NotFoundError &) {
-      continue;
-    }
-
-    // Check that we aren't dealing with monitor...
-    if (spDet->isMonitor())
+    if (!spectrumInfo.hasDetectors(i) || spectrumInfo.isMonitor(i))
       continue;
 
     // calculate the requested values;
     sp2detMap[i] = liveDetectorsCount;
-    detId[liveDetectorsCount] = int32_t(spDet->getID());
+    detId[liveDetectorsCount] = int32_t(spectrumInfo.detector(i).getID());
     detIDMap[liveDetectorsCount] = i;
-    L2[liveDetectorsCount] = spDet->getDistance(*sample);
+    L2[liveDetectorsCount] = spectrumInfo.l2(i);
 
-    double polar = inputWS->detectorTwoTheta(*spDet);
-    double azim = spDet->getPhi();
+    double polar = spectrumInfo.twoTheta(i);
+    double azim = spectrumInfo.detector(i).getPhi();
     TwoTheta[liveDetectorsCount] = polar;
     Azimuthal[liveDetectorsCount] = azim;
 
@@ -1310,4 +1307,32 @@ void create2DAngles(std::vector<double> &L2, std::vector<double> &polar,
     }
   }
 }
+
+ITableWorkspace_sptr
+createEPPTableWorkspace(const std::vector<EPPTableRow> &rows) {
+  ITableWorkspace_sptr ws = boost::make_shared<TableWorkspace>(rows.size());
+  auto wsIndexColumn = ws->addColumn("int", "WorkspaceIndex");
+  auto centreColumn = ws->addColumn("double", "PeakCentre");
+  auto centreErrorColumn = ws->addColumn("double", "PeakCentreError");
+  auto sigmaColumn = ws->addColumn("double", "Sigma");
+  auto sigmaErrorColumn = ws->addColumn("double", "SigmaError");
+  auto heightColumn = ws->addColumn("double", "Height");
+  auto heightErrorColumn = ws->addColumn("double", "HeightError");
+  auto chiSqColumn = ws->addColumn("double", "chiSq");
+  auto statusColumn = ws->addColumn("str", "FitStatus");
+  for (size_t i = 0; i != rows.size(); ++i) {
+    const auto &row = rows[i];
+    wsIndexColumn->cell<int>(i) = static_cast<int>(i);
+    centreColumn->cell<double>(i) = row.peakCentre;
+    centreErrorColumn->cell<double>(i) = row.peakCentreError;
+    sigmaColumn->cell<double>(i) = row.sigma;
+    sigmaErrorColumn->cell<double>(i) = row.sigmaError;
+    heightColumn->cell<double>(i) = row.height;
+    heightErrorColumn->cell<double>(i) = row.heightError;
+    chiSqColumn->cell<double>(i) = row.chiSq;
+    statusColumn->cell<std::string>(i) =
+        row.fitStatus == EPPTableRow::FitStatus::SUCCESS ? "success" : "failed";
+  }
+  return ws;
 }
+} // namespace WorkspaceCreationHelper
diff --git a/Framework/WorkflowAlgorithms/inc/MantidWorkflowAlgorithms/MuonProcess.h b/Framework/WorkflowAlgorithms/inc/MantidWorkflowAlgorithms/MuonProcess.h
index 5c91eb4df1a33b50b216f09b5d3d63ab46712ef6..0824d987083f86036d0f90bf3265ef19f35745f6 100644
--- a/Framework/WorkflowAlgorithms/inc/MantidWorkflowAlgorithms/MuonProcess.h
+++ b/Framework/WorkflowAlgorithms/inc/MantidWorkflowAlgorithms/MuonProcess.h
@@ -3,6 +3,7 @@
 
 #include "MantidKernel/System.h"
 #include "MantidAPI/DataProcessorAlgorithm.h"
+#include "MantidAPI/WorkspaceGroup_fwd.h"
 #include "MantidDataObjects/TableWorkspace.h"
 
 namespace Mantid {
diff --git a/Framework/WorkflowAlgorithms/inc/MantidWorkflowAlgorithms/SetupILLD33Reduction.h b/Framework/WorkflowAlgorithms/inc/MantidWorkflowAlgorithms/SetupILLD33Reduction.h
index 37c2a37147341aebe2e770b8969b03897661a790..10c37566be50c407f3d619025a07f0602f89f3e1 100644
--- a/Framework/WorkflowAlgorithms/inc/MantidWorkflowAlgorithms/SetupILLD33Reduction.h
+++ b/Framework/WorkflowAlgorithms/inc/MantidWorkflowAlgorithms/SetupILLD33Reduction.h
@@ -5,6 +5,7 @@
 // Includes
 //----------------------------------------------------------------------
 #include "MantidAPI/Algorithm.h"
+#include "MantidAPI/DeprecatedAlgorithm.h"
 #include "MantidDataObjects/EventWorkspace.h"
 #include "MantidAPI/MatrixWorkspace_fwd.h"
 #include "MantidKernel/PropertyManager.h"
@@ -36,7 +37,8 @@ namespace WorkflowAlgorithms {
     Code Documentation is available at: <http://doxygen.mantidproject.org>
 */
 
-class DLLExport SetupILLD33Reduction : public API::Algorithm {
+class DLLExport SetupILLD33Reduction : public API::Algorithm,
+                                       public API::DeprecatedAlgorithm {
 public:
   /// Algorithm's name
   const std::string name() const override { return "SetupILLD33Reduction"; }
diff --git a/Framework/WorkflowAlgorithms/src/AlignAndFocusPowder.cpp b/Framework/WorkflowAlgorithms/src/AlignAndFocusPowder.cpp
index 55de024f407e3bebd8bf8e99d20a03248303f810..d9ac8e049bc94bf0cdadcf77f5d2b470f2af4f8c 100644
--- a/Framework/WorkflowAlgorithms/src/AlignAndFocusPowder.cpp
+++ b/Framework/WorkflowAlgorithms/src/AlignAndFocusPowder.cpp
@@ -1,7 +1,5 @@
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidWorkflowAlgorithms/AlignAndFocusPowder.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/FileProperty.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidKernel/PropertyManagerDataService.h"
@@ -147,9 +145,11 @@ void AlignAndFocusPowder::init() {
   declareProperty(
       "CropWavelengthMin", 0.,
       "Crop the data at this minimum wavelength. Overrides LowResRef.");
+  mapPropertyName("CropWavelengthMin", "wavelength_min");
   declareProperty("CropWavelengthMax", EMPTY_DBL(),
                   "Crop the data at this maximum wavelength. Forces use of "
                   "CropWavelengthMin.");
+  mapPropertyName("CropWavelengthMax", "wavelength_max");
   declareProperty("PrimaryFlightPath", -1.0,
                   "If positive, focus positions are changed.  (Default -1) ");
   declareProperty(make_unique<ArrayProperty<int32_t>>("SpectrumIDs"),
diff --git a/Framework/WorkflowAlgorithms/src/ComputeSensitivity.cpp b/Framework/WorkflowAlgorithms/src/ComputeSensitivity.cpp
index 8b2111110b974a560f753c598444c139225004f5..029e32c04dd0fd62685b59a65a48fd3556e1d104 100644
--- a/Framework/WorkflowAlgorithms/src/ComputeSensitivity.cpp
+++ b/Framework/WorkflowAlgorithms/src/ComputeSensitivity.cpp
@@ -66,7 +66,7 @@ void ComputeSensitivity::exec() {
   // Set patch information so that the SANS sensitivity algorithm can
   // patch the sensitivity workspace
   const std::string patchWSName = getPropertyValue("PatchWorkspace");
-  if (patchWSName.size() > 0) {
+  if (!patchWSName.empty()) {
     IAlgorithm_sptr patchAlg = createChildAlgorithm("EQSANSPatchSensitivity");
     patchAlg->setPropertyValue("PatchWorkspace", patchWSName);
     if (!reductionManager->existsProperty("SensitivityPatchAlgorithm")) {
diff --git a/Framework/WorkflowAlgorithms/src/ConvolutionFitSequential.cpp b/Framework/WorkflowAlgorithms/src/ConvolutionFitSequential.cpp
index 7e05ad35f573b30a148baf169e939bc14f628df5..93801abbccf4470a48dfe2b240a44ff834cf137c 100644
--- a/Framework/WorkflowAlgorithms/src/ConvolutionFitSequential.cpp
+++ b/Framework/WorkflowAlgorithms/src/ConvolutionFitSequential.cpp
@@ -109,6 +109,14 @@ void ConvolutionFitSequential::init() {
   declareProperty("MaxIterations", 500, boundedV,
                   "The maximum number of iterations permitted",
                   Direction::Input);
+  declareProperty("PeakRadius", 0,
+                  "A value of the peak radius the peak functions should use. A "
+                  "peak radius defines an interval on the x axis around the "
+                  "centre of the peak where its values are calculated. Values "
+                  "outside the interval are not calculated and assumed zeros."
+                  "Numerically the radius is a whole number of peak widths "
+                  "(FWHM) that fit into the interval on each side from the "
+                  "centre. The default value of 0 means the whole x axis.");
 
   declareProperty(make_unique<WorkspaceProperty<>>("OutputWorkspace", "",
                                                    Direction::Output),
@@ -131,6 +139,7 @@ void ConvolutionFitSequential::exec() {
   const bool convolve = getProperty("Convolve");
   const int maxIter = getProperty("MaxIterations");
   const std::string minimizer = getProperty("Minimizer");
+  const int peakRadius = getProperty("PeakRadius");
 
   // Inspect function to obtain fit Type and background
   const auto functionValues = findValuesFromFunction(function);
@@ -207,6 +216,7 @@ void ConvolutionFitSequential::exec() {
   plotPeaks->setProperty("MaxIterations", maxIter);
   plotPeaks->setProperty("Minimizer", minimizer);
   plotPeaks->setProperty("PassWSIndexToFunction", passIndex);
+  plotPeaks->setProperty("PeakRadius", peakRadius);
   plotPeaks->executeAsChildAlg();
   ITableWorkspace_sptr outputWs = plotPeaks->getProperty("OutputWorkspace");
 
diff --git a/Framework/WorkflowAlgorithms/src/DgsConvertToEnergyTransfer.cpp b/Framework/WorkflowAlgorithms/src/DgsConvertToEnergyTransfer.cpp
index 8736a061c97a55188f0462fbf73eb77a23ff26e9..c1871505494a619cd6cd45b8adc255da9aa53464 100644
--- a/Framework/WorkflowAlgorithms/src/DgsConvertToEnergyTransfer.cpp
+++ b/Framework/WorkflowAlgorithms/src/DgsConvertToEnergyTransfer.cpp
@@ -1,6 +1,5 @@
 #include "MantidWorkflowAlgorithms/DgsConvertToEnergyTransfer.h"
 #include "MantidAPI/MatrixWorkspace.h"
-#include "MantidKernel/PropertyManagerDataService.h"
 #include "MantidAPI/Run.h"
 #include "MantidAPI/WorkspaceHistory.h"
 #include "MantidGeometry/IDetector.h"
@@ -11,6 +10,7 @@
 #include "MantidKernel/FacilityInfo.h"
 #include "MantidKernel/ListValidator.h"
 #include "MantidKernel/PropertyManager.h"
+#include "MantidKernel/PropertyManagerDataService.h"
 #include "MantidKernel/RebinParamsValidator.h"
 #include "MantidKernel/System.h"
 #include "MantidKernel/TimeSeriesProperty.h"
@@ -348,6 +348,7 @@ void DgsConvertToEnergyTransfer::exec() {
         rebin->setProperty("OutputWorkspace", origBkgWsName);
         rebin->setProperty("Params", params);
         rebin->setProperty("PreserveEvents", false);
+        rebin->setProperty("IgnoreBinErrors", true);
         rebin->executeAsChildAlg();
         MatrixWorkspace_sptr origBkgWS = rebin->getProperty("OutputWorkspace");
 
@@ -465,6 +466,7 @@ void DgsConvertToEnergyTransfer::exec() {
   rebin->setProperty("InputWorkspace", outputWS);
   rebin->setProperty("OutputWorkspace", outputWS);
   rebin->setProperty("Params", etBinning);
+  rebin->setProperty("IgnoreBinErrors", true);
   rebin->setProperty("PreserveEvents", preserveEvents);
   rebin->executeAsChildAlg();
   outputWS = rebin->getProperty("OutputWorkspace");
@@ -519,6 +521,7 @@ void DgsConvertToEnergyTransfer::exec() {
   g_log.notice() << "Rebinning data\n";
   rebin->setProperty("InputWorkspace", outputWS);
   rebin->setProperty("OutputWorkspace", outputWS);
+  rebin->setProperty("IgnoreBinErrors", true);
   if (sofphieIsDistribution) {
     rebin->setProperty("PreserveEvents", false);
   }
diff --git a/Framework/WorkflowAlgorithms/src/EQSANSDarkCurrentSubtraction.cpp b/Framework/WorkflowAlgorithms/src/EQSANSDarkCurrentSubtraction.cpp
index a4e189b80a076db2e0281436a1bb2d85d4eafdfb..210550da3ac68846261b81aeae64b3fdef146ced 100644
--- a/Framework/WorkflowAlgorithms/src/EQSANSDarkCurrentSubtraction.cpp
+++ b/Framework/WorkflowAlgorithms/src/EQSANSDarkCurrentSubtraction.cpp
@@ -1,5 +1,6 @@
 #include "MantidWorkflowAlgorithms/EQSANSDarkCurrentSubtraction.h"
 #include "MantidDataObjects/EventWorkspace.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/WorkspaceUnitValidator.h"
 #include "MantidKernel/TimeSeriesProperty.h"
 #include "MantidAPI/FileProperty.h"
@@ -117,7 +118,7 @@ void EQSANSDarkCurrentSubtraction::exec() {
 
     std::string darkWSOutputName =
         getPropertyValue("OutputDarkCurrentWorkspace");
-    if (!(darkWSOutputName.size() == 0))
+    if (!darkWSOutputName.empty())
       setProperty("OutputDarkCurrentWorkspace", darkWS);
     AnalysisDataService::Instance().addOrReplace(darkWSName, darkWS);
     reductionManager->declareProperty(Kernel::make_unique<WorkspaceProperty<>>(
diff --git a/Framework/WorkflowAlgorithms/src/EQSANSDarkCurrentSubtraction2.cpp b/Framework/WorkflowAlgorithms/src/EQSANSDarkCurrentSubtraction2.cpp
index fc5db20edebca8719f7efd74f71bdbe43ddafc26..8f0293a96fc1d055974a8b12504a2593bd827b1a 100644
--- a/Framework/WorkflowAlgorithms/src/EQSANSDarkCurrentSubtraction2.cpp
+++ b/Framework/WorkflowAlgorithms/src/EQSANSDarkCurrentSubtraction2.cpp
@@ -1,9 +1,11 @@
 #include "MantidWorkflowAlgorithms/EQSANSDarkCurrentSubtraction2.h"
 #include "MantidDataObjects/EventWorkspace.h"
 #include "MantidAPI/AlgorithmProperty.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/FileProperty.h"
 #include "MantidKernel/PropertyManagerDataService.h"
 #include "MantidAPI/Run.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidAPI/WorkspaceUnitValidator.h"
 #include "MantidGeometry/IDetector.h"
 #include "MantidKernel/PropertyManager.h"
@@ -132,7 +134,7 @@ void EQSANSDarkCurrentSubtraction2::exec() {
 
     std::string darkWSOutputName =
         getPropertyValue("OutputDarkCurrentWorkspace");
-    if (!(darkWSOutputName.size() == 0))
+    if (!darkWSOutputName.empty())
       setProperty("OutputDarkCurrentWorkspace", darkWS);
     AnalysisDataService::Instance().addOrReplace(darkWSName, darkWS);
     reductionManager->declareProperty(Kernel::make_unique<WorkspaceProperty<>>(
@@ -208,11 +210,11 @@ void EQSANSDarkCurrentSubtraction2::exec() {
   }
 
   progress.report("Subtracting dark current");
+  const auto &spectrumInfo = inputWS->spectrumInfo();
   // Loop over all tubes and patch as necessary
   for (int i = 0; i < numberOfSpectra; i++) {
-    IDetector_const_sptr det = inputWS->getDetector(i);
     // If this detector is a monitor, skip to the next one
-    if (det->isMasked())
+    if (spectrumInfo.isMasked(i))
       continue;
 
     const MantidVec &YDarkValues = scaledDarkWS->readY(i);
diff --git a/Framework/WorkflowAlgorithms/src/EQSANSLoad.cpp b/Framework/WorkflowAlgorithms/src/EQSANSLoad.cpp
index 59c6490ef04c5887870946ec662113bb2dd2eb2c..5536ce88c958231de79e1af270742925215dbc01 100644
--- a/Framework/WorkflowAlgorithms/src/EQSANSLoad.cpp
+++ b/Framework/WorkflowAlgorithms/src/EQSANSLoad.cpp
@@ -442,12 +442,12 @@ void EQSANSLoad::exec() {
   // live data reduction (when it's implemented...)
   const std::string fileName = getPropertyValue("Filename");
   EventWorkspace_sptr inputEventWS = getProperty("InputWorkspace");
-  if (fileName.size() == 0 && !inputEventWS) {
+  if (fileName.empty() && !inputEventWS) {
     g_log.error() << "EQSANSLoad input error: Either a valid file path or an "
                      "input workspace must be provided\n";
     throw std::runtime_error("EQSANSLoad input error: Either a valid file path "
                              "or an input workspace must be provided");
-  } else if (fileName.size() > 0 && inputEventWS) {
+  } else if (!fileName.empty() && inputEventWS) {
     g_log.error() << "EQSANSLoad input error: Either a valid file path or an "
                      "input workspace must be provided, but not both\n";
     throw std::runtime_error("EQSANSLoad input error: Either a valid file path "
@@ -607,7 +607,7 @@ void EQSANSLoad::exec() {
 
   // Process the config file
   bool use_config = getProperty("UseConfig");
-  if (use_config && config_file.size() > 0) {
+  if (use_config && !config_file.empty()) {
     // Special case to force reading the beam center from the config file
     // We're adding this to be compatible with the original EQSANS load
     // written in python
diff --git a/Framework/WorkflowAlgorithms/src/EQSANSPatchSensitivity.cpp b/Framework/WorkflowAlgorithms/src/EQSANSPatchSensitivity.cpp
index 9c5c8a0da6e7d04159d97ba958722e3b6689e34b..0e06d4457a2dabc3757bf85b952f7525ac7296e5 100644
--- a/Framework/WorkflowAlgorithms/src/EQSANSPatchSensitivity.cpp
+++ b/Framework/WorkflowAlgorithms/src/EQSANSPatchSensitivity.cpp
@@ -1,10 +1,7 @@
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidWorkflowAlgorithms/EQSANSPatchSensitivity.h"
 #include "MantidAPI/MatrixWorkspace.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidGeometry/Instrument.h"
-#include "MantidGeometry/Instrument/ParameterMap.h"
 #include "MantidKernel/cow_ptr.h"
 
 namespace Mantid {
@@ -40,9 +37,9 @@ void EQSANSPatchSensitivity::exec() {
       inputWS->getInstrument()->getNumberParameter("number-of-y-pixels")[0]);
 
   const int numberOfSpectra = static_cast<int>(inputWS->getNumberHistograms());
-  // Need to get hold of the parameter map
-  Geometry::ParameterMap &pmap = inputWS->instrumentParameters();
 
+  const auto &spectrumInfo = patchWS->spectrumInfo();
+  const auto &inSpectrumInfo = inputWS->spectrumInfo();
   // Loop over all tubes and patch as necessary
   for (int i = 0; i < nx_pixels; i++) {
     std::vector<int> patched_ids;
@@ -65,21 +62,19 @@ void EQSANSPatchSensitivity::exec() {
         continue;
       }
 
-      IDetector_const_sptr det = patchWS->getDetector(iDet);
       // If this detector is a monitor, skip to the next one
-      if (det->isMonitor())
+      if (spectrumInfo.isMonitor(iDet))
         continue;
 
       const MantidVec &YValues = inputWS->readY(iDet);
       const MantidVec &YErrors = inputWS->readE(iDet);
 
       // If this detector is masked, skip to the next one
-      if (det->isMasked())
+      if (spectrumInfo.isMasked(i))
         patched_ids.push_back(iDet);
       else {
-        IDetector_const_sptr sensitivityDet = inputWS->getDetector(iDet);
-        if (!sensitivityDet->isMasked()) {
-          double yPosition = det->getPos().Y();
+        if (!inSpectrumInfo.isMasked(iDet)) {
+          double yPosition = spectrumInfo.position(iDet).Y();
           totalUnmasked += YErrors[0] * YErrors[0] * YValues[0];
           errorUnmasked += YErrors[0] * YErrors[0];
           nUnmasked++;
@@ -104,26 +99,23 @@ void EQSANSPatchSensitivity::exec() {
 
       // Apply patch
       progress(0.91, "Applying patch");
+      auto &spectrumInfo = inputWS->mutableSpectrumInfo();
       for (auto patched_id : patched_ids) {
-        const Geometry::ComponentID det =
-            inputWS->getDetector(patched_id)->getComponentID();
-        try {
-          if (det) {
-            MantidVec &YValues = inputWS->dataY(patched_id);
-            MantidVec &YErrors = inputWS->dataE(patched_id);
-            if (useRegression) {
-              YValues[0] = alpha + beta * det->getPos().Y();
-              YErrors[0] = error;
-            } else {
-              YValues[0] = average;
-              YErrors[0] = error;
-            }
-
-            pmap.addBool(det, "masked", false);
-          }
-        } catch (Kernel::Exception::NotFoundError &e) {
-          g_log.warning() << e.what() << " Found while setting mask bit\n";
+        if (!spectrumInfo.hasDetectors(patched_id)) {
+          g_log.warning() << "Spectrum " << patched_id
+                          << " has no detector, skipping (not clearing mask)\n";
+          continue;
         }
+        MantidVec &YValues = inputWS->dataY(patched_id);
+        MantidVec &YErrors = inputWS->dataE(patched_id);
+        if (useRegression) {
+          YValues[0] = alpha + beta * spectrumInfo.position(patched_id).Y();
+          YErrors[0] = error;
+        } else {
+          YValues[0] = average;
+          YErrors[0] = error;
+        }
+        spectrumInfo.setMasked(patched_id, false);
       }
     }
   }
diff --git a/Framework/WorkflowAlgorithms/src/EQSANSQ2D.cpp b/Framework/WorkflowAlgorithms/src/EQSANSQ2D.cpp
index 32d410265f42cfe2446488701acf2768ca7e3662..3645d5b40ac0cf2b3dd4d2e86b194295ecba11c7 100644
--- a/Framework/WorkflowAlgorithms/src/EQSANSQ2D.cpp
+++ b/Framework/WorkflowAlgorithms/src/EQSANSQ2D.cpp
@@ -45,7 +45,7 @@ void EQSANSQ2D::exec() {
   // If the OutputWorkspace property was not given, use the
   // name of the input workspace as the base name for the output
   std::string outputWSName = getPropertyValue("OutputWorkspace");
-  if (outputWSName.size() == 0) {
+  if (outputWSName.empty()) {
     outputWSName = inputWS->getName();
   }
 
diff --git a/Framework/WorkflowAlgorithms/src/HFIRDarkCurrentSubtraction.cpp b/Framework/WorkflowAlgorithms/src/HFIRDarkCurrentSubtraction.cpp
index 812c1038fd67a9fed29c8d3355d9e48418c379f8..a0f760750bebbf7da06d0b1ca94908c8de101ba1 100644
--- a/Framework/WorkflowAlgorithms/src/HFIRDarkCurrentSubtraction.cpp
+++ b/Framework/WorkflowAlgorithms/src/HFIRDarkCurrentSubtraction.cpp
@@ -83,7 +83,7 @@ void HFIRDarkCurrentSubtraction::exec() {
     output_message += darkWSName + '\n';
   } else {
     // Load the dark current if we don't have it already
-    if (darkWSName.size() == 0) {
+    if (darkWSName.empty()) {
       darkWSName = "__dark_current_" + path.getBaseName();
       setPropertyValue("OutputDarkCurrentWorkspace", darkWSName);
     }
diff --git a/Framework/WorkflowAlgorithms/src/HFIRLoad.cpp b/Framework/WorkflowAlgorithms/src/HFIRLoad.cpp
index 72a933f66a6442994d58a94d517cea37721e15cf..94a950b4293b199fd571d35547e989ee78bda1f1 100644
--- a/Framework/WorkflowAlgorithms/src/HFIRLoad.cpp
+++ b/Framework/WorkflowAlgorithms/src/HFIRLoad.cpp
@@ -5,6 +5,7 @@
 #include "Poco/NumberFormatter.h"
 #include "MantidKernel/BoundedValidator.h"
 #include "MantidAPI/AlgorithmProperty.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidKernel/PropertyManagerDataService.h"
 #include "MantidAPI/FileProperty.h"
 #include "MantidAPI/Run.h"
@@ -176,7 +177,7 @@ void HFIRLoad::exec() {
   AnalysisDataService::Instance().addOrReplace(
       getPropertyValue("OutputWorkspace"), dataWS_tmp);
   g_log.debug() << "Calling LoadSpice2D Done. OutputWorkspace name = "
-                << dataWS_tmp->name() << "\n";
+                << dataWS_tmp->getName() << '\n';
   API::MatrixWorkspace_sptr dataWS =
       boost::dynamic_pointer_cast<MatrixWorkspace>(dataWS_tmp);
 
diff --git a/Framework/WorkflowAlgorithms/src/RefReduction.cpp b/Framework/WorkflowAlgorithms/src/RefReduction.cpp
index fa22f2acedfc6dae7976615db35eb4ae2a0e5322..acc38e5cb3ffbf679fa7b85c3d78d60fda7871a5 100644
--- a/Framework/WorkflowAlgorithms/src/RefReduction.cpp
+++ b/Framework/WorkflowAlgorithms/src/RefReduction.cpp
@@ -1,4 +1,5 @@
 #include "MantidWorkflowAlgorithms/RefReduction.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/FileFinder.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/Run.h"
@@ -477,7 +478,7 @@ IEventWorkspace_sptr RefReduction::loadData(const std::string dataRun,
     // If we can't find a workspace, find a file to load
     std::string path = FileFinder::Instance().getFullPath(dataRun);
 
-    if (path.size() == 0 || !Poco::File(path).exists()) {
+    if (path.empty() || !Poco::File(path).exists()) {
       try {
         std::vector<std::string> paths =
             FileFinder::Instance().findRuns(instrument + dataRun);
@@ -487,7 +488,7 @@ IEventWorkspace_sptr RefReduction::loadData(const std::string dataRun,
       }
     }
 
-    if (path.size() == 0 || !Poco::File(path).exists()) {
+    if (path.empty() || !Poco::File(path).exists()) {
       try {
         std::vector<std::string> paths =
             FileFinder::Instance().findRuns(dataRun);
diff --git a/Framework/WorkflowAlgorithms/src/RefRoi.cpp b/Framework/WorkflowAlgorithms/src/RefRoi.cpp
index 0de6a0ef8271b0f9206d02ebfe86073e4feaa661..83cf7adbeb221270c48b3856826d8a56042d9a52 100644
--- a/Framework/WorkflowAlgorithms/src/RefRoi.cpp
+++ b/Framework/WorkflowAlgorithms/src/RefRoi.cpp
@@ -1,11 +1,9 @@
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidWorkflowAlgorithms/RefRoi.h"
 #include "MantidAPI/Axis.h"
 #include "MantidAPI/CommonBinsValidator.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidDataObjects/EventWorkspace.h"
+#include "MantidKernel/Unit.h"
 #include "MantidKernel/UnitFactory.h"
 #include "Poco/String.h"
 
@@ -77,7 +75,7 @@ void RefRoi::exec() {
   const MatrixWorkspace_const_sptr inputWS = getProperty("InputWorkspace");
   // Bin boundaries need to be the same, so do the full check on whether they
   // actually are
-  if (!API::WorkspaceHelpers::commonBoundaries(inputWS)) {
+  if (!API::WorkspaceHelpers::commonBoundaries(*inputWS)) {
     g_log.error()
         << "Can only group if the histograms have common bin boundaries\n";
     throw std::invalid_argument(
diff --git a/Framework/WorkflowAlgorithms/src/SANSBeamFinder.cpp b/Framework/WorkflowAlgorithms/src/SANSBeamFinder.cpp
index 39d8cf8cb2a923b7df81535a2dd026cabd240dfb..2d76a5e28fc03927271c2bbca62e5ea13a17cb9c 100644
--- a/Framework/WorkflowAlgorithms/src/SANSBeamFinder.cpp
+++ b/Framework/WorkflowAlgorithms/src/SANSBeamFinder.cpp
@@ -1,9 +1,7 @@
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidWorkflowAlgorithms/SANSBeamFinder.h"
 #include "MantidWorkflowAlgorithms/EQSANSInstrument.h"
 #include "MantidWorkflowAlgorithms/HFIRInstrument.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/FileProperty.h"
 #include "MantidAPI/AlgorithmProperty.h"
 #include "MantidKernel/PropertyManagerDataService.h"
@@ -65,7 +63,7 @@ SANSBeamFinder::loadBeamFinderFile(const std::string &beamCenterFile) {
   if (m_reductionManager->existsProperty(entryName)) {
     finderWS = m_reductionManager->getProperty(entryName);
     m_output_message +=
-        "   |Using existing workspace: " + finderWS->name() + '\n';
+        "   |Using existing workspace: " + finderWS->getName() + '\n';
   } else {
     // Load the dark current if we don't have it already
     std::string finderWSName = "__beam_finder_" + path.getBaseName();
diff --git a/Framework/WorkflowAlgorithms/src/SANSBeamFluxCorrection.cpp b/Framework/WorkflowAlgorithms/src/SANSBeamFluxCorrection.cpp
index aafb6853d4c06caeeb784c2a8db4fe219450eb83..a628da8580cd35bcd7dbc36c517c7dd1b21697e7 100644
--- a/Framework/WorkflowAlgorithms/src/SANSBeamFluxCorrection.cpp
+++ b/Framework/WorkflowAlgorithms/src/SANSBeamFluxCorrection.cpp
@@ -1,8 +1,6 @@
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidWorkflowAlgorithms/SANSBeamFluxCorrection.h"
 #include "MantidAPI/AlgorithmProperty.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/FileProperty.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidKernel/PropertyManager.h"
diff --git a/Framework/WorkflowAlgorithms/src/SANSSensitivityCorrection.cpp b/Framework/WorkflowAlgorithms/src/SANSSensitivityCorrection.cpp
index 350d754009aa463fc7d667115201af7ded44f47c..148c1418c4b0b06e821a1fe7d327e5637d7363f1 100644
--- a/Framework/WorkflowAlgorithms/src/SANSSensitivityCorrection.cpp
+++ b/Framework/WorkflowAlgorithms/src/SANSSensitivityCorrection.cpp
@@ -251,7 +251,7 @@ void SANSSensitivityCorrection::exec() {
             darkAlg->execute();
             if (darkAlg->existsProperty("OutputMessage"))
               dark_result = darkAlg->getPropertyValue("OutputMessage");
-          } else if (darkCurrentFile.size() > 0) {
+          } else if (!darkCurrentFile.empty()) {
             darkAlg->setProperty("Filename", darkCurrentFile);
             darkAlg->setProperty("PersistentCorrection", false);
             darkAlg->execute();
@@ -260,7 +260,7 @@ void SANSSensitivityCorrection::exec() {
             else
               dark_result = "   Dark current subtracted\n";
           }
-        } else if (darkCurrentFile.size() > 0) {
+        } else if (!darkCurrentFile.empty()) {
           // We need to subtract the dark current for the flood field but no
           // dark
           // current subtraction was set for the sample! Use the default dark
@@ -356,7 +356,7 @@ void SANSSensitivityCorrection::exec() {
     }
     std::string floodWSOutputName =
         getPropertyValue("OutputSensitivityWorkspace");
-    if (floodWSOutputName.size() == 0) {
+    if (floodWSOutputName.empty()) {
       setPropertyValue("OutputSensitivityWorkspace", floodWSName);
       AnalysisDataService::Instance().addOrReplace(floodWSName, floodWS);
       reductionManager->declareProperty(
diff --git a/Framework/WorkflowAlgorithms/src/SANSSolidAngleCorrection.cpp b/Framework/WorkflowAlgorithms/src/SANSSolidAngleCorrection.cpp
index 5d1452e6baba2bb7c09a6e7d66da2c8bb9c10d37..f6bd3f6a6204b67661b51bbc52bba60d731fc0ab 100644
--- a/Framework/WorkflowAlgorithms/src/SANSSolidAngleCorrection.cpp
+++ b/Framework/WorkflowAlgorithms/src/SANSSolidAngleCorrection.cpp
@@ -1,17 +1,13 @@
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidWorkflowAlgorithms/SANSSolidAngleCorrection.h"
 #include "MantidAPI/AlgorithmProperty.h"
 #include "MantidAPI/HistogramValidator.h"
 #include "MantidKernel/PropertyManagerDataService.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidAPI/WorkspaceUnitValidator.h"
 #include "MantidDataObjects/EventWorkspace.h"
 #include "MantidDataObjects/EventList.h"
 #include "MantidDataObjects/TableWorkspace.h"
-#include "MantidGeometry/IDetector.h"
-#include "MantidGeometry/Instrument.h"
 #include "MantidKernel/CompositeValidator.h"
 #include "MantidKernel/PropertyManager.h"
 
@@ -28,16 +24,11 @@ DECLARE_ALGORITHM(SANSSolidAngleCorrection)
 
 /// Returns the angle between the sample-to-pixel vector and its
 /// projection on the X-Z plane.
-static double getYTubeAngle(const IDetector &det,
-                            const MatrixWorkspace &workspace) {
-
-  // Get the sample position
-  Geometry::IComponent_const_sptr sample =
-      workspace.getInstrument()->getSample();
-  const V3D samplePos = sample->getPos();
+static double getYTubeAngle(const SpectrumInfo &spectrumInfo, size_t i) {
+  const V3D samplePos = spectrumInfo.samplePosition();
 
   // Get the vector from the sample position to the detector pixel
-  V3D sampleDetVec = det.getPos() - samplePos;
+  V3D sampleDetVec = spectrumInfo.position(i) - samplePos;
 
   // Get the projection of that vector on the X-Z plane
   V3D inPlane = V3D(sampleDetVec);
@@ -110,29 +101,20 @@ void SANSSolidAngleCorrection::exec() {
   // Number of X bins
   const int xLength = static_cast<int>(inputWS->readY(0).size());
 
+  const auto &spectrumInfo = inputWS->spectrumInfo();
   PARALLEL_FOR_IF(Kernel::threadSafe(*outputWS, *inputWS))
   for (int i = 0; i < numHists; ++i) {
     PARALLEL_START_INTERUPT_REGION
     outputWS->dataX(i) = inputWS->readX(i);
 
-    IDetector_const_sptr det;
-    try {
-      det = inputWS->getDetector(i);
-    } catch (Exception::NotFoundError &) {
+    if (!spectrumInfo.hasDetectors(i)) {
       g_log.warning() << "Workspace index " << i
                       << " has no detector assigned to it - discarding\n";
-      // Catch if no detector. Next line tests whether this happened - test
-      // placed
-      // outside here because Mac Intel compiler doesn't like 'continue' in a
-      // catch
-      // in an openmp block.
-    }
-    // If no detector found, skip onto the next spectrum
-    if (!det)
       continue;
+    }
 
     // Skip if we have a monitor or if the detector is masked.
-    if (det->isMonitor() || det->isMasked())
+    if (spectrumInfo.isMonitor(i) || spectrumInfo.isMasked(i))
       continue;
 
     const MantidVec &YIn = inputWS->readY(i);
@@ -145,11 +127,11 @@ void SANSSolidAngleCorrection::exec() {
     const bool is_tube = getProperty("DetectorTubes");
     const bool is_wing = getProperty("DetectorWing");
 
-    const double tanTheta = tan(inputWS->detectorTwoTheta(*det));
+    const double tanTheta = tan(spectrumInfo.twoTheta(i));
     const double theta_term = sqrt(tanTheta * tanTheta + 1.0);
     double corr;
     if (is_tube || is_wing) {
-      const double tanAlpha = tan(getYTubeAngle(*det, *inputWS));
+      const double tanAlpha = tan(getYTubeAngle(spectrumInfo, i));
       const double alpha_term = sqrt(tanAlpha * tanAlpha + 1.0);
       if (is_tube)
         corr = alpha_term * theta_term * theta_term;
@@ -188,35 +170,28 @@ void SANSSolidAngleCorrection::execEvent() {
   Progress progress(this, 0.0, 1.0, numberOfSpectra);
   progress.report("Solid Angle Correction");
 
+  const auto &spectrumInfo = outputEventWS->spectrumInfo();
   PARALLEL_FOR_IF(Kernel::threadSafe(*outputEventWS))
   for (int i = 0; i < numberOfSpectra; i++) {
     PARALLEL_START_INTERUPT_REGION
-    IDetector_const_sptr det;
-    try {
-      det = outputEventWS->getDetector(i);
-    } catch (Exception::NotFoundError &) {
+
+    if (!spectrumInfo.hasDetectors(i)) {
       g_log.warning() << "Workspace index " << i
                       << " has no detector assigned to it - discarding\n";
-      // Catch if no detector. Next line tests whether this happened - test
-      // placed
-      // outside here because Mac Intel compiler doesn't like 'continue' in a
-      // catch
-      // in an openmp block.
-    }
-    if (!det)
       continue;
+    }
 
     // Skip if we have a monitor or if the detector is masked.
-    if (det->isMonitor() || det->isMasked())
+    if (spectrumInfo.isMonitor(i) || spectrumInfo.isMasked(i))
       continue;
 
     // Compute solid angle correction factor
     const bool is_tube = getProperty("DetectorTubes");
-    const double tanTheta = tan(outputEventWS->detectorTwoTheta(*det));
+    const double tanTheta = tan(spectrumInfo.twoTheta(i));
     const double theta_term = sqrt(tanTheta * tanTheta + 1.0);
     double corr;
     if (is_tube) {
-      const double tanAlpha = tan(getYTubeAngle(*det, *inputWS));
+      const double tanAlpha = tan(getYTubeAngle(spectrumInfo, i));
       const double alpha_term = sqrt(tanAlpha * tanAlpha + 1.0);
       corr = alpha_term * theta_term * theta_term;
     } else {
diff --git a/Framework/WorkflowAlgorithms/src/SetupEQSANSReduction.cpp b/Framework/WorkflowAlgorithms/src/SetupEQSANSReduction.cpp
index 736a7be6042ccd0293c7ed63b55962424b4e35ad..f221e3d744c04eb29b1f1b038adae7edec8f9a47 100644
--- a/Framework/WorkflowAlgorithms/src/SetupEQSANSReduction.cpp
+++ b/Framework/WorkflowAlgorithms/src/SetupEQSANSReduction.cpp
@@ -580,7 +580,7 @@ void SetupEQSANSReduction::init() {
 void SetupEQSANSReduction::exec() {
   // Reduction property manager
   const std::string reductionManagerName = getProperty("ReductionProperties");
-  if (reductionManagerName.size() == 0) {
+  if (reductionManagerName.empty()) {
     g_log.error() << "ERROR: Reduction Property Manager name is empty\n";
     return;
   }
@@ -619,7 +619,7 @@ void SetupEQSANSReduction::exec() {
     normAlg->setProperty("NormaliseToBeam", false);
   } else if (boost::contains(normalization, "Monitor")) {
     loadMonitors = true;
-    if (monitorRefFile.size() == 0) {
+    if (monitorRefFile.empty()) {
       g_log.error() << "ERROR: normalize-to-monitor was turned ON but no "
                        "reference data was selected\n";
     }
@@ -671,7 +671,7 @@ void SetupEQSANSReduction::exec() {
 
   // Store dark current algorithm
   const std::string darkCurrentFile = getPropertyValue("DarkCurrentFile");
-  if (darkCurrentFile.size() > 0) {
+  if (!darkCurrentFile.empty()) {
     IAlgorithm_sptr darkAlg =
         createChildAlgorithm("EQSANSDarkCurrentSubtraction");
     darkAlg->setProperty("Filename", darkCurrentFile);
@@ -722,7 +722,7 @@ void SetupEQSANSReduction::exec() {
     if (!boost::iequals(centerMethod, "DirectBeam"))
       useDirectBeamMethod = false;
     const std::string beamCenterFile = getProperty("BeamCenterFile");
-    if (beamCenterFile.size() > 0) {
+    if (!beamCenterFile.empty()) {
       const double beamRadius = getProperty("BeamRadius");
 
       IAlgorithm_sptr ctrAlg = createChildAlgorithm("SANSBeamFinder");
@@ -853,7 +853,7 @@ void SetupEQSANSReduction::setupSensitivity(
   const std::string reductionManagerName = getProperty("ReductionProperties");
 
   const std::string sensitivityFile = getPropertyValue("SensitivityFile");
-  if (sensitivityFile.size() > 0) {
+  if (!sensitivityFile.empty()) {
     const bool useSampleDC = getProperty("UseDefaultDC");
     const std::string sensitivityDarkCurrentFile =
         getPropertyValue("SensitivityDarkCurrentFile");
@@ -887,7 +887,7 @@ void SetupEQSANSReduction::setupSensitivity(
       const double sensitivityBeamRadius =
           getProperty("SensitivityBeamCenterRadius");
       bool useDirectBeam = boost::iequals(centerMethod, "DirectBeam");
-      if (beamCenterFile.size() > 0) {
+      if (!beamCenterFile.empty()) {
         IAlgorithm_sptr ctrAlg = createChildAlgorithm("SANSBeamFinder");
         ctrAlg->setProperty("Filename", beamCenterFile);
         ctrAlg->setProperty("UseDirectBeamMethod", useDirectBeam);
@@ -975,7 +975,7 @@ void SetupEQSANSReduction::setupTransmission(
     } else if (boost::iequals(centerMethod, "DirectBeam")) {
       const std::string beamCenterFile =
           getProperty("TransmissionBeamCenterFile");
-      if (beamCenterFile.size() > 0) {
+      if (!beamCenterFile.empty()) {
         IAlgorithm_sptr ctrAlg = createChildAlgorithm("SANSBeamFinder");
         ctrAlg->setProperty("Filename", beamCenterFile);
         ctrAlg->setProperty("UseDirectBeamMethod", true);
@@ -1004,7 +1004,7 @@ void SetupEQSANSReduction::setupBackground(
   const std::string reductionManagerName = getProperty("ReductionProperties");
   // Background
   const std::string backgroundFile = getPropertyValue("BackgroundFiles");
-  if (backgroundFile.size() > 0)
+  if (!backgroundFile.empty())
     reductionManager->declareProperty(
         Kernel::make_unique<PropertyWithValue<std::string>>("BackgroundFiles",
                                                             backgroundFile));
@@ -1066,7 +1066,7 @@ void SetupEQSANSReduction::setupBackground(
     } else if (boost::iequals(centerMethod, "DirectBeam")) {
       const std::string beamCenterFile =
           getProperty("BckTransmissionBeamCenterFile");
-      if (beamCenterFile.size() > 0) {
+      if (!beamCenterFile.empty()) {
         IAlgorithm_sptr ctrAlg = createChildAlgorithm("SANSBeamFinder");
         ctrAlg->setProperty("Filename", beamCenterFile);
         ctrAlg->setProperty("UseDirectBeamMethod", true);
diff --git a/Framework/WorkflowAlgorithms/src/SetupHFIRReduction.cpp b/Framework/WorkflowAlgorithms/src/SetupHFIRReduction.cpp
index 22352ea734293426161bf6389cab1f4b19a979c3..87ad6e0318f1cd0cc1067b8e3899f6b6c7564e63 100644
--- a/Framework/WorkflowAlgorithms/src/SetupHFIRReduction.cpp
+++ b/Framework/WorkflowAlgorithms/src/SetupHFIRReduction.cpp
@@ -629,7 +629,7 @@ void SetupHFIRReduction::init() {
 void SetupHFIRReduction::exec() {
   // Reduction property manager
   const std::string reductionManagerName = getProperty("ReductionProperties");
-  if (reductionManagerName.size() == 0) {
+  if (reductionManagerName.empty()) {
     g_log.error() << "ERROR: Reduction Property Manager name is empty\n";
     return;
   }
@@ -691,7 +691,7 @@ void SetupHFIRReduction::exec() {
     if (!boost::iequals(centerMethod, "DirectBeam"))
       useDirectBeamMethod = false;
     const std::string beamCenterFile = getProperty("BeamCenterFile");
-    if (beamCenterFile.size() > 0) {
+    if (!beamCenterFile.empty()) {
       const double beamRadius = getProperty("BeamRadius");
 
       IAlgorithm_sptr ctrAlg = createChildAlgorithm("SANSBeamFinder");
@@ -713,7 +713,7 @@ void SetupHFIRReduction::exec() {
 
   // Store dark current algorithm
   const std::string darkCurrentFile = getPropertyValue("DarkCurrentFile");
-  if (darkCurrentFile.size() > 0) {
+  if (!darkCurrentFile.empty()) {
     IAlgorithm_sptr darkAlg =
         createChildAlgorithm("HFIRDarkCurrentSubtraction");
     darkAlg->setProperty("Filename", darkCurrentFile);
@@ -890,7 +890,7 @@ void SetupHFIRReduction::setupSensitivity(
   const std::string reductionManagerName = getProperty("ReductionProperties");
 
   const std::string sensitivityFile = getPropertyValue("SensitivityFile");
-  if (sensitivityFile.size() > 0) {
+  if (!sensitivityFile.empty()) {
     const bool useSampleDC = getProperty("UseDefaultDC");
     const std::string sensitivityDarkCurrentFile =
         getPropertyValue("SensitivityDarkCurrentFile");
@@ -945,7 +945,7 @@ void SetupHFIRReduction::setupSensitivity(
       const double sensitivityBeamRadius =
           getProperty("SensitivityBeamCenterRadius");
       bool useDirectBeam = boost::iequals(centerMethod, "DirectBeam");
-      if (beamCenterFile.size() > 0) {
+      if (!beamCenterFile.empty()) {
         IAlgorithm_sptr ctrAlg = createChildAlgorithm("SANSBeamFinder");
         ctrAlg->setProperty("Filename", beamCenterFile);
         ctrAlg->setProperty("UseDirectBeamMethod", useDirectBeam);
@@ -979,7 +979,7 @@ void SetupHFIRReduction::setupBackground(
   const std::string reductionManagerName = getProperty("ReductionProperties");
   // Background
   const std::string backgroundFile = getPropertyValue("BackgroundFiles");
-  if (backgroundFile.size() > 0)
+  if (!backgroundFile.empty())
     reductionManager->declareProperty(
         Kernel::make_unique<PropertyWithValue<std::string>>("BackgroundFiles",
                                                             backgroundFile));
@@ -1037,7 +1037,7 @@ void SetupHFIRReduction::setupBackground(
     } else if (boost::iequals(centerMethod, "DirectBeam")) {
       const std::string beamCenterFile =
           getProperty("BckTransmissionBeamCenterFile");
-      if (beamCenterFile.size() > 0) {
+      if (!beamCenterFile.empty()) {
         IAlgorithm_sptr ctrAlg = createChildAlgorithm("SANSBeamFinder");
         ctrAlg->setProperty("Filename", beamCenterFile);
         ctrAlg->setProperty("UseDirectBeamMethod", true);
@@ -1150,7 +1150,7 @@ void SetupHFIRReduction::setupTransmission(
     } else if (boost::iequals(centerMethod, "DirectBeam")) {
       const std::string beamCenterFile =
           getProperty("TransmissionBeamCenterFile");
-      if (beamCenterFile.size() > 0) {
+      if (!beamCenterFile.empty()) {
         IAlgorithm_sptr ctrAlg = createChildAlgorithm("SANSBeamFinder");
         ctrAlg->setProperty("Filename", beamCenterFile);
         ctrAlg->setProperty("UseDirectBeamMethod", true);
diff --git a/Framework/WorkflowAlgorithms/src/SetupILLD33Reduction.cpp b/Framework/WorkflowAlgorithms/src/SetupILLD33Reduction.cpp
index 3a4297a17addf6045899a4f9308132194d4a28eb..45f57173cdcc0f17969997a63037efad89ab061e 100644
--- a/Framework/WorkflowAlgorithms/src/SetupILLD33Reduction.cpp
+++ b/Framework/WorkflowAlgorithms/src/SetupILLD33Reduction.cpp
@@ -483,7 +483,7 @@ void SetupILLD33Reduction::init() {
 void SetupILLD33Reduction::exec() {
   // Reduction property manager
   const std::string reductionManagerName = getProperty("ReductionProperties");
-  if (reductionManagerName.size() == 0) {
+  if (reductionManagerName.empty()) {
     g_log.error() << "ERROR: Reduction Property Manager name is empty\n";
     return;
   }
@@ -532,7 +532,7 @@ void SetupILLD33Reduction::exec() {
 
   // Store dark current algorithm
   const std::string darkCurrentFile = getPropertyValue("DarkCurrentFile");
-  if (darkCurrentFile.size() > 0) {
+  if (!darkCurrentFile.empty()) {
     IAlgorithm_sptr darkAlg =
         createChildAlgorithm("EQSANSDarkCurrentSubtraction");
     darkAlg->setProperty("Filename", darkCurrentFile);
@@ -583,7 +583,7 @@ void SetupILLD33Reduction::exec() {
     if (!boost::iequals(centerMethod, "DirectBeam"))
       useDirectBeamMethod = false;
     const std::string beamCenterFile = getProperty("BeamCenterFile");
-    if (beamCenterFile.size() > 0) {
+    if (!beamCenterFile.empty()) {
       const double beamRadius = getProperty("BeamRadius");
 
       IAlgorithm_sptr ctrAlg = createChildAlgorithm("SANSBeamFinder");
@@ -703,7 +703,7 @@ void SetupILLD33Reduction::setupSensitivity(
   const std::string reductionManagerName = getProperty("ReductionProperties");
 
   const std::string sensitivityFile = getPropertyValue("SensitivityFile");
-  if (sensitivityFile.size() > 0) {
+  if (!sensitivityFile.empty()) {
     const bool useSampleDC = getProperty("UseDefaultDC");
     const std::string sensitivityDarkCurrentFile =
         getPropertyValue("SensitivityDarkCurrentFile");
@@ -737,7 +737,7 @@ void SetupILLD33Reduction::setupSensitivity(
       const double sensitivityBeamRadius =
           getProperty("SensitivityBeamCenterRadius");
       bool useDirectBeam = boost::iequals(centerMethod, "DirectBeam");
-      if (beamCenterFile.size() > 0) {
+      if (!beamCenterFile.empty()) {
         IAlgorithm_sptr ctrAlg = createChildAlgorithm("SANSBeamFinder");
         ctrAlg->setProperty("Filename", beamCenterFile);
         ctrAlg->setProperty("UseDirectBeamMethod", useDirectBeam);
@@ -824,7 +824,7 @@ void SetupILLD33Reduction::setupTransmission(
     } else if (boost::iequals(centerMethod, "DirectBeam")) {
       const std::string beamCenterFile =
           getProperty("TransmissionBeamCenterFile");
-      if (beamCenterFile.size() > 0) {
+      if (!beamCenterFile.empty()) {
         IAlgorithm_sptr ctrAlg = createChildAlgorithm("SANSBeamFinder");
         ctrAlg->setProperty("Filename", beamCenterFile);
         ctrAlg->setProperty("UseDirectBeamMethod", true);
@@ -854,7 +854,7 @@ void SetupILLD33Reduction::setupBackground(
   const std::string reductionManagerName = getProperty("ReductionProperties");
   // Background
   const std::string backgroundFile = getPropertyValue("BackgroundFiles");
-  if (backgroundFile.size() > 0)
+  if (!backgroundFile.empty())
     reductionManager->declareProperty(
         Kernel::make_unique<PropertyWithValue<std::string>>("BackgroundFiles",
                                                             backgroundFile));
@@ -915,7 +915,7 @@ void SetupILLD33Reduction::setupBackground(
     } else if (boost::iequals(centerMethod, "DirectBeam")) {
       const std::string beamCenterFile =
           getProperty("BckTransmissionBeamCenterFile");
-      if (beamCenterFile.size() > 0) {
+      if (!beamCenterFile.empty()) {
         IAlgorithm_sptr ctrAlg = createChildAlgorithm("SANSBeamFinder");
         ctrAlg->setProperty("Filename", beamCenterFile);
         ctrAlg->setProperty("UseDirectBeamMethod", true);
diff --git a/Framework/WorkflowAlgorithms/test/ConvolutionFitSequentialTest.h b/Framework/WorkflowAlgorithms/test/ConvolutionFitSequentialTest.h
index 3e159495a85da72fc33366e30a8ce05328211a0e..98a519c364c9fc6b9dc58b6add538eb22e6d946e 100644
--- a/Framework/WorkflowAlgorithms/test/ConvolutionFitSequentialTest.h
+++ b/Framework/WorkflowAlgorithms/test/ConvolutionFitSequentialTest.h
@@ -6,6 +6,7 @@
 #include "MantidAPI/Axis.h"
 #include "MantidAPI/FrameworkManager.h"
 #include "MantidAPI/WorkspaceFactory.h"
+#include "MantidAPI/WorkspaceGroup.h"
 
 #include "MantidWorkflowAlgorithms/ConvolutionFitSequential.h"
 
diff --git a/Framework/WorkflowAlgorithms/test/IMuonAsymmetryCalculatorTest.h b/Framework/WorkflowAlgorithms/test/IMuonAsymmetryCalculatorTest.h
index 5cfa3e9ddbba848364b32dfa41a6409e83453ba4..974f8c18ae512048c4a4e7c981b1e408db4941f5 100644
--- a/Framework/WorkflowAlgorithms/test/IMuonAsymmetryCalculatorTest.h
+++ b/Framework/WorkflowAlgorithms/test/IMuonAsymmetryCalculatorTest.h
@@ -620,7 +620,7 @@ private:
   * X values are 1 2 3 for all the histograms.
   */
   MatrixWorkspace_sptr createWorkspace(double delta = 0.0) {
-    MatrixWorkspace_sptr ws = WorkspaceCreationHelper::Create2DWorkspace(3, 3);
+    MatrixWorkspace_sptr ws = WorkspaceCreationHelper::create2DWorkspace(3, 3);
 
     for (size_t i = 0; i < ws->getNumberHistograms(); i++) {
       for (size_t j = 0; j < ws->blocksize(); j++) {
diff --git a/Framework/WorkflowAlgorithms/test/LoadEventAndCompressTest.h b/Framework/WorkflowAlgorithms/test/LoadEventAndCompressTest.h
index a1fc310b9320d0b32d18df80f14eed60b1d7f28d..237b86f7cb1f1d1bdde7c658fb611bcde53d9e12 100644
--- a/Framework/WorkflowAlgorithms/test/LoadEventAndCompressTest.h
+++ b/Framework/WorkflowAlgorithms/test/LoadEventAndCompressTest.h
@@ -3,6 +3,7 @@
 
 #include <cxxtest/TestSuite.h>
 
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/FrameworkManager.h"
 #include "MantidDataObjects/EventWorkspace.h"
 #include "MantidWorkflowAlgorithms/LoadEventAndCompress.h"
diff --git a/Framework/WorkflowAlgorithms/test/ProcessIndirectFitParametersTest.h b/Framework/WorkflowAlgorithms/test/ProcessIndirectFitParametersTest.h
index 8f0ff2aa831e4cb4b76c649b51aaa0c72db417e6..37812f317d4e7865e1a011063606d1283c45869b 100644
--- a/Framework/WorkflowAlgorithms/test/ProcessIndirectFitParametersTest.h
+++ b/Framework/WorkflowAlgorithms/test/ProcessIndirectFitParametersTest.h
@@ -4,6 +4,7 @@
 #include <cxxtest/TestSuite.h>
 
 #include "MantidWorkflowAlgorithms/ProcessIndirectFitParameters.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Axis.h"
 #include "MantidAPI/ITableWorkspace.h"
 #include "MantidAPI/MatrixWorkspace.h"
diff --git a/Framework/WorkflowAlgorithms/test/SANSSolidAngleCorrectionTest.h b/Framework/WorkflowAlgorithms/test/SANSSolidAngleCorrectionTest.h
index 587e563dad215035a2d243b91c67d0ca0c6e9f6e..c5fc3785e3f213f545f0f3db290d0dc39d1af7d9 100644
--- a/Framework/WorkflowAlgorithms/test/SANSSolidAngleCorrectionTest.h
+++ b/Framework/WorkflowAlgorithms/test/SANSSolidAngleCorrectionTest.h
@@ -3,6 +3,7 @@
 
 #include <cxxtest/TestSuite.h>
 #include "MantidWorkflowAlgorithms/SANSSolidAngleCorrection.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Axis.h"
 #include "MantidKernel/Unit.h"
 #include "MantidDataHandling/LoadSpice2D.h"
diff --git a/Framework/WorkflowAlgorithms/test/StepScanTest.h b/Framework/WorkflowAlgorithms/test/StepScanTest.h
index 62c431cade068d46b0ce938c37b799eb5d4636b2..9d84dffaff703b91740dd7b3cc517a4c692a8027 100644
--- a/Framework/WorkflowAlgorithms/test/StepScanTest.h
+++ b/Framework/WorkflowAlgorithms/test/StepScanTest.h
@@ -33,7 +33,7 @@ public:
     dummy.version();
     // End of dummy code
 
-    inputWS = WorkspaceCreationHelper::CreateEventWorkspace2(3, 1);
+    inputWS = WorkspaceCreationHelper::createEventWorkspace2(3, 1);
     inputWS->getAxis(0)->unit() = UnitFactory::Instance().create("TOF");
     auto scan_index = new TimeSeriesProperty<int>("scan_index");
     scan_index->addValue("2010-01-01T00:00:00", 0);
diff --git a/MantidPlot/CMakeLists.txt b/MantidPlot/CMakeLists.txt
index 5662d5fb874524cf0feed00ceba335b173793931..a1d7876115902434aa4bfc02ade405afdc709dc2 100644
--- a/MantidPlot/CMakeLists.txt
+++ b/MantidPlot/CMakeLists.txt
@@ -90,6 +90,7 @@ set ( QTIPLOT_SRCS src/ApplicationWindow.cpp
                    src/PluginFit.cpp
                    src/PolynomFitDialog.cpp
                    src/PolynomialFit.cpp
+                   src/ProjectSaveView.cpp
                    src/ProjectSerialiser.cpp
                    src/PythonScript.cpp
                    src/PythonScripting.cpp
@@ -286,7 +287,8 @@ set ( QTIPLOT_HDRS src/ApplicationWindow.h
                    src/PluginFit.h
                    src/PolynomFitDialog.h
                    src/PolynomialFit.h
-		    src/ProjectSerialiser.h
+                   src/ProjectSerialiser.h
+                   src/ProjectSaveView.h
                    src/PythonScript.h
                    src/PythonScripting.h
                    src/QwtBarCurve.h
@@ -534,6 +536,8 @@ set ( QTIPLOT_MOC_FILES src/ApplicationWindow.h
                         src/PluginFit.h
                         src/PolynomFitDialog.h
                         src/PolynomialFit.h
+                        src/ProjectSaveView.h
+                        src/ProjectSerialiser.h
                         src/PythonScript.h
                         src/PythonScripting.h
                         src/QwtPieCurve.h
@@ -612,6 +616,7 @@ set ( MANTID_MOC_FILES src/Mantid/AlgorithmDockWidget.h
 )
 
 set ( UI_FILES src/SendToProgramDialog.ui
+               src/ProjectSave.ui
                src/Mantid/FirstTimeSetup.ui
                src/Mantid/UserFitFunctionDialog.ui
                src/Mantid/MantidAbout.ui
diff --git a/MantidPlot/make_package.rb.in b/MantidPlot/make_package.rb.in
index b3680e75b70e92ede43c563f6198befc8513c0f2..593b4d0e7eecd0f10e25131938a5c3fe0f5ee74a 100755
--- a/MantidPlot/make_package.rb.in
+++ b/MantidPlot/make_package.rb.in
@@ -295,7 +295,7 @@ end
 #Copy over python libraries not included with OSX. 
 #currently missing epics
 path = "/Library/Python/2.7/site-packages"
-directories = ["sphinx","sphinx_bootstrap_theme","IPython","zmq","pygments","backports","certifi","tornado","markupsafe","jinja2","psutil","jsonschema","functools32","ptyprocess","CifFile"]
+directories = ["sphinx","sphinx_bootstrap_theme","IPython","zmq","pygments","backports","certifi","tornado","markupsafe","jinja2","psutil","jsonschema","functools32","ptyprocess","CifFile","yaml"]
 directories.each do |directory|
   addPythonLibrary("#{path}/#{directory}","Contents/MacOS/")
 end
@@ -347,7 +347,7 @@ end
 copyOptionalFile("#{path}/mistune.so")
 
 `mkdir Contents/MacOS/bin`
-`cp /usr/local/bin/ipython Contents/MacOS/bin/`
+`cp /usr/local/bin/ipython@PYTHON_VERSION_MAJOR@ Contents/MacOS/bin/`
 
 #Lastly check for any libraries in the package linking against homebrew libraries.
 search_patterns.each do |pattern|
diff --git a/MantidPlot/pymantidplot/proxies.py b/MantidPlot/pymantidplot/proxies.py
index b05f474738ec2b3da1b1eca8b1255197183553a6..af6af6cf95c2a5cb7db50c02c2d86b36dfdad943 100644
--- a/MantidPlot/pymantidplot/proxies.py
+++ b/MantidPlot/pymantidplot/proxies.py
@@ -303,7 +303,7 @@ class Layer(QtProxyObject):
         if isinstance(args[0],str):
             return threadsafe_call(self._getHeldObject().insertCurve, *args)
         elif hasattr(args[0], 'getName'):
-            return threadsafe_call(self._getHeldObject().insertCurve, args[0].getName(),*args[1:])
+            return threadsafe_call(self._getHeldObject().insertCurve, args[0].name(),*args[1:])
         else:
             return threadsafe_call(self._getHeldObject().insertCurve, args[0]._getHeldObject(),*args[1:])
 
@@ -763,7 +763,7 @@ def getWorkspaceNames(source):
         for w in source:
             names = getWorkspaceNames(w)
             ws_names += names
-    elif hasattr(source, 'getName'):
+    elif hasattr(source, 'name'):
         if hasattr(source, '_getHeldObject'):
             wspace = source._getHeldObject()
         else:
@@ -773,10 +773,10 @@ def getWorkspaceNames(source):
         if hasattr(wspace, 'getNames'):
             grp_names = wspace.getNames()
             for n in grp_names:
-                if n != wspace.getName():
+                if n != wspace.name():
                     ws_names.append(n)
         else:
-            ws_names.append(wspace.getName())
+            ws_names.append(wspace.name())
     elif isinstance(source,str):
         w = None
         try:
@@ -803,7 +803,7 @@ class ProxyCompositePeaksPresenter(QtProxyObject):
         if isinstance(source, str):
             to_present = source
         elif isinstance(source, mantid.api.Workspace):
-            to_present = source.getName()
+            to_present = source.name()
         else:
             raise ValueError("getPeaksPresenter expects a Workspace name or a Workspace object.")
         if not mantid.api.mtd.doesExist(to_present):
diff --git a/MantidPlot/src/ApplicationWindow.cpp b/MantidPlot/src/ApplicationWindow.cpp
index 8e469c1f9ac39bbbaa666d475f6e2fc9cff1a9b3..0ff02c08f4e59c78f4430df11519998d3fdae2ae 100644
--- a/MantidPlot/src/ApplicationWindow.cpp
+++ b/MantidPlot/src/ApplicationWindow.cpp
@@ -133,6 +133,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <cassert>
+#include <iostream>
 
 #include <qwt_scale_engine.h>
 #include <QColorGroup>
@@ -188,7 +189,6 @@
 #include "Mantid/ManageInterfaceCategories.h"
 #include "Mantid/FirstTimeSetup.h"
 
-#include "MantidQtAPI/FileDialogHandler.h"
 #include "MantidQtAPI/InterfaceManager.h"
 #include "MantidQtAPI/UserSubWindow.h"
 #include "MantidQtAPI/AlgorithmInputHistory.h"
@@ -201,6 +201,7 @@
 #include "MantidQtMantidWidgets/FitPropertyBrowser.h"
 #include "MantidQtMantidWidgets/MessageDisplay.h"
 #include "MantidQtMantidWidgets/MuonFitPropertyBrowser.h"
+#include "MantidQtMantidWidgets/TrackedAction.h"
 
 #include "MantidKernel/ConfigService.h"
 #include "MantidKernel/FacilityInfo.h"
@@ -3629,7 +3630,7 @@ MdiSubWindow *ApplicationWindow::window(const QString &name) {
 }
 
 Table *ApplicationWindow::table(const QString &name) {
-  int pos = name.lastIndexOf("_");
+  int pos = name.indexOf("_");
   QString caption = name.left(pos);
 
   Folder *f = projectFolder();
@@ -5321,6 +5322,22 @@ void ApplicationWindow::readSettings() {
     g_log.warning() << tr(mess.toAscii()).toStdString() << "\n";
     settings.setValue("/DuplicationDialogShown", true);
   }
+
+  // Mantid Muon interface one time only change
+  settings.beginGroup("/CustomInterfaces");
+  settings.beginGroup("/MuonAnalysis");
+  if (!settings.contains("/UpdateForPlotPolicy1")) {
+    settings.setValue("/UpdateForPlotPolicy1", "true");
+    settings.beginGroup("/GeneralOptions");
+    if (settings.value("/newPlotPolicy", 0).toInt() == 0) {
+      settings.setValue("/newPlotPolicy", 1);
+      settings.setValue("/fitsToKeep", 0);
+    }
+    settings.endGroup();
+  }
+  settings.endGroup();
+  settings.endGroup();
+  // END Mantid Muon interface one time only change
 }
 
 void ApplicationWindow::saveSettings() {
@@ -5939,13 +5956,11 @@ std::string ApplicationWindow::windowGeometryInfo(MdiSubWindow *w) {
   }
 
   tsv << x << y;
-  if (w->status() != MdiSubWindow::Minimized)
-    tsv << w->width() << w->height();
-  else
-    tsv << w->minRestoreSize().width() << w->minRestoreSize().height()
-        << "minimized";
+  tsv << w->width() << w->height();
 
-  if (hidden(w))
+  if (w->status() == MdiSubWindow::Minimized)
+    tsv << "minimized";
+  else if (hidden(w))
     tsv << "hidden";
   else if (w == activeWindow())
     tsv << "active";
@@ -6015,7 +6030,7 @@ bool ApplicationWindow::saveProject(bool compress) {
   }
 
   ProjectSerialiser serialiser(this);
-  serialiser.save(projectFolder(), projectname, compress);
+  serialiser.save(projectname, compress);
 
   setWindowTitle("MantidPlot - " + projectname);
   savedProject();
@@ -6034,12 +6049,68 @@ bool ApplicationWindow::saveProject(bool compress) {
   return true;
 }
 
+void ApplicationWindow::prepareSaveProject() {
+  std::vector<IProjectSerialisable *> windows;
+
+  for (auto window : getSerialisableWindows()) {
+    auto win = dynamic_cast<IProjectSerialisable *>(window);
+    if (win)
+      windows.push_back(win);
+  }
+
+  for (auto window : windowsList()) {
+    auto win = dynamic_cast<IProjectSerialisable *>(window);
+    if (win)
+      windows.push_back(win);
+  }
+
+  auto serialiser = new ProjectSerialiser(this, currentFolder());
+  m_projectSaveView = new MantidQt::MantidWidgets::ProjectSaveView(
+      projectname, *serialiser, windows, this);
+  connect(m_projectSaveView, SIGNAL(projectSaved()), this,
+          SLOT(postSaveProject()));
+  m_projectSaveView->show();
+}
+
+/**
+ * The project was just saved. Update the main window.
+ */
+void ApplicationWindow::postSaveProject() {
+  setWindowTitle("MantidPlot - " + projectname);
+
+  if (autoSave) {
+    if (savingTimerId)
+      killTimer(savingTimerId);
+    savingTimerId = startTimer(autoSaveTime * 60000);
+  } else
+    savingTimerId = 0;
+
+  // Back-up file to be removed because file has successfully saved.
+  QFile::remove(projectname + "~");
+
+  QApplication::restoreOverrideCursor();
+
+  recentProjects.removeAll(projectname);
+  recentProjects.push_front(projectname);
+  updateRecentProjectsList();
+
+  QFileInfo fi(projectname);
+  QString baseName = fi.baseName();
+  FolderListItem *item = dynamic_cast<FolderListItem *>(folders->firstChild());
+  if (item) {
+    item->setText(0, baseName);
+    item->folder()->setObjectName(baseName);
+  }
+
+  savedProject();
+}
+
 void ApplicationWindow::savetoNexusFile() {
   QString filter = tr("Mantid Files") + " (*.nxs *.nx5 *.xml);;";
   QString selectedFilter;
   QString fileDir =
       MantidQt::API::AlgorithmInputHistory::Instance().getPreviousDirectory();
-  QString fileName = MantidQt::API::FileDialogHandler::getSaveFileName(
+  QString fileName = QFileDialog::getSaveFileName(
       this, tr("Save File As"), fileDir, filter, &selectedFilter);
   if (!fileName.isEmpty()) {
     std::string wsName;
@@ -6087,6 +6158,9 @@ void ApplicationWindow::loadDataFileByName(QString fn) {
   if (fnInfo.suffix() == "py") {
     // We have a python file, just load it into script window
     loadScript(fn, true);
+  } else if (fnInfo.suffix() == "mantid") {
+    // We have a mantid project file, pass on to project loading
+    open(fn);
   } else if (mantidUI) {
     // Run Load algorithm on file
     QHash<QString, QString> params;
@@ -6102,8 +6176,8 @@ void ApplicationWindow::saveProjectAs(const QString &fileName, bool compress) {
     filter += tr("Compressed MantidPlot project") + " (*.mantid.gz)";
 
     QString selectedFilter;
-    fn = MantidQt::API::FileDialogHandler::getSaveFileName(
-        this, tr("Save Project As"), workingDir, filter, &selectedFilter);
+    fn = QFileDialog::getSaveFileName(this, tr("Save Project As"), workingDir,
+                                      filter, &selectedFilter);
     if (selectedFilter.contains(".gz"))
       compress = true;
   }
@@ -6477,10 +6551,10 @@ void ApplicationWindow::exportASCII(const QString &tableName,
     return;
 
   QString selectedFilter;
-  QString fname = MantidQt::API::FileDialogHandler::getSaveFileName(
-      this, tr("Choose a filename to save under"),
-      asciiDirPath + "/" + w->objectName(), "*.txt;;*.dat;;*.DAT",
-      &selectedFilter);
+  QString fname =
+      QFileDialog::getSaveFileName(this, tr("Choose a filename to save under"),
+                                   asciiDirPath + "/" + w->objectName(),
+                                   "*.txt;;*.dat;;*.DAT", &selectedFilter);
   if (!fname.isEmpty()) {
     QFileInfo fi(fname);
     QString baseName = fi.fileName();
@@ -7614,7 +7688,7 @@ void ApplicationWindow::exportPDF() {
     return;
   }
 
-  QString fname = MantidQt::API::FileDialogHandler::getSaveFileName(
+  QString fname = QFileDialog::getSaveFileName(
       this, tr("Choose a filename to save under"), workingDir, "*.pdf");
   if (!fname.isEmpty()) {
     QFileInfo fi(fname);
@@ -9075,6 +9149,32 @@ void ApplicationWindow::closeWindow(MdiSubWindow *window) {
   emit modified();
 }
 
+/**
+ * Called when the user choses to close the program
+ */
+void ApplicationWindow::prepareToCloseMantid() {
+  if (!saved) {
+    QString savemsg =
+        tr("Save changes to project: <p><b> %1 </b> ?").arg(projectname);
+    int result =
+        QMessageBox::information(this, tr("MantidPlot"), savemsg, tr("Yes"),
+                                 tr("No"), tr("Cancel"), 0, 2);
+    if (result == 0) {
+      prepareSaveProject();
+      // When we're finished saving trigger the close event
+      connect(m_projectSaveView, SIGNAL(finished(int)), qApp,
+              SLOT(closeAllWindows()));
+      return;
+    } else if (result == 2) {
+      // User wanted to cancel, do nothing
+      return;
+    }
+  }
+
+  // Call to close all the windows and shutdown Mantid
+  QApplication::closeAllWindows();
+}
+
 /** Add a serialisable window to the application
  * @param window :: the window to add
  */
@@ -9575,7 +9675,6 @@ void ApplicationWindow::newProject(const bool doNotSave) {
   folders->blockSignals(false);
 
   // Reset everything else
-  resultsLog->clear();
   setWindowTitle(tr("MantidPlot - untitled")); // Mantid
   projectname = "untitled";
 
@@ -9661,18 +9760,6 @@ void ApplicationWindow::closeEvent(QCloseEvent *ce) {
     // script is running.
   }
 
-  if (!saved) {
-    QString savemsg =
-        tr("Save changes to project: <p><b> %1 </b> ?").arg(projectname);
-    int result =
-        QMessageBox::information(this, tr("MantidPlot"), savemsg, tr("Yes"),
-                                 tr("No"), tr("Cancel"), 0, 2);
-    if (result == 2 || (result == 0 && !saveProject())) {
-      ce->ignore();
-      return;
-    }
-  }
-
   // Close the remaining MDI windows. The Python API is required to be active
   // when the MDI window destructor is called so that those references can be
   // cleaned up meaning we cannot rely on the deleteLater functionality to
@@ -11470,126 +11557,134 @@ void ApplicationWindow::setPlot3DOptions() {
 }
 
 void ApplicationWindow::createActions() {
-  actionCustomActionDialog = new QAction(tr("Manage Custom Menus..."), this);
+  actionCustomActionDialog = new MantidQt::MantidWidgets::TrackedAction(
+      tr("Manage Custom Menus..."), this);
   connect(actionCustomActionDialog, SIGNAL(triggered()), this,
           SLOT(showCustomActionDialog()));
 
-  actionManageDirs = new QAction(QIcon(getQPixmap("managefolders_xpm")),
-                                 tr("Manage User Directories"), this);
+  actionManageDirs = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("managefolders_xpm")), tr("Manage User Directories"),
+      this);
   connect(actionManageDirs, SIGNAL(triggered()), this,
           SLOT(showUserDirectoryDialog()));
 
-  actionFirstTimeSetup = new QAction(tr("First Time Setup"), this);
+  actionFirstTimeSetup =
+      new MantidQt::MantidWidgets::TrackedAction(tr("First Time Setup"), this);
   connect(actionFirstTimeSetup, SIGNAL(triggered()), this,
           SLOT(showFirstTimeSetup()));
 
-  actionNewProject =
-      new QAction(QIcon(":/NewProject16x16.png"), tr("New &Project"), this);
+  actionNewProject = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(":/NewProject16x16.png"), tr("New &Project"), this);
   actionNewProject->setShortcut(tr("Ctrl+N"));
   connect(actionNewProject, SIGNAL(triggered()), this, SLOT(newProject()));
 
-  actionSaveProject =
-      new QAction(QIcon(":/SaveProject16x16.png"), tr("Save &Project"), this);
+  actionSaveProject = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(":/SaveProject16x16.png"), tr("Save &Project"), this);
   actionSaveProject->setShortcut(tr("Ctrl+Shift+S"));
-  connect(actionSaveProject, SIGNAL(triggered()), this, SLOT(saveProject()));
+  connect(actionSaveProject, SIGNAL(triggered()), this,
+          SLOT(prepareSaveProject()));
 
-  actionSaveFile = new QAction(QIcon(getQPixmap("filesave_nexus_xpm")),
-                               tr("Save Nexus &File"), this);
+  actionSaveFile = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("filesave_nexus_xpm")), tr("Save Nexus &File"), this);
   actionSaveFile->setShortcut(tr("Ctrl+S"));
   connect(actionSaveFile, SIGNAL(triggered()), this, SLOT(savetoNexusFile()));
 
-  actionNewGraph =
-      new QAction(QIcon(getQPixmap("new_graph_xpm")), tr("New &Graph"), this);
+  actionNewGraph = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("new_graph_xpm")), tr("New &Graph"), this);
   actionNewGraph->setShortcut(tr("Ctrl+G"));
   connect(actionNewGraph, SIGNAL(triggered()), this, SLOT(newGraph()));
 
-  actionNewNote =
-      new QAction(QIcon(getQPixmap("new_note_xpm")), tr("New &Note"), this);
+  actionNewNote = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("new_note_xpm")), tr("New &Note"), this);
   connect(actionNewNote, SIGNAL(triggered()), this, SLOT(newNote()));
 
-  actionNewTable =
-      new QAction(QIcon(getQPixmap("table_xpm")), tr("New &Table"), this);
+  actionNewTable = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("table_xpm")), tr("New &Table"), this);
   actionNewTable->setShortcut(tr("Ctrl+T"));
   connect(actionNewTable, SIGNAL(triggered()), this, SLOT(newTable()));
 
-  actionNewTiledWindow = new QAction(QIcon(getQPixmap("tiledwindow_xpm")),
-                                     tr("New Tiled &Window"), this);
+  actionNewTiledWindow = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("tiledwindow_xpm")), tr("New Tiled &Window"), this);
   actionNewTiledWindow->setShortcut(tr("Ctrl+Shift+T"));
   connect(actionNewTiledWindow, SIGNAL(triggered()), this,
           SLOT(newTiledWindow()));
 
-  actionNewMatrix =
-      new QAction(QIcon(getQPixmap("new_matrix_xpm")), tr("New &Matrix"), this);
+  actionNewMatrix = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("new_matrix_xpm")), tr("New &Matrix"), this);
   actionNewMatrix->setShortcut(tr("Ctrl+M"));
   connect(actionNewMatrix, SIGNAL(triggered()), this, SLOT(newMatrix()));
 
-  actionNewFunctionPlot = new QAction(QIcon(getQPixmap("newF_xpm")),
-                                      tr("New &Function Plot"), this);
+  actionNewFunctionPlot = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("newF_xpm")), tr("New &Function Plot"), this);
   connect(actionNewFunctionPlot, SIGNAL(triggered()), this,
           SLOT(functionDialog()));
 
-  actionNewSurfacePlot = new QAction(QIcon(getQPixmap("newFxy_xpm")),
-                                     tr("New 3D &Surface Plot"), this);
+  actionNewSurfacePlot = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("newFxy_xpm")), tr("New 3D &Surface Plot"), this);
   actionNewSurfacePlot->setShortcut(tr("Ctrl+ALT+Z"));
   connect(actionNewSurfacePlot, SIGNAL(triggered()), this,
           SLOT(newSurfacePlot()));
 
-  actionOpenProj =
-      new QAction(QIcon(":/LoadProject16x16.png"), tr("&Project"), this);
+  actionOpenProj = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(":/LoadProject16x16.png"), tr("&Project"), this);
   actionOpenProj->setShortcut(tr("Ctrl+Shift+O"));
   connect(actionOpenProj, SIGNAL(triggered()), this, SLOT(open()));
 
-  actionLoadFile =
-      new QAction(QIcon(":/Open-icon16x16.png"), tr("Data File"), this);
+  actionLoadFile = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(":/Open-icon16x16.png"), tr("Data File"), this);
   actionLoadFile->setShortcut(tr("Ctrl+Shift+F"));
   connect(actionLoadFile, SIGNAL(triggered()), this, SLOT(loadDataFile()));
 
-  actionLoadImage = new QAction(tr("Open Image &File"), this);
+  actionLoadImage =
+      new MantidQt::MantidWidgets::TrackedAction(tr("Open Image &File"), this);
   actionLoadImage->setShortcut(tr("Ctrl+I"));
   connect(actionLoadImage, SIGNAL(triggered()), this, SLOT(loadImage()));
 
-  actionScriptRepo = new QAction(tr("Script Repositor&y"), this);
+  actionScriptRepo = new MantidQt::MantidWidgets::TrackedAction(
+      tr("Script Repositor&y"), this);
   connect(actionScriptRepo, SIGNAL(triggered()), this, SLOT(loadScriptRepo()));
 
-  actionImportImage = new QAction(tr("Import I&mage..."), this);
+  actionImportImage =
+      new MantidQt::MantidWidgets::TrackedAction(tr("Import I&mage..."), this);
   connect(actionImportImage, SIGNAL(triggered()), this, SLOT(importImage()));
 
-  actionSaveProjectAs = new QAction(QIcon(":/SaveProject16x16.png"),
-                                    tr("Save Project &As..."), this);
+  actionSaveProjectAs = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(":/SaveProject16x16.png"), tr("Save Project &As..."), this);
   connect(actionSaveProjectAs, SIGNAL(triggered()), this,
-          SLOT(saveProjectAs()));
+          SLOT(prepareSaveProject()));
   actionSaveProjectAs->setEnabled(false);
 
-  actionSaveNote = new QAction(tr("Save Note As..."), this);
+  actionSaveNote =
+      new MantidQt::MantidWidgets::TrackedAction(tr("Save Note As..."), this);
   connect(actionSaveNote, SIGNAL(triggered()), this, SLOT(saveNoteAs()));
 
-  actionLoad = new QAction(QIcon(getQPixmap("import_xpm")),
-                           tr("&Import ASCII..."), this);
+  actionLoad = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("import_xpm")), tr("&Import ASCII..."), this);
   connect(actionLoad, SIGNAL(triggered()), this, SLOT(importASCII()));
 
-  actionCopyWindow =
-      new QAction(QIcon(getQPixmap("duplicate_xpm")), tr("&Duplicate"), this);
+  actionCopyWindow = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("duplicate_xpm")), tr("&Duplicate"), this);
   connect(actionCopyWindow, SIGNAL(triggered()), this, SLOT(clone()));
 
-  actionCutSelection =
-      new QAction(QIcon(getQPixmap("cut_xpm")), tr("Cu&t Selection"), this);
+  actionCutSelection = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("cut_xpm")), tr("Cu&t Selection"), this);
   actionCutSelection->setShortcut(tr("Ctrl+X"));
   connect(actionCutSelection, SIGNAL(triggered()), this, SLOT(cutSelection()));
 
-  actionCopySelection =
-      new QAction(QIcon(getQPixmap("copy_xpm")), tr("&Copy Selection"), this);
+  actionCopySelection = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("copy_xpm")), tr("&Copy Selection"), this);
   actionCopySelection->setShortcut(tr("Ctrl+C"));
   connect(actionCopySelection, SIGNAL(triggered()), this,
           SLOT(copySelection()));
 
-  actionPasteSelection =
-      new QAction(QIcon(getQPixmap("paste_xpm")), tr("&Paste Selection"), this);
+  actionPasteSelection = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("paste_xpm")), tr("&Paste Selection"), this);
   actionPasteSelection->setShortcut(tr("Ctrl+V"));
   connect(actionPasteSelection, SIGNAL(triggered()), this,
           SLOT(pasteSelection()));
 
-  actionClearSelection = new QAction(QIcon(getQPixmap("erase_xpm")),
-                                     tr("&Delete Selection"), this);
+  actionClearSelection = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("erase_xpm")), tr("&Delete Selection"), this);
   actionClearSelection->setShortcut(tr("Del", "delete key"));
   connect(actionClearSelection, SIGNAL(triggered()), this,
           SLOT(clearSelection()));
@@ -11602,8 +11697,8 @@ void ApplicationWindow::createActions() {
   actionShowLog->setIcon(getQPixmap("log_xpm"));
 
 #ifdef SCRIPTING_PYTHON
-  actionShowScriptWindow =
-      new QAction(getQPixmap("python_xpm"), tr("Toggle &Script Window"), this);
+  actionShowScriptWindow = new MantidQt::MantidWidgets::TrackedAction(
+      getQPixmap("python_xpm"), tr("Toggle &Script Window"), this);
 #ifdef __APPLE__
   actionShowScriptWindow->setShortcut(
       tr("Ctrl+3")); // F3 is used by the window manager on Mac
@@ -11614,7 +11709,7 @@ void ApplicationWindow::createActions() {
   connect(actionShowScriptWindow, SIGNAL(triggered()), this,
           SLOT(showScriptWindow()));
 
-  actionShowScriptInterpreter = new QAction(
+  actionShowScriptInterpreter = new MantidQt::MantidWidgets::TrackedAction(
       getQPixmap("python_xpm"), tr("Toggle Script &Interpreter"), this);
 #ifdef __APPLE__
   actionShowScriptInterpreter->setShortcut(
@@ -11627,783 +11722,891 @@ void ApplicationWindow::createActions() {
           SLOT(showScriptInterpreter()));
 #endif
 
-  actionAddLayer =
-      new QAction(QIcon(getQPixmap("newLayer_xpm")), tr("Add La&yer"), this);
+  actionAddLayer = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("newLayer_xpm")), tr("Add La&yer"), this);
   actionAddLayer->setShortcut(tr("Alt+L"));
   connect(actionAddLayer, SIGNAL(triggered()), this, SLOT(addLayer()));
 
-  actionShowLayerDialog = new QAction(QIcon(getQPixmap("arrangeLayers_xpm")),
-                                      tr("Arran&ge Layers"), this);
+  actionShowLayerDialog = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("arrangeLayers_xpm")), tr("Arran&ge Layers"), this);
   actionShowLayerDialog->setShortcut(tr("Alt+A"));
   connect(actionShowLayerDialog, SIGNAL(triggered()), this,
           SLOT(showLayerDialog()));
 
-  actionAutomaticLayout = new QAction(QIcon(getQPixmap("auto_layout_xpm")),
-                                      tr("Automatic Layout"), this);
+  actionAutomaticLayout = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("auto_layout_xpm")), tr("Automatic Layout"), this);
   connect(actionAutomaticLayout, SIGNAL(triggered()), this,
           SLOT(autoArrangeLayers()));
 
-  actionExportGraph = new QAction(tr("&Current"), this);
+  actionExportGraph =
+      new MantidQt::MantidWidgets::TrackedAction(tr("&Current"), this);
   actionExportGraph->setShortcut(tr("Alt+G"));
   connect(actionExportGraph, SIGNAL(triggered()), this, SLOT(exportGraph()));
 
-  actionExportAllGraphs = new QAction(tr("&All"), this);
+  actionExportAllGraphs =
+      new MantidQt::MantidWidgets::TrackedAction(tr("&All"), this);
   actionExportAllGraphs->setShortcut(tr("Alt+X"));
   connect(actionExportAllGraphs, SIGNAL(triggered()), this,
           SLOT(exportAllGraphs()));
 
-  actionExportPDF =
-      new QAction(QIcon(getQPixmap("pdf_xpm")), tr("&Export PDF"), this);
+  actionExportPDF = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("pdf_xpm")), tr("&Export PDF"), this);
   actionExportPDF->setShortcut(tr("Ctrl+Alt+P"));
   connect(actionExportPDF, SIGNAL(triggered()), this, SLOT(exportPDF()));
 
-  actionPrint =
-      new QAction(QIcon(getQPixmap("fileprint_xpm")), tr("&Print"), this);
+  actionPrint = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("fileprint_xpm")), tr("&Print"), this);
   actionPrint->setShortcut(tr("Ctrl+P"));
   connect(actionPrint, SIGNAL(triggered()), this, SLOT(print()));
 
-  actionPrintAllPlots = new QAction(tr("Print All Plo&ts"), this);
+  actionPrintAllPlots =
+      new MantidQt::MantidWidgets::TrackedAction(tr("Print All Plo&ts"), this);
   connect(actionPrintAllPlots, SIGNAL(triggered()), this,
           SLOT(printAllPlots()));
 
-  actionShowExportASCIIDialog = new QAction(tr("E&xport ASCII"), this);
+  actionShowExportASCIIDialog =
+      new MantidQt::MantidWidgets::TrackedAction(tr("E&xport ASCII"), this);
   connect(actionShowExportASCIIDialog, SIGNAL(triggered()), this,
           SLOT(showExportASCIIDialog()));
 
-  actionCloseAllWindows =
-      new QAction(QIcon(getQPixmap("quit_xpm")), tr("&Quit"), this);
+  actionCloseAllWindows = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("quit_xpm")), tr("&Quit"), this);
   actionCloseAllWindows->setShortcut(tr("Ctrl+Q"));
-  connect(actionCloseAllWindows, SIGNAL(triggered()), qApp,
-          SLOT(closeAllWindows()));
+  connect(actionCloseAllWindows, SIGNAL(triggered()), this,
+          SLOT(prepareToCloseMantid()));
 
-  actionDeleteFitTables = new QAction(QIcon(getQPixmap("close_xpm")),
-                                      tr("Delete &Fit Tables"), this);
+  actionDeleteFitTables = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("close_xpm")), tr("Delete &Fit Tables"), this);
   connect(actionDeleteFitTables, SIGNAL(triggered()), this,
           SLOT(deleteFitTables()));
 
-  actionShowPlotWizard =
-      new QAction(QIcon(getQPixmap("wizard_xpm")), tr("Plot &Wizard"), this);
+  actionShowPlotWizard = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("wizard_xpm")), tr("Plot &Wizard"), this);
   actionShowPlotWizard->setShortcut(tr("Ctrl+Alt+W"));
   connect(actionShowPlotWizard, SIGNAL(triggered()), this,
           SLOT(showPlotWizard()));
 
-  actionShowConfigureDialog =
-      new QAction(QIcon(":/configure.png"), tr("&Preferences..."), this);
+  actionShowConfigureDialog = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(":/configure.png"), tr("&Preferences..."), this);
   connect(actionShowConfigureDialog, SIGNAL(triggered()), this,
           SLOT(showPreferencesDialog()));
 
-  actionShowCurvesDialog = new QAction(QIcon(getQPixmap("curves_xpm")),
-                                       tr("Add/Remove &Curve..."), this);
+  actionShowCurvesDialog = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("curves_xpm")), tr("Add/Remove &Curve..."), this);
   actionShowCurvesDialog->setShortcut(tr("Ctrl+Alt+C"));
   connect(actionShowCurvesDialog, SIGNAL(triggered()), this,
           SLOT(showCurvesDialog()));
 
-  actionAddErrorBars = new QAction(QIcon(getQPixmap("errors_xpm")),
-                                   tr("Add &Error Bars..."), this);
+  actionAddErrorBars = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("errors_xpm")), tr("Add &Error Bars..."), this);
   actionAddErrorBars->setShortcut(tr("Ctrl+Alt+E"));
   connect(actionAddErrorBars, SIGNAL(triggered()), this, SLOT(addErrorBars()));
 
-  actionRemoveErrorBars = new QAction(QIcon(getQPixmap("errors_remove_xpm")),
-                                      tr("&Remove Error Bars..."), this);
+  actionRemoveErrorBars = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("errors_remove_xpm")), tr("&Remove Error Bars..."),
+      this);
   actionRemoveErrorBars->setShortcut(tr("Ctrl+Alt+R"));
   connect(actionRemoveErrorBars, SIGNAL(triggered()), this,
           SLOT(removeErrorBars()));
 
-  actionAddFunctionCurve =
-      new QAction(QIcon(getQPixmap("fx_xpm")), tr("Add &Function..."), this);
+  actionAddFunctionCurve = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("fx_xpm")), tr("Add &Function..."), this);
   actionAddFunctionCurve->setShortcut(tr("Ctrl+Alt+F"));
   connect(actionAddFunctionCurve, SIGNAL(triggered()), this,
           SLOT(addFunctionCurve()));
 
-  actionUnzoom = new QAction(QIcon(getQPixmap("unzoom_xpm")),
-                             tr("&Rescale to Show All"), this);
+  actionUnzoom = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("unzoom_xpm")), tr("&Rescale to Show All"), this);
   actionUnzoom->setShortcut(tr("Ctrl+Shift+R"));
   connect(actionUnzoom, SIGNAL(triggered()), this, SLOT(setAutoScale()));
 
-  actionNewLegend =
-      new QAction(QIcon(getQPixmap("legend_xpm")), tr("New &Legend"), this);
+  actionNewLegend = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("legend_xpm")), tr("New &Legend"), this);
   actionNewLegend->setShortcut(tr("Ctrl+Alt+L"));
   connect(actionNewLegend, SIGNAL(triggered()), this, SLOT(newLegend()));
 
-  actionTimeStamp =
-      new QAction(QIcon(getQPixmap("clock_xpm")), tr("Add Time &Stamp"), this);
+  actionTimeStamp = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("clock_xpm")), tr("Add Time &Stamp"), this);
   actionTimeStamp->setShortcut(tr("Ctrl+ALT+S"));
   connect(actionTimeStamp, SIGNAL(triggered()), this, SLOT(addTimeStamp()));
 
-  actionAddImage =
-      new QAction(QIcon(getQPixmap("monalisa_xpm")), tr("Add &Image"), this);
+  actionAddImage = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("monalisa_xpm")), tr("Add &Image"), this);
   actionAddImage->setShortcut(tr("Ctrl+Alt+I"));
   connect(actionAddImage, SIGNAL(triggered()), this, SLOT(addImage()));
 
-  actionPlotL = new QAction(QIcon(getQPixmap("lPlot_xpm")), tr("&Line"), this);
+  actionPlotL = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("lPlot_xpm")), tr("&Line"), this);
   connect(actionPlotL, SIGNAL(triggered()), this, SLOT(plotL()));
 
-  actionPlotP =
-      new QAction(QIcon(getQPixmap("pPlot_xpm")), tr("&Scatter"), this);
+  actionPlotP = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("pPlot_xpm")), tr("&Scatter"), this);
   connect(actionPlotP, SIGNAL(triggered()), this, SLOT(plotP()));
 
-  actionPlotLP =
-      new QAction(QIcon(getQPixmap("lpPlot_xpm")), tr("Line + S&ymbol"), this);
+  actionPlotLP = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("lpPlot_xpm")), tr("Line + S&ymbol"), this);
   connect(actionPlotLP, SIGNAL(triggered()), this, SLOT(plotLP()));
 
-  actionPlotVerticalDropLines = new QAction(QIcon(getQPixmap("dropLines_xpm")),
-                                            tr("Vertical &Drop Lines"), this);
+  actionPlotVerticalDropLines = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("dropLines_xpm")), tr("Vertical &Drop Lines"), this);
   connect(actionPlotVerticalDropLines, SIGNAL(triggered()), this,
           SLOT(plotVerticalDropLines()));
 
-  actionPlotSpline =
-      new QAction(QIcon(getQPixmap("spline_xpm")), tr("&Spline"), this);
+  actionPlotSpline = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("spline_xpm")), tr("&Spline"), this);
   connect(actionPlotSpline, SIGNAL(triggered()), this, SLOT(plotSpline()));
 
-  actionPlotHorSteps =
-      new QAction(getQPixmap("hor_steps_xpm"), tr("&Horizontal Steps"), this);
+  actionPlotHorSteps = new MantidQt::MantidWidgets::TrackedAction(
+      getQPixmap("hor_steps_xpm"), tr("&Horizontal Steps"), this);
   connect(actionPlotHorSteps, SIGNAL(triggered()), this, SLOT(plotHorSteps()));
 
-  actionPlotVertSteps = new QAction(QIcon(getQPixmap("vert_steps_xpm")),
-                                    tr("&Vertical Steps"), this);
+  actionPlotVertSteps = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("vert_steps_xpm")), tr("&Vertical Steps"), this);
   connect(actionPlotVertSteps, SIGNAL(triggered()), this,
           SLOT(plotVertSteps()));
 
-  actionPlotVerticalBars =
-      new QAction(QIcon(getQPixmap("vertBars_xpm")), tr("&Columns"), this);
+  actionPlotVerticalBars = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("vertBars_xpm")), tr("&Columns"), this);
   connect(actionPlotVerticalBars, SIGNAL(triggered()), this,
           SLOT(plotVerticalBars()));
 
-  actionPlotHorizontalBars =
-      new QAction(QIcon(getQPixmap("hBars_xpm")), tr("&Rows"), this);
+  actionPlotHorizontalBars = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("hBars_xpm")), tr("&Rows"), this);
   connect(actionPlotHorizontalBars, SIGNAL(triggered()), this,
           SLOT(plotHorizontalBars()));
 
-  actionPlotArea =
-      new QAction(QIcon(getQPixmap("area_xpm")), tr("&Area"), this);
+  actionPlotArea = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("area_xpm")), tr("&Area"), this);
   connect(actionPlotArea, SIGNAL(triggered()), this, SLOT(plotArea()));
 
-  actionPlotPie = new QAction(QIcon(getQPixmap("pie_xpm")), tr("&Pie"), this);
+  actionPlotPie = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("pie_xpm")), tr("&Pie"), this);
   connect(actionPlotPie, SIGNAL(triggered()), this, SLOT(plotPie()));
 
-  actionPlotVectXYAM =
-      new QAction(QIcon(getQPixmap("vectXYAM_xpm")), tr("Vectors XY&AM"), this);
+  actionPlotVectXYAM = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("vectXYAM_xpm")), tr("Vectors XY&AM"), this);
   connect(actionPlotVectXYAM, SIGNAL(triggered()), this, SLOT(plotVectXYAM()));
 
-  actionPlotVectXYXY = new QAction(QIcon(getQPixmap("vectXYXY_xpm")),
-                                   tr("&Vectors &XYXY"), this);
+  actionPlotVectXYXY = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("vectXYXY_xpm")), tr("&Vectors &XYXY"), this);
   connect(actionPlotVectXYXY, SIGNAL(triggered()), this, SLOT(plotVectXYXY()));
 
-  actionPlotHistogram =
-      new QAction(QIcon(getQPixmap("histogram_xpm")), tr("&Histogram"), this);
+  actionPlotHistogram = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("histogram_xpm")), tr("&Histogram"), this);
   connect(actionPlotHistogram, SIGNAL(triggered()), this,
           SLOT(plotHistogram()));
 
-  actionPlotStackedHistograms = new QAction(
+  actionPlotStackedHistograms = new MantidQt::MantidWidgets::TrackedAction(
       QIcon(getQPixmap("stacked_hist_xpm")), tr("&Stacked Histogram"), this);
   connect(actionPlotStackedHistograms, SIGNAL(triggered()), this,
           SLOT(plotStackedHistograms()));
 
-  actionStemPlot =
-      new QAction(QIcon(":/leaf.png"), tr("Stem-and-&Leaf Plot"), this);
+  actionStemPlot = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(":/leaf.png"), tr("Stem-and-&Leaf Plot"), this);
   connect(actionStemPlot, SIGNAL(triggered()), this, SLOT(newStemPlot()));
 
-  actionPlot2VerticalLayers = new QAction(QIcon(getQPixmap("panel_v2_xpm")),
-                                          tr("&Vertical 2 Layers"), this);
+  actionPlot2VerticalLayers = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("panel_v2_xpm")), tr("&Vertical 2 Layers"), this);
   connect(actionPlot2VerticalLayers, SIGNAL(triggered()), this,
           SLOT(plot2VerticalLayers()));
 
-  actionPlot2HorizontalLayers = new QAction(QIcon(getQPixmap("panel_h2_xpm")),
-                                            tr("&Horizontal 2 Layers"), this);
+  actionPlot2HorizontalLayers = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("panel_h2_xpm")), tr("&Horizontal 2 Layers"), this);
   connect(actionPlot2HorizontalLayers, SIGNAL(triggered()), this,
           SLOT(plot2HorizontalLayers()));
 
-  actionPlot4Layers =
-      new QAction(QIcon(getQPixmap("panel_4_xpm")), tr("&4 Layers"), this);
+  actionPlot4Layers = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("panel_4_xpm")), tr("&4 Layers"), this);
   connect(actionPlot4Layers, SIGNAL(triggered()), this, SLOT(plot4Layers()));
 
-  actionPlotStackedLayers = new QAction(QIcon(getQPixmap("stacked_xpm")),
-                                        tr("&Stacked Layers"), this);
+  actionPlotStackedLayers = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("stacked_xpm")), tr("&Stacked Layers"), this);
   connect(actionPlotStackedLayers, SIGNAL(triggered()), this,
           SLOT(plotStackedLayers()));
 
-  actionPlot3DRibbon =
-      new QAction(QIcon(getQPixmap("ribbon_xpm")), tr("&Ribbon"), this);
+  actionPlot3DRibbon = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("ribbon_xpm")), tr("&Ribbon"), this);
   connect(actionPlot3DRibbon, SIGNAL(triggered()), this, SLOT(plot3DRibbon()));
 
-  actionPlot3DBars =
-      new QAction(QIcon(getQPixmap("bars_xpm")), tr("&Bars"), this);
+  actionPlot3DBars = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("bars_xpm")), tr("&Bars"), this);
   connect(actionPlot3DBars, SIGNAL(triggered()), this, SLOT(plot3DBars()));
 
-  actionPlot3DScatter =
-      new QAction(QIcon(getQPixmap("scatter_xpm")), tr("&Scatter"), this);
+  actionPlot3DScatter = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("scatter_xpm")), tr("&Scatter"), this);
   connect(actionPlot3DScatter, SIGNAL(triggered()), this,
           SLOT(plot3DScatter()));
 
-  actionPlot3DTrajectory =
-      new QAction(QIcon(getQPixmap("trajectory_xpm")), tr("&Trajectory"), this);
+  actionPlot3DTrajectory = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("trajectory_xpm")), tr("&Trajectory"), this);
   connect(actionPlot3DTrajectory, SIGNAL(triggered()), this,
           SLOT(plot3DTrajectory()));
 
-  actionShowColStatistics = new QAction(QIcon(getQPixmap("col_stat_xpm")),
-                                        tr("Statistics on &Columns"), this);
+  actionShowColStatistics = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("col_stat_xpm")), tr("Statistics on &Columns"), this);
   connect(actionShowColStatistics, SIGNAL(triggered()), this,
           SLOT(showColStatistics()));
 
-  actionShowRowStatistics = new QAction(QIcon(getQPixmap("stat_rows_xpm")),
-                                        tr("Statistics on &Rows"), this);
+  actionShowRowStatistics = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("stat_rows_xpm")), tr("Statistics on &Rows"), this);
   connect(actionShowRowStatistics, SIGNAL(triggered()), this,
           SLOT(showRowStatistics()));
 
-  actionIntegrate = new QAction(tr("&Integrate"), this);
+  actionIntegrate =
+      new MantidQt::MantidWidgets::TrackedAction(tr("&Integrate"), this);
   connect(actionIntegrate, SIGNAL(triggered()), this, SLOT(integrate()));
 
-  actionShowIntDialog = new QAction(tr("Integr&ate Function..."), this);
+  actionShowIntDialog = new MantidQt::MantidWidgets::TrackedAction(
+      tr("Integr&ate Function..."), this);
   connect(actionShowIntDialog, SIGNAL(triggered()), this,
           SLOT(showIntegrationDialog()));
 
-  actionInterpolate = new QAction(tr("Inte&rpolate ..."), this);
+  actionInterpolate =
+      new MantidQt::MantidWidgets::TrackedAction(tr("Inte&rpolate ..."), this);
   connect(actionInterpolate, SIGNAL(triggered()), this,
           SLOT(showInterpolationDialog()));
 
-  actionLowPassFilter = new QAction(tr("&Low Pass..."), this);
+  actionLowPassFilter =
+      new MantidQt::MantidWidgets::TrackedAction(tr("&Low Pass..."), this);
   connect(actionLowPassFilter, SIGNAL(triggered()), this,
           SLOT(lowPassFilterDialog()));
 
-  actionHighPassFilter = new QAction(tr("&High Pass..."), this);
+  actionHighPassFilter =
+      new MantidQt::MantidWidgets::TrackedAction(tr("&High Pass..."), this);
   connect(actionHighPassFilter, SIGNAL(triggered()), this,
           SLOT(highPassFilterDialog()));
 
-  actionBandPassFilter = new QAction(tr("&Band Pass..."), this);
+  actionBandPassFilter =
+      new MantidQt::MantidWidgets::TrackedAction(tr("&Band Pass..."), this);
   connect(actionBandPassFilter, SIGNAL(triggered()), this,
           SLOT(bandPassFilterDialog()));
 
-  actionBandBlockFilter = new QAction(tr("&Band Block..."), this);
+  actionBandBlockFilter =
+      new MantidQt::MantidWidgets::TrackedAction(tr("&Band Block..."), this);
   connect(actionBandBlockFilter, SIGNAL(triggered()), this,
           SLOT(bandBlockFilterDialog()));
 
-  actionFFT = new QAction(tr("&FFT..."), this);
+  actionFFT = new MantidQt::MantidWidgets::TrackedAction(tr("&FFT..."), this);
   connect(actionFFT, SIGNAL(triggered()), this, SLOT(showFFTDialog()));
 
-  actionSmoothSavGol = new QAction(tr("&Savitzky-Golay..."), this);
+  actionSmoothSavGol = new MantidQt::MantidWidgets::TrackedAction(
+      tr("&Savitzky-Golay..."), this);
   connect(actionSmoothSavGol, SIGNAL(triggered()), this,
           SLOT(showSmoothSavGolDialog()));
 
-  actionSmoothFFT = new QAction(tr("&FFT Filter..."), this);
+  actionSmoothFFT =
+      new MantidQt::MantidWidgets::TrackedAction(tr("&FFT Filter..."), this);
   connect(actionSmoothFFT, SIGNAL(triggered()), this,
           SLOT(showSmoothFFTDialog()));
 
-  actionSmoothAverage = new QAction(tr("Moving Window &Average..."), this);
+  actionSmoothAverage = new MantidQt::MantidWidgets::TrackedAction(
+      tr("Moving Window &Average..."), this);
   connect(actionSmoothAverage, SIGNAL(triggered()), this,
           SLOT(showSmoothAverageDialog()));
 
-  actionDifferentiate = new QAction(tr("&Differentiate"), this);
+  actionDifferentiate =
+      new MantidQt::MantidWidgets::TrackedAction(tr("&Differentiate"), this);
   connect(actionDifferentiate, SIGNAL(triggered()), this,
           SLOT(differentiate()));
 
-  actionFitLinear = new QAction(tr("Fit &Linear"), this);
+  actionFitLinear =
+      new MantidQt::MantidWidgets::TrackedAction(tr("Fit &Linear"), this);
   connect(actionFitLinear, SIGNAL(triggered()), this, SLOT(fitLinear()));
 
-  actionShowFitPolynomDialog = new QAction(tr("Fit &Polynomial ..."), this);
+  actionShowFitPolynomDialog = new MantidQt::MantidWidgets::TrackedAction(
+      tr("Fit &Polynomial ..."), this);
   connect(actionShowFitPolynomDialog, SIGNAL(triggered()), this,
           SLOT(showFitPolynomDialog()));
 
-  actionShowExpDecayDialog = new QAction(tr("&First Order ..."), this);
+  actionShowExpDecayDialog =
+      new MantidQt::MantidWidgets::TrackedAction(tr("&First Order ..."), this);
   connect(actionShowExpDecayDialog, SIGNAL(triggered()), this,
           SLOT(showExpDecayDialog()));
 
-  actionShowTwoExpDecayDialog = new QAction(tr("&Second Order ..."), this);
+  actionShowTwoExpDecayDialog =
+      new MantidQt::MantidWidgets::TrackedAction(tr("&Second Order ..."), this);
   connect(actionShowTwoExpDecayDialog, SIGNAL(triggered()), this,
           SLOT(showTwoExpDecayDialog()));
 
-  actionShowExpDecay3Dialog = new QAction(tr("&Third Order ..."), this);
+  actionShowExpDecay3Dialog =
+      new MantidQt::MantidWidgets::TrackedAction(tr("&Third Order ..."), this);
   connect(actionShowExpDecay3Dialog, SIGNAL(triggered()), this,
           SLOT(showExpDecay3Dialog()));
 
-  actionFitExpGrowth = new QAction(tr("Fit Exponential Gro&wth ..."), this);
+  actionFitExpGrowth = new MantidQt::MantidWidgets::TrackedAction(
+      tr("Fit Exponential Gro&wth ..."), this);
   connect(actionFitExpGrowth, SIGNAL(triggered()), this,
           SLOT(showExpGrowthDialog()));
 
-  actionFitSigmoidal = new QAction(tr("Fit &Boltzmann (Sigmoidal)"), this);
+  actionFitSigmoidal = new MantidQt::MantidWidgets::TrackedAction(
+      tr("Fit &Boltzmann (Sigmoidal)"), this);
   connect(actionFitSigmoidal, SIGNAL(triggered()), this, SLOT(fitSigmoidal()));
 
-  actionFitGauss = new QAction(tr("Fit &Gaussian"), this);
+  actionFitGauss =
+      new MantidQt::MantidWidgets::TrackedAction(tr("Fit &Gaussian"), this);
   connect(actionFitGauss, SIGNAL(triggered()), this, SLOT(fitGauss()));
 
-  actionFitLorentz = new QAction(tr("Fit Lorent&zian"), this);
+  actionFitLorentz =
+      new MantidQt::MantidWidgets::TrackedAction(tr("Fit Lorent&zian"), this);
   connect(actionFitLorentz, SIGNAL(triggered()), this, SLOT(fitLorentz()));
 
-  actionShowFitDialog = new QAction(tr("Fit &Wizard..."), this);
+  actionShowFitDialog =
+      new MantidQt::MantidWidgets::TrackedAction(tr("Fit &Wizard..."), this);
   actionShowFitDialog->setShortcut(tr("Ctrl+Y"));
   connect(actionShowFitDialog, SIGNAL(triggered()), this,
           SLOT(showFitDialog()));
 
-  actionShowPlotDialog = new QAction(tr("&Plot ..."), this);
+  actionShowPlotDialog =
+      new MantidQt::MantidWidgets::TrackedAction(tr("&Plot ..."), this);
   connect(actionShowPlotDialog, SIGNAL(triggered()), this,
           SLOT(showGeneralPlotDialog()));
 
-  actionShowScaleDialog = new QAction(tr("&Scales..."), this);
+  actionShowScaleDialog =
+      new MantidQt::MantidWidgets::TrackedAction(tr("&Scales..."), this);
   connect(actionShowScaleDialog, SIGNAL(triggered()), this,
           SLOT(showScaleDialog()));
 
-  actionShowAxisDialog = new QAction(tr("&Axes..."), this);
+  actionShowAxisDialog =
+      new MantidQt::MantidWidgets::TrackedAction(tr("&Axes..."), this);
   connect(actionShowAxisDialog, SIGNAL(triggered()), this,
           SLOT(showAxisDialog()));
 
-  actionShowGridDialog = new QAction(tr("&Grid ..."), this);
+  actionShowGridDialog =
+      new MantidQt::MantidWidgets::TrackedAction(tr("&Grid ..."), this);
   connect(actionShowGridDialog, SIGNAL(triggered()), this,
           SLOT(showGridDialog()));
 
-  actionShowTitleDialog = new QAction(tr("&Title ..."), this);
+  actionShowTitleDialog =
+      new MantidQt::MantidWidgets::TrackedAction(tr("&Title ..."), this);
   connect(actionShowTitleDialog, SIGNAL(triggered()), this,
           SLOT(showTitleDialog()));
 
-  actionShowColumnOptionsDialog = new QAction(tr("Column &Options ..."), this);
+  actionShowColumnOptionsDialog = new MantidQt::MantidWidgets::TrackedAction(
+      tr("Column &Options ..."), this);
   actionShowColumnOptionsDialog->setShortcut(tr("Ctrl+Alt+O"));
   connect(actionShowColumnOptionsDialog, SIGNAL(triggered()), this,
           SLOT(showColumnOptionsDialog()));
 
-  actionShowColumnValuesDialog = new QAction(
+  actionShowColumnValuesDialog = new MantidQt::MantidWidgets::TrackedAction(
       QIcon(getQPixmap("formula_xpm")), tr("Set Column &Values ..."), this);
   connect(actionShowColumnValuesDialog, SIGNAL(triggered()), this,
           SLOT(showColumnValuesDialog()));
   actionShowColumnValuesDialog->setShortcut(tr("Alt+Q"));
 
-  actionTableRecalculate = new QAction(tr("Recalculate"), this);
+  actionTableRecalculate =
+      new MantidQt::MantidWidgets::TrackedAction(tr("Recalculate"), this);
   actionTableRecalculate->setShortcut(tr("Ctrl+Return"));
   connect(actionTableRecalculate, SIGNAL(triggered()), this,
           SLOT(recalculateTable()));
 
-  actionHideSelectedColumns = new QAction(tr("&Hide Selected"), this);
+  actionHideSelectedColumns =
+      new MantidQt::MantidWidgets::TrackedAction(tr("&Hide Selected"), this);
   connect(actionHideSelectedColumns, SIGNAL(triggered()), this,
           SLOT(hideSelectedColumns()));
 
-  actionShowAllColumns = new QAction(tr("Sho&w All Columns"), this);
+  actionShowAllColumns =
+      new MantidQt::MantidWidgets::TrackedAction(tr("Sho&w All Columns"), this);
   connect(actionShowAllColumns, SIGNAL(triggered()), this,
           SLOT(showAllColumns()));
 
-  actionSwapColumns = new QAction(QIcon(getQPixmap("swap_columns_xpm")),
-                                  tr("&Swap columns"), this);
+  actionSwapColumns = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("swap_columns_xpm")), tr("&Swap columns"), this);
   connect(actionSwapColumns, SIGNAL(triggered()), this, SLOT(swapColumns()));
 
-  actionMoveColRight = new QAction(QIcon(getQPixmap("move_col_right_xpm")),
-                                   tr("Move &Right"), this);
+  actionMoveColRight = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("move_col_right_xpm")), tr("Move &Right"), this);
   connect(actionMoveColRight, SIGNAL(triggered()), this,
           SLOT(moveColumnRight()));
 
-  actionMoveColLeft = new QAction(QIcon(getQPixmap("move_col_left_xpm")),
-                                  tr("Move &Left"), this);
+  actionMoveColLeft = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("move_col_left_xpm")), tr("Move &Left"), this);
   connect(actionMoveColLeft, SIGNAL(triggered()), this, SLOT(moveColumnLeft()));
 
-  actionMoveColFirst = new QAction(QIcon(getQPixmap("move_col_first_xpm")),
-                                   tr("Move to F&irst"), this);
+  actionMoveColFirst = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("move_col_first_xpm")), tr("Move to F&irst"), this);
   connect(actionMoveColFirst, SIGNAL(triggered()), this,
           SLOT(moveColumnFirst()));
 
-  actionMoveColLast = new QAction(QIcon(getQPixmap("move_col_last_xpm")),
-                                  tr("Move to Las&t"), this);
+  actionMoveColLast = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("move_col_last_xpm")), tr("Move to Las&t"), this);
   connect(actionMoveColLast, SIGNAL(triggered()), this, SLOT(moveColumnLast()));
 
-  actionShowColsDialog = new QAction(tr("&Columns..."), this);
+  actionShowColsDialog =
+      new MantidQt::MantidWidgets::TrackedAction(tr("&Columns..."), this);
   connect(actionShowColsDialog, SIGNAL(triggered()), this,
           SLOT(showColsDialog()));
 
-  actionShowRowsDialog = new QAction(tr("&Rows..."), this);
+  actionShowRowsDialog =
+      new MantidQt::MantidWidgets::TrackedAction(tr("&Rows..."), this);
   connect(actionShowRowsDialog, SIGNAL(triggered()), this,
           SLOT(showRowsDialog()));
 
-  actionDeleteRows = new QAction(tr("&Delete Rows Interval..."), this);
+  actionDeleteRows = new MantidQt::MantidWidgets::TrackedAction(
+      tr("&Delete Rows Interval..."), this);
   connect(actionDeleteRows, SIGNAL(triggered()), this,
           SLOT(showDeleteRowsDialog()));
 
-  actionAbout = new QAction(tr("&About MantidPlot"), this); // Mantid
+  actionAbout = new MantidQt::MantidWidgets::TrackedAction(
+      tr("&About MantidPlot"), this); // Mantid
   actionAbout->setShortcut(tr("F1"));
   connect(actionAbout, SIGNAL(triggered()), this, SLOT(about()));
 
-  actionShowHelp = new QAction(tr("&Help"), this);
+  actionShowHelp =
+      new MantidQt::MantidWidgets::TrackedAction(tr("&Help"), this);
   actionShowHelp->setShortcut(tr("Ctrl+H"));
   connect(actionShowHelp, SIGNAL(triggered()), this, SLOT(showHelp()));
 
-  actionMantidConcepts = new QAction(tr("&Mantid Concepts"), this);
+  actionMantidConcepts =
+      new MantidQt::MantidWidgets::TrackedAction(tr("&Mantid Concepts"), this);
   connect(actionMantidConcepts, SIGNAL(triggered()), this,
           SLOT(showMantidConcepts()));
 
-  actionMantidAlgorithms = new QAction(tr("&Algorithm Descriptions"), this);
+  actionMantidAlgorithms = new MantidQt::MantidWidgets::TrackedAction(
+      tr("&Algorithm Descriptions"), this);
   connect(actionMantidAlgorithms, SIGNAL(triggered()), this,
           SLOT(showalgorithmDescriptions()));
 
-  actionmantidplotHelp = new QAction(tr("&MantidPlot Help"), this);
+  actionmantidplotHelp =
+      new MantidQt::MantidWidgets::TrackedAction(tr("&MantidPlot Help"), this);
   connect(actionmantidplotHelp, SIGNAL(triggered()), this,
           SLOT(showmantidplotHelp()));
 
-  actionChooseHelpFolder = new QAction(tr("&Choose Help Folder..."), this);
+  actionChooseHelpFolder = new MantidQt::MantidWidgets::TrackedAction(
+      tr("&Choose Help Folder..."), this);
   connect(actionChooseHelpFolder, SIGNAL(triggered()), this,
           SLOT(chooseHelpFolder()));
 
-  actionRename = new QAction(tr("&Rename Window"), this);
+  actionRename =
+      new MantidQt::MantidWidgets::TrackedAction(tr("&Rename Window"), this);
   connect(actionRename, SIGNAL(triggered()), this, SLOT(rename()));
 
-  actionCloseWindow =
-      new QAction(QIcon(getQPixmap("close_xpm")), tr("Close &Window"), this);
+  actionCloseWindow = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("close_xpm")), tr("Close &Window"), this);
   actionCloseWindow->setShortcut(tr("Ctrl+W"));
   connect(actionCloseWindow, SIGNAL(triggered()), this,
           SLOT(closeActiveWindow()));
 
-  actionAddColToTable =
-      new QAction(QIcon(getQPixmap("addCol_xpm")), tr("Add Column"), this);
+  actionAddColToTable = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("addCol_xpm")), tr("Add Column"), this);
   connect(actionAddColToTable, SIGNAL(triggered()), this,
           SLOT(addColToTable()));
 
-  actionGoToRow = new QAction(tr("&Go to Row..."), this);
+  actionGoToRow =
+      new MantidQt::MantidWidgets::TrackedAction(tr("&Go to Row..."), this);
   actionGoToRow->setShortcut(tr("Ctrl+Alt+G"));
   connect(actionGoToRow, SIGNAL(triggered()), this, SLOT(goToRow()));
 
-  actionGoToColumn = new QAction(tr("Go to Colum&n..."), this);
+  actionGoToColumn =
+      new MantidQt::MantidWidgets::TrackedAction(tr("Go to Colum&n..."), this);
   actionGoToColumn->setShortcut(tr("Ctrl+Alt+C"));
   connect(actionGoToColumn, SIGNAL(triggered()), this, SLOT(goToColumn()));
 
-  actionClearTable = new QAction(getQPixmap("erase_xpm"), tr("Clear"), this);
+  actionClearTable = new MantidQt::MantidWidgets::TrackedAction(
+      getQPixmap("erase_xpm"), tr("Clear"), this);
   connect(actionClearTable, SIGNAL(triggered()), this, SLOT(clearTable()));
 
-  actionDeleteLayer =
-      new QAction(QIcon(getQPixmap("erase_xpm")), tr("&Remove Layer"), this);
+  actionDeleteLayer = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("erase_xpm")), tr("&Remove Layer"), this);
   actionDeleteLayer->setShortcut(tr("Alt+R"));
   connect(actionDeleteLayer, SIGNAL(triggered()), this, SLOT(deleteLayer()));
 
-  actionResizeActiveWindow = new QAction(QIcon(getQPixmap("resize_xpm")),
-                                         tr("Window &Geometry..."), this);
+  actionResizeActiveWindow = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("resize_xpm")), tr("Window &Geometry..."), this);
   connect(actionResizeActiveWindow, SIGNAL(triggered()), this,
           SLOT(resizeActiveWindow()));
 
-  actionHideActiveWindow = new QAction(tr("&Hide Window"), this);
+  actionHideActiveWindow =
+      new MantidQt::MantidWidgets::TrackedAction(tr("&Hide Window"), this);
   connect(actionHideActiveWindow, SIGNAL(triggered()), this,
           SLOT(hideActiveWindow()));
 
-  actionShowMoreWindows = new QAction(tr("More windows..."), this);
+  actionShowMoreWindows =
+      new MantidQt::MantidWidgets::TrackedAction(tr("More windows..."), this);
   connect(actionShowMoreWindows, SIGNAL(triggered()), this,
           SLOT(showMoreWindows()));
 
-  actionPixelLineProfile = new QAction(QIcon(getQPixmap("pixelProfile_xpm")),
-                                       tr("&View Pixel Line Profile"), this);
+  actionPixelLineProfile = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("pixelProfile_xpm")), tr("&View Pixel Line Profile"),
+      this);
   connect(actionPixelLineProfile, SIGNAL(triggered()), this,
           SLOT(pixelLineProfile()));
 
-  actionIntensityTable = new QAction(tr("&Intensity Table"), this);
+  actionIntensityTable =
+      new MantidQt::MantidWidgets::TrackedAction(tr("&Intensity Table"), this);
   connect(actionIntensityTable, SIGNAL(triggered()), this,
           SLOT(intensityTable()));
 
-  actionShowLineDialog = new QAction(tr("&Properties"), this);
+  actionShowLineDialog =
+      new MantidQt::MantidWidgets::TrackedAction(tr("&Properties"), this);
   connect(actionShowLineDialog, SIGNAL(triggered()), this,
           SLOT(showLineDialog()));
 
-  actionShowImageDialog = new QAction(tr("&Properties"), this);
+  actionShowImageDialog =
+      new MantidQt::MantidWidgets::TrackedAction(tr("&Properties"), this);
   connect(actionShowImageDialog, SIGNAL(triggered()), this,
           SLOT(showImageDialog()));
 
-  actionShowTextDialog = new QAction(tr("&Properties"), this);
+  actionShowTextDialog =
+      new MantidQt::MantidWidgets::TrackedAction(tr("&Properties"), this);
   connect(actionShowTextDialog, SIGNAL(triggered()), this,
           SLOT(showTextDialog()));
 
-  actionActivateWindow = new QAction(tr("&Activate Window"), this);
+  actionActivateWindow =
+      new MantidQt::MantidWidgets::TrackedAction(tr("&Activate Window"), this);
   connect(actionActivateWindow, SIGNAL(triggered()), this,
           SLOT(activateWindow()));
 
-  actionMinimizeWindow = new QAction(tr("Mi&nimize Window"), this);
+  actionMinimizeWindow =
+      new MantidQt::MantidWidgets::TrackedAction(tr("Mi&nimize Window"), this);
   connect(actionMinimizeWindow, SIGNAL(triggered()), this,
           SLOT(minimizeWindow()));
 
-  actionMaximizeWindow = new QAction(tr("Ma&ximize Window"), this);
+  actionMaximizeWindow =
+      new MantidQt::MantidWidgets::TrackedAction(tr("Ma&ximize Window"), this);
   connect(actionMaximizeWindow, SIGNAL(triggered()), this,
           SLOT(maximizeWindow()));
 
-  actionHideWindow = new QAction(tr("&Hide Window"), this);
+  actionHideWindow =
+      new MantidQt::MantidWidgets::TrackedAction(tr("&Hide Window"), this);
   connect(actionHideWindow, SIGNAL(triggered()), this, SLOT(hideWindow()));
 
-  actionResizeWindow = new QAction(QIcon(getQPixmap("resize_xpm")),
-                                   tr("Re&size Window..."), this);
+  actionResizeWindow = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("resize_xpm")), tr("Re&size Window..."), this);
   connect(actionResizeWindow, SIGNAL(triggered()), this, SLOT(resizeWindow()));
 
-  actionEditSurfacePlot = new QAction(tr("&Surface..."), this);
+  actionEditSurfacePlot =
+      new MantidQt::MantidWidgets::TrackedAction(tr("&Surface..."), this);
   connect(actionEditSurfacePlot, SIGNAL(triggered()), this,
           SLOT(editSurfacePlot()));
 
-  actionAdd3DData = new QAction(tr("&Data Set..."), this);
+  actionAdd3DData =
+      new MantidQt::MantidWidgets::TrackedAction(tr("&Data Set..."), this);
   connect(actionAdd3DData, SIGNAL(triggered()), this, SLOT(add3DData()));
 
-  actionSetMatrixProperties = new QAction(tr("Set &Properties..."), this);
+  actionSetMatrixProperties = new MantidQt::MantidWidgets::TrackedAction(
+      tr("Set &Properties..."), this);
   connect(actionSetMatrixProperties, SIGNAL(triggered()), this,
           SLOT(showMatrixDialog()));
 
-  actionSetMatrixDimensions = new QAction(tr("Set &Dimensions..."), this);
+  actionSetMatrixDimensions = new MantidQt::MantidWidgets::TrackedAction(
+      tr("Set &Dimensions..."), this);
   connect(actionSetMatrixDimensions, SIGNAL(triggered()), this,
           SLOT(showMatrixSizeDialog()));
   actionSetMatrixDimensions->setShortcut(tr("Ctrl+D"));
 
-  actionSetMatrixValues =
-      new QAction(QIcon(getQPixmap("formula_xpm")), tr("Set &Values..."), this);
+  actionSetMatrixValues = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("formula_xpm")), tr("Set &Values..."), this);
   connect(actionSetMatrixValues, SIGNAL(triggered()), this,
           SLOT(showMatrixValuesDialog()));
   actionSetMatrixValues->setShortcut(tr("Alt+Q"));
 
-  actionImagePlot =
-      new QAction(QIcon(getQPixmap("image_plot_xpm")), tr("&Image Plot"), this);
+  actionImagePlot = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("image_plot_xpm")), tr("&Image Plot"), this);
   connect(actionImagePlot, SIGNAL(triggered()), this, SLOT(plotImage()));
 
-  actionTransposeMatrix = new QAction(tr("&Transpose"), this);
+  actionTransposeMatrix =
+      new MantidQt::MantidWidgets::TrackedAction(tr("&Transpose"), this);
   connect(actionTransposeMatrix, SIGNAL(triggered()), this,
           SLOT(transposeMatrix()));
 
-  actionFlipMatrixVertically =
-      new QAction(QIcon(getQPixmap("flip_vertical_xpm")), tr("Flip &V"), this);
+  actionFlipMatrixVertically = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("flip_vertical_xpm")), tr("Flip &V"), this);
   actionFlipMatrixVertically->setShortcut(tr("Ctrl+Shift+V"));
   connect(actionFlipMatrixVertically, SIGNAL(triggered()), this,
           SLOT(flipMatrixVertically()));
 
-  actionFlipMatrixHorizontally = new QAction(
+  actionFlipMatrixHorizontally = new MantidQt::MantidWidgets::TrackedAction(
       QIcon(getQPixmap("flip_horizontal_xpm")), tr("Flip &H"), this);
   actionFlipMatrixHorizontally->setShortcut(tr("Ctrl+Shift+H"));
   connect(actionFlipMatrixHorizontally, SIGNAL(triggered()), this,
           SLOT(flipMatrixHorizontally()));
 
-  actionRotateMatrix = new QAction(QIcon(getQPixmap("rotate_clockwise_xpm")),
-                                   tr("R&otate 90"), this);
+  actionRotateMatrix = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("rotate_clockwise_xpm")), tr("R&otate 90"), this);
   actionRotateMatrix->setShortcut(tr("Ctrl+Shift+R"));
   connect(actionRotateMatrix, SIGNAL(triggered()), this,
           SLOT(rotateMatrix90()));
 
-  actionRotateMatrixMinus =
-      new QAction(QIcon(getQPixmap("rotate_counterclockwise_xpm")),
-                  tr("Rotate &-90"), this);
+  actionRotateMatrixMinus = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("rotate_counterclockwise_xpm")), tr("Rotate &-90"),
+      this);
   actionRotateMatrixMinus->setShortcut(tr("Ctrl+Alt+R"));
   connect(actionRotateMatrixMinus, SIGNAL(triggered()), this,
           SLOT(rotateMatrixMinus90()));
 
-  actionInvertMatrix = new QAction(tr("&Invert"), this);
+  actionInvertMatrix =
+      new MantidQt::MantidWidgets::TrackedAction(tr("&Invert"), this);
   connect(actionInvertMatrix, SIGNAL(triggered()), this, SLOT(invertMatrix()));
 
-  actionMatrixDeterminant = new QAction(tr("&Determinant"), this);
+  actionMatrixDeterminant =
+      new MantidQt::MantidWidgets::TrackedAction(tr("&Determinant"), this);
   connect(actionMatrixDeterminant, SIGNAL(triggered()), this,
           SLOT(matrixDeterminant()));
 
-  actionViewMatrixImage = new QAction(tr("&Image mode"), this);
+  actionViewMatrixImage =
+      new MantidQt::MantidWidgets::TrackedAction(tr("&Image mode"), this);
   actionViewMatrixImage->setShortcut(tr("Ctrl+Shift+I"));
   connect(actionViewMatrixImage, SIGNAL(triggered()), this,
           SLOT(viewMatrixImage()));
   actionViewMatrixImage->setCheckable(true);
 
-  actionViewMatrix = new QAction(tr("&Data mode"), this);
+  actionViewMatrix =
+      new MantidQt::MantidWidgets::TrackedAction(tr("&Data mode"), this);
   actionViewMatrix->setShortcut(tr("Ctrl+Shift+D"));
   connect(actionViewMatrix, SIGNAL(triggered()), this, SLOT(viewMatrixTable()));
   actionViewMatrix->setCheckable(true);
 
-  actionMatrixXY = new QAction(tr("Show &X/Y"), this);
+  actionMatrixXY =
+      new MantidQt::MantidWidgets::TrackedAction(tr("Show &X/Y"), this);
   actionMatrixXY->setShortcut(tr("Ctrl+Shift+X"));
   connect(actionMatrixXY, SIGNAL(triggered()), this, SLOT(viewMatrixXY()));
   actionMatrixXY->setCheckable(true);
 
-  actionMatrixColumnRow = new QAction(tr("Show &Column/Row"), this);
+  actionMatrixColumnRow =
+      new MantidQt::MantidWidgets::TrackedAction(tr("Show &Column/Row"), this);
   actionMatrixColumnRow->setShortcut(tr("Ctrl+Shift+C"));
   connect(actionMatrixColumnRow, SIGNAL(triggered()), this,
           SLOT(viewMatrixColumnRow()));
   actionMatrixColumnRow->setCheckable(true);
 
-  actionMatrixGrayScale = new QAction(tr("&Gray Scale"), this);
+  actionMatrixGrayScale =
+      new MantidQt::MantidWidgets::TrackedAction(tr("&Gray Scale"), this);
   connect(actionMatrixGrayScale, SIGNAL(triggered()), this,
           SLOT(setMatrixGrayScale()));
   actionMatrixGrayScale->setCheckable(true);
 
-  actionMatrixRainbowScale = new QAction(tr("&Rainbow"), this);
+  actionMatrixRainbowScale =
+      new MantidQt::MantidWidgets::TrackedAction(tr("&Rainbow"), this);
   connect(actionMatrixRainbowScale, SIGNAL(triggered()), this,
           SLOT(setMatrixRainbowScale()));
   actionMatrixRainbowScale->setCheckable(true);
 
-  actionMatrixCustomScale = new QAction(tr("&Custom"), this);
+  actionMatrixCustomScale =
+      new MantidQt::MantidWidgets::TrackedAction(tr("&Custom"), this);
   connect(actionMatrixCustomScale, SIGNAL(triggered()), this,
           SLOT(showColorMapDialog()));
   actionMatrixCustomScale->setCheckable(true);
 
-  actionExportMatrix = new QAction(tr("&Export Image ..."), this);
+  actionExportMatrix =
+      new MantidQt::MantidWidgets::TrackedAction(tr("&Export Image ..."), this);
   connect(actionExportMatrix, SIGNAL(triggered()), this, SLOT(exportMatrix()));
 
-  actionConvertMatrixDirect = new QAction(tr("&Direct"), this);
+  actionConvertMatrixDirect =
+      new MantidQt::MantidWidgets::TrackedAction(tr("&Direct"), this);
   connect(actionConvertMatrixDirect, SIGNAL(triggered()), this,
           SLOT(convertMatrixToTableDirect()));
 
-  actionConvertMatrixXYZ = new QAction(tr("&XYZ Columns"), this);
+  actionConvertMatrixXYZ =
+      new MantidQt::MantidWidgets::TrackedAction(tr("&XYZ Columns"), this);
   connect(actionConvertMatrixXYZ, SIGNAL(triggered()), this,
           SLOT(convertMatrixToTableXYZ()));
 
-  actionConvertMatrixYXZ = new QAction(tr("&YXZ Columns"), this);
+  actionConvertMatrixYXZ =
+      new MantidQt::MantidWidgets::TrackedAction(tr("&YXZ Columns"), this);
   connect(actionConvertMatrixYXZ, SIGNAL(triggered()), this,
           SLOT(convertMatrixToTableYXZ()));
 
-  actionMatrixFFTDirect = new QAction(tr("&Forward FFT"), this);
+  actionMatrixFFTDirect =
+      new MantidQt::MantidWidgets::TrackedAction(tr("&Forward FFT"), this);
   connect(actionMatrixFFTDirect, SIGNAL(triggered()), this,
           SLOT(matrixDirectFFT()));
 
-  actionMatrixFFTInverse = new QAction(tr("&Inverse FFT"), this);
+  actionMatrixFFTInverse =
+      new MantidQt::MantidWidgets::TrackedAction(tr("&Inverse FFT"), this);
   connect(actionMatrixFFTInverse, SIGNAL(triggered()), this,
           SLOT(matrixInverseFFT()));
 
-  actionConvertTable = new QAction(tr("Convert to &Matrix"), this);
+  actionConvertTable = new MantidQt::MantidWidgets::TrackedAction(
+      tr("Convert to &Matrix"), this);
   connect(actionConvertTable, SIGNAL(triggered()), this,
           SLOT(convertTableToMatrix()));
 
-  actionConvertTableToWorkspace =
-      new QAction(tr("Convert to Table&Workspace"), this);
+  actionConvertTableToWorkspace = new MantidQt::MantidWidgets::TrackedAction(
+      tr("Convert to Table&Workspace"), this);
   connect(actionConvertTableToWorkspace, SIGNAL(triggered()), this,
           SLOT(convertTableToWorkspace()));
 
   actionConvertTableToMatrixWorkspace =
-      new QAction(tr("Convert to MatrixWorkspace"), this);
+      new MantidQt::MantidWidgets::TrackedAction(
+          tr("Convert to MatrixWorkspace"), this);
   connect(actionConvertTableToMatrixWorkspace, SIGNAL(triggered()), this,
           SLOT(convertTableToMatrixWorkspace()));
 
-  actionPlot3DWireFrame = new QAction(QIcon(getQPixmap("lineMesh_xpm")),
-                                      tr("3D &Wire Frame"), this);
+  actionPlot3DWireFrame = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("lineMesh_xpm")), tr("3D &Wire Frame"), this);
   connect(actionPlot3DWireFrame, SIGNAL(triggered()), this,
           SLOT(plot3DWireframe()));
 
-  actionPlot3DHiddenLine = new QAction(QIcon(getQPixmap("grid_only_xpm")),
-                                       tr("3D &Hidden Line"), this);
+  actionPlot3DHiddenLine = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("grid_only_xpm")), tr("3D &Hidden Line"), this);
   connect(actionPlot3DHiddenLine, SIGNAL(triggered()), this,
           SLOT(plot3DHiddenLine()));
 
-  actionPlot3DPolygons =
-      new QAction(QIcon(getQPixmap("no_grid_xpm")), tr("3D &Polygons"), this);
+  actionPlot3DPolygons = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("no_grid_xpm")), tr("3D &Polygons"), this);
   connect(actionPlot3DPolygons, SIGNAL(triggered()), this,
           SLOT(plot3DPolygons()));
 
-  actionPlot3DWireSurface = new QAction(QIcon(getQPixmap("grid_poly_xpm")),
-                                        tr("3D Wire &Surface"), this);
+  actionPlot3DWireSurface = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("grid_poly_xpm")), tr("3D Wire &Surface"), this);
   connect(actionPlot3DWireSurface, SIGNAL(triggered()), this,
           SLOT(plot3DWireSurface()));
 
-  actionColorMap = new QAction(QIcon(getQPixmap("color_map_xpm")),
-                               tr("Contour - &Color Fill"), this);
+  actionColorMap = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("color_map_xpm")), tr("Contour - &Color Fill"), this);
   connect(actionColorMap, SIGNAL(triggered()), this, SLOT(plotColorMap()));
 
-  actionContourMap = new QAction(QIcon(getQPixmap("contour_map_xpm")),
-                                 tr("Contour &Lines"), this);
+  actionContourMap = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("contour_map_xpm")), tr("Contour &Lines"), this);
   connect(actionContourMap, SIGNAL(triggered()), this, SLOT(plotContour()));
 
-  actionGrayMap = new QAction(QIcon(getQPixmap("gray_map_xpm")),
-                              tr("&Gray Scale Map"), this);
+  actionGrayMap = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("gray_map_xpm")), tr("&Gray Scale Map"), this);
   connect(actionGrayMap, SIGNAL(triggered()), this, SLOT(plotGrayScale()));
 
-  actionNoContourColorMap =
-      new QAction(QIcon(getQPixmap("color_map_xpm")), tr("Color &Fill"), this);
+  actionNoContourColorMap = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("color_map_xpm")), tr("Color &Fill"), this);
   connect(actionNoContourColorMap, SIGNAL(triggered()), this,
           SLOT(plotNoContourColorMap()));
 
-  actionSortTable = new QAction(tr("Sort Ta&ble"), this);
+  actionSortTable =
+      new MantidQt::MantidWidgets::TrackedAction(tr("Sort Ta&ble"), this);
   connect(actionSortTable, SIGNAL(triggered()), this, SLOT(sortActiveTable()));
 
-  actionSortSelection = new QAction(tr("Sort Columns"), this);
+  actionSortSelection =
+      new MantidQt::MantidWidgets::TrackedAction(tr("Sort Columns"), this);
   connect(actionSortSelection, SIGNAL(triggered()), this,
           SLOT(sortSelection()));
 
-  actionNormalizeTable = new QAction(tr("&Table"), this);
+  actionNormalizeTable =
+      new MantidQt::MantidWidgets::TrackedAction(tr("&Table"), this);
   connect(actionNormalizeTable, SIGNAL(triggered()), this,
           SLOT(normalizeActiveTable()));
 
-  actionNormalizeSelection = new QAction(tr("&Columns"), this);
+  actionNormalizeSelection =
+      new MantidQt::MantidWidgets::TrackedAction(tr("&Columns"), this);
   connect(actionNormalizeSelection, SIGNAL(triggered()), this,
           SLOT(normalizeSelection()));
 
-  actionCorrelate = new QAction(tr("Co&rrelate"), this);
+  actionCorrelate =
+      new MantidQt::MantidWidgets::TrackedAction(tr("Co&rrelate"), this);
   connect(actionCorrelate, SIGNAL(triggered()), this, SLOT(correlate()));
 
-  actionAutoCorrelate = new QAction(tr("&Autocorrelate"), this);
+  actionAutoCorrelate =
+      new MantidQt::MantidWidgets::TrackedAction(tr("&Autocorrelate"), this);
   connect(actionAutoCorrelate, SIGNAL(triggered()), this,
           SLOT(autoCorrelate()));
 
-  actionConvolute = new QAction(tr("&Convolute"), this);
+  actionConvolute =
+      new MantidQt::MantidWidgets::TrackedAction(tr("&Convolute"), this);
   connect(actionConvolute, SIGNAL(triggered()), this, SLOT(convolute()));
 
-  actionDeconvolute = new QAction(tr("&Deconvolute"), this);
+  actionDeconvolute =
+      new MantidQt::MantidWidgets::TrackedAction(tr("&Deconvolute"), this);
   connect(actionDeconvolute, SIGNAL(triggered()), this, SLOT(deconvolute()));
 
-  actionSetAscValues = new QAction(QIcon(getQPixmap("rowNumbers_xpm")),
-                                   tr("Ro&w Numbers"), this);
+  actionSetAscValues = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("rowNumbers_xpm")), tr("Ro&w Numbers"), this);
   connect(actionSetAscValues, SIGNAL(triggered()), this, SLOT(setAscValues()));
 
-  actionSetRandomValues = new QAction(QIcon(getQPixmap("randomNumbers_xpm")),
-                                      tr("&Random Values"), this);
+  actionSetRandomValues = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("randomNumbers_xpm")), tr("&Random Values"), this);
   connect(actionSetRandomValues, SIGNAL(triggered()), this,
           SLOT(setRandomValues()));
 
-  actionReadOnlyCol = new QAction(tr("&Read Only"), this);
+  actionReadOnlyCol =
+      new MantidQt::MantidWidgets::TrackedAction(tr("&Read Only"), this);
   connect(actionReadOnlyCol, SIGNAL(triggered()), this, SLOT(setReadOnlyCol()));
 
-  actionSetXCol = new QAction(QIcon(getQPixmap("x_col_xpm")), tr("&X"), this);
+  actionSetXCol = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("x_col_xpm")), tr("&X"), this);
   connect(actionSetXCol, SIGNAL(triggered()), this, SLOT(setXCol()));
 
-  actionSetYCol = new QAction(QIcon(getQPixmap("y_col_xpm")), tr("&Y"), this);
+  actionSetYCol = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("y_col_xpm")), tr("&Y"), this);
   connect(actionSetYCol, SIGNAL(triggered()), this, SLOT(setYCol()));
 
-  actionSetZCol = new QAction(QIcon(getQPixmap("z_col_xpm")), tr("&Z"), this);
+  actionSetZCol = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("z_col_xpm")), tr("&Z"), this);
   connect(actionSetZCol, SIGNAL(triggered()), this, SLOT(setZCol()));
 
-  actionSetXErrCol = new QAction(tr("X E&rror"), this);
+  actionSetXErrCol =
+      new MantidQt::MantidWidgets::TrackedAction(tr("X E&rror"), this);
   connect(actionSetXErrCol, SIGNAL(triggered()), this, SLOT(setXErrCol()));
 
-  actionSetYErrCol =
-      new QAction(QIcon(getQPixmap("errors_xpm")), tr("Y &Error"), this);
+  actionSetYErrCol = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("errors_xpm")), tr("Y &Error"), this);
   connect(actionSetYErrCol, SIGNAL(triggered()), this, SLOT(setYErrCol()));
 
-  actionDisregardCol = new QAction(QIcon(getQPixmap("disregard_col_xpm")),
-                                   tr("&Disregard"), this);
+  actionDisregardCol = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("disregard_col_xpm")), tr("&Disregard"), this);
   connect(actionDisregardCol, SIGNAL(triggered()), this, SLOT(disregardCol()));
 
-  actionSetLabelCol =
-      new QAction(QIcon(getQPixmap("set_label_col_xpm")), tr("&Label"), this);
+  actionSetLabelCol = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("set_label_col_xpm")), tr("&Label"), this);
   connect(actionSetLabelCol, SIGNAL(triggered()), this, SLOT(setLabelCol()));
 
-  actionBoxPlot =
-      new QAction(QIcon(getQPixmap("boxPlot_xpm")), tr("&Box Plot"), this);
+  actionBoxPlot = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(getQPixmap("boxPlot_xpm")), tr("&Box Plot"), this);
   connect(actionBoxPlot, SIGNAL(triggered()), this, SLOT(plotBoxDiagram()));
 
-  actionHomePage = new QAction(tr("&Mantid Homepage"), this); // Mantid change
+  actionHomePage = new MantidQt::MantidWidgets::TrackedAction(
+      tr("&Mantid Homepage"), this); // Mantid change
   connect(actionHomePage, SIGNAL(triggered()), this, SLOT(showHomePage()));
 
-  actionHelpBugReports = new QAction(tr("Report a &Bug"), this);
+  actionHelpBugReports =
+      new MantidQt::MantidWidgets::TrackedAction(tr("Report a &Bug"), this);
   connect(actionHelpBugReports, SIGNAL(triggered()), this,
           SLOT(showBugTracker()));
 
-  actionAskHelp = new QAction(tr("Ask for Help"), this);
+  actionAskHelp =
+      new MantidQt::MantidWidgets::TrackedAction(tr("Ask for Help"), this);
   connect(actionAskHelp, SIGNAL(triggered()), this, SLOT(showBugTracker()));
 
-  actionShowCurvePlotDialog = new QAction(tr("&Plot details..."), this);
+  actionShowCurvePlotDialog =
+      new MantidQt::MantidWidgets::TrackedAction(tr("&Plot details..."), this);
   connect(actionShowCurvePlotDialog, SIGNAL(triggered()), this,
           SLOT(showCurvePlotDialog()));
 
-  actionShowCurveWorksheet = new QAction(tr("&Worksheet"), this);
+  actionShowCurveWorksheet =
+      new MantidQt::MantidWidgets::TrackedAction(tr("&Worksheet"), this);
   connect(actionShowCurveWorksheet, SIGNAL(triggered()), this,
           SLOT(showCurveWorksheet()));
 
-  actionCurveFullRange = new QAction(tr("&Reset to Full Range"), this);
+  actionCurveFullRange = new MantidQt::MantidWidgets::TrackedAction(
+      tr("&Reset to Full Range"), this);
   connect(actionCurveFullRange, SIGNAL(triggered()), this,
           SLOT(setCurveFullRange()));
 
-  actionEditCurveRange = new QAction(tr("Edit &Range..."), this);
+  actionEditCurveRange =
+      new MantidQt::MantidWidgets::TrackedAction(tr("Edit &Range..."), this);
   connect(actionEditCurveRange, SIGNAL(triggered()), this,
           SLOT(showCurveRangeDialog()));
 
-  actionRemoveCurve = new QAction(getQPixmap("close_xpm"), tr("&Delete"), this);
+  actionRemoveCurve = new MantidQt::MantidWidgets::TrackedAction(
+      getQPixmap("close_xpm"), tr("&Delete"), this);
   connect(actionRemoveCurve, SIGNAL(triggered()), this, SLOT(removeCurve()));
 
-  actionHideCurve = new QAction(tr("&Hide"), this);
+  actionHideCurve =
+      new MantidQt::MantidWidgets::TrackedAction(tr("&Hide"), this);
   connect(actionHideCurve, SIGNAL(triggered()), this, SLOT(hideCurve()));
 
-  actionHideOtherCurves = new QAction(tr("Hide &Other Curves"), this);
+  actionHideOtherCurves = new MantidQt::MantidWidgets::TrackedAction(
+      tr("Hide &Other Curves"), this);
   connect(actionHideOtherCurves, SIGNAL(triggered()), this,
           SLOT(hideOtherCurves()));
 
-  actionShowAllCurves = new QAction(tr("&Show All Curves"), this);
+  actionShowAllCurves =
+      new MantidQt::MantidWidgets::TrackedAction(tr("&Show All Curves"), this);
   connect(actionShowAllCurves, SIGNAL(triggered()), this,
           SLOT(showAllCurves()));
 
-  actionEditFunction = new QAction(tr("&Edit Function..."), this);
+  actionEditFunction =
+      new MantidQt::MantidWidgets::TrackedAction(tr("&Edit Function..."), this);
   connect(actionEditFunction, SIGNAL(triggered()), this,
           SLOT(showFunctionDialog()));
 
-  actionFontBold = new QAction("B", this);
+  actionFontBold = new MantidQt::MantidWidgets::TrackedAction("B", this);
   actionFontBold->setToolTip(tr("Bold"));
   QFont font = appFont;
   font.setBold(true);
@@ -12411,7 +12614,7 @@ void ApplicationWindow::createActions() {
   actionFontBold->setCheckable(true);
   connect(actionFontBold, SIGNAL(toggled(bool)), this, SLOT(setBoldFont(bool)));
 
-  actionFontItalic = new QAction("It", this);
+  actionFontItalic = new MantidQt::MantidWidgets::TrackedAction("It", this);
   actionFontItalic->setToolTip(tr("Italic"));
   font = appFont;
   font.setItalic(true);
@@ -12420,17 +12623,18 @@ void ApplicationWindow::createActions() {
   connect(actionFontItalic, SIGNAL(toggled(bool)), this,
           SLOT(setItalicFont(bool)));
 
-  actionSuperscript =
-      new QAction(getQPixmap("exp_xpm"), tr("Superscript"), this);
+  actionSuperscript = new MantidQt::MantidWidgets::TrackedAction(
+      getQPixmap("exp_xpm"), tr("Superscript"), this);
   connect(actionSuperscript, SIGNAL(triggered()), this,
           SLOT(insertSuperscript()));
   actionSuperscript->setEnabled(false);
 
-  actionSubscript = new QAction(getQPixmap("index_xpm"), tr("Subscript"), this);
+  actionSubscript = new MantidQt::MantidWidgets::TrackedAction(
+      getQPixmap("index_xpm"), tr("Subscript"), this);
   connect(actionSubscript, SIGNAL(triggered()), this, SLOT(insertSubscript()));
   actionSubscript->setEnabled(false);
 
-  actionUnderline = new QAction("U", this);
+  actionUnderline = new MantidQt::MantidWidgets::TrackedAction("U", this);
   actionUnderline->setToolTip(tr("Underline (Ctrl+U)"));
   actionUnderline->setShortcut(tr("Ctrl+U"));
   font = appFont;
@@ -12439,51 +12643,59 @@ void ApplicationWindow::createActions() {
   connect(actionUnderline, SIGNAL(triggered()), this, SLOT(underline()));
   actionUnderline->setEnabled(false);
 
-  actionGreekSymbol =
-      new QAction(QString(QChar(0x3B1)) + QString(QChar(0x3B2)), this);
+  actionGreekSymbol = new MantidQt::MantidWidgets::TrackedAction(
+      QString(QChar(0x3B1)) + QString(QChar(0x3B2)), this);
   actionGreekSymbol->setToolTip(tr("Greek"));
   connect(actionGreekSymbol, SIGNAL(triggered()), this,
           SLOT(insertGreekSymbol()));
 
-  actionGreekMajSymbol = new QAction(QString(QChar(0x393)), this);
+  actionGreekMajSymbol =
+      new MantidQt::MantidWidgets::TrackedAction(QString(QChar(0x393)), this);
   actionGreekMajSymbol->setToolTip(tr("Greek"));
   connect(actionGreekMajSymbol, SIGNAL(triggered()), this,
           SLOT(insertGreekMajSymbol()));
 
-  actionMathSymbol = new QAction(QString(QChar(0x222B)), this);
+  actionMathSymbol =
+      new MantidQt::MantidWidgets::TrackedAction(QString(QChar(0x222B)), this);
   actionMathSymbol->setToolTip(tr("Mathematical Symbols"));
   connect(actionMathSymbol, SIGNAL(triggered()), this,
           SLOT(insertMathSymbol()));
 
-  actionclearAllMemory = new QAction("&Clear All Memory", this);
+  actionclearAllMemory =
+      new MantidQt::MantidWidgets::TrackedAction("&Clear All Memory", this);
   actionclearAllMemory->setShortcut(QKeySequence::fromString("Ctrl+Shift+L"));
   connect(actionclearAllMemory, SIGNAL(triggered()), mantidUI,
           SLOT(clearAllMemory()));
 
-  actionPanPlot = new QAction(QIcon(":/panning.png"), tr("Panning tool"), this);
+  actionPanPlot = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(":/panning.png"), tr("Panning tool"), this);
   connect(actionPanPlot, SIGNAL(triggered()), this, SLOT(panOnPlot()));
 
-  actionCatalogLogin = new QAction("Login", this);
+  actionCatalogLogin =
+      new MantidQt::MantidWidgets::TrackedAction("Login", this);
   actionCatalogLogin->setToolTip(tr("Catalog Login"));
   connect(actionCatalogLogin, SIGNAL(triggered()), this, SLOT(CatalogLogin()));
 
-  actionCatalogSearch = new QAction("Search", this);
+  actionCatalogSearch =
+      new MantidQt::MantidWidgets::TrackedAction("Search", this);
   actionCatalogSearch->setToolTip(tr("Search data in archives."));
   connect(actionCatalogSearch, SIGNAL(triggered()), this,
           SLOT(CatalogSearch()));
 
-  actionCatalogPublish = new QAction("Publish", this);
+  actionCatalogPublish =
+      new MantidQt::MantidWidgets::TrackedAction("Publish", this);
   actionCatalogPublish->setToolTip(tr("Publish data to the archives."));
   connect(actionCatalogPublish, SIGNAL(triggered()), this,
           SLOT(CatalogPublish()));
 
-  actionCatalogLogout = new QAction("Logout", this);
+  actionCatalogLogout =
+      new MantidQt::MantidWidgets::TrackedAction("Logout", this);
   actionCatalogLogout->setToolTip(tr("Catalog Logout"));
   connect(actionCatalogLogout, SIGNAL(triggered()), this,
           SLOT(CatalogLogout()));
 
-  actionWaterfallPlot =
-      new QAction(QIcon(":/waterfall_plot.png"), tr("&Waterfall Plot"), this);
+  actionWaterfallPlot = new MantidQt::MantidWidgets::TrackedAction(
+      QIcon(":/waterfall_plot.png"), tr("&Waterfall Plot"), this);
   connect(actionWaterfallPlot, SIGNAL(triggered()), this,
           SLOT(waterfallPlot()));
 }
@@ -13853,15 +14065,11 @@ Folder *ApplicationWindow::appendProject(const QString &fn,
 }
 
 void ApplicationWindow::saveAsProject() {
-  saveFolderAsProject(currentFolder());
-}
-
-void ApplicationWindow::saveFolderAsProject(Folder *f) {
   QString filter = tr("MantidPlot project") + " (*.qti);;"; // Mantid
   filter += tr("Compressed MantidPlot project") + " (*.qti.gz)";
 
   QString selectedFilter;
-  QString fn = MantidQt::API::FileDialogHandler::getSaveFileName(
+  QString fn = QFileDialog::getSaveFileName(
       this, tr("Save project as"), workingDir, filter, &selectedFilter);
   if (!fn.isEmpty()) {
     QFileInfo fi(fn);
@@ -13871,7 +14079,7 @@ void ApplicationWindow::saveFolderAsProject(Folder *f) {
       fn.append(".qti");
 
     ProjectSerialiser serialiser(this);
-    serialiser.save(f, fn, selectedFilter.contains(".gz"));
+    serialiser.save(fn, selectedFilter.contains(".gz"));
   }
 }
 
@@ -13898,7 +14106,7 @@ void ApplicationWindow::showFolderPopupMenu(QTreeWidgetItem *it,
   if (fli->folder()->parent())
     cm.addAction(tr("Save &As Project..."), this, SLOT(saveAsProject()));
   else
-    cm.addAction(tr("Save Project &As..."), this, SLOT(saveProjectAs()));
+    cm.addAction(tr("Save Project &As..."), this, SLOT(prepareSaveProject()));
   cm.addSeparator();
 
   if (fromFolders && show_windows_policy != HideAll) {
@@ -14240,10 +14448,11 @@ bool ApplicationWindow::changeFolder(Folder *newFolder, bool force) {
   if (active_window)
     active_window_state = active_window->status();
 
-  hideFolderWindows(oldFolder);
+  if (newFolder != oldFolder)
+    hideFolderWindows(oldFolder);
+
   d_current_folder = newFolder;
 
-  resultsLog->clear();
   resultsLog->appendInformation(currentFolder()->logInfo());
 
   lv->clear();
diff --git a/MantidPlot/src/ApplicationWindow.h b/MantidPlot/src/ApplicationWindow.h
index 6b83b835f6a73a5c455fca20b6116b7277c99eea..6372f23a7b950c0fc96faeaca51d1ee56f3861f1 100644
--- a/MantidPlot/src/ApplicationWindow.h
+++ b/MantidPlot/src/ApplicationWindow.h
@@ -44,6 +44,7 @@ Description          : QtiPlot's main window
 
 #include "MantidQtAPI/HelpWindow.h"
 #include "MantidQtAPI/IProjectSerialisable.h"
+#include "ProjectSaveView.h"
 #include "Script.h"
 #include "Scripted.h"
 #include "ScriptingEnv.h"
@@ -269,6 +270,10 @@ public slots:
   void saveProjectAs(const QString &fileName = QString(),
                      bool compress = false);
   bool saveProject(bool compress = false);
+  /// Show the project saver dialog
+  void prepareSaveProject();
+  /// Update application window post save
+  void postSaveProject();
 
   //! Set the project status to modifed
   void modifiedProject();
@@ -597,6 +602,7 @@ public slots:
   bool hidden(QWidget *window);
   void closeActiveWindow();
   void closeWindow(MdiSubWindow *window);
+  void prepareToCloseMantid();
 
   //!  Does all the cleaning work before actually deleting a window!
   void removeWindowFromLists(MdiSubWindow *w);
@@ -1022,7 +1028,6 @@ public slots:
   // parentFolder or to the current folder if no parent folder is specified.
   Folder *appendProject(const QString &file_name, Folder *parentFolder = 0);
   void saveAsProject();
-  void saveFolderAsProject(Folder *f);
 
   //!  adds a folder list item to the list view "lv"
   void addFolderListViewItem(Folder *f);
@@ -1453,6 +1458,8 @@ private:
   MantidQt::MantidWidgets::MessageDisplay *resultsLog;
   QMdiArea *d_workspace;
 
+  MantidQt::MantidWidgets::ProjectSaveView *m_projectSaveView;
+
   QToolBar *standardTools, *plotTools, *displayBar;
   QToolBar *formatToolBar;
   QToolButton *btnResults;
diff --git a/MantidPlot/src/ConfigDialog.cpp b/MantidPlot/src/ConfigDialog.cpp
index 032912b7ef8db18881a14e6f7f740ee2fecf60b7..f30837b4dd25b2f05baa0af6c0b0d6b76363084a 100644
--- a/MantidPlot/src/ConfigDialog.cpp
+++ b/MantidPlot/src/ConfigDialog.cpp
@@ -1586,11 +1586,6 @@ void ConfigDialog::initCurveFittingTab() {
   findPeaksTolerance->setMaximum(1000000);
   grid->addWidget(findPeaksTolerance, 4, 1);
 
-  grid->addWidget(new QLabel(tr("Peak Radius (in FWHM)")), 5, 0);
-  peakRadius = new QSpinBox();
-  peakRadius->setMaximum(std::numeric_limits<int>::max());
-  grid->addWidget(peakRadius, 5, 1);
-
   grid->addWidget(new QLabel(tr("Double property decimals")), 6, 0);
   decimals = new QSpinBox();
   grid->addWidget(decimals, 6, 1);
@@ -1675,15 +1670,6 @@ void ConfigDialog::initCurveFittingTab() {
     findPeaksTolerance->setValue(4);
   }
 
-  setting = QString::fromStdString(
-      Mantid::Kernel::ConfigService::Instance().getString(
-          "curvefitting.peakRadius"));
-  if (!setting.isEmpty()) {
-    peakRadius->setValue(setting.toInt());
-  } else {
-    peakRadius->setValue(5);
-  }
-
   decimals->setValue(app->mantidUI->fitFunctionBrowser()->getDecimals());
 }
 
@@ -2806,9 +2792,6 @@ void ConfigDialog::updateCurveFitSettings() {
   setting = QString::number(findPeaksTolerance->value()).toStdString();
   cfgSvc.setString("curvefitting.findPeaksTolerance", setting);
 
-  setting = QString::number(peakRadius->value()).toStdString();
-  cfgSvc.setString("curvefitting.peakRadius", setting);
-
   app->mantidUI->fitFunctionBrowser()->setDecimals(decimals->value());
 }
 
diff --git a/MantidPlot/src/ConfigDialog.h b/MantidPlot/src/ConfigDialog.h
index cc14cf626f202a95a2818351ba15c2fdd8fdc002..e795145e2acd681c176c82cdc12d41f23707524f 100644
--- a/MantidPlot/src/ConfigDialog.h
+++ b/MantidPlot/src/ConfigDialog.h
@@ -219,7 +219,6 @@ private:
   QLineEdit *functionArguments;
   QComboBox *defaultPeakShape;
   QSpinBox *findPeaksFWHM, *findPeaksTolerance;
-  QSpinBox *peakRadius;
   QSpinBox *decimals;
   /// mantid options page
   QWidget *mantidOptionsPage;
diff --git a/MantidPlot/src/ContourLinesEditor.cpp b/MantidPlot/src/ContourLinesEditor.cpp
index 71ffb62742aaf8dfd4bec6fb4fc96da5212c1532..a891c57424a0515b2afaee2d4c6fd019a7a74e5b 100644
--- a/MantidPlot/src/ContourLinesEditor.cpp
+++ b/MantidPlot/src/ContourLinesEditor.cpp
@@ -173,16 +173,23 @@ void ContourLinesEditor::insertLevel() {
     return;
 
   int row = table->currentRow();
-  DoubleSpinBox *sb = table_cellWidget<DoubleSpinBox>(row, 0);
 
+  DoubleSpinBox *sb;
   QwtDoubleInterval range = d_spectrogram->data().range();
-  double current_value = sb->value();
-  double previous_value = range.minValue();
-  sb = dynamic_cast<DoubleSpinBox *>(table->cellWidget(row - 1, 0));
-  if (sb)
-    previous_value = sb->value();
-
-  double val = 0.5 * (current_value + previous_value);
+  double val = (range.maxValue() + range.minValue()) / 2.0;
+  if (row >= 0) {
+    sb = table_cellWidget<DoubleSpinBox>(row, 0);
+
+    double current_value = sb->value();
+    double previous_value = range.minValue();
+    sb = dynamic_cast<DoubleSpinBox *>(table->cellWidget(row - 1, 0));
+    if (sb)
+      previous_value = sb->value();
+    val = 0.5 * (current_value + previous_value);
+  } else {
+    // no rows at present, set insertion point
+    row = 0;
+  }
 
   table->blockSignals(true);
   table->insertRow(row);
@@ -214,6 +221,7 @@ void ContourLinesEditor::insertLevel() {
   lbl->setPixmap(pix);
 
   table->setCellWidget(row, 1, lbl);
+  table->setCurrentCell(row, 1);
   table->blockSignals(false);
 
   enableButtons(table->currentRow());
diff --git a/MantidPlot/src/FitDialog.cpp b/MantidPlot/src/FitDialog.cpp
index 225ae7a19cd01d48428e05622155d3b66fe02a3d..f4cde40d9fef22eeccff0ac10d79abbd005ea55f 100644
--- a/MantidPlot/src/FitDialog.cpp
+++ b/MantidPlot/src/FitDialog.cpp
@@ -65,8 +65,6 @@
 
 #include <qwt_plot_curve.h>
 
-#include "MantidQtAPI/FileDialogHandler.h"
-
 using namespace MantidQt::API;
 
 FitDialog::FitDialog(Graph *g, QWidget *parent, Qt::WFlags fl)
@@ -662,7 +660,7 @@ void FitDialog::saveUserFunction() {
     }
     QString filter = tr("MantidPlot fit model") + " (*.fit);;";
     filter += tr("All files") + " (*)";
-    QString fn = MantidQt::API::FileDialogHandler::getSaveFileName(
+    QString fn = QFileDialog::getSaveFileName(
         app, tr("MantidPlot") + " - " + tr("Save Fit Model As"),
         app->fitModelsPath + "/" + name, filter);
     if (!fn.isEmpty()) {
@@ -1423,7 +1421,7 @@ void FitDialog::saveInitialGuesses() {
     }
     QString filter = tr("MantidPlot fit model") + " (*.fit);;";
     filter += tr("All files") + " (*)";
-    QString fn = MantidQt::API::FileDialogHandler::getSaveFileName(
+    QString fn = QFileDialog::getSaveFileName(
         app, tr("MantidPlot") + " - " + tr("Save Fit Model As"),
         app->fitModelsPath + "/" + d_current_fit->objectName(), filter);
     if (!fn.isEmpty()) {
diff --git a/MantidPlot/src/FunctionCurve.cpp b/MantidPlot/src/FunctionCurve.cpp
index 46ff376e7223b96b31f2a9a393c4f2aa64a93e28..6ce438adc963976b15111b3b48163bf9868342ca 100644
--- a/MantidPlot/src/FunctionCurve.cpp
+++ b/MantidPlot/src/FunctionCurve.cpp
@@ -254,9 +254,10 @@ void FunctionCurve::loadData(int points) {
  * Load the data from a MatrixWorkspace if it is a Mantid-type FunctionCurve.
  * @param ws :: A workspace to load the data from.
  * @param wi :: An index of a histogram with the data.
+ * @param peakRadius :: A peak radius to pass to the domain.
  */
 void FunctionCurve::loadMantidData(Mantid::API::MatrixWorkspace_const_sptr ws,
-                                   size_t wi) {
+                                   size_t wi, int peakRadius) {
   if (!d_variable.isEmpty() || d_formulas.isEmpty() ||
       d_formulas[0] != "Mantid")
     return;
@@ -310,6 +311,9 @@ void FunctionCurve::loadMantidData(Mantid::API::MatrixWorkspace_const_sptr ws,
     f->applyTies();
     Mantid::API::FunctionDomain1DVector domain(X);
     Mantid::API::FunctionValues Y(domain);
+    if (peakRadius > 0) {
+      domain.setPeakRadius(peakRadius);
+    }
     f->function(domain, Y);
 
     setData(&X[0], Y.getPointerToCalculated(0), static_cast<int>(X.size()));
diff --git a/MantidPlot/src/FunctionCurve.h b/MantidPlot/src/FunctionCurve.h
index d0d01b9d2ecffc25bec45b4f3d0e6ab24122cd86..fa19031030d15bfb5ced3b7f2a1f51ad1110954e 100644
--- a/MantidPlot/src/FunctionCurve.h
+++ b/MantidPlot/src/FunctionCurve.h
@@ -84,7 +84,7 @@ public:
   void loadData(int points = 0);
 
   void loadMantidData(boost::shared_ptr<const Mantid::API::MatrixWorkspace> ws,
-                      size_t wi);
+                      size_t wi, int peakRadius = 0);
 
   /// No error bars on this curve: Always return an empty list.
   QList<ErrorBarSettings *> errorBarSettingsList() const override {
diff --git a/MantidPlot/src/Graph.cpp b/MantidPlot/src/Graph.cpp
index 15010d5b5fc86f025f337fdb90fb5fc1034ae284..f0b393b600ba7476d52bbd379be4001732cbf873 100644
--- a/MantidPlot/src/Graph.cpp
+++ b/MantidPlot/src/Graph.cpp
@@ -62,6 +62,7 @@
 #include "Mantid/ErrorBarSettings.h"
 #include "Mantid/MantidMDCurve.h"
 #include "Mantid/MantidMatrixCurve.h"
+#include "MantidKernel/Strings.h"
 #include "MantidAPI/AnalysisDataService.h"
 #include "MantidQtAPI/PlotAxis.h"
 #include "MantidQtAPI/QwtRasterDataMD.h"
@@ -3285,6 +3286,20 @@ void Graph::addLegendItem() {
   }
 }
 
+/**
+ * Trim a table name from the legend key.
+ *
+ * Take a string that looks like 'Table-1_run-number' and convert it
+ * to just 'run-number'
+ *
+ * @param key :: the legend key to trim
+ * @return QString containing the trimmed value
+ */
+QString Graph::trimTableNameFromLegendKey(const QString &key) const {
+  int splitPos = key.indexOf("_");
+  return key.mid(splitPos + 1, key.size()).replace('_', '-');
+}
+
 QString Graph::yAxisTitleFromFirstCurve() {
   // I really don't like this...
   if (auto *firstCurve = dynamic_cast<MantidMatrixCurve *>(curve(0))) {
@@ -4369,10 +4384,8 @@ void Graph::copy(Graph *g) {
       if (pie)
         pie->addLabel(dynamic_cast<PieLabel *>(t), true);
       else
-        // cppcheck-suppress leakReturnValNotUsed
         insertText(t);
     } else
-      // cppcheck-suppress leakReturnValNotUsed
       insertText(t);
   }
 
@@ -6036,6 +6049,10 @@ void Graph::loadFromProject(const std::string &lines, ApplicationWindow *app,
       tsv >> tableName >> plotType;
 
       Table *table = app->table(tableName);
+
+      curveValues[1] = trimTableNameFromLegendKey(curveValues[1]);
+      curveValues[2] = trimTableNameFromLegendKey(curveValues[2]);
+
       if (table) {
         PlotCurve *c = NULL;
         if (plotType == GraphOptions::VectXYXY ||
@@ -6180,6 +6197,9 @@ void Graph::loadFromProject(const std::string &lines, ApplicationWindow *app,
       Table *w = app->table(sl[3]);
       Table *errTable = app->table(sl[4]);
       if (w && errTable) {
+        sl[2] = trimTableNameFromLegendKey(sl[2]);
+        sl[3] = trimTableNameFromLegendKey(sl[3]);
+        sl[4] = trimTableNameFromLegendKey(sl[4]);
         addErrorBars(sl[2], sl[3], errTable, sl[4], sl[1].toInt(),
                      sl[5].toDouble(), sl[6].toInt(), QColor(sl[7]),
                      sl[8].toInt(), sl[10].toInt(), sl[9].toInt());
diff --git a/MantidPlot/src/Graph.h b/MantidPlot/src/Graph.h
index e0ef6c981410927b6bfc6e6583f8be237aeb1cb3..4c95b1abb553849483e41aa64e03c444a9a6e0fd 100644
--- a/MantidPlot/src/Graph.h
+++ b/MantidPlot/src/Graph.h
@@ -848,6 +848,7 @@ public slots:
   //@}
   void updateDataCurves();
   void reverseCurveOrder();
+  int getNumCurves() { return n_curves; };
 
 signals:
   void selectedGraph(Graph *);
@@ -898,6 +899,8 @@ private:
   void niceLogScales(QwtPlot::Axis axis);
   void deselectCurves();
   void addLegendItem();
+  /// trim a title from a legend key
+  QString trimTableNameFromLegendKey(const QString &key) const;
 
   QString yAxisTitleFromFirstCurve();
 
diff --git a/MantidPlot/src/Graph3D.cpp b/MantidPlot/src/Graph3D.cpp
index 9c9950f09b4642d366b3453c81ef27f80327c31b..a4d5c9b3cd88a5109a2a70521795bc599f38b48b 100644
--- a/MantidPlot/src/Graph3D.cpp
+++ b/MantidPlot/src/Graph3D.cpp
@@ -44,7 +44,6 @@
 #include <QBitmap>
 #include <QClipboard>
 #include <QCursor>
-#include <QFileDialog>
 #include <QImageWriter>
 #include <QMessageBox>
 #include <QPixmap>
@@ -3102,3 +3101,9 @@ std::string Graph3D::saveToProject(ApplicationWindow *app) {
   tsv.writeRaw("</SurfacePlot>");
   return tsv.outputLines();
 }
+
+std::vector<std::string> Graph3D::getWorkspaceNames() {
+  // wsName is actually "Workspace workspacename", so we chop off
+  // the first 10 characters.
+  return {title.toStdString().substr(10, std::string::npos)};
+}
diff --git a/MantidPlot/src/Graph3D.h b/MantidPlot/src/Graph3D.h
index e08427948245bb68dcab6296c071afae513135e1..51e9b5733c1c61e339a098fe97bb33989fb29939 100644
--- a/MantidPlot/src/Graph3D.h
+++ b/MantidPlot/src/Graph3D.h
@@ -303,6 +303,7 @@ public slots:
   loadFromProject(const std::string &lines, ApplicationWindow *app,
                   const int fileVersion);
   std::string saveToProject(ApplicationWindow *app) override;
+  std::vector<std::string> getWorkspaceNames() override;
 
   void zoomChanged(double);
   void rotationChanged(double, double, double);
diff --git a/MantidPlot/src/Mantid/AlgorithmDockWidget.cpp b/MantidPlot/src/Mantid/AlgorithmDockWidget.cpp
index a58653032080dfc0b16869e7c7a32b686b36e732..45610917d9e07426ac20a8876d3ba08d402b396a 100644
--- a/MantidPlot/src/Mantid/AlgorithmDockWidget.cpp
+++ b/MantidPlot/src/Mantid/AlgorithmDockWidget.cpp
@@ -1,5 +1,6 @@
 #include "AlgorithmDockWidget.h"
 #include "MantidUI.h"
+#include <iomanip>
 
 //-------------------- AlgorithmDockWidget ----------------------//
 /** Create a QDockWidget containing:
@@ -110,4 +111,4 @@ void AlgorithmDockWidget::hideProgressBar() {
     delete m_progressBar;
     m_progressBar = NULL;
   }
-}
\ No newline at end of file
+}
diff --git a/MantidPlot/src/Mantid/AlgorithmHistoryWindow.cpp b/MantidPlot/src/Mantid/AlgorithmHistoryWindow.cpp
index e5eaa086c92877187fbcfa3793dc0a038d99cdfd..da000c1c69f67995d6c1bd4a741484d73289144a 100644
--- a/MantidPlot/src/Mantid/AlgorithmHistoryWindow.cpp
+++ b/MantidPlot/src/Mantid/AlgorithmHistoryWindow.cpp
@@ -1,22 +1,23 @@
 #include "AlgorithmHistoryWindow.h"
+#include "MantidKernel/ConfigService.h"
 #include "MantidAPI/AlgorithmManager.h"
+#include "MantidAPI/Workspace.h"
 
 #include "MantidQtAPI/AlgorithmInputHistory.h"
-#include "MantidQtAPI/FileDialogHandler.h"
 
-#include <QLineEdit>
-#include <QLabel>
-#include <QFileDialog>
+#include <QAction>
+#include <QApplication>
+#include <QClipboard>
 #include <QDateTime>
+#include <QDir>
+#include <QFileDialog>
 #include <QFormLayout>
+#include <QLabel>
+#include <QLineEdit>
 #include <QMenu>
-#include <QAction>
 #include <QMessageBox>
-#include <QApplication>
-#include <QClipboard>
-#include <QTextStream>
 #include <QTemporaryFile>
-#include <QDir>
+#include <QTextStream>
 
 #include <numeric>
 #include <fstream>
@@ -391,7 +392,7 @@ void AlgorithmHistoryWindow::writeToScriptFile() {
   } else {
     scriptDir = prevDir;
   }
-  QString filePath = MantidQt::API::FileDialogHandler::getSaveFileName(
+  QString filePath = QFileDialog::getSaveFileName(
       this, tr("Save Script As "), scriptDir, tr("Script files (*.py)"));
   // An empty string indicates they clicked cancel
   if (filePath.isEmpty())
diff --git a/MantidPlot/src/Mantid/InputHistory.cpp b/MantidPlot/src/Mantid/InputHistory.cpp
index 94aa62e35c1d7816cb8e2f5fbe14cf7eb823eb80..f3b0b438979cf22992c965e5ee187e3c13e9bca0 100644
--- a/MantidPlot/src/Mantid/InputHistory.cpp
+++ b/MantidPlot/src/Mantid/InputHistory.cpp
@@ -4,6 +4,7 @@
 #include <QSettings>
 #include <QStringList>
 #include <vector>
+#include <iostream>
 
 using namespace Mantid::API;
 using namespace Mantid::Kernel;
diff --git a/MantidPlot/src/Mantid/InstrumentWidget/InstrumentWindow.cpp b/MantidPlot/src/Mantid/InstrumentWidget/InstrumentWindow.cpp
index 5b576137f164a1f19e706d5539ef9c62b36375c8..58088ae731874118c74d921095f399a60f38085f 100644
--- a/MantidPlot/src/Mantid/InstrumentWidget/InstrumentWindow.cpp
+++ b/MantidPlot/src/Mantid/InstrumentWidget/InstrumentWindow.cpp
@@ -99,6 +99,14 @@ MantidQt::API::IProjectSerialisable *InstrumentWindow::loadFromProject(
   return nullptr;
 }
 
+std::vector<std::string> InstrumentWindow::getWorkspaceNames() {
+  return {m_instrumentWidget->getWorkspaceNameStdString()};
+}
+
+std::string InstrumentWindow::getWindowName() {
+  return m_instrumentWidget->windowTitle().toStdString();
+}
+
 /**
  * Save the state of the instrument window to a Mantid project file
  * @param app :: handle to the current application window instance
diff --git a/MantidPlot/src/Mantid/InstrumentWidget/InstrumentWindow.h b/MantidPlot/src/Mantid/InstrumentWidget/InstrumentWindow.h
index c062c0e019568c6dba8c8f121b2a31f31c3cc9d1..13ecf50b26882b92ef0cc03cfaaacc914df9da13 100644
--- a/MantidPlot/src/Mantid/InstrumentWidget/InstrumentWindow.h
+++ b/MantidPlot/src/Mantid/InstrumentWidget/InstrumentWindow.h
@@ -32,6 +32,11 @@ public:
   static MantidQt::API::IProjectSerialisable *
   loadFromProject(const std::string &lines, ApplicationWindow *app,
                   const int fileVersion);
+  /// Returns a list of workspace names that are used by this window
+  std::vector<std::string> getWorkspaceNames() override;
+  /// Returns the user friendly name of the window
+  std::string getWindowName() override;
+
   /// Save the state of the instrument window to a Mantid project file
   std::string saveToProject(ApplicationWindow *app) override;
   void selectTab(int tab);
diff --git a/MantidPlot/src/Mantid/MantidDock.cpp b/MantidPlot/src/Mantid/MantidDock.cpp
deleted file mode 100644
index 33713e175abfca37148d3b28f9c413d21e6e8719..0000000000000000000000000000000000000000
--- a/MantidPlot/src/Mantid/MantidDock.cpp
+++ /dev/null
@@ -1,1541 +0,0 @@
-#include "MantidDock.h"
-#include "../ApplicationWindow.h"
-#include "../pixmaps.h"
-#include "FlowLayout.h"
-#include "MantidGroupPlotGenerator.h"
-#include "MantidMatrix.h"
-#include "MantidTreeWidget.h"
-#include "MantidTreeWidgetItem.h"
-#include "MantidUI.h"
-#include "MantidWSIndexDialog.h"
-#include "WorkspaceIcons.h"
-
-#include "MantidAPI/IMDEventWorkspace.h"
-#include "MantidAPI/IMDHistoWorkspace.h"
-
-#include "MantidAPI/IPeaksWorkspace.h"
-#include "MantidAPI/MatrixWorkspace.h"
-#include "MantidAPI/WorkspaceGroup.h"
-#include "MantidGeometry/Instrument.h"
-#include <MantidAPI/FileProperty.h>
-#include <MantidKernel/make_unique.h>
-#include <MantidQtAPI/InterfaceManager.h>
-#include <MantidQtMantidWidgets/LineEditWithClear.h>
-
-#include <Poco/Path.h>
-
-#include <QFileDialog>
-#include <QMenu>
-#include <QSignalMapper>
-
-#ifdef MAKE_VATES
-#include "vtkPVDisplayInformation.h"
-#endif
-
-#include <algorithm>
-#include <sstream>
-
-using namespace Mantid::API;
-using namespace Mantid::Kernel;
-using namespace Mantid::Geometry;
-
-namespace {
-/// static logger for dock widget
-Mantid::Kernel::Logger docklog("MantidDockWidget");
-
-WorkspaceIcons WORKSPACE_ICONS = WorkspaceIcons();
-}
-
-MantidDockWidget::MantidDockWidget(MantidUI *mui, ApplicationWindow *parent)
-    : QDockWidget(tr("Workspaces"), parent), m_mantidUI(mui), m_updateCount(0),
-      m_treeUpdating(false),
-      m_ads(Mantid::API::AnalysisDataService::Instance()) {
-  setObjectName(
-      "exploreMantid"); // this is needed for QMainWindow::restoreState()
-  setMinimumHeight(150);
-  setMinimumWidth(200);
-  parent->addDockWidget(Qt::RightDockWidgetArea, this);
-
-  m_appParent = parent;
-
-  QFrame *f = new QFrame(this);
-  setWidget(f);
-
-  m_tree = new MantidTreeWidget(this, m_mantidUI);
-  m_tree->setHeaderLabel("Workspaces");
-
-  FlowLayout *buttonLayout = new FlowLayout();
-  m_loadButton = new QPushButton("Load");
-  m_saveButton = new QPushButton("Save");
-  m_deleteButton = new QPushButton("Delete");
-  m_groupButton = new QPushButton("Group");
-  m_sortButton = new QPushButton("Sort");
-
-  if (m_groupButton)
-    m_groupButton->setEnabled(false);
-  m_deleteButton->setEnabled(false);
-  m_saveButton->setEnabled(false);
-
-  buttonLayout->addWidget(m_loadButton);
-  buttonLayout->addWidget(m_deleteButton);
-  buttonLayout->addWidget(m_groupButton);
-  buttonLayout->addWidget(m_sortButton);
-  buttonLayout->addWidget(m_saveButton);
-
-  m_workspaceFilter = new MantidQt::MantidWidgets::LineEditWithClear();
-  m_workspaceFilter->setPlaceholderText("Filter Workspaces");
-  m_workspaceFilter->setToolTip("Type here to filter the workspaces");
-
-  connect(m_workspaceFilter, SIGNAL(textChanged(const QString &)), this,
-          SLOT(filterWorkspaceTree(const QString &)));
-
-  QVBoxLayout *layout = new QVBoxLayout();
-  f->setLayout(layout);
-  layout->setSpacing(0);
-  layout->setMargin(0);
-  layout->addLayout(buttonLayout);
-  layout->addWidget(m_workspaceFilter);
-  layout->addWidget(m_tree);
-
-  m_loadMenu = new QMenu(this);
-  m_saveMenu = new QMenu(this);
-
-  QAction *loadFileAction = new QAction("File", this);
-  QAction *liveDataAction = new QAction("Live Data", this);
-  m_loadMapper = new QSignalMapper(this);
-  m_loadMapper->setMapping(liveDataAction, "StartLiveData");
-  m_loadMapper->setMapping(loadFileAction, "Load");
-  connect(liveDataAction, SIGNAL(triggered()), m_loadMapper, SLOT(map()));
-  connect(loadFileAction, SIGNAL(triggered()), m_loadMapper, SLOT(map()));
-  connect(m_loadMapper, SIGNAL(mapped(const QString &)), m_mantidUI,
-          SLOT(showAlgorithmDialog(const QString &)));
-  m_loadMenu->addAction(loadFileAction);
-  m_loadMenu->addAction(liveDataAction);
-  m_loadButton->setMenu(m_loadMenu);
-
-  // Dialog box used for user to specify folder to save multiple workspaces into
-  m_saveFolderDialog = new QFileDialog;
-  m_saveFolderDialog->setFileMode(QFileDialog::DirectoryOnly);
-  m_saveFolderDialog->setOption(QFileDialog::ShowDirsOnly);
-
-  // SET UP SORT
-  createSortMenuActions();
-  createWorkspaceMenuActions();
-
-  connect(m_deleteButton, SIGNAL(clicked()), this, SLOT(deleteWorkspaces()));
-  connect(m_tree, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this,
-          SLOT(clickedWorkspace(QTreeWidgetItem *, int)));
-  connect(m_tree, SIGNAL(itemSelectionChanged()), this,
-          SLOT(workspaceSelected()));
-  connect(m_groupButton, SIGNAL(clicked()), this, SLOT(groupingButtonClick()));
-
-  m_tree->setContextMenuPolicy(Qt::CustomContextMenu);
-  connect(m_tree, SIGNAL(customContextMenuRequested(const QPoint &)), this,
-          SLOT(popupMenu(const QPoint &)));
-
-  // call this slot directly after the signal is received. just increment the
-  // update counter
-  connect(m_mantidUI, SIGNAL(workspace_renamed(QString, QString)), this,
-          SLOT(recordWorkspaceRename(QString, QString)), Qt::DirectConnection);
-  // call this slot directly after the signal is received. just increment the
-  // update counter
-  connect(m_mantidUI, SIGNAL(ADS_updated()), this, SLOT(incrementUpdateCount()),
-          Qt::DirectConnection);
-  // this slot is called when the GUI thread is free. decrement the counter. do
-  // nothing until the counter == 0
-  connect(m_mantidUI, SIGNAL(ADS_updated()), this,
-          SLOT(updateTreeOnADSUpdate()), Qt::QueuedConnection);
-
-  connect(m_mantidUI, SIGNAL(workspaces_cleared()), m_tree, SLOT(clear()),
-          Qt::QueuedConnection);
-  connect(m_tree, SIGNAL(itemSelectionChanged()), this,
-          SLOT(treeSelectionChanged()));
-  connect(m_tree, SIGNAL(itemExpanded(QTreeWidgetItem *)), this,
-          SLOT(populateChildData(QTreeWidgetItem *)));
-  m_tree->setDragEnabled(true);
-}
-
-MantidDockWidget::~MantidDockWidget() {}
-
-/** Returns the name of the selected workspace
-*  (the first one if more than one is selected)
-*/
-QString MantidDockWidget::getSelectedWorkspaceName() const {
-  QList<QTreeWidgetItem *> items = m_tree->selectedItems();
-  QString str("");
-  if (!items.empty()) {
-    QTreeWidgetItem *item = items[0];
-    if (item)
-      str = item->text(0);
-  }
-  return str;
-}
-
-/// Returns a pointer to the selected workspace (the first if multiple
-/// workspaces selected)
-Mantid::API::Workspace_sptr MantidDockWidget::getSelectedWorkspace() const {
-  QString workspaceName = getSelectedWorkspaceName();
-  if (m_ads.doesExist(workspaceName.toStdString())) {
-    return m_ads.retrieve(workspaceName.toStdString());
-  } else {
-    return Mantid::API::Workspace_sptr();
-  }
-}
-
-/**
-* Create the action items associated with the dock
-*/
-void MantidDockWidget::createWorkspaceMenuActions() {
-  m_showData = new QAction(tr("Show Data"), this);
-  connect(m_showData, SIGNAL(triggered()), m_mantidUI, SLOT(importWorkspace()));
-
-  m_showInst = new QAction(tr("Show Instrument"), this);
-  connect(m_showInst, SIGNAL(triggered()), m_mantidUI,
-          SLOT(showMantidInstrumentSelected()));
-
-  m_plotSpec = new QAction(tr("Plot Spectrum..."), this);
-  connect(m_plotSpec, SIGNAL(triggered()), this, SLOT(plotSpectra()));
-
-  m_plotSpecErr = new QAction(tr("Plot Spectrum with Errors..."), this);
-  connect(m_plotSpecErr, SIGNAL(triggered()), this, SLOT(plotSpectraErr()));
-
-  m_colorFill = new QAction(tr("Color Fill Plot"), this);
-  connect(m_colorFill, SIGNAL(triggered()), this, SLOT(drawColorFillPlot()));
-
-  m_showDetectors = new QAction(tr("Show Detectors"), this);
-  connect(m_showDetectors, SIGNAL(triggered()), this,
-          SLOT(showDetectorTable()));
-
-  m_showBoxData = new QAction(tr("Show Box Data Table"), this);
-  connect(m_showBoxData, SIGNAL(triggered()), m_mantidUI,
-          SLOT(importBoxDataTable()));
-
-  m_showVatesGui = new QAction(tr("Show Vates Simple Interface"), this);
-  {
-    QIcon icon;
-    icon.addFile(
-        QString::fromUtf8(":/VatesSimpleGuiViewWidgets/icons/pvIcon.png"),
-        QSize(), QIcon::Normal, QIcon::Off);
-    m_showVatesGui->setIcon(icon);
-  }
-  connect(m_showVatesGui, SIGNAL(triggered()), m_mantidUI,
-          SLOT(showVatesSimpleInterface()));
-
-  m_showMDPlot = new QAction(tr("Plot MD"), this);
-  connect(m_showMDPlot, SIGNAL(triggered()), m_mantidUI, SLOT(showMDPlot()));
-
-  m_showListData = new QAction(tr("List Data"), this);
-  connect(m_showListData, SIGNAL(triggered()), m_mantidUI,
-          SLOT(showListData()));
-
-  m_showSpectrumViewer = new QAction(tr("Show Spectrum Viewer"), this);
-  connect(m_showSpectrumViewer, SIGNAL(triggered()), m_mantidUI,
-          SLOT(showSpectrumViewer()));
-
-  m_showSliceViewer = new QAction(tr("Show Slice Viewer"), this);
-  {
-    QIcon icon;
-    icon.addFile(
-        QString::fromUtf8(":/SliceViewer/icons/SliceViewerWindow_icon.png"),
-        QSize(), QIcon::Normal, QIcon::Off);
-    m_showSliceViewer->setIcon(icon);
-  }
-  connect(m_showSliceViewer, SIGNAL(triggered()), m_mantidUI,
-          SLOT(showSliceViewer()));
-
-  m_showLogs = new QAction(tr("Sample Logs..."), this);
-  connect(m_showLogs, SIGNAL(triggered()), m_mantidUI,
-          SLOT(showLogFileWindow()));
-
-  m_showSampleMaterial = new QAction(tr("Sample Material..."), this);
-  connect(m_showSampleMaterial, SIGNAL(triggered()), m_mantidUI,
-          SLOT(showSampleMaterialWindow()));
-
-  m_showHist = new QAction(tr("Show History"), this);
-  connect(m_showHist, SIGNAL(triggered()), m_mantidUI,
-          SLOT(showAlgorithmHistory()));
-
-  m_saveNexus = new QAction(tr("Save Nexus"), this);
-  connect(m_saveNexus, SIGNAL(triggered()), m_mantidUI,
-          SLOT(saveNexusWorkspace()));
-
-  m_rename = new QAction(tr("Rename"), this);
-  connect(m_rename, SIGNAL(triggered()), this, SLOT(renameWorkspace()));
-
-  m_delete = new QAction(tr("Delete"), this);
-  connect(m_delete, SIGNAL(triggered()), this, SLOT(deleteWorkspaces()));
-
-  m_showTransposed = new QAction(tr("Show Transposed"), this);
-  connect(m_showTransposed, SIGNAL(triggered()), m_mantidUI,
-          SLOT(importTransposed()));
-
-  m_convertToMatrixWorkspace =
-      new QAction(tr("Convert to MatrixWorkspace"), this);
-  m_convertToMatrixWorkspace->setIcon(QIcon(getQPixmap("mantid_matrix_xpm")));
-  connect(m_convertToMatrixWorkspace, SIGNAL(triggered()), this,
-          SLOT(convertToMatrixWorkspace()));
-
-  m_convertMDHistoToMatrixWorkspace =
-      new QAction(tr("Convert to MatrixWorkspace"), this);
-  m_convertMDHistoToMatrixWorkspace->setIcon(
-      QIcon(getQPixmap("mantid_matrix_xpm")));
-  connect(m_convertMDHistoToMatrixWorkspace, SIGNAL(triggered()), this,
-          SLOT(convertMDHistoToMatrixWorkspace()));
-
-  m_clearUB = new QAction(tr("Clear UB Matrix"), this);
-  connect(m_clearUB, SIGNAL(triggered()), this, SLOT(clearUB()));
-
-  m_plotSurface = new QAction(tr("Plot Surface from Group"), this);
-  connect(m_plotSurface, SIGNAL(triggered()), this, SLOT(plotSurface()));
-
-  m_plotContour = new QAction(tr("Plot Contour from Group"), this);
-  connect(m_plotContour, SIGNAL(triggered()), this, SLOT(plotContour()));
-}
-
-/**
-* Create actions for sorting.
-*/
-void MantidDockWidget::createSortMenuActions() {
-  chooseByName();
-  m_sortMenu = new QMenu(this);
-
-  QAction *m_ascendingSortAction = new QAction("Ascending", this);
-  QAction *m_descendingSortAction = new QAction("Descending", this);
-  QAction *m_byNameChoice = new QAction("Name", this);
-  QAction *m_byLastModifiedChoice = new QAction("Last Modified", this);
-
-  m_ascendingSortAction->setCheckable(true);
-  m_ascendingSortAction->setEnabled(true);
-
-  m_descendingSortAction->setCheckable(true);
-  m_descendingSortAction->setEnabled(true);
-
-  QActionGroup *sortDirectionGroup = new QActionGroup(m_sortMenu);
-  sortDirectionGroup->addAction(m_ascendingSortAction);
-  sortDirectionGroup->addAction(m_descendingSortAction);
-  sortDirectionGroup->setExclusive(true);
-  m_ascendingSortAction->setChecked(true);
-
-  m_byNameChoice->setCheckable(true);
-  m_byNameChoice->setEnabled(true);
-
-  m_byLastModifiedChoice->setCheckable(true);
-  m_byLastModifiedChoice->setEnabled(true);
-
-  m_sortChoiceGroup = new QActionGroup(m_sortMenu);
-  m_sortChoiceGroup->addAction(m_byNameChoice);
-  m_sortChoiceGroup->addAction(m_byLastModifiedChoice);
-  m_sortChoiceGroup->setExclusive(true);
-  m_byNameChoice->setChecked(true);
-
-  connect(m_ascendingSortAction, SIGNAL(triggered()), this,
-          SLOT(sortAscending()));
-  connect(m_descendingSortAction, SIGNAL(triggered()), this,
-          SLOT(sortDescending()));
-  connect(m_byNameChoice, SIGNAL(triggered()), this, SLOT(chooseByName()));
-  connect(m_byLastModifiedChoice, SIGNAL(triggered()), this,
-          SLOT(chooseByLastModified()));
-
-  m_sortMenu->addActions(sortDirectionGroup->actions());
-  m_sortMenu->addSeparator();
-  m_sortMenu->addActions(m_sortChoiceGroup->actions());
-  m_sortButton->setMenu(m_sortMenu);
-}
-
-/**
-* When an item is expanded, populate the child data for this item
-* @param item :: The item being expanded
-*/
-void MantidDockWidget::populateChildData(QTreeWidgetItem *item) {
-  QVariant userData = item->data(0, Qt::UserRole);
-  if (userData.isNull())
-    return;
-
-  // Clear it first
-  while (item->childCount() > 0) {
-    auto *widgetItem = item->takeChild(0);
-    delete widgetItem;
-  }
-
-  Workspace_sptr workspace = userData.value<Workspace_sptr>();
-
-  if (auto group = boost::dynamic_pointer_cast<WorkspaceGroup>(workspace)) {
-    const size_t nmembers = group->getNumberOfEntries();
-    for (size_t i = 0; i < nmembers; ++i) {
-      auto ws = group->getItem(i);
-      auto *node = addTreeEntry(std::make_pair(ws->name(), ws), item);
-      excludeItemFromSort(node);
-      if (shouldBeSelected(node->text(0)))
-        node->setSelected(true);
-    }
-  } else {
-    QString details;
-    try {
-      details = workspace->toString().c_str();
-    } catch (std::runtime_error &e) {
-      details = QString("Error: %1").arg(e.what());
-    }
-    QStringList rows =
-        details.split(QLatin1Char('\n'), QString::SkipEmptyParts);
-    rows.append(QString("Memory used: ") +
-                workspace->getMemorySizeAsStr().c_str());
-
-    auto iend = rows.constEnd();
-    for (auto itr = rows.constBegin(); itr != iend; ++itr) {
-      MantidTreeWidgetItem *data =
-          new MantidTreeWidgetItem(QStringList(*itr), m_tree);
-      data->setFlags(Qt::NoItemFlags);
-      excludeItemFromSort(data);
-      item->addChild(data);
-    }
-  }
-}
-
-/**
-* Set tree item's icon based on the ID of the workspace.
-* @param item :: A workspace tree item.
-* @param wsID :: An icon type code.
-*/
-void MantidDockWidget::setItemIcon(QTreeWidgetItem *item,
-                                   const std::string &wsID) {
-  try {
-    item->setIcon(0, QIcon(WORKSPACE_ICONS.getIcon(wsID)));
-  } catch (std::runtime_error &) {
-    docklog.warning() << "Cannot find icon for workspace ID '" << wsID << "'\n";
-  }
-}
-
-void MantidDockWidget::updateTreeOnADSUpdate() {
-  // do not update until the counter is zero
-  if (m_updateCount.deref())
-    return;
-  updateTree();
-}
-
-/**
-* Update the workspace tree to match the current state of the ADS.
-* It is important that the workspace tree is modified only by this method.
-*/
-void MantidDockWidget::updateTree() {
-  // find all expanded top-level entries
-  QStringList expanded;
-  int n = m_tree->topLevelItemCount();
-  for (int i = 0; i < n; ++i) {
-    auto item = m_tree->topLevelItem(i);
-    if (item->isExpanded()) {
-      expanded << item->text(0);
-    }
-  }
-
-  // create a new tree
-  setTreeUpdating(true);
-  populateTopLevel(m_ads.topLevelItems(), expanded);
-  setTreeUpdating(false);
-
-  // Re-sort
-  m_tree->sort();
-}
-
-/**
-* Slot to be connected directly to ADS_updated signal. Increase m_updateCount
-* and return.
-*/
-void MantidDockWidget::incrementUpdateCount() { m_updateCount.ref(); }
-
-/**
-* Save the old and the new name in m_renameMap. This is needed to restore
-* selection
-*   of the renamed workspace (if it was selected before renaming).
-* @param old_name :: Old name of a renamed workspace.
-* @param new_name :: New name of a renamed workspace.
-*/
-void MantidDockWidget::recordWorkspaceRename(QString old_name,
-                                             QString new_name) {
-  // check if old_name has been recently a new name
-  QList<QString> oldNames = m_renameMap.keys(old_name);
-  // non-empty list of oldNames become new_name
-  if (!oldNames.isEmpty()) {
-    foreach (QString name, oldNames) { m_renameMap[name] = new_name; }
-  } else {
-    // record a new rename pair
-    m_renameMap[old_name] = new_name;
-  }
-}
-
-/**
-* Flips the flag indicating whether a tree update is in progress. Actions such
-* as sorting
-* are disabled while an update is in progress.
-* @param state The required state for the flag
-*/
-void MantidDockWidget::setTreeUpdating(const bool state) {
-  m_treeUpdating = state;
-}
-
-/**
-* Clears the tree and re-populates it with the given top level items
-* @param topLevelItems The map of names to workspaces
-* @param expanded Names of items who should expanded after being populated
-*/
-void MantidDockWidget::populateTopLevel(
-    const std::map<std::string, Mantid::API::Workspace_sptr> &topLevelItems,
-    const QStringList &expanded) {
-  // collect names of selected workspaces
-  QList<QTreeWidgetItem *> selected = m_tree->selectedItems();
-  m_selectedNames.clear(); // just in case
-  foreach (QTreeWidgetItem *item, selected) {
-    m_selectedNames << item->text(0);
-  }
-
-  // populate the tree from scratch
-  m_tree->clear();
-  auto iend = topLevelItems.end();
-  for (auto it = topLevelItems.begin(); it != iend; ++it) {
-    auto *node = addTreeEntry(*it);
-    QString name = node->text(0);
-    if (expanded.contains(name))
-      node->setExpanded(true);
-    // see if item must be selected
-    if (shouldBeSelected(name))
-      node->setSelected(true);
-  }
-  m_selectedNames.clear();
-  m_renameMap.clear();
-
-  // apply any filtering
-  filterWorkspaceTree(m_workspaceFilter->text());
-}
-
-/**
-* Adds a node for the given named item, including a single child ID item to make
-* each node have a expandable button
-* and allowing plotting to work from non-expanded items
-* @param item A name/workspace pair to add.
-* @param parent If not null then add the new items as a child of the given item
-*/
-MantidTreeWidgetItem *MantidDockWidget::addTreeEntry(
-    const std::pair<std::string, Mantid::API::Workspace_sptr> &item,
-    QTreeWidgetItem *parent) {
-  MantidTreeWidgetItem *node =
-      new MantidTreeWidgetItem(QStringList(item.first.c_str()), m_tree);
-  node->setData(0, Qt::UserRole, QVariant::fromValue(item.second));
-
-  // A a child ID item so that it becomes expandable. Using the correct ID is
-  // needed when plotting from non-expanded groups.
-  const std::string wsID = item.second->id();
-  MantidTreeWidgetItem *idNode =
-      new MantidTreeWidgetItem(QStringList(wsID.c_str()), m_tree);
-  idNode->setFlags(Qt::NoItemFlags);
-  node->addChild(idNode);
-  setItemIcon(node, wsID);
-
-  if (parent) {
-    parent->addChild(node);
-  } else {
-    m_tree->addTopLevelItem(node);
-  }
-  return node;
-}
-
-/**
-* Check if a workspace should be selected after dock update.
-* @param name :: Name of a workspace to check.
-*/
-bool MantidDockWidget::shouldBeSelected(QString name) const {
-  QStringList renamed = m_renameMap.keys(name);
-  if (!renamed.isEmpty()) {
-    foreach (QString oldName, renamed) {
-      if (m_selectedNames.contains(oldName)) {
-        return true;
-      }
-    }
-  } else if (m_selectedNames.contains(name)) {
-    return true;
-  }
-  return false;
-}
-
-/**
-* Add the actions that are appropriate for a MatrixWorkspace
-* @param menu :: The menu to store the items
-* @param matrixWS :: The workspace related to the menu
-*/
-void MantidDockWidget::addMatrixWorkspaceMenuItems(
-    QMenu *menu,
-    const Mantid::API::MatrixWorkspace_const_sptr &matrixWS) const {
-  // Add all options except plot of we only have 1 value
-  menu->addAction(m_showData);
-  menu->addAction(m_showInst);
-  // Disable the 'show instrument' option if a workspace doesn't have an
-  // instrument attached
-  m_showInst->setEnabled(matrixWS->getInstrument() &&
-                         !matrixWS->getInstrument()->getName().empty());
-  menu->addSeparator();
-  menu->addAction(m_plotSpec);
-  menu->addAction(m_plotSpecErr);
-
-  // Don't plot a spectrum if only one X value
-  m_plotSpec->setEnabled(matrixWS->blocksize() > 1);
-  m_plotSpecErr->setEnabled(matrixWS->blocksize() > 1);
-
-  menu->addAction(m_showSpectrumViewer); // The 2D spectrum viewer
-
-  menu->addAction(m_colorFill);
-  // Show the color fill plot if you have more than one histogram
-  m_colorFill->setEnabled(
-      (matrixWS->axes() > 1 && matrixWS->getNumberHistograms() > 1));
-  menu->addAction(m_showSliceViewer); // The 2D slice viewer
-  menu->addSeparator();
-  menu->addAction(m_showDetectors);
-  menu->addAction(m_showLogs);
-  menu->addAction(m_showSampleMaterial);
-  menu->addAction(m_showHist);
-  menu->addAction(m_saveNexus);
-}
-
-/**
-* Add the actions that are appropriate for a MDEventWorkspace
-* @param menu :: The menu to store the items
-* @param WS :: The workspace related to the menu
-*/
-void MantidDockWidget::addMDEventWorkspaceMenuItems(
-    QMenu *menu, const Mantid::API::IMDEventWorkspace_const_sptr &WS) const {
-  Q_UNUSED(WS);
-
-  // menu->addAction(m_showBoxData); // Show MD Box data (for debugging only)
-  menu->addAction(m_showVatesGui); // Show the Vates simple interface
-  if (!MantidQt::API::InterfaceManager::hasVatesLibraries()) {
-    m_showVatesGui->setEnabled(false);
-#ifdef MAKE_VATES
-  } else if (!vtkPVDisplayInformation::SupportsOpenGLLocally()) {
-    m_showVatesGui->setEnabled(false);
-#endif
-  } else {
-    std::size_t nDim = WS->getNonIntegratedDimensions().size();
-    m_showVatesGui->setEnabled(nDim >= 3 && nDim < 5);
-  }
-  menu->addAction(m_showSliceViewer); // The 2D slice viewer
-  menu->addAction(m_showHist);        // Algorithm history
-  menu->addAction(m_showListData);    // Show data in table
-  menu->addAction(m_showLogs);
-}
-
-void MantidDockWidget::addMDHistoWorkspaceMenuItems(
-    QMenu *menu, const Mantid::API::IMDWorkspace_const_sptr &WS) const {
-  Q_UNUSED(WS);
-  menu->addAction(m_showHist);     // Algorithm history
-  menu->addAction(m_showVatesGui); // Show the Vates simple interface
-  if (!MantidQt::API::InterfaceManager::hasVatesLibraries()) {
-    m_showVatesGui->setEnabled(false);
-#ifdef MAKE_VATES
-  } else if (!vtkPVDisplayInformation::SupportsOpenGLLocally()) {
-    m_showVatesGui->setEnabled(false);
-#endif
-  } else {
-    std::size_t nDim = WS->getNonIntegratedDimensions().size();
-    m_showVatesGui->setEnabled(nDim >= 3 && nDim < 5);
-  }
-  menu->addAction(m_showSliceViewer); // The 2D slice viewer
-  menu->addAction(m_showMDPlot);      // A plot of intensity vs bins
-  menu->addAction(m_showListData);    // Show data in table
-  menu->addAction(m_convertMDHistoToMatrixWorkspace);
-  menu->addAction(m_showLogs);
-}
-
-/** Add the actions that are appropriate for a PeaksWorkspace
-* @param menu :: The menu to store the items
-* @param WS :: The workspace related to the menu
-*/
-void MantidDockWidget::addPeaksWorkspaceMenuItems(
-    QMenu *menu, const Mantid::API::IPeaksWorkspace_const_sptr &WS) const {
-  Q_UNUSED(WS);
-  menu->addAction(m_showData);
-  menu->addSeparator();
-  menu->addAction(m_showDetectors);
-  menu->addAction(m_showHist);
-}
-
-/**
-* Add the actions that are appropriate for a WorkspaceGroup
-* @param menu :: The menu to store the items
-* @param groupWS :: [input] Workspace group related to the menu
-*/
-void MantidDockWidget::addWorkspaceGroupMenuItems(
-    QMenu *menu, const WorkspaceGroup_const_sptr &groupWS) const {
-  m_plotSpec->setEnabled(true);
-  menu->addAction(m_plotSpec);
-  m_plotSpecErr->setEnabled(true);
-  menu->addAction(m_plotSpecErr);
-  menu->addAction(m_colorFill);
-  m_colorFill->setEnabled(true);
-
-  // If appropriate, add "plot surface" and "plot contour" options
-  // Only add these if:
-  // - there are >2 workspaces in group
-  // - all are MatrixWorkspaces (otherwise they can't be plotted)
-  // - only one group is selected
-  if (m_tree->selectedItems().size() == 1) {
-    if (groupWS && groupWS->getNumberOfEntries() > 2) {
-      if (MantidGroupPlotGenerator::groupIsAllMatrixWorkspaces(groupWS)) {
-        menu->addAction(m_plotSurface);
-        m_plotSurface->setEnabled(true);
-        menu->addAction(m_plotContour);
-        m_plotContour->setEnabled(true);
-      }
-    }
-  }
-
-  menu->addSeparator();
-  menu->addAction(m_saveNexus);
-}
-
-/**
-* Add the actions that are appropriate for a MatrixWorkspace
-* @param menu :: The menu to store the items
-*/
-void MantidDockWidget::addTableWorkspaceMenuItems(QMenu *menu) const {
-  menu->addAction(m_showData);
-  menu->addAction(m_showTransposed);
-  menu->addAction(m_showHist);
-  menu->addAction(m_saveNexus);
-  menu->addAction(m_convertToMatrixWorkspace);
-}
-
-/**
-* Add menu for clearing workspace items.
-* @param menu : Parent menu.
-* @param wsName : Name of the selected workspace.
-*/
-void MantidDockWidget::addClearMenuItems(QMenu *menu, const QString &wsName) {
-  QMenu *clearMenu = new QMenu(tr("Clear Options"), this);
-
-  m_clearUB->setEnabled(m_mantidUI->hasUB(wsName));
-
-  clearMenu->addAction(m_clearUB);
-  menu->addMenu(clearMenu);
-}
-
-/**
-* Filter workspaces based on the string provided
-* @param text : the string to filter on.
-*/
-void MantidDockWidget::filterWorkspaceTree(const QString &text) {
-  const QString filterText = text.trimmed();
-  QRegExp filterRegEx(filterText, Qt::CaseInsensitive);
-
-  // show all items
-  QTreeWidgetItemIterator it(m_tree);
-  while (*it) {
-    (*it)->setHidden(false);
-    ++it;
-  }
-
-  int hiddenCount = 0;
-  QList<QTreeWidgetItem *> visibleGroups;
-  if (!filterText.isEmpty()) {
-
-    // Loop over everything (currently loaded) and top level
-    // find out what is already expanded
-    QStringList expanded;
-    int n = m_tree->topLevelItemCount();
-    for (int i = 0; i < n; ++i) {
-      auto item = m_tree->topLevelItem(i);
-      if (item->isExpanded()) {
-        expanded << item->text(0);
-      } else {
-        // expand everything that is at the top level (as we lazy load this is
-        // required)
-        item->setExpanded(true);
-      }
-    }
-
-    // filter based on the string
-    QTreeWidgetItemIterator it(m_tree, QTreeWidgetItemIterator::All);
-    while (*it) {
-      QTreeWidgetItem *item = (*it);
-      QVariant userData = item->data(0, Qt::UserRole);
-
-      if (!userData.isNull()) {
-        Workspace_sptr workspace = userData.value<Workspace_sptr>();
-        if (workspace) {
-          // I am a workspace
-          if (item->text(0).contains(filterRegEx)) {
-            // my name does match the filter
-            if (auto group =
-                    boost::dynamic_pointer_cast<WorkspaceGroup>(workspace)) {
-              // I am a group, I will want my children to be visible
-              // but I cannot do that until this iterator has finished
-              // store this pointer in a list for processing later
-              visibleGroups.append(item);
-              item->setHidden(false);
-            }
-
-            if (item->parent() == NULL) {
-              // No parent, I am a top level workspace - show me
-              item->setHidden(false);
-            } else {
-              // I am a child workspace of a group
-              // I match, so I want my parent to remain visible as well.
-              item->setHidden(false);
-              if (item->parent()->isHidden()) {
-                // I was previously hidden, show me and set to be expanded
-                --hiddenCount;
-                item->parent()->setHidden(false);
-                expanded << item->parent()->text(0);
-              }
-            }
-          } else {
-            // my name does not match the filter - hide me
-            item->setHidden(true);
-            ++hiddenCount;
-          }
-        }
-      }
-      ++it;
-    }
-
-    // make children of visible groups visible
-    for (auto itGroup = visibleGroups.begin(); itGroup != visibleGroups.end();
-         ++itGroup) {
-      QTreeWidgetItem *group = (*itGroup);
-      for (int i = 0; i < group->childCount(); i++) {
-        QTreeWidgetItem *child = group->child(i);
-        if (child->isHidden()) {
-          // I was previously hidden, show me
-          --hiddenCount;
-          child->setHidden(false);
-        }
-      }
-    }
-
-    // set the expanded state
-    for (int i = 0; i < n; ++i) {
-      auto item = m_tree->topLevelItem(i);
-      item->setExpanded(expanded.contains(item->text(0)));
-    }
-  }
-
-  // display a message if items are hidden
-  if (hiddenCount > 0) {
-    QString headerString =
-        QString("Workspaces (%1 filtered)").arg(QString::number(hiddenCount));
-    m_tree->headerItem()->setText(0, headerString);
-  } else {
-    m_tree->headerItem()->setText(0, "Workspaces");
-  }
-}
-
-void MantidDockWidget::clickedWorkspace(QTreeWidgetItem *item, int) {
-  Q_UNUSED(item);
-}
-
-void MantidDockWidget::workspaceSelected() {
-  QList<QTreeWidgetItem *> selectedItems = m_tree->selectedItems();
-  if (selectedItems.isEmpty())
-    return;
-
-  // If there are multiple workspaces selected group and save as Nexus
-  if (selectedItems.length() > 1) {
-    connect(m_saveButton, SIGNAL(clicked()), this, SLOT(saveWorkspaceGroup()));
-
-    // Don't display as a group
-    m_saveButton->setMenu(NULL);
-  } else {
-    // Don't run the save group function when clicked
-    disconnect(m_saveButton, SIGNAL(clicked()), this,
-               SLOT(saveWorkspaceGroup()));
-
-    // Remove all existing save algorithms from list
-    m_saveMenu->clear();
-
-    // Add some save algorithms
-    addSaveMenuOption("SaveNexus", "Nexus");
-    addSaveMenuOption("SaveAscii", "ASCII");
-    addSaveMenuOption("SaveAscii.1", "ASCII v1");
-
-    // Set the button to show the menu
-    m_saveButton->setMenu(m_saveMenu);
-  }
-
-  QString wsName = selectedItems[0]->text(0);
-  if (m_ads.doesExist(wsName.toStdString())) {
-    m_mantidUI->enableSaveNexus(wsName);
-  }
-}
-
-/**
- * Adds an algorithm to the save menu.
- *
- * @param algorithmString Algorithm string in format ALGO_NAME.VERSION or
- * ALGO_NAME
- * @param menuEntryName Text to be shown in menu
- */
-void MantidDockWidget::addSaveMenuOption(QString algorithmString,
-                                         QString menuEntryName) {
-  // Default to algo string if no entry name given
-  if (menuEntryName.isEmpty())
-    menuEntryName = algorithmString;
-
-  // Create the action and add data
-  QAction *saveAction = new QAction(menuEntryName, this);
-  saveAction->setData(QVariant(algorithmString));
-
-  // Connect the tigger slot to show algorithm dialog
-  connect(saveAction, SIGNAL(triggered()), this,
-          SLOT(handleShowSaveAlgorithm()));
-
-  // Add it to the menu
-  m_saveMenu->addAction(saveAction);
-}
-
-/**
- * Save all selected workspaces
- */
-void MantidDockWidget::saveWorkspaceGroup() {
-  QList<QTreeWidgetItem *> items = m_tree->selectedItems();
-  if (items.size() < 2)
-    return;
-
-  m_saveFolderDialog->setWindowTitle("Select save folder");
-  m_saveFolderDialog->setLabelText(QFileDialog::Accept, "Select");
-  m_saveFolderDialog->open(this, SLOT(saveWorkspacesToFolder(const QString &)));
-}
-
-/**
- * Handler for the directory browser being closed when selecting save on
- * multiple workspaces
- *
- * @param folder Path to folder to save workspaces in
- */
-void MantidDockWidget::saveWorkspacesToFolder(const QString &folder) {
-  QList<QTreeWidgetItem *> items = m_tree->selectedItems();
-
-  // Loop through multiple items selected from the mantid tree
-  QList<QTreeWidgetItem *>::iterator itr = items.begin();
-  for (itr = items.begin(); itr != items.end(); ++itr) {
-    QString workspaceName = (*itr)->text(0);
-    QString filename = folder + "/" + workspaceName + ".nxs";
-
-    IAlgorithm_sptr saveAlg = AlgorithmManager::Instance().create("SaveNexus");
-    saveAlg->initialize();
-    try {
-      saveAlg->setProperty("InputWorkspace", workspaceName.toStdString());
-      saveAlg->setProperty("Filename", filename.toStdString());
-      saveAlg->execute();
-    } catch (std::runtime_error &rte) {
-      docklog.error() << "Error saving workspace "
-                      << workspaceName.toStdString() << ": " << rte.what()
-                      << '\n';
-    }
-  }
-}
-
-/**
- * Handles a save algorithm being triggered by the Save menu.
- *
- * To select a specific algorithm add a QString to the data of the QAction
- * in the form ALGORITHM_NAME.VERSION or just ALGORITHM_NAME to use the
- * most recent version.
- */
-void MantidDockWidget::handleShowSaveAlgorithm() {
-  const QAction *sendingAction = dynamic_cast<QAction *>(sender());
-
-  if (sendingAction) {
-    const auto inputWorkspace = getSelectedWorkspace();
-    const QString wsName = QString::fromStdString(inputWorkspace->getName());
-    const QVariant data = sendingAction->data();
-
-    if (data.canConvert<QString>()) {
-      QString algorithmName;
-      int version = -1;
-
-      // Check if workspace is MD, this is the same check used in
-      // SaveNexusProcessed.cpp in the doExec()
-      if (bool(boost::dynamic_pointer_cast<const IMDEventWorkspace>(
-              inputWorkspace)) ||
-          bool(boost::dynamic_pointer_cast<const IMDHistoWorkspace>(
-              inputWorkspace))) {
-        // This will also be executed if the user clicks Save to ASCII or ASCII
-        // v1, therefore overwriting their choice and running
-        // SaveMD. SaveASCII doesn't support MD Workspaces, but if an issue,
-        // move the MD check to case 1: below
-        algorithmName = "SaveMD";
-
-      } else {
-        QStringList splitData = data.toString().split(".");
-        switch (splitData.length()) {
-        case 2:
-          version = splitData[1].toInt();
-        // intentional fall through to get algorithm name
-        case 1:
-          algorithmName = splitData[0];
-          break;
-        default:
-          m_mantidUI->saveNexusWorkspace();
-          return;
-        }
-      }
-      QHash<QString, QString> presets;
-      if (!wsName.isEmpty())
-        presets["InputWorkspace"] = wsName;
-
-      m_mantidUI->showAlgorithmDialog(algorithmName, presets, NULL, version);
-      return;
-    }
-  }
-
-  // If we can't get the type of algorithm this should be we can always fall
-  // back on Nexus
-  m_mantidUI->saveNexusWorkspace();
-}
-
-/**
-deleteWorkspaces
-*/
-void MantidDockWidget::deleteWorkspaces() {
-  QList<QTreeWidgetItem *> items = m_tree->selectedItems();
-  MantidMatrix *m =
-      dynamic_cast<MantidMatrix *>(m_mantidUI->appWindow()->activeWindow());
-
-  bool deleteExplorer = false;
-  bool deleteActive = false;
-
-  if ((m_deleteButton->hasFocus() || m_tree->hasFocus()) && !items.empty()) {
-    deleteExplorer = true;
-  }
-  if ((m && (strcmp(m->metaObject()->className(), "MantidMatrix") == 0)) &&
-      (!m->workspaceName().isEmpty() &&
-       m_ads.doesExist(m->workspaceName().toStdString()))) {
-    deleteActive = true;
-  }
-
-  if (deleteActive || deleteExplorer) {
-    QMessageBox::StandardButton reply;
-
-    if (m_appParent->isDeleteWorkspacePromptEnabled()) {
-      reply = QMessageBox::question(
-          this, "Delete Workspaces",
-          "Are you sure you want to delete the selected Workspaces?\n\nThis "
-          "prompt can be disabled from:\nPreferences->General->Confirmations",
-          QMessageBox::Yes | QMessageBox::No);
-    } else {
-      reply = QMessageBox::Yes;
-    }
-
-    if (reply == QMessageBox::Yes) {
-      if (deleteExplorer) {
-        // loop through multiple items selected from the mantid tree
-        QList<QTreeWidgetItem *>::iterator itr = items.begin();
-        for (itr = items.begin(); itr != items.end(); ++itr) {
-          // Sometimes we try to delete a workspace that's already been deleted.
-          if (m_ads.doesExist((*itr)->text(0).toStdString()))
-            m_mantidUI->deleteWorkspace((*itr)->text(0));
-        } // end of for loop for selected items
-      } else if (deleteActive) {
-        m_mantidUI->deleteWorkspace(m->workspaceName());
-      }
-    }
-  }
-}
-
-void MantidDockWidget::sortAscending() {
-  if (isTreeUpdating())
-    return;
-  m_tree->setSortOrder(Qt::AscendingOrder);
-  m_tree->sort();
-}
-
-void MantidDockWidget::sortDescending() {
-  if (isTreeUpdating())
-    return;
-  m_tree->setSortOrder(Qt::DescendingOrder);
-  m_tree->sort();
-}
-
-void MantidDockWidget::chooseByName() {
-  if (isTreeUpdating())
-    return;
-  m_tree->setSortScheme(MantidItemSortScheme::ByName);
-  m_tree->sort();
-}
-
-void MantidDockWidget::chooseByLastModified() {
-  if (isTreeUpdating())
-    return;
-  m_tree->setSortScheme(MantidItemSortScheme::ByLastModified);
-  m_tree->sort();
-}
-
-void MantidDockWidget::excludeItemFromSort(MantidTreeWidgetItem *item) {
-  static int counter = 1;
-
-  item->setSortPos(counter);
-
-  counter++;
-}
-
-/**
-* Saves a workspace based on the program the user chooses to save to.
-* @param name :: A string containing the name of the program
-*/
-
-void MantidDockWidget::saveToProgram(const QString &name) {
-  // Create a map for the keys and details to go into
-  std::map<std::string, std::string> programKeysAndDetails;
-  programKeysAndDetails["name"] = name.toStdString();
-
-  // Get a list of the program detail keys (mandatory - target, saveusing)
-  // (optional - arguments, save parameters, workspace type)
-  std::vector<std::string> programKeys =
-      (Mantid::Kernel::ConfigService::Instance().getKeys(
-          ("workspace.sendto." + programKeysAndDetails.find("name")->second)));
-
-  for (size_t i = 0; i < programKeys.size(); i++) {
-    // Assign a key to its value using the map
-    programKeysAndDetails[programKeys[i]] =
-        (Mantid::Kernel::ConfigService::Instance().getString(
-            ("workspace.sendto." + programKeysAndDetails.find("name")->second +
-             "." + programKeys[i])));
-  }
-
-  // Check to see if mandatory information is included
-  if ((programKeysAndDetails.count("name") != 0) &&
-      (programKeysAndDetails.count("target") != 0) &&
-      (programKeysAndDetails.count("saveusing") != 0)) {
-    std::string expTarget =
-        Poco::Path::expand(programKeysAndDetails.find("target")->second);
-
-    QFileInfo target = QString::fromStdString(expTarget);
-    if (target.exists()) {
-      try {
-        // Setup a shared pointer for the algorithm using the appropriate save
-        // type
-        Mantid::API::IAlgorithm_sptr alg;
-
-        // Convert to QString and create Algorithm
-        QString saveUsing = QString::fromStdString(
-            programKeysAndDetails.find("saveusing")->second);
-
-        // Create a new save based on what files the new program can open
-        alg = m_mantidUI->createAlgorithm(saveUsing);
-
-        // Get the file extention based on the workspace
-        Property *prop = alg->getProperty("Filename");
-        FileProperty *fileProp = dynamic_cast<FileProperty *>(prop);
-        std::string ext;
-        if (fileProp) {
-          ext = fileProp->getDefaultExt();
-        }
-
-        // Save as.. default save + the file type i.e .nxs
-        alg->setPropertyValue(
-            "fileName", "auto_save_" + selectedWsName.toStdString() + ext);
-
-        // Save the workspace
-        alg->setPropertyValue("InputWorkspace", selectedWsName.toStdString());
-
-        // If there are any save parameters
-        if (programKeysAndDetails.count("saveparameters") != 0) {
-          QString saveParametersGrouped = QString::fromStdString(
-              programKeysAndDetails.find("saveparameters")->second);
-          QStringList saveParameters = saveParametersGrouped.split(',');
-
-          // For each one found split it up and assign the parameter
-          for (int i = 0; i < saveParameters.size(); i++) {
-            QStringList sPNameAndDetail = saveParameters[i].split('=');
-            std::string saveParameterName =
-                sPNameAndDetail[0].trimmed().toStdString();
-            std::string saveParameterDetail =
-                sPNameAndDetail[1].trimmed().toStdString();
-            if (saveParameterDetail == "True")
-              alg->setProperty(saveParameterName, true);
-            else if (saveParameterDetail == "False")
-              alg->setProperty(saveParameterName, false);
-            else // if not true or false then must be a value
-            {
-              alg->setPropertyValue(saveParameterName, saveParameterDetail);
-            }
-          }
-        }
-
-        // Execute the save
-        m_mantidUI->executeAlgorithmAsync(alg, true);
-        // alg->execute();
-
-        // Get the save location of the file (should be default Mantid folder)
-        // std::string savedFile = alg->getProperty("Filename");
-        QString savedFile =
-            QString::fromStdString(alg->getProperty("Filename"));
-        QStringList arguments;
-
-        // Arguments for the program to take. Default will be the file anyway.
-        if (programKeysAndDetails.count("arguments") != 0) {
-          QString temp = QString::fromStdString(
-              programKeysAndDetails.find("arguments")->second);
-          temp.replace(QString("[file]"), savedFile);
-          // temp.replace(QString("[user]"), user;
-          arguments = temp.split(",");
-        } else
-          arguments.insert(0, savedFile);
-
-        // convert the list into a standard vector for compatibility with Poco
-        std::vector<std::string> argumentsV;
-
-        for (int i = 0; i < arguments.size(); i++) {
-          argumentsV.assign(1, (arguments[i].toStdString()));
-        }
-
-        // Execute the program
-        try {
-          Mantid::Kernel::ConfigService::Instance().launchProcess(expTarget,
-                                                                  argumentsV);
-        } catch (std::runtime_error &) {
-          QMessageBox::information(
-              this, "Error", "User tried to open program from: " +
-                                 QString::fromStdString(expTarget) +
-                                 " There was an error opening the program. "
-                                 "Please check the target and arguments list "
-                                 "to ensure that these are correct");
-        }
-      } catch (std::exception &) {
-        QMessageBox::information(
-            this, "Mantid - Send to Program",
-            "A file property wasn't found. Please check that the correct" +
-                QString("save algorithm was used.\n(View -> Preferences -> "
-                        "Mantid -> SendTo -> Edit -> SaveUsing)"));
-      }
-    } else
-      QMessageBox::information(this, "Target Path Error",
-                               "User tried to open program from: " +
-                                   QString::fromStdString(expTarget) +
-                                   " The target file path for the program "
-                                   "can't be found. Please check that the full "
-                                   "path is correct");
-  }
-}
-
-void MantidDockWidget::renameWorkspace() {
-  // get selected workspace
-  QList<QTreeWidgetItem *> selectedItems = m_tree->selectedItems();
-  QStringList selectedwsNames;
-  if (!selectedItems.empty()) {
-    for (int i = 0; i < selectedItems.size(); ++i) {
-      selectedwsNames.append(selectedItems[i]->text(0));
-    }
-  }
-  m_mantidUI->renameWorkspace(selectedwsNames);
-}
-
-void MantidDockWidget::showDetectorTable() {
-  // get selected workspace
-  QList<QTreeWidgetItem *> selectedItems = m_tree->selectedItems();
-  QString selctedwsName;
-  if (!selectedItems.empty()) {
-    selctedwsName = selectedItems[0]->text(0);
-  }
-  m_mantidUI->createDetectorTable(selctedwsName, std::vector<int>());
-}
-
-void MantidDockWidget::popupMenu(const QPoint &pos) {
-  QTreeWidgetItem *treeItem = m_tree->itemAt(pos);
-  selectedWsName = "";
-  if (treeItem)
-    selectedWsName = treeItem->text(0);
-  else
-    m_tree->selectionModel()->clear();
-  QMenu *menu(NULL);
-
-  // If no workspace is here then have load raw and dae
-  if (selectedWsName.isEmpty()) {
-    menu = m_loadMenu;
-  }
-  // else show instrument, sample logs and delete
-  else {
-    // Fresh menu
-    menu = new QMenu(this);
-    menu->setObjectName("WorkspaceContextMenu");
-    Mantid::API::Workspace_const_sptr ws;
-    try {
-      ws = m_ads.retrieve(selectedWsName.toStdString());
-    } catch (Mantid::Kernel::Exception::NotFoundError &) {
-      // Nothing to do
-      return;
-    }
-
-    // Add the items that are appropriate for the type
-    if (MatrixWorkspace_const_sptr matrixWS =
-            boost::dynamic_pointer_cast<const Mantid::API::MatrixWorkspace>(
-                ws)) {
-      addMatrixWorkspaceMenuItems(menu, matrixWS);
-    } else if (IMDEventWorkspace_const_sptr mdeventWS =
-                   boost::dynamic_pointer_cast<const IMDEventWorkspace>(ws)) {
-      addMDEventWorkspaceMenuItems(menu, mdeventWS);
-    } else if (IMDWorkspace_const_sptr mdWS =
-                   boost::dynamic_pointer_cast<const IMDWorkspace>(ws)) {
-      addMDHistoWorkspaceMenuItems(menu, mdWS);
-    } else if (IPeaksWorkspace_const_sptr peaksWS =
-                   boost::dynamic_pointer_cast<const IPeaksWorkspace>(ws)) {
-      addPeaksWorkspaceMenuItems(menu, peaksWS);
-    } else if (WorkspaceGroup_const_sptr groupWS =
-                   boost::dynamic_pointer_cast<const WorkspaceGroup>(ws)) {
-      addWorkspaceGroupMenuItems(menu, groupWS);
-    } else if (boost::dynamic_pointer_cast<const Mantid::API::ITableWorkspace>(
-                   ws)) {
-      addTableWorkspaceMenuItems(menu);
-    }
-    addClearMenuItems(menu, selectedWsName);
-
-    // Get the names of the programs for the send to option
-    std::vector<std::string> programNames =
-        (Mantid::Kernel::ConfigService::Instance().getKeys(
-            "workspace.sendto.name"));
-    bool firstPass(true);
-    // Check to see if any options aren't visible
-    for (size_t i = 0; i < programNames.size(); i++) {
-      std::string visible = Mantid::Kernel::ConfigService::Instance().getString(
-          "workspace.sendto." + programNames[i] + ".visible");
-      std::string target = Mantid::Kernel::ConfigService::Instance().getString(
-          "workspace.sendto." + programNames[i] + ".target");
-      if (Mantid::Kernel::ConfigService::Instance().isExecutable(target) &&
-          visible == "Yes") {
-        bool compatible(true);
-        std::string saveUsing(
-            Mantid::Kernel::ConfigService::Instance().getString(
-                "workspace.sendto." + programNames[i] + ".saveusing"));
-        try {
-          Mantid::API::IAlgorithm_sptr alg =
-              Mantid::API::AlgorithmManager::Instance().create(saveUsing);
-          alg->setPropertyValue("InputWorkspace", selectedWsName.toStdString());
-        } catch (std::exception &) {
-          compatible = false;
-        }
-        if (compatible) {
-          if (firstPass) {
-            m_saveToProgram = new QMenu(tr("Send to"), this);
-            menu->addMenu(m_saveToProgram);
-
-            // Sub-menu for program list
-            m_programMapper = new QSignalMapper(this);
-          }
-          QString name = QString::fromStdString(programNames[i]);
-          // Setup new menu option for the program
-          m_program = new QAction(name, this);
-          connect(m_program, SIGNAL(triggered()), m_programMapper, SLOT(map()));
-          // Send name of program when clicked
-          m_programMapper->setMapping(m_program, name);
-          m_saveToProgram->addAction(m_program);
-
-          // Set first pass to false so that it doesn't set up another menu
-          // entry for all programs.
-          firstPass = false;
-        }
-      }
-    }
-
-    // Tell the button what to listen for and what to do once clicked (if there
-    // is anything to connect it will be set to false)
-    if (!firstPass)
-      connect(m_programMapper, SIGNAL(mapped(const QString &)), this,
-              SLOT(saveToProgram(const QString &)));
-
-    // Rename is valid for all workspace types
-    menu->addAction(m_rename);
-    // separate delete
-    menu->addSeparator();
-    menu->addAction(m_delete);
-  }
-
-  // Show the menu at the cursor's current position
-  menu->popup(QCursor::pos());
-}
-
-void MantidDockWidget::groupingButtonClick() {
-  if (m_groupButton) {
-    QString qButtonName = m_groupButton->text();
-    if (qButtonName == "Group") {
-      m_mantidUI->groupWorkspaces();
-    } else if (qButtonName == "Ungroup") {
-      m_mantidUI->ungroupWorkspaces();
-    }
-  }
-}
-
-/// Plots a single spectrum from each selected workspace
-void MantidDockWidget::plotSpectra() { doPlotSpectra(false); }
-
-/// Plots a single spectrum from each selected workspace with errors
-void MantidDockWidget::plotSpectraErr() { doPlotSpectra(true); }
-
-/**
- * Plots a single spectrum from each selected workspace.
- * Option to plot errors or not.
- * @param errors :: [input] True if errors should be plotted, else false
- */
-void MantidDockWidget::doPlotSpectra(bool errors) {
-  const auto userInput = m_tree->chooseSpectrumFromSelected();
-  // An empty map will be returned if the user clicks cancel in the spectrum
-  // selection
-  if (userInput.plots.empty())
-    return;
-
-  if (userInput.tiled) {
-    m_mantidUI->plotSubplots(userInput.plots, MantidQt::DistributionDefault,
-                             errors);
-  } else {
-    m_mantidUI->plot1D(userInput.plots, true, MantidQt::DistributionDefault,
-                       errors, nullptr, false, userInput.waterfall);
-  }
-}
-
-/**
-* Draw a color fill plot of the workspaces that are currently selected.
-* NOTE: The drawing of 2D plots is currently intimately linked with MantidMatrix
-* meaning
-* that one of these must be generated first!
-*/
-void MantidDockWidget::drawColorFillPlot() {
-  // Get the selected workspaces
-  const QStringList wsNames = m_tree->getSelectedWorkspaceNames();
-  if (wsNames.empty())
-    return;
-
-  // Extract child workspace names from any WorkspaceGroups selected.
-  // Use a list to preserve workspace order.
-  QStringList allWsNames;
-  foreach (const QString wsName, wsNames) {
-    const auto wsGroup = boost::dynamic_pointer_cast<const WorkspaceGroup>(
-        m_ads.retrieve(wsName.toStdString()));
-    if (wsGroup) {
-      const auto children = wsGroup->getNames();
-      for (auto childWsName = children.begin(); childWsName != children.end();
-           ++childWsName) {
-        auto name = QString::fromStdString(*childWsName);
-        if (allWsNames.contains(name))
-          continue;
-        allWsNames.append(name);
-      }
-    } else
-      allWsNames.append(wsName);
-  }
-
-  m_mantidUI->drawColorFillPlots(allWsNames);
-}
-
-void MantidDockWidget::treeSelectionChanged() {
-  // get selected workspaces
-  QList<QTreeWidgetItem *> Items = m_tree->selectedItems();
-
-  if (m_groupButton) {
-    if (Items.size() == 1) {
-      // check it's group
-      QList<QTreeWidgetItem *>::const_iterator itr = Items.begin();
-      std::string selectedWSName = (*itr)->text(0).toStdString();
-      if (m_ads.doesExist(selectedWSName)) {
-        Workspace_sptr wsSptr = m_ads.retrieve(selectedWSName);
-        WorkspaceGroup_sptr grpSptr =
-            boost::dynamic_pointer_cast<WorkspaceGroup>(wsSptr);
-        if (grpSptr) {
-          m_groupButton->setText("Ungroup");
-          m_groupButton->setEnabled(true);
-        } else
-          m_groupButton->setEnabled(false);
-      }
-
-    } else if (Items.size() >= 2) {
-      m_groupButton->setText("Group");
-      m_groupButton->setEnabled(true);
-    } else if (Items.size() == 0) {
-      m_groupButton->setText("Group");
-      m_groupButton->setEnabled(false);
-    }
-  }
-
-  if (m_deleteButton)
-    m_deleteButton->setEnabled(Items.size() > 0);
-
-  if (m_saveButton)
-    m_saveButton->setEnabled(Items.size() > 0);
-
-  if (Items.size() > 0) {
-    auto item = *(Items.begin());
-    m_mantidUI->enableSaveNexus(item->text(0));
-  } else {
-    m_mantidUI->disableSaveNexus();
-  }
-}
-
-/**
-* Convert selected TableWorkspace to a MatrixWorkspace.
-*/
-void MantidDockWidget::convertToMatrixWorkspace() {
-  m_mantidUI->showAlgorithmDialog(QString("ConvertTableToMatrixWorkspace"), -1);
-}
-
-/**
-* Convert selected MDHistoWorkspace to a MatrixWorkspace.
-*/
-void MantidDockWidget::convertMDHistoToMatrixWorkspace() {
-  m_mantidUI->showAlgorithmDialog(QString("ConvertMDHistoToMatrixWorkspace"),
-                                  -1);
-}
-
-/**
-* Handler for the clear the UB matrix event.
-*/
-void MantidDockWidget::clearUB() {
-  QList<QTreeWidgetItem *> selectedItems = m_tree->selectedItems();
-  QStringList selctedWSNames;
-  if (!selectedItems.empty()) {
-    for (int i = 0; i < selectedItems.size(); ++i) {
-      selctedWSNames.append(selectedItems[i]->text(0));
-    }
-  }
-  m_mantidUI->clearUB(selctedWSNames);
-}
-
-/**
-* Accept a drag drop event and process the data appropriately
-* @param de :: The drag drop event
-*/
-void MantidDockWidget::dropEvent(QDropEvent *de) { m_tree->dropEvent(de); }
-
-/**
- * Create a 3D surface plot from the selected workspace group
- */
-void MantidDockWidget::plotSurface() {
-  // find the workspace group clicked on
-  const QStringList wsNames = m_tree->getSelectedWorkspaceNames();
-  if (!wsNames.empty()) {
-    const auto wsName = wsNames[0];
-    const auto wsGroup = boost::dynamic_pointer_cast<const WorkspaceGroup>(
-        m_ads.retrieve(wsName.toStdString()));
-    if (wsGroup) {
-      auto options =
-          m_tree->chooseSurfacePlotOptions(wsGroup->getNumberOfEntries());
-
-      auto plotter =
-          Mantid::Kernel::make_unique<MantidGroupPlotGenerator>(m_mantidUI);
-      plotter->plotSurface(wsGroup, options);
-    }
-  }
-}
-
-/**
- * Create a contour plot from the selected workspace group
- */
-void MantidDockWidget::plotContour() {
-  const QStringList wsNames = m_tree->getSelectedWorkspaceNames();
-  if (!wsNames.empty()) {
-    const auto wsName = wsNames[0];
-    const auto wsGroup = boost::dynamic_pointer_cast<const WorkspaceGroup>(
-        m_ads.retrieve(wsName.toStdString()));
-    if (wsGroup) {
-      auto options =
-          m_tree->chooseContourPlotOptions(wsGroup->getNumberOfEntries());
-
-      auto plotter =
-          Mantid::Kernel::make_unique<MantidGroupPlotGenerator>(m_mantidUI);
-      plotter->plotContour(wsGroup, options);
-    }
-  }
-}
\ No newline at end of file
diff --git a/MantidPlot/src/Mantid/MantidDock.h b/MantidPlot/src/Mantid/MantidDock.h
deleted file mode 100644
index a1b9e26c290f172298c0e078b387253cb7daf2a1..0000000000000000000000000000000000000000
--- a/MantidPlot/src/Mantid/MantidDock.h
+++ /dev/null
@@ -1,162 +0,0 @@
-#ifndef MANTIDDOCK_H
-#define MANTIDDOCK_H
-
-#include "MantidAPI/ExperimentInfo.h"
-#include "MantidAPI/IMDEventWorkspace_fwd.h"
-#include "MantidAPI/IMDWorkspace.h"
-#include "MantidAPI/IPeaksWorkspace_fwd.h"
-#include "MantidAPI/ITableWorkspace_fwd.h"
-#include "MantidAPI/MatrixWorkspace_fwd.h"
-#include "MantidAPI/WorkspaceGroup_fwd.h"
-
-#include <QActionGroup>
-#include <QAtomicInt>
-#include <QComboBox>
-#include <QDockWidget>
-#include <QList>
-#include <QPoint>
-#include <QSortFilterProxyModel>
-#include <QStringList>
-#include <QMap>
-
-#include <set>
-
-class MantidUI;
-class ApplicationWindow;
-class MantidTreeWidgetItem;
-class MantidTreeWidget;
-class QLabel;
-class QFileDialog;
-class QMenu;
-class QPushButton;
-class QTreeWidget;
-class QTreeWidgetItem;
-class QProgressBar;
-class QVBoxLayout;
-class QHBoxLayout;
-class QSignalMapper;
-class QSortFilterProxyModel;
-
-enum MantidItemSortScheme { ByName, ByLastModified };
-
-class MantidDockWidget : public QDockWidget {
-  Q_OBJECT
-public:
-  MantidDockWidget(MantidUI *mui, ApplicationWindow *parent);
-  ~MantidDockWidget() override;
-  QString getSelectedWorkspaceName() const;
-  Mantid::API::Workspace_sptr getSelectedWorkspace() const;
-  void dropEvent(QDropEvent *de) override;
-
-public slots:
-  void clickedWorkspace(QTreeWidgetItem *, int);
-  void saveWorkspaceGroup();
-  void deleteWorkspaces();
-  void renameWorkspace();
-  void populateChildData(QTreeWidgetItem *item);
-  void saveToProgram(const QString &name);
-  void sortAscending();
-  void sortDescending();
-  void chooseByName();
-  void chooseByLastModified();
-  void saveWorkspacesToFolder(const QString &folder);
-
-protected slots:
-  void popupMenu(const QPoint &pos);
-  void workspaceSelected();
-
-private slots:
-  void handleShowSaveAlgorithm();
-  void treeSelectionChanged();
-  void groupingButtonClick();
-  void plotSpectra();
-  void plotSpectraErr();
-  void drawColorFillPlot();
-  void showDetectorTable();
-  void convertToMatrixWorkspace();
-  void convertMDHistoToMatrixWorkspace();
-  void updateTreeOnADSUpdate();
-  void incrementUpdateCount();
-  void recordWorkspaceRename(QString, QString);
-  void clearUB();
-  void filterWorkspaceTree(const QString &text);
-  void plotSurface();
-  void plotContour();
-
-private:
-  void addSaveMenuOption(QString algorithmString, QString menuEntryName = "");
-  void setTreeUpdating(const bool state);
-  inline bool isTreeUpdating() const { return m_treeUpdating; }
-  void updateTree();
-  void populateTopLevel(
-      const std::map<std::string, Mantid::API::Workspace_sptr> &topLevelItems,
-      const QStringList &expanded);
-  MantidTreeWidgetItem *
-  addTreeEntry(const std::pair<std::string, Mantid::API::Workspace_sptr> &item,
-               QTreeWidgetItem *parent = NULL);
-  bool shouldBeSelected(QString name) const;
-  void createWorkspaceMenuActions();
-  void createSortMenuActions();
-  void setItemIcon(QTreeWidgetItem *item, const std::string &wsID);
-
-  void addMatrixWorkspaceMenuItems(
-      QMenu *menu,
-      const Mantid::API::MatrixWorkspace_const_sptr &matrixWS) const;
-  void addMDEventWorkspaceMenuItems(
-      QMenu *menu,
-      const Mantid::API::IMDEventWorkspace_const_sptr &mdeventWS) const;
-  void addMDHistoWorkspaceMenuItems(
-      QMenu *menu, const Mantid::API::IMDWorkspace_const_sptr &WS) const;
-  void addPeaksWorkspaceMenuItems(
-      QMenu *menu, const Mantid::API::IPeaksWorkspace_const_sptr &WS) const;
-  void addWorkspaceGroupMenuItems(
-      QMenu *menu, const Mantid::API::WorkspaceGroup_const_sptr &groupWS) const;
-  void addTableWorkspaceMenuItems(QMenu *menu) const;
-  void addClearMenuItems(QMenu *menu, const QString &wsName);
-
-  void excludeItemFromSort(MantidTreeWidgetItem *item);
-  void doPlotSpectra(bool errors);
-
-protected:
-  MantidTreeWidget *m_tree;
-  friend class MantidUI;
-
-private:
-  QString selectedWsName;
-
-  MantidUI *const m_mantidUI;
-
-  QPushButton *m_loadButton;
-  QPushButton *m_saveButton;
-  QMenu *m_loadMenu, *m_saveToProgram, *m_sortMenu, *m_saveMenu;
-  QPushButton *m_deleteButton;
-  QPushButton *m_groupButton;
-  QPushButton *m_sortButton;
-  QLineEdit *m_workspaceFilter;
-  QSignalMapper *m_loadMapper, *m_programMapper;
-  QActionGroup *m_sortChoiceGroup;
-  QFileDialog *m_saveFolderDialog;
-
-  // Context-menu actions
-  QAction *m_showData, *m_showInst, *m_plotSpec, *m_plotSpecErr,
-      *m_showDetectors, *m_showBoxData, *m_showVatesGui, *m_showSpectrumViewer,
-      *m_showSliceViewer, *m_colorFill, *m_showLogs, *m_showSampleMaterial,
-      *m_showHist, *m_showMDPlot, *m_showListData, *m_saveNexus, *m_rename,
-      *m_delete, *m_program, *m_ascendingSortAction, *m_descendingSortAction,
-      *m_byNameChoice, *m_byLastModifiedChoice, *m_showTransposed,
-      *m_convertToMatrixWorkspace, *m_convertMDHistoToMatrixWorkspace,
-      *m_clearUB, *m_plotSurface, *m_plotContour;
-
-  ApplicationWindow *m_appParent;
-
-  QAtomicInt m_updateCount;
-  bool m_treeUpdating;
-  Mantid::API::AnalysisDataServiceImpl &m_ads;
-  /// Temporarily keeps names of selected workspaces during tree update
-  /// in order to restore selection after update
-  QStringList m_selectedNames;
-  /// Keep a map of renamed workspaces between updates
-  QMap<QString, QString> m_renameMap;
-};
-
-#endif
diff --git a/MantidPlot/src/Mantid/MantidGroupPlotGenerator.cpp b/MantidPlot/src/Mantid/MantidGroupPlotGenerator.cpp
index 94f5a03c6492c22360b95443479747283e0acb7c..be6502706e3f8c997350a5fb5dd8952e6b1dbb24 100644
--- a/MantidPlot/src/Mantid/MantidGroupPlotGenerator.cpp
+++ b/MantidPlot/src/Mantid/MantidGroupPlotGenerator.cpp
@@ -3,6 +3,8 @@
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/Run.h"
 #include "MantidAPI/WorkspaceFactory.h"
+#include "MantidAPI/WorkspaceGroup.h"
+#include "MantidGeometry/MDGeometry/IMDDimension.h"
 #include <MantidQtMantidWidgets/MantidDisplayBase.h>
 
 using namespace MantidQt::MantidWidgets;
@@ -70,9 +72,9 @@ void MantidGroupPlotGenerator::plot(
         m_mantidUI->importMatrixWorkspace(matrixWS, -1, -1, false);
 
     // Change the default plot title
-    QString title =
-        QString("plot for %1, spectrum %2")
-            .arg(wsGroup->name().c_str(), QString::number(options.plotIndex));
+    QString title = QString("plot for %1, spectrum %2")
+                        .arg(wsGroup->getName().c_str(),
+                             QString::number(options.plotIndex));
 
     // Plot the correct type of graph
     if (graphType == Type::Surface) {
diff --git a/MantidPlot/src/Mantid/MantidGroupPlotGenerator.h b/MantidPlot/src/Mantid/MantidGroupPlotGenerator.h
index c4b8c8483d36621602b3555678e982c7ce262ecf..051ef36ce3c192bd20a09718043102cc9589554a 100644
--- a/MantidPlot/src/Mantid/MantidGroupPlotGenerator.h
+++ b/MantidPlot/src/Mantid/MantidGroupPlotGenerator.h
@@ -3,6 +3,7 @@
 
 #include "Graph3D.h"
 #include "MantidAPI/NumericAxis.h"
+#include "MantidAPI/WorkspaceGroup_fwd.h"
 #include "MantidMatrix.h"
 #include <MantidQtMantidWidgets/MantidSurfacePlotDialog.h>
 
diff --git a/MantidPlot/src/Mantid/MantidMatrix.cpp b/MantidPlot/src/Mantid/MantidMatrix.cpp
index 6251323398288f29ec6f4c3403021900200727fe..c29f3bb0a53b5783c8a0dcd3e71760c4dc1b9917 100644
--- a/MantidPlot/src/Mantid/MantidMatrix.cpp
+++ b/MantidPlot/src/Mantid/MantidMatrix.cpp
@@ -1239,6 +1239,10 @@ std::string MantidMatrix::saveToProject(ApplicationWindow *app) {
   return tsv.outputLines();
 }
 
+std::vector<std::string> MantidMatrix::getWorkspaceNames() {
+  return {m_strName};
+}
+
 /**
  * Creates a MantidMatrixTabExtension of a specified type
  * @param type: the type of the tab extension
diff --git a/MantidPlot/src/Mantid/MantidMatrix.h b/MantidPlot/src/Mantid/MantidMatrix.h
index 5b227af6a47526c3515c29ca8874e38c0628336a..a3621023dd08c8f3138156feee2477c5aeb86f6a 100644
--- a/MantidPlot/src/Mantid/MantidMatrix.h
+++ b/MantidPlot/src/Mantid/MantidMatrix.h
@@ -157,6 +157,8 @@ public:
   loadFromProject(const std::string &lines, ApplicationWindow *app,
                   const int fileVersion);
   std::string saveToProject(ApplicationWindow *app) override;
+  /// Returns a list of workspace names that are used by this window
+  std::vector<std::string> getWorkspaceNames() override;
 
   /// returns the workspace name
   const std::string &getWorkspaceName();
diff --git a/MantidPlot/src/Mantid/MantidMatrixCurve.cpp b/MantidPlot/src/Mantid/MantidMatrixCurve.cpp
index bbb80525696f0e63eb499b84f6a8723adb230081..cf38b44252fdf94650efe1afe3b7a0c68b176227 100644
--- a/MantidPlot/src/Mantid/MantidMatrixCurve.cpp
+++ b/MantidPlot/src/Mantid/MantidMatrixCurve.cpp
@@ -15,6 +15,7 @@
 #include "../MultiLayer.h"
 #include "ErrorBarSettings.h"
 #include "MantidKernel/ReadLock.h"
+#include <sstream>
 
 using namespace Mantid::API;
 using namespace MantidQt::API;
diff --git a/MantidPlot/src/Mantid/MantidMatrixFunction.cpp b/MantidPlot/src/Mantid/MantidMatrixFunction.cpp
index ba4ec08ecfab9c7775b615528184f31327c54b3a..8e89ef09d3cfe77650fe4f510ee59bd48c40243a 100644
--- a/MantidPlot/src/Mantid/MantidMatrixFunction.cpp
+++ b/MantidPlot/src/Mantid/MantidMatrixFunction.cpp
@@ -234,7 +234,7 @@ MantidMatrixFunctionWorkspaceObserver::MantidMatrixFunctionWorkspaceObserver(
 void MantidMatrixFunctionWorkspaceObserver::afterReplaceHandle(
     const std::string &wsName,
     const boost::shared_ptr<Mantid::API::Workspace> ws) {
-  if (m_function->m_workspace && wsName == m_function->m_workspace->name()) {
+  if (m_function->m_workspace && wsName == m_function->m_workspace->getName()) {
     auto mws =
         boost::dynamic_pointer_cast<const Mantid::API::MatrixWorkspace>(ws);
     if (mws) {
@@ -249,7 +249,7 @@ void MantidMatrixFunctionWorkspaceObserver::afterReplaceHandle(
 void MantidMatrixFunctionWorkspaceObserver::preDeleteHandle(
     const std::string &wsName,
     const boost::shared_ptr<Mantid::API::Workspace>) {
-  if (m_function->m_workspace && wsName == m_function->m_workspace->name()) {
+  if (m_function->m_workspace && wsName == m_function->m_workspace->getName()) {
     emit requestClose();
   }
 }
diff --git a/MantidPlot/src/Mantid/MantidMatrixModel.cpp b/MantidPlot/src/Mantid/MantidMatrixModel.cpp
index 587384289951d93961f2425a693b217320d52459..88e71c41a5a0e34ed4bd293d5d32c7a3daad464f 100644
--- a/MantidPlot/src/Mantid/MantidMatrixModel.cpp
+++ b/MantidPlot/src/Mantid/MantidMatrixModel.cpp
@@ -3,12 +3,11 @@
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/NumericAxis.h"
 #include "MantidAPI/SpectraAxis.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidAPI/RefAxis.h"
 #include "MantidAPI/TextAxis.h"
 #include "MantidKernel/ReadLock.h"
 
-#include "MantidGeometry/IDetector.h"
-
 #include <QApplication>
 #include <QObject>
 #include <QPalette>
@@ -282,15 +281,10 @@ bool MantidMatrixModel::checkMonitorCache(int row) const {
     if (m_monCache.contains(row)) {
       isMon = m_monCache.value(row);
     } else {
-      try {
-        size_t wsIndex = static_cast<size_t>(row);
-        auto det = m_workspace->getDetector(wsIndex);
-        isMon = det->isMonitor();
-        m_monCache.insert(row, isMon);
-      } catch (std::exception &) {
-        m_monCache.insert(row, false);
-        isMon = false;
-      }
+      const auto &specInfo = m_workspace->spectrumInfo();
+      size_t wsIndex = static_cast<size_t>(row);
+      isMon = specInfo.hasDetectors(wsIndex) && specInfo.isMonitor(wsIndex);
+      m_monCache.insert(row, isMon);
     }
     return isMon;
   } else {
@@ -310,15 +304,10 @@ bool MantidMatrixModel::checkMaskedCache(int row) const {
     if (m_maskCache.contains(row)) {
       isMasked = m_maskCache.value(row);
     } else {
-      try {
-        size_t wsIndex = static_cast<size_t>(row);
-        auto det = m_workspace->getDetector(wsIndex);
-        isMasked = det->isMasked();
-        m_maskCache.insert(row, isMasked);
-      } catch (std::exception &) {
-        m_maskCache.insert(row, false);
-        isMasked = false;
-      }
+      const auto &specInfo = m_workspace->spectrumInfo();
+      size_t wsIndex = static_cast<size_t>(row);
+      isMasked = specInfo.hasDetectors(wsIndex) && specInfo.isMasked(wsIndex);
+      m_maskCache.insert(row, isMasked);
     }
     return isMasked;
   } else {
diff --git a/MantidPlot/src/Mantid/MantidSampleLogDialog.cpp b/MantidPlot/src/Mantid/MantidSampleLogDialog.cpp
index 9d5cade184fdaa1a339374a1a3ee4c9233e25897..58d2cd19c3789fa0aa9f2db1b6c740c78859bec9 100644
--- a/MantidPlot/src/Mantid/MantidSampleLogDialog.cpp
+++ b/MantidPlot/src/Mantid/MantidSampleLogDialog.cpp
@@ -48,15 +48,22 @@ MantidSampleLogDialog::MantidSampleLogDialog(const QString &wsname,
   filterPeriod = new QRadioButton("Period");
   filterStatusPeriod = new QRadioButton("Status + Period");
   filterStatusPeriod->setChecked(true);
+  const std::vector<QRadioButton *> filterRadioButtons{
+      filterNone, filterStatus, filterPeriod, filterStatusPeriod};
 
+  // Add options to layout
   QVBoxLayout *vbox = new QVBoxLayout;
-  vbox->addWidget(filterNone);
-  vbox->addWidget(filterStatus);
-  vbox->addWidget(filterPeriod);
-  vbox->addWidget(filterStatusPeriod);
-  // vbox->addStretch(1);
+  for (auto *radioButton : filterRadioButtons) {
+    vbox->addWidget(radioButton);
+  }
   groupBox->setLayout(vbox);
 
+  // Changing filter option updates stats
+  for (auto *radioButton : filterRadioButtons) {
+    connect(radioButton, SIGNAL(toggled(bool)), this,
+            SLOT(showLogStatistics()));
+  }
+
   // -------------- Statistics on logs ------------------------
   std::string stats[NUM_STATS] = {
       "Min:", "Max:", "Mean:", "Time Avg:", "Median:", "Std Dev:", "Duration:"};
@@ -144,3 +151,20 @@ void MantidSampleLogDialog::importItem(QTreeWidgetItem *item) {
     throw std::invalid_argument("Error importing log entry, wrong data type");
   }
 }
+
+/**
+ * Return filter type based on which radio button is selected
+ * @returns :: Filter type selected in UI
+ */
+Mantid::API::LogFilterGenerator::FilterType
+MantidSampleLogDialog::getFilterType() const {
+  if (filterStatus->isChecked()) {
+    return Mantid::API::LogFilterGenerator::FilterType::Status;
+  } else if (filterPeriod->isChecked()) {
+    return Mantid::API::LogFilterGenerator::FilterType::Period;
+  } else if (filterStatusPeriod->isChecked()) {
+    return Mantid::API::LogFilterGenerator::FilterType::StatusAndPeriod;
+  } else {
+    return Mantid::API::LogFilterGenerator::FilterType::None;
+  }
+}
diff --git a/MantidPlot/src/Mantid/MantidSampleLogDialog.h b/MantidPlot/src/Mantid/MantidSampleLogDialog.h
index dcc3eac881ae7ec9e6fed845e1f53d38a5a12551..53f66bef70f6fa3398d273084c7a556b1358d6b6 100644
--- a/MantidPlot/src/Mantid/MantidSampleLogDialog.h
+++ b/MantidPlot/src/Mantid/MantidSampleLogDialog.h
@@ -60,6 +60,9 @@ public:
   /// Destructor
   virtual ~MantidSampleLogDialog() override;
 
+  /// Which type of filtering is selected
+  Mantid::API::LogFilterGenerator::FilterType getFilterType() const override;
+
 protected slots:
 
   /// Import a single item
diff --git a/MantidPlot/src/Mantid/MantidTable.cpp b/MantidPlot/src/Mantid/MantidTable.cpp
index de0aea63a1cb1e8c5c7d095bcea96e6fdea1ed54..d6ab77d7e50354730737cbc1586ca09aaba5977b 100644
--- a/MantidPlot/src/Mantid/MantidTable.cpp
+++ b/MantidPlot/src/Mantid/MantidTable.cpp
@@ -133,6 +133,8 @@ void MantidTable::fillTable() {
     // Print out the data in each row of this column
     for (int j = 0; j < static_cast<int>(m_ws->rowCount()); j++) {
       std::ostringstream ostr;
+      std::locale systemLocale("");
+      ostr.imbue(systemLocale);
       // Avoid losing precision for numeric data
       if (c->type() == "double") {
         ostr.precision(std::numeric_limits<double>::max_digits10);
@@ -199,6 +201,8 @@ void MantidTable::fillTableTransposed() {
     // Print out the data in each row of this column
     for (int j = 0; j < static_cast<int>(m_ws->rowCount()); ++j) {
       std::ostringstream ostr;
+      const std::locale systemLocale("");
+      ostr.imbue(systemLocale);
       // Avoid losing precision for numeric data
       if (c->type() == "double") {
         ostr.precision(std::numeric_limits<double>::max_digits10);
@@ -285,15 +289,19 @@ void MantidTable::cellEdited(int row, int col) {
     oldText.remove(QRegExp("\\s"));
   }
 
-  std::string text = oldText.toStdString();
+  const std::string text = oldText.toStdString();
 
   // Have the column convert the text to a value internally
   int index = row;
-  c->read(index, text);
+  std::istringstream textStream(text);
+  const std::locale systemLocale("");
+  textStream.imbue(systemLocale);
+  c->read(index, textStream);
 
   // Set the table view to be the same text after editing.
   // That way, if the string was stupid, it will be reset to the old value.
   std::ostringstream s;
+  s.imbue(systemLocale);
   // Avoid losing precision for numeric data
   if (c->type() == "double") {
     s.precision(std::numeric_limits<double>::max_digits10);
diff --git a/MantidPlot/src/Mantid/MantidUI.cpp b/MantidPlot/src/Mantid/MantidUI.cpp
index 064c267d5b4507074bc3111903d0afc5c3525984..f39e24ce1fcf5b6059b21db174dcd818b1f2e644 100644
--- a/MantidPlot/src/Mantid/MantidUI.cpp
+++ b/MantidPlot/src/Mantid/MantidUI.cpp
@@ -53,7 +53,10 @@
 #include "MantidAPI/IMDEventWorkspace.h"
 #include "MantidAPI/IMDHistoWorkspace.h"
 #include "MantidAPI/IPeaksWorkspace.h"
+#include "MantidAPI/LogFilterGenerator.h"
 #include "MantidAPI/Run.h"
+#include "MantidAPI/SpectrumInfo.h"
+#include "MantidAPI/WorkspaceGroup.h"
 
 #include <QListWidget>
 #include <QMdiArea>
@@ -128,6 +131,17 @@ QString getLegendKey(const QString &wsName, const int spectrum) {
   return QString();
 }
 
+/// Get all graph legend keys in one string
+QString getLegendKeys(const QString &wsName, const std::set<int> &spectra) {
+  QString legendText = wsName + '\n';
+  int curveIndex(0);
+  for (const auto &spec : spectra) {
+    legendText += "\\l(" + QString::number(++curveIndex) + ")" +
+                  getLegendKey(wsName, spec) + "\n";
+  }
+  return legendText;
+}
+
 /// Decide whether this graph in a multilayer plot should have an X axis label
 bool drawXAxisLabel(const int row, const int col, const int nRows,
                     const int nCols, const int nPlots) {
@@ -567,7 +581,7 @@ MantidUI::importMatrixWorkspace(const MatrixWorkspace_sptr workspace, int lower,
                                 int upper, bool showDlg) {
   MantidMatrix *matrix = 0;
   if (workspace) {
-    const QString wsName(workspace->name().c_str());
+    const QString wsName(workspace->getName().c_str());
     if (showDlg) {
       ImportWorkspaceDlg dlg(appWindow(), workspace->getNumberHistograms());
       if (dlg.exec() == QDialog::Accepted) {
@@ -832,8 +846,7 @@ void MantidUI::showVatesSimpleInterface() {
         connect(vsui, SIGNAL(requestClose()), m_vatesSubWindow, SLOT(close()));
         vsui->setParent(m_vatesSubWindow);
         m_vatesSubWindow->setWindowTitle("Vates Simple Interface");
-        vsui->setupPluginMode();
-        // m_appWindow->setGeometry(m_vatesSubWindow, vsui);
+        vsui->setupPluginMode(wsType, instrumentName);
         m_vatesSubWindow->setWidget(vsui);
         m_vatesSubWindow->widget()->show();
         vsui->renderWorkspace(wsName, wsType, instrumentName);
@@ -1261,6 +1274,7 @@ Table *MantidUI::createDetectorTable(
                                  // value should be displayed
   QVector<QList<QVariant>> tableColValues;
   tableColValues.resize(nrows);
+  const auto &spectrumInfo = ws->spectrumInfo();
   PARALLEL_FOR_IF(Mantid::Kernel::threadSafe(*ws))
   for (int row = 0; row < nrows; ++row) {
     // Note PARALLEL_START_INTERUPT_REGION & friends apparently not needed (like
@@ -1305,31 +1319,34 @@ Table *MantidUI::createDetectorTable(
       }
 
       // Geometry
-      IDetector_const_sptr det = ws->getDetector(wsIndex);
+      if (!spectrumInfo.hasDetectors(wsIndex))
+        throw std::runtime_error("No detectors found.");
       if (!signedThetaParamRetrieved) {
         const std::vector<std::string> &parameters =
-            det->getStringParameter("show-signed-theta", true); // recursive
+            spectrumInfo.detector(wsIndex)
+                .getStringParameter("show-signed-theta", true); // recursive
         showSignedTwoTheta = (!parameters.empty() &&
                               find(parameters.begin(), parameters.end(),
                                    "Always") != parameters.end());
         signedThetaParamRetrieved = true;
       }
-      // We want the position of the detector relative to the sample
-      Mantid::Kernel::V3D pos = det->getPos() - sample->getPos();
       double R(0.0), theta(0.0), phi(0.0);
-      pos.getSpherical(R, theta, phi);
-      // Need to get R, theta through these methods to be correct for grouped
-      // detectors
-      R = det->getDistance(*sample);
+      // R and theta used as dummy variables
+      // Note: phi is the angle around Z, not necessarily the beam direction.
+      spectrumInfo.position(wsIndex).getSpherical(R, theta, phi);
+      // R is actually L2 (same as R if sample is at (0,0,0))
+      R = spectrumInfo.l2(wsIndex);
+      // Theta is actually 'twoTheta' (twice the scattering angle), if Z is the
+      // beam direction this corresponds to theta in spherical coordinates.
       try {
-        theta = showSignedTwoTheta ? ws->detectorSignedTwoTheta(*det)
-                                   : ws->detectorTwoTheta(*det);
+        theta = showSignedTwoTheta ? spectrumInfo.signedTwoTheta(wsIndex)
+                                   : spectrumInfo.twoTheta(wsIndex);
         theta *= 180.0 / M_PI; // To degrees
       } catch (const Mantid::Kernel::Exception::InstrumentDefinitionError &ex) {
         // Log the error and leave theta as it is
         g_log.error(ex.what());
       }
-      QString isMonitor = det->isMonitor() ? "yes" : "no";
+      QString isMonitor = spectrumInfo.isMonitor(wsIndex) ? "yes" : "no";
 
       colValues << QVariant(specNo) << QVariant(detIds);
       // Y/E
@@ -1342,8 +1359,10 @@ Table *MantidUI::createDetectorTable(
 
         try {
           // Get unsigned theta and efixed value
+          IDetector_const_sptr det(&spectrumInfo.detector(wsIndex),
+                                   Mantid::NoDeleting());
           double efixed = ws->getEFixed(det);
-          double usignTheta = ws->detectorTwoTheta(*det) * 0.5;
+          double usignTheta = spectrumInfo.twoTheta(wsIndex) * 0.5;
 
           double q = Mantid::Kernel::UnitConversion::run(usignTheta, efixed);
           colValues << QVariant(q);
@@ -2394,12 +2413,29 @@ void MantidUI::importStrSeriesLog(const QString &logName, const QString &data,
 */
 void MantidUI::importNumSeriesLog(const QString &wsName, const QString &logName,
                                   int filter) {
-  // if you need to add a final filter valure to the end of the filter to match
+  // if you need to add a final filter value to the end of the filter to match
   // the extent of the data, then set this to the index of the row to add the
   // value
   int addFinalFilterValueIndex = 0;
   Mantid::Kernel::DateAndTime lastFilterTime;
 
+  // Convert input int into enum value
+  const Mantid::API::LogFilterGenerator::FilterType filterType = [&filter]() {
+    switch (filter) {
+    case 0:
+      return Mantid::API::LogFilterGenerator::FilterType::None;
+    case 1:
+      return Mantid::API::LogFilterGenerator::FilterType::Status;
+    case 2:
+      return Mantid::API::LogFilterGenerator::FilterType::Period;
+    case 3:
+      return Mantid::API::LogFilterGenerator::FilterType::StatusAndPeriod;
+    default:
+      return Mantid::API::LogFilterGenerator::FilterType::None;
+    }
+  }();
+
+  // Make sure the workspace exists and contains the log
   MatrixWorkspace_const_sptr ws =
       boost::dynamic_pointer_cast<const MatrixWorkspace>(getWorkspace(wsName));
   if (!ws)
@@ -2410,12 +2446,14 @@ void MantidUI::importNumSeriesLog(const QString &wsName, const QString &logName,
   if (!logData)
     return;
 
-  Mantid::Kernel::LogFilter flt(logData);
+  // Generate the filter
+  Mantid::API::LogFilterGenerator filterGenerator(filterType, ws);
+  const auto &flt = filterGenerator.generateFilter(logName.toStdString());
 
   // Get a map of time/value. This greatly speeds up display.
   // NOTE: valueAsMap() skips repeated values.
   std::map<DateAndTime, double> time_value_map =
-      flt.data()->valueAsCorrectMap();
+      flt->data()->valueAsCorrectMap();
   int rowcount = static_cast<int>(time_value_map.size());
   int colCount = 2;
 
@@ -2465,9 +2503,6 @@ void MantidUI::importNumSeriesLog(const QString &wsName, const QString &logName,
     t->setColumnType(0, Table::Numeric);
   }
 
-  // The time when the first data was recorded.
-  auto firstTime = time_value_map.begin()->first;
-
   // Make the column header with the units, if any
   QString column1 = label.section("-", 1);
   if (logData->units() != "")
@@ -2477,65 +2512,9 @@ void MantidUI::importNumSeriesLog(const QString &wsName, const QString &logName,
 
   int iValueCurve = 0;
 
-  // Applying filters
-  if (filter > 0) {
-    Mantid::Kernel::TimeSeriesProperty<bool> *f = 0;
-    if (filter == 1 || filter == 3) {
-      // one of the filters is the running status
-      try {
-        f = dynamic_cast<Mantid::Kernel::TimeSeriesProperty<bool> *>(
-            ws->run().getLogData("running"));
-        if (f)
-          flt.addFilter(*f);
-        else {
-          t->setconfirmcloseFlag(false);
-          t->setAttribute(Qt::WA_DeleteOnClose);
-          t->close();
-          importNumSeriesLog(wsName, logName, 0);
-          return;
-        }
-        // If filter records start later than the data we add a value at the
-        // filter's front
-        if (f->firstTime() > firstTime) {
-          // add a "not running" value to the status filter
-          Mantid::Kernel::TimeSeriesProperty<bool> atStart("tmp");
-          atStart.addValue(firstTime, false);
-          atStart.addValue(f->firstTime(), f->firstValue());
-          flt.addFilter(atStart);
-        }
-      } catch (...) {
-        t->setconfirmcloseFlag(false);
-        t->setAttribute(Qt::WA_DeleteOnClose);
-        t->close();
-        importNumSeriesLog(wsName, logName, 0);
-        return;
-      }
-    }
-
-    if (filter == 2 || filter == 3) {
-      std::vector<Mantid::Kernel::Property *> ps = ws->run().getLogData();
-      for (std::vector<Mantid::Kernel::Property *>::const_iterator it =
-               ps.begin();
-           it != ps.end(); ++it)
-        if ((*it)->name().find("period ") == 0) {
-          try {
-            f = dynamic_cast<Mantid::Kernel::TimeSeriesProperty<bool> *>(*it);
-            if (f)
-              flt.addFilter(*f);
-            else {
-              importNumSeriesLog(wsName, logName, 0);
-              return;
-            }
-          } catch (...) {
-            importNumSeriesLog(wsName, logName, 0);
-            return;
-          }
-
-          break;
-        }
-    }
-
-    if (flt.filter()) {
+  // Applying filter column to table
+  if (filterType != Mantid::API::LogFilterGenerator::FilterType::None) {
+    if (flt->filter()) {
       // Valid filter was found
       t->addColumns(2);
       t->setColName(2, "FTime");
@@ -2551,29 +2530,30 @@ void MantidUI::importNumSeriesLog(const QString &wsName, const QString &logName,
       t->setColPlotDesignation(2, Table::X);
       t->setColName(3, "Filter");
 
-      if (flt.filter()->size() > rowcount) {
-        t->addRows(flt.filter()->size() - rowcount);
+      if (flt->filter()->size() > rowcount) {
+        t->addRows(flt->filter()->size() - rowcount);
       }
 
-      if (flt.data()->size() > rowcount) {
-        t->addRows(flt.data()->size() - rowcount);
+      if (flt->data()->size() > rowcount) {
+        t->addRows(flt->data()->size() - rowcount);
       }
 
-      for (int i = 0; i < flt.filter()->size(); i++) {
-        if (flt.filter()->nthInterval(i).begin() >
+      for (int i = 0; i < flt->filter()->size(); i++) {
+        if (flt->filter()->nthInterval(i).begin() >
             0) // protect against bizarre values we sometimes get
         {
-          std::string time_string = extractLogTime(
-              flt.filter()->nthInterval(i).begin(), useAbsoluteDate, startTime);
+          std::string time_string =
+              extractLogTime(flt->filter()->nthInterval(i).begin(),
+                             useAbsoluteDate, startTime);
 
           t->setText(i, 2, QString::fromStdString(time_string));
-          t->setCell(i, 3, !flt.filter()->nthValue(i));
-          if ((i + 1 == flt.filter()->size()) &&
-              (!flt.filter()->nthValue(
+          t->setCell(i, 3, !flt->filter()->nthValue(i));
+          if ((i + 1 == flt->filter()->size()) &&
+              (!flt->filter()->nthValue(
                   i))) // last filter value and set to be filtering
           {
             addFinalFilterValueIndex = i + 1;
-            lastFilterTime = flt.filter()->nthInterval(i).begin();
+            lastFilterTime = flt->filter()->nthInterval(i).begin();
           }
         }
       }
@@ -2601,13 +2581,13 @@ void MantidUI::importNumSeriesLog(const QString &wsName, const QString &logName,
 
   try {
     // Set the filter strings
-    if (filter && flt.filter() && lastTime < flt.filter()->lastTime()) {
+    if (filter && flt->filter() && lastTime < flt->filter()->lastTime()) {
       rowcount = static_cast<int>(time_value_map.size());
       if (rowcount == t->numRows())
         t->addRows(1);
 
       std::string time_string =
-          extractLogTime(flt.filter()->lastTime(), useAbsoluteDate, startTime);
+          extractLogTime(flt->filter()->lastTime(), useAbsoluteDate, startTime);
 
       t->setText(rowcount, 0, QString::fromStdString(time_string));
       t->setCell(rowcount, 1, lastValue);
@@ -2643,7 +2623,7 @@ void MantidUI::importNumSeriesLog(const QString &wsName, const QString &logName,
     return;
 
   QStringList colNames;
-  if (filter && flt.filter()) {
+  if (filter && flt->filter()) {
     colNames << t->colName(3);
   }
   colNames << t->colName(1);
@@ -2656,7 +2636,7 @@ void MantidUI::importNumSeriesLog(const QString &wsName, const QString &logName,
   // Set x-axis label format
   if (useAbsoluteDate) {
     Mantid::Kernel::DateAndTime label_as_ptime =
-        flt.data()->nthInterval(0).begin();
+        flt->data()->nthInterval(0).begin();
     QDateTime dt = QDateTime::fromTime_t(uint(label_as_ptime.to_localtime_t()));
     QString format = dt.toString(Qt::ISODate) + ";HH:mm:ss";
     g->setLabelsDateTimeFormat(2, ScaleDraw::Date, format);
@@ -2670,7 +2650,7 @@ void MantidUI::importNumSeriesLog(const QString &wsName, const QString &logName,
   QPen pn = QPen(Qt::black);
   g->setCurvePen(iValueCurve, pn);
 
-  if (filter && flt.filter()) {
+  if (filter && flt->filter()) {
     int iFilterCurve = 1;
     QwtPlotCurve *c = g->curve(iFilterCurve);
     if (c) {
@@ -2856,7 +2836,7 @@ Table *MantidUI::createTableFromSelectedRows(MantidMatrix *m, bool errs,
     return NULL;
 
   return createTableFromSpectraList(
-      m->name(), QString::fromStdString(m->workspace()->name()), indexList,
+      m->name(), QString::fromStdString(m->workspace()->getName()), indexList,
       errs, binCentres);
 }
 
@@ -3432,25 +3412,39 @@ MultiLayer *MantidUI::plotSubplots(const QMultiMap<QString, set<int>> &toPlot,
   multi->setCloseOnEmpty(true);
   multi->arrangeLayers(true, true);
 
+  QStringList legends; // Legends for each plot
+  legends.reserve(nSubplots);
   int row(0), col(0);
   if (nWorkspaces == 1) {
     // One workspace, each spectrum in its own subplot
     const auto &wsName = toPlot.begin().key();
     const auto &spectra = toPlot.begin().value();
     for (const auto &spec : spectra) {
+      const std::set<int> spectraSet{spec};
       plotLayerOfMultilayer(multi, errs, plotAsDistribution, row, col, wsName,
-                            std::set<int>{spec});
+                            spectraSet);
+      legends.append(getLegendKeys(wsName, spectraSet));
     }
   } else {
     // Each workspace in its own subplot
     for (auto iter = toPlot.constBegin(); iter != toPlot.constEnd(); ++iter) {
-      plotLayerOfMultilayer(multi, errs, plotAsDistribution, row, col,
-                            iter.key(), iter.value());
+      const auto &wsName = iter.key();
+      const auto &spectra = iter.value();
+      plotLayerOfMultilayer(multi, errs, plotAsDistribution, row, col, wsName,
+                            spectra);
+      legends.append(getLegendKeys(wsName, spectra));
     }
   }
 
   multi->setCommonAxisScales();
   multi->arrangeLayers(true, true);
+
+  // add legends last of all, so they are in the correct place
+  for (int index = 0; index < multi->layers(); ++index) {
+    auto *layer = multi->layer(index + 1); // MultiLayer has 1-based indices
+    layer->newLegend(legends[index]);
+  }
+
   // Check if window does not contain any curves and should be closed
   multi->maybeNeedToClose();
 
@@ -3487,34 +3481,31 @@ void MantidUI::plotLayerOfMultilayer(MultiLayer *multi, const bool plotErrors,
     }
   };
 
-  // Lambda to set legend and axis label hiding
-  const auto formatPlot = [&nRows, &nCols, &nPlots](
-      Graph *layer, const QString &legendText, const int row, const int col) {
-    const bool drawYAxisLabel = col == 0;
-    layer->newLegend(legendText);
-    if (!drawXAxisLabel(row, col, nRows, nCols, nPlots)) {
-      layer->setXAxisTitle(QString::null);
-    }
-    if (!drawYAxisLabel) {
-      layer->setYAxisTitle(QString::null);
-    }
-  };
+  // Lambda to set axis label hiding
+  const auto formatAxes =
+      [&nRows, &nCols, &nPlots](Graph *layer, const int row, const int col) {
+        const bool drawYAxisLabel = col == 0;
+        if (!drawXAxisLabel(row, col, nRows, nCols, nPlots)) {
+          layer->setXAxisTitle(QString::null);
+        }
+        if (!drawYAxisLabel) {
+          layer->setYAxisTitle(QString::null);
+        }
+      };
 
   const bool isFitResult = workspaceIsFitResult(wsName);
 
   const int layerIndex = row * nCols + col + 1; // layers numbered from 1
   auto *layer = multi->layer(layerIndex);
-  QString legendText = wsName + '\n';
-  int curveIndex(0);
   for (const int spec : spectra) {
     const auto plotType = isFitResult ? getCurveTypeForFitResult(spec)
                                       : GraphOptions::Unspecified;
     layer->insertCurve(wsName, spec, plotErrors, plotType, plotDist);
-    legendText += "\\l(" + QString::number(++curveIndex) + ")" +
-                  getLegendKey(wsName, spec) + "\n";
   }
+  m_appWindow->setPreferences(layer); // apply default style
+  layer->removeTitle();
   setInitialAutoscale(layer);
-  formatPlot(layer, legendText, row, col);
+  formatAxes(layer, row, col);
   incrementCounters(row, col);
 }
 
diff --git a/MantidPlot/src/Mantid/PeakPickerTool.cpp b/MantidPlot/src/Mantid/PeakPickerTool.cpp
index 084ff8b1e0b6b1a27ed0e3778f8c9c7cd0ee0260..f81882e6262b174acb6f989471ea87b91161b259 100644
--- a/MantidPlot/src/Mantid/PeakPickerTool.cpp
+++ b/MantidPlot/src/Mantid/PeakPickerTool.cpp
@@ -654,7 +654,8 @@ void PeakPickerTool::replot(MantidQt::MantidWidgets::PropertyHandler *h) const {
       // fc->loadData();
       auto ws = boost::dynamic_pointer_cast<const Mantid::API::MatrixWorkspace>(
           m_fitPropertyBrowser->getWorkspace());
-      fc->loadMantidData(ws, m_fitPropertyBrowser->workspaceIndex());
+      fc->loadMantidData(ws, m_fitPropertyBrowser->workspaceIndex(),
+                         m_fitPropertyBrowser->getPeakRadius());
     }
   }
 }
@@ -886,7 +887,8 @@ void PeakPickerTool::plotFitFunction(
                    m_fitPropertyBrowser->endX());
       auto ws = boost::dynamic_pointer_cast<const Mantid::API::MatrixWorkspace>(
           m_fitPropertyBrowser->getWorkspace());
-      fc->loadMantidData(ws, m_fitPropertyBrowser->workspaceIndex());
+      fc->loadMantidData(ws, m_fitPropertyBrowser->workspaceIndex(),
+                         m_fitPropertyBrowser->getPeakRadius());
       // Graph now owns m_curve. Use m_curve->removeMe() to remove (and delete)
       // from Graph
       d_graph->insertCurve(fc);
diff --git a/MantidPlot/src/Mantid/SampleLogDialogBase.cpp b/MantidPlot/src/Mantid/SampleLogDialogBase.cpp
index 0d1eebd072f40dcbe6c7e9e571e905beef37866c..06c5051001f540db926def34c826338d7637d40f 100644
--- a/MantidPlot/src/Mantid/SampleLogDialogBase.cpp
+++ b/MantidPlot/src/Mantid/SampleLogDialogBase.cpp
@@ -1,15 +1,13 @@
 #include "SampleLogDialogBase.h"
 
-// Mantid API
-#include <MantidAPI/MultipleExperimentInfos.h>
-#include <MantidAPI/IMDWorkspace.h>
+#include "MantidAPI/AnalysisDataService.h"
+#include "MantidAPI/IMDWorkspace.h"
+#include "MantidAPI/MultipleExperimentInfos.h"
 #include "MantidAPI/Run.h"
 
-// Mantid Kernel
-#include <MantidKernel/TimeSeriesProperty.h>
-#include <MantidKernel/ArrayProperty.h>
+#include "MantidKernel/ArrayProperty.h"
+#include "MantidKernel/Strings.h"
 
-// Qt
 #include <QMenu>
 #include <QFileInfo>
 #include <QHeaderView>
@@ -86,11 +84,14 @@ void SampleLogDialogBase::importSelectedLogs() {
 *	@date 05/11/2009
 */
 void SampleLogDialogBase::showLogStatistics() {
+
+  const auto &filter = this->getFilterType();
+
   QList<QTreeWidgetItem *> items = m_tree->selectedItems();
   QListIterator<QTreeWidgetItem *> pItr(items);
   if (pItr.hasNext()) {
     // Show only the first one
-    showLogStatisticsOfItem(pItr.next());
+    showLogStatisticsOfItem(pItr.next(), filter);
   }
 }
 
@@ -99,12 +100,14 @@ void SampleLogDialogBase::showLogStatistics() {
 * Show the stats of the log for the selected item
 *
 *	@param item :: The item to be imported
+* @param filter :: Type of filtering (default none)
 *	@throw invalid_argument if format identifier for the item is wrong
 *
 *	@author Martyn Gigg, Tessella Support Services plc
 *	@date 05/11/2009
 */
-void SampleLogDialogBase::showLogStatisticsOfItem(QTreeWidgetItem *item) {
+void SampleLogDialogBase::showLogStatisticsOfItem(
+    QTreeWidgetItem *item, const LogFilterGenerator::FilterType filter) {
   // Assume that you can't show the stats
   for (size_t i = 0; i < NUM_STATS; i++) {
     statValues[i]->setText(QString(""));
@@ -127,19 +130,23 @@ void SampleLogDialogBase::showLogStatisticsOfItem(QTreeWidgetItem *item) {
       return;
 
     // Now the log
+    const auto &logName = item->text(0).toStdString();
     Mantid::Kernel::TimeSeriesPropertyStatistics stats;
-    Mantid::Kernel::Property *logData =
-        m_ei->run().getLogData(item->text(0).toStdString());
-    // Get the stas if its a series of int or double; fail otherwise
+    Mantid::Kernel::Property *logData = m_ei->run().getLogData(logName);
+    // Get the stats if its a series of int or double; fail otherwise
     Mantid::Kernel::TimeSeriesProperty<double> *tspd =
         dynamic_cast<TimeSeriesProperty<double> *>(logData);
     Mantid::Kernel::TimeSeriesProperty<int> *tspi =
         dynamic_cast<TimeSeriesProperty<int> *>(logData);
     double timeAvg = 0.;
+    LogFilterGenerator generator(filter, m_ei->run());
+    const auto &logFilter = generator.generateFilter(logName);
     if (tspd) {
+      ScopedFilter<double> applyFilter(tspd, std::move(logFilter));
       stats = tspd->getStatistics();
       timeAvg = tspd->timeAverageValue();
     } else if (tspi) {
+      ScopedFilter<int> applyFilter(tspi, std::move(logFilter));
       stats = tspi->getStatistics();
       timeAvg = tspi->timeAverageValue();
     } else
diff --git a/MantidPlot/src/Mantid/SampleLogDialogBase.h b/MantidPlot/src/Mantid/SampleLogDialogBase.h
index 855028f6848298f1bf1d113001df50b789537199..4def7f419a815051192d276248be366706125ff1 100644
--- a/MantidPlot/src/Mantid/SampleLogDialogBase.h
+++ b/MantidPlot/src/Mantid/SampleLogDialogBase.h
@@ -5,8 +5,10 @@
 // Includes
 //----------------------------------
 #include <QDialog>
-#include <MantidAPI/ExperimentInfo.h>
-
+#include "MantidAPI/ExperimentInfo.h"
+#include "MantidAPI/LogFilterGenerator.h"
+#include "MantidKernel/TimeSeriesProperty.h"
+#include <memory>
 //----------------------------------
 // Forward declarations
 //----------------------------------
@@ -73,7 +75,10 @@ protected slots:
 
   /// Show the stats of the selected log
   virtual void showLogStatistics();
-  virtual void showLogStatisticsOfItem(QTreeWidgetItem *item);
+  virtual void showLogStatisticsOfItem(
+      QTreeWidgetItem *item,
+      const Mantid::API::LogFilterGenerator::FilterType
+          filter = Mantid::API::LogFilterGenerator::FilterType::None);
 
   /// Context menu popup
   virtual void popupMenu(const QPoint &pos);
@@ -104,6 +109,11 @@ protected:
   /// Sets up the QTreeWidget's connections for functionality
   void setUpTreeWidgetConnections();
 
+  /// Which type of filtering is selected - in base class case, none
+  virtual Mantid::API::LogFilterGenerator::FilterType getFilterType() const {
+    return Mantid::API::LogFilterGenerator::FilterType::None;
+  }
+
   /// A tree widget
   QTreeWidget *m_tree;
 
@@ -143,4 +153,21 @@ protected:
   };
 };
 
+/// Object that applies a filter to a property for as long as it is in scope.
+/// When scope ends, filter is cleared.
+template <typename T> class ScopedFilter {
+public:
+  ScopedFilter(Mantid::Kernel::TimeSeriesProperty<T> *prop,
+               const std::unique_ptr<Mantid::Kernel::LogFilter> &logFilter)
+      : m_prop(prop) {
+    if (logFilter && logFilter->filter()) {
+      m_prop->filterWith(logFilter->filter());
+    }
+  }
+  ~ScopedFilter() { m_prop->clearFilter(); }
+
+private:
+  Mantid::Kernel::TimeSeriesProperty<T> *m_prop;
+};
+
 #endif // SAMPLELOGDIALOGBASE_H_
\ No newline at end of file
diff --git a/MantidPlot/src/Matrix.cpp b/MantidPlot/src/Matrix.cpp
index 8e46d83879f5b9d804e17c98e2f794e82b380f8d..97904523b10fc7e27f394a3f8a44ec681b379d8d 100644
--- a/MantidPlot/src/Matrix.cpp
+++ b/MantidPlot/src/Matrix.cpp
@@ -1704,3 +1704,5 @@ std::string Matrix::saveToProject(ApplicationWindow *app) {
 
   return tsv.outputLines();
 }
+
+std::vector<std::string> Matrix::getWorkspaceNames() { return {}; }
diff --git a/MantidPlot/src/Matrix.h b/MantidPlot/src/Matrix.h
index be9133cb125950e0529613268d1c722dca003289..a08bab1733dd8c45d15424b70fca4183b6241065 100644
--- a/MantidPlot/src/Matrix.h
+++ b/MantidPlot/src/Matrix.h
@@ -262,6 +262,7 @@ public slots:
   loadFromProject(const std::string &lines, ApplicationWindow *app,
                   const int fileVersion);
   std::string saveToProject(ApplicationWindow *app) override;
+  std::vector<std::string> getWorkspaceNames() override;
 
   // selection operations
   //! Standard cut operation
diff --git a/MantidPlot/src/MdiSubWindow.cpp b/MantidPlot/src/MdiSubWindow.cpp
index 58263be42349e075d7a9bba8a22ff45f5011e7e1..e63d7479efbae56263ccd88d37b1a44a11fc06bb 100644
--- a/MantidPlot/src/MdiSubWindow.cpp
+++ b/MantidPlot/src/MdiSubWindow.cpp
@@ -91,6 +91,7 @@ void MdiSubWindow::init(QWidget *parent, const QString &label,
             SLOT(changeToFloating(MdiSubWindow *)));
   }
 }
+
 void MdiSubWindow::updateCaption() {
   switch (d_caption_policy) {
   case Name:
@@ -137,6 +138,12 @@ std::string MdiSubWindow::saveToProject(ApplicationWindow *app) {
   return "";
 }
 
+std::vector<std::string> MdiSubWindow::getWorkspaceNames() { return {}; }
+
+std::string MdiSubWindow::getWindowName() { return objectName().toStdString(); }
+
+std::string MdiSubWindow::getWindowType() { return metaObject()->className(); }
+
 void MdiSubWindow::resizeEvent(QResizeEvent *e) {
   emit resizedWindow(this);
   MdiSubWindowParent_t::resizeEvent(e);
diff --git a/MantidPlot/src/MdiSubWindow.h b/MantidPlot/src/MdiSubWindow.h
index e474f417b907cb1ac79c5367017ccc6d009069c8..8850e82f31d47c5962b4be1fd23c4bbb586e62e4 100644
--- a/MantidPlot/src/MdiSubWindow.h
+++ b/MantidPlot/src/MdiSubWindow.h
@@ -145,6 +145,7 @@ public:
   ApplicationWindow *applicationWindow() { return d_app; }
   /// Get the pointer to Folder
   Folder *folder() { return d_folder; }
+
 public slots:
 
   //! Return the window label
@@ -282,6 +283,13 @@ public: // non-slot methods
                   const int fileVersion);
   /// Serialises to a string that can be saved to a project file.
   std::string saveToProject(ApplicationWindow *app) override;
+  /// Returns a list of workspace names that are used by this window
+  std::vector<std::string> getWorkspaceNames() override;
+  /// Returns the user friendly name of the window
+  std::string getWindowName() override;
+  /// Get the window type as a string
+  std::string getWindowType() override;
+
 signals:
   //! Emitted when the window was closed
   void closedWindow(MdiSubWindow *);
diff --git a/MantidPlot/src/MultiLayer.cpp b/MantidPlot/src/MultiLayer.cpp
index 04f45975ba2afa0af14a0723fb7caff33c310c5a..01e0e1327391d10ea093b3bab744ce7bc23f0fa2 100644
--- a/MantidPlot/src/MultiLayer.cpp
+++ b/MantidPlot/src/MultiLayer.cpp
@@ -62,10 +62,12 @@
 #include "MultiLayer.h"
 #include "Plot.h"
 #include "SelectionMoveResizer.h"
+#include "Spectrogram.h"
 #include <ColorButton.h>
 
 #include "Mantid/MantidMDCurve.h"
 #include "Mantid/MantidMatrixCurve.h"
+#include "MantidKernel/Strings.h"
 #include <MantidQtMantidWidgets/MantidTreeWidget.h>
 
 #include "Mantid/MantidMDCurveDialog.h"
@@ -1324,7 +1326,7 @@ void MultiLayer::dropOntoMDCurve(Graph *g, MantidMDCurve *originalCurve,
     IMDWorkspace_sptr imdWS = boost::dynamic_pointer_cast<IMDWorkspace>(ws);
     // Only process IMDWorkspaces
     if (imdWS) {
-      QString currentName(imdWS->name().c_str());
+      QString currentName(imdWS->getName().c_str());
       try {
         MantidMDCurve *curve = new MantidMDCurve(currentName, g, showErrors);
         MantidQwtIMDWorkspaceData *data = curve->mantidData();
@@ -1811,18 +1813,7 @@ MultiLayer::loadFromProject(const std::string &lines, ApplicationWindow *app,
 
       if (gtsv.selectLine("ggeometry")) {
         int x = 0, y = 0, w = 0, h = 0;
-        gtsv >> x >> y;
-
-        w = multiLayer->canvas->width();
-        w -= multiLayer->left_margin;
-        w -= multiLayer->right_margin;
-        w -= (multiLayer->d_cols - 1) * multiLayer->colsSpace;
-
-        h = multiLayer->canvas->height();
-        h -= multiLayer->top_margin;
-        h -= multiLayer->left_margin;
-        h -= (multiLayer->d_rows - 1) * multiLayer->rowsSpace;
-        h -= LayerButton::btnSize();
+        gtsv >> x >> y >> w >> h;
 
         if (isWaterfall)
           h -= LayerButton::btnSize(); // need an extra offset for the buttons
@@ -1868,6 +1859,39 @@ std::string MultiLayer::saveToProject(ApplicationWindow *app) {
   return tsv.outputLines();
 }
 
+std::vector<std::string> MultiLayer::getWorkspaceNames() {
+  std::vector<std::string> names;
+  std::string name;
+  MantidMatrixCurve *mmc;
+  Spectrogram *spec;
+  for (auto graph : graphsList) {
+    for (int i = 0; i < graph->getNumCurves(); ++i) {
+      auto item = graph->plotItem(i);
+
+      switch (item->rtti()) {
+      case QwtPlotItem::Rtti_PlotUserItem:
+        mmc = dynamic_cast<MantidMatrixCurve *>(item);
+        if (!mmc)
+          continue;
+
+        name = mmc->workspaceName().toStdString();
+        names.push_back(name);
+        break;
+      case QwtPlotItem::Rtti_PlotSpectrogram:
+        spec = dynamic_cast<Spectrogram *>(item);
+        if (!spec)
+          continue;
+
+        name = spec->workspaceName();
+        names.push_back(name);
+        break;
+      }
+    }
+  }
+
+  return names;
+}
+
 /**
  * Sets axes for all layers to the same scales, which are set to encompass the
  * widest range of data.
@@ -1895,5 +1919,6 @@ void MultiLayer::setCommonAxisScales() {
     auto *plot = layer(i)->plotWidget();
     plot->setAxisScale(AXIS_X, lowestX, highestX);
     plot->setAxisScale(AXIS_Y, lowestY, highestY);
+    layer(i)->replot();
   }
 }
diff --git a/MantidPlot/src/MultiLayer.h b/MantidPlot/src/MultiLayer.h
index af1f3cddaa36d324365bbab832e254bc14e6aed7..6c702c17c9ad05522140fdf0dcadf12d4d5b9cc3 100644
--- a/MantidPlot/src/MultiLayer.h
+++ b/MantidPlot/src/MultiLayer.h
@@ -113,6 +113,7 @@ public:
   loadFromProject(const std::string &lines, ApplicationWindow *app,
                   const int fileVersion);
   std::string saveToProject(ApplicationWindow *app) override;
+  std::vector<std::string> getWorkspaceNames() override;
 
   void setCommonAxisScales();
 
diff --git a/MantidPlot/src/Note.cpp b/MantidPlot/src/Note.cpp
index 0bcb0a4f7a4b1174b908062fff4662a85829b409..8c378775572e59b0c22c185a6a5962a0e0f58f7f 100644
--- a/MantidPlot/src/Note.cpp
+++ b/MantidPlot/src/Note.cpp
@@ -35,15 +35,14 @@
 
 #include <QFileDialog>
 #include <QMessageBox>
+#include <QPrintDialog>
 #include <QTextCodec>
 #include <QTextStream>
 #include <Qsci/qsciprinter.h>
-#include <QPrintDialog>
 
 #include "ApplicationWindow.h"
 #include "MantidQtAPI/TSVSerialiser.h"
 #include "MantidKernel/ConfigService.h"
-#include "MantidQtAPI/FileDialogHandler.h"
 
 // Register the window into the WindowFactory
 DECLARE_WINDOW(Note)
@@ -99,8 +98,8 @@ QString Note::exportASCII(const QString &filename) {
     QString dir(Mantid::Kernel::ConfigService::Instance()
                     .getString("defaultsave.directory")
                     .c_str());
-    fn = MantidQt::API::FileDialogHandler::getSaveFileName(
-        this, tr("Save Text to File"), dir, filter, &selectedFilter);
+    fn = QFileDialog::getSaveFileName(this, tr("Save Text to File"), dir,
+                                      filter, &selectedFilter);
   } else
     fn = filename;
 
@@ -195,3 +194,5 @@ std::string Note::saveToProject(ApplicationWindow *app) {
   tsv.writeRaw("</note>");
   return tsv.outputLines();
 }
+
+std::vector<std::string> Note::getWorkspaceNames() { return {}; }
diff --git a/MantidPlot/src/Note.h b/MantidPlot/src/Note.h
index 248f4128a89ea4c620d207ec5c89218fd3d7f4c5..57e822dde0a44ab3685aea381fab4f81d892c770 100644
--- a/MantidPlot/src/Note.h
+++ b/MantidPlot/src/Note.h
@@ -53,6 +53,7 @@ public:
   loadFromProject(const std::string &lines, ApplicationWindow *app,
                   const int fileVersion);
   std::string saveToProject(ApplicationWindow *app) override;
+  std::vector<std::string> getWorkspaceNames() override;
 
   void setName(const QString &name);
 
diff --git a/MantidPlot/src/Plot3DDialog.cpp b/MantidPlot/src/Plot3DDialog.cpp
index 95f6eefff0a752f107a4cb3387d830d3796c5d96..6c5bc1536a9b967cc36b4583afec07b591233bdb 100644
--- a/MantidPlot/src/Plot3DDialog.cpp
+++ b/MantidPlot/src/Plot3DDialog.cpp
@@ -47,7 +47,6 @@
 #include <QMessageBox>
 #include <QComboBox>
 #include <QWidgetList>
-#include <QFileDialog>
 #include <QGroupBox>
 #include <QFontDialog>
 #include <QApplication>
diff --git a/MantidPlot/src/PlotDialog.cpp b/MantidPlot/src/PlotDialog.cpp
index cebc468f8f45f53042c4421336d7e9e85a3feec6..1626c4116b57644c4b77362c511793d890cfc9ff 100644
--- a/MantidPlot/src/PlotDialog.cpp
+++ b/MantidPlot/src/PlotDialog.cpp
@@ -54,7 +54,7 @@
 #include <QComboBox>
 #include <QDateTime>
 #include <QDoubleSpinBox>
-#include <QFileDialog>
+#include <QFileInfo>
 #include <QFontDialog>
 #include <QGroupBox>
 #include <QKeySequence>
diff --git a/MantidPlot/src/ProjectSave.ui b/MantidPlot/src/ProjectSave.ui
new file mode 100644
index 0000000000000000000000000000000000000000..b76c4458be3810c3551ba349f37add1198464b04
--- /dev/null
+++ b/MantidPlot/src/ProjectSave.ui
@@ -0,0 +1,218 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ProjectSave</class>
+ <widget class="QDialog" name="ProjectSave">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>1062</width>
+    <height>602</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Save Project</string>
+  </property>
+  <property name="modal">
+   <bool>true</bool>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout_8">
+   <item>
+    <layout class="QGridLayout" name="gridLayout">
+     <property name="sizeConstraint">
+      <enum>QLayout::SetDefaultConstraint</enum>
+     </property>
+     <item row="1" column="0" colspan="3">
+      <widget class="QSplitter" name="splitter">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <widget class="QWidget" name="verticalLayoutWidget_2">
+        <layout class="QVBoxLayout" name="verticalLayout_3">
+         <item>
+          <widget class="QLabel" name="label">
+           <property name="text">
+            <string>Workspaces</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QTreeWidget" name="workspaceList">
+           <column>
+            <property name="text">
+             <string>Name</string>
+            </property>
+           </column>
+           <column>
+            <property name="text">
+             <string>Type</string>
+            </property>
+           </column>
+           <column>
+            <property name="text">
+             <string>Size</string>
+            </property>
+           </column>
+           <item>
+            <property name="text">
+             <string>ws1</string>
+            </property>
+            <property name="checkState">
+             <enum>Checked</enum>
+            </property>
+            <property name="text">
+             <string>Matrix</string>
+            </property>
+            <property name="text">
+             <string>10mb</string>
+            </property>
+           </item>
+          </widget>
+         </item>
+        </layout>
+       </widget>
+       <widget class="QWidget" name="verticalLayoutWidget">
+        <layout class="QVBoxLayout" name="verticalLayout">
+         <item>
+          <widget class="QSplitter" name="splitter_2">
+           <property name="orientation">
+            <enum>Qt::Vertical</enum>
+           </property>
+           <widget class="QWidget" name="verticalLayoutWidget_3">
+            <layout class="QVBoxLayout" name="verticalLayout_5">
+             <item>
+              <widget class="QLabel" name="label_2">
+               <property name="text">
+                <string>Included Windows</string>
+               </property>
+              </widget>
+             </item>
+             <item>
+              <widget class="QTreeWidget" name="includedWindows">
+               <column>
+                <property name="text">
+                 <string>Name</string>
+                </property>
+               </column>
+               <column>
+                <property name="text">
+                 <string>Type</string>
+                </property>
+               </column>
+              </widget>
+             </item>
+            </layout>
+           </widget>
+           <widget class="QWidget" name="verticalLayoutWidget_4">
+            <layout class="QVBoxLayout" name="verticalLayout_6">
+             <item>
+              <widget class="QLabel" name="label_3">
+               <property name="text">
+                <string>Excluded Windows</string>
+               </property>
+              </widget>
+             </item>
+             <item>
+              <widget class="QTreeWidget" name="excludedWindows">
+               <column>
+                <property name="text">
+                 <string>Name</string>
+                </property>
+               </column>
+               <column>
+                <property name="text">
+                 <string>Type</string>
+                </property>
+               </column>
+              </widget>
+             </item>
+            </layout>
+           </widget>
+          </widget>
+         </item>
+        </layout>
+       </widget>
+      </widget>
+     </item>
+     <item row="2" column="0" colspan="3">
+      <layout class="QHBoxLayout" name="horizontalLayout_2">
+       <property name="sizeConstraint">
+        <enum>QLayout::SetFixedSize</enum>
+       </property>
+       <item>
+        <widget class="QProgressBar" name="saveProgressBar">
+         <property name="value">
+          <number>24</number>
+         </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>0</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+       <item>
+        <widget class="QPushButton" name="btnCancel">
+         <property name="text">
+          <string>Cancel</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QPushButton" name="btnSave">
+         <property name="text">
+          <string>Save</string>
+         </property>
+        </widget>
+       </item>
+      </layout>
+     </item>
+     <item row="0" column="0" colspan="3">
+      <layout class="QVBoxLayout" name="verticalLayout_7">
+       <item>
+        <widget class="QLabel" name="label_4">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
+         <property name="text">
+          <string>Project Location</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <layout class="QHBoxLayout" name="horizontalLayout">
+         <property name="sizeConstraint">
+          <enum>QLayout::SetFixedSize</enum>
+         </property>
+         <item>
+          <widget class="QLineEdit" name="projectPath"/>
+         </item>
+         <item>
+          <widget class="QPushButton" name="btnBrowseFilePath">
+           <property name="text">
+            <string>Browse</string>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </item>
+      </layout>
+     </item>
+    </layout>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/MantidPlot/src/ProjectSaveView.cpp b/MantidPlot/src/ProjectSaveView.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5fe91179c2f067538859bb00e7416fea694ad113
--- /dev/null
+++ b/MantidPlot/src/ProjectSaveView.cpp
@@ -0,0 +1,411 @@
+#include "MantidQtAPI/IProjectSerialisable.h"
+#include "MantidQtAPI/WindowIcons.h"
+#include "MantidQtMantidWidgets/ProjectSavePresenter.h"
+
+#include "ProjectSaveView.h"
+
+#include <QFileDialog>
+
+using namespace MantidQt::API;
+
+namespace MantidQt {
+namespace MantidWidgets {
+
+/**
+ * Create a new instance of the view.
+ *
+ * @param projectName :: the existing project path
+ * @param serialiser :: a ProjectSerialiser instance
+ * @param windows :: vector of window handles for the open application
+ * @param parent :: parent widget for this object
+ */
+ProjectSaveView::ProjectSaveView(
+    const QString &projectName, ProjectSerialiser &serialiser,
+    const std::vector<IProjectSerialisable *> &windows, QWidget *parent)
+    : QDialog(parent), m_serialisableWindows(windows.cbegin(), windows.cend()),
+      m_serialiser(serialiser) {
+
+  m_ui.setupUi(this);
+  m_presenter.reset(new ProjectSavePresenter(this));
+
+  if (!checkIfNewProject(projectName))
+    m_ui.projectPath->setText(projectName);
+
+  m_ui.saveProgressBar->setValue(0);
+
+  connectSignals();
+}
+
+// IProjectSaveView interface implementations
+//==============================================================================
+
+/**
+ * Get all window handles passed to the view
+ * @return a vector of handles to each window
+ */
+std::vector<API::IProjectSerialisable *> ProjectSaveView::getWindows() {
+  return m_serialisableWindows;
+}
+
+/**
+ * Get all of the checked workspace names
+ * @return a vector of workspace names
+ */
+std::vector<std::string> ProjectSaveView::getCheckedWorkspaceNames() {
+  return getItemsWithCheckState(Qt::CheckState::Checked);
+}
+
+/**
+ * Get all of the unchecked workspace names
+ * @return a vector of workspace names
+ */
+std::vector<std::string> ProjectSaveView::getUncheckedWorkspaceNames() {
+  return getItemsWithCheckState(Qt::CheckState::Unchecked);
+}
+
+/**
+ * Get the project path text
+ *
+ * This path may or may not exist yet and must be further validated.
+ *
+ * @return string representing the project path
+ */
+QString ProjectSaveView::getProjectPath() { return m_ui.projectPath->text(); }
+
+/**
+ * Set the project path
+ * @param path :: path the project will be saved to
+ */
+void ProjectSaveView::setProjectPath(const QString &path) {
+  m_ui.projectPath->setText(path);
+}
+
+/**
+ * Update the list of workspaces.
+ *
+ * This will create one new item in the list for each workspace info
+ * object passed
+ *
+ * @param workspaces :: vector of workspace info objects to add to the view
+ */
+void ProjectSaveView::updateWorkspacesList(
+    const std::vector<WorkspaceInfo> &workspaces) {
+  m_ui.workspaceList->clear();
+  for (auto info : workspaces) {
+    addWorkspaceItem(info);
+  }
+  // pad the header for longish workspace names
+  m_ui.workspaceList->header()->resizeSection(0, 300);
+}
+
+/**
+ * Update the included windows list
+ *
+ * This will create one new item in the list for each window info object passed.
+ *
+ * @param windows :: vector of window info objects to add to the view
+ */
+void ProjectSaveView::updateIncludedWindowsList(
+    const std::vector<WindowInfo> &windows) {
+  m_ui.includedWindows->clear();
+  for (auto info : windows) {
+    addWindowItem(m_ui.includedWindows, info);
+  }
+
+  resizeWidgetColumns(m_ui.includedWindows);
+}
+
+/**
+ * Update the excluded windows list
+ *
+ * This will create one new item in the list for each window info object passed.
+ *
+ * @param windows :: vector of window info objects to add to the view
+ */
+void ProjectSaveView::updateExcludedWindowsList(
+    const std::vector<WindowInfo> &windows) {
+  m_ui.excludedWindows->clear();
+  for (auto info : windows) {
+    addWindowItem(m_ui.excludedWindows, info);
+  }
+
+  resizeWidgetColumns(m_ui.excludedWindows);
+}
+
+/**
+ * Remove a list of windows from the included windows list
+ * @param windows :: vector of window names to remove from the include list
+ */
+void ProjectSaveView::removeFromIncludedWindowsList(
+    const std::vector<std::string> &windows) {
+  for (auto name : windows) {
+    removeItem(m_ui.includedWindows, name);
+  }
+}
+
+/**
+ * Remove a list of windows from the excluded windows list
+ * @param windows :: vector of window names to remove from the exclude list
+ */
+void ProjectSaveView::removeFromExcludedWindowsList(
+    const std::vector<std::string> &windows) {
+  for (auto name : windows) {
+    removeItem(m_ui.excludedWindows, name);
+  }
+}
+
+// Private slots
+//==============================================================================
+
+/**
+ * Slot of handle when a workspace item is changed.
+ *
+ * When a workspace item is check or unchecked this will notify the presenter to
+ * move the windows associated with this workspace to the other (included/
+ * excluded) list.
+ *
+ * @param item :: QTreeWidget item that was modified
+ * @param column :: column that was modified
+ */
+void ProjectSaveView::workspaceItemChanged(QTreeWidgetItem *item, int column) {
+  updateWorkspaceListCheckState(item);
+  if (item->checkState(column) == Qt::CheckState::Checked) {
+    m_presenter->notify(ProjectSavePresenter::Notification::CheckWorkspace);
+  } else if (item->checkState(column) == Qt::CheckState::Unchecked) {
+    m_presenter->notify(ProjectSavePresenter::Notification::UncheckWorkspace);
+  }
+}
+
+/**
+ * Slot to save the project.
+ *
+ * This will call the project serialiser passed on construction and save the
+ * current state of the project. If only certain workspaces have been selected
+ * then only a subset of the workspaces/windows will be passed to the project
+ * serialiser.
+ *
+ * @param checked :: unused arguement
+ */
+void ProjectSaveView::save(bool checked) {
+  UNUSED_ARG(checked);
+
+  if (m_ui.projectPath->text().isEmpty()) {
+    QMessageBox::warning(this, "Project Save",
+                         "Please choose a valid file path", QMessageBox::Ok);
+    return;
+  }
+
+  m_presenter->notify(ProjectSavePresenter::Notification::PrepareProjectFolder);
+  auto wsNames = getCheckedWorkspaceNames();
+  auto windowNames = getIncludedWindowNames();
+  auto filePath = m_ui.projectPath->text();
+  auto compress = filePath.endsWith(".gz");
+
+  m_serialiser.save(filePath, wsNames, windowNames, compress);
+  emit projectSaved();
+
+  close();
+}
+
+/**
+ * Slot to ask the user to find a new project path.
+ *
+ * This will open a file dialog and let the user choose a new location for the
+ * project.
+ */
+void ProjectSaveView::findFilePath() {
+  QString filter = "MantidPlot project (*.mantid);;";
+  filter += "Compressed MantidPlot project (*.mantid.gz)";
+
+  QString selectedFilter;
+  QString filename = QFileDialog::getSaveFileName(this, "Save Project As", "",
+                                                  filter, &selectedFilter);
+
+  m_ui.projectPath->setText(filename);
+}
+
+// Private helper methods
+//==============================================================================
+
+/**
+ * Get all items with a given check state from the workspace list
+ * @param state :: any of the values in Qt::CheckState
+ * @return a vector of names of workspaces that had the state
+ */
+std::vector<std::string>
+ProjectSaveView::getItemsWithCheckState(const Qt::CheckState state) const {
+  std::vector<std::string> names;
+  for (int i = 0; i < m_ui.workspaceList->topLevelItemCount(); ++i) {
+    auto item = m_ui.workspaceList->topLevelItem(i);
+    if (item->checkState(0) == state) {
+      auto name = item->text(0).toStdString();
+      names.push_back(name);
+    }
+
+    // now check the child items and append any that have the check state
+    for (int i = 0; i < item->childCount(); ++i) {
+      auto child = item->child(i);
+      if (child->checkState(0) == state) {
+        auto childName = child->text(0).toStdString();
+        names.push_back(childName);
+      }
+    }
+  }
+  return names;
+}
+
+/**
+ * Get any included window names
+ *
+ * These will depend on which workspaces are checked in the view
+ *
+ * @return vector of included window names
+ */
+std::vector<std::string> ProjectSaveView::getIncludedWindowNames() const {
+  std::vector<std::string> names;
+  for (int i = 0; i < m_ui.includedWindows->topLevelItemCount(); ++i) {
+    auto item = m_ui.includedWindows->topLevelItem(i);
+    auto name = item->text(0).toStdString();
+    names.push_back(name);
+  }
+  return names;
+}
+
+/**
+ * Remove an item from a QTreeWidget
+ * @param widget :: handle to the widget
+ * @param name :: name to match widget items with
+ */
+void ProjectSaveView::removeItem(QTreeWidget *widget, const std::string &name) {
+  auto qname = QString::fromStdString(name);
+  auto items = widget->findItems(qname, Qt::MatchContains);
+  for (auto item : items) {
+    delete item;
+  }
+}
+
+/**
+ * Add a new window item to the view
+ * @param widget :: the widget to add the item to
+ * @param info :: window info object with data to add
+ */
+void ProjectSaveView::addWindowItem(QTreeWidget *widget,
+                                    const WindowInfo &info) {
+  QStringList lst;
+  WindowIcons icons;
+  lst << QString::fromStdString(info.name);
+  lst << QString::fromStdString(info.type);
+
+  auto item = new QTreeWidgetItem(lst);
+  if (!info.icon_id.empty())
+    item->setIcon(0, icons.getIcon(info.type));
+  widget->addTopLevelItem(item);
+}
+
+/**
+ * Add a new workspace item to the view
+ * @param info :: workspace info object with data to add
+ */
+void ProjectSaveView::addWorkspaceItem(const WorkspaceInfo &info) {
+  auto item = makeWorkspaceItem(info);
+
+  for (auto subInfo : info.subWorkspaces) {
+    auto subItem = makeWorkspaceItem(subInfo);
+    item->addChild(subItem);
+  }
+
+  m_ui.workspaceList->addTopLevelItem(item);
+}
+
+/**
+ * Build a new QTreeWidgetItem for a WorkspaceInfo
+ * @param info :: reference to the WorkspaceInfo to make an item for
+ * @return new QTreeWidgetItem for the info object
+ */
+QTreeWidgetItem *
+ProjectSaveView::makeWorkspaceItem(const WorkspaceInfo &info) const {
+  QStringList lst;
+  lst << QString::fromStdString(info.name);
+  lst << QString::fromStdString(info.type);
+  lst << QString::fromStdString(info.size);
+  lst << QString::number(info.numWindows);
+
+  auto item = new QTreeWidgetItem(lst);
+
+  if (!info.icon_id.empty())
+    item->setIcon(0, getQPixmap(info.icon_id));
+  item->setCheckState(0, Qt::CheckState::Checked);
+
+  return item;
+}
+
+/**
+ * Check if project path is a new unsaved project or has been saved before
+ * @param projectName :: path to the project
+ * @return whether the project already exists
+ */
+bool ProjectSaveView::checkIfNewProject(const QString &projectName) const {
+  return (projectName == "untitled" ||
+          projectName.endsWith(".opj", Qt::CaseInsensitive) ||
+          projectName.endsWith(".ogm", Qt::CaseInsensitive) ||
+          projectName.endsWith(".ogw", Qt::CaseInsensitive) ||
+          projectName.endsWith(".ogg", Qt::CaseInsensitive));
+}
+
+/**
+ * Resize the columns of a widget to match the length of the contents
+ * @param widget :: the widget to resize
+ */
+void ProjectSaveView::resizeWidgetColumns(QTreeWidget *widget) {
+  for (int i = 0; i < widget->topLevelItemCount(); ++i)
+    widget->resizeColumnToContents(i);
+}
+
+/**
+ * Connect the internal signals
+ */
+void ProjectSaveView::connectSignals() {
+  // Connect signal to listen for when workspaces are changed
+  // (checked/unchecked)
+  connect(m_ui.workspaceList, SIGNAL(itemChanged(QTreeWidgetItem *, int)), this,
+          SLOT(workspaceItemChanged(QTreeWidgetItem *, int)));
+
+  connect(m_ui.btnBrowseFilePath, SIGNAL(clicked(bool)), this,
+          SLOT(findFilePath()));
+  connect(m_ui.btnSave, SIGNAL(clicked(bool)), this, SLOT(save(bool)));
+  connect(m_ui.btnCancel, SIGNAL(clicked(bool)), this, SLOT(close()));
+
+  connect(&m_serialiser, SIGNAL(setProgressBarRange(int, int)),
+          m_ui.saveProgressBar, SLOT(setRange(int, int)));
+  connect(&m_serialiser, SIGNAL(setProgressBarValue(int)), m_ui.saveProgressBar,
+          SLOT(setValue(int)));
+}
+
+/**
+ * Update other items that are parents/children of this item.
+ *
+ * This makes sure that the state of the checkboxes are always logically
+ * consistent. E.g. is a parent item is checked, so are all its children
+ *
+ * @param item :: item that has changed check state
+ */
+void ProjectSaveView::updateWorkspaceListCheckState(QTreeWidgetItem *item) {
+  // block signals so we don't trigger more updates to widget items
+  blockSignals(true);
+
+  // update child check state
+  // children should match the check state of the parent item
+  auto checkState = item->checkState(0);
+  for (int i = 0; i < item->childCount(); ++i) {
+    item->child(i)->setCheckState(0, checkState);
+  }
+
+  // the parent item should be unchecked if any single child is unchecked
+  auto parent = item->parent();
+  if (parent && checkState == Qt::CheckState::Unchecked)
+    parent->setCheckState(0, checkState);
+
+  blockSignals(false);
+}
+}
+}
diff --git a/MantidPlot/src/ProjectSaveView.h b/MantidPlot/src/ProjectSaveView.h
new file mode 100644
index 0000000000000000000000000000000000000000..05bf1bc7b7be3c4245515ae71c69761524d30f96
--- /dev/null
+++ b/MantidPlot/src/ProjectSaveView.h
@@ -0,0 +1,127 @@
+#ifndef MANTIDQT_MANTIDWIDGETS_PROJECTSAVEVIEW_H
+#define MANTIDQT_MANTIDWIDGETS_PROJECTSAVEVIEW_H
+
+#include "MantidQtAPI/IProjectSerialisable.h"
+#include "MantidQtMantidWidgets/IProjectSaveView.h"
+#include "MantidQtMantidWidgets/ProjectSavePresenter.h"
+#include "ProjectSerialiser.h"
+#include "ui_ProjectSave.h"
+
+#include <QMainWindow>
+#include <QWidget>
+#include <set>
+#include <string>
+#include <vector>
+
+namespace MantidQt {
+namespace MantidWidgets {
+
+/** @class ProjectSaveView
+
+ProjectSaveView is the interaces for defining the functions that the project
+save view needs to implement.
+
+Copyright &copy; 2011-14 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>
+*/
+class ProjectSaveView : public QDialog, IProjectSaveView {
+  Q_OBJECT
+public:
+  ProjectSaveView(
+      const QString &projectName, MantidQt::API::ProjectSerialiser &serialiser,
+      const std::vector<MantidQt::API::IProjectSerialisable *> &windows,
+      QWidget *parent = nullptr);
+
+  /// Get all of the window handles passed to the view
+  std::vector<MantidQt::API::IProjectSerialisable *> getWindows() override;
+  /// Get any checked workspace names on the view
+  std::vector<std::string> getCheckedWorkspaceNames() override;
+  /// Get any unchecked workspace names on the view
+  std::vector<std::string> getUncheckedWorkspaceNames() override;
+  /// Get the current path of the project
+  QString getProjectPath() override;
+  /// Set the current path of the project
+  void setProjectPath(const QString &path) override;
+  /// Update the list of workspaces with a collection of workspace info
+  void
+  updateWorkspacesList(const std::vector<WorkspaceInfo> &workspaces) override;
+  /// Update the list of included windows with a collection of window info
+  void
+  updateIncludedWindowsList(const std::vector<WindowInfo> &windows) override;
+  /// Update the list of excluded windows with a collection of window info
+  void
+  updateExcludedWindowsList(const std::vector<WindowInfo> &windows) override;
+  /// Remove a collection of windows from the included window list
+  void removeFromIncludedWindowsList(
+      const std::vector<std::string> &windows) override;
+  /// Remove a collection of windows from the excluded window list
+  void removeFromExcludedWindowsList(
+      const std::vector<std::string> &windows) override;
+
+signals:
+  /// Signal emitted when the ProjectSerialiser has finished writing
+  void projectSaved();
+
+private slots:
+  /// Slot to browse for a new project path
+  void findFilePath();
+  /// Slot to save the project
+  void save(bool checked);
+  /// Slot to move windows when workspaces are checked/unchecked
+  void workspaceItemChanged(QTreeWidgetItem *item, int column);
+
+private:
+  /// Get a list of included windows names to be saved
+  std::vector<std::string> getIncludedWindowNames() const;
+  /// Get the name value of all items with a given check state
+  std::vector<std::string>
+  getItemsWithCheckState(const Qt::CheckState state) const;
+  /// Remove an item from a QTreeWidget
+  void removeItem(QTreeWidget *widget, const std::string &name);
+  /// Add an new window item QTreeWidget
+  void addWindowItem(QTreeWidget *widget, const WindowInfo &info);
+  /// Add an new workspace item QTreeWidget
+  void addWorkspaceItem(const WorkspaceInfo &info);
+  /// Make a new tree widget item from a workspace info object
+  QTreeWidgetItem *makeWorkspaceItem(const WorkspaceInfo &info) const;
+  /// Check if the project path already existed
+  bool checkIfNewProject(const QString &projectName) const;
+  /// Resize a QTreeWidgets columns to fit text correctly
+  void resizeWidgetColumns(QTreeWidget *widget);
+  /// Connect up signals to the interface on initilisation
+  void connectSignals();
+  /// Update the checked state of the tree when an item is updated
+  void updateWorkspaceListCheckState(QTreeWidgetItem *item);
+
+  // Instance variables
+
+  /// List of windows to be serialised
+  std::vector<MantidQt::API::IProjectSerialisable *> m_serialisableWindows;
+  /// Handle to the presenter for this view
+  std::unique_ptr<ProjectSavePresenter> m_presenter;
+  /// Handle to the project serialiser
+  MantidQt::API::ProjectSerialiser &m_serialiser;
+  /// Handle to the UI
+  Ui::ProjectSave m_ui;
+};
+}
+}
+#endif /* MANTIDQT_MANTIDWIDGETS_PROJECTSAVEVIEW_H */
diff --git a/MantidPlot/src/ProjectSerialiser.cpp b/MantidPlot/src/ProjectSerialiser.cpp
index 03c50f250f0f24f681b0e05559b51101281931b1..0e21886de8654fb39f255f3dec26607f275c82ac 100644
--- a/MantidPlot/src/ProjectSerialiser.cpp
+++ b/MantidPlot/src/ProjectSerialiser.cpp
@@ -1,17 +1,19 @@
-#include "globals.h"
+#include "ProjectSerialiser.h"
 #include "ApplicationWindow.h"
 #include "Graph3D.h"
 #include "Matrix.h"
 #include "Note.h"
-#include "ProjectSerialiser.h"
 #include "ScriptingWindow.h"
 #include "TableStatistics.h"
 #include "WindowFactory.h"
+#include "globals.h"
 
 #include "Mantid/InstrumentWidget/InstrumentWindow.h"
 #include "Mantid/MantidMatrixFunction.h"
 #include "Mantid/MantidUI.h"
 #include "MantidAPI/MatrixWorkspace.h"
+#include "MantidAPI/WorkspaceGroup.h"
+#include "MantidKernel/Logger.h"
 #include "MantidKernel/MantidVersion.h"
 #include "MantidQtAPI/PlotAxis.h"
 #include "MantidQtAPI/VatesViewerInterface.h"
@@ -23,6 +25,12 @@
 
 using namespace Mantid::API;
 using namespace MantidQt::API;
+using Mantid::Kernel::Logger;
+
+namespace {
+/// static logger
+Logger g_log("ProjectSerialiser");
+}
 
 // This C function is defined in the third party C lib minigzip.c
 extern "C" {
@@ -30,7 +38,24 @@ void file_compress(const char *file, const char *mode);
 }
 
 ProjectSerialiser::ProjectSerialiser(ApplicationWindow *window)
-    : window(window), m_windowCount(0) {}
+    : window(window), m_currentFolder(nullptr), m_windowCount(0),
+      m_saveAll(true) {}
+
+ProjectSerialiser::ProjectSerialiser(ApplicationWindow *window, Folder *folder)
+    : window(window), m_currentFolder(folder), m_windowCount(0),
+      m_saveAll(true) {}
+
+void ProjectSerialiser::save(const QString &projectName,
+                             const std::vector<std::string> &wsNames,
+                             const std::vector<std::string> &windowNames,
+                             bool compress) {
+  m_windowNames = windowNames;
+  m_workspaceNames = wsNames;
+  window->projectname = projectName;
+  QFileInfo fileInfo(projectName);
+  window->workingDir = fileInfo.absoluteDir().absolutePath();
+  save(projectName, compress, false);
+}
 
 /**
  * Save the current state of the application as a Mantid project file
@@ -39,9 +64,10 @@ ProjectSerialiser::ProjectSerialiser(ApplicationWindow *window)
  * @param projectName :: the name of the project to write to
  * @param compress :: whether to compress the project (default false)
  */
-void ProjectSerialiser::save(Folder *folder, const QString &projectName,
-                             bool compress) {
+void ProjectSerialiser::save(const QString &projectName, bool compress,
+                             bool saveAll) {
   m_windowCount = 0;
+  m_saveAll = saveAll;
   QFile fileHandle(projectName);
 
   // attempt to backup project files and check we can write
@@ -50,7 +76,14 @@ void ProjectSerialiser::save(Folder *folder, const QString &projectName,
     return;
   }
 
-  QString text = serialiseProjectState(folder);
+  if (!m_currentFolder)
+    m_currentFolder = window->currentFolder();
+
+  // update any listening progress bars
+  emit setProgressBarRange(0, static_cast<int>(m_workspaceNames.size()));
+  emit setProgressBarValue(0);
+
+  QString text = serialiseProjectState(m_currentFolder);
   saveProjectFile(&fileHandle, projectName, text, compress);
 }
 
@@ -68,6 +101,9 @@ void ProjectSerialiser::load(std::string lines, const int fileVersion,
   // folder
   // This is a legacy edgecase because folders are written
   // <folder>\tsettings\tgo\there
+  g_log.notice() << "Reading Mantid Project: "
+                 << window->projectname.toStdString() << "\n";
+
   if (!isTopLevel && lines.size() > 0) {
     std::vector<std::string> lineVec;
     boost::split(lineVec, lines, boost::is_any_of("\n"));
@@ -104,6 +140,9 @@ void ProjectSerialiser::load(std::string lines, const int fileVersion,
     window->d_current_folder = window->projectFolder();
   else
     window->d_current_folder = parent;
+
+  g_log.notice() << "Finished Loading Project: "
+                 << window->projectname.toStdString() << "\n";
 }
 
 /**
@@ -359,6 +398,8 @@ QString ProjectSerialiser::saveFolderSubWindows(Folder *folder) {
   for (auto &w : windows) {
     MantidQt::API::IProjectSerialisable *ips =
         dynamic_cast<MantidQt::API::IProjectSerialisable *>(w);
+    if (!m_saveAll && !contains(m_windowNames, w->getWindowName()))
+      continue;
 
     if (ips) {
       text += QString::fromUtf8(ips->saveToProject(window).c_str());
@@ -401,6 +442,7 @@ QString ProjectSerialiser::saveWorkspaces() {
   wsNames = "<mantidworkspaces>\n";
   wsNames += "WorkspaceNames";
 
+  int count = 0;
   auto workspaceItems = AnalysisDataService::Instance().getObjectNames();
   for (auto &itemIter : workspaceItems) {
     QString wsName = QString::fromStdString(itemIter);
@@ -417,18 +459,30 @@ QString ProjectSerialiser::saveWorkspaces() {
       wsNames += wsName;
       std::vector<std::string> secondLevelItems = group->getNames();
       for (size_t j = 0; j < secondLevelItems.size(); j++) {
+
+        // check whether the user wants to save this workspace
+        if (!m_saveAll && !contains(m_workspaceNames, secondLevelItems[j]))
+          continue;
+
         wsNames += ",";
         wsNames += QString::fromStdString(secondLevelItems[j]);
         std::string fileName(workingDir + "//" + secondLevelItems[j] + ".nxs");
         window->mantidUI->savedatainNexusFormat(fileName, secondLevelItems[j]);
       }
     } else {
+      // check whether the user wants to save this workspace
+      if (!m_saveAll && !contains(m_workspaceNames, wsName.toStdString()))
+        continue;
+
       wsNames += "\t";
       wsNames += wsName;
 
       std::string fileName(workingDir + "//" + wsName.toStdString() + ".nxs");
       window->mantidUI->savedatainNexusFormat(fileName, wsName.toStdString());
     }
+
+    // update listening progress bars
+    emit setProgressBarValue(++count);
   }
   wsNames += "\n</mantidworkspaces>\n";
   return wsNames;
@@ -445,7 +499,9 @@ QString ProjectSerialiser::saveAdditionalWindows() {
   QString output;
   for (auto win : window->getSerialisableWindows()) {
     auto serialisableWindow = dynamic_cast<IProjectSerialisable *>(win);
-    if (!serialisableWindow)
+    if (!serialisableWindow ||
+        (!m_saveAll &&
+         !contains(m_windowNames, serialisableWindow->getWindowName())))
       continue;
 
     auto lines = serialisableWindow->saveToProject(window);
@@ -744,3 +800,8 @@ QMdiSubWindow *ProjectSerialiser::setupQMdiSubWindow() const {
   window->connect(window, SIGNAL(shutting_down()), subWindow, SLOT(close()));
   return subWindow;
 }
+
+bool ProjectSerialiser::contains(const std::vector<std::string> &vec,
+                                 const std::string &value) {
+  return std::find(vec.cbegin(), vec.cend(), value) != vec.cend();
+}
diff --git a/MantidPlot/src/ProjectSerialiser.h b/MantidPlot/src/ProjectSerialiser.h
index 2ccc1b7336e0bff0f209859b83cf210eb55fb637..af1f1cd16e4fc8450503330ee46be7d4a5d9cd97 100644
--- a/MantidPlot/src/ProjectSerialiser.h
+++ b/MantidPlot/src/ProjectSerialiser.h
@@ -49,25 +49,47 @@ class ApplicationWindow;
 namespace MantidQt {
 namespace API {
 
-class ProjectSerialiser {
+class ProjectSerialiser : public QObject {
+  Q_OBJECT
 public:
   /// Create a new serialiser with the current application window
   explicit ProjectSerialiser(ApplicationWindow *window);
+  explicit ProjectSerialiser(ApplicationWindow *window, Folder *folder);
+
   /// Save the current state of the project to disk
-  void save(Folder *folder, const QString &projectName, bool compress = false);
+  void save(const QString &projectName, const std::vector<std::string> &wsNames,
+            const std::vector<std::string> &windowNames, bool compress = false);
+  void save(const QString &projectName, bool compress = false,
+            bool saveAll = true);
   /// Load a project file from disk
   void load(std::string lines, const int fileVersion,
             const bool isTopLevel = true);
   /// Open the script window and load scripts from string
   void openScriptWindow(const QStringList &files);
 
+signals:
+  /// Set the curret progress of serialisation
+  void setProgressBarRange(int min, int max);
+  /// Set the forcasted range of things to do when saving
+  void setProgressBarValue(int value);
+  /// Set what is currently happening to listening progress bars
+  void setProgressBarText(QString text);
+
 private:
   // Instance Variables
 
   /// Store a reference to the caller application window instance
   ApplicationWindow *window;
+  /// Store a reference to the current folder
+  Folder *m_currentFolder;
+  /// Vector of names of windows to save to file
+  std::vector<std::string> m_windowNames;
+  /// Vector of names of workspaces to save to file
+  std::vector<std::string> m_workspaceNames;
   /// Store a count of the number of windows during saving
   int m_windowCount;
+  /// Flag to check if e should save all workspaces
+  bool m_saveAll;
 
   // Saving Functions
 
@@ -123,6 +145,8 @@ private:
 
   /// Create a handle to a new QMdiSubWindow instance
   QMdiSubWindow *setupQMdiSubWindow() const;
+  /// Check if a vector of strings contains a string
+  bool contains(const std::vector<std::string> &vec, const std::string &value);
 };
 }
 }
diff --git a/MantidPlot/src/PythonScript.cpp b/MantidPlot/src/PythonScript.cpp
index abccf72ed32015ee34d68bb373fa46dc7a0f76f5..81400c8e980320b90e774394531c830302682190 100644
--- a/MantidPlot/src/PythonScript.cpp
+++ b/MantidPlot/src/PythonScript.cpp
@@ -130,11 +130,8 @@ void PythonScript::setIdentifier(const QString &name) {
  * @return A PyObject wrapping this instance
  */
 PyObject *PythonScript::createSipInstanceFromMe() {
-  static sipWrapperType *sipClass(NULL);
-  if (!sipClass) {
-    sipClass = sipFindClass("PythonScript");
-  }
-  PyObject *sipWrapper = sipConvertFromInstance(this, sipClass, NULL);
+  const sipTypeDef *sipClass = sipFindType("PythonScript");
+  PyObject *sipWrapper = sipConvertFromType(this, sipClass, NULL);
   assert(sipWrapper);
   return sipWrapper;
 }
diff --git a/MantidPlot/src/PythonScripting.cpp b/MantidPlot/src/PythonScripting.cpp
index 073f2695c1aa3e62aed3f74c96a681ec7552792e..bbe351ed30e59a7b14aabe805e5eb5357da0955a 100644
--- a/MantidPlot/src/PythonScripting.cpp
+++ b/MantidPlot/src/PythonScripting.cpp
@@ -348,10 +348,10 @@ bool PythonScripting::setQObject(QObject *val, const char *name,
   if (!sipAPI__qti->api_find_class) {
     throw std::runtime_error("sipAPI_qti->api_find_class is undefined");
   }
-  sipWrapperType *klass = sipFindClass(val->metaObject()->className());
+  const sipTypeDef *klass = sipFindType(val->metaObject()->className());
   if (!klass)
     return false;
-  pyobj = sipConvertFromInstance(val, klass, NULL);
+  pyobj = sipConvertFromType(val, klass, NULL);
 
   if (!pyobj)
     return false;
diff --git a/MantidPlot/src/ScriptOutputDisplay.cpp b/MantidPlot/src/ScriptOutputDisplay.cpp
index 39825ddb9f186efc474904ded0d1f9daec0b33d0..a87e936e17e1610cdd4e7edc7e7503f08fb479f6 100644
--- a/MantidPlot/src/ScriptOutputDisplay.cpp
+++ b/MantidPlot/src/ScriptOutputDisplay.cpp
@@ -4,7 +4,6 @@
 #include <MantidQtAPI/pixmaps.h>
 
 #include <QDateTime>
-#include <QFileDialog>
 #include <QKeyEvent>
 #include <QMenu>
 #include <QPrintDialog>
diff --git a/MantidPlot/src/ScriptingWindow.cpp b/MantidPlot/src/ScriptingWindow.cpp
index 646be1e419741ee2e7a7d1694c5e66a61cef1bb9..9f0ddfb2161b9e3ed6fd9425ea25dd57e83058c0 100644
--- a/MantidPlot/src/ScriptingWindow.cpp
+++ b/MantidPlot/src/ScriptingWindow.cpp
@@ -23,7 +23,7 @@
 #include <QApplication>
 #include <QCloseEvent>
 #include <QDateTime>
-#include <QFileDialog>
+#include <QFileInfo>
 #include <QList>
 #include <QMenu>
 #include <QMenuBar>
diff --git a/MantidPlot/src/SetColValuesDialog.cpp b/MantidPlot/src/SetColValuesDialog.cpp
index fac8cbe2eef9cd3ce7a14c0cb0676528db734c81..fc58c61f7c281ae4963ae41320a8f1a17886a6b1 100644
--- a/MantidPlot/src/SetColValuesDialog.cpp
+++ b/MantidPlot/src/SetColValuesDialog.cpp
@@ -68,6 +68,9 @@ SetColValuesDialog::SetColValuesDialog(ScriptingEnv *env, Table *t,
   end->setMinimum(1);
   hbox1->addWidget(end);
 
+  // Ideally this would be checked at compile time. Until we have 'constexpr if`
+  // on all platforms, the added complexity and minimal cost isn't worthwhile.
+  // cppcheck-suppress knownConditionTrueFalse
   if (sizeof(int) == 2) { // 16 bit signed integer
     start->setMaximum(0x7fff);
     end->setMaximum(0x7fff);
diff --git a/MantidPlot/src/Spectrogram.cpp b/MantidPlot/src/Spectrogram.cpp
index 1e543976b0c0415d6ddb354492322105e526c855..d4f536954234eba4f20bf318d0dff6627342dd96 100644
--- a/MantidPlot/src/Spectrogram.cpp
+++ b/MantidPlot/src/Spectrogram.cpp
@@ -39,6 +39,7 @@
 #include "Mantid/MantidMatrix.h"
 #include "Mantid/MantidMatrixFunction.h"
 #include "MantidAPI/IMDIterator.h"
+#include "MantidKernel/Strings.h"
 #include "MantidKernel/make_unique.h"
 #include "MantidQtAPI/PlotAxis.h"
 #include "MantidQtAPI/QwtRasterDataMD.h"
diff --git a/MantidPlot/src/Spectrogram.h b/MantidPlot/src/Spectrogram.h
index d30a5ec7cb70e8d27faaa31aa9f311085d4896e8..fd25fefaadeceaead877643b85f5082b5d414104 100644
--- a/MantidPlot/src/Spectrogram.h
+++ b/MantidPlot/src/Spectrogram.h
@@ -175,6 +175,8 @@ public:
   void setIntensityChange(bool on);
   /// returns boolan flag intensity change
   bool isIntensityChanged();
+  /// returns the name of workspace for this spectrogram
+  std::string workspaceName() { return d_wsName; };
 
 signals:
   void removeMe(Spectrogram *);
diff --git a/MantidPlot/src/Table.cpp b/MantidPlot/src/Table.cpp
index c4c81949a886a659ad3cfe244eefb2990afaee4e..00397b741afb80078261f60776a96aca0cbec06b 100644
--- a/MantidPlot/src/Table.cpp
+++ b/MantidPlot/src/Table.cpp
@@ -3176,6 +3176,8 @@ Table::loadFromProject(const std::string &lines, ApplicationWindow *app,
   return table;
 }
 
+std::vector<std::string> Table::getWorkspaceNames() { return {}; }
+
 std::string Table::saveTableMetadata() {
   MantidQt::API::TSVSerialiser tsv;
   tsv.writeLine("header");
diff --git a/MantidPlot/src/Table.h b/MantidPlot/src/Table.h
index e6d8d77d07140c1c0d8c796100992e36367fcb6b..8f0f95d5dee4a6b3e04c35d6494d40b097c76ee4 100644
--- a/MantidPlot/src/Table.h
+++ b/MantidPlot/src/Table.h
@@ -396,6 +396,9 @@ public slots:
   static MantidQt::API::IProjectSerialisable *
   loadFromProject(const std::string &lines, ApplicationWindow *app,
                   const int fileVersion);
+  /// Returns a list of workspace names that are used by this window
+  std::vector<std::string> getWorkspaceNames() override;
+
   void restore(const QStringList &lst) override;
 
   //! This slot notifies the main application that the table has been modified.
diff --git a/MantidPlot/src/TextFileIO.cpp b/MantidPlot/src/TextFileIO.cpp
index 48a221a59613aebbe038c35294e3d52a6742659f..c6da8829961cb600c8cb85d07fd22bde0b0d69b8 100644
--- a/MantidPlot/src/TextFileIO.cpp
+++ b/MantidPlot/src/TextFileIO.cpp
@@ -1,13 +1,11 @@
 #include "TextFileIO.h"
+#include "MantidQtAPI/FileDialogHandler.h"
 
+#include <QApplication>
 #include <QFile>
 #include <QFileDialog>
-#include <QFileInfo>
 #include <QMessageBox>
 #include <QTextStream>
-#include <QApplication>
-
-#include "MantidQtAPI/FileDialogHandler.h"
 
 /**
  * Construct an object with a list of file filters
@@ -47,15 +45,8 @@ bool TextFileIO::save(const QString &txt, const QString &filename) const {
 QString TextFileIO::askWhereToSave() const {
   QString selectedFilter;
   QString filter = m_filters.join(";;");
-  QString filename = MantidQt::API::FileDialogHandler::getSaveFileName(
-      NULL, "MantidPlot - Save", "", filter, &selectedFilter);
-  if (filename.isEmpty())
-    return QString();
-  if (QFileInfo(filename).suffix().isEmpty()) {
-    QString ext = selectedFilter.section('(', 1).section(' ', 0, 0);
-    ext.remove(0, 1);
-    if (ext != ")")
-      filename += ext;
-  }
-  return filename;
+  QString filename = QFileDialog::getSaveFileName(NULL, "MantidPlot - Save", "",
+                                                  filter, &selectedFilter);
+  return MantidQt::API::FileDialogHandler::addExtension(filename,
+                                                        selectedFilter);
 }
diff --git a/MantidPlot/src/TiledWindow.cpp b/MantidPlot/src/TiledWindow.cpp
index 719e9234e10bc6ed43317e3d7d184e51305afc3a..c8781615273bd6faf2fcbef239e26f120ee93858 100644
--- a/MantidPlot/src/TiledWindow.cpp
+++ b/MantidPlot/src/TiledWindow.cpp
@@ -979,6 +979,35 @@ void TiledWindow::populateMenu(QMenu *menu) {
   menu->addAction(actionClear);
 }
 
+MantidQt::API::IProjectSerialisable *
+TiledWindow::loadFromProject(const std::string &lines, ApplicationWindow *app,
+                             const int fileVersion) {
+  UNUSED_ARG(lines);
+  UNUSED_ARG(app);
+  UNUSED_ARG(fileVersion);
+  throw std::runtime_error("Not implemented");
+}
+
+std::vector<std::string> TiledWindow::getWorkspaceNames() {
+  std::vector<std::string> wsNames;
+  auto tiles = getAllTiles();
+
+  for (auto tile : tiles) {
+    auto widget = tile->widget();
+    auto names = widget->getWorkspaceNames();
+    std::copy(names.begin(), names.end(), std::back_inserter(wsNames));
+  }
+
+  return wsNames;
+}
+
+std::string TiledWindow::getWindowName() { return objectName().toStdString(); }
+
+std::string TiledWindow::saveToProject(ApplicationWindow *app) {
+  UNUSED_ARG(app);
+  return "";
+}
+
 /**
  * Check if a Tile can accept drops.
  * @param tile :: A tile to check.
diff --git a/MantidPlot/src/TiledWindow.h b/MantidPlot/src/TiledWindow.h
index 4500974367a1d75196006d4283e31306b934762c..42e991b853918a7b6e898d498517792b0b4022ab 100644
--- a/MantidPlot/src/TiledWindow.h
+++ b/MantidPlot/src/TiledWindow.h
@@ -30,6 +30,17 @@ public:
   /// Populate a menu with actions
   void populateMenu(QMenu *menu);
 
+  static IProjectSerialisable *loadFromProject(const std::string &lines,
+                                               ApplicationWindow *app,
+                                               const int fileVersion);
+
+  /// Serialises to a string that can be saved to a project file.
+  std::string saveToProject(ApplicationWindow *app) override;
+  /// Returns a list of workspace names that are used by this window
+  std::vector<std::string> getWorkspaceNames() override;
+  /// Returns the user friendly name of the window
+  std::string getWindowName() override;
+
 public slots:
 
   /// Get number of rows
diff --git a/MantidPlot/src/qti.sip b/MantidPlot/src/qti.sip
index 6ebefc7df62fdf8c0b8930aeaf77391d395e94cd..56dc9ae453aa4cd9c13926ca3d65a7917014588d 100644
--- a/MantidPlot/src/qti.sip
+++ b/MantidPlot/src/qti.sip
@@ -1098,7 +1098,7 @@ class ApplicationWindow: QMainWindow
 // we have to do this to override casting in qt/qobject.sip (PyQt 3.16)
 // Russell Taylor, 4/8/09: Change needed for mac build.
 //   Taken from main qtiplot svn revision 1187.
-sipClass=sipFindClass(sipCpp->metaObject()->className());
+sipType=sipFindType(sipCpp->metaObject()->className());
 %End
 
 public:
@@ -1262,8 +1262,8 @@ ApplicationWindow *sipqti_app()
   PyObject *mydict = PyModule_GetDict(me);
   PyObject *pyapp = PyDict_GetItemString(mydict,"app");
   Py_DECREF(me);
-  if (sipCanConvertToInstance(pyapp, sipClass_ApplicationWindow, SIP_NOT_NONE))
-    return (ApplicationWindow*) sipConvertToInstance(pyapp, sipClass_ApplicationWindow, NULL, SIP_NOT_NONE, NULL, &iserr);
+  if (sipCanConvertToType(pyapp, sipType_ApplicationWindow, SIP_NOT_NONE))
+    return (ApplicationWindow*) sipConvertToType(pyapp, sipType_ApplicationWindow, NULL, SIP_NOT_NONE, NULL, &iserr);
   else
     return NULL;
 }
@@ -1467,7 +1467,7 @@ class MantidUI: QObject
 // we have to do this to override casting in qt/qobject.sip (PyQt 3.16)
 // Russell Taylor, 4/8/09: Change needed for mac build.
 //   Taken from main qtiplot svn revision 1187.
-sipClass=sipFindClass(sipCpp->metaObject()->className());
+sipType=sipFindType(sipCpp->metaObject()->className());
 %End
 
 public:
diff --git a/MantidPlot/test/MantidPlotPVPythonTest.py b/MantidPlot/test/MantidPlotPVPythonTest.py
index 9d2ed809a18b31375992aea784dabecc0fe1e121..874e7217b03aa7b7bd34c9c83dc8249aec85f529 100644
--- a/MantidPlot/test/MantidPlotPVPythonTest.py
+++ b/MantidPlot/test/MantidPlotPVPythonTest.py
@@ -3,6 +3,7 @@ Test one can import paraview.simple in MantidPlot
 """
 import mantidplottests
 from mantidplottests import *
+from paraview.simple import *
 
 
 class MantidPlotPVPythonTest(unittest.TestCase):
@@ -14,7 +15,6 @@ class MantidPlotPVPythonTest(unittest.TestCase):
         pass
 
     def test_PVPython(self):
-        from paraview.simple import *
         self.assertEqual(GetParaViewVersion().major, 5)
 
 # Run the unit tests
diff --git a/MantidPlot/test/squish_test_suites/refl_gui_tests/envvars b/MantidPlot/test/squish_test_suites/refl_gui_tests/envvars
index f184f89c1b478e8393e5ddd510490feabc781148..ed06b9fd471b36c98900b81f04b472b7ee620149 100644
--- a/MantidPlot/test/squish_test_suites/refl_gui_tests/envvars
+++ b/MantidPlot/test/squish_test_suites/refl_gui_tests/envvars
@@ -1 +1 @@
-LD_LIBRARY_PATH=/opt/mantidnightly/lib/paraview-5.1
+LD_LIBRARY_PATH=/opt/mantidnightly/lib/paraview-5.2
diff --git a/MantidQt/API/CMakeLists.txt b/MantidQt/API/CMakeLists.txt
index f6cdaa1ed48eb1eae067d824aeece59f653ea6b8..f7a7ad31b7d3f87a1bc4745afda97bddd8cc180c 100644
--- a/MantidQt/API/CMakeLists.txt
+++ b/MantidQt/API/CMakeLists.txt
@@ -5,6 +5,7 @@
 	src/AlgorithmRunner.cpp
 	src/BatchAlgorithmRunner.cpp
 	src/BoolPropertyWidget.cpp
+        src/FileDialogHandler.cpp
 	src/FilePropertyWidget.cpp
 	src/GenericDialog.cpp
 	src/HelpWindow.cpp
@@ -24,6 +25,8 @@
 	src/MdPlottingCmapsProvider.cpp
 	src/MdSettings.cpp
 	src/Message.cpp
+	src/NonOrthogonal.cpp
+	src/MWRunFiles.cpp
 	src/OptionsPropertyWidget.cpp
 	src/pixmaps.cpp
 	src/PlotAxis.cpp
@@ -35,6 +38,7 @@
         src/QScienceSpinBox.cpp
 	src/QtSignalChannel.cpp
         src/QwtRasterDataMD.cpp
+        src/QwtRasterDataMDNonOrthogonal.cpp
 	src/QwtWorkspaceBinData.cpp
 	src/QwtWorkspaceSpectrumData.cpp
 	src/RepoModel.cpp
@@ -49,6 +53,7 @@
 	src/UserSubWindow.cpp
 	src/VatesViewerInterface.cpp
         src/WidgetScrollbarDecorator.cpp
+  src/WindowIcons.cpp
 	src/WorkspaceObserver.cpp
 	src/WorkspaceIcons.cpp
 )
@@ -66,6 +71,8 @@ set ( MOC_FILES
   inc/MantidQtAPI/MantidDialog.h
   inc/MantidQtAPI/MantidHelpInterface.h
   inc/MantidQtAPI/MantidWidget.h
+  inc/MantidQtAPI/NonOrthogonal.h
+  inc/MantidQtAPI/MWRunFiles.h
   inc/MantidQtAPI/OptionsPropertyWidget.h
   inc/MantidQtAPI/PropertyWidget.h
   inc/MantidQtAPI/PythonRunner.h
@@ -113,6 +120,7 @@ set ( INC_FILES
 	inc/MantidQtAPI/PythonThreading.h
         inc/MantidQtAPI/QScienceSpinBox.h
         inc/MantidQtAPI/QwtRasterDataMD.h
+        inc/MantidQtAPI/QwtRasterDataMDNonOrthogonal.h
         inc/MantidQtAPI/QwtWorkspaceBinData.h
 	inc/MantidQtAPI/QwtWorkspaceSpectrumData.h
 	inc/MantidQtAPI/ScaleEngine.h
@@ -123,18 +131,27 @@ set ( INC_FILES
   inc/MantidQtAPI/TSVSerialiser.h
 	inc/MantidQtAPI/qwt_compat.h
         inc/MantidQtAPI/WidgetScrollbarDecorator.h
-		inc/MantidQtAPI/WorkspaceIcons.h
+  inc/MantidQtAPI/WindowIcons.h
+  inc/MantidQtAPI/WorkspaceIcons.h
 )
 
 set ( UI_FILES
   inc/MantidQtAPI/ManageUserDirectories.ui
+  inc/MantidQtAPI/MWRunFiles.ui
   inc/MantidQtAPI/ScriptRepositoryView.ui
 )
 
+# Python unit tests
+set ( TEST_PY_FILES
+  test/MWRunFilesTest.py
+)
+
 set( TEST_FILES
    BatchAlgorithmRunnerTest.h
+   FileDialogHandlerTest.h
    InterfaceManagerTest.h
    MantidColorMapTest.h
+   NonOrthogonalTest.h
    PlotAxisTest.h
    QwtWorkspaceBinDataTest.h
    QwtWorkspaceSpectrumDataTest.h
@@ -200,6 +217,7 @@ endif()
 
 add_subdirectory ( test )
 
+
 ###########################################################################
 # Installation settings
 ###########################################################################
diff --git a/MantidQt/API/inc/MantidQtAPI/BatchAlgorithmRunner.h b/MantidQt/API/inc/MantidQtAPI/BatchAlgorithmRunner.h
index 0e0ac3bd7249b3b946c162c27b9c428ff0b98e43..5e51a0644492fa49cfd1ecd549b82f7b65d20616 100644
--- a/MantidQt/API/inc/MantidQtAPI/BatchAlgorithmRunner.h
+++ b/MantidQt/API/inc/MantidQtAPI/BatchAlgorithmRunner.h
@@ -11,6 +11,8 @@
 #include <Poco/NObserver.h>
 #include <Poco/Void.h>
 
+#include <deque>
+
 namespace MantidQt {
 namespace API {
 /**
diff --git a/MantidQt/API/inc/MantidQtAPI/FileDialogHandler.h b/MantidQt/API/inc/MantidQtAPI/FileDialogHandler.h
index d11d77e47399815c75d8e5029f964ab416411ba8..f53bb16def2991340ed5631058d0375817fbd81e 100644
--- a/MantidQt/API/inc/MantidQtAPI/FileDialogHandler.h
+++ b/MantidQt/API/inc/MantidQtAPI/FileDialogHandler.h
@@ -1,12 +1,19 @@
 #ifndef MANTIDQT_API_FILEDIALOGHANDLER_H_
 #define MANTIDQT_API_FILEDIALOGHANDLER_H_
 
+#include "MantidKernel/DllConfig.h"
 #include <QFileDialog>
 #ifdef Q_OS_DARWIN
 #include <errno.h>
 #include <sys/sysctl.h>
 #endif
 
+namespace Mantid {
+namespace Kernel {
+class Property;
+}
+}
+
 namespace MantidQt {
 namespace API {
 /**
@@ -35,33 +42,41 @@ namespace API {
     File change history is stored at: <https://github.com/mantidproject/mantid>
     Code Documentation is available at: <http://doxygen.mantidproject.org>
 */
-struct FileDialogHandler {
-  /** The MacOS's native save dialog crashes when running a 10.6 package on 10.8
-  * so this function, which takes
-  *  the same arguments as the Qt function, ensures a nonnative object is used
-  * on the Mac when necessary.
-  *  If compiled on 10.8 the native will be used
-  *  @param parent :: the dialog will be shown centered over this parent widget
-  *  @param caption :: The dialog's caption
-  *  @param dir :: The file dialog's working directory will be set to dir. If
-  * dir includes a file name, the file will be selected
-  *  @param filter :: extensions of files to look for
-  *  @param selectedFilter :: pass a pointer an existing string that will be
-  * filled with the extension the user selected
-  *  @param options :: The options argument holds various options about how to
-  * run the dialog
+namespace FileDialogHandler {
+/**
+ * @param parent :: the dialog will be shown centered over this parent
+ * widget
+ * @param baseProp :: The property that the dialog parameters will be extracted
+ * from.
+ * @param options :: The options argument holds various options about how
+ * to run the dialog
   */
-  static QString getSaveFileName(QWidget *parent = 0,
-                                 const QString &caption = QString(),
-                                 const QString &dir = QString(),
-                                 const QString &filter = QString(),
-                                 QString *selectedFilter = 0,
-                                 QFileDialog::Options options = 0) {
-    options = options | QFileDialog::DontUseNativeDialog;
-    return QFileDialog::getSaveFileName(parent, caption, dir, filter,
-                                        selectedFilter, options);
-  }
-};
+DLLExport QString getSaveFileName(QWidget *parent = 0,
+                                  const Mantid::Kernel::Property *baseProp = 0,
+                                  QFileDialog::Options options = 0);
+
+/**
+ * For file dialogs. This will add the selected extension if an extension
+ * doesn't
+ * already exist.
+ */
+DLLExport QString
+addExtension(const QString &filename, const QString &selectedFilter);
+
+DLLExport QString getFilter(const Mantid::Kernel::Property *baseProp);
+
+/** For file dialogs
+ *
+ * @param exts :: vector of extensions
+ * @param defaultExt :: default extension to use
+ * @return a string that filters files by extenstions
+ */
+DLLExport QString
+getFilter(const std::vector<std::string> &exts, const std::string &defaultExt);
+
+DLLExport QString
+getCaption(const std::string &dialogName, const Mantid::Kernel::Property *prop);
+}
 }
 }
 
diff --git a/MantidQt/API/inc/MantidQtAPI/IProjectSerialisable.h b/MantidQt/API/inc/MantidQtAPI/IProjectSerialisable.h
index e46734a27ec5ffc69b94b2b8bbcb8cfb98cf9d09..0f21b581b6989de168a833984cc3417981df3b91 100644
--- a/MantidQt/API/inc/MantidQtAPI/IProjectSerialisable.h
+++ b/MantidQt/API/inc/MantidQtAPI/IProjectSerialisable.h
@@ -4,6 +4,7 @@
 #include "MantidKernel/System.h"
 #include <stdexcept>
 #include <string>
+#include <vector>
 
 class ApplicationWindow;
 
@@ -55,6 +56,12 @@ public:
 
   /// Serialises to a string that can be saved to a project file.
   virtual std::string saveToProject(ApplicationWindow *app) = 0;
+  /// Returns a list of workspace names that are used by this window
+  virtual std::vector<std::string> getWorkspaceNames() = 0;
+  /// Returns the user friendly name of the window
+  virtual std::string getWindowName() = 0;
+  /// Returns the type of the window
+  virtual std::string getWindowType() = 0;
 };
 
 } // namespace API
diff --git a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/MWRunFiles.h b/MantidQt/API/inc/MantidQtAPI/MWRunFiles.h
similarity index 94%
rename from MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/MWRunFiles.h
rename to MantidQt/API/inc/MantidQtAPI/MWRunFiles.h
index da23a5ca868e4c6b8d6ced837c4ef732314b1928..59d4fd822a378f1fbbada876c4e6ca48d08923fa 100644
--- a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/MWRunFiles.h
+++ b/MantidQt/API/inc/MantidQtAPI/MWRunFiles.h
@@ -2,8 +2,8 @@
 #define MANTIDQTMANTIDWIDGETS_MWRUNFILES_H_
 
 #include "ui_MWRunFiles.h"
+#include "MantidQtAPI/DllOption.h"
 #include "MantidQtAPI/MantidWidget.h"
-#include "WidgetDllOption.h"
 #include <QString>
 #include <QSettings>
 #include <QComboBox>
@@ -19,7 +19,7 @@ class IAlgorithm;
 }
 
 namespace MantidQt {
-namespace MantidWidgets {
+namespace API {
 /**
  * A class to allow the asynchronous finding of files.
  */
@@ -97,7 +97,7 @@ File change history is stored at: <https://github.com/mantidproject/mantid>
 Code Documentation is available at: <http://doxygen.mantidproject.org>
 */
 
-class EXPORT_OPT_MANTIDQT_MANTIDWIDGETS MWRunFiles : public API::MantidWidget {
+class EXPORT_OPT_MANTIDQT_API MWRunFiles : public API::MantidWidget {
   Q_OBJECT
 
   Q_PROPERTY(bool findRunFiles READ isForRunFiles WRITE isForRunFiles)
@@ -137,10 +137,8 @@ public:
   };
   /// Options for the live button
   enum LiveButtonOpts {
-    Hide,       ///< Don't use the live button
-    AlwaysShow, ///< Show whether a connection is possible or not (will be
-    /// disabled)
-    ShowIfCanConnect ///< Only show if able to connect to the live data server
+    Hide, ///< Don't use the live button
+    Show, ///< Display the live button
   };
 
   /// Default constructor
@@ -175,7 +173,6 @@ public:
   void liveButtonState(LiveButtonOpts);
 
   // Standard setters/getters
-  void liveButtonSetEnabled(bool);
   void liveButtonSetChecked(bool);
   bool liveButtonIsChecked() const;
   bool isEmpty() const;
@@ -238,8 +235,6 @@ signals:
   void fileFindingFinished();
   /// Emitted when the live button is toggled
   void liveButtonPressed(bool);
-  /// Signal emitted after asynchronous checking of live stream availability
-  void liveButtonSetEnabledSignal(bool);
   /// Emitted when inspection of any found files is completed
   void fileInspectionFinished();
 
@@ -254,7 +249,7 @@ public slots:
   void findFiles();
   boost::shared_ptr<const Mantid::API::IAlgorithm> stopLiveAlgorithm();
 
-protected:
+public:
   // Method for handling drop events
   void dropEvent(QDropEvent *) override;
   // called when a drag event enters the class
@@ -278,8 +273,6 @@ private:
   /// displays the validator red star if either m_fileProblem or
   /// m_entryNumProblem are not empty
   void refreshValidator();
-  /// Called asynchronously to check the availability of the live stream
-  void checkLiveConnection();
   /// Turn on/off display of validator red star (default is on)
   void setValidatorDisplay(bool display);
 
diff --git a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/MWRunFiles.ui b/MantidQt/API/inc/MantidQtAPI/MWRunFiles.ui
similarity index 96%
rename from MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/MWRunFiles.ui
rename to MantidQt/API/inc/MantidQtAPI/MWRunFiles.ui
index 6edbb9057145dede6af2f9b6857fbfc818a05270..eb3246fe18b3aefd454ed534fbc5799683080457 100644
--- a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/MWRunFiles.ui
+++ b/MantidQt/API/inc/MantidQtAPI/MWRunFiles.ui
@@ -20,7 +20,16 @@
    <string>Form</string>
   </property>
   <layout class="QHBoxLayout" name="horizontalLayout">
-   <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>
@@ -32,9 +41,6 @@
    </item>
    <item>
     <widget class="QLineEdit" name="fileEditor">
-     <property name="maxLength">
-       <number>500000</number>
-     </property>
      <property name="sizePolicy">
       <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
        <horstretch>0</horstretch>
@@ -47,6 +53,9 @@
        <height>0</height>
       </size>
      </property>
+     <property name="maxLength">
+      <number>500000</number>
+     </property>
     </widget>
    </item>
    <item>
@@ -154,9 +163,6 @@
    </item>
    <item>
     <widget class="QPushButton" name="liveButton">
-     <property name="enabled">
-      <bool>false</bool>
-     </property>
      <property name="toolTip">
       <string>Enabled if a connection can be made to your default instrument</string>
      </property>
diff --git a/MantidQt/API/inc/MantidQtAPI/NonOrthogonal.h b/MantidQt/API/inc/MantidQtAPI/NonOrthogonal.h
new file mode 100644
index 0000000000000000000000000000000000000000..e78351e4a19e69a5b83ed649f1cdfc99aa4f2feb
--- /dev/null
+++ b/MantidQt/API/inc/MantidQtAPI/NonOrthogonal.h
@@ -0,0 +1,70 @@
+#ifndef MANTID_MANTIDQT_API_NON_ORTHOGONAL_H_
+#define MANTID_MANTIDQT_API_NON_ORTHOGONAL_H_
+
+#include "MantidQtAPI/DllOption.h"
+#include "MantidAPI/IMDWorkspace.h"
+#include "MantidKernel/Matrix.h"
+
+namespace MantidQt {
+namespace API {
+
+enum class DimensionSelection { H, K, L };
+
+void EXPORT_OPT_MANTIDQT_API
+provideSkewMatrix(Mantid::Kernel::DblMatrix &skewMatrix,
+                  Mantid::API::IMDWorkspace_const_sptr workspace);
+
+bool EXPORT_OPT_MANTIDQT_API
+requiresSkewMatrix(Mantid::API::IMDWorkspace_const_sptr workspace);
+
+bool EXPORT_OPT_MANTIDQT_API
+isHKLDimensions(Mantid::API::IMDWorkspace_const_sptr workspace, size_t dimX,
+                size_t dimY);
+
+size_t EXPORT_OPT_MANTIDQT_API
+getMissingHKLDimensionIndex(Mantid::API::IMDWorkspace_const_sptr workspace,
+                            size_t dimX, size_t dimY);
+
+void EXPORT_OPT_MANTIDQT_API
+transformFromDoubleToCoordT(Mantid::Kernel::DblMatrix &skewMatrix,
+                            Mantid::coord_t skewMatrixCoord[9]);
+
+void EXPORT_OPT_MANTIDQT_API
+transformLookpointToWorkspaceCoord(Mantid::coord_t *lookPoint,
+                                   const Mantid::coord_t skewMatrix[9],
+                                   const size_t &dimX, const size_t &dimY,
+                                   const size_t &dimSlice);
+
+template <typename T>
+void transformLookpointToWorkspaceCoordGeneric(
+    T &lookPoint, const Mantid::coord_t skewMatrix[9], const size_t &dimX,
+    const size_t &dimY, const size_t &dimSlice) {
+  auto sliceDimResult =
+      (lookPoint[dimSlice] - skewMatrix[3 * dimSlice + dimX] * lookPoint[dimX] -
+       skewMatrix[3 * dimSlice + dimY] * lookPoint[dimY]) /
+      skewMatrix[3 * dimSlice + dimSlice];
+
+  auto OrigDimSliceValue = lookPoint[dimSlice];
+  lookPoint[dimSlice] = sliceDimResult;
+
+  auto v1 = lookPoint[0];
+  auto v2 = lookPoint[1];
+  auto v3 = lookPoint[2];
+
+  lookPoint[dimX] = v1 * skewMatrix[0 + 3 * dimX] +
+                    v2 * skewMatrix[1 + 3 * dimX] +
+                    v3 * skewMatrix[2 + 3 * dimX];
+  lookPoint[dimY] = v1 * skewMatrix[0 + 3 * dimY] +
+                    v2 * skewMatrix[1 + 3 * dimY] +
+                    v3 * skewMatrix[2 + 3 * dimY];
+
+  lookPoint[dimSlice] = OrigDimSliceValue;
+}
+
+std::pair<double, double> EXPORT_OPT_MANTIDQT_API
+getGridLineAnglesInRadian(Mantid::coord_t skewMatrixCoord[9], size_t dimX,
+                          size_t dimY);
+}
+}
+
+#endif
diff --git a/MantidQt/API/inc/MantidQtAPI/QwtRasterDataMD.h b/MantidQt/API/inc/MantidQtAPI/QwtRasterDataMD.h
index 6e50d2b64665928a6980d21b5bd7d80349225c88..4775a964bb0cf70bf10e143d4fbc614958f82756 100644
--- a/MantidQt/API/inc/MantidQtAPI/QwtRasterDataMD.h
+++ b/MantidQt/API/inc/MantidQtAPI/QwtRasterDataMD.h
@@ -41,10 +41,10 @@ public:
   QwtDoubleInterval range() const override;
   void setRange(const QwtDoubleInterval &range);
 
-  void setSliceParams(size_t dimX, size_t dimY,
-                      Mantid::Geometry::IMDDimension_const_sptr X,
-                      Mantid::Geometry::IMDDimension_const_sptr Y,
-                      std::vector<Mantid::coord_t> &slicePoint);
+  virtual void setSliceParams(size_t dimX, size_t dimY,
+                              Mantid::Geometry::IMDDimension_const_sptr X,
+                              Mantid::Geometry::IMDDimension_const_sptr Y,
+                              std::vector<Mantid::coord_t> &slicePoint);
 
   double value(double x, double y) const override;
 
diff --git a/MantidQt/API/inc/MantidQtAPI/QwtRasterDataMDNonOrthogonal.h b/MantidQt/API/inc/MantidQtAPI/QwtRasterDataMDNonOrthogonal.h
new file mode 100644
index 0000000000000000000000000000000000000000..827e9067bfaf15f1c425804766a08c92b15a0f51
--- /dev/null
+++ b/MantidQt/API/inc/MantidQtAPI/QwtRasterDataMDNonOrthogonal.h
@@ -0,0 +1,39 @@
+#ifndef QwtRasterDataMDNonOrthogonal_H_
+#define QwtRasterDataMDNonOrthogonal_H_
+
+#include "MantidQtAPI/DllOption.h"
+#include "MantidQtAPI/QwtRasterDataMD.h"
+#include "MantidAPI/IMDWorkspace.h"
+#include "MantidKernel/Matrix.h"
+
+namespace MantidQt {
+namespace API {
+
+class EXPORT_OPT_MANTIDQT_API QwtRasterDataMDNonOrthogonal
+    : public QwtRasterDataMD {
+public:
+  QwtRasterDataMDNonOrthogonal();
+  ~QwtRasterDataMDNonOrthogonal() override;
+  QwtRasterDataMDNonOrthogonal *copy() const override;
+
+  void setWorkspace(Mantid::API::IMDWorkspace_const_sptr ws) override;
+
+  double value(double x, double y) const override;
+
+  void setSliceParams(size_t dimX, size_t dimY,
+                      Mantid::Geometry::IMDDimension_const_sptr X,
+                      Mantid::Geometry::IMDDimension_const_sptr Y,
+                      std::vector<Mantid::coord_t> &slicePoint) override;
+  Mantid::coord_t *m_lookPoint;
+  Mantid::coord_t m_fromHklToXyz[9];
+  size_t m_missingHKLdim;
+
+protected:
+  void copyFrom(const QwtRasterDataMDNonOrthogonal &source,
+                QwtRasterDataMDNonOrthogonal &dest) const;
+};
+
+} // namespace SliceViewer
+} // namespace Mantid
+
+#endif /* QwtRasterDataMDNonOrthogonal_H_ */
diff --git a/MantidQt/API/inc/MantidQtAPI/VatesViewerInterface.h b/MantidQt/API/inc/MantidQtAPI/VatesViewerInterface.h
index 900937d14358e19d99f5f2e106efe7da02b7fe46..038a863c0aa8bb2438c0aa6ca936a08d1093f22e 100644
--- a/MantidQt/API/inc/MantidQtAPI/VatesViewerInterface.h
+++ b/MantidQt/API/inc/MantidQtAPI/VatesViewerInterface.h
@@ -68,7 +68,7 @@ public:
   /**
    * Special function of correct widget invocation for plugin mode.
    */
-  virtual void setupPluginMode();
+  virtual void setupPluginMode(int WsType, const std::string &instrumentName);
 
   /// Static method to create a handle to new window instance
   static IProjectSerialisable *loadFromProject(const std::string &lines,
diff --git a/MantidQt/API/inc/MantidQtAPI/WindowIcons.h b/MantidQt/API/inc/MantidQtAPI/WindowIcons.h
new file mode 100644
index 0000000000000000000000000000000000000000..a48e2029d5b4285322d54de9170b6be64724ce4f
--- /dev/null
+++ b/MantidQt/API/inc/MantidQtAPI/WindowIcons.h
@@ -0,0 +1,34 @@
+#ifndef MANTIDQT_API_WINDOWICONS_H_
+#define MANTIDQT_API_WINDOWICONS_H_
+
+#include "DllOption.h"
+#include <QIcon>
+#include <QMap>
+
+namespace MantidQt {
+namespace API {
+/**
+ * Defines a mapping between a workspace ID and a pixmap
+ * to use for an icon.
+ */
+class EXPORT_OPT_MANTIDQT_API WindowIcons {
+public:
+  WindowIcons();
+
+  /// Returns an icon for the given ID
+  QIcon getIcon(const std::string &windowID) const;
+  /// Returns an icon ID for the given window ID
+  std::string getIconID(const std::string &windowID) const;
+
+private:
+  /// Defines the mapping between ID & pixmap name
+  void initInternalLookup();
+  /// Build a icon object from an image file
+  QIcon makeIconFromFile(const std::string &path) const;
+
+  /// Internal map instance
+  QMap<std::string, std::string> m_idToPixmapName;
+};
+}
+}
+#endif // MANTIDQT_API_WINDOWICONS_H_
diff --git a/MantidQt/API/inc/MantidQtAPI/WorkspaceIcons.h b/MantidQt/API/inc/MantidQtAPI/WorkspaceIcons.h
index 877542fbf2647947f495f3c7229249943d994444..ca5361d8eb185d8d363980d97bb550ffac0db326 100644
--- a/MantidQt/API/inc/MantidQtAPI/WorkspaceIcons.h
+++ b/MantidQt/API/inc/MantidQtAPI/WorkspaceIcons.h
@@ -17,6 +17,8 @@ public:
 
   /// Returns an icon for the given ID
   QPixmap getIcon(const std::string &workspaceID) const;
+  /// Returns an icon ID for the given workspace ID
+  std::string getIconID(const std::string &workspaceID) const;
 
 private:
   /// Defines the mapping between ID & pixmap name
diff --git a/MantidQt/API/src/AlgorithmDialog.cpp b/MantidQt/API/src/AlgorithmDialog.cpp
index 0addeb5985764e8228fa348cb75a35922c8b0f28..f4f0cbee9259fda500af5aaccd3fde30ceaf75a1 100644
--- a/MantidQt/API/src/AlgorithmDialog.cpp
+++ b/MantidQt/API/src/AlgorithmDialog.cpp
@@ -1,9 +1,7 @@
-//----------------------------------
-// Includes
-//----------------------------------
 #include "MantidAPI/AlgorithmManager.h"
 #include "MantidAPI/IWorkspaceProperty.h"
 #include "MantidKernel/DateAndTime.h"
+#include "MantidKernel/IPropertySettings.h"
 #include "MantidKernel/Logger.h"
 
 #include "MantidQtAPI/AlgorithmDialog.h"
diff --git a/MantidQt/API/src/AlgorithmPropertiesWidget.cpp b/MantidQt/API/src/AlgorithmPropertiesWidget.cpp
index 9ad793f078832ccd64e222a860d922d051f81590..5f1a75078960660c3bda06d67f5caab26570ab31 100644
--- a/MantidQt/API/src/AlgorithmPropertiesWidget.cpp
+++ b/MantidQt/API/src/AlgorithmPropertiesWidget.cpp
@@ -1,3 +1,4 @@
+#include "MantidKernel/IPropertySettings.h"
 #include "MantidKernel/Property.h"
 #include "MantidKernel/System.h"
 #include "MantidQtAPI/AlgorithmPropertiesWidget.h"
diff --git a/MantidQt/API/src/FileDialogHandler.cpp b/MantidQt/API/src/FileDialogHandler.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b355c1765da484a4982676101d92d8a96d153a02
--- /dev/null
+++ b/MantidQt/API/src/FileDialogHandler.cpp
@@ -0,0 +1,167 @@
+#include "MantidQtAPI/FileDialogHandler.h"
+#include "MantidAPI/FileProperty.h"
+#include "MantidAPI/MultipleFileProperty.h"
+#include "MantidQtAPI/AlgorithmInputHistory.h"
+#include <boost/regex.hpp>
+
+namespace { // anonymous namespace
+const boost::regex FILE_EXT_REG_EXP{"^.+\\s+\\((\\S+)\\)$"};
+const QString ALL_FILES("All Files (*)");
+
+QString getExtensionFromFilter(const QString &selectedFilter) {
+  // empty returns empty
+  if (selectedFilter.isEmpty()) {
+    return QString("");
+  }
+
+  // search for single extension
+  boost::smatch result;
+  if (boost::regex_search(selectedFilter.toStdString(), result,
+                          FILE_EXT_REG_EXP) &&
+      result.size() == 2) {
+    auto extension = QString::fromStdString(result[1]);
+    if (extension.startsWith("*"))
+      return extension.remove(0, 1);
+    else
+      return extension;
+  } else {
+    // failure to match suggests multi-extension filter
+    std::stringstream msg;
+    msg << "Failed to determine single extension from \""
+        << selectedFilter.toStdString() << "\"";
+    throw std::runtime_error(msg.str());
+  }
+}
+} // anonymous namespace
+
+namespace MantidQt {
+namespace API {
+namespace FileDialogHandler {
+/**
+    Contains modifications to Qt functions where problems have been found
+    on certain operating systems
+
+    Copyright &copy; 2009-2010 ISIS Rutherford Appleton Laboratory, NScD Oak
+   Ridge National Laboratory & European Spallation Source
+    @date 17/09/2010
+
+    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>
+*/
+QString getSaveFileName(QWidget *parent,
+                        const Mantid::Kernel::Property *baseProp,
+                        QFileDialog::Options options) {
+  // set up filters and dialog title
+  const auto filter = getFilter(baseProp);
+  const auto caption = getCaption("Save file", baseProp);
+
+  QString selectedFilter;
+
+  // create the file browser
+  QString filename = QFileDialog::getSaveFileName(
+      parent, caption, AlgorithmInputHistory::Instance().getPreviousDirectory(),
+      filter, &selectedFilter, options);
+
+  return addExtension(filename, selectedFilter);
+}
+
+QString addExtension(const QString &filename, const QString &selectedFilter) {
+  // just return an empty string if that is what was given
+  if (filename.isEmpty())
+    return filename;
+
+  // Check the filename and append the selected filter if necessary
+  if (QFileInfo(filename).completeSuffix().isEmpty()) {
+    auto ext = getExtensionFromFilter(selectedFilter);
+    if (filename.endsWith(".") && ext.startsWith(".")) {
+      ext = ext.remove(0, 1);
+    }
+    return filename + ext;
+  } else {
+    return filename;
+  }
+}
+
+QString getFilter(const Mantid::Kernel::Property *baseProp) {
+  if (!baseProp)
+    return ALL_FILES;
+
+  // multiple file version
+  const auto *multiProp =
+      dynamic_cast<const Mantid::API::MultipleFileProperty *>(baseProp);
+  if (bool(multiProp))
+    return getFilter(multiProp->getExts(), multiProp->getDefaultExt());
+
+  // regular file version
+  const auto *singleProp =
+      dynamic_cast<const Mantid::API::FileProperty *>(baseProp);
+  // The allowed values in this context are file extensions
+  if (bool(singleProp))
+    return getFilter(singleProp->allowedValues(), singleProp->getDefaultExt());
+
+  // otherwise only the all files exists
+  return ALL_FILES;
+}
+
+/** For file dialogs. Have each filter on a separate line with the default as
+ * the first.
+ *
+ * @param exts :: vector of extensions
+ * @param defaultExt :: default extension to use
+ * @return a string that filters files by extenstions
+ */
+QString getFilter(const std::vector<std::string> &exts,
+                  const std::string &defaultExt) {
+  QString filter("");
+
+  if (!defaultExt.empty()) {
+    filter.append(QString::fromStdString(defaultExt) + " (*" +
+                  QString::fromStdString(defaultExt) + ");;");
+  }
+
+  if (!exts.empty()) {
+    // Push a wild-card onto the front of each file suffix
+    for (auto &itr : exts) {
+      if (itr != defaultExt) {
+        filter.append(QString::fromStdString(itr) + " (*" +
+                      QString::fromStdString(itr) + ");;");
+      }
+    }
+    filter = filter.trimmed();
+  }
+  filter.append(ALL_FILES);
+  return filter;
+}
+
+QString getCaption(const std::string &dialogName,
+                   const Mantid::Kernel::Property *prop) {
+  // generate the dialog title
+  auto dialogTitle = QString::fromStdString(dialogName);
+  if (bool(prop)) {
+    const auto name = prop->name();
+    if (name != "Filename" && prop->name() != "Directory" &&
+        prop->name() != "Dir") {
+      dialogTitle.append(" - ");
+      dialogTitle.append(QString::fromStdString(name));
+    }
+  }
+  return dialogTitle;
+}
+}
+}
+}
diff --git a/MantidQt/API/src/FilePropertyWidget.cpp b/MantidQt/API/src/FilePropertyWidget.cpp
index 4e84296181e106943e33dfdbf808ae1f526bcc92..f640f64cd3c4127b028faf25d270ed1473d4b11b 100644
--- a/MantidQt/API/src/FilePropertyWidget.cpp
+++ b/MantidQt/API/src/FilePropertyWidget.cpp
@@ -77,38 +77,6 @@ void FilePropertyWidget::browseClicked() {
   }
 }
 
-//-------------------------------------------------------------------------------------------------
-/** For file dialogs
- *
- * @param exts :: vector of extensions
- * @param defaultExt :: default extension to use
- * @return a string that filters files by extenstions
- */
-QString getFileDialogFilter(const std::vector<std::string> &exts,
-                            const std::string &defaultExt) {
-  QString filter("");
-
-  if (!defaultExt.empty()) {
-    filter.append(QString::fromStdString(defaultExt) + " (*" +
-                  QString::fromStdString(defaultExt) + ");;");
-  }
-
-  if (!exts.empty()) {
-    // --------- Load a File -------------
-    auto iend = exts.end();
-    // Push a wild-card onto the front of each file suffix
-    for (auto itr = exts.begin(); itr != iend; ++itr) {
-      if ((*itr) != defaultExt) {
-        filter.append(QString::fromStdString(*itr) + " (*" +
-                      QString::fromStdString(*itr) + ");;");
-      }
-    }
-    filter = filter.trimmed();
-  }
-  filter.append("All Files (*)");
-  return filter;
-}
-
 //----------------------------------------------------------------------------------------------
 /** Open the file dialog for a given property
  *
@@ -121,10 +89,6 @@ QString FilePropertyWidget::openFileDialog(Mantid::Kernel::Property *baseProp) {
   if (!prop)
     return "";
 
-  // The allowed values in this context are file extensions
-  std::vector<std::string> exts = prop->allowedValues();
-  std::string defaultExt = prop->getDefaultExt();
-
   /* MG 20/07/09: Static functions such as these that use native Windows and MAC
      dialogs
      in those environments are alot faster. This is unforunately at the expense
@@ -133,55 +97,18 @@ QString FilePropertyWidget::openFileDialog(Mantid::Kernel::Property *baseProp) {
   */
   QString filename;
   if (prop->isLoadProperty()) {
-    QString filter = getFileDialogFilter(exts, defaultExt);
+    const auto filter = FileDialogHandler::getFilter(baseProp);
+    const auto caption = FileDialogHandler::getCaption("Open file", baseProp);
     filename = QFileDialog::getOpenFileName(
-        NULL, "Open file",
+        nullptr, caption,
         AlgorithmInputHistory::Instance().getPreviousDirectory(), filter);
   } else if (prop->isSaveProperty()) {
-    // --------- Save a File -------------
-    // Have each filter on a separate line with the default as the first
-    QString filter;
-    if (!defaultExt.empty()) {
-      filter = "*" + QString::fromStdString(defaultExt) + ";;";
-    }
-    auto iend = exts.end();
-    for (auto itr = exts.begin(); itr != iend; ++itr) {
-      if ((*itr) != defaultExt) {
-        filter.append("*" + QString::fromStdString(*itr) + ";;");
-      }
-    }
-    // Remove last two semi-colons or else we get an extra empty option in the
-    // box
-    filter.chop(2);
-    // Prepend the default filter
-    QString selectedFilter;
-    filename = MantidQt::API::FileDialogHandler::getSaveFileName(
-        NULL, "Save file",
-        AlgorithmInputHistory::Instance().getPreviousDirectory(), filter,
-        &selectedFilter);
-
-    // Check the filename and append the selected filter if necessary
-    if (QFileInfo(filename).completeSuffix().isEmpty()) {
-      // Hack off the first star that the filter returns
-      QString ext = selectedFilter;
-
-      if (selectedFilter.startsWith("*.")) {
-        // 1 character from the start
-        ext = ext.remove(0, 1);
-      } else {
-        ext = "";
-      }
-
-      if (filename.endsWith(".") && ext.startsWith(".")) {
-        ext = ext.remove(0, 1);
-      }
-
-      // Construct the full file name
-      filename += ext;
-    }
+    filename = FileDialogHandler::getSaveFileName(nullptr, prop);
   } else if (prop->isDirectoryProperty()) {
+    const auto caption =
+        FileDialogHandler::getCaption("Choose a Directory", baseProp);
     filename = QFileDialog::getExistingDirectory(
-        NULL, "Choose a Directory",
+        nullptr, caption,
         AlgorithmInputHistory::Instance().getPreviousDirectory());
   } else {
     throw std::runtime_error(
@@ -211,9 +138,9 @@ FilePropertyWidget::openMultipleFileDialog(Mantid::Kernel::Property *baseProp) {
   if (!prop)
     return QStringList();
 
-  QString filter = getFileDialogFilter(prop->getExts(), prop->getDefaultExt());
+  const auto filter = FileDialogHandler::getFilter(baseProp);
   QStringList files = QFileDialog::getOpenFileNames(
-      NULL, "Open Multiple Files",
+      nullptr, "Open Multiple Files",
       AlgorithmInputHistory::Instance().getPreviousDirectory(), filter);
 
   return files;
diff --git a/MantidQt/API/src/GenericDialog.cpp b/MantidQt/API/src/GenericDialog.cpp
index cfad329e99df845f41a0a7493d6cf5540c5c8d90..9069528375c6ba91d7ad8d16e4b17c311fa00cb3 100644
--- a/MantidQt/API/src/GenericDialog.cpp
+++ b/MantidQt/API/src/GenericDialog.cpp
@@ -24,10 +24,8 @@
 #include <QSignalMapper>
 #include <QFileInfo>
 #include <QDir>
-#include "MantidAPI/MultipleFileProperty.h"
 #include <QGroupBox>
 #include <climits>
-#include "MantidQtAPI/FilePropertyWidget.h"
 #include "MantidQtAPI/PropertyWidgetFactory.h"
 #include "MantidQtAPI/AlgorithmPropertiesWidget.h"
 #include "MantidQtAPI/PropertyWidget.h"
diff --git a/MantidQt/MantidWidgets/src/MWRunFiles.cpp b/MantidQt/API/src/MWRunFiles.cpp
similarity index 96%
rename from MantidQt/MantidWidgets/src/MWRunFiles.cpp
rename to MantidQt/API/src/MWRunFiles.cpp
index a5addee02c46f293b713933a22b1833408911e85..9abc3aa5f7d3f5c0e20da1e05a26894003562627 100644
--- a/MantidQt/MantidWidgets/src/MWRunFiles.cpp
+++ b/MantidQt/API/src/MWRunFiles.cpp
@@ -1,4 +1,4 @@
-#include "MantidQtMantidWidgets/MWRunFiles.h"
+#include "MantidQtAPI/MWRunFiles.h"
 
 #include "MantidKernel/ConfigService.h"
 #include "MantidKernel/FacilityInfo.h"
@@ -25,7 +25,7 @@
 
 using namespace Mantid::Kernel;
 using namespace Mantid::API;
-using namespace MantidQt::MantidWidgets;
+using namespace MantidQt::API;
 
 ////////////////////////////////////////////////////////////////////
 // FindFilesThread
@@ -227,10 +227,6 @@ MWRunFiles::MWRunFiles(QWidget *parent)
   doButtonOpt(m_buttonOpt);
 
   liveButtonState(m_liveButtonState);
-  connect(this, SIGNAL(liveButtonSetEnabledSignal(bool)), m_uiForm.liveButton,
-          SLOT(setEnabled(bool)));
-  connect(this, SIGNAL(liveButtonSetEnabledSignal(bool)), m_uiForm.liveButton,
-          SLOT(show()));
   connect(m_uiForm.liveButton, SIGNAL(toggled(bool)), this,
           SIGNAL(liveButtonPressed(bool)));
 
@@ -450,30 +446,11 @@ void MWRunFiles::liveButtonState(const LiveButtonOpts option) {
   m_liveButtonState = option;
   if (m_liveButtonState == Hide) {
     m_uiForm.liveButton->hide();
-  } else {
-    liveButtonSetEnabled(false); // This setting ensures right outcome if the
-                                 // connection check fails
-    // Checks (asynchronously) whether it's possible to connect to the user's
-    // default instrument
-    QtConcurrent::run(this, &MWRunFiles::checkLiveConnection);
-    if (m_liveButtonState == AlwaysShow) {
-      m_uiForm.liveButton->show();
-    }
+  } else if (m_liveButtonState == Show) {
+    m_uiForm.liveButton->show();
   }
 }
 
-void MWRunFiles::checkLiveConnection() {
-  // Checks whether it's possible to connect to the user's default instrument
-  if (LiveListenerFactory::Instance().checkConnection(
-          ConfigService::Instance().getInstrument().name())) {
-    emit liveButtonSetEnabledSignal(true);
-  }
-}
-
-void MWRunFiles::liveButtonSetEnabled(const bool enabled) {
-  m_uiForm.liveButton->setEnabled(enabled);
-}
-
 void MWRunFiles::liveButtonSetChecked(const bool checked) {
   m_uiForm.liveButton->setChecked(checked);
 }
@@ -997,13 +974,13 @@ QString MWRunFiles::openFileDialog() {
     if (!file.isEmpty())
       filenames.append(file);
   } else if (m_allowMultipleFiles) {
-    filenames =
-        QFileDialog::getOpenFileNames(this, "Open file", dir, m_fileFilter, 0,
-                                      QFileDialog::DontResolveSymlinks);
+    filenames = QFileDialog::getOpenFileNames(this, "Open file", dir,
+                                              m_fileFilter, nullptr,
+                                              QFileDialog::DontResolveSymlinks);
   } else {
     QString file =
-        QFileDialog::getOpenFileName(this, "Open file", dir, m_fileFilter, 0,
-                                     QFileDialog::DontResolveSymlinks);
+        QFileDialog::getOpenFileName(this, "Open file", dir, m_fileFilter,
+                                     nullptr, QFileDialog::DontResolveSymlinks);
     if (!file.isEmpty())
       filenames.append(file);
   }
diff --git a/MantidQt/API/src/NonOrthogonal.cpp b/MantidQt/API/src/NonOrthogonal.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1ac0feb0a3a3972dd9966fd683fdc007dffd346d
--- /dev/null
+++ b/MantidQt/API/src/NonOrthogonal.cpp
@@ -0,0 +1,493 @@
+#include "MantidQtAPI/NonOrthogonal.h"
+#include "MantidAPI/IMDWorkspace.h"
+#include "MantidAPI/Sample.h"
+#include "MantidAPI/Run.h"
+#include "MantidAPI/CoordTransform.h"
+#include "MantidKernel/Matrix.h"
+#include "MantidGeometry/Crystal/UnitCell.h"
+#include "MantidGeometry/Crystal/OrientedLattice.h"
+#include "MantidAPI/IMDEventWorkspace.h"
+#include "MantidAPI/IMDHistoWorkspace.h"
+#include "MantidGeometry/MDGeometry/HKL.h"
+
+#include <boost/pointer_cast.hpp>
+#include <array>
+#include <algorithm>
+#include <math.h>
+
+/**
+*
+* There are several things which should be clarified.
+*
+* 1. We are dealing with a (potentially non-orthogonal system) defined by
+* the basisi vectors a*, b* and c* with the coordinates h, k, l. On occasion
+* H, K, and L are used to describe the basisi vectors.
+*
+* 2. What we call a skewMatrix is a modified BW (and sometimes a modified
+*(BW)^-1) matrix.
+* The BW matrix transforms from the non-orhtogonal presentation to the
+*orthogonal representation.
+* The (BW)^-1 transforms form the orhtogonal presentation to the non-orthogonal
+*representation.
+* The orthogonal representation is a orthogonal coordinate system with
+*coordinates (x, y, z),
+* where the basis vector eX assoicated with x is aligned with the H. The basis
+*vector eY
+* associated with y is in the H-K plane and perpendicular to x. The basis vector
+*eZ associated
+* with z is orthgonal to x and y.
+*
+* This is important. H is always parallel to eX, K is always in the x-y plane
+*and L can be pretty
+* much anything.
+*
+* 3. The screen coordinate system consists of Xs and Ys.
+*
+*
+*/
+
+namespace {
+void checkForSampleAndRunEntries(
+    const Mantid::API::Sample &sample, const Mantid::API::Run &run,
+    Mantid::Kernel::SpecialCoordinateSystem specialCoordinateSystem) {
+
+  if (Mantid::Kernel::HKL != specialCoordinateSystem) {
+    throw std::invalid_argument(
+        "Cannot create non-orthogonal view for non-HKL coordinates");
+  }
+
+  if (!sample.hasOrientedLattice()) {
+    throw std::invalid_argument("OrientedLattice is not present on workspace");
+  }
+
+  if (!run.hasProperty("W_MATRIX")) {
+    throw std::invalid_argument("W_MATRIX is not present on workspace");
+  }
+}
+
+void normalizeColumns(Mantid::Kernel::DblMatrix &skewMatrix) {
+  const auto numberOfColumns = skewMatrix.numCols();
+  const auto numberOfRows = skewMatrix.numRows();
+  std::vector<double> bNorm;
+  bNorm.reserve(skewMatrix.numCols());
+  for (size_t column = 0; column < numberOfColumns; ++column) {
+    double sumOverRow(0.0);
+    for (size_t row = 0; row < numberOfRows; ++row) {
+      sumOverRow += std::pow(skewMatrix[row][column], 2);
+    }
+    bNorm.push_back(std::sqrt(sumOverRow));
+  }
+
+  // Apply column normalisation to skew matrix
+  const size_t dim = 3;
+  Mantid::Kernel::DblMatrix scaleMat(3, 3, true);
+  for (size_t index = 0; index < dim; ++index) {
+    scaleMat[index][index] /= bNorm[index];
+  }
+
+  skewMatrix *= scaleMat;
+}
+
+void stripMatrix(Mantid::Kernel::DblMatrix &matrix) {
+  std::size_t dim = matrix.Ssize() - 1;
+  Mantid::Kernel::DblMatrix temp(dim, dim);
+  for (std::size_t i = 0; i < dim; i++) {
+    for (std::size_t j = 0; j < dim; j++) {
+      temp[i][j] = matrix[i][j];
+    }
+  }
+  matrix = temp;
+}
+
+template <typename T>
+void doProvideSkewMatrix(Mantid::Kernel::DblMatrix &skewMatrix, T workspace) {
+  // The input workspace needs have
+  // 1. an HKL frame
+  // 2. an oriented lattice
+  // else we cannot create the skew matrix
+  const auto &sample = workspace->getExperimentInfo(0)->sample();
+  const auto &run = workspace->getExperimentInfo(0)->run();
+  auto specialCoordnateSystem = workspace->getSpecialCoordinateSystem();
+  checkForSampleAndRunEntries(sample, run, specialCoordnateSystem);
+
+  // Create Affine Matrix
+  Mantid::Kernel::Matrix<Mantid::coord_t> affineMatrix;
+  try {
+    auto const *transform = workspace->getTransformToOriginal();
+    affineMatrix = transform->makeAffineMatrix();
+  } catch (std::runtime_error &) {
+    // Create identity matrix of dimension+1
+    std::size_t nDims = workspace->getNumDims() + 1;
+    Mantid::Kernel::Matrix<Mantid::coord_t> temp(nDims, nDims, true);
+    affineMatrix = temp;
+  }
+
+  // Extract W Matrix
+  auto wMatrixAsArray =
+      run.template getPropertyValueAsType<std::vector<double>>("W_MATRIX");
+  Mantid::Kernel::DblMatrix wMatrix(wMatrixAsArray);
+
+  // Get the B Matrix from the oriented lattice
+  const auto &orientedLattice = sample.getOrientedLattice();
+  Mantid::Kernel::DblMatrix bMatrix = orientedLattice.getB();
+  bMatrix *= wMatrix;
+
+  // Get G* Matrix
+  Mantid::Kernel::DblMatrix gStarMatrix = bMatrix.Tprime() * bMatrix;
+
+  // Get recalculated BMatrix from Unit Cell
+  Mantid::Geometry::UnitCell unitCell(orientedLattice);
+  unitCell.recalculateFromGstar(gStarMatrix);
+  skewMatrix = unitCell.getB();
+
+  // Provide column normalisation of the skewMatrix
+  normalizeColumns(skewMatrix);
+
+  // Setup basis normalisation array
+  std::vector<double> basisNormalization = {orientedLattice.astar(),
+                                            orientedLattice.bstar(),
+                                            orientedLattice.cstar()};
+
+  // Expand matrix to 4 dimensions if necessary
+  if (4 == workspace->getNumDims()) {
+    basisNormalization.push_back(1.0);
+    Mantid::Kernel::DblMatrix temp(4, 4, true);
+    for (std::size_t i = 0; i < 3; i++) {
+      for (std::size_t j = 0; j < 3; j++) {
+        temp[i][j] = skewMatrix[i][j];
+      }
+    }
+    skewMatrix = temp;
+  }
+
+  // The affine matrix has a underlying type of coord_t(float) but
+  // we need a double
+
+  auto reducedDimension = affineMatrix.Ssize() - 1;
+  Mantid::Kernel::DblMatrix affMat(reducedDimension, reducedDimension);
+  for (std::size_t i = 0; i < reducedDimension; i++) {
+    for (std::size_t j = 0; j < reducedDimension; j++) {
+      affMat[i][j] = affineMatrix[i][j];
+    }
+  }
+
+  // Perform similarity transform to get coordinate orientation correct
+  skewMatrix = affMat.Tprime() * (skewMatrix * affMat);
+
+  if (4 == workspace->getNumDims()) {
+    stripMatrix(skewMatrix);
+  }
+  skewMatrix
+      .Invert(); // Current fix so skewed image displays in correct orientation
+}
+
+template <typename T> bool doRequiresSkewMatrix(T workspace) {
+  auto requiresSkew(true);
+  try {
+    const auto &sample = workspace->getExperimentInfo(0)->sample();
+    const auto &run = workspace->getExperimentInfo(0)->run();
+    auto specialCoordnateSystem = workspace->getSpecialCoordinateSystem();
+    checkForSampleAndRunEntries(sample, run, specialCoordnateSystem);
+  } catch (std::invalid_argument &) {
+    requiresSkew = false;
+  }
+
+  return requiresSkew;
+}
+
+template <size_t N>
+std::array<Mantid::coord_t, N>
+getTransformedArray(Mantid::coord_t skewMatrix[N * N], size_t dimension) {
+  std::array<Mantid::coord_t, N> vec = {{0., 0., 0.}};
+  for (size_t index = 0; index < N; ++index) {
+    vec[index] = skewMatrix[dimension + index * N];
+  }
+  return vec;
+}
+
+template <typename T, size_t N> void normalizeVector(std::array<T, N> &vector) {
+  auto sumOfSquares = [](T sum, T element) { return sum + element * element; };
+  auto norm = std::accumulate(vector.begin(), vector.end(), 0.f, sumOfSquares);
+  norm = std::sqrt(norm);
+  for (auto &element : vector) {
+    element /= norm;
+  }
+}
+/**
+* Gets the normal vector for two specified vectors
+*
+*/
+std::array<Mantid::coord_t, 3>
+    getNormalVector(std::array<Mantid::coord_t, 3> vector1,
+                    std::array<Mantid::coord_t, 3> vector2) {
+  std::array<Mantid::coord_t, 3> normalVector;
+  for (size_t index = 0; index < 3; ++index) {
+    normalVector[index] = vector1[(index + 1) % 3] * vector2[(index + 2) % 3] -
+                          vector1[(index + 2) % 3] * vector2[(index + 1) % 3];
+  }
+
+  // Make sure that the output is truely normalized
+  normalizeVector<Mantid::coord_t, 3>(normalVector);
+  return normalVector;
+}
+
+/**
+* The normal vector will depend on the chosen dimensions and the order of these
+*dimensions:
+* It is essentially the cross product of vect(dimX) x vect(dimY), e.g.
+* x-y -> z
+* y-x -> -z ...
+*
+*/
+std::array<Mantid::coord_t, 3> getNormalVector(size_t dimX, size_t dimY) {
+  std::array<Mantid::coord_t, 3> vector1 = {{0., 0., 0.}};
+  std::array<Mantid::coord_t, 3> vector2 = {{0., 0., 0.}};
+  vector1[dimX] = 1.0;
+  vector2[dimY] = 1.0;
+
+  std::array<Mantid::coord_t, 3> normalVector;
+  for (size_t index = 0; index < 3; ++index) {
+    normalVector[index] = vector1[(index + 1) % 3] * vector2[(index + 2) % 3] -
+                          vector1[(index + 2) % 3] * vector2[(index + 1) % 3];
+  }
+
+  // Make sure that the output is normalized
+  normalizeVector<Mantid::coord_t, 3>(normalVector);
+  return normalVector;
+}
+/**
+* Calculate the angle for a given dimension. Note that this function expects all
+* vectors to be normalized.
+*/
+template <size_t N>
+double getAngleInRadian(std::array<Mantid::coord_t, N> orthogonalVector,
+                        std::array<Mantid::coord_t, N> nonOrthogonalVector,
+                        const std::array<Mantid::coord_t, N> &normalVector,
+                        size_t currentDimension, size_t otherDimension) {
+  // We want to get the angle between an orthogonal basis vector eX, eY, eZ and
+  // the corresponding
+  // nonorthogonal basis vector H, K, L
+  // There are several special cases to consider.
+  // 1. When the currentDimension or otherDimension is x, then the angle is 0
+  // since x and H are aligned
+  // 2. When currentDimension is y and otherDimension is z,
+  //    then the angle betwee K and eY  is set to 0. This is a slight
+  //    oddity since  y-z and K are not in a plane. Mathematically, there is of
+  //    course a potentially non-zero
+  //    angle between K and eY, but this is not relevant for our 2D display.
+  // 3. When dimX/Y is z, then L needs to be projected onto either the x-z or
+  // the y-z plane (denpending
+  //    on the current selection). The angle is calculatd between the projection
+  //    and the eZ axis.
+
+  double angle(0.);
+  if (currentDimension == 0) {
+    // Handle case 1.
+    return 0.;
+  } else if (currentDimension == 1 && otherDimension == 2) {
+    // Handle case 2.
+    return 0.;
+  } else if (currentDimension == 2) {
+    // Handle case 3.
+    normalizeVector<Mantid::coord_t, N>(orthogonalVector);
+    normalizeVector<Mantid::coord_t, N>(nonOrthogonalVector);
+
+    // projecting onto third dimension by setting dimension coming out of screen
+    // to zero
+    std::array<Mantid::coord_t, 3> temporaryNonOrthogonal{{0.f, 0.f, 0.f}};
+    temporaryNonOrthogonal[currentDimension] =
+        nonOrthogonalVector[currentDimension];
+    temporaryNonOrthogonal[otherDimension] =
+        nonOrthogonalVector[otherDimension];
+    nonOrthogonalVector = temporaryNonOrthogonal;
+  }
+
+  normalizeVector<Mantid::coord_t, N>(orthogonalVector);
+  normalizeVector<Mantid::coord_t, N>(nonOrthogonalVector);
+  // Get the value of the angle from the dot product: v1*v2 = cos (a)*|v1|*|v2|
+  auto dotProduct =
+      std::inner_product(orthogonalVector.begin(), orthogonalVector.end(),
+                         nonOrthogonalVector.begin(), 0.f);
+
+  // Handle case where the dotProduct is 1 or -
+  if (dotProduct == 1.) {
+    angle = 0.;
+
+  } else if (dotProduct == -1.) {
+    angle = static_cast<double>(M_PI);
+
+  } else {
+    angle = std::acos(dotProduct);
+  }
+  // Get the direction of the angle
+  auto normalForDirection =
+      getNormalVector(orthogonalVector, nonOrthogonalVector);
+  auto direction =
+      std::inner_product(normalForDirection.begin(), normalForDirection.end(),
+                         normalVector.begin(), 0.f);
+
+  if (direction < 0) {
+    angle *= -1.f;
+  }
+  return angle;
+}
+}
+
+namespace MantidQt {
+namespace API {
+
+size_t
+getMissingHKLDimensionIndex(Mantid::API::IMDWorkspace_const_sptr workspace,
+                            size_t dimX, size_t dimY) {
+  for (size_t i = 0; i < workspace->getNumDims(); ++i) {
+    auto dimension = workspace->getDimension(i);
+    const auto &frame = dimension->getMDFrame();
+    if ((frame.name() == Mantid::Geometry::HKL::HKLName) && (i != dimX) &&
+        (i != dimY)) {
+      return i;
+    }
+  }
+  return static_cast<size_t>(NULL);
+}
+
+void provideSkewMatrix(Mantid::Kernel::DblMatrix &skewMatrix,
+                       Mantid::API::IMDWorkspace_const_sptr workspace) {
+  if (Mantid::API::IMDEventWorkspace_const_sptr eventWorkspace =
+          boost::dynamic_pointer_cast<const Mantid::API::IMDEventWorkspace>(
+              workspace)) {
+    doProvideSkewMatrix(skewMatrix, eventWorkspace);
+  } else if (Mantid::API::IMDHistoWorkspace_const_sptr histoWorkspace =
+                 boost::dynamic_pointer_cast<
+                     const Mantid::API::IMDHistoWorkspace>(workspace)) {
+    doProvideSkewMatrix(skewMatrix, histoWorkspace);
+  } else {
+    throw std::invalid_argument("NonOrthogonal: The provided workspace "
+                                "must either be an IMDEvent or IMDHisto "
+                                "workspace.");
+  }
+}
+
+bool requiresSkewMatrix(Mantid::API::IMDWorkspace_const_sptr workspace) {
+
+  auto requiresSkewMatrix(false);
+  if (Mantid::API::IMDEventWorkspace_const_sptr eventWorkspace =
+          boost::dynamic_pointer_cast<const Mantid::API::IMDEventWorkspace>(
+              workspace)) {
+    requiresSkewMatrix = doRequiresSkewMatrix(eventWorkspace);
+  } else if (Mantid::API::IMDHistoWorkspace_const_sptr histoWorkspace =
+                 boost::dynamic_pointer_cast<
+                     const Mantid::API::IMDHistoWorkspace>(workspace)) {
+    requiresSkewMatrix = doRequiresSkewMatrix(histoWorkspace);
+  }
+  return requiresSkewMatrix;
+}
+bool isHKLDimensions(Mantid::API::IMDWorkspace_const_sptr workspace,
+                     size_t dimX, size_t dimY) {
+  auto dimensionHKL = true;
+  size_t dimensionIndices[2] = {dimX, dimY};
+  for (const auto &dimensionIndex : dimensionIndices) {
+    auto dimension = workspace->getDimension(dimensionIndex);
+    const auto &frame = dimension->getMDFrame();
+    if (frame.name() != Mantid::Geometry::HKL::HKLName) {
+      dimensionHKL = false;
+    }
+  }
+  return dimensionHKL;
+}
+
+void transformFromDoubleToCoordT(Mantid::Kernel::DblMatrix &skewMatrix,
+                                 Mantid::coord_t skewMatrixCoord[9]) {
+  std::size_t index = 0;
+  for (std::size_t i = 0; i < skewMatrix.numRows(); ++i) {
+    for (std::size_t j = 0; j < skewMatrix.numCols(); ++j) {
+      skewMatrixCoord[index] = static_cast<Mantid::coord_t>(skewMatrix[i][j]);
+      ++index;
+    }
+  }
+}
+/**
+Explanation of index mapping
+lookPoint[0] is H
+lookPoint[1] is K
+lookPoint[2] is L
+eg
+Have matrix (from xyz -> hkl) and X, K, Z
+H = M11 . X + M12Y + M13Z
+K = M24X + M22Y + M23Z
+L = M31X + M32Y + M33Z
+
+*/
+void transformLookpointToWorkspaceCoord(Mantid::coord_t *lookPoint,
+                                        const Mantid::coord_t skewMatrix[9],
+                                        const size_t &dimX, const size_t &dimY,
+                                        const size_t &dimSlice) {
+
+  auto sliceDimResult =
+      (lookPoint[dimSlice] - skewMatrix[3 * dimSlice + dimX] * lookPoint[dimX] -
+       skewMatrix[3 * dimSlice + dimY] * lookPoint[dimY]) /
+      skewMatrix[3 * dimSlice + dimSlice];
+
+  auto OrigDimSliceValue = lookPoint[dimSlice];
+  lookPoint[dimSlice] = sliceDimResult;
+
+  auto v1 = lookPoint[0];
+  auto v2 = lookPoint[1];
+  auto v3 = lookPoint[2];
+
+  lookPoint[dimX] = v1 * skewMatrix[0 + 3 * dimX] +
+                    v2 * skewMatrix[1 + 3 * dimX] +
+                    v3 * skewMatrix[2 + 3 * dimX];
+  lookPoint[dimY] = v1 * skewMatrix[0 + 3 * dimY] +
+                    v2 * skewMatrix[1 + 3 * dimY] +
+                    v3 * skewMatrix[2 + 3 * dimY];
+
+  lookPoint[dimSlice] = OrigDimSliceValue;
+}
+
+/**
+* We get the angles that are used for plotting of the grid lines. There are
+*several scenarios:
+* x-y (when H and K are selected)
+* y-x (when K and H are selected)
+* x-z (when H and L are selected)
+* z-x (when L and H are selected)
+* y-z (when K and L are selected)
+* z-y (when L and K are selected)
+*
+* Some things to consider the BW transformation provides a system where x is
+*aligned with a*,
+* where y is in the same plane as
+*
+*
+* @param skewMatrixCoord The tranformation matrix from the non-orthogonal system
+*to the orthogonal system
+* @param dimX the selected orthogonal dimension for the x axis of the screen
+* @param dimY the selected orthogonal dimension for the y axis of the screen
+* @return an angle for the x grid lines and an angle for the y grid lines. Both
+*are measured from the x axis.
+*/
+std::pair<double, double>
+getGridLineAnglesInRadian(Mantid::coord_t skewMatrixCoord[9], size_t dimX,
+                          size_t dimY) {
+  // Get the two vectors for the selected dimensions in the orthogonal axis
+  // representation.
+
+  std::array<Mantid::coord_t, 3> dimXOriginal = {{0., 0., 0.}};
+  std::array<Mantid::coord_t, 3> dimYOriginal = {{0., 0., 0.}};
+  dimXOriginal[dimX] = 1.0;
+  dimYOriginal[dimY] = 1.0;
+  auto dimXTransformed = getTransformedArray<3>(skewMatrixCoord, dimX);
+  auto dimYTransformed = getTransformedArray<3>(skewMatrixCoord, dimY);
+
+  // Get the normal vector for the selected dimensions
+  auto normalVector = getNormalVector(dimX, dimY);
+
+  // Get the angle for dimX and dimY
+  auto angleDimX =
+      getAngleInRadian(dimXOriginal, dimXTransformed, normalVector, dimX, dimY);
+  auto angleDimY =
+      getAngleInRadian(dimYOriginal, dimYTransformed, normalVector, dimY, dimX);
+  return std::make_pair(angleDimX, angleDimY);
+}
+}
+}
diff --git a/MantidQt/API/src/PlotAxis.cpp b/MantidQt/API/src/PlotAxis.cpp
index a0a4989db8b221c856283b5130e02d099487b42e..5e3e3a9200a037d9531193a768f0aeafb2becb66 100644
--- a/MantidQt/API/src/PlotAxis.cpp
+++ b/MantidQt/API/src/PlotAxis.cpp
@@ -4,6 +4,8 @@
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidKernel/Unit.h"
 
+#include <boost/lexical_cast.hpp>
+
 namespace MantidQt {
 namespace API {
 
diff --git a/MantidQt/API/src/PropertyWidget.cpp b/MantidQt/API/src/PropertyWidget.cpp
index d8d1beb69364acb1d379828772c42a99920fc554..d107b81aebe7a7e137a547d16153c232c972dfe1 100644
--- a/MantidQt/API/src/PropertyWidget.cpp
+++ b/MantidQt/API/src/PropertyWidget.cpp
@@ -11,6 +11,7 @@
 #include <cfloat>
 
 #include <algorithm>
+#include <sstream>
 
 #include <QLineEdit>
 
diff --git a/MantidQt/API/src/QwtRasterDataMDNonOrthogonal.cpp b/MantidQt/API/src/QwtRasterDataMDNonOrthogonal.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..49df28477ba1f1ca0d5182573011289cead2671b
--- /dev/null
+++ b/MantidQt/API/src/QwtRasterDataMDNonOrthogonal.cpp
@@ -0,0 +1,151 @@
+#include "MantidQtAPI/QwtRasterDataMDNonOrthogonal.h"
+#include "MantidQtAPI/NonOrthogonal.h"
+
+namespace MantidQt {
+namespace API {
+
+using namespace Mantid;
+using namespace Mantid::API;
+
+QwtRasterDataMDNonOrthogonal::QwtRasterDataMDNonOrthogonal()
+    : m_lookPoint(nullptr) {
+  m_fromHklToXyz[0] = 1.0;
+  m_fromHklToXyz[1] = 0.0;
+  m_fromHklToXyz[2] = 0.0;
+  m_fromHklToXyz[3] = 0.0;
+  m_fromHklToXyz[4] = 1.0;
+  m_fromHklToXyz[5] = 0.0;
+  m_fromHklToXyz[6] = 0.0;
+  m_fromHklToXyz[7] = 0.0;
+  m_fromHklToXyz[8] = 1.0;
+  m_missingHKLdim = 0;
+}
+
+QwtRasterDataMDNonOrthogonal::~QwtRasterDataMDNonOrthogonal() {
+  delete[] m_lookPoint;
+}
+
+//-------------------------------------------------------------------------
+/** Return the data value to plot at the given position
+*
+* @param x :: position in coordinates of the MDWorkspace
+* @param y :: position in coordinates of the MDWorkspace
+* @return signal to plot
+*/
+double QwtRasterDataMDNonOrthogonal::value(double x, double y) const {
+  if (!m_ws)
+    return 0;
+
+  // Generate the vector of coordinates, filling in X and Y
+  for (size_t d = 0; d < m_nd;
+       d++) { // m_nd is number dimensions in the workplace
+    if (d == m_dimX)
+      m_lookPoint[d] = static_cast<coord_t>(x);
+    else if (d == m_dimY)
+      m_lookPoint[d] = static_cast<coord_t>(y);
+    else {
+      m_lookPoint[d] = m_slicePoint[d];
+    }
+  }
+
+  // Transform the lookpoint to the coordinate of the workspace
+  transformLookpointToWorkspaceCoord(m_lookPoint, m_fromHklToXyz, m_dimX,
+                                     m_dimY, m_missingHKLdim);
+  // Get the signal at that point
+  signal_t value = 0;
+
+  // Check if the overlay WS is within range of being viewed
+  if (m_overlayWS && m_overlayInSlice && (x >= m_overlayXMin) &&
+      (x < m_overlayXMax) && (y >= m_overlayYMin) && (y < m_overlayYMax)) {
+    // Point is in the overlaid workspace
+    value = m_overlayWS->getSignalWithMaskAtCoord(m_lookPoint, m_normalization);
+  } else {
+    // No overlay, or not within range of that workspace
+    value = m_ws->getSignalWithMaskAtCoord(m_lookPoint, m_normalization);
+  }
+
+  // Special case for 0 = show as NAN
+  if (m_zerosAsNan && value == 0.)
+    return nan;
+
+  return value;
+}
+
+//------------------------------------------------------------------------------------------------------
+/** Sets the workspace being displayed
+*
+* @param ws :: IMDWorkspace to show
+*/
+void QwtRasterDataMDNonOrthogonal::setWorkspace(IMDWorkspace_const_sptr ws) {
+  QwtRasterDataMD::setWorkspace(ws);
+  // Create a lookpoint
+  if (m_lookPoint) {
+    delete[] m_lookPoint;
+  }
+  m_lookPoint = new coord_t[m_nd];
+  // Add the skewMatrix for the basis
+  Mantid::Kernel::DblMatrix skewMatrix(m_nd, m_nd, true);
+  provideSkewMatrix(skewMatrix, ws);
+  transformFromDoubleToCoordT(skewMatrix, m_fromHklToXyz);
+}
+
+void QwtRasterDataMDNonOrthogonal::setSliceParams(
+    size_t dimX, size_t dimY, Mantid::Geometry::IMDDimension_const_sptr X,
+    Mantid::Geometry::IMDDimension_const_sptr Y,
+    std::vector<Mantid::coord_t> &slicePoint) {
+  QwtRasterDataMD::setSliceParams(dimX, dimY, X, Y, slicePoint);
+  // find missing HKL
+  m_missingHKLdim = API::getMissingHKLDimensionIndex(m_ws, dimX, dimY);
+}
+
+//-------------------------------------------------------------------------
+/** Perform a copy of this data object */
+QwtRasterDataMDNonOrthogonal *QwtRasterDataMDNonOrthogonal::copy() const {
+  QwtRasterDataMDNonOrthogonal *out = new QwtRasterDataMDNonOrthogonal();
+  this->copyFrom(*this, *out);
+  return out;
+}
+
+/**
+* Copy settings from one object to another
+* @param source A source object to copy from
+* @param dest The destination object that receives the contents
+*/
+void QwtRasterDataMDNonOrthogonal::copyFrom(
+    const QwtRasterDataMDNonOrthogonal &source,
+    QwtRasterDataMDNonOrthogonal &dest) const {
+  // base bounding box
+  dest.setBoundingRect(source.boundingRect());
+
+  dest.m_ws = source.m_ws;
+  dest.m_dimX = source.m_dimX;
+  dest.m_dimY = source.m_dimY;
+  dest.m_nd = source.m_nd;
+  dest.m_range = source.m_range;
+  dest.m_slicePoint = new coord_t[m_nd];
+  for (size_t d = 0; d < m_nd; d++)
+    dest.m_slicePoint[d] = source.m_slicePoint[d];
+  dest.m_ws = source.m_ws;
+  dest.m_fast = source.m_fast;
+  dest.m_zerosAsNan = source.m_zerosAsNan;
+  dest.m_normalization = source.m_normalization;
+
+  dest.m_overlayWS = source.m_overlayWS;
+  dest.m_overlayXMin = source.m_overlayXMin;
+  dest.m_overlayXMax = source.m_overlayXMax;
+  dest.m_overlayYMin = source.m_overlayYMin;
+  dest.m_overlayYMax = source.m_overlayYMax;
+  dest.m_overlayInSlice = source.m_overlayInSlice;
+  dest.m_missingHKLdim = source.m_missingHKLdim;
+  dest.m_lookPoint = new coord_t[m_nd];
+  for (size_t d = 0; d < m_nd; ++d) {
+    dest.m_lookPoint[d] = source.m_lookPoint[d];
+  }
+
+  for (size_t d = 0; d < 9; ++d) {
+    dest.m_fromHklToXyz[d] = source.m_fromHklToXyz[d];
+  }
+}
+
+} // namespace
+} // namespace
diff --git a/MantidQt/API/src/QwtWorkspaceBinData.cpp b/MantidQt/API/src/QwtWorkspaceBinData.cpp
index 37e9454000f0557cbe4283efdcd90a9ea2f5d786..1408a915bf058796e1eab73bbab25a4042fc90eb 100644
--- a/MantidQt/API/src/QwtWorkspaceBinData.cpp
+++ b/MantidQt/API/src/QwtWorkspaceBinData.cpp
@@ -5,6 +5,7 @@
 #include "MantidQtAPI/PlotAxis.h"
 
 #include <QStringBuilder>
+#include <sstream>
 
 /// Constructor
 QwtWorkspaceBinData::QwtWorkspaceBinData(
@@ -121,4 +122,4 @@ void QwtWorkspaceBinData::init(const Mantid::API::MatrixWorkspace &workspace) {
 
   // Calculate the min and max values
   calculateYMinAndMax();
-}
\ No newline at end of file
+}
diff --git a/MantidQt/API/src/UserSubWindow.cpp b/MantidQt/API/src/UserSubWindow.cpp
index 33b432775f22cba222e244e8103e813d19cc006f..13eb293f1d2edcbef273dfd101c55a535704ec3a 100644
--- a/MantidQt/API/src/UserSubWindow.cpp
+++ b/MantidQt/API/src/UserSubWindow.cpp
@@ -2,7 +2,6 @@
 // Includes
 //----------------------------------
 #include "MantidQtAPI/AlgorithmInputHistory.h"
-#include "MantidQtAPI/FileDialogHandler.h"
 #include "MantidQtAPI/UserSubWindow.h"
 #include "MantidKernel/UsageService.h"
 
@@ -129,7 +128,7 @@ QString UserSubWindow::openFileDialog(const bool save,
 
   QString filename;
   if (save) {
-    filename = MantidQt::API::FileDialogHandler::getSaveFileName(
+    filename = QFileDialog::getSaveFileName(
         this, "Save file",
         AlgorithmInputHistory::Instance().getPreviousDirectory(), filter);
   } else {
diff --git a/MantidQt/API/src/VatesViewerInterface.cpp b/MantidQt/API/src/VatesViewerInterface.cpp
index e4f07009c47d62f250650714b113b303d71b46e1..02ead09c5a0df0910fdf3b4c466ecb2e078319bf 100644
--- a/MantidQt/API/src/VatesViewerInterface.cpp
+++ b/MantidQt/API/src/VatesViewerInterface.cpp
@@ -9,7 +9,8 @@ VatesViewerInterface::VatesViewerInterface(QWidget *parent) : QWidget(parent) {}
 
 VatesViewerInterface::~VatesViewerInterface() {}
 
-void VatesViewerInterface::setupPluginMode() {}
+void VatesViewerInterface::setupPluginMode(
+    int /*WsType*/, const std::string & /*instrumentName*/) {}
 
 void VatesViewerInterface::renderWorkspace(QString workSpaceName,
                                            int workspaceType,
diff --git a/MantidQt/API/src/WindowIcons.cpp b/MantidQt/API/src/WindowIcons.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8c71c9751af8788928cebc49a07a1954f163e9cd
--- /dev/null
+++ b/MantidQt/API/src/WindowIcons.cpp
@@ -0,0 +1,81 @@
+//-----------------------------------------------------------------------------
+// Includes
+//-----------------------------------------------------------------------------
+#include "MantidQtAPI/WindowIcons.h"
+#include "MantidQtAPI/pixmaps.h"
+
+namespace MantidQt {
+namespace API {
+
+//-----------------------------------------------------------------------------
+// Public member functions
+//-----------------------------------------------------------------------------
+/**
+ * Default constructor
+ */
+WindowIcons::WindowIcons() : m_idToPixmapName() { initInternalLookup(); }
+
+/**
+ * @param windowID A string giving the ID for a window
+ * @throws std::runtime_error if no icon can be found
+ */
+QIcon WindowIcons::getIcon(const std::string &windowID) const {
+  auto value = m_idToPixmapName.value(windowID);
+  if (QString::fromStdString(value).endsWith(".png")) {
+    return makeIconFromFile(value);
+  } else {
+    return getQPixmap(value);
+  }
+}
+
+/**
+ * Get the string ID representing the icon
+ * @param windowID :: a string representing the ID of the window
+ * @return a string with the QPixmap id for this window.
+ */
+std::string WindowIcons::getIconID(const std::string &windowID) const {
+  if (m_idToPixmapName.contains(windowID))
+    return m_idToPixmapName.value(windowID);
+  else
+    return "";
+}
+
+//-----------------------------------------------------------------------------
+// Private member functions
+//-----------------------------------------------------------------------------
+
+/**
+ * Initilise the internal lookup map
+ */
+void WindowIcons::initInternalLookup() {
+  m_idToPixmapName.clear();
+  m_idToPixmapName["Matrix"] = "matrix_xpm";
+  m_idToPixmapName["MantidMatrix"] = "mantid_matrix_xpm";
+  m_idToPixmapName["Table"] = "worksheet_xpm";
+  m_idToPixmapName["Note"] = "note_xpm";
+  m_idToPixmapName["MultiLayer"] = "graph_xpm";
+  m_idToPixmapName["Graph3D"] = "trajectory_xpm";
+  m_idToPixmapName["Workspace"] = "mantid_matrix_xpm";
+  m_idToPixmapName["SliceViewer"] =
+      ":/SliceViewer/icons/SliceViewerWindow_icon.png";
+  m_idToPixmapName["VSIWindow"] =
+      ":/VatesSimpleGuiViewWidgets/icons/pvIcon.png";
+}
+
+/**
+ * Make a QIcon object froma file path
+ *
+ * This is used in the case that a pixmap does not exist and a file path to an
+ * image was provided instead.
+ *
+ * @param path :: path to the image to use to create the icon
+ * @return icon object made from the path
+ */
+QIcon WindowIcons::makeIconFromFile(const std::string &path) const {
+  QIcon icon;
+  icon.addFile(QString::fromStdString(path), QSize(), QIcon::Normal,
+               QIcon::Off);
+  return icon;
+}
+}
+}
diff --git a/MantidQt/API/src/WorkspaceIcons.cpp b/MantidQt/API/src/WorkspaceIcons.cpp
index ebc388cf8f0c1d2f4f2898b3bbd590e38c9523a5..6f72d3f5077c9841d2e979ab9e0721ae95ece7bf 100644
--- a/MantidQt/API/src/WorkspaceIcons.cpp
+++ b/MantidQt/API/src/WorkspaceIcons.cpp
@@ -27,6 +27,18 @@ QPixmap WorkspaceIcons::getIcon(const std::string &workspaceID) const {
     return getQPixmap(m_idToPixmapName.value(workspaceID));
 }
 
+/**
+ * Get the string ID representing the icon
+ * @param workspaceID :: a string representing the ID of the workspace
+ * @return a string with the QPixmap id for this workspace.
+ */
+std::string WorkspaceIcons::getIconID(const std::string &workspaceID) const {
+  if (workspaceID.compare(0, 16, "MDEventWorkspace") == 0)
+    return m_idToPixmapName.value("MDEventWorkspace");
+  else
+    return m_idToPixmapName.value(workspaceID);
+}
+
 //-----------------------------------------------------------------------------
 // Private member functions
 //-----------------------------------------------------------------------------
diff --git a/MantidQt/API/test/BatchAlgorithmRunnerTest.h b/MantidQt/API/test/BatchAlgorithmRunnerTest.h
index 9cf971a861c70378b834ac85b11d3ffe23ccc9b8..4ef631fb1868c0530d04ae162121719cefdfe6da 100644
--- a/MantidQt/API/test/BatchAlgorithmRunnerTest.h
+++ b/MantidQt/API/test/BatchAlgorithmRunnerTest.h
@@ -4,8 +4,10 @@
 #include <cxxtest/TestSuite.h>
 
 #include "MantidAPI/AlgorithmManager.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/FrameworkManager.h"
 #include "MantidAPI/MatrixWorkspace.h"
+#include "MantidAPI/WorkspaceHistory.h"
 #include "MantidQtAPI/BatchAlgorithmRunner.h"
 
 using namespace Mantid::API;
diff --git a/MantidQt/API/test/CMakeLists.txt b/MantidQt/API/test/CMakeLists.txt
index 2107f499a80dd81a7329d4a7288f1a7a6ff7b754..8651bceb6e368e56ace46ec0bb2b5ccb661148f2 100644
--- a/MantidQt/API/test/CMakeLists.txt
+++ b/MantidQt/API/test/CMakeLists.txt
@@ -2,8 +2,8 @@ if ( CXXTEST_FOUND )
     include_directories ( SYSTEM ${CXXTEST_INCLUDE_DIR} ${GMOCK_INCLUDE_DIR} ${GTEST_INCLUDE_DIR} )
 
     include_directories ( ../../../Framework/TestHelpers/inc
-                          ../../../Framework/DataObjects/inc )
-    
+                          ../../../Framework/DataObjects/inc 
+						  ../../../Framework/Crystal/inc)
     # This variable is used within the cxxtest_add_test macro to build these helper classes into the test executable.
     # It will go out of scope at the end of this file so doesn't need un-setting
     set ( TESTHELPER_SRCS ../../../Framework/TestHelpers/src/TearDownWorld.cpp
@@ -11,10 +11,11 @@ if ( CXXTEST_FOUND )
                           ../../../Framework/TestHelpers/src/InstrumentCreationHelper.cpp
                           ../../../Framework/TestHelpers/src/WorkspaceCreationHelper.cpp
         )
-    
+
     cxxtest_add_test ( MantidQtAPITest ${TEST_FILES} )
-    target_link_libraries( MantidQtAPITest LINK_PRIVATE ${TCMALLOC_LIBRARIES_LINKTIME} 
+    target_link_libraries( MantidQtAPITest LINK_PRIVATE ${TCMALLOC_LIBRARIES_LINKTIME}
             MantidQtAPI
+            Crystal
             API
             DataObjects
             Geometry
@@ -27,7 +28,11 @@ if ( CXXTEST_FOUND )
             ${GMOCK_LIBRARIES}
             ${GTEST_LIBRARIES} )
     add_dependencies( GUITests MantidQtAPITest )
-    
+
     # Add to the 'UnitTests' group in VS
     set_property( TARGET MantidQtAPITest PROPERTY FOLDER "UnitTests" )
 endif ()
+
+if ( PYUNITTEST_FOUND )
+  pyunittest_add_test (${CMAKE_CURRENT_SOURCE_DIR} MantidQtAPITest ${TEST_PY_FILES} )
+endif ()
diff --git a/MantidQt/API/test/FileDialogHandlerTest.h b/MantidQt/API/test/FileDialogHandlerTest.h
new file mode 100644
index 0000000000000000000000000000000000000000..b73532723f792817ea44594532f5c5cffb925694
--- /dev/null
+++ b/MantidQt/API/test/FileDialogHandlerTest.h
@@ -0,0 +1,66 @@
+#ifndef MANTIDQT_API_FILEDIALOGHANDLERTEST_H_
+#define MANTIDQT_API_FILEDIALOGHANDLERTEST_H_
+
+#include "MantidQtAPI/FileDialogHandler.h"
+#include <cxxtest/TestSuite.h>
+
+class FileDialogHandlerTest : public CxxTest::TestSuite {
+public:
+  void test_addExtension() {
+    // --- single extensions
+    const QString singleExt(".nxs (*.nxs)");
+    const QString nexusResult("/tmp/testing.nxs");
+
+    auto result1 = MantidQt::API::FileDialogHandler::addExtension(
+        QString::fromStdString("/tmp/testing"), singleExt);
+    TS_ASSERT_EQUALS(nexusResult.toStdString(), result1.toStdString());
+
+    auto result2 = MantidQt::API::FileDialogHandler::addExtension(
+        QString::fromStdString("/tmp/testing."), singleExt);
+    TS_ASSERT_EQUALS(nexusResult.toStdString(), result2.toStdString());
+
+    auto result3 =
+        MantidQt::API::FileDialogHandler::addExtension(nexusResult, singleExt);
+    TS_ASSERT_EQUALS(nexusResult.toStdString(), result3.toStdString());
+
+    // don't override if it is already specified
+    const QString singleH5("/tmp/testing.h5");
+    auto result4 =
+        MantidQt::API::FileDialogHandler::addExtension(singleH5, singleExt);
+    TS_ASSERT_EQUALS(singleH5.toStdString(), result4.toStdString());
+
+    // --- double extensions
+    const QString doubleExt("JPEG (*.jpg *.jpeg)");
+    const QString jpegResult("/tmp/testing.jpg");
+
+    // this can't work because you can't determine one extension
+    TS_ASSERT_THROWS(MantidQt::API::FileDialogHandler::addExtension(
+                         QString::fromStdString("/tmp/testing"), doubleExt),
+                     std::runtime_error);
+
+    // this shouldn't do anything
+    auto result5 =
+        MantidQt::API::FileDialogHandler::addExtension(jpegResult, doubleExt);
+    TS_ASSERT_EQUALS(jpegResult.toStdString(), result5.toStdString());
+  }
+
+  void test_getFileDialogFilter() {
+    std::vector<std::string> exts({"*.h5", "*.nxs"});
+
+    const auto result1 = MantidQt::API::FileDialogHandler::getFilter(
+        std::vector<std::string>(), std::string(""));
+    TS_ASSERT_EQUALS(std::string("All Files (*)"), result1.toStdString());
+
+    const auto result2 =
+        MantidQt::API::FileDialogHandler::getFilter(exts, std::string(""));
+    TS_ASSERT_EQUALS(std::string("*.h5 (**.h5);;*.nxs (**.nxs);;All Files (*)"),
+                     result2.toStdString());
+
+    const auto result3 =
+        MantidQt::API::FileDialogHandler::getFilter(exts, std::string("*.nxs"));
+    TS_ASSERT_EQUALS(std::string("*.nxs (**.nxs);;*.h5 (**.h5);;All Files (*)"),
+                     result3.toStdString());
+  }
+};
+
+#endif /* MANTIDQT_API_FILEDIALOGHANDLERTEST_H_ */
diff --git a/MantidQt/MantidWidgets/test/MWRunFilesTest.py b/MantidQt/API/test/MWRunFilesTest.py
similarity index 89%
rename from MantidQt/MantidWidgets/test/MWRunFilesTest.py
rename to MantidQt/API/test/MWRunFilesTest.py
index fecd8cdfee82603b6a02c3ab39999cccb6fada8c..78e2ca1f00344dc423568c00626e35b9f6569f11 100644
--- a/MantidQt/MantidWidgets/test/MWRunFilesTest.py
+++ b/MantidQt/API/test/MWRunFilesTest.py
@@ -14,7 +14,7 @@ class MWRunFilesTest(unittest.TestCase):
     python interpreter"""
 
     def setUp(self):
-        self.mwrunfiles = mantidqtpython.MantidQt.MantidWidgets.MWRunFiles()
+        self.mwrunfiles = mantidqtpython.MantidQt.API.MWRunFiles()
 
     def tearDown(self):
         """ Close the created widget """
@@ -28,7 +28,7 @@ class MWRunFilesTest(unittest.TestCase):
         app.exec_()
 
     def test_creation(self):
-        self.assertTrue(isinstance(self.mwrunfiles,mantidqtpython.MantidQt.MantidWidgets.MWRunFiles), "Created object is not an instance of MWRunFiles")
+        self.assertTrue(isinstance(self.mwrunfiles,mantidqtpython.MantidQt.API.MWRunFiles), "Created object is not an instance of MWRunFiles")
 
     def test_lineedit_text(self):
         self.assertEqual(len(self.mwrunfiles.text()), 0)
diff --git a/MantidQt/API/test/NonOrthogonalTest.h b/MantidQt/API/test/NonOrthogonalTest.h
new file mode 100644
index 0000000000000000000000000000000000000000..fde653e4539473a2f9d4271126cfb7b56824d978
--- /dev/null
+++ b/MantidQt/API/test/NonOrthogonalTest.h
@@ -0,0 +1,347 @@
+#ifndef MANTIDQT_API_NONORTHOGONALTEST_H_
+#define MANTIDQT_API_NONORTHOGONALTEST_H_
+
+#include <cxxtest/TestSuite.h>
+#include "MantidQtAPI/NonOrthogonal.h"
+#include "MantidAPI/FrameworkManager.h"
+#include "MantidAPI/IMDEventWorkspace.h"
+#include "MantidKernel/MDUnitFactory.h"
+#include "MantidGeometry/MDGeometry/HKL.h"
+#include "MantidTestHelpers/MDEventsTestHelper.h"
+#include "MantidKernel/Unit.h"
+#include "MantidKernel/UnitLabelTypes.h"
+#include "MantidGeometry/MDGeometry/QSample.h"
+#include "MantidDataObjects/CoordTransformAffine.h"
+#include "MantidTestHelpers/MDEventsTestHelper.h"
+#include "MantidAPI/FrameworkManager.h"
+#include "MantidKernel/PropertyWithValue.h"
+#include "MantidAPI/AlgorithmManager.h"
+#include "MantidAPI/ExperimentInfo.h"
+#include "MantidAPI/Run.h"
+#include "MantidKernel/Matrix.h"
+#include "MantidKernel/MDUnit.h"
+#include "MantidCrystal/SetUB.h"
+#include "MantidTestHelpers/WorkspaceCreationHelper.h"
+
+class NonOrthogonalTest : public CxxTest::TestSuite {
+private:
+  Mantid::API::IMDEventWorkspace_sptr getOrthogonalHKLEventWorkspace() {
+    Mantid::Kernel::ReciprocalLatticeUnitFactory factory;
+    auto product = factory.create(Mantid::Kernel::Units::Symbol::RLU);
+    Mantid::Geometry::HKL frame(product);
+    auto workspace =
+        Mantid::DataObjects::MDEventsTestHelper::makeMDEWWithFrames<3>(
+            5, -10, 10, frame);
+    return workspace;
+  }
+
+  Mantid::DataObjects::EventWorkspace_sptr getOrthogonalEventWorkspace() {
+    Mantid::DataObjects::EventWorkspace_sptr ws =
+        WorkspaceCreationHelper::createEventWorkspace();
+    return ws;
+  }
+  size_t m_dimX = 0;
+  size_t m_dimY = 1;
+  size_t m_sliceDim = 2;
+
+  Mantid::API::IMDEventWorkspace_sptr getNonOrthogonalEventWorkspace(
+      bool wrongCoords = false, bool forgetUB = false, bool forgetWmat = false,
+      bool forgetAffmat = false, double scale = 1.0) {
+    Mantid::API::IMDEventWorkspace_sptr ws;
+    std::string wsName = "simpleWS";
+    if (wrongCoords) {
+      Mantid::Geometry::QSample frame;
+      ws = Mantid::DataObjects::MDEventsTestHelper::makeAnyMDEWWithFrames<
+          Mantid::DataObjects::MDEvent<4>, 4>(1, 0.0, 1.0, frame, 1, wsName);
+    } else {
+      Mantid::Kernel::ReciprocalLatticeUnitFactory factory;
+      auto product = factory.create(Mantid::Kernel::Units::Symbol::RLU);
+      Mantid::Geometry::HKL frame(product);
+      ws = Mantid::DataObjects::MDEventsTestHelper::makeAnyMDEWWithFrames<
+          Mantid::DataObjects::MDEvent<4>, 4>(1, 0.0, 1.0, frame, 1, wsName);
+    }
+    if (!forgetUB) {
+      // add UB Matrix
+      Mantid::API::IAlgorithm_sptr alg =
+          Mantid::API::AlgorithmManager::Instance().create("SetUB");
+      alg->initialize();
+      alg->setRethrows(true);
+      alg->setProperty("Workspace", wsName);
+      alg->setProperty("a", 3.643 * scale);
+      alg->setProperty("b", 3.643);
+      alg->setProperty("c", 5.781);
+      alg->setProperty("alpha", 90.0);
+      alg->setProperty("beta", 90.0);
+      alg->setProperty("gamma", 120.0);
+      std::vector<double> uVec;
+      uVec.push_back(1 * scale);
+      uVec.push_back(1);
+      uVec.push_back(0);
+      std::vector<double> vVec;
+      vVec.push_back(0);
+      vVec.push_back(0);
+      vVec.push_back(1);
+      alg->setProperty("u", uVec);
+      alg->setProperty("v", vVec);
+      alg->execute();
+    }
+
+    // Create the coordinate transformation information
+    std::vector<Mantid::coord_t> affMatVals{1, 0, 0, 0, 0, 0, 0, 1, 0,
+                                            0, 0, 0, 0, 1, 0, 0, 1, 0,
+                                            0, 0, 0, 0, 0, 0, 1};
+
+    Mantid::DataObjects::CoordTransformAffine affMat(4, 4);
+    affMat.setMatrix(Mantid::Kernel::Matrix<Mantid::coord_t>(affMatVals));
+    if (!forgetAffmat) {
+      ws->setTransformToOriginal(affMat.clone(), 0);
+    }
+    // Create the transform (W) matrix
+    // Need it as a vector
+    std::vector<double> wMat;
+    Mantid::Kernel::DblMatrix temp(3, 3, true);
+    wMat = temp.getVector();
+    if (!forgetWmat) {
+      Mantid::Kernel::PropertyWithValue<std::vector<double>> *p;
+      p = new Mantid::Kernel::PropertyWithValue<std::vector<double>>("W_MATRIX",
+                                                                     wMat);
+      ws->getExperimentInfo(0)->mutableRun().addProperty(p, true);
+    }
+    return ws;
+  }
+
+  Mantid::Kernel::DblMatrix getExampleSkewMatrix() {
+    Mantid::Kernel::DblMatrix skewMatrix(3, 3, true);
+    skewMatrix[0][0] = 1; // 1
+    skewMatrix[0][1] = 0;
+    skewMatrix[0][2] = -0.57735;
+    skewMatrix[1][0] = 0;
+    skewMatrix[1][1] = 1;
+    skewMatrix[1][2] = 0;
+    skewMatrix[2][0] = 0;
+    skewMatrix[2][1] = 0;
+    skewMatrix[2][2] = 1.1547;
+    return skewMatrix;
+  }
+
+  template <typename T> bool skewWithinTolerance(T coord, T target) {
+    if ((coord >= target - 0.000005) && (coord <= target + 0.000005)) {
+      return true;
+    } else
+      return false;
+  }
+
+  void getExampleCoordTArray(Mantid::coord_t *coordTArrayExample,
+                             bool nonSkewed) {
+    if (nonSkewed) {
+      coordTArrayExample[0] = 1.0;
+      coordTArrayExample[1] = 0.0;
+      coordTArrayExample[2] = 0.0;
+      coordTArrayExample[3] = 0.0;
+      coordTArrayExample[4] = 1.0;
+      coordTArrayExample[5] = 0.0;
+      coordTArrayExample[6] = 0.0;
+      coordTArrayExample[7] = 0.0;
+      coordTArrayExample[8] = 1.0;
+    } else {
+      coordTArrayExample[0] = 1.0;
+      coordTArrayExample[1] = 0.0;
+      coordTArrayExample[2] = static_cast<Mantid::coord_t>(-0.57735);
+      coordTArrayExample[3] = 0.0;
+      coordTArrayExample[4] = 1.0;
+      coordTArrayExample[5] = 0.0;
+      coordTArrayExample[6] = 0.0;
+      coordTArrayExample[7] = 0.0;
+      coordTArrayExample[8] = static_cast<Mantid::coord_t>(1.1547);
+    }
+  }
+
+public:
+  static NonOrthogonalTest *createSuite() {
+    Mantid::API::FrameworkManager::Instance();
+    Mantid::API::AlgorithmManager::Instance();
+    return new NonOrthogonalTest;
+  }
+  static void destroySuite(NonOrthogonalTest *suite) { delete suite; }
+
+  void test_provideSkewMatrixWithOrthogonal() {
+    // Arrange
+    auto eventWorkspace = getOrthogonalEventWorkspace();
+    Mantid::Kernel::DblMatrix skewMatrix;
+
+    // Act
+    bool orthogonalWorkspaceFailed = false;
+    try {
+      MantidQt::API::provideSkewMatrix(skewMatrix, eventWorkspace);
+    } catch (std::invalid_argument &) {
+      orthogonalWorkspaceFailed = true;
+    }
+    // Assert
+    TSM_ASSERT("Orthogonal workspaces should not be given a skew matrix",
+               orthogonalWorkspaceFailed);
+  }
+
+  void test_provideSkewMatrixWithOrthogonalAndHKL() {
+    // Arrange
+    auto eventWorkspace = getOrthogonalHKLEventWorkspace();
+    Mantid::Kernel::DblMatrix skewMatrix;
+
+    // Act
+    bool orthogonalWorkspaceFailed = false;
+    try {
+      MantidQt::API::provideSkewMatrix(skewMatrix, eventWorkspace);
+    } catch (std::invalid_argument &) {
+      orthogonalWorkspaceFailed = true;
+    }
+    // Assert
+    TSM_ASSERT("Orthogonal HKL workspaces should not be given a skew matrix",
+               orthogonalWorkspaceFailed);
+  }
+
+  void test_provideSkewMatrixWithNonOrthogonal() {
+    auto eventWorkspace = getNonOrthogonalEventWorkspace();
+    Mantid::Kernel::DblMatrix skewMatrix(3, 3, true);
+    Mantid::Kernel::DblMatrix exampleSkewMatrix(3, 3, true);
+    exampleSkewMatrix = getExampleSkewMatrix();
+    bool nonOrthogonalWorkspaceFailed = true;
+
+    MantidQt::API::provideSkewMatrix(skewMatrix, eventWorkspace);
+
+    const auto numberOfColumns = skewMatrix.numCols();
+    const auto numberOfRows = skewMatrix.numRows();
+    for (size_t column = 0; column < numberOfColumns; ++column) {
+      for (size_t row = 0; row < numberOfRows; ++row) {
+        if (!skewWithinTolerance(skewMatrix[row][column],
+                                 exampleSkewMatrix[row][column])) {
+          nonOrthogonalWorkspaceFailed = false;
+        }
+      }
+    }
+
+    TSM_ASSERT("Skew matrix for nonOrthogonal workspace incorrect",
+               nonOrthogonalWorkspaceFailed);
+  }
+
+  void test_requiresSkewMatrixWithOrthogonal() {
+    auto eventWorkspace = getOrthogonalEventWorkspace();
+    bool requiresSkewMatrix;
+    requiresSkewMatrix = MantidQt::API::requiresSkewMatrix(eventWorkspace);
+    TSM_ASSERT("Orthogonal workspaces should not require a skew matrix",
+               !requiresSkewMatrix);
+  }
+
+  void test_requiresSkewMatrixWithOrthogonalandHKL() {
+    auto eventWorkspace = getOrthogonalHKLEventWorkspace();
+    bool requiresSkewMatrix;
+    requiresSkewMatrix = MantidQt::API::requiresSkewMatrix(eventWorkspace);
+    TSM_ASSERT("Orthogonal HKL workspaces should not require a skew matrix",
+               !requiresSkewMatrix);
+  }
+
+  void test_requiresSkewMatrixWithNonOrthogonal() {
+    auto eventWorkspace = getNonOrthogonalEventWorkspace();
+    bool requiresSkewMatrix;
+    requiresSkewMatrix = MantidQt::API::requiresSkewMatrix(eventWorkspace);
+    TSM_ASSERT("NonOrthogonal workspaces should require a skew matrix",
+               requiresSkewMatrix);
+  }
+
+  void test_isHKLDimensionsWithOrthogonal() {
+    auto eventWorkspace = getOrthogonalEventWorkspace();
+    bool hasHKLDimension;
+    hasHKLDimension =
+        MantidQt::API::isHKLDimensions(eventWorkspace, m_dimX, m_dimY);
+    TSM_ASSERT("Should not have HKL dimensions", !hasHKLDimension);
+  }
+
+  void test_isHKLDimensionsWithOrthogonalandHKL() {
+    auto eventWorkspace = getOrthogonalHKLEventWorkspace();
+    bool hasHKLDimension;
+    hasHKLDimension =
+        MantidQt::API::isHKLDimensions(eventWorkspace, m_dimX, m_dimY);
+    TSM_ASSERT("Should have HKL dimensions", hasHKLDimension);
+  }
+
+  void test_isHKLDimensionsWithNonOrthogonal() {
+    auto eventWorkspace = getNonOrthogonalEventWorkspace();
+    bool hasHKLDimension;
+    hasHKLDimension =
+        MantidQt::API::isHKLDimensions(eventWorkspace, m_dimX, m_dimY);
+    TSM_ASSERT("Should have HKL dimensions", hasHKLDimension);
+  }
+
+  void test_getGridLineAnglesInRadianWithZeroArray() {
+    Mantid::coord_t skewMatrixCoord[9] = {0};
+    std::pair<double, double> radianAngles;
+    bool radianResultCorrect;
+    radianResultCorrect = false;
+    radianAngles = MantidQt::API::getGridLineAnglesInRadian(skewMatrixCoord,
+                                                            m_dimX, m_dimY);
+    if ((radianAngles.first == 0) && (std::isnan(radianAngles.second))) {
+      radianResultCorrect = true;
+    }
+    TSM_ASSERT("When given Zero array, getGridLinesInRadian should return 0 "
+               "and Nan result",
+               radianResultCorrect);
+  }
+
+  void test_getGridLineAnglesInRadianWithDefaultTestArray() {
+    Mantid::coord_t skewMatrixCoord[9];
+    getExampleCoordTArray(skewMatrixCoord, true);
+    std::pair<double, double> radianAngles;
+    bool radianResultCorrect;
+    radianResultCorrect = false;
+    radianAngles = MantidQt::API::getGridLineAnglesInRadian(skewMatrixCoord,
+                                                            m_dimX, m_dimY);
+    if ((radianAngles.first == 0) && (radianAngles.second == 0)) {
+      radianResultCorrect = true;
+    }
+    TSM_ASSERT("When given default array, getGridLinesInRadian should return 0 "
+               "and 0 result",
+               radianResultCorrect);
+  }
+
+  void test_transformLookpointToWorkspaceCoordWithZeroZeroCoords() {
+    bool coordsRemainZero;
+    coordsRemainZero = false;
+    Mantid::coord_t skewMatrixCoord[9];
+    getExampleCoordTArray(skewMatrixCoord, true);
+    auto eventWorkspace = getOrthogonalEventWorkspace();
+    Mantid::Kernel::VMD coords = eventWorkspace->getNumDims();
+    for (size_t d = 0; d < eventWorkspace->getNumDims();
+         d++) // change to num dims of eventworkspace
+    {
+      coords[d] = Mantid::Kernel::VMD_t(0.0);
+    }
+    MantidQt::API::transformLookpointToWorkspaceCoordGeneric(
+        coords, skewMatrixCoord, m_dimX, m_dimY, m_sliceDim);
+    if ((coords[0] == 0) && (coords[1] == 0)) {
+      coordsRemainZero = true;
+    }
+    TSM_ASSERT("Zero, zero coordinates should not be affected by skewMatrix "
+               "translation",
+               coordsRemainZero);
+  }
+
+  void test_transformLookPointToWorkspaceCoordWithExampleCoords() {
+    bool coordsAccurate;
+    coordsAccurate = false;
+    Mantid::coord_t skewMatrixCoord[9];
+    getExampleCoordTArray(skewMatrixCoord, false);
+    auto eventWorkspace = getNonOrthogonalEventWorkspace();
+    Mantid::Kernel::VMD coords = eventWorkspace->getNumDims();
+    for (size_t d = 0; d < eventWorkspace->getNumDims(); d++) {
+      coords[d] = Mantid::Kernel::VMD_t(1.5);
+    }
+    MantidQt::API::transformLookpointToWorkspaceCoordGeneric(
+        coords, skewMatrixCoord, m_dimX, m_dimY, m_sliceDim);
+    if ((skewWithinTolerance(coords[0],
+                             static_cast<Mantid::Kernel::VMD_t>(0.75))) &&
+        (coords[1] == 1.5) && (coords[2] == 1.5) && (coords[3] == 1.5)) {
+      coordsAccurate = true;
+    }
+    TSM_ASSERT("Example coordinates skewed result incorrect", coordsAccurate);
+  }
+};
+
+#endif /* MANTIDQT_API_NONORTHOGONALTEST_H_ */
diff --git a/MantidQt/API/test/PlotAxisTest.h b/MantidQt/API/test/PlotAxisTest.h
index d130313dd3032e75f832fd581019b28f5cd9f098..f1a0d9721789457a211b8d89df10b055e0ae6d72 100644
--- a/MantidQt/API/test/PlotAxisTest.h
+++ b/MantidQt/API/test/PlotAxisTest.h
@@ -43,7 +43,7 @@ public:
 
   void test_NoUnit_On_Indexed_Axis_Prints_Default() {
     using MantidQt::API::PlotAxis;
-    auto ws = WorkspaceCreationHelper::Create2DWorkspace(1, 1);
+    auto ws = WorkspaceCreationHelper::create2DWorkspace(1, 1);
     ws->replaceAxis(1, new Mantid::API::NumericAxis(1));
     TS_ASSERT_EQUALS("X axis", PlotAxis(*ws, 0).title());
     TS_ASSERT_EQUALS("Y axis", PlotAxis(*ws, 1).title());
@@ -51,7 +51,7 @@ public:
 
   void test_Empty_Unit_And_Empty_Axis_Title_On_Indexed_Axis_Prints_Default() {
     using MantidQt::API::PlotAxis;
-    auto ws = WorkspaceCreationHelper::Create2DWorkspace(1, 1);
+    auto ws = WorkspaceCreationHelper::create2DWorkspace(1, 1);
     ws->getAxis(0)->setUnit("Empty");
     ws->replaceAxis(1, new Mantid::API::NumericAxis(1));
     ws->getAxis(1)->setUnit("Empty");
@@ -61,7 +61,7 @@ public:
 
   void test_Empty_Unit_And_Non_Empty_Title_On_Indexed_Axis_Prints_Title() {
     using MantidQt::API::PlotAxis;
-    auto ws = WorkspaceCreationHelper::Create2DWorkspace(1, 1);
+    auto ws = WorkspaceCreationHelper::create2DWorkspace(1, 1);
     ws->getAxis(0)->setUnit("Empty");
     auto *ax0 = ws->getAxis(0);
     ax0->setUnit("Empty");
@@ -76,7 +76,7 @@ public:
 
   void test_Axis_With_Unit_Has_Label_In_Parentheses() {
     using MantidQt::API::PlotAxis;
-    auto ws = WorkspaceCreationHelper::Create2DWorkspace(1, 1);
+    auto ws = WorkspaceCreationHelper::create2DWorkspace(1, 1);
     ws->getAxis(0)->setUnit("TOF");
     ws->replaceAxis(1, new Mantid::API::NumericAxis(1));
     ws->getAxis(1)->setUnit("TOF");
@@ -88,7 +88,7 @@ public:
   void test_Axis_With_Y_Axis_Normalised_By_X_Axis_Unit() {
     using MantidQt::API::PlotAxis;
     using Mantid::Kernel::UnitLabel;
-    auto ws = WorkspaceCreationHelper::Create2DWorkspace(1, 1);
+    auto ws = WorkspaceCreationHelper::create2DWorkspace(1, 1);
     ws->getAxis(0)->setUnit("TOF");
     const auto xunit = ws->getAxis(0)->unit();
     const auto lbl = xunit->label();
@@ -102,14 +102,14 @@ public:
   void test_Axis_With_Unit_But_Empty_Utf8_Lable_Uses_Ascii_In_Parentheses() {
     using MantidQt::API::PlotAxis;
     using Mantid::Kernel::Units::Degrees;
-    auto ws = WorkspaceCreationHelper::Create2DWorkspace(1, 1);
+    auto ws = WorkspaceCreationHelper::create2DWorkspace(1, 1);
     ws->getAxis(0)->unit() = boost::make_shared<EmptyUtf8Label>();
     TS_ASSERT_EQUALS("Caption (unittext)", PlotAxis(*ws, 0).title());
   }
 
   void test_SpectraAxis_Gives_Standard_Text() {
     using MantidQt::API::PlotAxis;
-    auto ws = WorkspaceCreationHelper::Create2DWorkspace(1, 1);
+    auto ws = WorkspaceCreationHelper::create2DWorkspace(1, 1);
     ws->replaceAxis(0, new Mantid::API::SpectraAxis(ws.get()));
     TS_ASSERT_EQUALS("Spectrum", PlotAxis(*ws, 0).title());
     TS_ASSERT_EQUALS("Spectrum", PlotAxis(*ws, 1).title());
@@ -118,7 +118,7 @@ public:
   void
   test_Passing_Workspace_Not_Plotting_As_Distribution_Creates_UnitLess_Title_For_Y_Data() {
     using MantidQt::API::PlotAxis;
-    auto ws = WorkspaceCreationHelper::Create2DWorkspace(1, 1);
+    auto ws = WorkspaceCreationHelper::create2DWorkspace(1, 1);
     ws->setYUnit("Counts");
     TS_ASSERT_EQUALS("Counts", PlotAxis(false, *ws).title());
   }
@@ -126,7 +126,7 @@ public:
   void
   test_Passing_Workspace_And_Plotting_As_Distribution_Creates_UnitLess_Title_For_Y_Data() {
     using MantidQt::API::PlotAxis;
-    auto ws = WorkspaceCreationHelper::Create2DWorkspace(1, 1);
+    auto ws = WorkspaceCreationHelper::create2DWorkspace(1, 1);
     ws->setYUnit("Counts");
     TS_ASSERT_EQUALS("Counts", PlotAxis(true, *ws).title());
   }
@@ -148,7 +148,7 @@ public:
   void
   test_Index_Greater_Than_numDims_Or_Less_Than_Zero_Throws_Invalid_Argument() {
     using MantidQt::API::PlotAxis;
-    auto ws = WorkspaceCreationHelper::Create2DWorkspace(1, 1);
+    auto ws = WorkspaceCreationHelper::create2DWorkspace(1, 1);
     TS_ASSERT_THROWS(PlotAxis(*ws, 2), std::invalid_argument);
     TS_ASSERT_THROWS(PlotAxis(*ws, -1), std::invalid_argument);
   }
diff --git a/MantidQt/API/test/QwtWorkspaceBinDataTest.h b/MantidQt/API/test/QwtWorkspaceBinDataTest.h
index 5a7cab60963beba78c2a10d3b8e92312bd848fe6..421b54d022e954fa70c802e73bac0f6b62a00c7a 100644
--- a/MantidQt/API/test/QwtWorkspaceBinDataTest.h
+++ b/MantidQt/API/test/QwtWorkspaceBinDataTest.h
@@ -13,7 +13,7 @@ class QwtWorkspaceBinDataTest : public CxxTest::TestSuite {
 
 public:
   void setUp() override {
-    ws = WorkspaceCreationHelper::Create2DWorkspace(3, 4);
+    ws = WorkspaceCreationHelper::create2DWorkspace(3, 4);
     auto *ax1 = new Mantid::API::NumericAxis(3);
     ws->replaceAxis(1, ax1);
     for (size_t i = 0; i < 3; i++) {
diff --git a/MantidQt/API/test/QwtWorkspaceSpectrumDataTest.h b/MantidQt/API/test/QwtWorkspaceSpectrumDataTest.h
index fab0e833a7799958bd72c324c781563263fce52e..f16528cb86eb8aea6c4ce09fc2e28ce51dbbde77 100644
--- a/MantidQt/API/test/QwtWorkspaceSpectrumDataTest.h
+++ b/MantidQt/API/test/QwtWorkspaceSpectrumDataTest.h
@@ -13,7 +13,7 @@ class QwtWorkspaceSpectrumDataTest : public CxxTest::TestSuite {
 
 public:
   void setUp() override {
-    ws = WorkspaceCreationHelper::Create2DWorkspace(3, 4);
+    ws = WorkspaceCreationHelper::create2DWorkspace(3, 4);
     for (size_t i = 0; i < 3; i++) {
       for (size_t j = 0; j < 5; j++)
         ws->dataX(i)[j] = double(i) + double(j);
diff --git a/MantidQt/CustomDialogs/inc/MantidQtCustomDialogs/LoadDialog.h b/MantidQt/CustomDialogs/inc/MantidQtCustomDialogs/LoadDialog.h
index d773bede626129dbcc32abf4517f2c1164423d55..19afc1b1469ab97cced34f6366fe05f53eca8e37 100644
--- a/MantidQt/CustomDialogs/inc/MantidQtCustomDialogs/LoadDialog.h
+++ b/MantidQt/CustomDialogs/inc/MantidQtCustomDialogs/LoadDialog.h
@@ -16,7 +16,7 @@ namespace MantidQt {
 //------------------------------------------------------------------------------
 // Mantid Forward declarations
 //------------------------------------------------------------------------------
-namespace MantidWidgets {
+namespace API {
 class MWRunFiles;
 }
 
diff --git a/MantidQt/CustomDialogs/inc/MantidQtCustomDialogs/LoadDialog.ui b/MantidQt/CustomDialogs/inc/MantidQtCustomDialogs/LoadDialog.ui
index 0d7081eefa1428394513de35b5598c509cc69ba0..685333e22a57f7b6b9f86c1196aeb3eeb864c27f 100644
--- a/MantidQt/CustomDialogs/inc/MantidQtCustomDialogs/LoadDialog.ui
+++ b/MantidQt/CustomDialogs/inc/MantidQtCustomDialogs/LoadDialog.ui
@@ -179,7 +179,7 @@
         <enum>QLayout::SetMinAndMaxSize</enum>
        </property>
        <item>
-        <widget class="MantidQt::MantidWidgets::MWRunFiles" name="fileWidget" native="true">
+        <widget class="MantidQt::API::MWRunFiles" name="fileWidget" native="true">
          <property name="sizePolicy">
           <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
            <horstretch>0</horstretch>
@@ -228,9 +228,9 @@
  </widget>
  <customwidgets>
   <customwidget>
-   <class>MantidQt::MantidWidgets::MWRunFiles</class>
+   <class>MantidQt::API::MWRunFiles</class>
    <extends>QWidget</extends>
-   <header>MantidQtMantidWidgets/MWRunFiles.h</header>
+   <header>MantidQtAPI/MWRunFiles.h</header>
   </customwidget>
  </customwidgets>
  <resources/>
diff --git a/MantidQt/CustomDialogs/inc/MantidQtCustomDialogs/StartLiveDataDialog.h b/MantidQt/CustomDialogs/inc/MantidQtCustomDialogs/StartLiveDataDialog.h
index 47968140a5856630940a4c19a488f4e7dda9b4da..7a1572dc07940a7ec82f46282e3bc17cf89811ec 100644
--- a/MantidQt/CustomDialogs/inc/MantidQtCustomDialogs/StartLiveDataDialog.h
+++ b/MantidQt/CustomDialogs/inc/MantidQtCustomDialogs/StartLiveDataDialog.h
@@ -34,6 +34,8 @@ private slots:
   void updateUiElements(const QString &);
   void accept() override;
   void initListenerPropLayout(const QString &);
+  void updateConnectionChoices(const QString &inst_name);
+  void updateConnectionDetails(const QString &connection);
 
 private:
   /// Initialize the layout
@@ -63,6 +65,9 @@ private:
 
   /// The algorithm for processing the accumulated workspace
   Mantid::API::Algorithm_sptr m_postProcessingAlg;
+
+  /// Constant used for custom listener connection setups
+  static const QString CUSTOM_CONNECTION;
 };
 }
 }
diff --git a/MantidQt/CustomDialogs/inc/MantidQtCustomDialogs/StartLiveDataDialog.ui b/MantidQt/CustomDialogs/inc/MantidQtCustomDialogs/StartLiveDataDialog.ui
index f472b6b467df1ac6f5b9b05b8588109d6f739609..3e8796f7c606b5af30a946fc1090a267d5696183 100644
--- a/MantidQt/CustomDialogs/inc/MantidQtCustomDialogs/StartLiveDataDialog.ui
+++ b/MantidQt/CustomDialogs/inc/MantidQtCustomDialogs/StartLiveDataDialog.ui
@@ -28,80 +28,118 @@
       </property>
       <layout class="QVBoxLayout" name="widgetLeftLayout">
        <item>
-        <layout class="QHBoxLayout" name="horizontalLayout_5">
-         <item>
+        <layout class="QGridLayout" name="gridLayout_3">
+         <item row="0" column="0">
           <widget class="QLabel" name="lblInstrument">
            <property name="text">
             <string>Instrument:</string>
            </property>
           </widget>
          </item>
-         <item>
+         <item row="1" column="1">
+          <widget class="QComboBox" name="cmbConnection"/>
+         </item>
+         <item row="1" column="0">
+          <widget class="QLabel" name="lblConnection">
+           <property name="text">
+            <string>Connection:</string>
+           </property>
+          </widget>
+         </item>
+         <item row="0" column="1">
           <widget class="QComboBox" name="cmbInstrument"/>
          </item>
         </layout>
        </item>
        <item>
-        <widget class="QGroupBox" name="groupBox">
+        <widget class="QGroupBox" name="grpConnection">
          <property name="styleSheet">
           <string notr="true">QGroupBox { border: 1px solid gray;  border-radius: 4px; font-weight: bold; margin-top: 4px; margin-bottom: 4px; padding-top: 16px; }
 QGroupBox::title { background-color: transparent;  subcontrol-position: top center;  padding-top:4px; padding-bottom:4px; } 
 </string>
          </property>
          <property name="title">
-          <string>Starting Time</string>
+          <string>Connection Parameters</string>
          </property>
-         <layout class="QVBoxLayout" name="verticalLayout_4">
+         <layout class="QVBoxLayout" name="verticalLayout">
           <item>
-           <layout class="QHBoxLayout" name="horizontalLayout">
-            <item>
-             <widget class="QRadioButton" name="radNow">
-              <property name="toolTip">
-               <string>Start collecting data from current time</string>
-              </property>
+           <layout class="QGridLayout" name="gridLayout_2">
+            <item row="0" column="1">
+             <widget class="QComboBox" name="cmbConnListener"/>
+            </item>
+            <item row="0" column="0">
+             <widget class="QLabel" name="lblConnListener">
               <property name="text">
-               <string>Now</string>
-              </property>
-              <property name="checked">
-               <bool>true</bool>
+               <string>Listener Type:</string>
               </property>
              </widget>
             </item>
-            <item>
-             <widget class="QRadioButton" name="radStartOfRun">
-              <property name="toolTip">
-               <string>Start processing data from the beginning of the current run</string>
-              </property>
+            <item row="1" column="0">
+             <widget class="QLabel" name="lblConnAddress">
               <property name="text">
-               <string>Start of Run</string>
+               <string>Address String:</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>
+            <item row="1" column="1">
+             <widget class="QLineEdit" name="edtConnAddress">
+              <property name="sizePolicy">
+               <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+                <horstretch>0</horstretch>
+                <verstretch>0</verstretch>
+               </sizepolicy>
               </property>
-             </spacer>
+             </widget>
             </item>
            </layout>
           </item>
+         </layout>
+        </widget>
+       </item>
+       <item>
+        <widget class="QGroupBox" name="groupBox">
+         <property name="styleSheet">
+          <string notr="true">QGroupBox { border: 1px solid gray;  border-radius: 4px; font-weight: bold; margin-top: 4px; margin-bottom: 4px; padding-top: 16px; }
+QGroupBox::title { background-color: transparent;  subcontrol-position: top center;  padding-top:4px; padding-bottom:4px; } 
+</string>
+         </property>
+         <property name="title">
+          <string>Starting Time</string>
+         </property>
+         <layout class="QVBoxLayout" name="verticalLayout_4">
+          <property name="spacing">
+           <number>2</number>
+          </property>
+          <item>
+           <widget class="QRadioButton" name="radNow">
+            <property name="toolTip">
+             <string>Start collecting data from current time</string>
+            </property>
+            <property name="text">
+             <string>Now</string>
+            </property>
+            <property name="checked">
+             <bool>true</bool>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="QRadioButton" name="radStartOfRun">
+            <property name="toolTip">
+             <string>Start processing data from the beginning of the current run</string>
+            </property>
+            <property name="text">
+             <string>Start of Run</string>
+            </property>
+           </widget>
+          </item>
           <item>
            <layout class="QHBoxLayout" name="horizontalLayout_4">
+            <property name="spacing">
+             <number>6</number>
+            </property>
             <item>
              <widget class="QRadioButton" name="radAbsoluteTime">
-              <property name="maximumSize">
-               <size>
-                <width>17</width>
-                <height>16777215</height>
-               </size>
-              </property>
               <property name="toolTip">
                <string>Start collecting data from a specific time:</string>
               </property>
@@ -174,19 +212,6 @@ QGroupBox::title { background-color: transparent;  subcontrol-position: top cent
        </item>
        <item>
         <layout class="QHBoxLayout" name="horizontalLayout_8">
-         <item>
-          <spacer name="horizontalSpacer_4">
-           <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="grpProcess">
            <property name="styleSheet">
@@ -198,6 +223,9 @@ QGroupBox::title { background-color: transparent;  subcontrol-position: top cent
             <string>Processing</string>
            </property>
            <layout class="QVBoxLayout" name="verticalLayout_5">
+            <property name="spacing">
+             <number>2</number>
+            </property>
             <item>
              <widget class="QRadioButton" name="radProcessNone">
               <property name="toolTip">
@@ -234,36 +262,10 @@ QGroupBox::title { background-color: transparent;  subcontrol-position: top cent
            </layout>
           </widget>
          </item>
-         <item>
-          <spacer name="horizontalSpacer_3">
-           <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>
         <layout class="QHBoxLayout" name="horizontalLayout_3">
-         <item>
-          <spacer name="horizontalSpacer_9">
-           <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="QCheckBox" name="chkPreserveEvents">
            <property name="text">
@@ -271,19 +273,6 @@ QGroupBox::title { background-color: transparent;  subcontrol-position: top cent
            </property>
           </widget>
          </item>
-         <item>
-          <spacer name="horizontalSpacer_10">
-           <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>
@@ -302,19 +291,6 @@ p, li { white-space: pre-wrap; }
        </item>
        <item>
         <layout class="QHBoxLayout" name="horizontalLayout_7">
-         <item>
-          <spacer name="horizontalSpacer_8">
-           <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="QLabel" name="lblInstrument_2">
            <property name="text">
@@ -325,36 +301,10 @@ p, li { white-space: pre-wrap; }
          <item>
           <widget class="QComboBox" name="cmbAccumulationMethod"/>
          </item>
-         <item>
-          <spacer name="horizontalSpacer_7">
-           <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>
         <layout class="QHBoxLayout" name="horizontalLayout_9">
-         <item>
-          <spacer name="horizontalSpacer_5">
-           <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="grpPostProcessing">
            <property name="styleSheet">
@@ -366,6 +316,9 @@ QGroupBox::title { background-color: transparent;  subcontrol-position: top cent
             <string>Post Processing</string>
            </property>
            <layout class="QVBoxLayout" name="verticalLayout_7">
+            <property name="spacing">
+             <number>2</number>
+            </property>
             <item>
              <widget class="QRadioButton" name="radPostProcessNone">
               <property name="toolTip">
@@ -402,36 +355,10 @@ QGroupBox::title { background-color: transparent;  subcontrol-position: top cent
            </layout>
           </widget>
          </item>
-         <item>
-          <spacer name="horizontalSpacer_6">
-           <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>
         <layout class="QHBoxLayout" name="horizontalLayout_6">
-         <item>
-          <spacer name="horizontalSpacer_11">
-           <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="QLabel" name="lblRunTransitionBehavior">
            <property name="text">
@@ -442,19 +369,6 @@ QGroupBox::title { background-color: transparent;  subcontrol-position: top cent
          <item>
           <widget class="QComboBox" name="cmbRunTransitionBehavior"/>
          </item>
-         <item>
-          <spacer name="horizontalSpacer_12">
-           <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>
diff --git a/MantidQt/CustomDialogs/src/ConvertTableToMatrixWorkspaceDialog.cpp b/MantidQt/CustomDialogs/src/ConvertTableToMatrixWorkspaceDialog.cpp
index 4af8ab2f443508bdf32fd7a968a15b1ab7308ce8..3287aba559e39b0531d769261294dc3db4980caa 100644
--- a/MantidQt/CustomDialogs/src/ConvertTableToMatrixWorkspaceDialog.cpp
+++ b/MantidQt/CustomDialogs/src/ConvertTableToMatrixWorkspaceDialog.cpp
@@ -1,6 +1,3 @@
-//------------------------------------------------------------------------------
-// Includes
-//------------------------------------------------------------------------------
 #include "MantidQtCustomDialogs/ConvertTableToMatrixWorkspaceDialog.h"
 #include "MantidQtAPI/AlgorithmInputHistory.h"
 // Qt
@@ -12,6 +9,7 @@
 
 // Mantid
 #include "MantidKernel/Property.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/IWorkspaceProperty.h"
 #include "MantidAPI/AlgorithmManager.h"
 #include "MantidAPI/ITableWorkspace.h"
@@ -21,19 +19,11 @@ namespace CustomDialogs {
 // Declare the dialog. Name must match the class name
 DECLARE_DIALOG(ConvertTableToMatrixWorkspaceDialog)
 
-//--------------------------------------------------------------------------
-// Public methods
-//---------------------------------------------------------------------------
-
 /// Default constructor
 ConvertTableToMatrixWorkspaceDialog::ConvertTableToMatrixWorkspaceDialog(
     QWidget *parent)
     : API::AlgorithmDialog(parent), m_form() {}
 
-//--------------------------------------------------------------------------
-// Private methods (slot)
-//---------------------------------------------------------------------------
-
 /**
 * When the input workspace changes the column name comboboxes have to
 * be updated.
diff --git a/MantidQt/CustomDialogs/src/LoadDialog.cpp b/MantidQt/CustomDialogs/src/LoadDialog.cpp
index 82cc328ea83eba5d6579b4395bd5f5a8ad0c7d27..0489e557d7956fb3a0cb32864de6515572f15c42 100644
--- a/MantidQt/CustomDialogs/src/LoadDialog.cpp
+++ b/MantidQt/CustomDialogs/src/LoadDialog.cpp
@@ -2,7 +2,7 @@
 // Includes
 //------------------------------------------------------------------------------
 #include "MantidQtCustomDialogs/LoadDialog.h"
-#include "MantidQtMantidWidgets/MWRunFiles.h"
+#include "MantidQtAPI/MWRunFiles.h"
 #include "MantidQtAPI/AlgorithmInputHistory.h"
 // Qt
 #include <QCheckBox>
@@ -311,7 +311,7 @@ int LoadDialog::createWidgetsForProperty(const Mantid::Kernel::Property *prop,
                                          QWidget *parent) {
   using namespace Mantid::API;
   using namespace Mantid::Kernel;
-  using MantidQt::MantidWidgets::MWRunFiles;
+  using MantidQt::API::MWRunFiles;
 
   QString propName = QString::fromStdString(prop->name());
   QWidget *inputWidget(NULL);
diff --git a/MantidQt/CustomDialogs/src/PlotAsymmetryByLogValueDialog.cpp b/MantidQt/CustomDialogs/src/PlotAsymmetryByLogValueDialog.cpp
index 4e4407a53ece915e1b558deb53925b72db5c74d5..1f23d623eefa79be0205514619a189099d78b520 100644
--- a/MantidQt/CustomDialogs/src/PlotAsymmetryByLogValueDialog.cpp
+++ b/MantidQt/CustomDialogs/src/PlotAsymmetryByLogValueDialog.cpp
@@ -6,6 +6,7 @@
 #include "MantidAPI/Algorithm.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/Run.h"
+#include "MantidAPI/WorkspaceGroup.h"
 
 #include <QLabel>
 #include <QLineEdit>
diff --git a/MantidQt/CustomDialogs/src/StartLiveDataDialog.cpp b/MantidQt/CustomDialogs/src/StartLiveDataDialog.cpp
index f71d5c8021fa70900c2ebe54aff0d9c5094ff563..8b1541ce8ecbe82c7c7465f04a127f8a6e1aafa6 100644
--- a/MantidQt/CustomDialogs/src/StartLiveDataDialog.cpp
+++ b/MantidQt/CustomDialogs/src/StartLiveDataDialog.cpp
@@ -12,7 +12,9 @@
 #include "MantidAPI/LiveListenerFactory.h"
 #include "MantidKernel/DateAndTime.h"
 #include "MantidKernel/SingletonHolder.h"
+#include "MantidKernel/ConfigService.h"
 #include "MantidKernel/InstrumentInfo.h"
+#include "MantidKernel/LiveListenerInfo.h"
 #include <QtGui>
 #include "MantidQtAPI/AlgorithmInputHistory.h"
 
@@ -21,6 +23,7 @@ using namespace MantidQt::API;
 using Mantid::API::AlgorithmManager;
 using Mantid::API::Algorithm_sptr;
 using Mantid::Kernel::DateAndTime;
+using Mantid::Kernel::ConfigService;
 
 namespace {
 class LiveDataAlgInputHistoryImpl : public AbstractAlgorithmInputHistory {
@@ -69,6 +72,9 @@ namespace MantidQt {
 namespace CustomDialogs {
 DECLARE_DIALOG(StartLiveDataDialog)
 
+// Initialize static members
+const QString StartLiveDataDialog::CUSTOM_CONNECTION = "[Custom]";
+
 //----------------------
 // Public member functions
 //----------------------
@@ -174,13 +180,22 @@ void StartLiveDataDialog::initLayout() {
     }
   }
 
+  //=========== Load Listener Class Names =============
+  // Add available listeners to combo box
+  ui.cmbConnListener->clear();
+  std::vector<std::string> listeners =
+      Mantid::API::LiveListenerFactory::Instance().getKeys();
+  for (const auto &listener : listeners) {
+    ui.cmbConnListener->addItem(QString::fromStdString(listener));
+  }
+
+  //=========== Update UI Elements =============
   radioPostProcessClicked();
-  setDefaultAccumulationMethod(ui.cmbInstrument->currentText());
   updateUiElements(ui.cmbInstrument->currentText());
-
-  //=========== Listener's properties =============
-
-  initListenerPropLayout(ui.cmbInstrument->currentText());
+  updateConnectionChoices(ui.cmbInstrument->currentText());
+  updateConnectionDetails(ui.cmbConnection->currentText());
+  setDefaultAccumulationMethod(ui.cmbConnListener->currentText());
+  initListenerPropLayout(ui.cmbConnListener->currentText());
 
   //=========== SLOTS =============
   connect(ui.processingAlgo, SIGNAL(changedAlgorithm()), this,
@@ -211,12 +226,17 @@ void StartLiveDataDialog::initLayout() {
   connect(ui.chkPreserveEvents, SIGNAL(toggled(bool)), this,
           SLOT(chkPreserveEventsToggled()));
 
-  connect(ui.cmbInstrument, SIGNAL(currentIndexChanged(const QString &)), this,
-          SLOT(setDefaultAccumulationMethod(const QString &)));
-  connect(ui.cmbInstrument, SIGNAL(currentIndexChanged(const QString &)), this,
-          SLOT(initListenerPropLayout(const QString &)));
+  connect(ui.cmbConnListener, SIGNAL(currentIndexChanged(const QString &)),
+          this, SLOT(setDefaultAccumulationMethod(const QString &)));
+  connect(ui.cmbConnListener, SIGNAL(currentIndexChanged(const QString &)),
+          this, SLOT(initListenerPropLayout(const QString &)));
   connect(ui.cmbInstrument, SIGNAL(currentIndexChanged(const QString &)), this,
           SLOT(updateUiElements(const QString &)));
+  connect(ui.cmbInstrument, SIGNAL(currentIndexChanged(const QString &)), this,
+          SLOT(updateConnectionChoices(const QString &)));
+
+  connect(ui.cmbConnection, SIGNAL(currentIndexChanged(const QString &)), this,
+          SLOT(updateConnectionDetails(const QString &)));
 
   QLayout *buttonLayout = this->createDefaultButtonLayout();
   ui.mainLayout->addLayout(buttonLayout);
@@ -226,6 +246,11 @@ void StartLiveDataDialog::initLayout() {
 /// Parse input when the dialog is accepted
 void StartLiveDataDialog::parseInput() {
   storePropertyValue("Instrument", ui.cmbInstrument->currentText());
+
+  // "Connection" property does not need to be set, since these override it
+  storePropertyValue("Listener", ui.cmbConnListener->currentText());
+  storePropertyValue("Address", ui.edtConnAddress->text());
+
   storePropertyValue("AccumulationMethod",
                      ui.cmbAccumulationMethod->currentText());
 
@@ -323,10 +348,11 @@ void StartLiveDataDialog::changePostProcessingAlgorithm() {
 //------------------------------------------------------------------------------
 /** Slot called when picking a different instrument.
  *  Disables the 'Add' option if the listener is going to pass back histograms.
- *  @param inst :: The instrument name.
+ *  @param listener :: The listener class name.
  */
-void StartLiveDataDialog::setDefaultAccumulationMethod(const QString &inst) {
-  if (inst.isEmpty())
+void StartLiveDataDialog::setDefaultAccumulationMethod(
+    const QString &listener) {
+  if (listener.isEmpty())
     return;
   try {
     // Make sure 'Add' is enabled ahead of the check (the check may throw)
@@ -338,12 +364,14 @@ void StartLiveDataDialog::setDefaultAccumulationMethod(const QString &inst) {
     // Check whether this listener will give back events. If not, disable 'Add'
     // as an option
     // The 'false' 2nd argument means don't connect the created listener
+    Mantid::Kernel::LiveListenerInfo info(listener.toStdString());
     if (!Mantid::API::LiveListenerFactory::Instance()
-             .create(inst.toStdString(), false)
+             .create(info, false)
              ->buffersEvents()) {
       // If 'Add' is currently selected, select 'Replace' instead
       if (ui.cmbAccumulationMethod->currentIndex() == addIndex) {
-        ui.cmbAccumulationMethod->setItemText(-1, "Replace");
+        int replaceIndex = ui.cmbAccumulationMethod->findText("Replace");
+        ui.cmbAccumulationMethod->setCurrentIndex(replaceIndex);
       }
       // Disable the 'Add' option in the combobox. It just wouldn't make sense.
       ui.cmbAccumulationMethod->setItemData(addIndex, false, Qt::UserRole - 1);
@@ -390,7 +418,12 @@ void StartLiveDataDialog::accept() {
   AlgorithmDialog::accept(); // accept executes the algorithm
 }
 
-void StartLiveDataDialog::initListenerPropLayout(const QString &inst) {
+/**
+ * Update the Listener Properties group box for the current LiveListener.
+ *
+ * @param listener Name of the LiveListener class that is selected
+ */
+void StartLiveDataDialog::initListenerPropLayout(const QString &listener) {
   // remove previous listener's properties
   auto props = m_algorithm->getPropertiesInGroup("ListenerProperties");
   for (auto prop = props.begin(); prop != props.end(); ++prop) {
@@ -401,7 +434,9 @@ void StartLiveDataDialog::initListenerPropLayout(const QString &inst) {
   }
 
   // update algorithm's properties
-  m_algorithm->setPropertyValue("Instrument", inst.toStdString());
+  m_algorithm->setPropertyValue("Instrument",
+                                ui.cmbInstrument->currentText().toStdString());
+  m_algorithm->setPropertyValue("Listener", listener.toStdString());
   // create or clear the layout
   QLayout *layout = ui.listenerProps->layout();
   if (!layout) {
@@ -439,5 +474,61 @@ void StartLiveDataDialog::initListenerPropLayout(const QString &inst) {
   }
   ui.listenerProps->setVisible(true);
 }
+
+/**
+ * Slot to update list of available connections when instrument is changed
+ *
+ * @param inst_name Name of selected instrument
+ */
+void StartLiveDataDialog::updateConnectionChoices(const QString &inst_name) {
+  // Reset the connections listed
+  ui.cmbConnection->clear();
+  ui.cmbConnection->addItem(CUSTOM_CONNECTION);
+
+  // Add available LiveListenerInfo names based on selected instrument
+  const auto &inst =
+      ConfigService::Instance().getInstrument(inst_name.toStdString());
+  for (const auto &listener : inst.liveListenerInfoList()) {
+    ui.cmbConnection->addItem(QString::fromStdString(listener.name()));
+  }
+
+  // Select default item
+  auto selectName = QString::fromStdString(inst.liveListenerInfo().name());
+  auto index = ui.cmbConnection->findText(selectName);
+  ui.cmbConnection->setCurrentIndex(index);
+}
+
+/**
+ * Slot to update connection parameters when connection selected
+ *
+ * @param connection Name of selected live listener connection
+ */
+void StartLiveDataDialog::updateConnectionDetails(const QString &connection) {
+  // Custom connections just enable editting connection parameters
+  if (connection == CUSTOM_CONNECTION) {
+    ui.cmbConnListener->setEnabled(true);
+    ui.edtConnAddress->setEnabled(true);
+    return;
+  }
+
+  // User shouldn't be able to edit values loaded from Facilities.xml
+  ui.cmbConnListener->setEnabled(false);
+  ui.edtConnAddress->setEnabled(false);
+
+  // Get live listener for select instrument and connection
+  const auto &inst = ConfigService::Instance().getInstrument(
+      ui.cmbInstrument->currentText().toStdString());
+  const auto &info = inst.liveListenerInfo(connection.toStdString());
+
+  // Select correct listener
+  auto listener = QString::fromStdString(info.listener());
+  auto index = ui.cmbConnListener->findText(listener);
+  ui.cmbConnListener->setCurrentIndex(index);
+
+  // Set address text box
+  auto address = QString::fromStdString(info.address());
+  ui.edtConnAddress->setText(address);
+  ui.edtConnAddress->home(false); // display long lines from beginning, not end
+}
 }
 }
diff --git a/MantidQt/CustomInterfaces/CMakeLists.txt b/MantidQt/CustomInterfaces/CMakeLists.txt
index b5cd80ab35dc4d3cbd9ca2d040e853cabf33af4a..c56dfb611266dea43bb92987dc18ca3c6cd87a87 100644
--- a/MantidQt/CustomInterfaces/CMakeLists.txt
+++ b/MantidQt/CustomInterfaces/CMakeLists.txt
@@ -88,11 +88,13 @@ set ( SRC_FILES
 	src/Muon/MuonAnalysisOptionTab.cpp
 	src/Muon/MuonAnalysisResultTableCreator.cpp
 	src/Muon/MuonAnalysisResultTableTab.cpp
-	src/Muon/MuonSequentialFitDialog.cpp
-	src/Reflectometry/MeasurementItem.cpp
+  src/Muon/MuonSequentialFitDialog.cpp
+  src/Reflectometry/MeasurementItem.cpp
 	src/Reflectometry/QtReflMainWindowView.cpp
 	src/Reflectometry/QtReflRunsTabView.cpp
+	src/Reflectometry/QtReflSaveTabView.cpp
 	src/Reflectometry/QtReflSettingsTabView.cpp
+	src/Reflectometry/QtReflSettingsView.cpp
 	src/Reflectometry/ReflCatalogSearcher.cpp
 	src/Reflectometry/ReflGenericDataProcessorPresenterFactory.cpp
 	src/Reflectometry/ReflLegacyTransferStrategy.cpp
@@ -101,6 +103,8 @@ set ( SRC_FILES
 	src/Reflectometry/ReflNexusMeasurementItemSource.cpp
 	src/Reflectometry/ReflRunsTabPresenter.cpp
 	src/Reflectometry/ReflSearchModel.cpp
+	src/Reflectometry/ReflSaveTabPresenter.cpp
+	src/Reflectometry/ReflSettingsPresenter.cpp
 	src/Reflectometry/ReflSettingsTabPresenter.cpp
 	src/Reflectometry/ReflTableSchema.cpp
 	src/Reflectometry/TransferResults.cpp
@@ -121,7 +125,6 @@ set ( SRC_FILES
 	src/Tomography/ImggFormats.cpp
 	src/Tomography/ImggFormatsConvertPresenter.cpp
 	src/Tomography/ImggFormatsConvertViewQtWidget.cpp
-	src/Tomography/SavuConfigDialog.cpp
 	src/Tomography/StackOfImagesDirs.cpp
 	src/Tomography/TomoPathsConfig.cpp
 	src/Tomography/TomoReconPostprocSettings.cpp
@@ -129,7 +132,11 @@ set ( SRC_FILES
 	src/Tomography/TomoSystemSettings.cpp
 	src/Tomography/TomoSystemSettingsLocal.cpp
 	src/Tomography/TomoSystemSettingsRemote.cpp
-	src/Tomography/TomoToolConfigDialog.cpp
+	src/Tomography/TomoToolConfigDialogBase.cpp
+	src/Tomography/TomoToolConfigDialogTomoPy.cpp
+	src/Tomography/TomoToolConfigDialogCustom.cpp
+	src/Tomography/TomoToolConfigDialogSavu.cpp
+	src/Tomography/TomoToolConfigDialogAstra.cpp
 	src/Tomography/TomographyIfaceModel.cpp
 	src/Tomography/TomographyIfacePresenter.cpp
 	src/Tomography/TomographyIfaceViewQtGUI.cpp
@@ -245,13 +252,16 @@ set ( INC_FILES
 	inc/MantidQtCustomInterfaces/Muon/MuonAnalysisResultTableCreator.h
 	inc/MantidQtCustomInterfaces/Muon/MuonAnalysisResultTableTab.h
 	inc/MantidQtCustomInterfaces/Muon/MuonSequentialFitDialog.h
-	inc/MantidQtCustomInterfaces/Reflectometry/IReflMainWindowPresenter.h
+  inc/MantidQtCustomInterfaces/Reflectometry/IReflMainWindowPresenter.h
 	inc/MantidQtCustomInterfaces/Reflectometry/IReflMainWindowView.h
 	inc/MantidQtCustomInterfaces/Reflectometry/IReflRunsTabPresenter.h
 	inc/MantidQtCustomInterfaces/Reflectometry/IReflRunsTabView.h
 	inc/MantidQtCustomInterfaces/Reflectometry/IReflSearcher.h
+	inc/MantidQtCustomInterfaces/Reflectometry/IReflSaveTabPresenter.h
+	inc/MantidQtCustomInterfaces/Reflectometry/IReflSaveTabView.h
+	inc/MantidQtCustomInterfaces/Reflectometry/IReflSettingsPresenter.h
 	inc/MantidQtCustomInterfaces/Reflectometry/IReflSettingsTabPresenter.h
-	inc/MantidQtCustomInterfaces/Reflectometry/IReflSettingsTabView.h
+	inc/MantidQtCustomInterfaces/Reflectometry/IReflSettingsView.h
 	inc/MantidQtCustomInterfaces/Reflectometry/MeasurementItem.h
 	inc/MantidQtCustomInterfaces/Reflectometry/QtReflMainWindowView.h
 	inc/MantidQtCustomInterfaces/Reflectometry/QtReflRunsTabView.h
@@ -263,6 +273,8 @@ set ( INC_FILES
 	inc/MantidQtCustomInterfaces/Reflectometry/ReflMeasurementItemSource.h
 	inc/MantidQtCustomInterfaces/Reflectometry/ReflNexusMeasurementItemSource.h
 	inc/MantidQtCustomInterfaces/Reflectometry/ReflRunsTabPresenter.h
+	inc/MantidQtCustomInterfaces/Reflectometry/ReflSettingsPresenter.h
+	inc/MantidQtCustomInterfaces/Reflectometry/ReflSettingsTabPresenter.h
 	inc/MantidQtCustomInterfaces/Reflectometry/ReflSearchModel.h
 	inc/MantidQtCustomInterfaces/Reflectometry/ReflTableSchema.h
 	inc/MantidQtCustomInterfaces/Reflectometry/ReflTransferStrategy.h
@@ -298,10 +310,16 @@ set ( INC_FILES
 	inc/MantidQtCustomInterfaces/Tomography/TomoSystemSettings.h
 	inc/MantidQtCustomInterfaces/Tomography/TomoSystemSettingsLocal.h
 	inc/MantidQtCustomInterfaces/Tomography/TomoSystemSettingsRemote.h
-	inc/MantidQtCustomInterfaces/Tomography/TomoToolConfigDialog.h
+	inc/MantidQtCustomInterfaces/Tomography/TomoToolConfigDialogBase.h
+	inc/MantidQtCustomInterfaces/Tomography/TomoToolConfigDialogTomoPy.h
+	inc/MantidQtCustomInterfaces/Tomography/TomoToolConfigDialogCustom.h
+	inc/MantidQtCustomInterfaces/Tomography/TomoToolConfigDialogSavu.h
+	inc/MantidQtCustomInterfaces/Tomography/TomoToolConfigDialogAstra.h
 	inc/MantidQtCustomInterfaces/Tomography/TomographyIfaceModel.h
 	inc/MantidQtCustomInterfaces/Tomography/TomographyIfacePresenter.h
 	inc/MantidQtCustomInterfaces/Tomography/TomographyIfaceViewQtGUI.h
+	inc/MantidQtCustomInterfaces/Tomography/TomographyThread.h
+	inc/MantidQtCustomInterfaces/Tomography/TomographyProcess.h
 	inc/MantidQtCustomInterfaces/Tomography/ToolConfigAstraToolbox.h
 	inc/MantidQtCustomInterfaces/Tomography/ToolConfigCustom.h
 	inc/MantidQtCustomInterfaces/Tomography/ToolConfigTomoPy.h
@@ -390,16 +408,18 @@ set ( MOC_FILES inc/MantidQtCustomInterfaces/Background.h
                 inc/MantidQtCustomInterfaces/Muon/IALCPeakFittingView.h
                 inc/MantidQtCustomInterfaces/Muon/IALCPeakFittingModel.h
                 inc/MantidQtCustomInterfaces/Muon/MuonAnalysis.h
-				inc/MantidQtCustomInterfaces/Muon/MuonAnalysisFitDataPresenter.h
+                inc/MantidQtCustomInterfaces/Muon/MuonAnalysisFitDataPresenter.h
                 inc/MantidQtCustomInterfaces/Muon/MuonAnalysisFitDataTab.h
-				inc/MantidQtCustomInterfaces/Muon/MuonAnalysisFitFunctionPresenter.h
+                inc/MantidQtCustomInterfaces/Muon/MuonAnalysisFitFunctionPresenter.h
                 inc/MantidQtCustomInterfaces/Muon/MuonAnalysisHelper.h
                 inc/MantidQtCustomInterfaces/Muon/MuonAnalysisOptionTab.h
                 inc/MantidQtCustomInterfaces/Muon/MuonAnalysisResultTableTab.h
                 inc/MantidQtCustomInterfaces/Muon/MuonSequentialFitDialog.h
                 inc/MantidQtCustomInterfaces/Reflectometry/ReflSearchModel.h
                 inc/MantidQtCustomInterfaces/Reflectometry/QtReflRunsTabView.h
+                inc/MantidQtCustomInterfaces/Reflectometry/QtReflSaveTabView.h
                 inc/MantidQtCustomInterfaces/Reflectometry/QtReflSettingsTabView.h
+                inc/MantidQtCustomInterfaces/Reflectometry/QtReflSettingsView.h
                 inc/MantidQtCustomInterfaces/SampleTransmission.h
                 inc/MantidQtCustomInterfaces/SANSBackgroundCorrectionWidget.h
                 inc/MantidQtCustomInterfaces/SANSAddFiles.h
@@ -413,7 +433,9 @@ set ( MOC_FILES inc/MantidQtCustomInterfaces/Background.h
                 inc/MantidQtCustomInterfaces/Tomography/ImggFormatsConvertViewQtWidget.h
                 inc/MantidQtCustomInterfaces/Tomography/TomographyIfacePresenter.h
                 inc/MantidQtCustomInterfaces/Tomography/TomographyIfaceViewQtGUI.h
-                inc/MantidQtCustomInterfaces/Tomography/TomoToolConfigDialog.h
+                inc/MantidQtCustomInterfaces/Tomography/TomoToolConfigDialogSavu.h								
+                inc/MantidQtCustomInterfaces/Tomography/TomographyProcess.h								
+                inc/MantidQtCustomInterfaces/Tomography/TomographyThread.h
 )
 
 set ( UI_FILES inc/MantidQtCustomInterfaces/DataComparison.ui
@@ -472,10 +494,12 @@ set ( UI_FILES inc/MantidQtCustomInterfaces/DataComparison.ui
                inc/MantidQtCustomInterfaces/Muon/ALCInterface.ui
                inc/MantidQtCustomInterfaces/Muon/ALCPeakFittingView.ui
                inc/MantidQtCustomInterfaces/Muon/MuonAnalysis.ui
-			   inc/MantidQtCustomInterfaces/Muon/MuonSequentialFitDialog.ui
+               inc/MantidQtCustomInterfaces/Muon/MuonSequentialFitDialog.ui
                inc/MantidQtCustomInterfaces/Reflectometry/ReflMainWindowWidget.ui
                inc/MantidQtCustomInterfaces/Reflectometry/ReflRunsTabWidget.ui
+               inc/MantidQtCustomInterfaces/Reflectometry/ReflSaveTabWidget.ui
                inc/MantidQtCustomInterfaces/Reflectometry/ReflSettingsTabWidget.ui
+               inc/MantidQtCustomInterfaces/Reflectometry/ReflSettingsWidget.ui
                inc/MantidQtCustomInterfaces/Reflectometry/ReflWindow.ui
                inc/MantidQtCustomInterfaces/SampleTransmission.ui
                inc/MantidQtCustomInterfaces/SANSBackgroundCorrectionWidget.ui
@@ -517,11 +541,13 @@ set ( TEST_FILES
 	MuonAnalysisFitFunctionPresenterTest.h
 	MuonAnalysisHelperTest.h
 	MuonAnalysisResultTableCreatorTest.h
-	ReflLegacyTransferStrategyTest.h
+  ReflLegacyTransferStrategyTest.h
 	ReflMainWindowPresenterTest.h
 	ReflMeasureTransferStrategyTest.h
 	ReflNexusMeasurementItemSourceTest.h
 	ReflRunsTabPresenterTest.h
+	ReflSaveTabPresenterTest.h
+	ReflSettingsPresenterTest.h
 	ReflSettingsTabPresenterTest.h
 	StackOfImagesDirsTest.h
 	TomographyIfaceModelTest.h
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/DirectConvertToEnergy.ui b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/DirectConvertToEnergy.ui
index 5972eb26dba100b41fbb7e6d4d28a62cba581896..4fc4ab9799ecdda23ea9628d61b6147d44ecdf2b 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/DirectConvertToEnergy.ui
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/DirectConvertToEnergy.ui
@@ -113,7 +113,7 @@
                  <number>6</number>
                 </property>
                 <item>
-                 <widget class="MantidQt::MantidWidgets::MWRunFiles" name="runFiles" native="true">
+                 <widget class="MantidQt::API::MWRunFiles" name="runFiles" native="true">
                   <property name="label" stdset="0">
                    <string>Runs          </string>
                   </property>
@@ -129,7 +129,7 @@
                </layout>
               </item>
               <item>
-               <widget class="MantidQt::MantidWidgets::MWRunFiles" name="mapFile" native="true">
+               <widget class="MantidQt::API::MWRunFiles" name="mapFile" native="true">
                 <property name="findRunFiles" stdset="0">
                  <bool>false</bool>
                 </property>
@@ -148,7 +148,7 @@
                </widget>
               </item>
               <item>
-               <widget class="MantidQt::MantidWidgets::MWRunFiles" name="whiteBeamFile" native="true">
+               <widget class="MantidQt::API::MWRunFiles" name="whiteBeamFile" native="true">
                 <property name="label" stdset="0">
                  <string>Detector Vanadium</string>
                 </property>
@@ -888,14 +888,14 @@
          </property>
          <layout class="QVBoxLayout" name="verticalLayout_31">
           <item>
-           <widget class="MantidQt::MantidWidgets::MWRunFiles" name="absRunFiles" native="true">
+           <widget class="MantidQt::API::MWRunFiles" name="absRunFiles" native="true">
             <property name="label" stdset="0">
              <string>Abs Units Vanadium</string>
             </property>
            </widget>
           </item>
           <item>
-           <widget class="MantidQt::MantidWidgets::MWRunFiles" name="absMapFile" native="true">
+           <widget class="MantidQt::API::MWRunFiles" name="absMapFile" native="true">
             <property name="findRunFiles" stdset="0">
              <bool>false</bool>
             </property>
@@ -914,7 +914,7 @@
            </widget>
           </item>
           <item>
-           <widget class="MantidQt::MantidWidgets::MWRunFiles" name="absWhiteFile" native="true">
+           <widget class="MantidQt::API::MWRunFiles" name="absWhiteFile" native="true">
             <property name="label" stdset="0">
              <string>Detector Vanadium (Abs Units)</string>
             </property>
@@ -1309,9 +1309,9 @@
  </widget>
  <customwidgets>
   <customwidget>
-   <class>MantidQt::MantidWidgets::MWRunFiles</class>
+   <class>MantidQt::API::MWRunFiles</class>
    <extends>QWidget</extends>
-   <header>MantidQtMantidWidgets/MWRunFiles.h</header>
+   <header>MantidQtAPI/MWRunFiles.h</header>
   </customwidget>
   <customwidget>
    <class>MantidQt::MantidWidgets::InstrumentSelector</class>
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionQtTabCalib.ui b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionQtTabCalib.ui
index 7b7bd2d41555f673d37b695090aa893fc0524c11..e4d0a1c9b671e8d9bfd7ee27b5d00248b7991c99 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionQtTabCalib.ui
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionQtTabCalib.ui
@@ -151,7 +151,7 @@
            </widget>
           </item>
           <item>
-           <widget class="MantidQt::MantidWidgets::MWRunFiles" name="MWRunFiles_new_vanadium_num" native="true">
+           <widget class="MantidQt::API::MWRunFiles" name="MWRunFiles_new_vanadium_num" native="true">
             <property name="text" stdset="0">
              <string>236516</string>
             </property>
@@ -175,7 +175,7 @@
            </widget>
           </item>
           <item>
-           <widget class="MantidQt::MantidWidgets::MWRunFiles" name="MWRunFiles_new_ceria_num" native="true">
+           <widget class="MantidQt::API::MWRunFiles" name="MWRunFiles_new_ceria_num" native="true">
             <property name="text" stdset="0">
              <string>241391</string>
             </property>
@@ -430,9 +430,9 @@
  </widget>
  <customwidgets>
   <customwidget>
-   <class>MantidQt::MantidWidgets::MWRunFiles</class>
+   <class>MantidQt::API::MWRunFiles</class>
    <extends>QWidget</extends>
-   <header>MantidQtMantidWidgets/MWRunFiles.h</header>
+   <header>MantidQtAPI/MWRunFiles.h</header>
   </customwidget>
  </customwidgets>
  <resources/>
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionQtTabFocus.ui b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionQtTabFocus.ui
index a8e60152cc6943fe3424ef129e915c510a83936e..8dfd9f2a564799bb5abe84c966a4f1691a517fb2 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionQtTabFocus.ui
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionQtTabFocus.ui
@@ -131,7 +131,7 @@
          </spacer>
         </item>
         <item>
-         <widget class="MantidQt::MantidWidgets::MWRunFiles" name="MWRunFiles_run_num" native="true">
+         <widget class="MantidQt::API::MWRunFiles" name="MWRunFiles_run_num" native="true">
           <property name="text" stdset="0">
            <string/>
           </property>
@@ -189,7 +189,7 @@
          </spacer>
         </item>
         <item>
-         <widget class="MantidQt::MantidWidgets::MWRunFiles" name="MWRunFiles_cropped_run_num" native="true">
+         <widget class="MantidQt::API::MWRunFiles" name="MWRunFiles_cropped_run_num" native="true">
           <property name="text" stdset="0">
            <string/>
           </property>
@@ -305,7 +305,7 @@
          </spacer>
         </item>
         <item>
-         <widget class="MantidQt::MantidWidgets::MWRunFiles" name="MWRunFiles_texture_run_num" native="true">
+         <widget class="MantidQt::API::MWRunFiles" name="MWRunFiles_texture_run_num" native="true">
           <property name="text" stdset="0">
            <string/>
           </property>
@@ -644,9 +644,9 @@
  </widget>
  <customwidgets>
   <customwidget>
-   <class>MantidQt::MantidWidgets::MWRunFiles</class>
+   <class>MantidQt::API::MWRunFiles</class>
    <extends>QWidget</extends>
-   <header>MantidQtMantidWidgets/MWRunFiles.h</header>
+   <header>MantidQtAPI/MWRunFiles.h</header>
   </customwidget>
  </customwidgets>
  <resources/>
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionQtTabPreproc.ui b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionQtTabPreproc.ui
index 3e16a807eabe7ec4f2608768e46c5ef3c995ab18..6723e98dacaa217084075feb0f21d1ea9f13c354 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionQtTabPreproc.ui
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionQtTabPreproc.ui
@@ -37,7 +37,7 @@
       </spacer>
      </item>
      <item>
-      <widget class="MantidQt::MantidWidgets::MWRunFiles" name="MWRunFiles_preproc_run_num" native="true">
+      <widget class="MantidQt::API::MWRunFiles" name="MWRunFiles_preproc_run_num" native="true">
        <property name="text" stdset="0">
         <string/>
        </property>
@@ -251,9 +251,9 @@
  </widget>
  <customwidgets>
   <customwidget>
-   <class>MantidQt::MantidWidgets::MWRunFiles</class>
+   <class>MantidQt::API::MWRunFiles</class>
    <extends>QWidget</extends>
-   <header>MantidQtMantidWidgets/MWRunFiles.h</header>
+   <header>MantidQtAPI/MWRunFiles.h</header>
   </customwidget>
  </customwidgets>
  <resources/>
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/DensityOfStates.ui b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/DensityOfStates.ui
index 49f0e38fe22e5473a8bba11b4a80c44ef818217f..f04057a83e832d2734fa13ff7e91e0abc9888742 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/DensityOfStates.ui
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/DensityOfStates.ui
@@ -21,7 +21,7 @@
      </property>
      <layout class="QGridLayout" name="gridLayout">
       <item row="0" column="0">
-       <widget class="MantidQt::MantidWidgets::MWRunFiles" name="mwInputFile" native="true">
+       <widget class="MantidQt::API::MWRunFiles" name="mwInputFile" native="true">
         <property name="sizePolicy">
          <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
           <horstretch>0</horstretch>
@@ -537,9 +537,9 @@
  </widget>
  <customwidgets>
   <customwidget>
-   <class>MantidQt::MantidWidgets::MWRunFiles</class>
+   <class>MantidQt::API::MWRunFiles</class>
    <extends>QWidget</extends>
-   <header>MantidQtMantidWidgets/MWRunFiles.h</header>
+   <header>MantidQtAPI/MWRunFiles.h</header>
   </customwidget>
  </customwidgets>
  <tabstops>
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/Elwin.ui b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/Elwin.ui
index 58549540f082cf26e4bd0c36e20e748caa9333d3..54113cd8d662a0245a7eb30d8c423e46e32898d9 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/Elwin.ui
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/Elwin.ui
@@ -21,7 +21,7 @@
      </property>
      <layout class="QHBoxLayout" name="horizontalLayout_16">
       <item>
-       <widget class="MantidQt::MantidWidgets::MWRunFiles" name="dsInputFiles" native="true">
+       <widget class="MantidQt::API::MWRunFiles" name="dsInputFiles" native="true">
         <property name="sizePolicy">
          <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
           <horstretch>0</horstretch>
@@ -206,9 +206,9 @@
  </widget>
  <customwidgets>
   <customwidget>
-   <class>MantidQt::MantidWidgets::MWRunFiles</class>
+   <class>MantidQt::API::MWRunFiles</class>
    <extends>QWidget</extends>
-   <header>MantidQtMantidWidgets/MWRunFiles.h</header>
+   <header>MantidQtAPI/MWRunFiles.h</header>
   </customwidget>
   <customwidget>
    <class>MantidQt::MantidWidgets::PreviewPlot</class>
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/ILLCalibration.ui b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/ILLCalibration.ui
index 58d4b6665b3fb8d8fb5e362b892cfa0d420bab15..f5be5a0e82a51711121602a943952b10df637cce 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/ILLCalibration.ui
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/ILLCalibration.ui
@@ -7,7 +7,7 @@
     <x>0</x>
     <y>0</y>
     <width>500</width>
-    <height>326</height>
+    <height>344</height>
    </rect>
   </property>
   <property name="minimumSize">
@@ -20,6 +20,16 @@
    <string>Form</string>
   </property>
   <layout class="QVBoxLayout" name="verticalLayout_10">
+   <item alignment="Qt::AlignTop">
+    <widget class="QLabel" name="label">
+     <property name="styleSheet">
+      <string notr="true">background:rgb(255, 251, 125)</string>
+     </property>
+     <property name="text">
+      <string>This tab is deprecated. Use CalibrationRun in Energy Transfer tab.</string>
+     </property>
+    </widget>
+   </item>
    <item>
     <widget class="QGroupBox" name="gbInput">
      <property name="title">
@@ -27,7 +37,7 @@
      </property>
      <layout class="QHBoxLayout" name="horizontalLayout_2">
       <item>
-       <widget class="MantidQt::MantidWidgets::MWRunFiles" name="rfRunFile" native="true">
+       <widget class="MantidQt::API::MWRunFiles" name="rfRunFile" native="true">
         <property name="label" stdset="0">
          <string>Run File</string>
         </property>
@@ -64,13 +74,22 @@
         <widget class="QWidget" name="pgCGDefault"/>
         <widget class="QWidget" name="pgCGMapFile">
          <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>
-           <widget class="MantidQt::MantidWidgets::MWRunFiles" name="rfMapFile" native="true">
+           <widget class="MantidQt::API::MWRunFiles" name="rfMapFile" native="true">
             <property name="label" stdset="0">
-             <string></string>
+             <string/>
             </property>
             <property name="fileExtensions" stdset="0">
              <stringlist>
@@ -88,6 +107,12 @@
    </item>
    <item>
     <widget class="QGroupBox" name="gbCalibration">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
      <property name="title">
       <string>Calibration</string>
      </property>
@@ -230,9 +255,9 @@
  </widget>
  <customwidgets>
   <customwidget>
-   <class>MantidQt::MantidWidgets::MWRunFiles</class>
+   <class>MantidQt::API::MWRunFiles</class>
    <extends>QWidget</extends>
-   <header>MantidQtMantidWidgets/MWRunFiles.h</header>
+   <header>MantidQtAPI/MWRunFiles.h</header>
    <container>1</container>
   </customwidget>
  </customwidgets>
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/ILLEnergyTransfer.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/ILLEnergyTransfer.h
index c4e8e634ee52da391ef5eebba0f2ce63ab340098..04ffa09f590186cb84dc64a5d243f5b90d80288f 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/ILLEnergyTransfer.h
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/ILLEnergyTransfer.h
@@ -52,6 +52,12 @@ private slots:
 
 private:
   Ui::ILLEnergyTransfer m_uiForm;
+  double m_backScaling = 1.;
+  double m_peakRange[2];
+  int m_pixelRange[2];
+  void save();
+  void plot();
+  void convertTo2Theta();
 };
 } // namespace CustomInterfaces
 } // namespace Mantid
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/ILLEnergyTransfer.ui b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/ILLEnergyTransfer.ui
index dde6a058d5dfb7e4a4ac2a1b0a55164eea547e1e..5a6f59d938ebe022efe069ad21db8305209cfe9b 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/ILLEnergyTransfer.ui
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/ILLEnergyTransfer.ui
@@ -7,68 +7,241 @@
     <x>0</x>
     <y>0</y>
     <width>600</width>
-    <height>330</height>
+    <height>518</height>
    </rect>
   </property>
+  <property name="sizePolicy">
+   <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+    <horstretch>0</horstretch>
+    <verstretch>0</verstretch>
+   </sizepolicy>
+  </property>
   <property name="minimumSize">
    <size>
-    <width>500</width>
+    <width>600</width>
     <height>0</height>
    </size>
   </property>
   <property name="windowTitle">
    <string>Form</string>
   </property>
+  <property name="styleSheet">
+   <string notr="true"/>
+  </property>
   <layout class="QVBoxLayout" name="loMain">
    <item>
     <widget class="QGroupBox" name="gbInput">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
      <property name="title">
-      <string>Input</string>
+      <string>Input File(s)</string>
      </property>
      <layout class="QHBoxLayout" name="horizontalLayout_2">
       <item>
-       <widget class="MantidQt::MantidWidgets::MWRunFiles" name="rfInput" native="true">
+       <widget class="MantidQt::API::MWRunFiles" name="rfInput" native="true">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="toolTip">
+         <string>Input files</string>
+        </property>
         <property name="label" stdset="0">
          <string>Run File</string>
         </property>
+        <property name="multipleFiles" stdset="0">
+         <bool>true</bool>
+        </property>
+        <property name="algorithmAndProperty" stdset="0">
+         <string>IndirectILLReductionQENS|Run</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QCheckBox" name="ckSum">
+        <property name="enabled">
+         <bool>true</bool>
+        </property>
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="toolTip">
+         <string>Sum all the input files</string>
+        </property>
+        <property name="text">
+         <string>Sum All Runs</string>
+        </property>
+        <property name="checked">
+         <bool>false</bool>
+        </property>
        </widget>
       </item>
+      <item>
+       <spacer name="horizontalSpacer_2">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeType">
+         <enum>QSizePolicy::Ignored</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>40</width>
+          <height>20</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
      </layout>
     </widget>
    </item>
    <item>
-    <widget class="QGroupBox" name="gbCalibration">
+    <widget class="QGroupBox" name="gbType">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="minimumSize">
+      <size>
+       <width>0</width>
+       <height>80</height>
+      </size>
+     </property>
      <property name="title">
-      <string>Calibration</string>
+      <string>Reduction Type</string>
      </property>
-     <layout class="QVBoxLayout" name="verticalLayout_2">
+     <layout class="QHBoxLayout" name="horizontalLayout_8">
       <item>
-       <widget class="QCheckBox" name="ckUseCalibration">
+       <widget class="QRadioButton" name="rdQENS">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="toolTip">
+         <string>Quasi-Elastic Neutron Scattering</string>
+        </property>
         <property name="text">
-         <string>Use Calibration</string>
+         <string>QENS</string>
+        </property>
+        <property name="checked">
+         <bool>true</bool>
         </property>
+        <attribute name="buttonGroup">
+         <string notr="true">buttonGroup</string>
+        </attribute>
        </widget>
       </item>
       <item>
-       <widget class="MantidQt::MantidWidgets::DataSelector" name="dsCalibration" native="true">
-        <property name="enabled">
+       <widget class="QRadioButton" name="rdFWS">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="toolTip">
+         <string>Elastic/Inelastic Fixed Window Scan</string>
+        </property>
+        <property name="text">
+         <string>E/I - FWS</string>
+        </property>
+        <property name="checked">
+         <bool>false</bool>
+        </property>
+        <attribute name="buttonGroup">
+         <string notr="true">buttonGroup</string>
+        </attribute>
+       </widget>
+      </item>
+      <item>
+       <widget class="Line" name="line_5">
+        <property name="orientation">
+         <enum>Qt::Vertical</enum>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QCheckBox" name="cbCrop">
+        <property name="toolTip">
+         <string>Whether or not to crop the first and last channels with zero monitor count</string>
+        </property>
+        <property name="text">
+         <string>Crop Dead Monitor Channels</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QLabel" name="lbObservable">
+        <property name="visible">
          <bool>false</bool>
         </property>
-        <property name="autoLoad" stdset="0">
+        <property name="text">
+         <string>Observable</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QComboBox" name="cbObservable">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="visible">
+         <bool>false</bool>
+        </property>
+        <property name="toolTip">
+         <string>Select or type the desired observable. See Sample Logs for the list of valid parameters.</string>
+        </property>
+        <property name="editable">
          <bool>true</bool>
         </property>
-        <property name="showLoad" stdset="0">
+        <item>
+         <property name="text">
+          <string>sample.temperature</string>
+         </property>
+        </item>
+        <item>
+         <property name="text">
+          <string>sample.pressure</string>
+         </property>
+        </item>
+        <item>
+         <property name="text">
+          <string>start_time</string>
+         </property>
+        </item>
+        <item>
+         <property name="text">
+          <string>run_number</string>
+         </property>
+        </item>
+       </widget>
+      </item>
+      <item>
+       <widget class="QCheckBox" name="cbSortX">
+        <property name="visible">
          <bool>false</bool>
         </property>
-        <property name="workspaceSuffixes" stdset="0">
-         <stringlist>
-          <string>_calib</string>
-         </stringlist>
+        <property name="toolTip">
+         <string>Whether or not to sort the x-axis.</string>
         </property>
-        <property name="fileBrowserSuffixes" stdset="0">
-         <stringlist>
-          <string>_calib.nxs</string>
-         </stringlist>
+        <property name="text">
+         <string>SortXAxis</string>
         </property>
        </widget>
       </item>
@@ -77,28 +250,102 @@
    </item>
    <item>
     <widget class="QGroupBox" name="gbGrouping">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="minimumSize">
+      <size>
+       <width>0</width>
+       <height>80</height>
+      </size>
+     </property>
      <property name="title">
-      <string>Grouping</string>
+      <string>Detector Grouping</string>
      </property>
      <layout class="QHBoxLayout" name="horizontalLayout_3">
       <item>
-       <widget class="QComboBox" name="cbGroupingType">
-        <item>
-         <property name="text">
-          <string>Default</string>
-         </property>
-        </item>
-        <item>
-         <property name="text">
-          <string>File</string>
-         </property>
-        </item>
+       <widget class="QRadioButton" name="rdGroupDefault">
+        <property name="toolTip">
+         <string>By default, all the pixels of each tube will be summed.</string>
+        </property>
+        <property name="text">
+         <string>Default</string>
+        </property>
+        <property name="checked">
+         <bool>true</bool>
+        </property>
+        <attribute name="buttonGroup">
+         <string notr="true">buttonGroup_2</string>
+        </attribute>
+       </widget>
+      </item>
+      <item alignment="Qt::AlignLeft">
+       <widget class="QRadioButton" name="rdGroupRange">
+        <property name="toolTip">
+         <string>Choose the pixel range manually, will be applied to all PSD tubes.</string>
+        </property>
+        <property name="text">
+         <string>Choose Range</string>
+        </property>
+        <attribute name="buttonGroup">
+         <string notr="true">buttonGroup_2</string>
+        </attribute>
+       </widget>
+      </item>
+      <item alignment="Qt::AlignLeft">
+       <widget class="QRadioButton" name="rdGroupChoose">
+        <property name="toolTip">
+         <string>Choose a detector grouping file, if separate range is needed per each PSD tube.</string>
+        </property>
+        <property name="text">
+         <string>Choose File</string>
+        </property>
+        <attribute name="buttonGroup">
+         <string notr="true">buttonGroup_2</string>
+        </attribute>
+       </widget>
+      </item>
+      <item alignment="Qt::AlignLeft">
+       <widget class="QLineEdit" name="lePixelRange">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="minimumSize">
+         <size>
+          <width>75</width>
+          <height>0</height>
+         </size>
+        </property>
+        <property name="visible">
+         <bool>false</bool>
+        </property>
+        <property name="toolTip">
+         <string>Pixel range to sum for each PSD tube, e.g. 1,128</string>
+        </property>
+        <property name="text">
+         <string>1,128</string>
+        </property>
        </widget>
       </item>
       <item>
        <widget class="QStackedWidget" name="swGroupingTypes">
+        <property name="enabled">
+         <bool>true</bool>
+        </property>
+        <property name="toolTip">
+         <string/>
+        </property>
         <property name="currentIndex">
-         <number>0</number>
+         <number>1</number>
+        </property>
+        <property name="algorithmAndProperty" stdset="0">
+         <string>IndirectILLReductionQENS|MapFile</string>
         </property>
         <widget class="QWidget" name="pgILLMapDefault"/>
         <widget class="QWidget" name="pgILLMapFile">
@@ -109,14 +356,21 @@
           <property name="bottomMargin">
            <number>0</number>
           </property>
-          <item>
-           <widget class="MantidQt::MantidWidgets::MWRunFiles" name="rfMapFile" native="true">
+          <item alignment="Qt::AlignVCenter">
+           <widget class="MantidQt::API::MWRunFiles" name="rfMapFile" native="true">
+            <property name="visible">
+             <bool>false</bool>
+            </property>
+            <property name="toolTip">
+             <string>Choose an .xml or .map file for detector grouping</string>
+            </property>
             <property name="label" stdset="0">
-             <string></string>
+             <string/>
             </property>
             <property name="fileExtensions" stdset="0">
              <stringlist>
               <string>.xml</string>
+              <string>.map</string>
              </stringlist>
             </property>
            </widget>
@@ -129,15 +383,107 @@
     </widget>
    </item>
    <item>
-    <widget class="QGroupBox" name="gbOptions">
+    <widget class="QGroupBox" name="gbBackground">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
      <property name="title">
-      <string>Options</string>
+      <string>Background Subtraction</string>
      </property>
-     <layout class="QVBoxLayout" name="verticalLayout">
-      <item>
-       <widget class="QCheckBox" name="ckMirrorMode">
+     <layout class="QGridLayout" name="gridLayout">
+      <item row="0" column="2">
+       <widget class="QLineEdit" name="leBackgroundFactor">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="maximumSize">
+         <size>
+          <width>50</width>
+          <height>16777215</height>
+         </size>
+        </property>
+        <property name="text">
+         <string>1.0</string>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="1">
+       <widget class="QLabel" name="lbScale">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="text">
+         <string>Scaling Factor</string>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="4">
+       <widget class="QComboBox" name="cbBackOption">
+        <property name="visible">
+         <bool>false</bool>
+        </property>
+        <property name="toolTip">
+         <string>Background subtraction option</string>
+        </property>
+        <item>
+         <property name="text">
+          <string>Sum</string>
+         </property>
+        </item>
+        <item>
+         <property name="text">
+          <string>Interpolate</string>
+         </property>
+        </item>
+       </widget>
+      </item>
+      <item row="0" column="0">
+       <widget class="MantidQt::API::MWRunFiles" name="rfBackgroundRun" native="true">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="minimumSize">
+         <size>
+          <width>230</width>
+          <height>20</height>
+         </size>
+        </property>
+        <property name="toolTip">
+         <string>Background files (empty can)</string>
+        </property>
+        <property name="algorithmAndProperty" stdset="0">
+         <string>IndirectILLReductionQENS|BackgroundRun</string>
+        </property>
+        <property name="label" stdset="0">
+         <string>Background File</string>
+        </property>
+        <property name="multipleFiles" stdset="0">
+         <bool>true</bool>
+        </property>
+        <property name="optional" stdset="0">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="3">
+       <widget class="QLabel" name="lbBackOption">
+        <property name="visible">
+         <bool>false</bool>
+        </property>
         <property name="text">
-         <string>Use Mirror Mode</string>
+         <string>Option</string>
         </property>
        </widget>
       </item>
@@ -145,110 +491,804 @@
     </widget>
    </item>
    <item>
-    <spacer name="verticalSpacer">
-     <property name="orientation">
-      <enum>Qt::Vertical</enum>
-     </property>
-     <property name="sizeHint" stdset="0">
-      <size>
-       <width>20</width>
-       <height>0</height>
-      </size>
+    <widget class="QGroupBox" name="gbCalibration">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
      </property>
-    </spacer>
-   </item>
-   <item>
-    <widget class="QGroupBox" name="gbOutput">
      <property name="title">
-      <string>Output</string>
+      <string>Detector Calibration</string>
      </property>
-     <layout class="QHBoxLayout" name="horizontalLayout">
-      <item>
-       <widget class="QCheckBox" name="ckPlot">
+     <layout class="QGridLayout" name="gridLayout_2">
+      <item row="0" column="1">
+       <widget class="QLabel" name="lbPeakRange">
         <property name="text">
-         <string>Plot Result</string>
+         <string>Peak Range</string>
         </property>
        </widget>
       </item>
-      <item>
-       <spacer name="horizontalSpacer">
-        <property name="orientation">
-         <enum>Qt::Horizontal</enum>
+      <item row="0" column="2">
+       <widget class="QLineEdit" name="lePeakRange">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
         </property>
-        <property name="sizeHint" stdset="0">
+        <property name="toolTip">
+         <string>Peak integration range for calibration (in mev).</string>
+        </property>
+        <property name="text">
+         <string>-0.003,0.003</string>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="3">
+       <widget class="QLabel" name="lbCalibOption">
+        <property name="visible">
+         <bool>false</bool>
+        </property>
+        <property name="text">
+         <string>Option</string>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="0">
+       <widget class="MantidQt::API::MWRunFiles" name="rfCalibrationRun" native="true">
+        <property name="enabled">
+         <bool>true</bool>
+        </property>
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="minimumSize">
          <size>
-          <width>40</width>
+          <width>0</width>
           <height>20</height>
          </size>
         </property>
-       </spacer>
+        <property name="toolTip">
+         <string>Calibration files (vanadium)</string>
+        </property>
+        <property name="label" stdset="0">
+         <string>Calibration File </string>
+        </property>
+        <property name="algorithmAndProperty" stdset="0">
+         <string>IndirectILLReductionQENS|CalibrationRun</string>
+        </property>
+        <property name="multipleFiles" stdset="0">
+         <bool>true</bool>
+        </property>
+        <property name="optional" stdset="0">
+         <bool>true</bool>
+        </property>
+       </widget>
       </item>
-      <item>
-       <widget class="QCheckBox" name="ckSave">
-        <property name="text">
-         <string>Save Result</string>
+      <item row="0" column="4">
+       <widget class="QComboBox" name="cbCalibOption">
+        <property name="visible">
+         <bool>false</bool>
         </property>
+        <property name="toolTip">
+         <string>Detector calibration option</string>
+        </property>
+        <item>
+         <property name="text">
+          <string>Sum</string>
+         </property>
+        </item>
+        <item>
+         <property name="text">
+          <string>Interpolate</string>
+         </property>
+        </item>
        </widget>
       </item>
      </layout>
     </widget>
    </item>
-  </layout>
- </widget>
- <customwidgets>
-  <customwidget>
-   <class>MantidQt::MantidWidgets::MWRunFiles</class>
-   <extends>QWidget</extends>
-   <header>MantidQtMantidWidgets/MWRunFiles.h</header>
-   <container>1</container>
-  </customwidget>
-  <customwidget>
-   <class>MantidQt::MantidWidgets::DataSelector</class>
-   <extends>QWidget</extends>
-   <header>MantidQtMantidWidgets/DataSelector.h</header>
-   <container>1</container>
-  </customwidget>
+   <item>
+    <widget class="QGroupBox" name="gbOptions">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="title">
+      <string>Unmirror Options</string>
+     </property>
+     <layout class="QGridLayout" name="gridLayout_3">
+      <item row="0" column="3">
+       <widget class="MantidQt::API::MWRunFiles" name="rfAlignmentRun" native="true">
+        <property name="enabled">
+         <bool>true</bool>
+        </property>
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="minimumSize">
+         <size>
+          <width>0</width>
+          <height>0</height>
+         </size>
+        </property>
+        <property name="toolTip">
+         <string>Alignment files (vanadium) for unmirror option 5 or 7</string>
+        </property>
+        <property name="label" stdset="0">
+         <string>Alignment Run </string>
+        </property>
+        <property name="algorithmAndProperty" stdset="0">
+         <string>IndirectILLReductionQENS|AlignmentRun</string>
+        </property>
+        <property name="multipleFiles" stdset="0">
+         <bool>true</bool>
+        </property>
+        <property name="optional" stdset="0">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="0">
+       <widget class="QLabel" name="lbUnmirror">
+        <property name="text">
+         <string>Unmirror Option</string>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="1">
+       <widget class="QSpinBox" name="sbUnmirrorOption">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="toolTip">
+         <string>Unmirroring options:
+0 no unmirroring
+1 sum of left and right
+2 left
+3 right
+4 shift right according to left and sum
+5 shift right according to Vanadium run for peak positions
+6 center both left and right at zero and sum
+7 shift both left and right according to Vanadium run for peak positions</string>
+        </property>
+        <property name="minimum">
+         <number>0</number>
+        </property>
+        <property name="maximum">
+         <number>7</number>
+        </property>
+        <property name="value">
+         <number>6</number>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="QGroupBox" name="gbOutput">
+     <property name="title">
+      <string>Output Options</string>
+     </property>
+     <layout class="QHBoxLayout" name="horizontalLayout">
+      <item>
+       <widget class="QCheckBox" name="ckPlot">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="toolTip">
+         <string>Plot the reduced workspace</string>
+        </property>
+        <property name="text">
+         <string>Plot Result</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="Line" name="line">
+        <property name="orientation">
+         <enum>Qt::Vertical</enum>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QLabel" name="lbOut">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="minimumSize">
+         <size>
+          <width>0</width>
+          <height>0</height>
+         </size>
+        </property>
+        <property name="text">
+         <string>Output Name:</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QLineEdit" name="leOutWS">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="toolTip">
+         <string>Output workspace name</string>
+        </property>
+        <property name="text">
+         <string>sample</string>
+        </property>
+        <property name="placeholderText">
+         <string>result</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QCheckBox" name="ck2Theta">
+        <property name="toolTip">
+         <string>Convert the y-axis of the output also to 2theta.</string>
+        </property>
+        <property name="text">
+         <string>Convert to 2Theta</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="Line" name="line_2">
+        <property name="orientation">
+         <enum>Qt::Vertical</enum>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QCheckBox" name="ckSave">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="toolTip">
+         <string>Save the reduced workspace</string>
+        </property>
+        <property name="text">
+         <string>Save Result</string>
+        </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>0</width>
+       <height>5</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+  </layout>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>MantidQt::API::MWRunFiles</class>
+   <extends>QWidget</extends>
+   <header>MantidQtAPI/MWRunFiles.h</header>
+   <container>1</container>
+  </customwidget>
  </customwidgets>
- <tabstops>
-  <tabstop>ckUseCalibration</tabstop>
-  <tabstop>cbGroupingType</tabstop>
-  <tabstop>ckMirrorMode</tabstop>
-  <tabstop>ckPlot</tabstop>
-  <tabstop>ckSave</tabstop>
- </tabstops>
  <resources/>
  <connections>
   <connection>
-   <sender>cbGroupingType</sender>
-   <signal>currentIndexChanged(int)</signal>
-   <receiver>swGroupingTypes</receiver>
-   <slot>setCurrentIndex(int)</slot>
+   <sender>rdQENS</sender>
+   <signal>clicked(bool)</signal>
+   <receiver>cbObservable</receiver>
+   <slot>setHidden(bool)</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>70</x>
+     <y>116</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>499</x>
+     <y>116</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>rdFWS</sender>
+   <signal>clicked(bool)</signal>
+   <receiver>cbObservable</receiver>
+   <slot>setVisible(bool)</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>171</x>
+     <y>116</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>499</x>
+     <y>116</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>rdQENS</sender>
+   <signal>clicked(bool)</signal>
+   <receiver>lbObservable</receiver>
+   <slot>setHidden(bool)</slot>
    <hints>
     <hint type="sourcelabel">
-     <x>80</x>
-     <y>230</y>
+     <x>70</x>
+     <y>116</y>
     </hint>
     <hint type="destinationlabel">
-     <x>343</x>
-     <y>161</y>
+     <x>373</x>
+     <y>115</y>
     </hint>
    </hints>
   </connection>
   <connection>
-   <sender>ckUseCalibration</sender>
-   <signal>toggled(bool)</signal>
-   <receiver>dsCalibration</receiver>
-   <slot>setEnabled(bool)</slot>
+   <sender>rdFWS</sender>
+   <signal>clicked(bool)</signal>
+   <receiver>lbObservable</receiver>
+   <slot>setVisible(bool)</slot>
    <hints>
     <hint type="sourcelabel">
-     <x>65</x>
-     <y>88</y>
+     <x>171</x>
+     <y>116</y>
     </hint>
     <hint type="destinationlabel">
-     <x>87</x>
+     <x>373</x>
+     <y>115</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>rdFWS</sender>
+   <signal>clicked(bool)</signal>
+   <receiver>ckSum</receiver>
+   <slot>setHidden(bool)</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>171</x>
+     <y>116</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>536</x>
+     <y>45</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>rdQENS</sender>
+   <signal>clicked(bool)</signal>
+   <receiver>ckSum</receiver>
+   <slot>setVisible(bool)</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>70</x>
+     <y>116</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>536</x>
+     <y>45</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>rdGroupDefault</sender>
+   <signal>clicked(bool)</signal>
+   <receiver>rfMapFile</receiver>
+   <slot>setHidden(bool)</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>59</x>
+     <y>245</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>391</x>
+     <y>244</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>rdGroupChoose</sender>
+   <signal>clicked(bool)</signal>
+   <receiver>rfMapFile</receiver>
+   <slot>setVisible(bool)</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>151</x>
+     <y>245</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>391</x>
+     <y>244</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>rdFWS</sender>
+   <signal>clicked(bool)</signal>
+   <receiver>gbOptions</receiver>
+   <slot>setHidden(bool)</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>218</x>
+     <y>112</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>295</x>
+     <y>359</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>rdQENS</sender>
+   <signal>clicked(bool)</signal>
+   <receiver>gbOptions</receiver>
+   <slot>setVisible(bool)</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>85</x>
+     <y>112</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>295</x>
+     <y>359</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>rdQENS</sender>
+   <signal>clicked(bool)</signal>
+   <receiver>cbSortX</receiver>
+   <slot>setHidden(bool)</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>55</x>
+     <y>113</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>531</x>
+     <y>112</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>rdFWS</sender>
+   <signal>clicked(bool)</signal>
+   <receiver>cbSortX</receiver>
+   <slot>setVisible(bool)</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>136</x>
+     <y>113</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>531</x>
+     <y>112</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>rdQENS</sender>
+   <signal>clicked(bool)</signal>
+   <receiver>cbCrop</receiver>
+   <slot>setVisible(bool)</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>55</x>
+     <y>109</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>390</x>
+     <y>108</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>rdFWS</sender>
+   <signal>clicked(bool)</signal>
+   <receiver>cbCrop</receiver>
+   <slot>setHidden(bool)</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>134</x>
+     <y>109</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>390</x>
+     <y>108</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>rdFWS</sender>
+   <signal>clicked(bool)</signal>
+   <receiver>lePeakRange</receiver>
+   <slot>setHidden(bool)</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>134</x>
+     <y>109</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>510</x>
+     <y>298</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>rdFWS</sender>
+   <signal>clicked(bool)</signal>
+   <receiver>lbPeakRange</receiver>
+   <slot>setHidden(bool)</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>134</x>
+     <y>109</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>403</x>
+     <y>298</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>rdQENS</sender>
+   <signal>clicked(bool)</signal>
+   <receiver>lbPeakRange</receiver>
+   <slot>setVisible(bool)</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>55</x>
+     <y>109</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>403</x>
+     <y>298</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>rdQENS</sender>
+   <signal>clicked(bool)</signal>
+   <receiver>lePeakRange</receiver>
+   <slot>setVisible(bool)</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>55</x>
+     <y>109</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>510</x>
+     <y>298</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>rdQENS</sender>
+   <signal>clicked(bool)</signal>
+   <receiver>lbBackOption</receiver>
+   <slot>setHidden(bool)</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>55</x>
+     <y>111</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>446</x>
+     <y>254</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>rdQENS</sender>
+   <signal>clicked(bool)</signal>
+   <receiver>lbCalibOption</receiver>
+   <slot>setHidden(bool)</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>55</x>
+     <y>111</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>446</x>
+     <y>318</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>rdQENS</sender>
+   <signal>clicked(bool)</signal>
+   <receiver>cbBackOption</receiver>
+   <slot>setHidden(bool)</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>55</x>
+     <y>111</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>523</x>
+     <y>254</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>rdQENS</sender>
+   <signal>clicked(bool)</signal>
+   <receiver>cbCalibOption</receiver>
+   <slot>setHidden(bool)</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>55</x>
+     <y>111</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>523</x>
+     <y>318</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>rdFWS</sender>
+   <signal>clicked(bool)</signal>
+   <receiver>lbBackOption</receiver>
+   <slot>setVisible(bool)</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>134</x>
+     <y>111</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>446</x>
+     <y>254</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>rdFWS</sender>
+   <signal>clicked(bool)</signal>
+   <receiver>lbCalibOption</receiver>
+   <slot>setVisible(bool)</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>134</x>
+     <y>111</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>446</x>
+     <y>318</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>rdFWS</sender>
+   <signal>clicked(bool)</signal>
+   <receiver>cbBackOption</receiver>
+   <slot>setVisible(bool)</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>134</x>
      <y>111</y>
     </hint>
+    <hint type="destinationlabel">
+     <x>523</x>
+     <y>254</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>rdFWS</sender>
+   <signal>clicked(bool)</signal>
+   <receiver>cbCalibOption</receiver>
+   <slot>setVisible(bool)</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>134</x>
+     <y>111</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>523</x>
+     <y>318</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>rdGroupDefault</sender>
+   <signal>clicked(bool)</signal>
+   <receiver>lePixelRange</receiver>
+   <slot>setHidden(bool)</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>59</x>
+     <y>185</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>289</x>
+     <y>185</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>rdGroupChoose</sender>
+   <signal>clicked(bool)</signal>
+   <receiver>lePixelRange</receiver>
+   <slot>setHidden(bool)</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>409</x>
+     <y>185</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>289</x>
+     <y>185</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>rdGroupRange</sender>
+   <signal>clicked(bool)</signal>
+   <receiver>lePixelRange</receiver>
+   <slot>setVisible(bool)</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>160</x>
+     <y>185</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>289</x>
+     <y>185</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>rdGroupRange</sender>
+   <signal>clicked(bool)</signal>
+   <receiver>rfMapFile</receiver>
+   <slot>setHidden(bool)</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>160</x>
+     <y>185</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>517</x>
+     <y>184</y>
+    </hint>
    </hints>
   </connection>
  </connections>
+ <buttongroups>
+  <buttongroup name="buttonGroup_2"/>
+  <buttongroup name="buttonGroup"/>
+ </buttongroups>
 </ui>
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/ISISCalibration.ui b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/ISISCalibration.ui
index 86fc866cf28f9557d3164b14f881a73f347f163a..b053071a403fc0121c391a0de40c1fa473b599af 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/ISISCalibration.ui
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/ISISCalibration.ui
@@ -29,7 +29,7 @@
       <item>
        <layout class="QHBoxLayout" name="loCalibInputFile">
         <item>
-         <widget class="MantidQt::MantidWidgets::MWRunFiles" name="leRunNo" native="true">
+         <widget class="MantidQt::API::MWRunFiles" name="leRunNo" native="true">
           <property name="sizePolicy">
            <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
             <horstretch>0</horstretch>
@@ -278,9 +278,9 @@
    <container>1</container>
   </customwidget>
   <customwidget>
-   <class>MantidQt::MantidWidgets::MWRunFiles</class>
+   <class>MantidQt::API::MWRunFiles</class>
    <extends>QWidget</extends>
-   <header>MantidQtMantidWidgets/MWRunFiles.h</header>
+   <header>MantidQtAPI/MWRunFiles.h</header>
   </customwidget>
  </customwidgets>
  <resources/>
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/ISISDiagnostics.ui b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/ISISDiagnostics.ui
index 509c838280b6ba6d840b838b57f566173f417428..1cdf319d81a3418bc057526b4c58bc417e39d428 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/ISISDiagnostics.ui
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/ISISDiagnostics.ui
@@ -29,7 +29,7 @@
       <item>
        <layout class="QHBoxLayout" name="loInputFiles">
         <item>
-         <widget class="MantidQt::MantidWidgets::MWRunFiles" name="dsInputFiles" native="true">
+         <widget class="MantidQt::API::MWRunFiles" name="dsInputFiles" native="true">
           <property name="sizePolicy">
            <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
             <horstretch>0</horstretch>
@@ -203,9 +203,9 @@
    <container>1</container>
   </customwidget>
   <customwidget>
-   <class>MantidQt::MantidWidgets::MWRunFiles</class>
+   <class>MantidQt::API::MWRunFiles</class>
    <extends>QWidget</extends>
-   <header>MantidQtMantidWidgets/MWRunFiles.h</header>
+   <header>MantidQtAPI/MWRunFiles.h</header>
   </customwidget>
  </customwidgets>
  <tabstops>
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/ISISEnergyTransfer.ui b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/ISISEnergyTransfer.ui
index 2dcbbc5475ace3d0d91262b60d1dfaebf3783e0a..c44c5bec6e87b7d1cdef391f379f6b98826fe535 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/ISISEnergyTransfer.ui
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/ISISEnergyTransfer.ui
@@ -72,7 +72,7 @@
        </widget>
       </item>
       <item row="0" column="0">
-       <widget class="MantidQt::MantidWidgets::MWRunFiles" name="dsRunFiles" native="true">
+       <widget class="MantidQt::API::MWRunFiles" name="dsRunFiles" native="true">
         <property name="sizePolicy">
          <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
           <horstretch>0</horstretch>
@@ -251,7 +251,7 @@
         <widget class="QWidget" name="pgMapFile">
          <layout class="QHBoxLayout" name="horizontalLayout_5">
           <item>
-           <widget class="MantidQt::MantidWidgets::MWRunFiles" name="dsMapFile" native="true">
+           <widget class="MantidQt::API::MWRunFiles" name="dsMapFile" native="true">
             <property name="sizePolicy">
              <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
               <horstretch>0</horstretch>
@@ -1002,9 +1002,9 @@
    <header>MantidQtMantidWidgets/DataSelector.h</header>
   </customwidget>
   <customwidget>
-   <class>MantidQt::MantidWidgets::MWRunFiles</class>
+   <class>MantidQt::API::MWRunFiles</class>
    <extends>QWidget</extends>
-   <header>MantidQtMantidWidgets/MWRunFiles.h</header>
+   <header>MantidQtAPI/MWRunFiles.h</header>
   </customwidget>
  </customwidgets>
  <tabstops>
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/IndirectDataReduction.ui b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/IndirectDataReduction.ui
index 441c1b631011d46460e0dfc8eb75c8e62e813451..226f9e4369ead85e610316db8ae8025bb1e9bb53 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/IndirectDataReduction.ui
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/IndirectDataReduction.ui
@@ -6,8 +6,8 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>700</width>
-    <height>600</height>
+    <width>740</width>
+    <height>750</height>
    </rect>
   </property>
   <property name="windowTitle">
@@ -55,11 +55,17 @@
     <item>
      <widget class="QTabWidget" name="twIDRTabs">
       <property name="sizePolicy">
-       <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+       <sizepolicy hsizetype="Expanding" vsizetype="MinimumExpanding">
         <horstretch>0</horstretch>
         <verstretch>0</verstretch>
        </sizepolicy>
       </property>
+      <property name="minimumSize">
+       <size>
+        <width>0</width>
+        <height>0</height>
+       </size>
+      </property>
       <property name="currentIndex">
        <number>-1</number>
       </property>
@@ -95,7 +101,7 @@
         </property>
        </widget>
       </item>
-      <item>
+      <item alignment="Qt::AlignLeft">
        <widget class="QPushButton" name="pbPythonExport">
         <property name="sizePolicy">
          <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
@@ -117,27 +123,20 @@
         </property>
        </widget>
       </item>
-      <item>
-       <spacer name="horizontalSpacer_1">
-        <property name="orientation">
-         <enum>Qt::Horizontal</enum>
-        </property>
-        <property name="sizeHint" stdset="0">
-         <size>
-          <width>30</width>
-          <height>20</height>
-         </size>
-        </property>
-       </spacer>
-      </item>
-      <item>
+      <item alignment="Qt::AlignLeft">
        <widget class="QPushButton" name="pbRun">
         <property name="sizePolicy">
-         <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
+         <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
           <horstretch>0</horstretch>
           <verstretch>0</verstretch>
          </sizepolicy>
         </property>
+        <property name="minimumSize">
+         <size>
+          <width>150</width>
+          <height>0</height>
+         </size>
+        </property>
         <property name="maximumSize">
          <size>
           <width>180</width>
@@ -152,21 +151,14 @@
         </property>
        </widget>
       </item>
-      <item>
-       <spacer name="horizontalSpacer_5">
-        <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>
+      <item alignment="Qt::AlignRight|Qt::AlignVCenter">
        <widget class="QPushButton" name="pbManageDirectories">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
         <property name="text">
          <string>Manage Directories</string>
         </property>
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/IndirectDiffractionReduction.ui b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/IndirectDiffractionReduction.ui
index fb6ef4652ce2cc6196a32b64fe1716f05a470205..c64f84950cb981013a972629440fe03b1d60f4af 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/IndirectDiffractionReduction.ui
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/IndirectDiffractionReduction.ui
@@ -122,7 +122,7 @@
         </widget>
        </item>
        <item row="5" column="1" colspan="2">
-        <widget class="MantidQt::MantidWidgets::MWRunFiles" name="rfCanFiles" native="true">
+        <widget class="MantidQt::API::MWRunFiles" name="rfCanFiles" native="true">
          <property name="enabled">
           <bool>false</bool>
          </property>
@@ -135,7 +135,7 @@
         </widget>
        </item>
        <item row="0" column="0" colspan="3">
-        <widget class="MantidQt::MantidWidgets::MWRunFiles" name="rfSampleFiles" native="true">
+        <widget class="MantidQt::API::MWRunFiles" name="rfSampleFiles" native="true">
          <property name="sizePolicy">
           <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
            <horstretch>0</horstretch>
@@ -199,7 +199,7 @@
             <number>6</number>
            </property>
            <item row="4" column="0" colspan="2">
-            <widget class="MantidQt::MantidWidgets::MWRunFiles" name="rfVanadiumFile" native="true">
+            <widget class="MantidQt::API::MWRunFiles" name="rfVanadiumFile" native="true">
              <property name="enabled">
               <bool>true</bool>
              </property>
@@ -241,7 +241,7 @@
             </widget>
            </item>
            <item row="3" column="0" colspan="2">
-            <widget class="MantidQt::MantidWidgets::MWRunFiles" name="rfCalFile" native="true">
+            <widget class="MantidQt::API::MWRunFiles" name="rfCalFile" native="true">
              <property name="minimumSize">
               <size>
                <width>0</width>
@@ -297,7 +297,7 @@
             </widget>
            </item>
            <item row="1" column="0" colspan="2">
-            <widget class="MantidQt::MantidWidgets::MWRunFiles" name="rfCalFile_only" native="true">
+            <widget class="MantidQt::API::MWRunFiles" name="rfCalFile_only" native="true">
              <property name="enabled">
               <bool>false</bool>
              </property>
@@ -680,9 +680,9 @@
  </widget>
  <customwidgets>
   <customwidget>
-   <class>MantidQt::MantidWidgets::MWRunFiles</class>
+   <class>MantidQt::API::MWRunFiles</class>
    <extends>QWidget</extends>
-   <header>MantidQtMantidWidgets/MWRunFiles.h</header>
+   <header>MantidQtAPI/MWRunFiles.h</header>
   </customwidget>
   <customwidget>
    <class>MantidQt::MantidWidgets::IndirectInstrumentConfig</class>
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/IndirectLoadILL.ui b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/IndirectLoadILL.ui
index 4aa9c8138798f3102a2770d442e7a504b609659f..2dba4d73ee7fefe8fbfade5e5c5af4877280b40a 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/IndirectLoadILL.ui
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/IndirectLoadILL.ui
@@ -15,7 +15,7 @@
   </property>
   <layout class="QVBoxLayout" name="verticalLayout">
    <item>
-    <widget class="MantidQt::MantidWidgets::MWRunFiles" name="mwRun">
+    <widget class="MantidQt::API::MWRunFiles" name="mwRun">
      <property name="sizePolicy">
       <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
        <horstretch>0</horstretch>
@@ -64,7 +64,7 @@
       </widget>
      </item>
      <item row="0" column="1">
-      <widget class="MantidQt::MantidWidgets::MWRunFiles" name="mwMapFile">
+      <widget class="MantidQt::API::MWRunFiles" name="mwMapFile">
        <property name="enabled">
         <bool>false</bool>
        </property>
@@ -186,9 +186,9 @@
  </widget>
  <customwidgets>
   <customwidget>
-   <class>MantidQt::MantidWidgets::MWRunFiles</class>
+   <class>MantidQt::API::MWRunFiles</class>
    <extends>QWidget</extends>
-   <header>MantidQtMantidWidgets/MWRunFiles.h</header>
+   <header>MantidQtAPI/MWRunFiles.h</header>
   </customwidget>
   <customwidget>
    <class>MantidQt::MantidWidgets::IndirectInstrumentConfig</class>
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/IndirectMolDyn.ui b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/IndirectMolDyn.ui
index 45254f92afe4ba701ab4d04d82dd264edd16150c..0e1613f4da01d8e4c0d4299aa3fee547df50d3da 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/IndirectMolDyn.ui
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/IndirectMolDyn.ui
@@ -28,7 +28,7 @@
        </widget>
       </item>
       <item row="1" column="1">
-       <widget class="MantidQt::MantidWidgets::MWRunFiles" name="mwRun" native="true">
+       <widget class="MantidQt::API::MWRunFiles" name="mwRun" native="true">
         <property name="sizePolicy">
          <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
           <horstretch>0</horstretch>
@@ -355,9 +355,9 @@
    <header>MantidQtMantidWidgets/DataSelector.h</header>
   </customwidget>
   <customwidget>
-   <class>MantidQt::MantidWidgets::MWRunFiles</class>
+   <class>MantidQt::API::MWRunFiles</class>
    <extends>QWidget</extends>
-   <header>MantidQtMantidWidgets/MWRunFiles.h</header>
+   <header>MantidQtAPI/MWRunFiles.h</header>
   </customwidget>
  </customwidgets>
  <tabstops>
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/IndirectSassena.ui b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/IndirectSassena.ui
index fc54263c1dc63d58d5b34fcc59e23bf8ac83de71..bbc63eb15aa3ab1083bcdeafb3a317bbd6aed6df 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/IndirectSassena.ui
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/IndirectSassena.ui
@@ -24,7 +24,7 @@
        <number>6</number>
       </property>
       <item row="0" column="1">
-       <widget class="MantidQt::MantidWidgets::MWRunFiles" name="mwInputFile" native="true">
+       <widget class="MantidQt::API::MWRunFiles" name="mwInputFile" native="true">
         <property name="sizePolicy">
          <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
           <horstretch>0</horstretch>
@@ -156,9 +156,9 @@
  </widget>
  <customwidgets>
   <customwidget>
-   <class>MantidQt::MantidWidgets::MWRunFiles</class>
+   <class>MantidQt::API::MWRunFiles</class>
    <extends>QWidget</extends>
-   <header>MantidQtMantidWidgets/MWRunFiles.h</header>
+   <header>MantidQtAPI/MWRunFiles.h</header>
   </customwidget>
  </customwidgets>
  <tabstops>
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/IndirectTransmissionCalc.ui b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/IndirectTransmissionCalc.ui
index 0ead455b0cb85e44c6734292992991639f619a3a..1500fb6bf8b69599ef7607d3ca108751fe34f87b 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/IndirectTransmissionCalc.ui
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/IndirectTransmissionCalc.ui
@@ -33,6 +33,7 @@
           <property name="techniques" stdset="0">
            <stringlist>
             <string>TOF Indirect Geometry Spectroscopy</string>
+            <string>Reactor Indirect Geometry Spectroscopy</string>
            </stringlist>
           </property>
           <property name="disabledInstruments" stdset="0">
@@ -57,9 +58,6 @@
         <string>Sample Details</string>
        </property>
        <layout class="QGridLayout" name="gridLayout_2">
-        <property name="margin">
-         <number>9</number>
-        </property>
         <item row="0" column="0">
          <widget class="QLabel" name="lbChemicalFormula">
           <property name="text">
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/Quasi.ui b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/Quasi.ui
index 3518f75b4bb259bd77bd15219bde318fa978c3cd..77bb3a92221337cd5e37acecd893f2632a8a22f4 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/Quasi.ui
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/Quasi.ui
@@ -137,7 +137,7 @@
          </widget>
         </item>
         <item row="1" column="1">
-         <widget class="MantidQt::MantidWidgets::MWRunFiles" name="mwFixWidthDat" native="true">
+         <widget class="MantidQt::API::MWRunFiles" name="mwFixWidthDat" native="true">
           <property name="enabled">
            <bool>false</bool>
           </property>
@@ -405,9 +405,9 @@
  </widget>
  <customwidgets>
   <customwidget>
-   <class>MantidQt::MantidWidgets::MWRunFiles</class>
+   <class>MantidQt::API::MWRunFiles</class>
    <extends>QWidget</extends>
-   <header>MantidQtMantidWidgets/MWRunFiles.h</header>
+   <header>MantidQtAPI/MWRunFiles.h</header>
   </customwidget>
   <customwidget>
    <class>MantidQt::MantidWidgets::DataSelector</class>
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Muon/ALCDataLoadingView.ui b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Muon/ALCDataLoadingView.ui
index 3435fb44fa92a393a93b16f1e75caef7e0d7167d..eb60fe4880cd9e373f8f0ab178a4bee9042e9196 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Muon/ALCDataLoadingView.ui
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Muon/ALCDataLoadingView.ui
@@ -50,7 +50,7 @@
              </widget>
             </item>
             <item row="1" column="1">
-             <widget class="MantidQt::MantidWidgets::MWRunFiles" name="lastRun" native="true">
+             <widget class="MantidQt::API::MWRunFiles" name="lastRun" native="true">
               <property name="sizePolicy">
                <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
                 <horstretch>0</horstretch>
@@ -76,7 +76,7 @@
              </widget>
             </item>
             <item row="0" column="1">
-             <widget class="MantidQt::MantidWidgets::MWRunFiles" name="firstRun" native="true">
+             <widget class="MantidQt::API::MWRunFiles" name="firstRun" native="true">
               <property name="sizePolicy">
                <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
                 <horstretch>0</horstretch>
@@ -158,7 +158,7 @@
           <item>
            <layout class="QHBoxLayout" name="horizontalLayoutDeadTime_2">
             <item>
-             <widget class="MantidQt::MantidWidgets::MWRunFiles" name="deadTimeFile" native="true">
+             <widget class="MantidQt::API::MWRunFiles" name="deadTimeFile" native="true">
               <property name="enabled">
                <bool>false</bool>
               </property>
@@ -523,9 +523,9 @@
    <container>1</container>
   </customwidget>
   <customwidget>
-   <class>MantidQt::MantidWidgets::MWRunFiles</class>
+   <class>MantidQt::API::MWRunFiles</class>
    <extends>QWidget</extends>
-   <header>MantidQtMantidWidgets/MWRunFiles.h</header>
+   <header>MantidQtAPI/MWRunFiles.h</header>
   </customwidget>
   <customwidget>
    <class>MantidQt::MantidWidgets::LogValueSelector</class>
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Muon/MuonAnalysis.ui b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Muon/MuonAnalysis.ui
index 1cd5237b6c98f68ff955c4b07d20f17e37cdea7c..5a9dba7224c02c339dbdad21fc46e66dca589fd9 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Muon/MuonAnalysis.ui
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Muon/MuonAnalysis.ui
@@ -195,7 +195,7 @@ p, li { white-space: pre-wrap; }
                   </widget>
                  </item>
                  <item row="4" column="1">
-                  <widget class="MantidQt::MantidWidgets::MWRunFiles" name="mwRunDeadTimeFile" native="true">
+                  <widget class="MantidQt::API::MWRunFiles" name="mwRunDeadTimeFile" native="true">
                    <property name="enabled">
                     <bool>true</bool>
                    </property>
@@ -526,7 +526,7 @@ p, li { white-space: pre-wrap; }
                <item>
                 <layout class="QHBoxLayout" name="fileInputLayout">
                  <item>
-                  <widget class="MantidQt::MantidWidgets::MWRunFiles" name="mwRunFiles" native="true">
+                  <widget class="MantidQt::API::MWRunFiles" name="mwRunFiles" native="true">
                    <property name="sizePolicy">
                     <sizepolicy hsizetype="Expanding" vsizetype="Minimum">
                      <horstretch>0</horstretch>
@@ -534,7 +534,7 @@ p, li { white-space: pre-wrap; }
                     </sizepolicy>
                    </property>
                    <property name="toolTip">
-                    <string>Specify a run number or data file by typing a run number or use 
+                    <string>Specify a run number or data file by typing a run number or use
 the Browse button to select</string>
                    </property>
                    <property name="findRunFiles" stdset="0">
@@ -1159,19 +1159,19 @@ p, li { white-space: pre-wrap; }
              <row/>
              <column>
               <property name="text">
-               <string>Group Pair 
+               <string>Group Pair
 (Name)</string>
               </property>
              </column>
              <column>
               <property name="text">
-               <string>Forward 
+               <string>Forward
 (Group name)</string>
               </property>
              </column>
              <column>
               <property name="text">
-               <string>Backward 
+               <string>Backward
 (Group name)</string>
               </property>
              </column>
@@ -1379,7 +1379,7 @@ p, li { white-space: pre-wrap; }
        <attribute name="toolTip">
         <string>The Results Table tab allows:
 ï‚· creating result(s) tables
-ï‚· selecting which instrument log values (temp, field etc) to write out alongside the fit 
+ï‚· selecting which instrument log values (temp, field etc) to write out alongside the fit
      parameters
 ï‚· option to write out fit information from one or several data files</string>
        </attribute>
@@ -1490,9 +1490,9 @@ p, li { white-space: pre-wrap; }
              <item row="0" column="1">
               <widget class="QCheckBox" name="selectAllFittingResults">
                <property name="toolTip">
-                <string>If checked then the fit results 
-from all the runs listed are 
-selected and written to the 
+                <string>If checked then the fit results
+from all the runs listed are
+selected and written to the
 results table.</string>
                </property>
                <property name="text">
@@ -1577,7 +1577,7 @@ p, li { white-space: pre-wrap; }
                 </sizepolicy>
                </property>
                <property name="text">
-                <string>Individual fits</string>
+                <string>Individual</string>
                </property>
                <property name="checked">
                 <bool>true</bool>
@@ -1599,7 +1599,7 @@ p, li { white-space: pre-wrap; }
                 </sizepolicy>
                </property>
                <property name="text">
-                <string>Sequential fits:</string>
+                <string>Sequential:</string>
                </property>
                <attribute name="buttonGroup">
                 <string notr="true">fitType</string>
@@ -1625,7 +1625,7 @@ p, li { white-space: pre-wrap; }
                 <bool>false</bool>
                </property>
                <property name="text">
-                <string>Simultaneous fits:</string>
+                <string>Simultaneous:</string>
                </property>
                <attribute name="buttonGroup">
                 <string notr="true">fitType</string>
@@ -1651,7 +1651,7 @@ p, li { white-space: pre-wrap; }
                 <bool>false</bool>
                </property>
                <property name="text">
-                <string>Multiple fits</string>
+                <string>Multiple</string>
                </property>
                <attribute name="buttonGroup">
                 <string notr="true">fitType</string>
@@ -2669,9 +2669,9 @@ p, li { white-space: pre-wrap; }
  </widget>
  <customwidgets>
   <customwidget>
-   <class>MantidQt::MantidWidgets::MWRunFiles</class>
+   <class>MantidQt::API::MWRunFiles</class>
    <extends>QWidget</extends>
-   <header>MantidQtMantidWidgets/MWRunFiles.h</header>
+   <header>MantidQtAPI/MWRunFiles.h</header>
   </customwidget>
   <customwidget>
    <class>MantidQt::MantidWidgets::InstrumentSelector</class>
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Muon/MuonAnalysisDataLoader.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Muon/MuonAnalysisDataLoader.h
index a610a841cfb7db3420ecc5cbf15151f3acf3d721..5c0c23eacc11bf127d0c2ddc974c65ce90b2af96 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Muon/MuonAnalysisDataLoader.h
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Muon/MuonAnalysisDataLoader.h
@@ -9,6 +9,7 @@
 #include "MantidAPI/MatrixWorkspace_fwd.h"
 #include "MantidAPI/Workspace_fwd.h"
 #include <QMap>
+#include <QRegExp>
 #include <QStringList>
 
 namespace MantidQt {
@@ -39,7 +40,7 @@ struct AnalysisOptions {
   std::string groupPairName; /// Name of group or pair to use
   const Mantid::API::Grouping grouping; /// Grouping to use
   PlotType plotType = {};               /// Type of analysis to perform
-  explicit AnalysisOptions(const Mantid::API::Grouping &g) : grouping(g){};
+  explicit AnalysisOptions(const Mantid::API::Grouping &g) : grouping(g) {}
 };
 } // namespace Muon
 
@@ -77,6 +78,7 @@ public:
                         const std::string &deadTimesFile = "");
   /// change list of supported instruments
   void setSupportedInstruments(const QStringList &instruments);
+
   /// load files
   Muon::LoadResult loadFiles(const QStringList &files) const;
   /// correct and group loaded data
@@ -106,6 +108,9 @@ private:
   /// Get instrument name from workspace
   std::string
   getInstrumentName(const Mantid::API::Workspace_sptr workspace) const;
+  /// Check if we should cache result of a load of the given files
+  bool shouldBeCached(const QStringList &filenames) const;
+
   /// Dead times type
   Muon::DeadTimesType m_deadTimesType;
   /// Dead times file
@@ -114,9 +119,11 @@ private:
   QStringList m_instruments;
   /// Cache of previously loaded data
   mutable std::map<std::string, Muon::LoadResult> m_loadedDataCache;
+  /// Regex blacklisting certain files from being cached
+  QRegExp m_cacheBlacklist;
 };
 
 } // namespace CustomInterfaces
 } // namespace MantidQt
 
-#endif /* MANTIDQt_CUSTOMINTERFACES_MUONANALYSISDATALOADER_H_ */
\ No newline at end of file
+#endif /* MANTIDQt_CUSTOMINTERFACES_MUONANALYSISDATALOADER_H_ */
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Muon/MuonAnalysisFitFunctionPresenter.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Muon/MuonAnalysisFitFunctionPresenter.h
index 15ccccdb904c7b62c3dc95d4fe7bf3bdfa63ca69..ddc82e870f8811d28c2038a45fac28d61fe52bc3 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Muon/MuonAnalysisFitFunctionPresenter.h
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Muon/MuonAnalysisFitFunctionPresenter.h
@@ -47,6 +47,8 @@ public:
       MantidQt::MantidWidgets::IFunctionBrowser *funcBrowser);
   /// Toggle multiple fitting mode
   void setMultiFitState(Muon::MultiFitState state);
+  /// Set function in model (fit property browser)
+  void setFunctionInModel(const Mantid::API::IFunction_sptr &function);
 public slots:
   /// Update function and pass to fit property browser
   void updateFunction();
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Muon/MuonSequentialFitDialog.ui b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Muon/MuonSequentialFitDialog.ui
index ce0433dfafbd1fd20fa7c4406d6d65805c94806d..f76871a008f68ae674e91b8c649d2455a97a88fe 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Muon/MuonSequentialFitDialog.ui
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Muon/MuonSequentialFitDialog.ui
@@ -35,7 +35,7 @@
       <number>6</number>
      </property>
      <item row="0" column="1">
-      <widget class="MantidQt::MantidWidgets::MWRunFiles" name="runs" native="true">
+      <widget class="MantidQt::API::MWRunFiles" name="runs" native="true">
        <property name="label" stdset="0">
         <string/>
        </property>
@@ -257,9 +257,9 @@
  </widget>
  <customwidgets>
   <customwidget>
-   <class>MantidQt::MantidWidgets::MWRunFiles</class>
+   <class>MantidQt::API::MWRunFiles</class>
    <extends>QWidget</extends>
-   <header>MantidQtMantidWidgets/MWRunFiles.h</header>
+   <header>MantidQtAPI/MWRunFiles.h</header>
   </customwidget>
  </customwidgets>
  <resources/>
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/ProjectSave.ui b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/ProjectSave.ui
new file mode 100644
index 0000000000000000000000000000000000000000..8d84279ce7ab4d227d2d68b4f515c9998539d708
--- /dev/null
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/ProjectSave.ui
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ProjectSave</class>
+ <widget class="QDialog" name="ProjectSave">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>868</width>
+    <height>596</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <layout class="QGridLayout" name="gridLayout">
+     <item row="0" column="0">
+      <widget class="QLabel" name="label">
+       <property name="text">
+        <string>Workspaces</string>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="1">
+      <widget class="QLabel" name="label_2">
+       <property name="text">
+        <string>Included Windows</string>
+       </property>
+      </widget>
+     </item>
+     <item row="1" column="1" colspan="2">
+      <widget class="QListView" name="includedWindows"/>
+     </item>
+     <item row="4" column="1">
+      <widget class="QPushButton" name="btnSave">
+       <property name="text">
+        <string>Save</string>
+       </property>
+      </widget>
+     </item>
+     <item row="1" column="0" rowspan="3">
+      <widget class="QTreeWidget" name="workspaceList">
+       <column>
+        <property name="text">
+         <string>Name</string>
+        </property>
+       </column>
+       <column>
+        <property name="text">
+         <string>Size</string>
+        </property>
+       </column>
+       <item>
+        <property name="text">
+         <string>ws1</string>
+        </property>
+        <property name="checkState">
+         <enum>Checked</enum>
+        </property>
+        <property name="text">
+         <string>10mb</string>
+        </property>
+       </item>
+      </widget>
+     </item>
+     <item row="4" column="2">
+      <widget class="QPushButton" name="btnSaveAll">
+       <property name="text">
+        <string>Save All</string>
+       </property>
+      </widget>
+     </item>
+     <item row="3" column="1" colspan="2">
+      <widget class="QListView" name="excludedWindows"/>
+     </item>
+     <item row="2" column="1">
+      <widget class="QLabel" name="label_3">
+       <property name="text">
+        <string>Excluded Windows</string>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/IReflMainWindowPresenter.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/IReflMainWindowPresenter.h
index e3c84ecf44274434ffa031361594b6614f4abd2d..7b6b9e136e96780472997e7db3fb8125e1716392 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/IReflMainWindowPresenter.h
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/IReflMainWindowPresenter.h
@@ -39,11 +39,11 @@ public:
   /// Destructor
   virtual ~IReflMainWindowPresenter(){};
   /// Pre-processing
-  virtual std::string getTransmissionOptions() const = 0;
+  virtual std::string getTransmissionOptions(int group) const = 0;
   /// Processing
-  virtual std::string getReductionOptions() const = 0;
+  virtual std::string getReductionOptions(int group) const = 0;
   /// Post-processing
-  virtual std::string getStitchOptions() const = 0;
+  virtual std::string getStitchOptions(int group) const = 0;
   /// Dialog/Prompt methods
   virtual std::string askUserString(const std::string &prompt,
                                     const std::string &title,
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/IReflRunsTabPresenter.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/IReflRunsTabPresenter.h
index 77a0380e22dc57e0693aac8cd3533de216f3e8e9..50bbcf9ea26345d99015e8400f203dee611de2d1 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/IReflRunsTabPresenter.h
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/IReflRunsTabPresenter.h
@@ -42,7 +42,8 @@ public:
     SearchFlag,
     ICATSearchCompleteFlag,
     TransferFlag,
-    InstrumentChangedFlag
+    InstrumentChangedFlag,
+    GroupChangedFlag
   };
 
   // Tell the presenter something happened
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/IReflRunsTabView.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/IReflRunsTabView.h
index 3249d5926ab3bb7c2c4ae37267633daa9c4a384d..8fcc04d7f951c699c457feace4aafa34cf8372d0 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/IReflRunsTabView.h
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/IReflRunsTabView.h
@@ -71,6 +71,7 @@ public:
   virtual std::string getSearchInstrument() const = 0;
   virtual std::string getSearchString() const = 0;
   virtual std::string getTransferMethod() const = 0;
+  virtual int getSelectedGroup() const = 0;
 
   virtual IReflRunsTabPresenter *getPresenter() const = 0;
   virtual boost::shared_ptr<MantidQt::API::AlgorithmRunner>
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/IReflSaveTabPresenter.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/IReflSaveTabPresenter.h
new file mode 100644
index 0000000000000000000000000000000000000000..059a87ba8f5f516d6015053cfb9eee92f6f6728d
--- /dev/null
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/IReflSaveTabPresenter.h
@@ -0,0 +1,54 @@
+#ifndef MANTID_CUSTOMINTERFACES_IREFLSAVETABPRESENTER_H
+#define MANTID_CUSTOMINTERFACES_IREFLSAVETABPRESENTER_H
+
+namespace MantidQt {
+namespace CustomInterfaces {
+
+class IReflMainWindowPresenter;
+
+/** @class IReflSaveTabPresenter
+
+IReflSaveTabPresenter is an interface which defines the functions that need
+to be implemented by a concrete 'Save ASCII' tab presenter
+
+Copyright &copy; 2016 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>
+*/
+class IReflSaveTabPresenter {
+public:
+  virtual ~IReflSaveTabPresenter(){};
+  /// Accept a main presenter
+  virtual void acceptMainPresenter(IReflMainWindowPresenter *mainPresenter) = 0;
+
+  enum Flag {
+    populateWorkspaceListFlag,
+    filterWorkspaceListFlag,
+    workspaceParamsFlag,
+    saveWorkspacesFlag,
+    suggestSaveDirFlag
+  };
+
+  /// Tell the presenter something happened
+  virtual void notify(IReflSaveTabPresenter::Flag flag) = 0;
+};
+}
+}
+#endif /* MANTID_CUSTOMINTERFACES_IREFLSAVETABPRESENTER_H */
\ No newline at end of file
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/IReflSaveTabView.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/IReflSaveTabView.h
new file mode 100644
index 0000000000000000000000000000000000000000..a812a5277906ea09fa0b8c3601c9485612240e5b
--- /dev/null
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/IReflSaveTabView.h
@@ -0,0 +1,70 @@
+#ifndef MANTID_CUSTOMINTERFACES_IREFLSAVETABVIEW_H
+#define MANTID_CUSTOMINTERFACES_IREFLSAVETABVIEW_H
+
+#include "MantidQtCustomInterfaces/DllConfig.h"
+#include <string>
+#include <vector>
+
+namespace MantidQt {
+namespace CustomInterfaces {
+
+class IReflSaveTabPresenter;
+
+/** @class IReflSaveTabView
+
+IReflSaveTabView is the base view class for the tab "Save ASCII" in the
+Reflectometry Interface. It contains no QT specific functionality as that should
+be handled by a subclass.
+
+Copyright &copy; 2016 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>
+*/
+
+class DLLExport IReflSaveTabView {
+public:
+  /// Constructor
+  IReflSaveTabView(){};
+  /// Destructor
+  virtual ~IReflSaveTabView(){};
+  /// Returns the presenter managing this view
+  virtual IReflSaveTabPresenter *getPresenter() const = 0;
+
+  virtual std::string getSavePath() const = 0;
+  virtual void setSavePath(const std::string &path) const = 0;
+  virtual std::string getPrefix() const = 0;
+  virtual std::string getFilter() const = 0;
+  virtual bool getRegexCheck() const = 0;
+  virtual std::string getCurrentWorkspaceName() const = 0;
+  virtual std::vector<std::string> getSelectedWorkspaces() const = 0;
+  virtual std::vector<std::string> getSelectedParameters() const = 0;
+  virtual int getFileFormatIndex() const = 0;
+  virtual bool getTitleCheck() const = 0;
+  virtual bool getQResolutionCheck() const = 0;
+  virtual std::string getSeparator() const = 0;
+
+  virtual void clearWorkspaceList() const = 0;
+  virtual void clearParametersList() const = 0;
+  virtual void setWorkspaceList(const std::vector<std::string> &) const = 0;
+  virtual void setParametersList(const std::vector<std::string> &) const = 0;
+};
+}
+}
+#endif /* MANTID_CUSTOMINTERFACES_IREFLSAVETABVIEW_H */
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/IReflSettingsPresenter.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/IReflSettingsPresenter.h
new file mode 100644
index 0000000000000000000000000000000000000000..25d6b7ff8db957657b5e4d039b790f7bdbf96c21
--- /dev/null
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/IReflSettingsPresenter.h
@@ -0,0 +1,56 @@
+#ifndef MANTID_CUSTOMINTERFACES_IREFLSETTINGSPRESENTER_H
+#define MANTID_CUSTOMINTERFACES_IREFLSETTINGSPRESENTER_H
+
+#include <string>
+
+namespace MantidQt {
+namespace CustomInterfaces {
+
+class IReflMainWindowPresenter;
+
+/** @class IReflSettingsPresenter
+
+IReflSettingsPresenter is an interface which defines the functions that need
+to be implemented by a concrete 'Settings' presenter
+
+Copyright &copy; 2011-16 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>
+*/
+class IReflSettingsPresenter {
+public:
+  virtual ~IReflSettingsPresenter(){};
+  /// Pre-processing
+  virtual std::string getTransmissionOptions() const = 0;
+  /// Processing
+  virtual std::string getReductionOptions() const = 0;
+  /// Post-processing
+  virtual std::string getStitchOptions() const = 0;
+
+  enum Flag { ExpDefaultsFlag, InstDefaultsFlag };
+
+  /// Tell the presenter something happened
+  virtual void notify(IReflSettingsPresenter::Flag flag) = 0;
+  /// Set current instrument name
+  virtual void setInstrumentName(const std::string &instName) = 0;
+};
+}
+}
+#endif /* MANTID_CUSTOMINTERFACES_IREFLSETTINGSPRESENTER_H */
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/IReflSettingsTabPresenter.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/IReflSettingsTabPresenter.h
index f00b18d1476ff9d35ae313d8849add441d4d74fc..89845e59a881531f4264d2360acf639255bc5e0a 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/IReflSettingsTabPresenter.h
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/IReflSettingsTabPresenter.h
@@ -37,21 +37,14 @@ Code Documentation is available at: <http://doxygen.mantidproject.org>
 class IReflSettingsTabPresenter {
 public:
   virtual ~IReflSettingsTabPresenter(){};
-  /// Accept a main presenter
-  virtual void acceptMainPresenter(IReflMainWindowPresenter *mainPresenter) = 0;
   /// Pre-processing
-  virtual std::string getTransmissionOptions() const = 0;
+  virtual std::string getTransmissionOptions(int group) const = 0;
   /// Processing
-  virtual std::string getReductionOptions() const = 0;
+  virtual std::string getReductionOptions(int group) const = 0;
   /// Post-processing
-  virtual std::string getStitchOptions() const = 0;
-
-  enum Flag { ExpDefaultsFlag, InstDefaultsFlag };
-
-  /// Tell the presenter something happened
-  virtual void notify(IReflSettingsTabPresenter::Flag flag) = 0;
+  virtual std::string getStitchOptions(int group) const = 0;
   /// Set current instrument name
-  virtual void setInstrumentName(const std::string instName) = 0;
+  virtual void setInstrumentName(const std::string &instName) = 0;
 };
 }
 }
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/IReflSettingsTabView.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/IReflSettingsView.h
similarity index 82%
rename from MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/IReflSettingsTabView.h
rename to MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/IReflSettingsView.h
index ff159575cb1d63dce69385112f208d956d332925..7d87dab566cb7dc80baa59880712a0690c110c06 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/IReflSettingsTabView.h
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/IReflSettingsView.h
@@ -1,5 +1,5 @@
-#ifndef MANTID_CUSTOMINTERFACES_IREFLSETTINGSTABVIEW_H
-#define MANTID_CUSTOMINTERFACES_IREFLSETTINGSTABVIEW_H
+#ifndef MANTID_CUSTOMINTERFACES_IREFLSETTINGSVIEW_H
+#define MANTID_CUSTOMINTERFACES_IREFLSETTINGSVIEW_H
 
 #include "MantidQtCustomInterfaces/DllConfig.h"
 #include <vector>
@@ -9,13 +9,12 @@ namespace MantidQt {
 
 namespace CustomInterfaces {
 
-class IReflSettingsTabPresenter;
+class IReflSettingsPresenter;
 
-/** @class IReflSettingsTabView
+/** @class IReflSettingsView
 
-IReflSettingsTabView is the base view class for the Reflectometry Interface. It
-contains
-no QT specific functionality as that should be handled by a subclass.
+IReflSettingsView is the base view class for the Reflectometry settings. It
+contains no QT specific functionality as that should be handled by a subclass.
 
 Copyright &copy; 2011-16 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge
 National Laboratory & European Spallation Source
@@ -39,14 +38,14 @@ File change history is stored at: <https://github.com/mantidproject/mantid>.
 Code Documentation is available at: <http://doxygen.mantidproject.org>
 */
 
-class DLLExport IReflSettingsTabView {
+class DLLExport IReflSettingsView {
 public:
   /// Constructor
-  IReflSettingsTabView(){};
+  IReflSettingsView(){};
   /// Destructor
-  virtual ~IReflSettingsTabView(){};
+  virtual ~IReflSettingsView(){};
   /// Returns the presenter managing this view
-  virtual IReflSettingsTabPresenter *getPresenter() const = 0;
+  virtual IReflSettingsPresenter *getPresenter() const = 0;
 
   /// Post-processing
   virtual std::string getStitchOptions() const = 0;
@@ -84,4 +83,4 @@ public:
 };
 }
 }
-#endif /* MANTID_CUSTOMINTERFACES_IREFLRUNSTABVIEW_H */
+#endif /* MANTID_CUSTOMINTERFACES_IREFLSETTINGSVIEW_H */
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/MeasurementItem.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/MeasurementItem.h
index 25576f0180bc74aa98fe42594018b60e873ca38a..85b6b21f58f13ddb8cedac316d37e802c9336466 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/MeasurementItem.h
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/MeasurementItem.h
@@ -38,7 +38,8 @@ public:
   /// Constructor
   MeasurementItem(const IDType &measurementItemId, const IDType &subId,
                   const std::string &label, const std::string &type,
-                  const double angle, const std::string &run);
+                  const double angle, const std::string &run,
+                  const std::string &title);
 
   /// Constructional method
   static MeasurementItem InvalidMeasurementItem(const std::string &why);
@@ -55,6 +56,7 @@ public:
   IDType subId() const;
   std::string run() const;
   std::string type() const;
+  std::string title() const;
   std::string label() const;
   double angle() const;
   std::string angleStr() const;
@@ -69,6 +71,7 @@ private:
   std::string m_type;
   double m_angle;
   std::string m_run;
+  std::string m_title;
   std::string m_whyUnuseable;
   /// Not assignable
 };
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/QtReflMainWindowView.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/QtReflMainWindowView.h
index a3f05e178c4e3f85ecb5242911c9dbd0942d0a26..5ee724e983a6367788b0a1034088849c53a4ce03 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/QtReflMainWindowView.h
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/QtReflMainWindowView.h
@@ -11,13 +11,14 @@ namespace CustomInterfaces {
 class IReflMainWindowPresenter;
 class IReflRunsTabPresenter;
 class IReflSettingsTabPresenter;
+class IReflSaveTabPresenter;
 
 /** @class ReflMainWindowView
 
 ReflMainWindowView is the concrete main window view implementing the
 functionality defined by the interface IReflMainWindowView
 
-Copyright &copy; 2011-14 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge
+Copyright &copy; 2016 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge
 National Laboratory & European Spallation Source
 
 This file is part of Mantid.
@@ -70,6 +71,8 @@ private:
   IReflRunsTabPresenter *createRunsTab();
   /// Creates the 'Settings' tab
   IReflSettingsTabPresenter *createSettingsTab();
+  /// Creates the 'Save ASCII' tab
+  IReflSaveTabPresenter *createSaveTab();
 
   /// Interface definition with widgets for the main interface window
   Ui::RelMainWindowWidget m_ui;
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/QtReflRunsTabView.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/QtReflRunsTabView.h
index deff40d87bf60fa744e2120c315771cc5702fa84..50f2e7a11992fbcd896881590fa4a8086f66b135 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/QtReflRunsTabView.h
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/QtReflRunsTabView.h
@@ -88,6 +88,7 @@ public:
   std::string getSearchInstrument() const override;
   std::string getSearchString() const override;
   std::string getTransferMethod() const override;
+  int getSelectedGroup() const override;
 
   IReflRunsTabPresenter *getPresenter() const override;
   boost::shared_ptr<MantidQt::API::AlgorithmRunner>
@@ -118,6 +119,7 @@ private slots:
   void slitCalculatorTriggered();
   void icatSearchComplete();
   void instrumentChanged(int index);
+  void groupChanged();
   void showSearchContextMenu(const QPoint &pos);
 };
 
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/QtReflSaveTabView.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/QtReflSaveTabView.h
new file mode 100644
index 0000000000000000000000000000000000000000..fec867d4113f33e68fb4132d42c5a4b2ed6f51f4
--- /dev/null
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/QtReflSaveTabView.h
@@ -0,0 +1,108 @@
+#ifndef MANTID_CUSTOMINTERFACES_QTREFLSAVETABVIEW_H_
+#define MANTID_CUSTOMINTERFACES_QTREFLSAVETABVIEW_H_
+
+#include "MantidQtCustomInterfaces/Reflectometry/IReflSaveTabView.h"
+#include "ui_ReflSaveTabWidget.h"
+#include <memory>
+
+namespace MantidQt {
+namespace CustomInterfaces {
+
+// Forward decs
+class IReflSaveTabPresenter;
+
+/** QtReflSaveTabView : Provides an interface for the "Save ASCII" tab in the
+Reflectometry (Polref) interface.
+
+Copyright &copy; 2016 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>
+*/
+class MANTIDQT_CUSTOMINTERFACES_DLL QtReflSaveTabView
+    : public QWidget,
+      public IReflSaveTabView {
+  Q_OBJECT
+public:
+  /// Constructor
+  QtReflSaveTabView(QWidget *parent = 0);
+  /// Destructor
+  ~QtReflSaveTabView() override;
+  /// Returns the presenter managing this view
+  IReflSaveTabPresenter *getPresenter() const override;
+
+  /// Returns the save path
+  std::string getSavePath() const override;
+  /// Sets the save path
+  void setSavePath(const std::string &path) const override;
+  /// Returns the prefix
+  std::string getPrefix() const override;
+  /// Returns the filter
+  std::string getFilter() const override;
+  /// Returns the regex check
+  bool getRegexCheck() const override;
+  /// Get name of the currently selected workspace name
+  std::string getCurrentWorkspaceName() const override;
+  /// Returns a list of names of selected workspaces
+  std::vector<std::string> getSelectedWorkspaces() const override;
+  /// Returns a list of names of selected parameters
+  std::vector<std::string> getSelectedParameters() const override;
+  /// Returns the index of selected file format
+  int getFileFormatIndex() const override;
+  /// Returns the title check
+  bool getTitleCheck() const override;
+  /// Returns the Q resolution check
+  bool getQResolutionCheck() const override;
+  /// Returns the separator type
+  std::string getSeparator() const override;
+
+  /// Clears the 'List of Workspaces' widget
+  void clearWorkspaceList() const override;
+  /// Clears the 'List of Logged Parameters' widget
+  void clearParametersList() const override;
+  /// Sets the 'List of workspaces' widget
+  void setWorkspaceList(const std::vector<std::string> &) const override;
+  /// Sets the 'List of logged parameters' widget
+  void setParametersList(const std::vector<std::string> &) const override;
+
+public slots:
+  /// Populate the 'List of workspaces' widget
+  void populateListOfWorkspaces() const;
+  /// Filters the 'List of workspaces' widget
+  void filterWorkspaceList() const;
+  /// Request parameters for a workspace of a name
+  void requestWorkspaceParams() const;
+  /// Save selected workspaces
+  void saveWorkspaces() const;
+  /// Suggest a save directory
+  void suggestSaveDir() const;
+
+private:
+  /// Initialize the interface
+  void initLayout();
+  /// The presenter
+  std::unique_ptr<IReflSaveTabPresenter> m_presenter;
+  /// The widget
+  Ui::ReflSaveTabWidget m_ui;
+};
+
+} // namespace Mantid
+} // namespace CustomInterfaces
+
+#endif /* MANTID_CUSTOMINTERFACES_QTREFLSAVETABVIEW_H_ */
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/QtReflSettingsTabView.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/QtReflSettingsTabView.h
index 4ba8ca4437a98f76bc59633e6647fefe8ed28c76..3f0df4151e6efbb778cdbeee07e056eb32e06596 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/QtReflSettingsTabView.h
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/QtReflSettingsTabView.h
@@ -1,7 +1,7 @@
 #ifndef MANTID_CUSTOMINTERFACES_QTREFLSETTINGSTABVIEW_H_
 #define MANTID_CUSTOMINTERFACES_QTREFLSETTINGSTABVIEW_H_
 
-#include "MantidQtCustomInterfaces/Reflectometry/IReflSettingsTabView.h"
+#include "MantidQtCustomInterfaces/DllConfig.h"
 #include "ui_ReflSettingsTabWidget.h"
 #include <memory>
 
@@ -35,7 +35,7 @@ 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>
 */
-class QtReflSettingsTabView : public QWidget, public IReflSettingsTabView {
+class MANTIDQT_CUSTOMINTERFACES_DLL QtReflSettingsTabView : public QWidget {
   Q_OBJECT
 public:
   /// Constructor
@@ -43,61 +43,7 @@ public:
   /// Destructor
   ~QtReflSettingsTabView() override;
   /// Returns the presenter managing this view
-  IReflSettingsTabPresenter *getPresenter() const override;
-  /// Returns global options for 'Stitch1DMany'
-  std::string getStitchOptions() const override;
-  /// Return selected analysis mode
-  std::string getAnalysisMode() const override;
-  /// Return direct beam
-  std::string getDirectBeam() const override;
-  /// Return transmission runs
-  std::string getTransmissionRuns() const override;
-  /// Return selected polarisation corrections
-  std::string getPolarisationCorrections() const override;
-  /// Return CRho
-  std::string getCRho() const override;
-  /// Return CAlpha
-  std::string getCAlpha() const override;
-  /// Return CAp
-  std::string getCAp() const override;
-  /// Return Cpp
-  std::string getCPp() const override;
-  /// Return momentum transfer limits
-  std::string getMomentumTransferStep() const override;
-  /// Return scale factor
-  std::string getScaleFactor() const override;
-  /// Return integrated monitors option
-  std::string getIntMonCheck() const override;
-  /// Return monitor integral wavelength min
-  std::string getMonitorIntegralMin() const override;
-  /// Return monitor integral wavelength max
-  std::string getMonitorIntegralMax() const override;
-  /// Return monitor background wavelength min
-  std::string getMonitorBackgroundMin() const override;
-  /// Return monitor background wavelength max
-  std::string getMonitorBackgroundMax() const override;
-  /// Return wavelength min
-  std::string getLambdaMin() const override;
-  /// Return wavelength max
-  std::string getLambdaMax() const override;
-  /// Return I0MonitorIndex
-  std::string getI0MonitorIndex() const override;
-  /// Return processing instructions
-  std::string getProcessingInstructions() const override;
-  /// Set default values for experiment and instrument settings
-  void setExpDefaults(const std::vector<std::string> &) const override;
-  void setInstDefaults(const std::vector<double> &) const override;
-
-  /// Creates hints for 'Stitch1DMany'
-  void
-  createStitchHints(const std::map<std::string, std::string> &hints) override;
-  /// Sets enabled status for polarisation corrections and parameters
-  void setPolarisationOptionsEnabled(bool enable) const override;
-
-public slots:
-  /// Request presenter to obtain default values for settings
-  void requestExpDefaults() const;
-  void requestInstDefaults() const;
+  IReflSettingsTabPresenter *getPresenter() const;
 
 private:
   /// Initialise the interface
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/QtReflSettingsView.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/QtReflSettingsView.h
new file mode 100644
index 0000000000000000000000000000000000000000..8df499be3be7e380e04c85cf831307d10cecddcb
--- /dev/null
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/QtReflSettingsView.h
@@ -0,0 +1,115 @@
+#ifndef MANTID_CUSTOMINTERFACES_QTREFLSETTINGSVIEW_H_
+#define MANTID_CUSTOMINTERFACES_QTREFLSETTINGSVIEW_H_
+
+#include "MantidQtCustomInterfaces/Reflectometry/IReflSettingsView.h"
+#include "ui_ReflSettingsWidget.h"
+#include <memory>
+
+namespace MantidQt {
+namespace CustomInterfaces {
+
+// Forward decs
+class IReflSettingsPresenter;
+
+/** QtReflSettingsView : Provides an interface for the "Settings" widget in the
+Reflectometry (Polref) interface.
+
+Copyright &copy; 2016 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>
+*/
+class QtReflSettingsView : public QWidget, public IReflSettingsView {
+  Q_OBJECT
+public:
+  /// Constructor
+  QtReflSettingsView(QWidget *parent = 0);
+  /// Destructor
+  ~QtReflSettingsView() override;
+  /// Returns the presenter managing this view
+  IReflSettingsPresenter *getPresenter() const override;
+  /// Returns global options for 'Stitch1DMany'
+  std::string getStitchOptions() const override;
+  /// Return selected analysis mode
+  std::string getAnalysisMode() const override;
+  /// Return direct beam
+  std::string getDirectBeam() const override;
+  /// Return transmission runs
+  std::string getTransmissionRuns() const override;
+  /// Return selected polarisation corrections
+  std::string getPolarisationCorrections() const override;
+  /// Return CRho
+  std::string getCRho() const override;
+  /// Return CAlpha
+  std::string getCAlpha() const override;
+  /// Return CAp
+  std::string getCAp() const override;
+  /// Return Cpp
+  std::string getCPp() const override;
+  /// Return momentum transfer limits
+  std::string getMomentumTransferStep() const override;
+  /// Return scale factor
+  std::string getScaleFactor() const override;
+  /// Return integrated monitors option
+  std::string getIntMonCheck() const override;
+  /// Return monitor integral wavelength min
+  std::string getMonitorIntegralMin() const override;
+  /// Return monitor integral wavelength max
+  std::string getMonitorIntegralMax() const override;
+  /// Return monitor background wavelength min
+  std::string getMonitorBackgroundMin() const override;
+  /// Return monitor background wavelength max
+  std::string getMonitorBackgroundMax() const override;
+  /// Return wavelength min
+  std::string getLambdaMin() const override;
+  /// Return wavelength max
+  std::string getLambdaMax() const override;
+  /// Return I0MonitorIndex
+  std::string getI0MonitorIndex() const override;
+  /// Return processing instructions
+  std::string getProcessingInstructions() const override;
+  /// Set default values for experiment and instrument settings
+  void setExpDefaults(const std::vector<std::string> &) const override;
+  void setInstDefaults(const std::vector<double> &) const override;
+
+  /// Creates hints for 'Stitch1DMany'
+  void
+  createStitchHints(const std::map<std::string, std::string> &hints) override;
+  /// Sets enabled status for polarisation corrections and parameters
+  void setPolarisationOptionsEnabled(bool enable) const override;
+
+public slots:
+  /// Request presenter to obtain default values for settings
+  void requestExpDefaults() const;
+  void requestInstDefaults() const;
+
+private:
+  /// Initialise the interface
+  void initLayout();
+
+  /// The widget
+  Ui::ReflSettingsWidget m_ui;
+  /// The presenter
+  std::unique_ptr<IReflSettingsPresenter> m_presenter;
+};
+
+} // namespace Mantid
+} // namespace CustomInterfaces
+
+#endif /* MANTID_CUSTOMINTERFACES_QTREFLSETTINGSVIEW_H_ */
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/ReflMainWindowPresenter.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/ReflMainWindowPresenter.h
index 91d82d57f2b6ed55fd028717d0dac78ae38a60bb..fca9cb6c204b7f69fc70064322234b5be1d98d19 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/ReflMainWindowPresenter.h
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/ReflMainWindowPresenter.h
@@ -10,6 +10,7 @@ namespace CustomInterfaces {
 class IReflMainWindowView;
 class IReflRunsTabPresenter;
 class IReflSettingsTabPresenter;
+class IReflSaveTabPresenter;
 
 /** @class ReflMainWindowPresenter
 
@@ -43,15 +44,16 @@ public:
   /// Constructor
   ReflMainWindowPresenter(IReflMainWindowView *view,
                           IReflRunsTabPresenter *runsPresenter,
-                          IReflSettingsTabPresenter *settingsPresenter);
+                          IReflSettingsTabPresenter *settingsPresenter,
+                          IReflSaveTabPresenter *savePresenter);
   /// Destructor
   ~ReflMainWindowPresenter() override;
   /// Returns global options for 'CreateTransmissionWorkspaceAuto'
-  std::string getTransmissionOptions() const override;
+  std::string getTransmissionOptions(int group) const override;
   /// Returns global options for 'ReflectometryReductionOneAuto'
-  std::string getReductionOptions() const override;
+  std::string getReductionOptions(int group) const override;
   /// Returns global options for 'Stitch1DMany'
-  std::string getStitchOptions() const override;
+  std::string getStitchOptions(int group) const override;
 
   /// Dialog/Prompt methods
   std::string askUserString(const std::string &prompt, const std::string &title,
@@ -76,6 +78,8 @@ private:
   IReflRunsTabPresenter *m_runsPresenter;
   /// The presenter of tab 'Settings'
   IReflSettingsTabPresenter *m_settingsPresenter;
+  /// The presenter of tab 'Save ASCII'
+  IReflSaveTabPresenter *m_savePresenter;
 };
 }
 }
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/ReflRunsTabPresenter.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/ReflRunsTabPresenter.h
index 4c859f25e3068f75f33a4ca7169b4283537dc60e..7696f2e002a7d5ff9870dd918b62dea2e7011ee0 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/ReflRunsTabPresenter.h
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/ReflRunsTabPresenter.h
@@ -59,7 +59,7 @@ class MANTIDQT_CUSTOMINTERFACES_DLL ReflRunsTabPresenter
 public:
   ReflRunsTabPresenter(IReflRunsTabView *mainView,
                        ProgressableView *progressView,
-                       DataProcessorPresenter *tablePresenter,
+                       std::vector<DataProcessorPresenter *> tablePresenter,
                        boost::shared_ptr<IReflSearcher> searcher =
                            boost::shared_ptr<IReflSearcher>());
   ~ReflRunsTabPresenter() override;
@@ -85,8 +85,8 @@ protected:
   IReflRunsTabView *m_view;
   /// The progress view
   ProgressableView *m_progressView;
-  /// The data processor presenter
-  DataProcessorPresenter *m_tablePresenter;
+  /// The data processor presenters stored in a vector
+  std::vector<DataProcessorPresenter *> m_tablePresenters;
   /// The main presenter
   IReflMainWindowPresenter *m_mainPresenter;
   /// The search implementation
@@ -98,6 +98,8 @@ protected:
   void pushCommands();
 
 private:
+  std::string m_currentTransferMethod;
+
   static const std::string LegacyTransferMethod;
   static const std::string MeasureTransferMethod;
 
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/ReflRunsTabWidget.ui b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/ReflRunsTabWidget.ui
index 402378410e06a608daae5babb22c2070978a844a..0b93c3bb4b7974d0fd459cf4dc0a6b74b26bab4d 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/ReflRunsTabWidget.ui
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/ReflRunsTabWidget.ui
@@ -246,6 +246,10 @@
            <property name="margin">
              <number>1</number>
            </property>
+           <item>
+             <widget class="QToolBox" name="toolbox">
+             </widget>
+           </item>
          </layout>
        </widget>
        </widget>
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/ReflSaveTabPresenter.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/ReflSaveTabPresenter.h
new file mode 100644
index 0000000000000000000000000000000000000000..aeaeae7559691801505e8621e45cb9862f6884a3
--- /dev/null
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/ReflSaveTabPresenter.h
@@ -0,0 +1,78 @@
+#ifndef MANTID_CUSTOMINTERFACES_REFLSAVETABPRESENTER_H
+#define MANTID_CUSTOMINTERFACES_REFLSAVETABPRESENTER_H
+
+#include "MantidQtCustomInterfaces/DllConfig.h"
+#include "MantidQtCustomInterfaces/Reflectometry/IReflSaveTabPresenter.h"
+#include <vector>
+#include <string>
+
+namespace MantidQt {
+namespace CustomInterfaces {
+
+// Forward decs
+class IReflMainWindowPresenter;
+class IReflSaveTabView;
+
+/** @class ReflSaveTabPresenter
+
+ReflSaveTabPresenter is a presenter class for the tab 'Save ASCII' in the
+Reflectometry (Polref) Interface.
+
+Copyright &copy; 2016 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>
+*/
+class MANTIDQT_CUSTOMINTERFACES_DLL ReflSaveTabPresenter
+    : public IReflSaveTabPresenter {
+public:
+  /// Constructor
+  ReflSaveTabPresenter(IReflSaveTabView *view);
+  /// Destructor
+  ~ReflSaveTabPresenter() override;
+  /// Accept a main presenter
+  void acceptMainPresenter(IReflMainWindowPresenter *mainPresenter) override;
+  void notify(IReflSaveTabPresenter::Flag flag) override;
+
+private:
+  /// Adds all workspace names to the list of workspaces
+  void populateWorkspaceList();
+  /// Adds all workspace params to the list of logged parameters
+  void populateParametersList();
+  /// Filter workspaces names
+  void filterWorkspaceNames();
+  /// Suggest a save directory
+  void suggestSaveDir();
+  /// Save selected workspaces to a directory
+  void saveWorkspaces();
+  /// Obtains all available workspace names
+  std::vector<std::string> getAvailableWorkspaceNames();
+
+  /// The view
+  IReflSaveTabView *m_view;
+  /// The main presenter
+  IReflMainWindowPresenter *m_mainPresenter;
+  /// Names of possible save algorithms
+  std::vector<std::string> m_saveAlgs;
+  /// Extensions used for each save algorithm
+  std::vector<std::string> m_saveExts;
+};
+}
+}
+#endif /* MANTID_CUSTOMINTERFACES_REFLSAVETABPRESENTER_H */
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/ReflSaveTabWidget.ui b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/ReflSaveTabWidget.ui
new file mode 100644
index 0000000000000000000000000000000000000000..682e164994229219e68b5d9ad16d79c631e5d099
--- /dev/null
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/ReflSaveTabWidget.ui
@@ -0,0 +1,351 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ReflSaveTabWidget</class>
+  <widget class="QWidget" name="ReflSaveTabWidget">
+    <property name="geometry">
+      <rect>
+        <x>0</x>
+        <y>0</y>
+        <width>959</width>
+        <height>346</height>
+      </rect>
+    </property>
+    <property name="windowTitle">
+      <string>Save ASCII</string>
+    </property>
+    <layout class="QVBoxLayout" name="verticalLayout">
+      <property name="margin">
+        <number>20</number>
+      </property>
+      <item>
+        <layout class="QHBoxLayout" name="horizontalLayout">
+          <item>
+            <widget class="QLabel" name="savePathLabel">
+              <property name="text">
+                <string>Save path:</string>
+              </property>
+            </widget>
+          </item>
+          <item>
+            <widget class="QLineEdit" name="savePathEdit"/>
+          </item>
+          <item>
+            <widget class="QLabel" name="prefixLabel">
+              <property name="text">
+                <string>Prefix:</string>
+              </property>
+            </widget>
+          </item>
+          <item>
+            <widget class="QLineEdit" name="prefixEdit"/>
+          </item>
+          <item>
+            <spacer name="prefixSpacer">
+              <property name="orientation">
+                <enum>Qt::Horizontal</enum>
+              </property>
+              <property name="sizeHint" stdset="0">
+                <size>
+                  <width>20</width>
+                  <height>20</height>
+                </size>
+              </property>
+            </spacer>
+          </item>
+        </layout>
+      </item>
+      <item>
+        <widget class="QGroupBox" name="customSaveGroup">
+          <property name="title">
+            <string>Custom save</string>
+          </property>
+          <layout class="QGridLayout" name="customSaveLayout">
+            <property name="margin">
+              <number>20</number>
+            </property>
+            <item row ="0" column="0">
+            <widget class="QLabel" name="filterLabel">
+              <property name="text">
+                <string>Filter</string>
+              </property>
+            </widget>
+            </item>
+            <item row="0" column="1">
+              <widget class="QLineEdit" name="filterEdit"/>
+            </item>
+            <item row="0" column="2">
+              <widget class="QCheckBox" name="regexCheckBox"/>
+            </item>
+            <item row="0" column="3">
+              <widget class="QLabel" name="regexLabel">
+                <property name="text">
+                  <string>Regex</string>
+                </property>
+              </widget>
+            </item>
+            <item row="0" column="4">
+              <spacer name="customSaveSpacer0">
+                <property name="orientation">
+                  <enum>Qt::Horizontal</enum>
+                </property>
+                <property name="sizeHint">
+                  <size>
+                    <width>20</width>
+                    <height>20</height>
+                  </size>
+                </property>
+              </spacer>
+            </item>
+            <item row ="1" column="0" colspan="4">
+              <widget class="QLabel" name="listOfWorkspacesLabel">
+                <property name="text">
+                  <string>List Of Workspaces</string>
+                </property>
+              </widget>
+            </item>
+            <item row="1" column="4">
+              <spacer name="customSaveSpacer1">
+                <property name="orientation">
+                  <enum>Qt::Horizontal</enum>
+                </property>
+                <property name="sizeHint">
+                  <size>
+                    <width>20</width>
+                    <height>20</height>
+                  </size>
+                </property>
+              </spacer>
+            </item>
+            <item row ="1" column="5">
+              <widget class="QLabel" name="listOfLoggedParametersLabel">
+                <property name="text">
+                  <string>List Of Logged Parameters</string>
+                </property>
+              </widget>
+            </item>
+            <item row ="2" column="0" colspan="4">
+              <widget class="QListWidget" name="listOfWorkspaces">
+                <property name="selectionMode">
+                  <enum>QAbstractItemView::ExtendedSelection</enum>
+                </property>
+              </widget>
+            </item>
+            <item row="2" column="4">
+              <spacer name="customSaveSpacer2">
+                <property name="orientation">
+                  <enum>Qt::Horizontal</enum>
+                </property>
+                <property name="sizeHint">
+                  <size>
+                    <width>20</width>
+                    <height>20</height>
+                  </size>
+                </property>
+              </spacer>
+            </item>
+            <item row ="2" column="5">
+              <widget class="QListWidget" name="listOfLoggedParameters">
+                <property name="selectionMode">
+                  <enum>QAbstractItemView::ExtendedSelection</enum>
+                </property>
+              </widget>
+            </item>
+            <item row="3" column="0" colspan="4">
+              <widget class="QPushButton" name="refreshButton">
+                <property name="text">
+                  <string>Refresh</string>
+                </property>
+              </widget>
+            </item>
+            <item row="3" column="4">
+              <spacer name="customSaveSpacer3">
+                <property name="orientation">
+                  <enum>Qt::Horizontal</enum>
+                </property>
+                <property name="sizeHint">
+                  <size>
+                    <width>20</width>
+                    <height>20</height>
+                  </size>
+                </property>
+              </spacer>
+            </item>
+            <item row="3" column="5" rowspan="4">
+              <widget class="QGroupBox" name="customFormatOptionsGroup">
+                <property name="title">
+                  <string>Custom Format Options</string>
+                </property>
+                <layout class="QGridLayout" name="customFormatOptionsLayout">
+                  <item row="0" column="0">
+                    <widget class="QCheckBox" name="titleCheckBox"/>
+                  </item>
+                  <item row="0" column="1">
+                    <widget class="QLabel" name="titleLabel">
+                      <property name="text">
+                        <string>Title</string>
+                      </property>
+                    </widget>
+                  </item>
+                  <item row="0" column="2">
+                    <widget class="QCheckBox" name="qResolutionCheckBox"/>
+                  </item>
+                  <item row="0" column="3">
+                    <widget class="QLabel" name="qResolutionLabel">
+                      <property name="text">
+                        <string>Q resolution</string>
+                      </property>
+                    </widget>
+                  </item>
+                  <item row="0" column="4">
+                    <spacer name="customFormatOptionsSpacer0">
+                      <property name="orientation">
+                        <enum>Qt::Horizontal</enum>
+                      </property>
+                      <property name="sizeHint" stdset="0">
+                        <size>
+                          <width>20</width>
+                          <height>20</height>
+                        </size>
+                      </property>
+                    </spacer>
+                  </item>
+                  <item row="1" column="0" colspan="5">
+                    <widget class="QGroupBox" name="separatorGroup">
+                      <property name="title">
+                        <string>Separator</string>
+                      </property>
+                      <layout class="QGridLayout" name="separatorLayout">
+                        <item row="0" column="0">
+                          <widget class="QRadioButton" name="commaRadioButton">
+                            <property name="text">
+                              <string>Comma</string>
+                            </property>
+                            <property name="checked">
+                              <bool>true</bool>
+                            </property>
+                            <attribute name="buttonGroup">
+                              <string notr="true">separatorButtonGroup</string>
+                            </attribute>
+                          </widget>
+                        </item>
+                        <item row="0" column="1">
+                          <widget class="QRadioButton" name="spaceRadioButton">
+                            <property name="text">
+                              <string>Space</string>
+                            </property>
+                            <attribute name="buttonGroup">
+                              <string notr="true">separatorButtonGroup</string>
+                            </attribute>
+                          </widget>
+                        </item>
+                        <item row="0" column="2">
+                          <widget class="QRadioButton" name="tabRadioButton">
+                            <property name="text">
+                              <string>Tab</string>
+                            </property>
+                            <attribute name="buttonGroup">
+                              <string notr="true">separatorButtonGroup</string>
+                            </attribute>
+                          </widget>
+                        </item>
+                        <item row="0" column="3">
+                          <spacer name="separatorSpacer0">
+                            <property name="orientation">
+                              <enum>Qt::Horizontal</enum>
+                            </property>
+                            <property name="sizeHint" stdset="0">
+                              <size>
+                                <width>20</width>
+                                <height>20</height>
+                              </size>
+                            </property>
+                          </spacer>
+                        </item>
+                      </layout>
+                    </widget>
+                  </item>
+                </layout>
+              </widget>
+            </item>     
+            <item row ="5" column="0">
+              <widget class="QLabel" name="fileFormatLabel">
+                <property name="text">
+                  <string>File format</string>
+                </property>
+              </widget>
+            </item>
+            <item row="5" column="1" colspan="3">
+              <widget class="QComboBox" name="fileFormatComboBox">
+                <item>
+                  <property name="text">
+                    <string>Custom format (*.dat)</string>
+                  </property>
+                </item>
+                <item>
+                  <property name="text">
+                    <string>3 column (*.dat)</string>
+                  </property>
+                </item>
+                <item>
+                  <property name="text">
+                    <string>ANSTO, MotoFit, 4 column (*.txt)</string>
+                  </property>
+                </item>
+                <item>
+                  <property name="text">
+                    <string>ILL Cosmos (*.mft)</string>
+                  </property>
+                </item>
+                <property name="font">
+                  <font>
+                    <bold>true</bold>
+                  </font>
+                </property>
+              </widget>
+            </item>
+            <item row="5" column="4">
+              <spacer name="customSaveSpacer5">
+                <property name="orientation">
+                  <enum>Qt::Horizontal</enum>
+                </property>
+                <property name="sizeHint" stdset="0">
+                  <size>
+                    <width>20</width>
+                    <height>20</height>
+                  </size>
+                </property>
+              </spacer>
+            </item>
+            <item row="6" column="0" colspan="4">
+              <widget class="QPushButton" name="saveButton">
+                <property name="text">
+                  <string>Save</string>
+                </property>
+              </widget>
+            </item>
+            <item row="6" column="4">
+              <spacer name="customSaveSpacer6">
+                <property name="orientation">
+                  <enum>Qt::Horizontal</enum>
+                </property>
+                <property name="sizeHint" stdset="0">
+                  <size>
+                    <width>20</width>
+                    <height>20</height>
+                  </size>
+                </property>
+              </spacer>
+            </item>    
+          </layout>
+        </widget>
+      </item>
+    </layout>
+  </widget>
+ <tabstops/>
+ <customwidgets/>
+ <resources/>
+ <connections/>
+<buttongroups>
+  <buttongroup name="separatorButtonGroup"/>
+</buttongroups>
+</ui>
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/ReflSettingsPresenter.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/ReflSettingsPresenter.h
new file mode 100644
index 0000000000000000000000000000000000000000..3733ea3ed4067cfe112034e2c50f977610d01f37
--- /dev/null
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/ReflSettingsPresenter.h
@@ -0,0 +1,75 @@
+#ifndef MANTID_CUSTOMINTERFACES_REFLSETTINGSPRESENTER_H
+#define MANTID_CUSTOMINTERFACES_REFLSETTINGSPRESENTER_H
+
+#include "MantidAPI/IAlgorithm_fwd.h"
+#include "MantidGeometry/Instrument_fwd.h"
+#include "MantidQtCustomInterfaces/DllConfig.h"
+#include "MantidQtCustomInterfaces/Reflectometry/IReflSettingsPresenter.h"
+
+namespace MantidQt {
+namespace CustomInterfaces {
+
+// Forward decs
+class IReflSettingsView;
+
+/** @class ReflSettingsPresenter
+
+ReflSettingsPresenter is a presenter class for the widget 'Settings' in the
+Reflectometry (Polref) Interface.
+
+Copyright &copy; 2011-16 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>
+*/
+class MANTIDQT_CUSTOMINTERFACES_DLL ReflSettingsPresenter
+    : public IReflSettingsPresenter {
+public:
+  /// Constructor
+  ReflSettingsPresenter(IReflSettingsView *view);
+  /// Destructor
+  ~ReflSettingsPresenter() override;
+  void notify(IReflSettingsPresenter::Flag flag) override;
+  void setInstrumentName(const std::string &instName) override;
+
+  /// Returns global options for 'CreateTransmissionWorkspaceAuto'
+  std::string getTransmissionOptions() const override;
+  /// Returns global options for 'ReflectometryReductionOneAuto'
+  std::string getReductionOptions() const override;
+  /// Returns global options for 'Stitch1DMany'
+  std::string getStitchOptions() const override;
+
+private:
+  void createStitchHints();
+  void getExpDefaults();
+  void getInstDefaults();
+  void wrapWithQuotes(std::string &str) const;
+  Mantid::API::IAlgorithm_sptr createReductionAlg();
+  Mantid::Geometry::Instrument_const_sptr
+  createEmptyInstrument(const std::string &instName);
+  std::string getTransmissionRuns() const;
+
+  /// The view we are managing
+  IReflSettingsView *m_view;
+  /// Name of the current instrument in use
+  std::string m_currentInstrumentName;
+};
+}
+}
+#endif /* MANTID_CUSTOMINTERFACES_REFLSETTINGSPRESENTER_H */
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/ReflSettingsTabPresenter.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/ReflSettingsTabPresenter.h
index 185428ebee3fa6dcd490f52a84428b78443309d2..ce53514041ff2775d080ea874c8a1bc85702873b 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/ReflSettingsTabPresenter.h
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/ReflSettingsTabPresenter.h
@@ -3,18 +3,14 @@
 
 #include "MantidQtCustomInterfaces/DllConfig.h"
 #include "MantidQtCustomInterfaces/Reflectometry/IReflSettingsTabPresenter.h"
-#include "MantidAPI/IAlgorithm.h"
-#include "MantidGeometry/Instrument.h"
+#include <vector>
 
 namespace MantidQt {
 namespace CustomInterfaces {
 
-using namespace Mantid::API;
-using namespace Mantid::Geometry;
-
 // Forward decs
 class IReflMainWindowPresenter;
-class IReflSettingsTabView;
+class IReflSettingsPresenter;
 
 /** @class ReflSettingsTabPresenter
 
@@ -46,35 +42,22 @@ class MANTIDQT_CUSTOMINTERFACES_DLL ReflSettingsTabPresenter
     : public IReflSettingsTabPresenter {
 public:
   /// Constructor
-  ReflSettingsTabPresenter(IReflSettingsTabView *view);
+  ReflSettingsTabPresenter(std::vector<IReflSettingsPresenter *> presenters);
   /// Destructor
   ~ReflSettingsTabPresenter() override;
-  /// Accept a main presenter
-  void acceptMainPresenter(IReflMainWindowPresenter *mainPresenter) override;
-  void notify(IReflSettingsTabPresenter::Flag flag) override;
-  void setInstrumentName(const std::string instName) override;
+  /// Set the instrument name
+  void setInstrumentName(const std::string &instName) override;
 
   /// Returns global options for 'CreateTransmissionWorkspaceAuto'
-  std::string getTransmissionOptions() const override;
+  std::string getTransmissionOptions(int group) const override;
   /// Returns global options for 'ReflectometryReductionOneAuto'
-  std::string getReductionOptions() const override;
+  std::string getReductionOptions(int group) const override;
   /// Returns global options for 'Stitch1DMany'
-  std::string getStitchOptions() const override;
+  std::string getStitchOptions(int group) const override;
 
 private:
-  void createStitchHints();
-  void getExpDefaults();
-  void getInstDefaults();
-  IAlgorithm_sptr createReductionAlg();
-  Instrument_const_sptr createEmptyInstrument(std::string instName);
-  std::string getTransmissionRuns() const;
-
-  /// The view we are managing
-  IReflSettingsTabView *m_view;
-  /// The main presenter
-  IReflMainWindowPresenter *m_mainPresenter;
-  /// Name of the current instrument in use
-  std::string m_currentInstrumentName;
+  /// The presenters for each group as a vector
+  std::vector<IReflSettingsPresenter *> m_settingsPresenters;
 };
 }
 }
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/ReflSettingsTabWidget.ui b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/ReflSettingsTabWidget.ui
index 968b04ed0635dcf8cad15aaebe0925fe5dbbd8da..f015e7a8a514ad8074580efb0827432b7106399d 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/ReflSettingsTabWidget.ui
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/ReflSettingsTabWidget.ui
@@ -18,522 +18,7 @@
         <number>5</number>
       </property>
       <item>
-        <widget class="QGroupBox" name="expSettingsGroup">
-          <property name="title">
-            <string>Experiment Settings</string>
-          </property>
-          <property name="checkable">
-            <bool>true</bool>
-          </property>
-          <layout class="QHBoxLayout" name="expSettingsLayoutContainer">
-            <item>
-              <layout class="QGridLayout" name="expSettingsLayout0">
-                <property name="margin">
-                  <number>10</number>
-                </property>
-                <item row="0" column="0">
-                  <widget class="QLabel" name="analysisModeLabel">
-                    <property name="text">
-                      <string>AnalysisMode</string>
-                    </property>
-                  </widget>
-                </item>
-                <item row="0" column="1">
-                  <widget class="QComboBox" name="analysisModeComboBox">
-                    <item>
-                      <property name="text">
-                        <string>PointDetectorAnalysis</string>
-                      </property>
-                    </item>
-                    <item>
-                      <property name="text">
-                        <string>MultiDetectorAnalysis</string>
-                      </property>
-                    </item>
-                  </widget>
-                </item>
-                <item row="0" column="2">
-                  <widget class="QLabel" name="expSettingsDirectBeamLabel">
-                    <property name="text">
-                      <string>DirectBeam</string>
-                    </property>
-                  </widget>
-                </item>
-                <item row="0" column="3">
-                  <widget class="QLineEdit" name="directBeamEdit"/>
-                </item>
-                <item row="0" column="4">
-                  <spacer name="expSettings0Spacer0">
-                    <property name="orientation">
-                      <enum>Qt::Horizontal</enum>
-                    </property>
-                    <property name="sizeHint" stdset="0">
-                      <size>
-                        <width>20</width>
-                        <height>20</height>
-                      </size>
-                    </property>
-                  </spacer>
-                </item>
-                <item row="1" column="0">
-                  <widget class="QLabel" name="transmissionRunsLabel">
-                    <property name="text">
-                      <string>Transmission run(s)</string>
-                    </property>
-                  </widget>
-                </item>
-                <item row="1" column="1">
-                  <widget class="QLineEdit" name="transmissionRunsEdit"/>
-                </item>
-                <item row="1" column="2">
-                  <spacer name="expSettings0Spacer1">
-                    <property name="orientation">
-                      <enum>Qt::Horizontal</enum>
-                    </property>
-                    <property name="sizeHint" stdset="0">
-                      <size>
-                        <width>20</width>
-                        <height>20</height>
-                      </size>
-                    </property>
-                  </spacer>
-                </item>
-                <item row="2" column="0">
-                  <widget class="QLabel" name="startOverlapLabel">
-                    <property name="text">
-                      <string>StartOverlap</string>
-                    </property>
-                  </widget>
-                </item>
-                <item row="2" column="1">
-                  <widget class="QLineEdit" name="startOverlapEdit"/>
-                </item>
-                <item row="2" column="2">
-                  <widget class="QLabel" name="endOverlapLabel">
-                    <property name="text">
-                      <string>EndOverlap</string>
-                    </property>
-                  </widget>
-                </item>
-                <item row="2" column="3">
-                  <widget class="QLineEdit" name="endOverlapEdit"/>
-                </item>
-                <item row="2" column="4">
-                  <spacer name="expSettings0Spacer2">
-                    <property name="orientation">
-                      <enum>Qt::Horizontal</enum>
-                    </property>
-                    <property name="sizeHint" stdset="0">
-                      <size>
-                        <width>20</width>
-                        <height>20</height>
-                      </size>
-                    </property>
-                  </spacer>
-                </item>
-                <item row="3" column="0">
-                  <widget class="QLabel" name="polCorrLabel">
-                    <property name="text">
-                      <string>PolarisationCorrections</string>
-                    </property>
-                  </widget>
-                </item>
-                <item row="3" column="1">
-                  <widget class="QComboBox" name="polCorrComboBox">
-                    <item>
-                      <property name="text">
-                        <string>None</string>
-                      </property>
-                    </item>
-                    <item>
-                      <property name="text">
-                        <string>PA</string>
-                      </property>
-                    </item>
-                    <item>
-                      <property name="text">
-                        <string>PNR</string>
-                      </property>
-                    </item>
-                  </widget>
-                </item>
-                <item row="3" column="2">
-                  <spacer name="expSettings0Spacer3">
-                    <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 row="4" column="0">
-                  <widget class="QLabel" name="CRhoLabel">
-                    <property name="text">
-                      <string>CRho</string>
-                    </property>
-                  </widget>
-                </item>
-                <item row="4" column="1">
-                  <widget class="QLineEdit" name="CRhoEdit"/>
-                </item>
-                <item row="4" column="2">
-                  <widget class="QLabel" name="CAlphaLabel">
-                    <property name="text">
-                      <string>CAlpha</string>
-                    </property>
-                  </widget>
-                </item>
-                <item row="4" column="3">
-                  <widget class="QLineEdit" name="CAlphaEdit"/>
-                </item>
-                <item row="4" column="4">
-                  <spacer name="expSettings0Spacer4">
-                    <property name="orientation">
-                      <enum>Qt::Horizontal</enum>
-                    </property>
-                    <property name="sizeHint" stdset="0">
-                      <size>
-                        <width>20</width>
-                        <height>20</height>
-                      </size>
-                    </property>
-                  </spacer>
-                </item>
-                <item row="5" column="0">
-                  <widget class="QLabel" name="CApLabel">
-                    <property name="text">
-                      <string>CAp</string>
-                    </property>
-                  </widget>
-                </item>
-                <item row="5" column="1">
-                  <widget class="QLineEdit" name="CApEdit"/>
-                </item>
-                <item row="5" column="2">
-                  <widget class="QLabel" name="CPpLabel">
-                    <property name="text">
-                      <string>CPp</string>
-                    </property>
-                  </widget>
-                </item>
-                <item row="5" column="3">
-                  <widget class="QLineEdit" name="CPpEdit"/>
-                </item>
-                <item row="5" column="4">
-                  <spacer name="expSettings0Spacer5">
-                    <property name="orientation">
-                      <enum>Qt::Horizontal</enum>
-                    </property>
-                    <property name="sizeHint" stdset="0">
-                      <size>
-                        <width>20</width>
-                        <height>20</height>
-                      </size>
-                    </property>
-                  </spacer>
-                </item>
-                <item row="6" column="0">
-                  <widget class="QLabel" name="momentumTransferStepLabel">
-                    <property name="text">
-                      <string>dQ/Q</string>
-                    </property>
-                  </widget>
-                </item>
-                <item row="6" column="1">
-                  <widget class="QLineEdit" name="momentumTransferStepEdit"/>
-                </item>
-                <item row="6" column="2">
-                  <widget class="QLabel" name="scaleFactorLabel">
-                    <property name="text">
-                      <string>Scale</string>
-                    </property>
-                  </widget>
-                </item>
-                <item row="6" column="3">
-                  <widget class="QLineEdit" name="scaleFactorEdit"/>
-                </item>
-                <item row="6" column="4">
-                  <spacer name="expSettings0Spacer6">
-                    <property name="orientation">
-                      <enum>Qt::Horizontal</enum>
-                    </property>
-                    <property name="sizeHint" stdset="0">
-                      <size>
-                        <width>20</width>
-                        <height>20</height>
-                      </size>
-                    </property>
-                  </spacer>
-                </item>
-                <item row="7" column="0">
-                  <widget class="QLabel" name="stitchLabel">
-                    <property name="text">
-                      <string>Stitch1DMany</string>
-                    </property>
-                  </widget>
-                </item>
-                <item row="7" column="4">
-                  <spacer name="expSettings0Spacer7">
-                    <property name="orientation">
-                      <enum>Qt::Horizontal</enum>
-                    </property>
-                    <property name="sizeHint" stdset="0">
-                      <size>
-                        <width>20</width>
-                        <height>20</height>
-                      </size>
-                    </property>
-                  </spacer>
-                </item>
-              </layout>
-            </item>
-            <item>
-              <layout class="QGridLayout" name="expSettingsLayout1">
-                <property name="margin">
-                  <number>10</number>
-                </property>
-                <item row="0" column="0">
-                  <widget class="QPushButton" name="getExpDefaultsButton">
-                    <property name="fixedWidth">
-                      <number>70</number>
-                    </property>
-                    <property name="fixedHeight">
-                      <number>100</number>
-                    </property>
-                    <layout class="QHBoxLayout" name="getExpDefaultsButtonLayout">
-                      <item>
-                        <widget class="QLabel" name="getExpDefaultsButtonLabel">
-                          <property name="wordWrap">
-                            <bool>true</bool>
-                          </property>
-                          <property name="alignment">
-                            <set>Qt::AlignCenter</set>
-                          </property>
-                          <property name="text">
-                            <string>Get Defaults</string>
-                          </property>
-                        </widget>
-                      </item>
-                    </layout>
-                  </widget>
-                </item>
-              </layout>
-            </item>
-          </layout>
-        </widget>
-      </item>
-      <item>
-        <widget class="QGroupBox" name="instSettingsGroup">
-          <property name="title">
-            <string>Instrument Settings</string>
-          </property>
-          <property name="checkable">
-            <bool>true</bool>
-          </property>
-          <layout class="QHBoxLayout" name="instSettingsLayoutContainer">
-            <item>
-              <layout class="QGridLayout" name="instSettingsLayout0">
-                <property name="margin">
-                  <number>10</number>
-                </property>
-                <item row="0" column="0">
-                  <widget class="QLabel" name="intMonCheckLabel">
-                    <property name="text">
-                      <string>IntegratedMonitors</string>
-                    </property>
-                  </widget>
-                </item>
-                <item row="0" column="1">
-                  <widget class="QCheckBox" name="intMonCheckBox">
-                    <property name="checkState">
-                      <set>Qt::Checked</set>
-                    </property>
-                  </widget>
-                </item>
-                <item row="0" column="2">
-                  <spacer name="instSettings0Spacer0">
-                    <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 row="1" column="0">
-                  <widget class="QLabel" name="monIntMinLabel">
-                    <property name="text">
-                      <string>MonitorIntegralMin</string>
-                    </property>
-                  </widget>
-                </item>
-                <item row="1" column="1">
-                  <widget class="QLineEdit" name="monIntMinEdit"/>
-                </item>
-                <item row="1" column="2">
-                  <widget class="QLabel" name="monIntMaxLabel">
-                    <property name="text">
-                      <string>MonitorIntegralMax</string>
-                    </property>
-                  </widget>
-                </item>
-                <item row="1" column="3">
-                  <widget class="QLineEdit" name="monIntMaxEdit"/>
-                </item>
-                <item row="1" column="4">
-                  <spacer name="instSettings0Spacer1">
-                    <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 row="2" column="0">
-                  <widget class="QLabel" name="monBgMinLabel">
-                    <property name="text">
-                      <string>MonitorBackgroundMin</string>
-                    </property>
-                  </widget>
-                </item>
-                <item row="2" column="1">
-                  <widget class="QLineEdit" name="monBgMinEdit"/>
-                </item>
-                <item row="2" column="2">
-                  <widget class="QLabel" name="monBgMaxLabel">
-                    <property name="text">
-                      <string>MonitorBackgroundMax</string>
-                    </property>
-                  </widget>
-                </item>
-                <item row="2" column="3">
-                  <widget class="QLineEdit" name="monBgMaxEdit"/>
-                </item>
-                <item row="2" column="4">
-                  <spacer name="instSettings0Spacer2">
-                    <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 row="3" column="0">
-                  <widget class="QLabel" name="lamMinLabel">
-                    <property name="text">
-                      <string>LambdaMin</string>
-                    </property>
-                  </widget>
-                </item>
-                <item row="3" column="1">
-                  <widget class="QLineEdit" name="lamMinEdit"/>
-                </item>
-                <item row="3" column="2">
-                  <widget class="QLabel" name="lamMaxLabel">
-                    <property name="text">
-                      <string>LambdaMax</string>
-                    </property>
-                  </widget>
-                </item>
-                <item row="3" column="3">
-                  <widget class="QLineEdit" name="lamMaxEdit"/>
-                </item>
-                <item row="3" column="4">
-                  <spacer name="instSettings0Spacer3">
-                    <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 row="4" column="0">
-                  <widget class="QLabel" name="I0MonIndexLabel">
-                    <property name="text">
-                      <string>I0MonitorIndex</string>
-                    </property>
-                  </widget>
-                </item>
-                <item row="4" column="1">
-                  <widget class="QLineEdit" name="I0MonIndexEdit"/>
-                </item>
-                <item row="4" column="2">
-                  <widget class="QLabel" name="procInstLabel">
-                    <property name="text">
-                      <string>ProcessingInstructions</string>
-                    </property>
-                  </widget>
-                </item>
-                <item row="4" column="3">
-                  <widget class="QLineEdit" name="procInstEdit"/>
-                </item>
-                <item row="4" column="4">
-                  <spacer name="instSettings0Spacer4">
-                    <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>
-              <layout class="QGridLayout" name="instSettingsLayout1">
-                <property name="margin">
-                  <number>10</number>
-                </property>
-                <item row="0" column="0">
-                  <widget class="QPushButton" name="getInstDefaultsButton">
-                    <property name="fixedWidth">
-                      <number>70</number>
-                    </property>
-                    <property name="fixedHeight">
-                      <number>100</number>
-                    </property>
-                    <layout class="QHBoxLayout" name="getInstDefaultsButtonLayout">
-                      <item>
-                        <widget class="QLabel" name="getInstDefaultsButtonLabel">
-                          <property name="wordWrap">
-                            <bool>true</bool>
-                          </property>
-                          <property name="alignment">
-                            <set>Qt::AlignCenter</set>
-                          </property>
-                          <property name="text">
-                            <string>Get Defaults</string>
-                          </property>
-                        </widget>
-                      </item>
-                    </layout>
-                  </widget>
-                </item>
-              </layout>
-            </item>
-          </layout>
+        <widget class="QToolBox" name="toolbox">
         </widget>
       </item>
     </layout>
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/ReflSettingsWidget.ui b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/ReflSettingsWidget.ui
new file mode 100644
index 0000000000000000000000000000000000000000..ce85e5f7ca844b38d4ef757327190194dbb603f3
--- /dev/null
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Reflectometry/ReflSettingsWidget.ui
@@ -0,0 +1,545 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+  <class>ReflSettingsWidget</class>
+  <widget class="QWidget" name="ReflSettingsWidget">
+    <property name="geometry">
+      <rect>
+        <x>0</x>
+        <y>0</y>
+        <width>959</width>
+        <height>346</height>
+      </rect>
+    </property>
+    <property name="windowTitle">
+      <string>Settings Tab</string>
+    </property>
+    <layout class="QVBoxLayout" name="settingsMainLayout">
+      <property name="margin">
+        <number>5</number>
+      </property>
+      <item>
+        <widget class="QGroupBox" name="expSettingsGroup">
+          <property name="title">
+            <string>Experiment Settings</string>
+          </property>
+          <property name="checkable">
+            <bool>true</bool>
+          </property>
+          <layout class="QHBoxLayout" name="expSettingsLayoutContainer">
+            <item>
+              <layout class="QGridLayout" name="expSettingsLayout0">
+                <property name="margin">
+                  <number>10</number>
+                </property>
+                <item row="0" column="0">
+                  <widget class="QLabel" name="analysisModeLabel">
+                    <property name="text">
+                      <string>AnalysisMode</string>
+                    </property>
+                  </widget>
+                </item>
+                <item row="0" column="1">
+                  <widget class="QComboBox" name="analysisModeComboBox">
+                    <item>
+                      <property name="text">
+                        <string>PointDetectorAnalysis</string>
+                      </property>
+                    </item>
+                    <item>
+                      <property name="text">
+                        <string>MultiDetectorAnalysis</string>
+                      </property>
+                    </item>
+                  </widget>
+                </item>
+                <item row="0" column="2">
+                  <widget class="QLabel" name="expSettingsDirectBeamLabel">
+                    <property name="text">
+                      <string>DirectBeam</string>
+                    </property>
+                  </widget>
+                </item>
+                <item row="0" column="3">
+                  <widget class="QLineEdit" name="directBeamEdit"/>
+                </item>
+                <item row="0" column="4">
+                  <spacer name="expSettings0Spacer0">
+                    <property name="orientation">
+                      <enum>Qt::Horizontal</enum>
+                    </property>
+                    <property name="sizeHint" stdset="0">
+                      <size>
+                        <width>20</width>
+                        <height>20</height>
+                      </size>
+                    </property>
+                  </spacer>
+                </item>
+                <item row="1" column="0">
+                  <widget class="QLabel" name="transmissionRunsLabel">
+                    <property name="text">
+                      <string>Transmission run(s)</string>
+                    </property>
+                  </widget>
+                </item>
+                <item row="1" column="1">
+                  <widget class="QLineEdit" name="transmissionRunsEdit"/>
+                </item>
+                <item row="1" column="2">
+                  <spacer name="expSettings0Spacer1">
+                    <property name="orientation">
+                      <enum>Qt::Horizontal</enum>
+                    </property>
+                    <property name="sizeHint" stdset="0">
+                      <size>
+                        <width>20</width>
+                        <height>20</height>
+                      </size>
+                    </property>
+                  </spacer>
+                </item>
+                <item row="2" column="0">
+                  <widget class="QLabel" name="startOverlapLabel">
+                    <property name="text">
+                      <string>StartOverlap</string>
+                    </property>
+                  </widget>
+                </item>
+                <item row="2" column="1">
+                  <widget class="QLineEdit" name="startOverlapEdit"/>
+                </item>
+                <item row="2" column="2">
+                  <widget class="QLabel" name="endOverlapLabel">
+                    <property name="text">
+                      <string>EndOverlap</string>
+                    </property>
+                  </widget>
+                </item>
+                <item row="2" column="3">
+                  <widget class="QLineEdit" name="endOverlapEdit"/>
+                </item>
+                <item row="2" column="4">
+                  <spacer name="expSettings0Spacer2">
+                    <property name="orientation">
+                      <enum>Qt::Horizontal</enum>
+                    </property>
+                    <property name="sizeHint" stdset="0">
+                      <size>
+                        <width>20</width>
+                        <height>20</height>
+                      </size>
+                    </property>
+                  </spacer>
+                </item>
+                <item row="3" column="0">
+                  <widget class="QLabel" name="polCorrLabel">
+                    <property name="text">
+                      <string>PolarisationCorrections</string>
+                    </property>
+                  </widget>
+                </item>
+                <item row="3" column="1">
+                  <widget class="QComboBox" name="polCorrComboBox">
+                    <item>
+                      <property name="text">
+                        <string>None</string>
+                      </property>
+                    </item>
+                    <item>
+                      <property name="text">
+                        <string>PA</string>
+                      </property>
+                    </item>
+                    <item>
+                      <property name="text">
+                        <string>PNR</string>
+                      </property>
+                    </item>
+                  </widget>
+                </item>
+                <item row="3" column="2">
+                  <spacer name="expSettings0Spacer3">
+                    <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 row="4" column="0">
+                  <widget class="QLabel" name="CRhoLabel">
+                    <property name="text">
+                      <string>CRho</string>
+                    </property>
+                  </widget>
+                </item>
+                <item row="4" column="1">
+                  <widget class="QLineEdit" name="CRhoEdit"/>
+                </item>
+                <item row="4" column="2">
+                  <widget class="QLabel" name="CAlphaLabel">
+                    <property name="text">
+                      <string>CAlpha</string>
+                    </property>
+                  </widget>
+                </item>
+                <item row="4" column="3">
+                  <widget class="QLineEdit" name="CAlphaEdit"/>
+                </item>
+                <item row="4" column="4">
+                  <spacer name="expSettings0Spacer4">
+                    <property name="orientation">
+                      <enum>Qt::Horizontal</enum>
+                    </property>
+                    <property name="sizeHint" stdset="0">
+                      <size>
+                        <width>20</width>
+                        <height>20</height>
+                      </size>
+                    </property>
+                  </spacer>
+                </item>
+                <item row="5" column="0">
+                  <widget class="QLabel" name="CApLabel">
+                    <property name="text">
+                      <string>CAp</string>
+                    </property>
+                  </widget>
+                </item>
+                <item row="5" column="1">
+                  <widget class="QLineEdit" name="CApEdit"/>
+                </item>
+                <item row="5" column="2">
+                  <widget class="QLabel" name="CPpLabel">
+                    <property name="text">
+                      <string>CPp</string>
+                    </property>
+                  </widget>
+                </item>
+                <item row="5" column="3">
+                  <widget class="QLineEdit" name="CPpEdit"/>
+                </item>
+                <item row="5" column="4">
+                  <spacer name="expSettings0Spacer5">
+                    <property name="orientation">
+                      <enum>Qt::Horizontal</enum>
+                    </property>
+                    <property name="sizeHint" stdset="0">
+                      <size>
+                        <width>20</width>
+                        <height>20</height>
+                      </size>
+                    </property>
+                  </spacer>
+                </item>
+                <item row="6" column="0">
+                  <widget class="QLabel" name="momentumTransferStepLabel">
+                    <property name="text">
+                      <string>dQ/Q</string>
+                    </property>
+                  </widget>
+                </item>
+                <item row="6" column="1">
+                  <widget class="QLineEdit" name="momentumTransferStepEdit"/>
+                </item>
+                <item row="6" column="2">
+                  <widget class="QLabel" name="scaleFactorLabel">
+                    <property name="text">
+                      <string>Scale</string>
+                    </property>
+                  </widget>
+                </item>
+                <item row="6" column="3">
+                  <widget class="QLineEdit" name="scaleFactorEdit"/>
+                </item>
+                <item row="6" column="4">
+                  <spacer name="expSettings0Spacer6">
+                    <property name="orientation">
+                      <enum>Qt::Horizontal</enum>
+                    </property>
+                    <property name="sizeHint" stdset="0">
+                      <size>
+                        <width>20</width>
+                        <height>20</height>
+                      </size>
+                    </property>
+                  </spacer>
+                </item>
+                <item row="7" column="0">
+                  <widget class="QLabel" name="stitchLabel">
+                    <property name="text">
+                      <string>Stitch1DMany</string>
+                    </property>
+                  </widget>
+                </item>
+                <item row="7" column="4">
+                  <spacer name="expSettings0Spacer7">
+                    <property name="orientation">
+                      <enum>Qt::Horizontal</enum>
+                    </property>
+                    <property name="sizeHint" stdset="0">
+                      <size>
+                        <width>20</width>
+                        <height>20</height>
+                      </size>
+                    </property>
+                  </spacer>
+                </item>
+              </layout>
+            </item>
+            <item>
+              <layout class="QGridLayout" name="expSettingsLayout1">
+                <property name="margin">
+                  <number>10</number>
+                </property>
+                <item row="0" column="0">
+                  <widget class="QPushButton" name="getExpDefaultsButton">
+                    <property name="fixedWidth">
+                      <number>70</number>
+                    </property>
+                    <property name="fixedHeight">
+                      <number>100</number>
+                    </property>
+                    <layout class="QHBoxLayout" name="getExpDefaultsButtonLayout">
+                      <item>
+                        <widget class="QLabel" name="getExpDefaultsButtonLabel">
+                          <property name="wordWrap">
+                            <bool>true</bool>
+                          </property>
+                          <property name="alignment">
+                            <set>Qt::AlignCenter</set>
+                          </property>
+                          <property name="text">
+                            <string>Get Defaults</string>
+                          </property>
+                        </widget>
+                      </item>
+                    </layout>
+                  </widget>
+                </item>
+              </layout>
+            </item>
+          </layout>
+        </widget>
+      </item>
+      <item>
+        <widget class="QGroupBox" name="instSettingsGroup">
+          <property name="title">
+            <string>Instrument Settings</string>
+          </property>
+          <property name="checkable">
+            <bool>true</bool>
+          </property>
+          <layout class="QHBoxLayout" name="instSettingsLayoutContainer">
+            <item>
+              <layout class="QGridLayout" name="instSettingsLayout0">
+                <property name="margin">
+                  <number>10</number>
+                </property>
+                <item row="0" column="0">
+                  <widget class="QLabel" name="intMonCheckLabel">
+                    <property name="text">
+                      <string>IntegratedMonitors</string>
+                    </property>
+                  </widget>
+                </item>
+                <item row="0" column="1">
+                  <widget class="QCheckBox" name="intMonCheckBox">
+                    <property name="checkState">
+                      <set>Qt::Checked</set>
+                    </property>
+                  </widget>
+                </item>
+                <item row="0" column="2">
+                  <spacer name="instSettings0Spacer0">
+                    <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 row="1" column="0">
+                  <widget class="QLabel" name="monIntMinLabel">
+                    <property name="text">
+                      <string>MonitorIntegralMin</string>
+                    </property>
+                  </widget>
+                </item>
+                <item row="1" column="1">
+                  <widget class="QLineEdit" name="monIntMinEdit"/>
+                </item>
+                <item row="1" column="2">
+                  <widget class="QLabel" name="monIntMaxLabel">
+                    <property name="text">
+                      <string>MonitorIntegralMax</string>
+                    </property>
+                  </widget>
+                </item>
+                <item row="1" column="3">
+                  <widget class="QLineEdit" name="monIntMaxEdit"/>
+                </item>
+                <item row="1" column="4">
+                  <spacer name="instSettings0Spacer1">
+                    <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 row="2" column="0">
+                  <widget class="QLabel" name="monBgMinLabel">
+                    <property name="text">
+                      <string>MonitorBackgroundMin</string>
+                    </property>
+                  </widget>
+                </item>
+                <item row="2" column="1">
+                  <widget class="QLineEdit" name="monBgMinEdit"/>
+                </item>
+                <item row="2" column="2">
+                  <widget class="QLabel" name="monBgMaxLabel">
+                    <property name="text">
+                      <string>MonitorBackgroundMax</string>
+                    </property>
+                  </widget>
+                </item>
+                <item row="2" column="3">
+                  <widget class="QLineEdit" name="monBgMaxEdit"/>
+                </item>
+                <item row="2" column="4">
+                  <spacer name="instSettings0Spacer2">
+                    <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 row="3" column="0">
+                  <widget class="QLabel" name="lamMinLabel">
+                    <property name="text">
+                      <string>LambdaMin</string>
+                    </property>
+                  </widget>
+                </item>
+                <item row="3" column="1">
+                  <widget class="QLineEdit" name="lamMinEdit"/>
+                </item>
+                <item row="3" column="2">
+                  <widget class="QLabel" name="lamMaxLabel">
+                    <property name="text">
+                      <string>LambdaMax</string>
+                    </property>
+                  </widget>
+                </item>
+                <item row="3" column="3">
+                  <widget class="QLineEdit" name="lamMaxEdit"/>
+                </item>
+                <item row="3" column="4">
+                  <spacer name="instSettings0Spacer3">
+                    <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 row="4" column="0">
+                  <widget class="QLabel" name="I0MonIndexLabel">
+                    <property name="text">
+                      <string>I0MonitorIndex</string>
+                    </property>
+                  </widget>
+                </item>
+                <item row="4" column="1">
+                  <widget class="QLineEdit" name="I0MonIndexEdit"/>
+                </item>
+                <item row="4" column="2">
+                  <widget class="QLabel" name="procInstLabel">
+                    <property name="text">
+                      <string>ProcessingInstructions</string>
+                    </property>
+                  </widget>
+                </item>
+                <item row="4" column="3">
+                  <widget class="QLineEdit" name="procInstEdit"/>
+                </item>
+                <item row="4" column="4">
+                  <spacer name="instSettings0Spacer4">
+                    <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>
+              <layout class="QGridLayout" name="instSettingsLayout1">
+                <property name="margin">
+                  <number>10</number>
+                </property>
+                <item row="0" column="0">
+                  <widget class="QPushButton" name="getInstDefaultsButton">
+                    <property name="fixedWidth">
+                      <number>70</number>
+                    </property>
+                    <property name="fixedHeight">
+                      <number>100</number>
+                    </property>
+                    <layout class="QHBoxLayout" name="getInstDefaultsButtonLayout">
+                      <item>
+                        <widget class="QLabel" name="getInstDefaultsButtonLabel">
+                          <property name="wordWrap">
+                            <bool>true</bool>
+                          </property>
+                          <property name="alignment">
+                            <set>Qt::AlignCenter</set>
+                          </property>
+                          <property name="text">
+                            <string>Get Defaults</string>
+                          </property>
+                        </widget>
+                      </item>
+                    </layout>
+                  </widget>
+                </item>
+              </layout>
+            </item>
+          </layout>
+        </widget>
+      </item>
+    </layout>
+  </widget>
+  <tabstops/>
+  <customwidgets/>
+  <resources/>
+  <connections/>
+</ui>
\ No newline at end of file
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/SANSRunWindow.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/SANSRunWindow.h
index 6b984b4852a973cf2c3261447c7c6521327c4159..2d6fa9ab13fde2862a0e6bf2dfeb08f9ab2669bb 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/SANSRunWindow.h
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/SANSRunWindow.h
@@ -159,7 +159,7 @@ private:
   void appendRowToMaskTable(const QString &type, const QString &detector,
                             const QString &details);
   void readNumberOfEntries(const QString &RunStep,
-                           MantidWidgets::MWRunFiles *const output);
+                           API::MWRunFiles *const output);
   QString readUserFileGUIChanges(const States type);
   QString readSampleObjectGUIChanges();
   /// Get the component distances
@@ -197,11 +197,9 @@ private:
   bool runAssign(int key, QString &logs);
   /// Load a scatter sample file or can run via Python objects using the passed
   /// Python command
-  bool assignDetBankRun(MantidWidgets::MWRunFiles &runFile,
-                        const QString &assignFn);
+  bool assignDetBankRun(API::MWRunFiles &runFile, const QString &assignFn);
   /// runs that contain only monitor counts can be direct or transmission runs
-  bool assignMonitorRun(MantidWidgets::MWRunFiles &trans,
-                        MantidWidgets::MWRunFiles &direct,
+  bool assignMonitorRun(API::MWRunFiles &trans, API::MWRunFiles &direct,
                         const QString &assignFn);
   /// Get the detectors' names
   void fillDetectNames(QComboBox *output);
@@ -361,7 +359,7 @@ private:
   /// The workspace containing the can run
   QString m_experCan;
   /// List of all run entry widgets, which are on tab page 1
-  std::vector<MantidWidgets::MWRunFiles *> m_runFiles;
+  std::vector<API::MWRunFiles *> m_runFiles;
   /// There validators are searched before a reduction begins. Where there is a
   /// problem focus goes to the widget linked to a validator whose tab is also
   /// stored in the pair. Disabling a validator QLabel disables checking that
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/SANSRunWindow.ui b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/SANSRunWindow.ui
index 89314a94f50c6e9dff02db70e60cbe6c813aa6e1..021935b5ee2bb7c9e13e629105f6f86d3f86a0fd 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/SANSRunWindow.ui
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/SANSRunWindow.ui
@@ -6,7 +6,7 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>950</width>
+    <width>1022</width>
     <height>632</height>
    </rect>
   </property>
@@ -382,7 +382,7 @@
                 </property>
                 <layout class="QGridLayout" name="gridLayout_10">
                  <item row="0" column="0">
-                  <widget class="MantidQt::MantidWidgets::MWRunFiles" name="scatterSample" native="true">
+                  <widget class="MantidQt::API::MWRunFiles" name="scatterSample" native="true">
                    <property name="toolTip">
                     <string>The run with the sample under investigation</string>
                    </property>
@@ -398,7 +398,7 @@
                   </widget>
                  </item>
                  <item row="1" column="0">
-                  <widget class="MantidQt::MantidWidgets::MWRunFiles" name="scatCan" native="true">
+                  <widget class="MantidQt::API::MWRunFiles" name="scatCan" native="true">
                    <property name="toolTip">
                     <string>The run with the sample under investigation</string>
                    </property>
@@ -439,7 +439,7 @@
                 </property>
                 <layout class="QGridLayout" name="gridLayout_11">
                  <item row="0" column="0">
-                  <widget class="MantidQt::MantidWidgets::MWRunFiles" name="transmis" native="true">
+                  <widget class="MantidQt::API::MWRunFiles" name="transmis" native="true">
                    <property name="toolTip">
                     <string>The run with the sample under investigation</string>
                    </property>
@@ -458,7 +458,7 @@
                   </widget>
                  </item>
                  <item row="1" column="0">
-                  <widget class="MantidQt::MantidWidgets::MWRunFiles" name="transCan" native="true">
+                  <widget class="MantidQt::API::MWRunFiles" name="transCan" native="true">
                    <property name="toolTip">
                     <string>The run with the sample under investigation</string>
                    </property>
@@ -499,7 +499,7 @@
                 </property>
                 <layout class="QGridLayout" name="gridLayout_12">
                  <item row="0" column="0">
-                  <widget class="MantidQt::MantidWidgets::MWRunFiles" name="direct" native="true">
+                  <widget class="MantidQt::API::MWRunFiles" name="direct" native="true">
                    <property name="toolTip">
                     <string>The run with the sample under investigation</string>
                    </property>
@@ -518,7 +518,7 @@
                   </widget>
                  </item>
                  <item row="1" column="0">
-                  <widget class="MantidQt::MantidWidgets::MWRunFiles" name="dirCan" native="true">
+                  <widget class="MantidQt::API::MWRunFiles" name="dirCan" native="true">
                    <property name="toolTip">
                     <string>The run with the sample under investigation</string>
                    </property>
@@ -752,7 +752,20 @@
              <string>Save</string>
             </property>
             <layout class="QGridLayout" name="gridLayout">
-             <item row="0" column="6" rowspan="2">
+             <item row="3" column="2">
+              <spacer name="horizontalSpacer_25">
+               <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 row="0" column="9" rowspan="2">
               <widget class="QPushButton" name="saveFilename_btn">
                <property name="minimumSize">
                 <size>
@@ -768,7 +781,7 @@
                </property>
               </widget>
              </item>
-             <item row="3" column="5">
+             <item row="3" column="3">
               <widget class="QCheckBox" name="saveRKH_check">
                <property name="toolTip">
                 <string>Select one or more file formats</string>
@@ -778,36 +791,13 @@
                </property>
               </widget>
              </item>
-             <item row="3" column="4">
-              <widget class="QCheckBox" name="saveCan_check">
-               <property name="toolTip">
-                <string>Select one or more file formats</string>
-               </property>
-               <property name="text">
-                <string>CanSAS</string>
-               </property>
-              </widget>
-             </item>
-             <item row="3" column="1">
-              <widget class="QCheckBox" name="saveNex_check">
-               <property name="toolTip">
-                <string>Select one or more file formats.
- The Nexus format can be used to save 1D and 2D data. 
-Consider using NxCanSAS format since this can be 
- imported into SasView.</string>
-               </property>
-               <property name="text">
-                <string>Nexus</string>
-               </property>
-              </widget>
-             </item>
-             <item row="0" column="0" rowspan="2">
-              <widget class="QLabel" name="label_58">
+             <item row="4" column="8" colspan="2">
+              <widget class="QPushButton" name="saveSel_btn">
                <property name="toolTip">
-                <string>Save the output workspace to this file</string>
+                <string>Save multiple workspaces</string>
                </property>
                <property name="text">
-                <string>Filename:</string>
+                <string>Save Other</string>
                </property>
               </widget>
              </item>
@@ -821,37 +811,30 @@ Consider using NxCanSAS format since this can be
                </property>
               </widget>
              </item>
-             <item row="4" column="1" colspan="3">
-              <widget class="QPushButton" name="saveDefault_btn">
-               <property name="toolTip">
-                <string>Save the workspace from a single run file reduction</string>
-               </property>
-               <property name="text">
-                <string>Save Result</string>
-               </property>
-              </widget>
-             </item>
-             <item row="1" column="1" colspan="5">
+             <item row="1" column="1" colspan="8">
               <widget class="QLineEdit" name="outfile_edit">
                <property name="toolTip">
                 <string>Save the output workspace to this file</string>
                </property>
               </widget>
              </item>
-             <item row="4" column="5" colspan="2">
-              <widget class="QPushButton" name="saveSel_btn">
+             <item row="4" column="1" colspan="6">
+              <widget class="QPushButton" name="saveDefault_btn">
                <property name="toolTip">
-                <string>Save multiple workspaces</string>
+                <string>Save the workspace from a single run file reduction</string>
                </property>
                <property name="text">
-                <string>Save Other</string>
+                <string>Save Result</string>
                </property>
               </widget>
              </item>
-             <item row="3" column="3">
-              <widget class="QCheckBox" name="saveNIST_Qxy_check">
+             <item row="3" column="7">
+              <widget class="QCheckBox" name="saveCan_check">
+               <property name="toolTip">
+                <string>Select one or more file formats</string>
+               </property>
                <property name="text">
-                <string>NIST Qxy</string>
+                <string>CanSAS</string>
                </property>
               </widget>
              </item>
@@ -869,27 +852,73 @@ Zero Error</string>
                </property>
               </widget>
              </item>
-             <item row="3" column="6">
-              <widget class="QCheckBox" name="saveCSV_check">
+             <item row="3" column="5">
+              <widget class="QCheckBox" name="saveNXcanSAS_check">
                <property name="toolTip">
-                <string>Select one or more file formats</string>
+                <string>Select one or more file formats. 
+The NXcanSAS format can be used to save 1D and 2D data. </string>
                </property>
                <property name="text">
-                <string>CSV</string>
+                <string>NXcanSAS</string>
                </property>
               </widget>
              </item>
-             <item row="3" column="2">
-              <widget class="QCheckBox" name="saveNXcanSAS_check">
+             <item row="0" column="0" rowspan="2">
+              <widget class="QLabel" name="label_58">
                <property name="toolTip">
-                <string>Select one or more file formats. 
-The NXcanSAS format can be used to save 1D and 2D data. </string>
+                <string>Save the output workspace to this file</string>
                </property>
                <property name="text">
-                <string>NxCanSAS</string>
+                <string>Filename:</string>
+               </property>
+              </widget>
+             </item>
+             <item row="3" column="1">
+              <widget class="QCheckBox" name="saveNIST_Qxy_check">
+               <property name="text">
+                <string>NIST Qxy</string>
                </property>
               </widget>
              </item>
+             <item row="3" column="4">
+              <spacer name="horizontalSpacer_26">
+               <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 row="3" column="6">
+              <spacer name="horizontalSpacer_27">
+               <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 row="3" column="8">
+              <spacer name="horizontalSpacer_28">
+               <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>
            </widget>
           </item>
@@ -1847,7 +1876,7 @@ intermediate ranges are there for comparison</string>
               </widget>
              </item>
              <item>
-              <widget class="MantidQt::MantidWidgets::MWRunFiles" name="floodRearFile" native="true">
+              <widget class="MantidQt::API::MWRunFiles" name="floodRearFile" native="true">
                <property name="findRunFiles" stdset="0">
                 <bool>false</bool>
                </property>
@@ -1877,7 +1906,7 @@ intermediate ranges are there for comparison</string>
               </widget>
              </item>
              <item>
-              <widget class="MantidQt::MantidWidgets::MWRunFiles" name="floodFrontFile" native="true">
+              <widget class="MantidQt::API::MWRunFiles" name="floodFrontFile" native="true">
                <property name="findRunFiles" stdset="0">
                 <bool>false</bool>
                </property>
@@ -2357,7 +2386,7 @@ intermediate ranges are there for comparison</string>
           <item>
            <widget class="QGroupBox" name="q_resolution_group_box">
             <property name="title">
-             <string>QResolution</string>
+             <string>&amp;QResolution</string>
             </property>
             <property name="checkable">
              <bool>true</bool>
@@ -3715,7 +3744,7 @@ p, li { white-space: pre-wrap; }
                     <item>
                      <widget class="QLabel" name="label_14">
                       <property name="text">
-                       <string>Tolerance 
+                       <string>Tolerance
 [um]</string>
                       </property>
                       <property name="alignment">
@@ -4409,7 +4438,7 @@ p, li { white-space: pre-wrap; }
            <number>6</number>
           </property>
           <item row="0" column="0">
-           <widget class="MantidQt::MantidWidgets::MWRunFiles" name="file_run_edit" native="true">
+           <widget class="MantidQt::API::MWRunFiles" name="file_run_edit" native="true">
             <property name="sizePolicy">
              <sizepolicy hsizetype="MinimumExpanding" vsizetype="Minimum">
               <horstretch>0</horstretch>
@@ -4667,9 +4696,9 @@ p, li { white-space: pre-wrap; }
  </widget>
  <customwidgets>
   <customwidget>
-   <class>MantidQt::MantidWidgets::MWRunFiles</class>
+   <class>MantidQt::API::MWRunFiles</class>
    <extends>QWidget</extends>
-   <header>MantidQtMantidWidgets/MWRunFiles.h</header>
+   <header>MantidQtAPI/MWRunFiles.h</header>
   </customwidget>
   <customwidget>
    <class>MantidQt::MantidWidgets::MessageDisplay</class>
@@ -4711,10 +4740,7 @@ p, li { white-space: pre-wrap; }
   <tabstop>oneDBtn</tabstop>
   <tabstop>twoDBtn</tabstop>
   <tabstop>saveFilename_btn</tabstop>
-  <tabstop>saveCSV_check</tabstop>
-  <tabstop>saveRKH_check</tabstop>
   <tabstop>saveCan_check</tabstop>
-  <tabstop>saveNex_check</tabstop>
   <tabstop>saveDefault_btn</tabstop>
   <tabstop>outfile_edit</tabstop>
   <tabstop>saveSel_btn</tabstop>
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/StepScan.ui b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/StepScan.ui
index 7f5bb741455901791e2b8e10cc0de10ee6715316..3eb2dd0adeca30ae425867e53cbe120a2f666ea8 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/StepScan.ui
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/StepScan.ui
@@ -18,7 +18,7 @@
    <item row="0" column="0">
     <layout class="QHBoxLayout" name="horizontalLayout">
      <item>
-      <widget class="MantidQt::MantidWidgets::MWRunFiles" name="mWRunFiles">
+      <widget class="MantidQt::API::MWRunFiles" name="mWRunFiles">
        <property name="label" stdset="0">
         <string>Data source</string>
        </property>
@@ -29,7 +29,7 @@
         <bool>true</bool>
        </property>
        <property name="buttonOpt" stdset="0">
-        <enum>MantidQt::MantidWidgets::MWRunFiles::Text</enum>
+        <enum>MantidQt::API::MWRunFiles::Text</enum>
        </property>
        <property name="fileExtensions">
         <stringlist>
@@ -37,7 +37,7 @@
         </stringlist>
        </property>
        <property name="liveButton" stdset="0">
-        <enum>MantidQt::MantidWidgets::MWRunFiles::AlwaysShow</enum>
+        <enum>MantidQt::API::MWRunFiles::Show</enum>
        </property>
       </widget>
      </item>
@@ -356,9 +356,9 @@ p, li { white-space: pre-wrap; }
  </widget>
  <customwidgets>
   <customwidget>
-   <class>MantidQt::MantidWidgets::MWRunFiles</class>
+   <class>MantidQt::API::MWRunFiles</class>
    <extends>QWidget</extends>
-   <header>MantidQtMantidWidgets/MWRunFiles.h</header>
+   <header>MantidQtAPI/MWRunFiles.h</header>
   </customwidget>
   <customwidget>
    <class>MantidQt::MantidWidgets::WorkspaceSelector</class>
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/ITomographyIfaceView.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/ITomographyIfaceView.h
index c1319fe981c0e024a06bdd0eab3d7df1e60e4bf3..d9e1bd342083e2bc1b6fcb5cb9e26b99548de539 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/ITomographyIfaceView.h
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/ITomographyIfaceView.h
@@ -6,10 +6,12 @@
 #include "MantidAPI/MatrixWorkspace_fwd.h"
 #include "MantidQtCustomInterfaces/Tomography/ImageStackPreParams.h"
 #include "MantidQtCustomInterfaces/Tomography/TomoPathsConfig.h"
-#include "MantidQtCustomInterfaces/Tomography/TomoReconToolsUserSettings.h"
 #include "MantidQtCustomInterfaces/Tomography/TomoReconFiltersSettings.h"
+#include "MantidQtCustomInterfaces/Tomography/TomoReconToolsUserSettings.h"
 #include "MantidQtCustomInterfaces/Tomography/TomoSystemSettings.h"
 
+#include "MantidQtCustomInterfaces/Tomography/TomoToolConfigDialogBase.h"
+
 namespace MantidQt {
 namespace CustomInterfaces {
 
@@ -141,15 +143,6 @@ public:
    */
   virtual TomoSystemSettings systemSettings() const = 0;
 
-  /**
-   * Get the current reconstruction tool settings set by the
-   * user. This is about tool specific options (like reconstruction
-   * method, etc.).
-   *
-   * @return Settings for the set of supported tools.
-   */
-  virtual TomoReconToolsUserSettings reconToolsSettings() const = 0;
-
   /**
    * The filters settings defined by the user. These options are
    * general pre-/post-processing options.
@@ -175,20 +168,6 @@ public:
    */
   virtual std::string currentReconTool() const = 0;
 
-  /**
-   * Method/algorithm selected from the TomoPy list.
-   *
-   * @return name of the method as used in TomoPy
-   */
-  virtual std::string astraMethod() const = 0;
-
-  /**
-   * Method/algorithm selected from the Astra list.
-   *
-   * @return name of the method as used in Astra Toolbox
-   */
-  virtual std::string tomopyMethod() const = 0;
-
   /**
    * Updates buttons and banners related to the current login
    * status. For example, when we are logged in, the 'log in' button
@@ -288,9 +267,9 @@ public:
   /**
    * Show a tool specific configuration dialog for the user to set it up
    *
-   * @param name human readable name of the tool, as a string
+   * @param dialog The pointer to the current dialog
    */
-  virtual void showToolConfig(const std::string &name) = 0;
+  virtual void showToolConfig(TomoToolConfigDialogBase &dialog) = 0;
 
   /**
    * Refresh the table, tree etc. that displays info on the running/finished
@@ -340,6 +319,16 @@ public:
    * @param alg algorithm initialized and ready to run.
    */
   virtual void runAggregateBands(Mantid::API::IAlgorithm_sptr alg) = 0;
+
+  /**
+   * Prompts the user for confirmation with a yes/no dialogue.
+   * The body can use HTML formatting.
+   *
+   * @param title The title that the message has
+   * @param body The body that the message has. This CAN use HTML formatting
+   */
+  virtual bool userConfirmation(const std::string &title,
+                                const std::string &body) = 0;
 };
 
 } // namespace CustomInterfaces
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/ImageROIPresenter.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/ImageROIPresenter.h
index f4853d99f45c73564d3289d56bdd7ff6a2f9b5bc..bb601de9f8b3b0e97c20aaaacb3eb99515327183 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/ImageROIPresenter.h
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/ImageROIPresenter.h
@@ -74,6 +74,9 @@ protected:
   void processBrowseImage();
   void processBrowseStack();
   void processNewStack(bool singleImage);
+  void processLoadSingleImage();
+  void processLoadStackOfImages();
+  void setupAlgorithmRunnerAfterLoad();
   void processChangeImageType();
   void processChangeRotation();
   void processPlayStartStop();
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomoSystemSettings.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomoSystemSettings.h
index e41f5d8d065be38b627517bed1e8a475a139cf74..ee1ce8ecf66e87ad7e7352defbc1196fa9ca2c8a 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomoSystemSettings.h
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomoSystemSettings.h
@@ -56,6 +56,9 @@ struct MANTIDQT_CUSTOMINTERFACES_DLL TomoSystemSettings {
   /// path component for the reconstructed files (outputs)
   std::string m_outputPathCompReconst;
 
+  /// experiment reference from the Run tab
+  std::string m_experimentReference;
+
   static const std::string g_defSamplesDirPrefix;
   static const std::string g_defFlatsDirPrefix;
   static const std::string g_defDarksDirPrefix;
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomoToolConfigDialog.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomoToolConfigDialog.h
deleted file mode 100644
index 5196ca49bef979e5268b8dc9cbd68a5e1c20aca8..0000000000000000000000000000000000000000
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomoToolConfigDialog.h
+++ /dev/null
@@ -1,97 +0,0 @@
-#ifndef MANTIDQTCUSTOMINTERFACES_TOMOTOOLCONFIGDIALOG_H_
-#define MANTIDQTCUSTOMINTERFACES_TOMOTOOLCONFIGDIALOG_H_
-
-#include "ui_TomoToolConfigAstra.h"
-#include "ui_TomoToolConfigCustom.h"
-#include "ui_TomoToolConfigSavu.h"
-#include "ui_TomoToolConfigTomoPy.h"
-
-#include <QDialog>
-
-namespace MantidQt {
-namespace CustomInterfaces {
-
-/**
-Third party tool configuration dialog(s) for the tomographic reconstruction
-GUI.
-
-Copyright &copy; 2014,2015 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>
-*/
-
-class TomoToolConfigTomoPy : public QDialog {
-  Q_OBJECT
-
-public:
-  TomoToolConfigTomoPy(QWidget *parent = 0);
-};
-
-class TomoToolConfigSavu : public QMainWindow {
-  Q_OBJECT
-public:
-  TomoToolConfigSavu(QWidget *parent = 0);
-
-private:
-  void initLayout();
-};
-
-class TomoToolConfigAstra : public QDialog {
-  Q_OBJECT
-public:
-  TomoToolConfigAstra(QWidget *parent = 0);
-
-private:
-  void initLayout();
-};
-
-class TomoToolConfigCustom : public QDialog {
-  Q_OBJECT
-public:
-  TomoToolConfigCustom(QWidget *parent = 0);
-
-private:
-  void initLayout();
-};
-
-class TomoToolConfigDialog : public QDialog {
-  Q_OBJECT
-
-public:
-  TomoToolConfigDialog(QWidget *parent = 0);
-
-private:
-  void initLayout();
-
-private slots:
-  void okClicked();
-  void cancelClicked();
-
-private:
-  QLabel *labelRun, *labelOpt;
-  QLineEdit *editRun, *editOpt;
-  QHBoxLayout *hRun, *hOpt, *hBut;
-  QGridLayout *layout;
-  QPushButton *okButton, *cancelButton;
-};
-}
-}
-
-#endif // MANTIDQTCUSTOMINTERFACES_TOMOTOOLCONFIGDIALOG_H_
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomoToolConfigDialogAstra.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomoToolConfigDialogAstra.h
new file mode 100644
index 0000000000000000000000000000000000000000..34fa4233bd4468bedfffe167aadcdbbfc623efcd
--- /dev/null
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomoToolConfigDialogAstra.h
@@ -0,0 +1,38 @@
+#ifndef MANTIDQTCUSTOMINTERFACES_TOMOTOOLCONFIGDIALOGASTRA_H_
+#define MANTIDQTCUSTOMINTERFACES_TOMOTOOLCONFIGDIALOGASTRA_H_
+
+#include "ui_TomoToolConfigAstra.h"
+#include "MantidQtCustomInterfaces/Tomography/TomoToolConfigDialogBase.h"
+
+namespace MantidQt {
+namespace CustomInterfaces {
+class TomoToolConfigDialogAstra : public TomoToolConfigDialogBase {
+public:
+  TomoToolConfigDialogAstra()
+      : TomoToolConfigDialogBase(DEFAULT_TOOL_NAME, DEFAULT_TOOL_METHOD) {}
+
+  ~TomoToolConfigDialogAstra() override {
+    if (m_dialog) {
+      delete m_dialog;
+    }
+  }
+
+private:
+  void initialiseDialog() override;
+  void setupMethodSelected() override;
+  void setupToolSettingsFromPaths() override;
+  void setupDialogUi() override;
+  int executeQt() override;
+  std::vector<std::pair<std::string, std::string>> getToolMethods() override;
+
+  // initialised in .cpp file
+  static const std::string DEFAULT_TOOL_NAME;
+  static const std::string DEFAULT_TOOL_METHOD;
+
+  QDialog *m_dialog = nullptr;
+  Ui::TomoToolConfigAstra m_astraUi;
+};
+
+} // CustomInterfaces
+} // MantidQt
+#endif // MANTIDQTCUSTOMINTERFACES_TOMOTOOLCONFIGDIALOGASTRA_H_
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomoToolConfigDialogBase.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomoToolConfigDialogBase.h
new file mode 100644
index 0000000000000000000000000000000000000000..4933973efc79da09842b464bd710e842537c9a61
--- /dev/null
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomoToolConfigDialogBase.h
@@ -0,0 +1,153 @@
+#ifndef MANTIDQTCUSTOMINTERFACES_TOMOTOOLCONFIGDIALOGBASE_H_
+#define MANTIDQTCUSTOMINTERFACES_TOMOTOOLCONFIGDIALOGBASE_H_
+
+#include "MantidQtCustomInterfaces/Tomography/TomoPathsConfig.h"
+#include "MantidQtCustomInterfaces/Tomography/TomoReconToolsUserSettings.h"
+
+#include <memory>
+
+namespace MantidQt {
+namespace CustomInterfaces {
+
+/**
+Third party tool configuration dialog(s) for the tomographic reconstruction
+GUI.
+
+Copyright &copy; 2014,2015 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>
+*/
+class TomoToolConfigDialogBase {
+public:
+  TomoToolConfigDialogBase(const std::string toolName = "",
+                           const std::string toolMethod = "")
+      : m_toolName(toolName), m_toolMethod(toolMethod), m_isInitialised(false) {
+  }
+  virtual ~TomoToolConfigDialogBase() {}
+
+  /// public static function accessor to create dialogues
+  static std::unique_ptr<TomoToolConfigDialogBase>
+  getToolDialogFor(const std::string &toolName);
+
+  /// Sets up the dialogue settings, but does not initialise a QDialog
+  void setupDialog(const std::string &runPath, const TomoPathsConfig &paths,
+                   const std::string &pathOut,
+                   const std::string &localOutNameAppendix) {
+
+    setupPaths(runPath, paths, pathOut, localOutNameAppendix);
+    setupToolSettingsFromPaths();
+  }
+
+  /// initialises a QDialog and handles the returns
+  virtual int initialiseGUIandExecute() {
+    if (!isInitialised()) {
+      // set up the tool's method on the first run
+      // this prevents from creating and destroying many dialogues if the user
+      // decides to scroll quickly, and the dialogue is only initialised if the
+      // user clicks the "Setup" button. If the tool is not setup the default
+      // settings will be provided if the user clicks Reconstruct
+      initialiseDialog();
+      setupDialogUi();
+      setupMethodSelected();
+
+      m_isInitialised = true;
+    }
+
+    const int res = this->executeQt();
+    this->handleDialogResult(res);
+    return res;
+  }
+
+  virtual bool isInitialised() const { return m_isInitialised; }
+
+  std::string getSelectedToolMethod() const { return m_toolMethod; }
+
+  /// return pointer and transfer ownership
+  std::shared_ptr<TomoRecToolConfig> getSelectedToolSettings() const {
+    return m_toolSettings;
+  }
+
+  std::string getSelectedToolName() const { return m_toolName; }
+
+protected:
+  virtual void initialiseDialog() = 0;
+
+  virtual void handleDialogResult(const int result);
+
+  virtual void setScriptRunPath(const std::string run) { m_runPath = run; }
+
+  virtual void setTomoPathsConfig(const TomoPathsConfig paths) {
+    m_paths = paths;
+  }
+
+  virtual void setPathOut(const std::string pathOut) { m_pathOut = pathOut; }
+
+  virtual void setLocalOutNameAppendix(const std::string localOutNameAppendix) {
+    m_localOutNameAppendix = localOutNameAppendix;
+  }
+
+  virtual void setupPaths(const std::string &runPath,
+                          const TomoPathsConfig &paths,
+                          const std::string &pathOut,
+                          const std::string &localOutNameAppendix) {
+    this->setScriptRunPath(runPath);
+    this->setTomoPathsConfig(paths);
+    this->setPathOut(pathOut);
+    this->setLocalOutNameAppendix(localOutNameAppendix);
+  }
+
+  virtual void setupDialogUi() = 0;
+
+  /// setup the selected method member variable
+  virtual void setupMethodSelected() = 0;
+
+  /// setup the tool config with the correct paths, must be called after the
+  /// paths have been set!
+  virtual void setupToolSettingsFromPaths() = 0;
+
+  /// provided virtual function to add Qt execute behaviour as necessary
+  virtual int executeQt() = 0; // this class doesn't inherit from Qt and doesnt
+                               // have this->exec()
+
+  // empty function body as not all tools have methods
+  virtual std::vector<std::pair<std::string, std::string>> getToolMethods() {
+    return {};
+  }
+
+  std::shared_ptr<TomoRecToolConfig> m_toolSettings;
+
+  const std::string m_toolName;
+
+  std::string m_toolMethod;
+
+  std::string m_runPath;
+
+  std::string m_localOutNameAppendix;
+
+  std::string m_pathOut;
+
+  TomoPathsConfig m_paths;
+
+  bool m_isInitialised;
+};
+}
+}
+
+#endif // MANTIDQTCUSTOMINTERFACES_TOMOTOOLCONFIGDIALOGBASE_H_
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomoToolConfigDialogCustom.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomoToolConfigDialogCustom.h
new file mode 100644
index 0000000000000000000000000000000000000000..98f493470a002e318d74510dfe88e05de05a4438
--- /dev/null
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomoToolConfigDialogCustom.h
@@ -0,0 +1,37 @@
+#ifndef MANTIDQTCUSTOMINTERFACES_TOMOTOOLCONFIGDIALOGCUSTOM_H_
+#define MANTIDQTCUSTOMINTERFACES_TOMOTOOLCONFIGDIALOGCUSTOM_H_
+
+#include "ui_TomoToolConfigCustom.h"
+#include "MantidQtCustomInterfaces/Tomography/TomoToolConfigDialogBase.h"
+
+namespace MantidQt {
+namespace CustomInterfaces {
+class TomoToolConfigDialogCustom : public TomoToolConfigDialogBase {
+public:
+  TomoToolConfigDialogCustom()
+      : TomoToolConfigDialogBase(DEFAULT_TOOL_NAME, DEFAULT_TOOL_METHOD) {}
+  ~TomoToolConfigDialogCustom() override {
+    if (m_dialog) {
+      delete m_dialog;
+    }
+  }
+
+private:
+  void initialiseDialog() override;
+  void setupMethodSelected() override;
+  void setupToolSettingsFromPaths() override;
+  void setupDialogUi() override;
+  void handleDialogResult(int result) override;
+  int executeQt() override;
+
+  // initialised in .cpp file
+  static const std::string DEFAULT_TOOL_NAME;
+  static const std::string DEFAULT_TOOL_METHOD;
+  static std::string m_backupCommandLine;
+
+  QDialog *m_dialog = nullptr;
+  Ui::TomoToolConfigCustom m_customUi;
+};
+} // CustomInterfaces
+} // MantidQt
+#endif // MANTIDQTCUSTOMINTERFACES_TOMOTOOLCONFIGDIALOGCUSTOM_H_
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomoToolConfigDialogSavu.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomoToolConfigDialogSavu.h
new file mode 100644
index 0000000000000000000000000000000000000000..fc6f242f53829f2589ae13815231c864e949aa86
--- /dev/null
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomoToolConfigDialogSavu.h
@@ -0,0 +1,71 @@
+#ifndef MANTIDQTCUSTOMINTERFACES_TOMOTOOLCONFIGDIALOGSAVU_H_
+#define MANTIDQTCUSTOMINTERFACES_TOMOTOOLCONFIGDIALOGSAVU_H_
+
+#include "ui_TomoToolConfigSavu.h"
+#include "MantidQtCustomInterfaces/Tomography/TomoToolConfigDialogBase.h"
+#include <MantidAPI/ITableWorkspace.h>
+
+namespace Mantid {
+namespace API {
+class TableRow;
+}
+}
+
+namespace MantidQt {
+namespace CustomInterfaces {
+class TomoToolConfigDialogSavu : public QMainWindow,
+                                 public TomoToolConfigDialogBase {
+  Q_OBJECT
+public:
+  TomoToolConfigDialogSavu(QWidget *parent = 0);
+
+private:
+  void setupMethodSelected() override;
+  void setupToolSettingsFromPaths() override;
+  void setupDialogUi() override;
+  void initialiseDialog() override;
+  int executeQt() override;
+
+  void initSavuWindow();
+  void loadAvailablePlugins();
+  void refreshAvailablePluginListUI();
+  void refreshCurrentPluginListUI();
+  void availablePluginSelected();
+
+  void createPluginTreeEntry(Mantid::API::TableRow &row);
+  void createPluginTreeEntries(Mantid::API::ITableWorkspace_sptr table);
+  void paramValModified(QTreeWidgetItem *item, int /*column*/);
+  void currentPluginSelected();
+  std::string paramValStringFromArray(const Json::Value &jsonVal,
+                                      const std::string &name);
+
+  std::string pluginParamValString(const Json::Value &jsonVal,
+                                   const std::string &name);
+
+  void loadSavuTomoConfig(std::string &filePath,
+                          Mantid::API::ITableWorkspace_sptr &currentPlugins);
+  void moveUpClicked();
+  void moveDownClicked();
+  void removeClicked();
+  void menuOpenClicked();
+  void menuSaveClicked();
+  void menuSaveAsClicked();
+  QString tableWSRowToString(Mantid::API::ITableWorkspace_sptr table, size_t i);
+  void expandedItem(QTreeWidgetItem *item);
+  void transferClicked();
+  std::string createUniqueNameHidden();
+
+  void userWarning(const std::string &err, const std::string &description);
+  void userError(const std::string &err, const std::string &description);
+
+  static size_t g_nameSeqNo;
+
+  Ui::TomoToolConfigSavu m_savuUi;
+  Mantid::API::ITableWorkspace_sptr m_availPlugins;
+  Mantid::API::ITableWorkspace_sptr m_currPlugins;
+  std::string m_currentParamPath;
+};
+
+} // CustomInterfaces
+} // MantidQt
+#endif // MANTIDQTCUSTOMINTERFACES_TOMOTOOLCONFIGDIALOGSAVU_H_
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomoToolConfigDialogTomoPy.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomoToolConfigDialogTomoPy.h
new file mode 100644
index 0000000000000000000000000000000000000000..bdd5b63e3aa211faa15e7f212fb459f47bee1127
--- /dev/null
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomoToolConfigDialogTomoPy.h
@@ -0,0 +1,37 @@
+#ifndef MANTIDQTCUSTOMINTERFACES_TOMOTOOLCONFIGDIALOGTOMOPY_H_
+#define MANTIDQTCUSTOMINTERFACES_TOMOTOOLCONFIGDIALOGTOMOPY_H_
+
+#include "ui_TomoToolConfigTomoPy.h"
+#include "MantidQtCustomInterfaces/Tomography/TomoToolConfigDialogBase.h"
+
+namespace MantidQt {
+namespace CustomInterfaces {
+class TomoToolConfigDialogTomoPy : public TomoToolConfigDialogBase {
+
+public:
+  TomoToolConfigDialogTomoPy()
+      : TomoToolConfigDialogBase(DEFAULT_TOOL_NAME, DEFAULT_TOOL_METHOD) {}
+
+  ~TomoToolConfigDialogTomoPy() override {
+    if (m_dialog) {
+      delete m_dialog;
+    }
+  }
+
+private:
+  void initialiseDialog() override;
+  void setupMethodSelected() override;
+  void setupToolSettingsFromPaths() override;
+  void setupDialogUi() override;
+  int executeQt() override;
+  std::vector<std::pair<std::string, std::string>> getToolMethods() override;
+  // initialised in .cpp file
+  static const std::string DEFAULT_TOOL_NAME;
+  static const std::string DEFAULT_TOOL_METHOD;
+
+  QDialog *m_dialog = nullptr;
+  Ui::TomoToolConfigTomoPy m_tomoPyUi;
+};
+} // CustomInterfaces
+} // MantidQt
+#endif // MANTIDQTCUSTOMINTERFACES_TOMOTOOLCONFIGDIALOGTOMOPY_H_
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomographyIfaceModel.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomographyIfaceModel.h
index 00ec970ea3b2ec0171fabc130ced425fa91034f3..3c64d78ed5772872e0ab569882ad6196b3ad014d 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomographyIfaceModel.h
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomographyIfaceModel.h
@@ -7,16 +7,19 @@
 #include "MantidKernel/System.h"
 #include "MantidQtCustomInterfaces/Tomography/ImageStackPreParams.h"
 #include "MantidQtCustomInterfaces/Tomography/TomoPathsConfig.h"
+#include "MantidQtCustomInterfaces/Tomography/TomoRecToolConfig.h"
 #include "MantidQtCustomInterfaces/Tomography/TomoReconFiltersSettings.h"
 #include "MantidQtCustomInterfaces/Tomography/TomoReconToolsUserSettings.h"
 #include "MantidQtCustomInterfaces/Tomography/TomoSystemSettings.h"
 
-// Qt classes forward declarations
-class QMutex;
+// Include instead of forward declare so we have definition of qint64
+#include <QMutex>
 
 namespace MantidQt {
 namespace CustomInterfaces {
 
+class TomographyProcess;
+class TomographyThread;
 /**
 Tomography GUI. Model for the interface (as in the MVP
 (Model-View-Presenter) pattern). In principle, in a strict MVP setup,
@@ -83,9 +86,52 @@ public:
 
   /// Username last logged in, if any.
   std::string loggedIn() const { return m_loggedInUser; }
+
   // TODO: add companion currentComputeResource where LoggedIn() is in
-  void usingTool(const std::string &tool) { m_currentTool = tool; }
-  std::string usingTool() const { return m_currentTool; }
+  //--------------------------------------------
+  // Current tool Settings
+  //--------------------------------------------
+  void usingTool(const std::string &tool) { m_currentToolName = tool; }
+  std::string usingTool() const { return m_currentToolName; }
+
+  void setCurrentToolMethod(std::string toolMethod) {
+    m_currentToolMethod = toolMethod;
+  }
+  std::string getCurrentToolMethod() const { return m_currentToolMethod; }
+
+  void setCurrentToolSettings(std::shared_ptr<TomoRecToolConfig> settings) {
+    m_currentToolSettings = settings;
+  }
+
+  //--------------------------------------------
+  // Access to the system settings information
+  //--------------------------------------------
+  // get the remote scripts base dir from the system settings
+  std::string getCurrentRemoteScriptsBasePath() const {
+    return m_systemSettings.m_remote.m_basePathReconScripts;
+  }
+
+  /// get the local paths from the system settings
+  std::string getCurrentLocalScriptsBasePath() const {
+    return m_systemSettings.m_local.m_reconScriptsPath;
+  }
+
+  std::string getExeternalInterpreterPath() const {
+    return m_systemSettings.m_local.m_externalInterpreterPath;
+  }
+
+  /// get the experiment reference currently selected
+  std::string getCurrentExperimentReference() const {
+    return m_systemSettings.m_experimentReference;
+  }
+
+  /// returns the scripts folder, used for remote path
+  std::string getTomoScriptFolderPath() const { return g_tomoScriptFolderPath; }
+
+  /// returns the tomo script location path inside the scripts folder
+  std::string getTomoScriptLocationPath() const {
+    return g_mainReconstructionScript;
+  }
 
   /// ping the (remote) compute resource
   bool doPing(const std::string &compRes);
@@ -101,42 +147,43 @@ public:
                         std::vector<std::string> &status,
                         std::vector<std::string> &cmds);
   /// Submit a new job to the (remote or local) compute resource
-  void doSubmitReconstructionJob(const std::string &compRes);
+  void prepareSubmissionArguments(const bool local, std::string &runnable,
+                                  std::vector<std::string> &args,
+                                  std::string &allOpts);
+
+  void doLocalRunReconstructionJob(
+      const std::string &runnable, const std::vector<std::string> &args,
+      const std::string &allOpts,
+      MantidQt::CustomInterfaces::TomographyThread &thread,
+      MantidQt::CustomInterfaces::TomographyProcess &worker);
+
+  void doRemoteRunReconstructionJob(const std::string &compRes,
+                                    const std::string &runnable,
+                                    const std::string &allOpts);
+
   /// Cancel a previously submitted job
   void doCancelJobs(const std::string &compRes,
                     const std::vector<std::string> &id);
+
+  void addJobToStatus(const qint64 pid, const std::string &runnable,
+                      const std::string &allOpts);
   /// Get fresh status information on running/recent jobs
   void doRefreshJobsInfo(const std::string &compRes);
 
   void refreshLocalJobsInfo();
 
-  void doRunReconstructionJobLocal();
-
-  void updateExperimentReference(const std::string ref) {
-    m_experimentRef = ref;
-  }
+  void setExperimentReference(const std::string ref) { m_experimentRef = ref; }
 
   /// Update to the current setings given by the user
-  void updateSystemSettings(const TomoSystemSettings &settings) {
+  void setSystemSettings(const TomoSystemSettings &settings) {
     m_systemSettings = settings;
   }
 
-  /// Update to the current setings given by the user
-  void updateReconToolsSettings(const TomoReconToolsUserSettings &ts) {
-    m_toolsSettings = ts;
-  }
-
-  void updateTomopyMethod(const std::string &method) {
-    m_tomopyMethod = method;
-  }
-
-  void updateAstraMethod(const std::string &method) { m_astraMethod = method; }
-
-  void updatePrePostProcSettings(const TomoReconFiltersSettings &filters) {
+  void setPrePostProcSettings(const TomoReconFiltersSettings &filters) {
     m_prePostProcSettings = filters;
   }
 
-  void updateImageStackPreParams(const ImageStackPreParams &roiEtc) {
+  void setImageStackPreParams(const ImageStackPreParams &roiEtc) {
     m_imageStackPreParams = roiEtc;
   }
 
@@ -145,49 +192,70 @@ public:
 
   /// Log this message through the system logging
   void logMsg(const std::string &msg);
+  void logErrMsg(const std::string &msg);
 
   /// for clean destruction
   void cleanup();
 
-  std::string localComputeResource() const { return m_localCompName; }
+  std::string localComputeResource() const { return g_LocalResourceName; }
 
-  void updateTomoPathsConfig(const TomoPathsConfig &tc) { m_pathsConfig = tc; }
+  void setTomoPathsConfig(const TomoPathsConfig &tc) { m_pathsConfig = tc; }
+  void updateProcessInJobList(const qint64 pid, const int exitCode);
+  void terminateProcess();
 
-  // tools not yet available/supported - TODO
+  // Names of reconstruction tools
+  static const std::string g_TomoPyTool;
+  static const std::string g_AstraTool;
+  static const std::string g_customCmdTool;
+  // not supported yet
   static const std::string g_CCPiTool;
   static const std::string g_SavuTool;
 
-private:
+  // Name of the remote compute resource
+  static const std::string g_SCARFName;
+  static const std::string g_LocalResourceName;
+
+  // The main tomo_reconstruct.py or similar script (as it is distributed with
+  // Mantid). This is the entry point for reconstruction jobs.
+  static const std::string g_mainReconstructionScript;
+  static const std::string g_tomoScriptFolderPath;
+
+protected: // protected to expose everything to testing
+  std::string
+  constructSingleStringFromVector(const std::vector<std::string> args) const;
+
   /// retrieve info from compute resource into status table
   void getJobStatusInfo(const std::string &compRes);
 
   std::string validateCompResource(const std::string &res) const;
 
-  /// makes the command line string to run on the remote/local
-  void makeRunnableWithOptions(const std::string &comp, std::string &run,
-                               std::vector<std::string> &opt) const;
-
-  void checkWarningToolNotSetup(const std::string &tool,
-                                const std::string &cmd) const;
+  bool checkIfToolIsSetupProperly(const std::string &tool,
+                                  const std::string &cmd,
+                                  const std::vector<std::string> &args) const;
 
-  std::vector<std::string> makeTomoRecScriptOptions(bool local) const;
+  void makeTomoRecScriptOptions(const bool local,
+                                std::vector<std::string> &opts) const;
 
   void filtersCfgToCmdOpts(const TomoReconFiltersSettings &filters,
-                           const ImageStackPreParams &corRegions, bool local,
+                           const ImageStackPreParams &corRegions,
+                           const bool local,
                            std::vector<std::string> &opts) const;
 
-  void splitCmdLine(const std::string &cmd, std::string &run,
+  void splitCmdLine(const std::string &cmd, std::string &runnable,
                     std::string &opts) const;
 
+  /// process the tool name to be appropriate for the command line arg
+  std::string prepareToolNameForArgs(const std::string &toolName) const;
+
   void checkDataPathsSet() const;
 
   std::string adaptInputPathForExecution(const std::string &path,
-                                         bool local) const;
+                                         const bool local) const;
 
   std::string buildOutReconstructionDir(const std::string &samplesDir,
                                         bool) const;
 
-  bool processIsRunning(int pid);
+  bool processIsRunning(qint64 pid) const;
 
   std::string
   buildOutReconstructionDirFromSystemRoot(const std::string &samplesDir,
@@ -196,10 +264,9 @@ private:
   std::string
   buildOutReconstructionDirFromSamplesDir(const std::string &samplesDir) const;
 
+private:
   /// facility for the remote compute resource
   const std::string m_facility;
-  /// display name of the "local" compute resource
-  const std::string m_localCompName;
 
   /// Experiment reference (RBNumber for example)
   std::string m_experimentRef;
@@ -225,21 +292,24 @@ private:
   /// reconstruction tools available on SCARF
   std::vector<std::string> m_SCARFtools;
 
-  // Name of the remote compute resource
-  static const std::string g_SCARFName;
-
-  std::string m_currentTool;
-
+  // Paths for the sample, flat and dark images
   TomoPathsConfig m_pathsConfig;
 
   // System settting including several paths and parameters (local and remote)
   TomoSystemSettings m_systemSettings;
 
-  // Settings for the third party (tomographic reconstruction) tools
-  TomoReconToolsUserSettings m_toolsSettings;
+  //--------------------------------
+  // Current tool variables
+  //--------------------------------
+
+  // current tool's name, updated from the presenter on change
+  std::string m_currentToolName;
 
-  std::string m_tomopyMethod;
-  std::string m_astraMethod;
+  // the tool settings so we can use it for reconstruction params
+  std::shared_ptr<TomoRecToolConfig> m_currentToolSettings;
+
+  // current tool's method, updated from the presenter on change
+  std::string m_currentToolMethod;
 
   // Settings for the pre-/post-processing filters
   TomoReconFiltersSettings m_prePostProcSettings;
@@ -247,15 +317,6 @@ private:
   // Parameters set for the ROI, normalization region, etc.
   ImageStackPreParams m_imageStackPreParams;
 
-  // The main tomo_reconstruct.py or similar script (as it is distributed with
-  // Mantid). This is the entry point for reconstruction jobs.
-  static const std::string g_mainReconstructionScript;
-
-  // Names of reconstruction tools
-  static const std::string g_TomoPyTool;
-  static const std::string g_AstraTool;
-  static const std::string g_customCmdTool;
-
   // mutex for the job status info update operations
   // TODO: replace with std::mutex+std::lock_guard
   QMutex *m_statusMutex;
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomographyIfacePresenter.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomographyIfacePresenter.h
index dc05e618418840879027d8b208fba1c76f17825f..6665302ba8fe5613bebaa98f1df0c596bf838d8e 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomographyIfacePresenter.h
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomographyIfacePresenter.h
@@ -6,9 +6,9 @@
 #include "MantidQtCustomInterfaces/Tomography/ITomographyIfaceView.h"
 #include "MantidQtCustomInterfaces/Tomography/TomographyIfaceModel.h"
 
-#include <boost/scoped_ptr.hpp>
 #include <QMutex>
 #include <QObject>
+#include <boost/scoped_ptr.hpp>
 
 // Qt classes forward declarations
 class QThread;
@@ -18,6 +18,7 @@ namespace MantidQt {
 namespace CustomInterfaces {
 
 class TomoPathsConfig;
+class TomoToolConfigDialogBase;
 
 /**
 Tomography GUI. Presenter for the GUI (as in the MVP
@@ -49,7 +50,6 @@ Code Documentation is available at: <http://doxygen.mantidproject.org>
 class MANTIDQT_CUSTOMINTERFACES_DLL TomographyIfacePresenter
     : public QObject,
       public ITomographyIfacePresenter {
-  // Q_OBJECT for the 'keep alive' signals
   Q_OBJECT
 
 public:
@@ -65,6 +65,7 @@ protected:
   /// clean shut down of model, view, etc.
   void cleanup();
 
+  // notification methods
   void processSystemSettingsUpdated();
   void processSetupResourcesAndTools();
   void processCompResourceChanged();
@@ -75,15 +76,6 @@ protected:
   void processLogout();
   void processSetupReconTool();
   void processRunRecon();
-
-  void subprocessRunReconRemote();
-  void subprocessRunReconLocal();
-
-protected slots:
-  /// It may be run on user request, or periodically from a timer/thread
-  void processRefreshJobs();
-
-protected:
   void processCancelJobs();
   void processVisualizeJobs();
   void processViewImg();
@@ -93,10 +85,6 @@ protected:
 
   void doVisualize(const std::vector<std::string> &ids);
 
-  /// To prepare a local run
-  void makeRunnableWithOptionsLocal(const std::string &comp, std::string &run,
-                                    std::string &opt);
-
   /// auto-guess additional directories when the user gives the samples path
   void findFlatsDarksFromSampleGivenByUser(TomoPathsConfig &cfg);
 
@@ -105,10 +93,57 @@ protected:
 
   /// Starts a periodic query just to keep sessions alive when logged in
   void startKeepAliveMechanism(int period);
+
   /// Stops/kills the periodic query (for example if the user logs out)
   void killKeepAliveMechanism();
 
+  bool isLocalResourceSelected() const;
+signals:
+  void terminated();
+
+protected slots:
+  /// It may be run on user request, or periodically from a timer/thread
+  void processRefreshJobs();
+  void readWorkerStdOut(const QString &s);
+  void readWorkerStdErr(const QString &s);
+  void addProcessToJobList();
+  void reconProcessFailedToStart();
+  void workerFinished(const qint64 pid, const int exitCode);
+
 private:
+  /// Asks the user for permission to cancel the running reconstruction
+  bool userConfirmationToCancelRecon();
+  void setupAndRunLocalReconstruction(const std::string &runnable,
+                                      const std::vector<std::string> &args,
+                                      const std::string &allOpts);
+  /// creates the correct dialog pointer and sets it to the member variable
+  void createConfigDialogUsingToolName(const std::string &toolName);
+
+  /// sets up the dialog and uses the settings to update the model
+  void
+  setupConfigDialogSettingsAndUpdateModel(TomoToolConfigDialogBase *dialog);
+
+  /// configures up the dialog using the view
+  void setupConfigDialogSettings(TomoToolConfigDialogBase &dialog);
+
+  /// does the actual path configuration for local resource
+  void setupConfigDialogSettingsForLocal(TomoToolConfigDialogBase &dialog);
+
+  /// does the actual path configuration for remote resource
+  void setupConfigDialogSettingsForRemote(TomoToolConfigDialogBase &dialog);
+
+  /// update all the model information after the tool's been changed
+  void updateModelAfterToolChanged(const TomoToolConfigDialogBase &dialog);
+
+  /// update the model's current tool name using the dialog
+  void updateModelCurrentToolName(const TomoToolConfigDialogBase &dialog);
+
+  /// update the model's current tool method using the dialog
+  void updateModelCurrentToolMethod(const TomoToolConfigDialogBase &dialog);
+
+  /// update the model's current tool settings using the dialog
+  void updateModelCurrentToolSettings(const TomoToolConfigDialogBase &dialog);
+
   /// Associated view for this presenter (MVP pattern)
   ITomographyIfaceView *const m_view;
 
@@ -121,7 +156,15 @@ private:
 
   // for periodic update of the job status table/tree
   QTimer *m_keepAliveTimer;
-  QThread *m_keepAliveThread;
+
+  std::unique_ptr<TomographyThread> m_workerThread;
+
+  std::unique_ptr<TomoToolConfigDialogBase> m_configDialog;
+
+  static const std::string g_defOutPathLocal;
+  static const std::string g_defOutPathRemote;
+
+  bool m_reconRunning = false;
 };
 
 } // namespace CustomInterfaces
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomographyIfaceQtTabRun.ui b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomographyIfaceQtTabRun.ui
index b01dccc1e18272912bf6eb9db659638520878a07..2f41dd946e6d0b32a0cbfeae38d88ac7864cd26b 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomographyIfaceQtTabRun.ui
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomographyIfaceQtTabRun.ui
@@ -86,7 +86,16 @@
            <enum>QFrame::Raised</enum>
           </property>
           <layout class="QGridLayout" name="gridLayout_13">
-           <property name="margin">
+           <property name="leftMargin">
+            <number>3</number>
+           </property>
+           <property name="topMargin">
+            <number>3</number>
+           </property>
+           <property name="rightMargin">
+            <number>3</number>
+           </property>
+           <property name="bottomMargin">
             <number>3</number>
            </property>
            <property name="spacing">
@@ -105,7 +114,7 @@
                <rect>
                 <x>0</x>
                 <y>0</y>
-                <width>273</width>
+                <width>268</width>
                 <height>256</height>
                </rect>
               </property>
@@ -116,7 +125,16 @@
                </sizepolicy>
               </property>
               <layout class="QGridLayout" name="gridLayout_5">
-               <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>
                <property name="spacing">
@@ -412,9 +430,15 @@
             <verstretch>1</verstretch>
            </sizepolicy>
           </property>
+          <property name="editTriggers">
+           <set>QAbstractItemView::NoEditTriggers</set>
+          </property>
           <property name="selectionBehavior">
            <enum>QAbstractItemView::SelectRows</enum>
           </property>
+          <property name="sortingEnabled">
+           <bool>false</bool>
+          </property>
           <attribute name="horizontalHeaderStretchLastSection">
            <bool>true</bool>
           </attribute>
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomographyIfaceViewQtGUI.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomographyIfaceViewQtGUI.h
index aab47dfbb71b0d65996c2d096e04e3af182447bc..03b0df36b5e9ee1c4e941ed26e93d01118a74492 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomographyIfaceViewQtGUI.h
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomographyIfaceViewQtGUI.h
@@ -12,7 +12,6 @@
 #include "MantidQtCustomInterfaces/Tomography/ITomographyIfaceView.h"
 #include "MantidQtCustomInterfaces/Tomography/ImageROIViewQtWidget.h"
 #include "MantidQtCustomInterfaces/Tomography/ImggFormatsConvertViewQtWidget.h"
-#include "MantidQtCustomInterfaces/Tomography/TomoToolConfigDialog.h"
 #include "MantidQtCustomInterfaces/Tomography/TomoSystemSettings.h"
 
 #include "ui_ImageSelectCoRAndRegions.h"
@@ -21,24 +20,22 @@
 #include "ui_TomographyIfaceQtTabFiltersSettings.h"
 #include "ui_TomographyIfaceQtTabRun.h"
 #include "ui_TomographyIfaceQtTabSetup.h"
-#include "ui_TomographyIfaceQtTabVisualize.h"
 #include "ui_TomographyIfaceQtTabSystemSettings.h"
-
+#include "ui_TomographyIfaceQtTabVisualize.h"
 #include <boost/scoped_ptr.hpp>
 #include <json/json.h>
 
 // widgets used in this interface
-class ImageROIViewQtWidget;
-
-// Qt classes forward declarations
 class QMutex;
 
 namespace MantidQt {
-
 namespace API {
 class BatchAlgorithmRunner;
 }
+}
+// Qt classes forward declarations
 
+namespace MantidQt {
 namespace CustomInterfaces {
 
 /**
@@ -108,10 +105,6 @@ public:
 
   std::string getPassword() const override;
 
-  std::string astraMethod() const override { return m_astraMethod; }
-
-  std::string tomopyMethod() const override { return m_tomopyMethod; }
-
   void updateLoginControls(bool loggedIn) override;
 
   void enableLoggedActions(bool enable) override;
@@ -135,11 +128,6 @@ public:
 
   TomoSystemSettings systemSettings() const override;
 
-  /// Get the current reconstruction tools settings set by the user
-  TomoReconToolsUserSettings reconToolsSettings() const override {
-    return m_toolsSettings;
-  }
-
   TomoReconFiltersSettings prePostProcSettings() const override;
 
   std::string currentComputeResource() const override {
@@ -169,6 +157,9 @@ public:
 
   void runAggregateBands(Mantid::API::IAlgorithm_sptr alg) override;
 
+  bool userConfirmation(const std::string &title,
+                        const std::string &body) override;
+
 private slots:
   /// for buttons, run tab, and similar
   void reconstructClicked();
@@ -235,19 +226,6 @@ private slots:
   // aggregation run finished
   void finishedAggBands(bool error);
 
-  // for the savu functionality - waiting for Savu
-  void menuSaveClicked();
-  void menuSaveAsClicked();
-  void availablePluginSelected();
-  void currentPluginSelected();
-  void transferClicked();
-  void moveUpClicked();
-  void moveDownClicked();
-  void removeClicked();
-  void menuOpenClicked();
-  void paramValModified(QTreeWidgetItem *, int);
-  void expandedItem(QTreeWidgetItem *);
-
 private:
   /// Setup the interface (tab UI)
   void initLayout() override;
@@ -260,8 +238,6 @@ private:
   void doSetupSectionSystemSettings();
   void doSetupGeneralWidgets();
 
-  void doSetupSavu();
-
   /// Load default interface settings for each tab, normally on startup
   void readSettings();
   /// for the energy bands tab/widget
@@ -271,11 +247,12 @@ private:
   /// for the energy bands tab/widget
   void saveSettingsEnergy() const;
 
-  void updateSystemSettings(const TomoSystemSettings &setts);
+  void updateSystemSettingsTabFields(const TomoSystemSettings &setts);
 
   void updatePathsConfig(const TomoPathsConfig &cfg) override;
 
-  void showToolConfig(const std::string &name) override;
+  void showToolConfig(
+      MantidQt::CustomInterfaces::TomoToolConfigDialogBase &dialog) override;
 
   void closeEvent(QCloseEvent *ev) override;
 
@@ -308,40 +285,6 @@ private:
 
   void sendLog(const std::string &msg);
 
-  // Begin of Savu related functionality. Waiting for the tool to become
-  // available. When that happens, this area of the code will grow and will
-  // need separation. They should find a better place to live.
-  ///@name Savu related methods
-  ///@{
-  /// to load plugins (savu classification / API)
-  void loadAvailablePlugins();
-
-  /// refresh the list/tree of savu plugins
-  void refreshAvailablePluginListUI();
-
-  void refreshCurrentPluginListUI();
-
-  /// make a tree entry from a row of a table of savu plugins
-  void createPluginTreeEntry(Mantid::API::TableRow &row);
-  void createPluginTreeEntries(Mantid::API::ITableWorkspace_sptr table);
-
-  std::string createUniqueNameHidden();
-
-  QString tableWSRowToString(Mantid::API::ITableWorkspace_sptr table, size_t i);
-
-  void loadSavuTomoConfig(std::string &filePath,
-                          Mantid::API::ITableWorkspace_sptr &currentPlugins);
-
-  std::string paramValStringFromArray(const Json::Value &jsonVal,
-                                      const std::string &name);
-  std::string pluginParamValString(const Json::Value &jsonVal,
-                                   const std::string &name);
-  ///@}
-
-  static size_t g_nameSeqNo;
-
-  // end of Savu related methods
-
   static const std::string g_styleSheetOffline;
   static const std::string g_styleSheetOnline;
 
@@ -361,12 +304,6 @@ private:
   ImageROIViewQtWidget *m_tabROIW;
   ImggFormatsConvertViewQtWidget *m_tabImggFormats;
 
-  /// Tool specific setup dialogs
-  Ui::TomoToolConfigAstra m_uiAstra;
-  Ui::TomoToolConfigCustom m_uiCustom;
-  Ui::TomoToolConfigSavu m_uiSavu;
-  Ui::TomoToolConfigTomoPy m_uiTomoPy;
-
   std::vector<std::string> m_processingJobsIDs;
 
   std::string m_currentComputeRes;
@@ -385,16 +322,8 @@ private:
   static const std::string g_defOutPathLocal;
   static const std::string g_defOutPathRemote;
 
-  static const std::string g_TomoPyTool;
-  static const std::string g_AstraTool;
-  static const std::string g_CCPiTool;
-  static const std::string g_SavuTool;
-  static const std::string g_customCmdTool;
-
   TomoPathsConfig m_pathsConfig;
 
-  static const std::string g_defRemotePathScripts;
-
   // several paths or path components related to where the files are found
   // (raw files, reconstructions, pre-post processed files, etc.)
   // These are the defaults
@@ -423,13 +352,6 @@ private:
   /// the local and remote machines
   TomoSystemSettings m_systemSettings;
 
-  /// Settings for the third party (tomographic reconstruction) tools
-  TomoReconToolsUserSettings m_toolsSettings;
-  static const std::vector<std::pair<std::string, std::string>>
-      g_tomopy_methods;
-  std::string m_astraMethod;
-  std::string m_tomopyMethod;
-
   // Basic representation of user settings, read/written on startup/close.
   // TODO: this could be done more sophisticated, with a class using
   // QDataStream and in/out stream operators for example. Keeping
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomographyProcess.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomographyProcess.h
new file mode 100644
index 0000000000000000000000000000000000000000..7ec67be58ab763754e43acd570e234159030ec59
--- /dev/null
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomographyProcess.h
@@ -0,0 +1,93 @@
+#ifndef MANTIDQTCUSTOMINTERFACES_TOMOGRAPHY_TOMOGRAPHYPROCESS_H_
+#define MANTIDQTCUSTOMINTERFACES_TOMOGRAPHY_TOMOGRAPHYPROCESS_H_
+
+#include <QProcess>
+#include <QString>
+#include <QStringList>
+#include <vector>
+
+namespace MantidQt {
+namespace CustomInterfaces {
+
+/*
+TomographyProcess class that run external processes and provides some helper
+functions. This class was designed to be used with TomographyThread to run
+external processes asyncronously to the main thread 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>
+*/
+class TomographyProcess : public QProcess {
+  Q_OBJECT
+public:
+  // we want a nullptr for parent so we can move it to a thread
+  TomographyProcess() : QProcess(nullptr) {}
+
+  // intentionally copy the vector
+  void setup(const std::string &runnable, const std::vector<std::string> &args,
+             const std::string &allOpts) {
+    m_allArgs = allOpts;
+    m_runnable = QString::fromStdString(runnable);
+    m_args = buildArguments(args);
+  }
+
+  std::string getRunnable() const { return m_runnable.toStdString(); }
+  std::string getArgs() const { return m_allArgs; }
+
+  qint64 getPID() const {
+    auto pid = this->pid();
+
+    // qt connect could sometimes try to read the terminated process' PID
+    if (!pid) {
+      return 0;
+    }
+
+#ifdef _WIN32
+    // windows gets a struct object with more info
+    auto actualpid = static_cast<qint64>(pid->dwProcessId);
+#else
+    // linux just gets the PID
+    auto actualpid = static_cast<qint64>(pid);
+#endif
+    return actualpid;
+  }
+
+public slots:
+  /** This method should be used to start the worker as it passes the setup
+   * runnable and args parameters into the base start method
+  */
+  void startWorker() { start(m_runnable, m_args); }
+
+private:
+  QStringList buildArguments(const std::vector<std::string> &args) const {
+    QStringList list;
+    list.reserve(static_cast<int>(args.size()));
+
+    for (const auto &arg : args) {
+      list << QString::fromStdString(arg);
+    }
+
+    return list;
+  }
+
+  QString m_runnable;
+  QStringList m_args;
+
+  std::string m_allArgs;
+};
+} // CustomInterfaces
+} // MantidQt
+#endif
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomographyThread.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomographyThread.h
new file mode 100644
index 0000000000000000000000000000000000000000..f8add9afeb49aee3c37e512703bfeb50237705d3
--- /dev/null
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/TomographyThread.h
@@ -0,0 +1,113 @@
+#ifndef MANTIDQTCUSTOMINTERFACES_TOMOGRAPHY_TOMOGRAPHYTHREAD_H_
+#define MANTIDQTCUSTOMINTERFACES_TOMOGRAPHY_TOMOGRAPHYTHREAD_H_
+
+// included for UNUSED_ARG
+#include "MantidKernel/System.h"
+#include "MantidQtCustomInterfaces/Tomography/TomographyProcess.h"
+#include <QString>
+#include <QThread>
+
+namespace MantidQt {
+namespace CustomInterfaces {
+/*
+TomographyThread class that can handle a single worker, and get all the standard
+output and standard error content from the process.
+
+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>
+*/
+class TomographyThread : public QThread {
+  Q_OBJECT
+public:
+  TomographyThread(QObject *parent, TomographyProcess *worker)
+      : QThread(parent), m_worker(worker) {
+    // interactions between the thread and the worker are defined here
+    connect(this, SIGNAL(started()), worker, SLOT(startWorker()));
+    connect(this, SIGNAL(started()), this, SLOT(startWorker()));
+
+    connect(worker, SIGNAL(readyReadStandardOutput()), this,
+            SLOT(readWorkerStdOut()));
+    connect(worker, SIGNAL(readyReadStandardError()), this,
+            SLOT(readWorkerStdErr()));
+
+    connect(worker, SIGNAL(finished(int)), this, SLOT(finished(int)));
+
+    connect(this, SIGNAL(finished()), this, SLOT(deleteLater()),
+            Qt::DirectConnection);
+
+    connect(this, SIGNAL(terminated()), worker, SLOT(terminate()));
+    m_worker->moveToThread(this);
+  }
+
+  ~TomographyThread() override {
+    // this will terminate the process if another reconstruction is started,
+    // thus not allowing to have multiple reconstructions running at the same
+    // time
+    emit terminated();
+
+    // this causes segfault in processRefreshJobs if the check isnt here
+    if (m_workerRunning || !m_worker) {
+      // emit that the worker has been forcefully closed, exit with error code 1
+      // this is bad, find a way to notify without an explicit emit on thread
+      // destroy
+      emit workerFinished(m_workerPID, 1);
+    }
+  }
+
+  void setProcessPID(const qint64 pid) { m_workerPID = pid; }
+
+  qint64 getProcessPID() const { return m_workerPID; }
+
+public slots:
+  void finished(const int exitCode) {
+    // queue up object deletion
+    m_worker->deleteLater();
+    m_workerRunning = false;
+    // emit the exit code to the presenter so the process info can be updated
+    emit workerFinished(m_workerPID, exitCode);
+  }
+
+  void readWorkerStdOut() const {
+    auto *worker = qobject_cast<TomographyProcess *>(sender());
+    QString out(worker->readAllStandardOutput());
+    if (!out.isEmpty())
+      emit stdOutReady(out.trimmed());
+  }
+
+  void readWorkerStdErr() const {
+    auto *worker = qobject_cast<TomographyProcess *>(sender());
+    QString out(worker->readAllStandardError());
+
+    if (!out.isEmpty())
+      emit stdErrReady(out.trimmed());
+  }
+
+  void startWorker() { m_workerRunning = true; }
+
+signals:
+  void workerFinished(const qint64, const int);
+  void stdOutReady(const QString &s) const;
+  void stdErrReady(const QString &s) const;
+
+private:
+  bool m_workerRunning = false;
+  /// Holder for the current running process' PID
+  qint64 m_workerPID;
+  TomographyProcess *const m_worker;
+};
+} // CustomInterfaces
+} // MantidQt
+#endif
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/ToolConfigTomoPy.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/ToolConfigTomoPy.h
index febc98d72fc11a19b3136e703c237c6a31e79259..1af2c729ff351ffd68dbf146d687951bf99cdb26 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/ToolConfigTomoPy.h
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Tomography/ToolConfigTomoPy.h
@@ -1,10 +1,8 @@
 #ifndef MANTIDQTCUSTOMINTERFACES_TOMOGRAPHY_TOOLCONFIGTOMOPY_H_
 #define MANTIDQTCUSTOMINTERFACES_TOMOGRAPHY_TOOLCONFIGTOMOPY_H_
 
-#include <string>
-
-#include "MantidKernel/System.h"
 #include "MantidQtCustomInterfaces/Tomography/TomoRecToolConfig.h"
+#include "MantidQtCustomInterfaces/DllConfig.h"
 
 namespace MantidQt {
 namespace CustomInterfaces {
diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/UserInputValidator.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/UserInputValidator.h
index a069c28acb4d0577b0f63b1817b34ea803f2736e..0fe5b0369a31cf6404e2ebd3ddb35752d3063e02 100644
--- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/UserInputValidator.h
+++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/UserInputValidator.h
@@ -2,11 +2,11 @@
 #define MANTID_CUSTOMINTERFACES_USERINPUTVALIDATOR_H_
 
 #include "MantidQtMantidWidgets/WorkspaceSelector.h"
-#include "MantidQtMantidWidgets/MWRunFiles.h"
+#include "MantidQtAPI/MWRunFiles.h"
 #include "MantidQtMantidWidgets/DataSelector.h"
 
+using MantidQt::API::MWRunFiles;
 using MantidQt::MantidWidgets::WorkspaceSelector;
-using MantidQt::MantidWidgets::MWRunFiles;
 using MantidQt::MantidWidgets::DataSelector;
 
 class QLineEdit;
diff --git a/MantidQt/CustomInterfaces/src/DataComparison.cpp b/MantidQt/CustomInterfaces/src/DataComparison.cpp
index a40d74aab6ad751ca0f8447b32f9356bbbabdce2..131319399c4c09e15288498486571d4b885cc3fa 100644
--- a/MantidQt/CustomInterfaces/src/DataComparison.cpp
+++ b/MantidQt/CustomInterfaces/src/DataComparison.cpp
@@ -1,11 +1,9 @@
-//----------------------
-// Includes
-//----------------------
 #include "MantidQtCustomInterfaces/DataComparison.h"
 
 #include "MantidAPI/AlgorithmManager.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidQtAPI/QwtWorkspaceSpectrumData.h"
+#include "MantidAPI/WorkspaceGroup.h"
 
 namespace {
 Mantid::Kernel::Logger g_log("DataComparison");
@@ -140,18 +138,18 @@ void DataComparison::addDataItem(Workspace_const_sptr ws) {
   MatrixWorkspace_const_sptr matrixWs =
       boost::dynamic_pointer_cast<const MatrixWorkspace>(ws);
   if (!matrixWs) {
-    g_log.error() << "Workspace " << ws->name() << "is of incorrect type!\n";
+    g_log.error() << "Workspace " << ws->getName() << "is of incorrect type!\n";
     return;
   }
 
   // Check that the workspace does not already exist in the comparison
   if (containsWorkspace(matrixWs)) {
-    g_log.information() << "Workspace " << matrixWs->name()
+    g_log.information() << "Workspace " << matrixWs->getName()
                         << " already shown in comparison.\n";
     return;
   }
 
-  std::string wsName = matrixWs->name();
+  std::string wsName = matrixWs->getName();
 
   // Append a new row to the data table
   int currentRows = m_uiForm.twCurrentData->rowCount();
@@ -209,7 +207,7 @@ void DataComparison::addDataItem(Workspace_const_sptr ws) {
  * @param ws Pointer to the workspace
  */
 bool DataComparison::containsWorkspace(MatrixWorkspace_const_sptr ws) {
-  QString testWsName = QString::fromStdString(ws->name());
+  QString testWsName = QString::fromStdString(ws->getName());
 
   int numRows = m_uiForm.twCurrentData->rowCount();
   for (int row = 0; row < numRows; row++) {
diff --git a/MantidQt/CustomInterfaces/src/DynamicPDF/DPDFInputDataControl.cpp b/MantidQt/CustomInterfaces/src/DynamicPDF/DPDFInputDataControl.cpp
index 933f1a66889fb66c38b8e28826e8801926137132..314bb3df4ef43ecfbf875d6d2931b34c2cd65958 100644
--- a/MantidQt/CustomInterfaces/src/DynamicPDF/DPDFInputDataControl.cpp
+++ b/MantidQt/CustomInterfaces/src/DynamicPDF/DPDFInputDataControl.cpp
@@ -109,7 +109,7 @@ std::string InputDataControl::getWorkspaceName() {
   if (!m_workspace) {
     throw std::runtime_error("InpuDataControl has not set m_workspace!");
   }
-  return m_workspace->name();
+  return m_workspace->getName();
 }
 
 /**
diff --git a/MantidQt/CustomInterfaces/src/EnggDiffraction/EnggDiffFittingPresenter.cpp b/MantidQt/CustomInterfaces/src/EnggDiffraction/EnggDiffFittingPresenter.cpp
index 6f7f31fe0f0b2635d76388c5f805a8bd64631f58..579dc6c3a112fdf0a117ce2f9c883d62a364077f 100644
--- a/MantidQt/CustomInterfaces/src/EnggDiffraction/EnggDiffFittingPresenter.cpp
+++ b/MantidQt/CustomInterfaces/src/EnggDiffraction/EnggDiffFittingPresenter.cpp
@@ -1,5 +1,6 @@
 #include "MantidQtCustomInterfaces/EnggDiffraction/EnggDiffFittingPresenter.h"
 #include "MantidAPI/AlgorithmManager.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/ITableWorkspace.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/Run.h"
@@ -10,6 +11,7 @@
 
 #include <boost/lexical_cast.hpp>
 #include <fstream>
+#include <cctype>
 
 #include <Poco/DirectoryIterator.h>
 #include <Poco/File.h>
@@ -1445,9 +1447,10 @@ void EnggDiffFittingPresenter::getDifcTzero(MatrixWorkspace_const_sptr wks,
     difc = 18400;
     g_log.warning()
         << "Could not retrieve the DIFC, DIFA, TZERO values from the workspace "
-        << wks->name() << ". Using default, which is not adjusted for this "
-                          "workspace/run: DIFA: " << difa << ", DIFC: " << difc
-        << ", TZERO: " << tzero << ". Error details: " << rexc.what() << '\n';
+        << wks->getName() << ". Using default, which is not adjusted for this "
+                             "workspace/run: DIFA: " << difa
+        << ", DIFC: " << difc << ", TZERO: " << tzero
+        << ". Error details: " << rexc.what() << '\n';
   }
 }
 
diff --git a/MantidQt/CustomInterfaces/src/EnggDiffraction/EnggDiffractionPresenter.cpp b/MantidQt/CustomInterfaces/src/EnggDiffraction/EnggDiffractionPresenter.cpp
index 6e4c80731e3659b74c66d398b5213804d8c6a9de..e158937a256ca7ed214f3dc221c8303a8344285b 100644
--- a/MantidQt/CustomInterfaces/src/EnggDiffraction/EnggDiffractionPresenter.cpp
+++ b/MantidQt/CustomInterfaces/src/EnggDiffraction/EnggDiffractionPresenter.cpp
@@ -1,16 +1,17 @@
 #include "MantidAPI/AlgorithmManager.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/ITableWorkspace.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/TableRow.h"
 #include "MantidKernel/Property.h"
 #include "MantidKernel/StringTokenizer.h"
 #include "MantidQtAPI/PythonRunner.h"
-// #include "MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionModel.h"
 #include "MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionPresWorker.h"
 #include "MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionPresenter.h"
 #include "MantidQtCustomInterfaces/EnggDiffraction/IEnggDiffractionView.h"
 
 #include <algorithm>
+#include <cctype>
 #include <fstream>
 
 #include <boost/lexical_cast.hpp>
@@ -182,14 +183,12 @@ void EnggDiffractionPresenter::notify(
 void EnggDiffractionPresenter::processStart() {
   EnggDiffCalibSettings cs = m_view->currentCalibSettings();
   m_view->showStatus("Ready");
-
-  updateNewCalib(m_view->currentCalibFile());
 }
 
 void EnggDiffractionPresenter::processLoadExistingCalib() {
   EnggDiffCalibSettings cs = m_view->currentCalibSettings();
 
-  std::string fname = m_view->askExistingCalibFilename();
+  const std::string fname = m_view->askExistingCalibFilename();
   if (fname.empty()) {
     return;
   }
@@ -2235,7 +2234,7 @@ void EnggDiffractionPresenter::doRebinningTime(const std::string &runNo,
     auto alg =
         Mantid::API::AlgorithmManager::Instance().createUnmanaged(rebinName);
     alg->initialize();
-    alg->setPropertyValue("InputWorkspace", inWS->name());
+    alg->setPropertyValue("InputWorkspace", inWS->getName());
     alg->setPropertyValue("OutputWorkspace", outWSName);
     alg->setProperty("Params", boost::lexical_cast<std::string>(bin));
 
@@ -2338,7 +2337,7 @@ void EnggDiffractionPresenter::doRebinningPulses(const std::string &runNo,
     auto alg =
         Mantid::API::AlgorithmManager::Instance().createUnmanaged(rebinName);
     alg->initialize();
-    alg->setPropertyValue("InputWorkspace", inWS->name());
+    alg->setPropertyValue("InputWorkspace", inWS->getName());
     alg->setPropertyValue("OutputWorkspace", outWSName);
     alg->setProperty("Params", boost::lexical_cast<std::string>(timeStep));
 
diff --git a/MantidQt/CustomInterfaces/src/EnggDiffraction/EnggDiffractionViewQtGUI.cpp b/MantidQt/CustomInterfaces/src/EnggDiffraction/EnggDiffractionViewQtGUI.cpp
index fa97dab139e1c64d11e79b77f6815166429c8dfa..ae30702477911ede138409d12d6adbc0a2846e23 100644
--- a/MantidQt/CustomInterfaces/src/EnggDiffraction/EnggDiffractionViewQtGUI.cpp
+++ b/MantidQt/CustomInterfaces/src/EnggDiffraction/EnggDiffractionViewQtGUI.cpp
@@ -4,7 +4,7 @@
 #include "MantidQtAPI/AlgorithmRunner.h"
 #include "MantidQtAPI/HelpWindow.h"
 #include "MantidQtCustomInterfaces/EnggDiffraction/EnggDiffractionPresenter.h"
-#include "MantidQtMantidWidgets/MWRunFiles.h"
+#include "MantidQtAPI/MWRunFiles.h"
 
 #include <Poco/DirectoryIterator.h>
 #include <Poco/Path.h>
diff --git a/MantidQt/CustomInterfaces/src/Homer.cpp b/MantidQt/CustomInterfaces/src/Homer.cpp
index 19effc35cdceb15fdf1e7b72b24f415a09e6492c..2a7a8b141b87392c5f56cd813d42064def8245d7 100644
--- a/MantidQt/CustomInterfaces/src/Homer.cpp
+++ b/MantidQt/CustomInterfaces/src/Homer.cpp
@@ -2,7 +2,6 @@
 #include "MantidQtCustomInterfaces/Background.h"
 #include "MantidQtCustomInterfaces/deltaECalc.h"
 #include "MantidQtMantidWidgets/MWDiag.h"
-#include "MantidQtAPI/FileDialogHandler.h"
 #include "MantidQtAPI/MantidDesktopServices.h"
 
 #include "MantidKernel/ConfigService.h"
@@ -392,8 +391,8 @@ QString Homer::openFileDia(const bool save, const QStringList &exts) {
 
   QString filename;
   if (save) {
-    filename = API::FileDialogHandler::getSaveFileName(this, "Save file",
-                                                       m_lastSaveDir, filter);
+    filename =
+        QFileDialog::getSaveFileName(this, "Save file", m_lastSaveDir, filter);
     if (!filename.isEmpty()) {
       m_lastSaveDir = QFileInfo(filename).absoluteDir().path();
     }
diff --git a/MantidQt/CustomInterfaces/src/Indirect/ApplyPaalmanPings.cpp b/MantidQt/CustomInterfaces/src/Indirect/ApplyPaalmanPings.cpp
index 5806df93a0c5fb7e052a763eec7b0b2c6b8396c2..bfe5dd58b9eaf8ed892f0ea0d113683a252bd415 100644
--- a/MantidQt/CustomInterfaces/src/Indirect/ApplyPaalmanPings.cpp
+++ b/MantidQt/CustomInterfaces/src/Indirect/ApplyPaalmanPings.cpp
@@ -3,6 +3,7 @@
 #include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Run.h"
 #include "MantidAPI/TextAxis.h"
+#include "MantidAPI/WorkspaceGroup.h"
 
 #include <QStringList>
 
@@ -226,7 +227,8 @@ void ApplyPaalmanPings::run() {
           result = QMessageBox::Yes;
         } else {
           std::string text = "Number of bins on sample and " +
-                             factorWs->name() + " workspace does not match.\n" +
+                             factorWs->getName() +
+                             " workspace does not match.\n" +
                              "Would you like to interpolate this workspace to "
                              "match the sample?";
 
@@ -356,8 +358,8 @@ void ApplyPaalmanPings::addInterpolationStep(MatrixWorkspace_sptr toInterpolate,
   interpolationAlg->initialize();
 
   interpolationAlg->setProperty("WorkspaceToInterpolate",
-                                toInterpolate->name());
-  interpolationAlg->setProperty("OutputWorkspace", toInterpolate->name());
+                                toInterpolate->getName());
+  interpolationAlg->setProperty("OutputWorkspace", toInterpolate->getName());
 
   m_batchAlgoRunner->addAlgorithm(interpolationAlg, interpolationProps);
 }
@@ -491,7 +493,7 @@ bool ApplyPaalmanPings::validate() {
         Mantid::Kernel::Unit_sptr xUnit = factorWs->getAxis(0)->unit();
         if (xUnit->caption() != "Wavelength") {
           QString msg = "Correction factor workspace " +
-                        QString::fromStdString(factorWs->name()) +
+                        QString::fromStdString(factorWs->getName()) +
                         " is not in wavelength";
           uiv.addErrorMessage(msg);
         }
diff --git a/MantidQt/CustomInterfaces/src/Indirect/CalculatePaalmanPings.cpp b/MantidQt/CustomInterfaces/src/Indirect/CalculatePaalmanPings.cpp
index e870bf063f7ee59a0ed55939988e91f64bd325e4..976843cc3e712b64be35412b98a1018c5180015a 100644
--- a/MantidQt/CustomInterfaces/src/Indirect/CalculatePaalmanPings.cpp
+++ b/MantidQt/CustomInterfaces/src/Indirect/CalculatePaalmanPings.cpp
@@ -3,6 +3,7 @@
 #include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Axis.h"
 #include "MantidAPI/MatrixWorkspace.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidGeometry/Instrument.h"
 #include "MantidKernel/Unit.h"
 #include "MantidKernel/Material.h"
@@ -271,7 +272,7 @@ void CalculatePaalmanPings::absCorComplete(bool error) {
           AlgorithmManager::Instance().create("ConvertSpectrumAxis");
       convertSpecAlgo->initialize();
       convertSpecAlgo->setProperty("InputWorkspace", factorWs);
-      convertSpecAlgo->setProperty("OutputWorkspace", factorWs->name());
+      convertSpecAlgo->setProperty("OutputWorkspace", factorWs->getName());
       convertSpecAlgo->setProperty("Target", "ElasticQ");
       convertSpecAlgo->setProperty("EMode", "Indirect");
 
diff --git a/MantidQt/CustomInterfaces/src/Indirect/ConvFit.cpp b/MantidQt/CustomInterfaces/src/Indirect/ConvFit.cpp
index 3c5f31c71e021ce0c99b9884f008c446a8196705..840e0e01b301e99a00055e9770453ef8d2e3f4dd 100644
--- a/MantidQt/CustomInterfaces/src/Indirect/ConvFit.cpp
+++ b/MantidQt/CustomInterfaces/src/Indirect/ConvFit.cpp
@@ -8,6 +8,7 @@
 #include "MantidAPI/FunctionDomain1D.h"
 #include "MantidAPI/FunctionFactory.h"
 #include "MantidAPI/TextAxis.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidGeometry/Instrument.h"
 
 #include <QDoubleValidator>
@@ -323,6 +324,11 @@ void ConvFit::plotClicked() {
         const auto specNumber = m_uiForm.cbPlotType->currentIndex();
         IndirectTab::plotSpectrum(QString::fromStdString(resultWs->getName()),
                                   specNumber, specNumber);
+        // Plot results for both Lorentzians if "Two Lorentzians"
+        if (m_uiForm.cbFitType->currentIndex() == 2) {
+          IndirectTab::plotSpectrum(QString::fromStdString(resultWs->getName()),
+                                    specNumber + 2, specNumber + 2);
+        }
       }
     }
   } else {
@@ -1539,14 +1545,16 @@ QStringList ConvFit::getFunctionParameters(QString functionName) {
     }
   }
   // Add another Lorentzian function parameter for two Lorentzian fit
-  if (functionName.compare("Two Lorentzian") == 0) {
+  if (functionName.compare("Two Lorentzians") == 0) {
     currentFitFunction = "Lorentzian";
+    IFunction_sptr func = FunctionFactory::Instance().createFunction(
+        currentFitFunction.toStdString());
+    for (size_t i = 0; i < func->nParams(); i++) {
+      parameters << QString::fromStdString(func->parameterName(i));
+    }
   }
   if (functionName.compare("Zero Lorentzians") == 0) {
     parameters.append("Zero");
-  } else {
-    IFunction_sptr func = FunctionFactory::Instance().createFunction(
-        currentFitFunction.toStdString());
   }
   return parameters;
 }
diff --git a/MantidQt/CustomInterfaces/src/Indirect/CorrectionsTab.cpp b/MantidQt/CustomInterfaces/src/Indirect/CorrectionsTab.cpp
index eb27f5b09dbfd68d8e65de0c00240756b80b566d..3411cdad54bbc2a23682da519e61b5089292e448 100644
--- a/MantidQt/CustomInterfaces/src/Indirect/CorrectionsTab.cpp
+++ b/MantidQt/CustomInterfaces/src/Indirect/CorrectionsTab.cpp
@@ -77,7 +77,7 @@ std::string CorrectionsTab::addConvertUnitsStep(MatrixWorkspace_sptr ws,
                                                 const std::string &unitID,
                                                 const std::string &suffix,
                                                 std::string eMode) {
-  std::string outputName = ws->name();
+  std::string outputName = ws->getName();
 
   if (suffix != "UNIT")
     outputName += suffix;
@@ -88,7 +88,7 @@ std::string CorrectionsTab::addConvertUnitsStep(MatrixWorkspace_sptr ws,
       AlgorithmManager::Instance().create("ConvertUnits");
   convertAlg->initialize();
 
-  convertAlg->setProperty("InputWorkspace", ws->name());
+  convertAlg->setProperty("InputWorkspace", ws->getName());
   convertAlg->setProperty("OutputWorkspace", outputName);
   convertAlg->setProperty("Target", unitID);
 
diff --git a/MantidQt/CustomInterfaces/src/Indirect/ILLEnergyTransfer.cpp b/MantidQt/CustomInterfaces/src/Indirect/ILLEnergyTransfer.cpp
index 4b0f502f8ca8c9cdd7c293b9f67ee18fff64b3dd..821b09c0e9bd40e643f8776b79870999ed2b5b86 100644
--- a/MantidQt/CustomInterfaces/src/Indirect/ILLEnergyTransfer.cpp
+++ b/MantidQt/CustomInterfaces/src/Indirect/ILLEnergyTransfer.cpp
@@ -41,15 +41,112 @@ bool ILLEnergyTransfer::validate() {
   if (!m_uiForm.rfInput->isValid())
     uiv.addErrorMessage("Run File is invalid.");
 
-  // Validate calibration file/workspace if it is being used
-  if (m_uiForm.ckUseCalibration->isChecked())
-    uiv.checkDataSelectorIsValid("Calibration", m_uiForm.dsCalibration);
-
   // Validate map file if it is being used
-  bool useMapFile = m_uiForm.cbGroupingType->currentText() == "File";
+  bool useMapFile = m_uiForm.rdGroupChoose->isChecked();
   if (useMapFile && !m_uiForm.rfMapFile->isValid())
     uiv.addErrorMessage("Grouping file is invalid.");
 
+  // Validate background file
+  if (!m_uiForm.rfBackgroundRun->isValid()) {
+    uiv.addErrorMessage("Background Run File is invalid.");
+  } else {
+    bool isDouble = true;
+    m_backScaling = m_uiForm.leBackgroundFactor->text().toDouble(&isDouble);
+    if ((!isDouble || m_backScaling <= 0) &&
+        !m_uiForm.rfBackgroundRun->getUserInput()
+             .toString()
+             .toStdString()
+             .empty()) {
+      uiv.addErrorMessage("BackgroundScaleFactor is invalid.");
+    }
+  }
+
+  // Validate calibration file
+  if (!m_uiForm.rfCalibrationRun->isValid()) {
+    uiv.addErrorMessage("Calibration Run File is invalid.");
+  } else if (!m_uiForm.rfCalibrationRun->getUserInput()
+                  .toString()
+                  .toStdString()
+                  .empty()) {
+    auto range = m_uiForm.lePeakRange->text().split(',');
+    if (range.size() != 2) {
+      uiv.addErrorMessage("Calibration Peak Range is invalid. \n"
+                          "Provide comma separated two energy values in meV.");
+    } else {
+      bool isDouble1 = true;
+      m_peakRange[0] = range[0].toDouble(&isDouble1);
+      bool isDouble2 = true;
+      m_peakRange[1] = range[1].toDouble(&isDouble2);
+
+      if (!isDouble1 || !isDouble2) {
+        uiv.addErrorMessage(
+            "Calibration Peak Range is invalid. \n"
+            "Provide comma separated two energy values in meV.");
+      } else {
+        if (m_peakRange[0] >= m_peakRange[1]) {
+          uiv.addErrorMessage("Calibration Peak Range is invalid. \n"
+                              "Start energy is >= than the end energy.");
+        }
+      }
+    }
+  }
+
+  // Validate the manual PSD integration range
+  if (m_uiForm.rdGroupRange->isChecked()) {
+    auto range = m_uiForm.lePixelRange->text().split(',');
+    if (range.size() != 2) {
+      uiv.addErrorMessage(
+          "PSD Integration Range is invalid. \n"
+          "Provide comma separated two pixel numbers, e.g. 1,128");
+    } else {
+      bool isDouble1 = true;
+      m_pixelRange[0] = range[0].toInt(&isDouble1);
+      bool isDouble2 = true;
+      m_pixelRange[1] = range[1].toInt(&isDouble2);
+
+      if (!isDouble1 || !isDouble2) {
+        uiv.addErrorMessage(
+            "PSD Integration Range is invalid. \n"
+            "Provide comma separated two pixel numbers, e.g. 1,128");
+      } else {
+        if (m_pixelRange[0] >= m_pixelRange[1] || m_pixelRange[0] < 1 ||
+            m_pixelRange[1] > 128) {
+          uiv.addErrorMessage(
+              "PSD Integration Range is invalid. \n"
+              "Start or end pixel number is outside range [1-128], "
+              "or start pixel number is >= than the end pixel number.");
+        }
+      }
+    }
+  }
+
+  // Validate if the output workspace name is not empty
+  if (m_uiForm.leOutWS->text().toStdString().empty())
+    uiv.addErrorMessage("OutputWorkspace name is invalid.");
+
+  // Validate QENS specific
+
+  // Validate vanadium file if it is being used
+  if (m_uiForm.rdQENS->isChecked()) {
+    int useVanadiumRun = m_uiForm.sbUnmirrorOption->value();
+    if ((useVanadiumRun == 5 || useVanadiumRun == 7) &&
+        (!m_uiForm.rfAlignmentRun->isValid() ||
+         m_uiForm.rfAlignmentRun->getUserInput()
+             .toString()
+             .toStdString()
+             .empty()))
+      uiv.addErrorMessage("Alignment run is invalid.");
+  }
+
+  // Validate FWS specific
+
+  if (m_uiForm.rdFWS->isChecked()) {
+    if (m_uiForm.cbObservable->currentText().toStdString().empty()) {
+      uiv.addErrorMessage("Observable is invalid, check the sample logs "
+                          "for available options");
+    }
+  }
+
   // Show error message for errors
   if (!uiv.isAllInputValid())
     showMessageBox(uiv.generateErrorMessage());
@@ -60,58 +157,98 @@ bool ILLEnergyTransfer::validate() {
 void ILLEnergyTransfer::run() {
   QMap<QString, QString> instDetails = getInstrumentDetails();
 
-  IAlgorithm_sptr reductionAlg =
-      AlgorithmManager::Instance().create("IndirectILLReduction");
-  reductionAlg->initialize();
+  QString runFilename = m_uiForm.rfInput->getUserInput().toString();
+  QString backgroundFilename =
+      m_uiForm.rfBackgroundRun->getUserInput().toString();
+  QString calibrationFilename =
+      m_uiForm.rfCalibrationRun->getUserInput().toString();
 
-  reductionAlg->setProperty("Analyser", instDetails["analyser"].toStdString());
-  reductionAlg->setProperty("Reflection",
-                            instDetails["reflection"].toStdString());
+  IAlgorithm_sptr reductionAlg = nullptr;
+
+  if (m_uiForm.rdQENS->isChecked()) // QENS
+  {
+    reductionAlg =
+        AlgorithmManager::Instance().create("IndirectILLReductionQENS");
+    reductionAlg->initialize();
+
+    // Set options
+    long int uo = m_uiForm.sbUnmirrorOption->value();
+    reductionAlg->setProperty("UnmirrorOption", uo);
+    reductionAlg->setProperty("SumRuns", m_uiForm.ckSum->isChecked());
+    reductionAlg->setProperty("CropDeadMonitorChannels",
+                              m_uiForm.cbCrop->isChecked());
+
+    // Calibraiton peak range
+    if (!calibrationFilename.toStdString().empty()) {
+      auto peakRange = boost::lexical_cast<std::string>(m_peakRange[0]) + "," +
+                       boost::lexical_cast<std::string>(m_peakRange[1]);
+      reductionAlg->setProperty("CalibrationPeakRange", peakRange);
+    }
+
+    // Vanadium alignment run
+    if (uo == 5 || uo == 7) {
+      QString vanFilename = m_uiForm.rfAlignmentRun->getUserInput().toString();
+      reductionAlg->setProperty("AlignmentRun", vanFilename.toStdString());
+    }
+
+  } else { // FWS
+
+    reductionAlg =
+        AlgorithmManager::Instance().create("IndirectILLReductionFWS");
+    reductionAlg->initialize();
+
+    reductionAlg->setProperty(
+        "Observable", m_uiForm.cbObservable->currentText().toStdString());
+
+    reductionAlg->setProperty(
+        "BackgroundOption", m_uiForm.cbBackOption->currentText().toStdString());
+
+    reductionAlg->setProperty(
+        "CalibrationOption",
+        m_uiForm.cbCalibOption->currentText().toStdString());
+
+    reductionAlg->setProperty("SortXAxis", m_uiForm.cbSortX->isChecked());
+  }
+
+  // options common for QENS and FWS
 
   // Handle input files
-  QString runFilename = m_uiForm.rfInput->getFirstFilename();
   reductionAlg->setProperty("Run", runFilename.toStdString());
 
-  // Handle calibration
-  bool useCalibration = m_uiForm.ckUseCalibration->isChecked();
-  if (useCalibration) {
-    QString calibrationWsName = m_uiForm.dsCalibration->getCurrentDataName();
-    reductionAlg->setProperty("CalibrationWorkspace",
-                              calibrationWsName.toStdString());
+  // Handle background file
+  if (!backgroundFilename.toStdString().empty()) {
+    reductionAlg->setProperty("BackgroundRun",
+                              backgroundFilename.toStdString());
+    reductionAlg->setProperty("BackgroundScalingFactor", m_backScaling);
+  }
+
+  // Handle calibration file
+  if (!calibrationFilename.toStdString().empty()) {
+    reductionAlg->setProperty("CalibrationRun",
+                              calibrationFilename.toStdString());
   }
 
+  reductionAlg->setProperty("Analyser", instDetails["analyser"].toStdString());
+  reductionAlg->setProperty("Reflection",
+                            instDetails["reflection"].toStdString());
+
   // Handle mapping file
-  bool useMapFile = m_uiForm.cbGroupingType->currentText() == "File";
+  bool useMapFile = m_uiForm.rdGroupChoose->isChecked();
   if (useMapFile) {
     QString mapFilename = m_uiForm.rfMapFile->getFirstFilename();
     reductionAlg->setProperty("MapFile", mapFilename.toStdString());
   }
 
-  // Set mirror mode option
-  bool mirrorMode = m_uiForm.ckMirrorMode->isChecked();
-  reductionAlg->setProperty("MirrorMode", mirrorMode);
-
-  // Get the name format for output files
-  QFileInfo runFileInfo(runFilename);
-  QString outputFilenameBase = runFileInfo.baseName() + "_" +
-                               instDetails["analyser"] + "_" +
-                               instDetails["reflection"];
-  std::string outputFilenameBaseStd = outputFilenameBase.toStdString();
-
-  // Set left and right workspaces when using mirror mode
-  if (mirrorMode) {
-    reductionAlg->setProperty("LeftWorkspace", outputFilenameBaseStd + "_left");
-    reductionAlg->setProperty("RightWorkspace",
-                              outputFilenameBaseStd + "_right");
+  // Handle manual PSD integration range
+  if (m_uiForm.rdGroupRange->isChecked()) {
+    auto pixelRange = boost::lexical_cast<std::string>(m_pixelRange[0]) + "," +
+                      boost::lexical_cast<std::string>(m_pixelRange[1]);
+    reductionAlg->setProperty("ManualPSDIntegrationRange", pixelRange);
   }
 
-  // Set output workspace properties
-  reductionAlg->setProperty("RawWorkspace", outputFilenameBaseStd + "_raw");
-  reductionAlg->setProperty("ReducedWorkspace", outputFilenameBaseStd + "_red");
-
-  // Set output options
-  reductionAlg->setProperty("Plot", m_uiForm.ckPlot->isChecked());
-  reductionAlg->setProperty("Save", m_uiForm.ckSave->isChecked());
+  // Output workspace name
+  QString outws = m_uiForm.leOutWS->text();
+  reductionAlg->setProperty("OutputWorkspace", outws.toStdString());
 
   m_batchAlgoRunner->addAlgorithm(reductionAlg);
   m_batchAlgoRunner->executeBatchAsync();
@@ -125,10 +262,60 @@ void ILLEnergyTransfer::run() {
 void ILLEnergyTransfer::algorithmComplete(bool error) {
   if (error)
     return;
+  else {
+    if (m_uiForm.ckSave->isChecked()) {
+      save();
+    }
+    if (m_uiForm.ckPlot->isChecked()) {
+      plot();
+    }
+    if (m_uiForm.ck2Theta->isChecked()) {
+      convertTo2Theta();
+    }
+  }
 
   // Nothing to do here
 }
 
+/**
+ * Handles plotting of the reduced ws.
+ */
+void ILLEnergyTransfer::plot() {
+  QString pyInput = "from mantid import mtd\n"
+                    "from IndirectReductionCommon import plot_reduction\n";
+  pyInput += "plot_reduction(mtd[\"";
+  pyInput += m_uiForm.leOutWS->text();
+  pyInput += "_red\"].getItem(0).getName(),\"Contour\")\n";
+  m_pythonRunner.runPythonCode(pyInput);
+}
+
+/**
+ * Handles saving of the reduced ws.
+ */
+void ILLEnergyTransfer::save() {
+  QString pyInput;
+  pyInput += "SaveNexusProcessed(\"";
+  pyInput += m_uiForm.leOutWS->text();
+  pyInput += "_red\",\"";
+  pyInput += m_uiForm.leOutWS->text();
+  pyInput += "_red.nxs\")\n";
+  m_pythonRunner.runPythonCode(pyInput);
+}
+
+/**
+ * Handles the conversion of y-axis to 2theta
+ */
+void ILLEnergyTransfer::convertTo2Theta() {
+  QString pyInput;
+  QString inputWS = m_uiForm.leOutWS->text();
+  pyInput += "ConvertSpectrumAxis(InputWorkspace=\"";
+  pyInput += inputWS;
+  pyInput += "_red\",EMode=\"Indirect\",Target=\"Theta\",OutputWorkspace=\"";
+  pyInput += inputWS;
+  pyInput += "_2theta\")\n";
+  m_pythonRunner.runPythonCode(pyInput);
+}
+
 /**
  * Called when the instrument has changed, used to update default values.
  */
diff --git a/MantidQt/CustomInterfaces/src/Indirect/ISISCalibration.cpp b/MantidQt/CustomInterfaces/src/Indirect/ISISCalibration.cpp
index 43e40be299f454234983cfb68a9975a91dca426f..cb842494b4026b234f68d30d9aa458c5a2335778 100644
--- a/MantidQt/CustomInterfaces/src/Indirect/ISISCalibration.cpp
+++ b/MantidQt/CustomInterfaces/src/Indirect/ISISCalibration.cpp
@@ -2,6 +2,7 @@
 
 #include "MantidGeometry/Instrument.h"
 #include "MantidKernel/Logger.h"
+#include "MantidAPI/WorkspaceGroup.h"
 
 #include <QFileInfo>
 
diff --git a/MantidQt/CustomInterfaces/src/Indirect/ISISDiagnostics.cpp b/MantidQt/CustomInterfaces/src/Indirect/ISISDiagnostics.cpp
index eaec3581f4ed5d4147d8c32bef4579205bcadf28..0cc5864488749ccce0fa3821024586700c2839fe 100644
--- a/MantidQt/CustomInterfaces/src/Indirect/ISISDiagnostics.cpp
+++ b/MantidQt/CustomInterfaces/src/Indirect/ISISDiagnostics.cpp
@@ -1,6 +1,7 @@
 #include "MantidQtCustomInterfaces/Indirect/ISISDiagnostics.h"
 
 #include "MantidAPI/MatrixWorkspace.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidKernel/Logger.h"
 #include "MantidQtCustomInterfaces/UserInputValidator.h"
 
@@ -238,7 +239,7 @@ void ISISDiagnostics::algorithmComplete(bool error) {
 
   for (size_t i = 0; i < sliceOutputGroup->size(); i++) {
     QString wsName =
-        QString::fromStdString(sliceOutputGroup->getItem(i)->name());
+        QString::fromStdString(sliceOutputGroup->getItem(i)->getName());
   }
   // Enable plot and save buttons
   m_uiForm.pbSave->setEnabled(true);
diff --git a/MantidQt/CustomInterfaces/src/Indirect/ISISEnergyTransfer.cpp b/MantidQt/CustomInterfaces/src/Indirect/ISISEnergyTransfer.cpp
index 6897dc29bac22bbe7e35feebc5e1204ff846b0ae..c426cb03763e8a2b4e3e61c6942ad1f9d0b42859 100644
--- a/MantidQt/CustomInterfaces/src/Indirect/ISISEnergyTransfer.cpp
+++ b/MantidQt/CustomInterfaces/src/Indirect/ISISEnergyTransfer.cpp
@@ -1,6 +1,7 @@
 #include "MantidQtCustomInterfaces/Indirect/ISISEnergyTransfer.h"
 
 #include "MantidAPI/MatrixWorkspace.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidGeometry/IDTypes.h"
 #include "MantidQtCustomInterfaces/UserInputValidator.h"
 
diff --git a/MantidQt/CustomInterfaces/src/Indirect/IndirectDiffractionReduction.cpp b/MantidQt/CustomInterfaces/src/Indirect/IndirectDiffractionReduction.cpp
index d4e8a6def74e16390210dbb8ee81ba4be4ef408b..d7b5c2b663a2d60626a8fd31bdc9e4d24fe8fb60 100644
--- a/MantidQt/CustomInterfaces/src/Indirect/IndirectDiffractionReduction.cpp
+++ b/MantidQt/CustomInterfaces/src/Indirect/IndirectDiffractionReduction.cpp
@@ -1,10 +1,8 @@
-//----------------------
-// Includes
-//----------------------
 #include "MantidQtCustomInterfaces/Indirect/IndirectDiffractionReduction.h"
 
 #include "MantidAPI/AlgorithmManager.h"
 #include "MantidAPI/MatrixWorkspace.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidGeometry/Instrument.h"
 #include "MantidKernel/Logger.h"
 #include "MantidKernel/MultiFileNameParser.h"
diff --git a/MantidQt/CustomInterfaces/src/Indirect/IndirectMolDyn.cpp b/MantidQt/CustomInterfaces/src/Indirect/IndirectMolDyn.cpp
index b0266ef1caa3d94b5d7e712d69888cd012d94071..95e26d66dff575ec7768357b47af74d566568a2f 100644
--- a/MantidQt/CustomInterfaces/src/Indirect/IndirectMolDyn.cpp
+++ b/MantidQt/CustomInterfaces/src/Indirect/IndirectMolDyn.cpp
@@ -1,6 +1,7 @@
 #include "MantidQtCustomInterfaces/Indirect/IndirectMolDyn.h"
 
 #include "MantidQtCustomInterfaces/UserInputValidator.h"
+#include "MantidAPI/WorkspaceGroup.h"
 
 #include <QFileInfo>
 #include <QString>
diff --git a/MantidQt/CustomInterfaces/src/Indirect/IndirectMoments.cpp b/MantidQt/CustomInterfaces/src/Indirect/IndirectMoments.cpp
index e5f9af1d7495ecd60d026e59c64f302529e38c69..4d26725911430eed5c2a998a2338581eba87b841 100644
--- a/MantidQt/CustomInterfaces/src/Indirect/IndirectMoments.cpp
+++ b/MantidQt/CustomInterfaces/src/Indirect/IndirectMoments.cpp
@@ -1,6 +1,7 @@
 #include "MantidQtCustomInterfaces/Indirect/IndirectMoments.h"
 
 #include "MantidQtCustomInterfaces/UserInputValidator.h"
+#include "MantidAPI/WorkspaceGroup.h"
 
 #include <QDoubleValidator>
 #include <QFileInfo>
@@ -73,7 +74,7 @@ void IndirectMoments::run() {
   IAlgorithm_sptr momentsAlg =
       AlgorithmManager::Instance().create("SofQWMoments", -1);
   momentsAlg->initialize();
-  momentsAlg->setProperty("Sample", workspaceName.toStdString());
+  momentsAlg->setProperty("InputWorkspace", workspaceName.toStdString());
   momentsAlg->setProperty("EnergyMin", eMin);
   momentsAlg->setProperty("EnergyMax", eMax);
   momentsAlg->setProperty("OutputWorkspace", outputWorkspaceName);
@@ -82,7 +83,7 @@ void IndirectMoments::run() {
     momentsAlg->setProperty("Scale", scale);
 
   // Set the workspace name for Python script export
-  m_pythonExportWsName = outputWorkspaceName + "_M0";
+  m_pythonExportWsName = outputWorkspaceName;
 
   // Execute algorithm on separate thread
   runAlgorithm(momentsAlg);
@@ -177,22 +178,21 @@ void IndirectMoments::momentsAlgComplete(bool error) {
   QString outputName = workspaceName.left(workspaceName.length() - 4);
   std::string outputWorkspaceName = outputName.toStdString() + "_Moments";
 
-  WorkspaceGroup_sptr resultWsGroup =
-      AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>(
+  MatrixWorkspace_sptr outputWorkspace =
+      AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(
           outputWorkspaceName);
-  std::vector<std::string> resultWsNames = resultWsGroup->getNames();
 
-  if (resultWsNames.size() < 4)
+  if (outputWorkspace->getNumberHistograms() < 5)
     return;
 
   // Plot each spectrum
   m_uiForm.ppMomentsPreview->clear();
   m_uiForm.ppMomentsPreview->addSpectrum(
-      "M0", QString::fromStdString(resultWsNames[0]), 0, Qt::green);
+      "M0", QString::fromStdString(outputWorkspaceName), 0, Qt::green);
   m_uiForm.ppMomentsPreview->addSpectrum(
-      "M1", QString::fromStdString(resultWsNames[1]), 0, Qt::black);
+      "M1", QString::fromStdString(outputWorkspaceName), 1, Qt::black);
   m_uiForm.ppMomentsPreview->addSpectrum(
-      "M2", QString::fromStdString(resultWsNames[2]), 0, Qt::red);
+      "M2", QString::fromStdString(outputWorkspaceName), 2, Qt::red);
   m_uiForm.ppMomentsPreview->resizeX();
 
   // Enable plot and save buttons
@@ -207,8 +207,7 @@ void IndirectMoments::plotClicked() {
   QString outputWs =
       getWorkspaceBasename(m_uiForm.dsInput->getCurrentDataName()) + "_Moments";
   if (checkADSForPlotSaveWorkspace(outputWs.toStdString(), true)) {
-    plotSpectrum(outputWs + "_M0");
-    plotSpectrum({outputWs + "_M2", outputWs + "_M4"});
+    plotSpectra(outputWs, {0, 2, 4});
   }
 }
 
diff --git a/MantidQt/CustomInterfaces/src/Indirect/IndirectTab.cpp b/MantidQt/CustomInterfaces/src/Indirect/IndirectTab.cpp
index b33af6c3fd39db5a001dd29b02905114dd226c66..96a489bface68f9a6362220a0f26c41c7e4e8915 100644
--- a/MantidQt/CustomInterfaces/src/Indirect/IndirectTab.cpp
+++ b/MantidQt/CustomInterfaces/src/Indirect/IndirectTab.cpp
@@ -265,11 +265,11 @@ void IndirectTab::plotSpectrum(const QStringList &workspaceNames, int specStart,
 
   pyInput += "plotSpectrum(['";
   pyInput += workspaceNames.join("','");
-  pyInput += "'], range(";
+  pyInput += "'], list(range(";
   pyInput += QString::number(specStart);
   pyInput += ",";
   pyInput += QString::number(specEnd + 1);
-  pyInput += "), error_bars = True)\n";
+  pyInput += ")), error_bars = True)\n";
 
   m_pythonRunner.runPythonCode(pyInput);
 }
diff --git a/MantidQt/CustomInterfaces/src/Indirect/IndirectTransmission.cpp b/MantidQt/CustomInterfaces/src/Indirect/IndirectTransmission.cpp
index 3b6e74e659c9aa29a9074276801ab058578e317b..a064cdea29a61fd021402098f47e4807db974e58 100644
--- a/MantidQt/CustomInterfaces/src/Indirect/IndirectTransmission.cpp
+++ b/MantidQt/CustomInterfaces/src/Indirect/IndirectTransmission.cpp
@@ -1,4 +1,5 @@
 #include "MantidQtCustomInterfaces/Indirect/IndirectTransmission.h"
+#include "MantidAPI/WorkspaceGroup.h"
 
 #include <QFileInfo>
 
diff --git a/MantidQt/CustomInterfaces/src/Indirect/IqtFit.cpp b/MantidQt/CustomInterfaces/src/Indirect/IqtFit.cpp
index 260515d88e4e4929a352e456f0fa5b49af55860c..c01713eb3c0e03c8bc48585fb879e7da77155425 100644
--- a/MantidQt/CustomInterfaces/src/Indirect/IqtFit.cpp
+++ b/MantidQt/CustomInterfaces/src/Indirect/IqtFit.cpp
@@ -7,6 +7,7 @@
 #include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/FunctionFactory.h"
 #include "MantidAPI/FunctionDomain1D.h"
+#include "MantidAPI/WorkspaceGroup.h"
 
 #include <math.h>
 #include <QFileInfo>
diff --git a/MantidQt/CustomInterfaces/src/Indirect/MSDFit.cpp b/MantidQt/CustomInterfaces/src/Indirect/MSDFit.cpp
index 23e44bf1adc877e1c2170739e1c1180bde5672bf..b33ebef1f854d059f330be5ff9e6c008aa44b714 100644
--- a/MantidQt/CustomInterfaces/src/Indirect/MSDFit.cpp
+++ b/MantidQt/CustomInterfaces/src/Indirect/MSDFit.cpp
@@ -1,5 +1,5 @@
 #include "MantidAPI/AnalysisDataService.h"
-#include "MantidAPI/WorkspaceGroup_fwd.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidQtCustomInterfaces/Indirect/MSDFit.h"
 #include "MantidQtCustomInterfaces/UserInputValidator.h"
 #include "MantidQtMantidWidgets/RangeSelector.h"
@@ -316,9 +316,20 @@ void MSDFit::saveClicked() {
  * Handles mantid plotting
  */
 void MSDFit::plotClicked() {
-  if (checkADSForPlotSaveWorkspace(m_pythonExportWsName + "_Workspaces", true))
-    plotSpectrum((QString::fromStdString(m_pythonExportWsName) + "_Workspaces"),
-                 0, 2);
+  auto wsName = QString::fromStdString(m_pythonExportWsName) + "_Workspaces";
+  if (checkADSForPlotSaveWorkspace(wsName.toStdString(), true)) {
+    // Get the workspace
+    auto groupWs =
+        AnalysisDataService::Instance().retrieveWS<const WorkspaceGroup>(
+            wsName.toStdString());
+    auto groupWsNames = groupWs->getNames();
+    if (groupWsNames.size() != 1) {
+      plotSpectrum(QString::fromStdString(m_pythonExportWsName), 1);
+    }
+
+    else
+      plotSpectrum(wsName, 0, 2);
+  }
 }
 
 } // namespace IDA
diff --git a/MantidQt/CustomInterfaces/src/Indirect/ResNorm.cpp b/MantidQt/CustomInterfaces/src/Indirect/ResNorm.cpp
index e2f6f22fc6f280632235d48e2cf25a53893ca44e..a73ec35c9a5e2def5b34ef1151b5365004505ccc 100644
--- a/MantidQt/CustomInterfaces/src/Indirect/ResNorm.cpp
+++ b/MantidQt/CustomInterfaces/src/Indirect/ResNorm.cpp
@@ -2,6 +2,7 @@
 
 #include "MantidQtCustomInterfaces/UserInputValidator.h"
 #include "MantidAPI/WorkspaceFactory.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidAPI/ITableWorkspace.h"
 
 using namespace Mantid::API;
@@ -282,7 +283,7 @@ void ResNorm::previewSpecChanged(int value) {
             fitParamsName);
     if (fitWorkspaces && fitParams) {
       Column_const_sptr scaleFactors = fitParams->getColumn("Scaling");
-      std::string fitWsName(fitWorkspaces->getItem(m_previewSpec)->name());
+      std::string fitWsName(fitWorkspaces->getItem(m_previewSpec)->getName());
       MatrixWorkspace_const_sptr fitWs =
           AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(
               fitWsName);
@@ -330,8 +331,8 @@ void ResNorm::plotClicked() {
   QString fitWsName("");
 
   if (fitWorkspaces)
-    fitWsName =
-        QString::fromStdString(fitWorkspaces->getItem(m_previewSpec)->name());
+    fitWsName = QString::fromStdString(
+        fitWorkspaces->getItem(m_previewSpec)->getName());
 
   QString plotOptions(m_uiForm.cbPlot->currentText());
   if (plotOptions == "Intensity" || plotOptions == "All")
diff --git a/MantidQt/CustomInterfaces/src/Indirect/Stretch.cpp b/MantidQt/CustomInterfaces/src/Indirect/Stretch.cpp
index 0d2e50dc7c537d30dc0a49439064db23cdef2799..7d4cbb4fd97df20b962327ec918b668e9017762f 100644
--- a/MantidQt/CustomInterfaces/src/Indirect/Stretch.cpp
+++ b/MantidQt/CustomInterfaces/src/Indirect/Stretch.cpp
@@ -2,6 +2,7 @@
 #include "MantidQtCustomInterfaces/UserInputValidator.h"
 
 #include "MantidAPI/AlgorithmManager.h"
+#include "MantidAPI/WorkspaceGroup.h"
 
 using namespace Mantid::API;
 
diff --git a/MantidQt/CustomInterfaces/src/MantidEVWorker.cpp b/MantidQt/CustomInterfaces/src/MantidEVWorker.cpp
index b87f18f79ac1dc3cda9dc124615aada5eec80a38..4e5a212ad6703d634d3112e7f87af5e420a8ca5a 100644
--- a/MantidQt/CustomInterfaces/src/MantidEVWorker.cpp
+++ b/MantidQt/CustomInterfaces/src/MantidEVWorker.cpp
@@ -5,6 +5,7 @@
 #include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/AlgorithmManager.h"
 #include "MantidAPI/Workspace.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidAPI/IEventWorkspace.h"
 #include "MantidAPI/IMDWorkspace.h"
 #include "MantidAPI/IPeaksWorkspace.h"
@@ -56,9 +57,19 @@ std::string MantidEVWorker::workspaceType(const std::string &ws_name) {
   if (!ADS.doesExist(ws_name))
     return std::string("");
 
-  Workspace_const_sptr outWS = ADS.retrieveWS<Workspace>(ws_name);
+  WorkspaceGroup_const_sptr wsgroup = ADS.retrieveWS<WorkspaceGroup>(ws_name);
+  if (wsgroup) {
 
-  return outWS->id();
+    std::vector<std::string> group = wsgroup->getNames();
+    Workspace_const_sptr outWS = ADS.retrieveWS<Workspace>(group[0]);
+
+    return outWS->id();
+  } else {
+
+    Workspace_const_sptr outWS = ADS.retrieveWS<Workspace>(ws_name);
+
+    return outWS->id();
+  }
 }
 
 /**
diff --git a/MantidQt/CustomInterfaces/src/MultiDatasetFit/MDFDataController.cpp b/MantidQt/CustomInterfaces/src/MultiDatasetFit/MDFDataController.cpp
index cf10f1d69836744e4988238f3f31ffd8d1805f90..0627e4fd577e690301f7813a21b572b29d82af04 100644
--- a/MantidQt/CustomInterfaces/src/MultiDatasetFit/MDFDataController.cpp
+++ b/MantidQt/CustomInterfaces/src/MultiDatasetFit/MDFDataController.cpp
@@ -70,7 +70,7 @@ void DataController::addWorkspace() {
       if (!matrixWorkspaces.empty()) {
         for (auto iws = matrixWorkspaces.begin(); iws != matrixWorkspaces.end();
              ++iws) {
-          auto name = QString::fromStdString((**iws).name());
+          auto name = QString::fromStdString((**iws).getName());
           for (auto i = indices.begin(); i != indices.end(); ++i) {
             addWorkspaceSpectrum(name, *i, **iws);
           }
diff --git a/MantidQt/CustomInterfaces/src/MultiDatasetFit/MultiDatasetFit.cpp b/MantidQt/CustomInterfaces/src/MultiDatasetFit/MultiDatasetFit.cpp
index 0fa179229e8a56109bb5ef3c09df26257b2efba5..d39dd074747c214fe576e699ef3205487d7f8e2f 100644
--- a/MantidQt/CustomInterfaces/src/MultiDatasetFit/MultiDatasetFit.cpp
+++ b/MantidQt/CustomInterfaces/src/MultiDatasetFit/MultiDatasetFit.cpp
@@ -9,6 +9,7 @@
 #include "MantidAPI/ITableWorkspace.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/Run.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidKernel/TimeSeriesProperty.h"
 
 #include "MantidQtAPI/AlgorithmRunner.h"
@@ -373,7 +374,7 @@ QString MultiDatasetFit::getOutputWorkspaceName(int i) const {
     auto ws = Mantid::API::AnalysisDataService::Instance().retrieve(wsName);
     if (auto group =
             boost::dynamic_pointer_cast<Mantid::API::WorkspaceGroup>(ws)) {
-      wsName = group->getItem(i)->name();
+      wsName = group->getItem(i)->getName();
     }
   }
   return QString::fromStdString(wsName);
diff --git a/MantidQt/CustomInterfaces/src/Muon/IO_MuonGrouping.cpp b/MantidQt/CustomInterfaces/src/Muon/IO_MuonGrouping.cpp
index ca42e651d15287e87aabb1be4f8fb3755a26a6b6..28775d2233072d7d80fe29ad87fb12a495b39878 100644
--- a/MantidQt/CustomInterfaces/src/Muon/IO_MuonGrouping.cpp
+++ b/MantidQt/CustomInterfaces/src/Muon/IO_MuonGrouping.cpp
@@ -27,6 +27,8 @@
 #pragma warning(disable : 4250)
 #include <Poco/XML/XMLWriter.h>
 #pragma warning(pop)
+#else
+#include <Poco/XML/XMLWriter.h>
 #endif
 
 //-----------------------------------------------------------------------------
diff --git a/MantidQt/CustomInterfaces/src/Muon/MuonAnalysis.cpp b/MantidQt/CustomInterfaces/src/Muon/MuonAnalysis.cpp
index 9d372e589fba433c0711cec5b9e281023ea53d53..9caa12314d5bce32a82557ab0ec6b944afc19878 100644
--- a/MantidQt/CustomInterfaces/src/Muon/MuonAnalysis.cpp
+++ b/MantidQt/CustomInterfaces/src/Muon/MuonAnalysis.cpp
@@ -1,6 +1,3 @@
-//----------------------
-// Includes
-//----------------------
 #include "MantidQtCustomInterfaces/Muon/MuonAnalysis.h"
 #include "MantidAPI/AlgorithmManager.h"
 #include "MantidAPI/AnalysisDataService.h"
@@ -20,8 +17,8 @@
 #include "MantidKernel/Exception.h"
 #include "MantidKernel/FacilityInfo.h"
 #include "MantidKernel/Logger.h"
+#include "MantidKernel/Strings.h"
 #include "MantidKernel/cow_ptr.h"
-#include "MantidQtAPI/FileDialogHandler.h"
 #include "MantidQtAPI/HelpWindow.h"
 #include "MantidQtAPI/ManageUserDirectories.h"
 #include "MantidQtCustomInterfaces/Muon/MuonAnalysisFitDataPresenter.h"
@@ -565,7 +562,7 @@ void MuonAnalysis::runSaveGroupButton() {
   QString filter;
   filter.append("Files (*.xml *.XML)");
   filter += ";;AllFiles (*)";
-  QString groupingFile = MantidQt::API::FileDialogHandler::getSaveFileName(
+  QString groupingFile = QFileDialog::getSaveFileName(
       this, "Save Grouping file as", prevPath, filter);
 
   // Add extension if the groupingFile specified doesn't have one. (Solving
@@ -2208,8 +2205,20 @@ void MuonAnalysis::setAppendingRun(int inc) {
 void MuonAnalysis::changeRun(int amountToChange) {
   QString filePath("");
   QString currentFile = m_uiForm.mwRunFiles->getFirstFilename();
-  if ((currentFile.isEmpty()))
-    currentFile = m_previousFilenames[0];
+  if ((currentFile.isEmpty())) {
+    if (m_previousFilenames.isEmpty()) {
+      // not a valid file, and no previous valid files
+      QMessageBox::warning(this, tr("Muon Analysis"),
+                           tr("Unable to open the file.\n"
+                              "and no previous valid files available."),
+                           QMessageBox::Ok, QMessageBox::Ok);
+      allowLoading(true);
+      return;
+    } else {
+      // blank box - use previous run
+      currentFile = m_previousFilenames[0];
+    }
+  }
 
   QString run("");
   int runSize(-1);
diff --git a/MantidQt/CustomInterfaces/src/Muon/MuonAnalysisDataLoader.cpp b/MantidQt/CustomInterfaces/src/Muon/MuonAnalysisDataLoader.cpp
index 9234edfd11fdad2ce83469d1f12a58ac544f0329..c8c5914ab134ad0a34c3b89abffe09c8af761cca 100644
--- a/MantidQt/CustomInterfaces/src/Muon/MuonAnalysisDataLoader.cpp
+++ b/MantidQt/CustomInterfaces/src/Muon/MuonAnalysisDataLoader.cpp
@@ -36,7 +36,9 @@ namespace CustomInterfaces {
 MuonAnalysisDataLoader::MuonAnalysisDataLoader(
     const DeadTimesType &deadTimesType, const QStringList &instruments,
     const std::string &deadTimesFile)
-    : m_instruments(instruments) {
+    : m_instruments(instruments),
+      m_cacheBlacklist("\\w*auto_\\w.tmp", Qt::CaseInsensitive,
+                       QRegExp::RegExp2) {
   this->setDeadTimesType(deadTimesType, deadTimesFile);
 }
 
@@ -80,10 +82,12 @@ LoadResult MuonAnalysisDataLoader::loadFiles(const QStringList &files) const {
     return oss.str();
   };
 
+  // Clean cache from stale files etc
+  updateCache();
   // Check cache to see if we've loaded this set of files before
   const std::string fileString = toString(files);
-  updateCache();
   if (m_loadedDataCache.find(fileString) != m_loadedDataCache.end()) {
+    g_log.information("Using cached workspace for file(s): " + fileString);
     return m_loadedDataCache[fileString];
   }
 
@@ -176,8 +180,11 @@ LoadResult MuonAnalysisDataLoader::loadFiles(const QStringList &files) const {
     result.label = MuonAnalysisHelper::getRunLabel(loadedWorkspaces);
   }
 
-  // Cache the result so we don't have to load it next time
-  m_loadedDataCache[fileString] = result;
+  // Cache the result if we should so we don't have to load it next time
+  if (shouldBeCached(files)) {
+    g_log.information("Caching loaded workspace for file(s): " + fileString);
+    m_loadedDataCache[fileString] = result;
+  }
   return result;
 }
 
@@ -200,6 +207,23 @@ std::string MuonAnalysisDataLoader::getInstrumentName(
   return "";
 }
 
+/**
+ * Checks against an internal regex for files that match. If any files match
+ * then none will be cached.
+ * @param filenames A list of file paths
+ * @return True if they should be cached on loading, false otherwise.
+ */
+bool MuonAnalysisDataLoader::shouldBeCached(
+    const QStringList &filenames) const {
+  for (const auto &filename : filenames) {
+    if (m_cacheBlacklist.indexIn(filename) >= 0) {
+      // match indicates not caching
+      return false;
+    }
+  }
+  return true;
+}
+
 /**
  * Correct loaded data for dead times (if present) and group
  * @param loadedData :: [input] Load result
@@ -443,6 +467,7 @@ void MuonAnalysisDataLoader::updateCache() const {
   }
   // Remove the invalid cache entries
   for (const auto &key : invalidKeys) {
+    g_log.information("Erasing invalid cached entry for file(s): " + key);
     m_loadedDataCache.erase(key);
   }
 }
diff --git a/MantidQt/CustomInterfaces/src/Muon/MuonAnalysisFitDataPresenter.cpp b/MantidQt/CustomInterfaces/src/Muon/MuonAnalysisFitDataPresenter.cpp
index 9860a424bd36a31420faa28929091987112d206b..a4ea16d99a8cd636eea72f107479fda723d7b135 100644
--- a/MantidQt/CustomInterfaces/src/Muon/MuonAnalysisFitDataPresenter.cpp
+++ b/MantidQt/CustomInterfaces/src/Muon/MuonAnalysisFitDataPresenter.cpp
@@ -6,6 +6,7 @@
 #include "MantidAPI/TableRow.h"
 #include "MantidAPI/Workspace_fwd.h"
 #include "MantidAPI/WorkspaceFactory.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidQtCustomInterfaces/Muon/MuonAnalysisFitDataPresenter.h"
 #include "MantidQtCustomInterfaces/Muon/MuonAnalysisHelper.h"
 #include "MantidQtCustomInterfaces/Muon/MuonSequentialFitDialog.h"
@@ -149,9 +150,8 @@ void MuonAnalysisFitDataPresenter::doConnect() {
  * Updates WS index, startX, endX
  */
 void MuonAnalysisFitDataPresenter::handleDataPropertiesChanged() {
-  // update workspace index
-  const unsigned int wsIndex = m_dataSelector->getWorkspaceIndex();
-  m_fitBrowser->setWorkspaceIndex(static_cast<int>(wsIndex));
+  // update workspace index: always 0
+  m_fitBrowser->setWorkspaceIndex(0);
 
   // update start and end times
   const double start = m_dataSelector->getStartTime();
@@ -189,7 +189,7 @@ void MuonAnalysisFitDataPresenter::handleXRangeChangedGraphically(double start,
 /**
  * Called by selectMultiPeak: fit browser has been reassigned to a new
  * workspace.
- * Sets run number, instrument and workspace index in the data selector.
+ * Sets run number and instrument in the data selector.
  * If multiple runs selected, disable sequential fit option.
  * @param wsName :: [input] Name of new workspace
  */
@@ -496,7 +496,7 @@ void MuonAnalysisFitDataPresenter::handleFittedWorkspaces(
   if (resultsGroup && paramsTable) {
     const size_t offset = paramsTable->rowCount() - resultsGroup->size();
     for (size_t i = 0; i < resultsGroup->size(); i++) {
-      const std::string oldName = resultsGroup->getItem(i)->name();
+      const std::string oldName = resultsGroup->getItem(i)->getName();
       auto wsName = paramsTable->cell<std::string>(offset + i, 0);
       wsName = wsName.substr(wsName.find_first_of('=') + 1); // strip the "f0="
       const auto wsDetails = MuonAnalysisHelper::parseWorkspaceName(wsName);
@@ -748,7 +748,6 @@ void MuonAnalysisFitDataPresenter::setUpDataSelector(const QString &wsName) {
   const QString numberString = instRun.right(instRun.size() - firstZero);
   m_dataSelector->setWorkspaceDetails(
       numberString, QString::fromStdString(wsParams.instrument));
-  m_dataSelector->setWorkspaceIndex(0u); // always has only one spectrum
 
   // Set selected groups/pairs and periods here too
   // (unless extra groups/periods are already selected, in which case don't
diff --git a/MantidQt/CustomInterfaces/src/Muon/MuonAnalysisFitFunctionPresenter.cpp b/MantidQt/CustomInterfaces/src/Muon/MuonAnalysisFitFunctionPresenter.cpp
index bd9ce894b429a681dfe369c7e60c5d7a9258969d..6a5af04871fa6ebab3f6448470fa941f8291b04d 100644
--- a/MantidQt/CustomInterfaces/src/Muon/MuonAnalysisFitFunctionPresenter.cpp
+++ b/MantidQt/CustomInterfaces/src/Muon/MuonAnalysisFitFunctionPresenter.cpp
@@ -88,7 +88,7 @@ void MuonAnalysisFitFunctionPresenter::updateFunction() {
   const Mantid::API::IFunction_sptr function =
       funcString.isEmpty() ? nullptr // last function has been removed
                            : m_funcBrowser->getGlobalFunction();
-  m_fitBrowser->setFunction(function);
+  setFunctionInModel(function);
 }
 
 /**
@@ -253,5 +253,31 @@ void MuonAnalysisFitFunctionPresenter::setMultiFitState(
   m_multiFitState = state;
 }
 
+/**
+ * Set the given function in the model (fit property browser).
+ *
+ * If and only if multi fit mode is enabled, need to deal with plot guess too.
+ * Remove the guess (if one is plotted) before updating the function, then
+ * replot if necessary afterwards.
+ * This ensures the guess is updated and prevents stale guesses in the plot.
+ *
+ * If multi fit mode is off, the user sets the function in the model directly so
+ * it works fine as is - no need to update the guess as it already happens.
+ *
+ * @param function :: [input] Function to set in the model
+ */
+void MuonAnalysisFitFunctionPresenter::setFunctionInModel(
+    const Mantid::API::IFunction_sptr &function) {
+  const bool updateGuess = m_multiFitState == Muon::MultiFitState::Enabled &&
+                           m_fitBrowser->hasGuess();
+  if (updateGuess) {
+    m_fitBrowser->doRemoveGuess();
+  }
+  m_fitBrowser->setFunction(function);
+  if (updateGuess) {
+    m_fitBrowser->doPlotGuess();
+  }
+}
+
 } // namespace CustomInterfaces
 } // namespace MantidQt
diff --git a/MantidQt/CustomInterfaces/src/Muon/MuonAnalysisHelper.cpp b/MantidQt/CustomInterfaces/src/Muon/MuonAnalysisHelper.cpp
index a4ce67ab68ab56df39790e37e381aaa39df0b7fa..d679fc4fa2e2ab51f7b70532d02a78c4ce55f2a3 100644
--- a/MantidQt/CustomInterfaces/src/Muon/MuonAnalysisHelper.cpp
+++ b/MantidQt/CustomInterfaces/src/Muon/MuonAnalysisHelper.cpp
@@ -295,6 +295,8 @@ void WidgetAutoSaver::saveWidgetValue() {
     settings.setValue(senderName, w->isChecked());
   } else if (auto w = qobject_cast<QComboBox *>(sender)) {
     settings.setValue(senderName, w->currentIndex());
+  } else if (auto w = qobject_cast<QSpinBox *>(sender)) {
+    settings.setValue(senderName, w->value());
   }
   // ... add more as neccessary
 }
@@ -319,6 +321,8 @@ void WidgetAutoSaver::loadWidgetValue(QWidget *widget) {
     w->setChecked(value.toBool());
   } else if (auto w = qobject_cast<QComboBox *>(widget)) {
     w->setCurrentIndex(value.toInt());
+  } else if (auto w = qobject_cast<QSpinBox *>(widget)) {
+    w->setValue(value.toInt());
   }
   // ... add more as neccessary
 }
@@ -1090,10 +1094,10 @@ getWorkspaceColors(const std::vector<Workspace_sptr> &workspaces) {
     if (const auto group = boost::dynamic_pointer_cast<WorkspaceGroup>(ws)) {
       for (size_t i = 0; i < group->size(); ++i) {
         const auto &ws = group->getItem(i);
-        if (ws->name().find("_Parameters") != std::string::npos) {
+        if (ws->getName().find("_Parameters") != std::string::npos) {
           params = getKeysFromTable(
               boost::dynamic_pointer_cast<ITableWorkspace>(ws));
-        } else if (ws->name().find("_Workspace") != std::string::npos) {
+        } else if (ws->getName().find("_Workspace") != std::string::npos) {
           ++nRuns;
         }
       }
@@ -1103,7 +1107,7 @@ getWorkspaceColors(const std::vector<Workspace_sptr> &workspaces) {
       params = getKeysFromTable(table);
     } else {
       throw std::invalid_argument(
-          "Unexpected workspace type for " + ws->name() +
+          "Unexpected workspace type for " + ws->getName() +
           " (expected WorkspaceGroup or ITableWorkspace)");
     }
     fitProperties.emplace_back(nRuns, params);
diff --git a/MantidQt/CustomInterfaces/src/Muon/MuonAnalysisOptionTab.cpp b/MantidQt/CustomInterfaces/src/Muon/MuonAnalysisOptionTab.cpp
index 1ef3adcc4b9b25fc5068419e20810ea4a4652353..b6d35a64f159698301da56ad2d4573f4357807b5 100644
--- a/MantidQt/CustomInterfaces/src/Muon/MuonAnalysisOptionTab.cpp
+++ b/MantidQt/CustomInterfaces/src/Muon/MuonAnalysisOptionTab.cpp
@@ -66,10 +66,10 @@ void MuonAnalysisOptionTab::initLayout() {
 
   m_autoSaver.beginGroup("GeneralOptions");
   m_autoSaver.registerWidget(m_uiForm.plotCreation, "plotCreation", 0);
-  m_autoSaver.registerWidget(m_uiForm.newPlotPolicy, "newPlotPolicy", 0);
+  m_autoSaver.registerWidget(m_uiForm.newPlotPolicy, "newPlotPolicy", 1);
   m_autoSaver.registerWidget(m_uiForm.hideToolbars, "toolbars", true);
   m_autoSaver.registerWidget(m_uiForm.hideGraphs, "hiddenGraphs", true);
-  m_autoSaver.registerWidget(m_uiForm.spinBoxNPlotsToKeep, "fitsToKeep", 1);
+  m_autoSaver.registerWidget(m_uiForm.spinBoxNPlotsToKeep, "fitsToKeep", 0);
   m_autoSaver.registerWidget(m_uiForm.chkEnableMultiFit, "enableMultiFit",
                              false);
   m_autoSaver.endGroup();
diff --git a/MantidQt/CustomInterfaces/src/Muon/MuonAnalysisResultTableTab.cpp b/MantidQt/CustomInterfaces/src/Muon/MuonAnalysisResultTableTab.cpp
index f1b63ef0f156067cb38f354b217b4b32072c9de6..51835401244fdc09cf8db5540367192d60192a12 100644
--- a/MantidQt/CustomInterfaces/src/Muon/MuonAnalysisResultTableTab.cpp
+++ b/MantidQt/CustomInterfaces/src/Muon/MuonAnalysisResultTableTab.cpp
@@ -4,6 +4,7 @@
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/Run.h"
 #include "MantidAPI/WorkspaceFactory.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidAPI/TableRow.h"
 #include "MantidKernel/ConfigService.h"
 #include "MantidKernel/TimeSeriesProperty.h"
@@ -18,13 +19,17 @@
 #include <boost/shared_ptr.hpp>
 #include <boost/algorithm/string/predicate.hpp>
 
+#include <QFileInfo>
 #include <QLineEdit>
-#include <QFileDialog>
 #include <QHash>
 #include <QMessageBox>
 
 #include <algorithm>
 
+namespace {
+const std::string RUNNING_LOG_NAME = "running";
+}
+
 namespace MantidQt {
 namespace CustomInterfaces {
 namespace Muon {
@@ -383,13 +388,36 @@ bool MuonAnalysisResultTableTab::isFittedWs(const std::string &wsName) {
 void MuonAnalysisResultTableTab::refresh() {
   m_uiForm.individualFit->setChecked(true);
 
-  auto labels = getFitLabels();
+  const auto &labels = getFitLabels();
 
   m_uiForm.fitLabelCombo->clear();
   m_uiForm.fitLabelCombo->addItems(labels.first);
   m_uiForm.cmbFitLabelSimultaneous->clear();
   m_uiForm.cmbFitLabelSimultaneous->addItems(labels.second);
 
+  // Find width of widest string in a list
+  const auto &font = this->fontMetrics();
+  const auto maxWidth = [&font](const QStringList &strings) {
+    const QString extraSpace = "   "; // to make sure string will fit
+    int maximum = 0;
+    for (const auto &string : strings) {
+      const auto &width = font.boundingRect(string + extraSpace).width();
+      if (width > maximum) {
+        maximum = width;
+      }
+    }
+    return maximum;
+  };
+
+  // Expand the width of the drop-down (not the combobox itself) to fit the
+  // longest string
+  const auto &seqSize = maxWidth(labels.first);
+  m_uiForm.fitLabelCombo->view()->setMinimumWidth(seqSize);
+  m_uiForm.fitLabelCombo->view()->setTextElideMode(Qt::ElideNone);
+  const auto &simSize = maxWidth(labels.second);
+  m_uiForm.cmbFitLabelSimultaneous->view()->setMinimumWidth(simSize);
+  m_uiForm.cmbFitLabelSimultaneous->view()->setTextElideMode(Qt::ElideNone);
+
   m_uiForm.sequentialFit->setEnabled(m_uiForm.fitLabelCombo->count() != 0);
   m_uiForm.simultaneousFit->setEnabled(
       m_uiForm.cmbFitLabelSimultaneous->count() > 0);
@@ -473,40 +501,33 @@ void MuonAnalysisResultTableTab::populateLogsAndValues(
     // Get log information
     std::string wsName = fittedWsList[i].toStdString();
     auto ws = retrieveWSChecked<ExperimentInfo>(wsName + WORKSPACE_POSTFIX);
-
-    Mantid::Kernel::DateAndTime start = ws->run().startTime();
-    Mantid::Kernel::DateAndTime end = ws->run().endTime();
-
     const std::vector<Property *> &logData = ws->run().getLogData();
+    const TimeSeriesProperty<bool> *runningLog = nullptr;
+    Property *runLog = nullptr;
+    const bool foundRunning = ws->run().hasProperty(RUNNING_LOG_NAME);
+    if (foundRunning) {
+      runLog = ws->run().getLogData(RUNNING_LOG_NAME);
+      runningLog = dynamic_cast<TimeSeriesProperty<bool> *>(runLog);
 
-    for (const auto prop : logData) {
+    } else {
+      Mantid::Kernel::Logger g_log("MuonAnalysisResultTableTab");
+      g_log.warning(
+          "No running log found. Filtering will not be applied to the data.\n");
+    }
+    for (const auto &prop : logData) {
       // Check if is a timeseries log
-      if (TimeSeriesProperty<double> *tspd =
+      if (TimeSeriesProperty<double> *log =
               dynamic_cast<TimeSeriesProperty<double> *>(prop)) {
-        QString logFile(QFileInfo(prop->name().c_str()).fileName());
-
-        double value(0.0);
-        int count(0);
-
-        Mantid::Kernel::DateAndTime logTime;
 
-        // iterate through all logs entries of a specific log
-        for (int k(0); k < tspd->size(); k++) {
-          // Get the log time for the specific entry
-          logTime = tspd->nthTime(k);
-
-          // If the entry was made during the run times
-          if ((logTime >= start) && (logTime <= end)) {
-            // add it to a total and increment the count (will be used to make
-            // average entry value during a run)
-            value += tspd->nthValue(k);
-            count++;
-          }
+        auto mylog = log->clone();
+        if (foundRunning) {
+          mylog->filterWith(runningLog);
         }
-
-        if (count != 0) {
-          // Find average
-          wsLogValues[logFile] = value / count;
+        QString logFile(QFileInfo(prop->name().c_str()).fileName());
+        auto time_ave = mylog->timeAverageValue(); // get the time average
+        if (time_ave != 0) {
+          // Return average
+          wsLogValues[logFile] = time_ave;
         }
       } else // Should be a non-timeseries one
       {
diff --git a/MantidQt/CustomInterfaces/src/Reflectometry/MeasurementItem.cpp b/MantidQt/CustomInterfaces/src/Reflectometry/MeasurementItem.cpp
index b777af5555cadd7a019cf5523a4840df07fc9f80..a9b14fa49e0727a1ce34549ae628c6cc59864a2e 100644
--- a/MantidQt/CustomInterfaces/src/Reflectometry/MeasurementItem.cpp
+++ b/MantidQt/CustomInterfaces/src/Reflectometry/MeasurementItem.cpp
@@ -13,13 +13,15 @@ namespace CustomInterfaces {
  * @param type
  * @param angle
  * @param run
+ * @param title
  */
 MeasurementItem::MeasurementItem(
     const MeasurementItem::IDType &measurementItemId,
     const MeasurementItem::IDType &subId, const std::string &label,
-    const std::string &type, const double angle, const std::string &run)
+    const std::string &type, const double angle, const std::string &run,
+    const std::string &title)
     : m_measurementItemId(measurementItemId), m_subId(subId), m_label(label),
-      m_type(type), m_angle(angle), m_run(run) {
+      m_type(type), m_angle(angle), m_run(run), m_title(title) {
 
   std::string accumulatedProblems;
   if (m_measurementItemId.empty()) {
@@ -45,7 +47,8 @@ MeasurementItem::MeasurementItem(const std::string &why)
 MeasurementItem::MeasurementItem(const MeasurementItem &other)
     : m_measurementItemId(other.m_measurementItemId), m_subId(other.m_subId),
       m_label(other.m_label), m_type(other.m_type), m_angle(other.m_angle),
-      m_run(other.m_run), m_whyUnuseable(other.m_whyUnuseable) {}
+      m_run(other.m_run), m_title(other.m_title),
+      m_whyUnuseable(other.m_whyUnuseable) {}
 
 /// Destructor
 MeasurementItem::~MeasurementItem() {}
@@ -75,6 +78,8 @@ double MeasurementItem::angle() const { return m_angle; }
 
 std::string MeasurementItem::run() const { return m_run; }
 
+std::string MeasurementItem::title() const { return m_title; }
+
 std::string MeasurementItem::angleStr() const {
   std::stringstream buffer;
   buffer << angle();
diff --git a/MantidQt/CustomInterfaces/src/Reflectometry/QtReflMainWindowView.cpp b/MantidQt/CustomInterfaces/src/Reflectometry/QtReflMainWindowView.cpp
index 3c082f951ecfa11ae093d168e07c4e4a6caf80b6..a70085ef8ca51d62d944e2fbeb7448954f490130 100644
--- a/MantidQt/CustomInterfaces/src/Reflectometry/QtReflMainWindowView.cpp
+++ b/MantidQt/CustomInterfaces/src/Reflectometry/QtReflMainWindowView.cpp
@@ -1,5 +1,6 @@
 #include "MantidQtCustomInterfaces/Reflectometry/QtReflMainWindowView.h"
 #include "MantidQtCustomInterfaces/Reflectometry/QtReflRunsTabView.h"
+#include "MantidQtCustomInterfaces/Reflectometry/QtReflSaveTabView.h"
 #include "MantidQtCustomInterfaces/Reflectometry/QtReflSettingsTabView.h"
 #include "MantidQtCustomInterfaces/Reflectometry/ReflMainWindowPresenter.h"
 
@@ -31,10 +32,11 @@ void QtReflMainWindowView::initLayout() {
   // Create the tabs
   auto runsPresenter = createRunsTab();
   auto settingsPresenter = createSettingsTab();
+  auto savePresenter = createSaveTab();
 
   // Create the presenter
-  m_presenter.reset(
-      new ReflMainWindowPresenter(this, runsPresenter, settingsPresenter));
+  m_presenter.reset(new ReflMainWindowPresenter(
+      this, runsPresenter, settingsPresenter, savePresenter));
 }
 
 /** Creates the 'Runs' tab and returns a pointer to its presenter
@@ -59,6 +61,17 @@ IReflSettingsTabPresenter *QtReflMainWindowView::createSettingsTab() {
   return settingsTab->getPresenter();
 }
 
+/** Creates the 'Save ASCII' tab and returns a pointer to its presenter
+* @return :: A pointer to the presenter managing the 'Save ASCII' tab
+*/
+IReflSaveTabPresenter *QtReflMainWindowView::createSaveTab() {
+
+  QtReflSaveTabView *saveTab = new QtReflSaveTabView(this);
+  m_ui.mainTab->addTab(saveTab, QString("Save ASCII"));
+
+  return saveTab->getPresenter();
+}
+
 /**
 Show an critical error dialog
 @param prompt : The prompt to appear on the dialog
diff --git a/MantidQt/CustomInterfaces/src/Reflectometry/QtReflRunsTabView.cpp b/MantidQt/CustomInterfaces/src/Reflectometry/QtReflRunsTabView.cpp
index a6601af6f8fcb7eca3065af343a641af04abda14..587aa09904076699e41d41f298d7c0fc63a58457 100644
--- a/MantidQt/CustomInterfaces/src/Reflectometry/QtReflRunsTabView.cpp
+++ b/MantidQt/CustomInterfaces/src/Reflectometry/QtReflRunsTabView.cpp
@@ -50,32 +50,54 @@ void QtReflRunsTabView::initLayout() {
   // Create the DataProcessor presenter
   ReflGenericDataProcessorPresenterFactory presenterFactory;
 
-  QDataProcessorWidget *qDataProcessorWidget = new QDataProcessorWidget(
+  QDataProcessorWidget *qDataProcessorWidget_1 = new QDataProcessorWidget(
       std::unique_ptr<DataProcessorPresenter>(presenterFactory.create()), this);
-  ui.layoutProcessPane->addWidget(qDataProcessorWidget);
+  ui.toolbox->addItem(qDataProcessorWidget_1, "Group 1");
+
+  QDataProcessorWidget *qDataProcessorWidget_2 = new QDataProcessorWidget(
+      std::unique_ptr<DataProcessorPresenter>(presenterFactory.create()), this);
+  ui.toolbox->addItem(qDataProcessorWidget_2, "Group 2");
+
+  std::vector<DataProcessorPresenter *> processingWidgets;
+  processingWidgets.push_back(qDataProcessorWidget_1->getPresenter());
+  processingWidgets.push_back(qDataProcessorWidget_2->getPresenter());
 
   // Create the presenter
   m_presenter = std::make_shared<ReflRunsTabPresenter>(
       this /* main view */,
       this /* Currently this concrete view is also responsible for prog reporting */,
-      qDataProcessorWidget->getPresenter() /* The data processor presenter */);
+      processingWidgets /* The data processor presenters */);
   m_algoRunner = boost::make_shared<MantidQt::API::AlgorithmRunner>(this);
 
   // Custom context menu for table
   connect(ui.tableSearchResults,
           SIGNAL(customContextMenuRequested(const QPoint &)), this,
           SLOT(showSearchContextMenu(const QPoint &)));
-  // Synchronize the two instrument selection widgets
+  // Synchronize the slit calculator
+  connect(ui.comboSearchInstrument, SIGNAL(currentIndexChanged(int)), this,
+          SLOT(instrumentChanged(int)));
+  // Selected group changed
+  connect(ui.toolbox, SIGNAL(currentChanged(int)), this, SLOT(groupChanged()));
+
+  // Synchronize the instrument selection widgets
+  // Processing table in group 1
   connect(ui.comboSearchInstrument, SIGNAL(currentIndexChanged(int)),
-          qDataProcessorWidget,
+          qDataProcessorWidget_1,
           SLOT(on_comboProcessInstrument_currentIndexChanged(int)));
-  connect(qDataProcessorWidget,
+  connect(qDataProcessorWidget_1,
           SIGNAL(comboProcessInstrument_currentIndexChanged(int)),
           ui.comboSearchInstrument, SLOT(setCurrentIndex(int)));
-  // Synchronize the slit calculator
-  connect(ui.comboSearchInstrument, SIGNAL(currentIndexChanged(int)), this,
+  connect(qDataProcessorWidget_1,
+          SIGNAL(comboProcessInstrument_currentIndexChanged(int)), this,
           SLOT(instrumentChanged(int)));
-  connect(qDataProcessorWidget,
+  // Processing table in group 2
+  connect(ui.comboSearchInstrument, SIGNAL(currentIndexChanged(int)),
+          qDataProcessorWidget_2,
+          SLOT(on_comboProcessInstrument_currentIndexChanged(int)));
+  connect(qDataProcessorWidget_2,
+          SIGNAL(comboProcessInstrument_currentIndexChanged(int)),
+          ui.comboSearchInstrument, SLOT(setCurrentIndex(int)));
+  connect(qDataProcessorWidget_2,
           SIGNAL(comboProcessInstrument_currentIndexChanged(int)), this,
           SLOT(instrumentChanged(int)));
 }
@@ -302,5 +324,19 @@ std::string QtReflRunsTabView::getTransferMethod() const {
   return ui.comboTransferMethod->currentText().toStdString();
 }
 
+/**
+* @return the selected group
+*/
+int QtReflRunsTabView::getSelectedGroup() const {
+  return ui.toolbox->currentIndex();
+}
+
+/** This is slot is triggered when the selected group changes.
+*
+*/
+void QtReflRunsTabView::groupChanged() {
+  m_presenter->notify(IReflRunsTabPresenter::GroupChangedFlag);
+}
+
 } // namespace CustomInterfaces
 } // namespace Mantid
diff --git a/MantidQt/CustomInterfaces/src/Reflectometry/QtReflSaveTabView.cpp b/MantidQt/CustomInterfaces/src/Reflectometry/QtReflSaveTabView.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..58d331b812a1695f5d88ddd61527233432d4b18d
--- /dev/null
+++ b/MantidQt/CustomInterfaces/src/Reflectometry/QtReflSaveTabView.cpp
@@ -0,0 +1,208 @@
+#include "MantidQtCustomInterfaces/Reflectometry/QtReflSaveTabView.h"
+#include "MantidQtCustomInterfaces/Reflectometry/ReflSaveTabPresenter.h"
+
+#include <boost/algorithm/string.hpp>
+
+namespace MantidQt {
+namespace CustomInterfaces {
+
+/** Constructor
+* @param parent :: The parent of this view
+*/
+QtReflSaveTabView::QtReflSaveTabView(QWidget *parent) : m_presenter() {
+
+  UNUSED_ARG(parent);
+  initLayout();
+}
+
+/** Destructor
+*/
+QtReflSaveTabView::~QtReflSaveTabView() {}
+
+/**
+Initialize the Interface
+*/
+void QtReflSaveTabView::initLayout() {
+  m_ui.setupUi(this);
+
+  connect(m_ui.refreshButton, SIGNAL(clicked()), this,
+          SLOT(populateListOfWorkspaces()));
+  connect(m_ui.saveButton, SIGNAL(clicked()), this, SLOT(saveWorkspaces()));
+  connect(m_ui.filterEdit, SIGNAL(textEdited(const QString &)), this,
+          SLOT(filterWorkspaceList()));
+  connect(m_ui.listOfWorkspaces, SIGNAL(itemDoubleClicked(QListWidgetItem *)),
+          this, SLOT(requestWorkspaceParams()));
+
+  m_presenter.reset(new ReflSaveTabPresenter(this));
+  populateListOfWorkspaces();
+  suggestSaveDir();
+}
+
+/** Returns the presenter managing this view
+* @return :: A pointer to the presenter
+*/
+IReflSaveTabPresenter *QtReflSaveTabView::getPresenter() const {
+
+  return m_presenter.get();
+}
+
+/** Returns the save path
+* @return :: The save path
+*/
+std::string QtReflSaveTabView::getSavePath() const {
+  return m_ui.savePathEdit->text().toStdString();
+}
+
+/** Sets the save path
+*/
+void QtReflSaveTabView::setSavePath(const std::string &path) const {
+  m_ui.savePathEdit->setText(QString::fromStdString(path));
+}
+
+/** Returns the file name prefix
+* @return :: The prefix
+*/
+std::string QtReflSaveTabView::getPrefix() const {
+  return m_ui.prefixEdit->text().toStdString();
+}
+
+/** Returns the workspace list filter
+* @return :: The filter
+*/
+std::string QtReflSaveTabView::getFilter() const {
+  return m_ui.filterEdit->text().toStdString();
+}
+
+/** Returns the regular expression check value
+* @return :: The regex check
+*/
+bool QtReflSaveTabView::getRegexCheck() const {
+  return m_ui.regexCheckBox->isChecked();
+}
+
+/** Returns the name of the currently selected workspace from the 'List of
+* workspaces' widget
+* @return :: item name
+*/
+std::string QtReflSaveTabView::getCurrentWorkspaceName() const {
+  return m_ui.listOfWorkspaces->currentItem()->text().toStdString();
+}
+
+/** Returns a list of names of currently selected workspaces
+* @return :: workspace names
+*/
+std::vector<std::string> QtReflSaveTabView::getSelectedWorkspaces() const {
+  std::vector<std::string> itemNames;
+  auto items = m_ui.listOfWorkspaces->selectedItems();
+  for (auto it = items.begin(); it != items.end(); it++) {
+    itemNames.push_back((*it)->text().toStdString());
+  }
+  return itemNames;
+}
+
+/** Returns a list of names of currently selected parameters
+* @return :: parameter names
+*/
+std::vector<std::string> QtReflSaveTabView::getSelectedParameters() const {
+  std::vector<std::string> paramNames;
+  auto items = m_ui.listOfLoggedParameters->selectedItems();
+  for (auto it = items.begin(); it != items.end(); it++) {
+    paramNames.push_back((*it)->text().toStdString());
+  }
+  return paramNames;
+}
+
+/** Returns the index of the selected file format
+* @return :: File format index
+*/
+int QtReflSaveTabView::getFileFormatIndex() const {
+  return m_ui.fileFormatComboBox->currentIndex();
+}
+
+/** Returns the title check value
+* @return :: The title check
+*/
+bool QtReflSaveTabView::getTitleCheck() const {
+  return m_ui.titleCheckBox->isChecked();
+}
+
+/** Returns the Q resolution check value
+* @return :: The Q resolution check
+*/
+bool QtReflSaveTabView::getQResolutionCheck() const {
+  return m_ui.qResolutionCheckBox->isChecked();
+}
+
+/** Returns the separator type
+* @return :: The separator
+*/
+std::string QtReflSaveTabView::getSeparator() const {
+  auto sep = m_ui.separatorButtonGroup->checkedButton()->text().toStdString();
+  boost::to_lower(sep); // lowercase
+  return sep;
+}
+
+/** Clear the 'List of workspaces' widget
+*/
+void QtReflSaveTabView::clearWorkspaceList() const {
+  m_ui.listOfWorkspaces->clear();
+}
+
+/** Clear the 'List of Logged Parameters' widget
+*/
+void QtReflSaveTabView::clearParametersList() const {
+  m_ui.listOfLoggedParameters->clear();
+}
+
+/** Set the 'List of workspaces' widget with workspace names
+* @param names :: The list of workspace names
+*/
+void QtReflSaveTabView::setWorkspaceList(
+    const std::vector<std::string> &names) const {
+  for (auto it = names.begin(); it != names.end(); it++) {
+    m_ui.listOfWorkspaces->addItem(QString::fromStdString(*it));
+  }
+}
+
+/** Set the 'List of logged parameters' widget with workspace run logs
+* @param logs :: The list of workspace run logs
+*/
+void QtReflSaveTabView::setParametersList(
+    const std::vector<std::string> &logs) const {
+  for (auto it = logs.begin(); it != logs.end(); it++) {
+    m_ui.listOfLoggedParameters->addItem(QString::fromStdString(*it));
+  }
+}
+
+/** Populate the 'List of workspaces' widget
+*/
+void QtReflSaveTabView::populateListOfWorkspaces() const {
+  m_presenter->notify(IReflSaveTabPresenter::populateWorkspaceListFlag);
+}
+
+/** Filter the 'List of workspaces' widget
+*/
+void QtReflSaveTabView::filterWorkspaceList() const {
+  m_presenter->notify(IReflSaveTabPresenter::filterWorkspaceListFlag);
+}
+
+/** Request for the parameters of a workspace
+*/
+void QtReflSaveTabView::requestWorkspaceParams() const {
+  m_presenter->notify(IReflSaveTabPresenter::workspaceParamsFlag);
+}
+
+/** Save selected workspaces
+*/
+void QtReflSaveTabView::saveWorkspaces() const {
+  m_presenter->notify(IReflSaveTabPresenter::saveWorkspacesFlag);
+}
+
+/** Suggest a save directory
+*/
+void QtReflSaveTabView::suggestSaveDir() const {
+  m_presenter->notify(IReflSaveTabPresenter::suggestSaveDirFlag);
+}
+
+} // namespace CustomInterfaces
+} // namespace Mantid
diff --git a/MantidQt/CustomInterfaces/src/Reflectometry/QtReflSettingsTabView.cpp b/MantidQt/CustomInterfaces/src/Reflectometry/QtReflSettingsTabView.cpp
index feb486bedeb29716e07f5e77be1a32b6758ad0f2..0dd9bf213f455ba0dfc0b4c508003888f531a37d 100644
--- a/MantidQt/CustomInterfaces/src/Reflectometry/QtReflSettingsTabView.cpp
+++ b/MantidQt/CustomInterfaces/src/Reflectometry/QtReflSettingsTabView.cpp
@@ -1,12 +1,10 @@
 #include "MantidQtCustomInterfaces/Reflectometry/QtReflSettingsTabView.h"
+#include "MantidQtCustomInterfaces/Reflectometry/QtReflSettingsView.h"
 #include "MantidQtCustomInterfaces/Reflectometry/ReflSettingsTabPresenter.h"
-#include "MantidQtMantidWidgets/HintingLineEdit.h"
 
 namespace MantidQt {
 namespace CustomInterfaces {
 
-using namespace MantidQt::MantidWidgets;
-
 //----------------------------------------------------------------------------------------------
 /** Constructor
 * @param parent :: [input] The parent of this widget
@@ -15,8 +13,6 @@ QtReflSettingsTabView::QtReflSettingsTabView(QWidget *parent) {
 
   UNUSED_ARG(parent);
   initLayout();
-
-  m_presenter.reset(new ReflSettingsTabPresenter(this));
 }
 
 //----------------------------------------------------------------------------------------------
@@ -25,15 +21,22 @@ QtReflSettingsTabView::QtReflSettingsTabView(QWidget *parent) {
 QtReflSettingsTabView::~QtReflSettingsTabView() {}
 
 /**
-Initialise the Interface
+Initialise the interface
 */
 void QtReflSettingsTabView::initLayout() {
   m_ui.setupUi(this);
 
-  connect(m_ui.getExpDefaultsButton, SIGNAL(clicked()), this,
-          SLOT(requestExpDefaults()));
-  connect(m_ui.getInstDefaultsButton, SIGNAL(clicked()), this,
-          SLOT(requestInstDefaults()));
+  QtReflSettingsView *settings_1 = new QtReflSettingsView(this);
+  m_ui.toolbox->addItem(settings_1, "Group 1");
+
+  QtReflSettingsView *settings_2 = new QtReflSettingsView(this);
+  m_ui.toolbox->addItem(settings_2, "Group 2");
+
+  std::vector<IReflSettingsPresenter *> presenters;
+  presenters.push_back(settings_1->getPresenter());
+  presenters.push_back(settings_2->getPresenter());
+
+  m_presenter.reset(new ReflSettingsTabPresenter(presenters));
 }
 
 /** Returns the presenter managing this view
@@ -44,254 +47,5 @@ IReflSettingsTabPresenter *QtReflSettingsTabView::getPresenter() const {
   return m_presenter.get();
 }
 
-/** This slot notifies the presenter to fill experiment settings with default
-* values.
-*/
-void QtReflSettingsTabView::requestExpDefaults() const {
-  m_presenter->notify(IReflSettingsTabPresenter::ExpDefaultsFlag);
-}
-
-/** This slot notifies the presenter to fill instrument settings with default
-* values.
-*/
-void QtReflSettingsTabView::requestInstDefaults() const {
-  m_presenter->notify(IReflSettingsTabPresenter::InstDefaultsFlag);
-}
-
-/* Sets default values for all experiment settings given a list of default
-* values.
-*/
-void QtReflSettingsTabView::setExpDefaults(
-    const std::vector<std::string> &defaults) const {
-
-  int amIndex =
-      m_ui.analysisModeComboBox->findText(QString::fromStdString(defaults[0]));
-  if (amIndex != -1)
-    m_ui.analysisModeComboBox->setCurrentIndex(amIndex);
-
-  int pcIndex =
-      m_ui.polCorrComboBox->findText(QString::fromStdString(defaults[1]));
-  if (pcIndex != -1)
-    m_ui.polCorrComboBox->setCurrentIndex(pcIndex);
-
-  m_ui.CRhoEdit->setText(QString::fromStdString(defaults[2]));
-  m_ui.CAlphaEdit->setText(QString::fromStdString(defaults[3]));
-  m_ui.CApEdit->setText(QString::fromStdString(defaults[4]));
-  m_ui.CPpEdit->setText(QString::fromStdString(defaults[5]));
-  m_ui.scaleFactorEdit->setText(QString::fromStdString(defaults[6]));
-}
-
-/* Sets default values for all instrument settings given a list of default
-* values.
-*/
-void QtReflSettingsTabView::setInstDefaults(
-    const std::vector<double> &defaults) const {
-
-  auto intMonCheckState = (defaults[0] != 0) ? Qt::Checked : Qt::Unchecked;
-  m_ui.intMonCheckBox->setCheckState(intMonCheckState);
-
-  m_ui.monIntMinEdit->setText(QString::number(defaults[1]));
-  m_ui.monIntMaxEdit->setText(QString::number(defaults[2]));
-  m_ui.monBgMinEdit->setText(QString::number(defaults[3]));
-  m_ui.monBgMaxEdit->setText(QString::number(defaults[4]));
-  m_ui.lamMinEdit->setText(QString::number(defaults[5]));
-  m_ui.lamMaxEdit->setText(QString::number(defaults[6]));
-  m_ui.I0MonIndexEdit->setText(QString::number(defaults[7]));
-}
-
-/* Sets the enabled status of polarisation corrections and parameters
-* @param enable :: [input] bool to enable options or not
-*/
-void QtReflSettingsTabView::setPolarisationOptionsEnabled(bool enable) const {
-  m_ui.polCorrComboBox->setEnabled(enable);
-  m_ui.CRhoEdit->setEnabled(enable);
-  m_ui.CAlphaEdit->setEnabled(enable);
-  m_ui.CApEdit->setEnabled(enable);
-  m_ui.CPpEdit->setEnabled(enable);
-
-  if (!enable) {
-    // Set polarisation corrections text to 'None' when disabled
-    int noneIndex = m_ui.polCorrComboBox->findText("None");
-    if (noneIndex != -1)
-      m_ui.polCorrComboBox->setCurrentIndex(noneIndex);
-    // Clear all parameters as well
-    m_ui.CRhoEdit->clear();
-    m_ui.CAlphaEdit->clear();
-    m_ui.CApEdit->clear();
-    m_ui.CPpEdit->clear();
-  }
-}
-
-/** Returns global options for 'Stitch1DMany'
-* @return :: Global options for 'Stitch1DMany'
-*/
-std::string QtReflSettingsTabView::getStitchOptions() const {
-
-  auto widget = m_ui.expSettingsLayout0->itemAtPosition(7, 1)->widget();
-  return static_cast<HintingLineEdit *>(widget)->text().toStdString();
-}
-
-/** Creates hints for 'Stitch1DMany'
-* @param hints :: Hints as a map
-*/
-void QtReflSettingsTabView::createStitchHints(
-    const std::map<std::string, std::string> &hints) {
-
-  m_ui.expSettingsLayout0->addWidget(new HintingLineEdit(this, hints), 7, 1, 1,
-                                     3);
-}
-
-/** Return selected analysis mode
-* @return :: selected analysis mode
-*/
-std::string QtReflSettingsTabView::getAnalysisMode() const {
-
-  return m_ui.analysisModeComboBox->currentText().toStdString();
-}
-
-/** Return direct beam
-* @return :: direct beam range
-*/
-std::string QtReflSettingsTabView::getDirectBeam() const {
-
-  return m_ui.directBeamEdit->text().toStdString();
-}
-
-/** Return selected transmission run(s)
-* @return :: selected transmission run(s)
-*/
-std::string QtReflSettingsTabView::getTransmissionRuns() const {
-
-  return m_ui.transmissionRunsEdit->text().toStdString();
-}
-
-/** Return selected polarisation corrections
-* @return :: selected polarisation corrections
-*/
-std::string QtReflSettingsTabView::getPolarisationCorrections() const {
-
-  return m_ui.polCorrComboBox->currentText().toStdString();
-}
-
-/** Return CRho
-* @return :: polarization correction CRho
-*/
-std::string QtReflSettingsTabView::getCRho() const {
-
-  return m_ui.CRhoEdit->text().toStdString();
-}
-
-/** Return CAlpha
-* @return :: polarization correction CAlpha
-*/
-std::string QtReflSettingsTabView::getCAlpha() const {
-
-  return m_ui.CAlphaEdit->text().toStdString();
-}
-
-/** Return CAp
-* @return :: polarization correction CAp
-*/
-std::string QtReflSettingsTabView::getCAp() const {
-
-  return m_ui.CApEdit->text().toStdString();
-}
-
-/** Return CPp
-* @return :: polarization correction CPp
-*/
-std::string QtReflSettingsTabView::getCPp() const {
-
-  return m_ui.CPpEdit->text().toStdString();
-}
-
-/** Return momentum transfer limits
-* @return :: momentum transfer limits
-*/
-std::string QtReflSettingsTabView::getMomentumTransferStep() const {
-
-  return m_ui.momentumTransferStepEdit->text().toStdString();
-}
-
-/** Return scale factor
-* @return :: scale factor
-*/
-std::string QtReflSettingsTabView::getScaleFactor() const {
-
-  return m_ui.scaleFactorEdit->text().toStdString();
-}
-
-/** Return integrated monitors option
-* @return :: integrated monitors check
-*/
-std::string QtReflSettingsTabView::getIntMonCheck() const {
-
-  return m_ui.intMonCheckBox->isChecked() ? "1" : "0";
-}
-
-/** Return monitor integral wavelength min
-* @return :: monitor integral min
-*/
-std::string QtReflSettingsTabView::getMonitorIntegralMin() const {
-
-  return m_ui.monIntMinEdit->text().toStdString();
-}
-
-/** Return monitor integral wavelength max
-* @return :: monitor integral max
-*/
-std::string QtReflSettingsTabView::getMonitorIntegralMax() const {
-
-  return m_ui.monIntMaxEdit->text().toStdString();
-}
-
-/** Return monitor background wavelength min
-* @return :: monitor background min
-*/
-std::string QtReflSettingsTabView::getMonitorBackgroundMin() const {
-
-  return m_ui.monBgMinEdit->text().toStdString();
-}
-
-/** Return monitor background wavelength max
-* @return :: monitor background max
-*/
-std::string QtReflSettingsTabView::getMonitorBackgroundMax() const {
-
-  return m_ui.monBgMaxEdit->text().toStdString();
-}
-
-/** Return wavelength min
-* @return :: lambda min
-*/
-std::string QtReflSettingsTabView::getLambdaMin() const {
-
-  return m_ui.lamMinEdit->text().toStdString();
-}
-
-/** Return wavelength max
-* @return :: lambda max
-*/
-std::string QtReflSettingsTabView::getLambdaMax() const {
-
-  return m_ui.lamMaxEdit->text().toStdString();
-}
-
-/** Return I0MonitorIndex
-* @return :: I0MonitorIndex
-*/
-std::string QtReflSettingsTabView::getI0MonitorIndex() const {
-
-  return m_ui.I0MonIndexEdit->text().toStdString();
-}
-
-/** Return processing instructions
-* @return :: processing instructions
-*/
-std::string QtReflSettingsTabView::getProcessingInstructions() const {
-
-  return m_ui.procInstEdit->text().toStdString();
-}
-
 } // namespace CustomInterfaces
 } // namespace Mantid
diff --git a/MantidQt/CustomInterfaces/src/Reflectometry/QtReflSettingsView.cpp b/MantidQt/CustomInterfaces/src/Reflectometry/QtReflSettingsView.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f6511d4e0660ae7f4c336e66477c31f8a63ab6e5
--- /dev/null
+++ b/MantidQt/CustomInterfaces/src/Reflectometry/QtReflSettingsView.cpp
@@ -0,0 +1,297 @@
+#include "MantidQtCustomInterfaces/Reflectometry/QtReflSettingsView.h"
+#include "MantidQtCustomInterfaces/Reflectometry/ReflSettingsPresenter.h"
+#include "MantidQtMantidWidgets/HintingLineEdit.h"
+
+namespace MantidQt {
+namespace CustomInterfaces {
+
+using namespace MantidQt::MantidWidgets;
+
+//----------------------------------------------------------------------------------------------
+/** Constructor
+* @param parent :: [input] The parent of this widget
+*/
+QtReflSettingsView::QtReflSettingsView(QWidget *parent) {
+
+  UNUSED_ARG(parent);
+  initLayout();
+
+  m_presenter.reset(new ReflSettingsPresenter(this));
+}
+
+//----------------------------------------------------------------------------------------------
+/** Destructor
+*/
+QtReflSettingsView::~QtReflSettingsView() {}
+
+/**
+Initialise the Interface
+*/
+void QtReflSettingsView::initLayout() {
+  m_ui.setupUi(this);
+
+  connect(m_ui.getExpDefaultsButton, SIGNAL(clicked()), this,
+          SLOT(requestExpDefaults()));
+  connect(m_ui.getInstDefaultsButton, SIGNAL(clicked()), this,
+          SLOT(requestInstDefaults()));
+}
+
+/** Returns the presenter managing this view
+* @return :: A pointer to the presenter
+*/
+IReflSettingsPresenter *QtReflSettingsView::getPresenter() const {
+
+  return m_presenter.get();
+}
+
+/** This slot notifies the presenter to fill experiment settings with default
+* values.
+*/
+void QtReflSettingsView::requestExpDefaults() const {
+  m_presenter->notify(IReflSettingsPresenter::ExpDefaultsFlag);
+}
+
+/** This slot notifies the presenter to fill instrument settings with default
+* values.
+*/
+void QtReflSettingsView::requestInstDefaults() const {
+  m_presenter->notify(IReflSettingsPresenter::InstDefaultsFlag);
+}
+
+/* Sets default values for all experiment settings given a list of default
+* values.
+*/
+void QtReflSettingsView::setExpDefaults(
+    const std::vector<std::string> &defaults) const {
+
+  int amIndex =
+      m_ui.analysisModeComboBox->findText(QString::fromStdString(defaults[0]));
+  if (amIndex != -1)
+    m_ui.analysisModeComboBox->setCurrentIndex(amIndex);
+
+  int pcIndex =
+      m_ui.polCorrComboBox->findText(QString::fromStdString(defaults[1]));
+  if (pcIndex != -1)
+    m_ui.polCorrComboBox->setCurrentIndex(pcIndex);
+
+  m_ui.CRhoEdit->setText(QString::fromStdString(defaults[2]));
+  m_ui.CAlphaEdit->setText(QString::fromStdString(defaults[3]));
+  m_ui.CApEdit->setText(QString::fromStdString(defaults[4]));
+  m_ui.CPpEdit->setText(QString::fromStdString(defaults[5]));
+  m_ui.scaleFactorEdit->setText(QString::fromStdString(defaults[6]));
+}
+
+/* Sets default values for all instrument settings given a list of default
+* values.
+*/
+void QtReflSettingsView::setInstDefaults(
+    const std::vector<double> &defaults) const {
+
+  auto intMonCheckState = (defaults[0] != 0) ? Qt::Checked : Qt::Unchecked;
+  m_ui.intMonCheckBox->setCheckState(intMonCheckState);
+
+  m_ui.monIntMinEdit->setText(QString::number(defaults[1]));
+  m_ui.monIntMaxEdit->setText(QString::number(defaults[2]));
+  m_ui.monBgMinEdit->setText(QString::number(defaults[3]));
+  m_ui.monBgMaxEdit->setText(QString::number(defaults[4]));
+  m_ui.lamMinEdit->setText(QString::number(defaults[5]));
+  m_ui.lamMaxEdit->setText(QString::number(defaults[6]));
+  m_ui.I0MonIndexEdit->setText(QString::number(defaults[7]));
+}
+
+/* Sets the enabled status of polarisation corrections and parameters
+* @param enable :: [input] bool to enable options or not
+*/
+void QtReflSettingsView::setPolarisationOptionsEnabled(bool enable) const {
+  m_ui.polCorrComboBox->setEnabled(enable);
+  m_ui.CRhoEdit->setEnabled(enable);
+  m_ui.CAlphaEdit->setEnabled(enable);
+  m_ui.CApEdit->setEnabled(enable);
+  m_ui.CPpEdit->setEnabled(enable);
+
+  if (!enable) {
+    // Set polarisation corrections text to 'None' when disabled
+    int noneIndex = m_ui.polCorrComboBox->findText("None");
+    if (noneIndex != -1)
+      m_ui.polCorrComboBox->setCurrentIndex(noneIndex);
+    // Clear all parameters as well
+    m_ui.CRhoEdit->clear();
+    m_ui.CAlphaEdit->clear();
+    m_ui.CApEdit->clear();
+    m_ui.CPpEdit->clear();
+  }
+}
+
+/** Returns global options for 'Stitch1DMany'
+* @return :: Global options for 'Stitch1DMany'
+*/
+std::string QtReflSettingsView::getStitchOptions() const {
+
+  auto widget = m_ui.expSettingsLayout0->itemAtPosition(7, 1)->widget();
+  return static_cast<HintingLineEdit *>(widget)->text().toStdString();
+}
+
+/** Creates hints for 'Stitch1DMany'
+* @param hints :: Hints as a map
+*/
+void QtReflSettingsView::createStitchHints(
+    const std::map<std::string, std::string> &hints) {
+
+  m_ui.expSettingsLayout0->addWidget(new HintingLineEdit(this, hints), 7, 1, 1,
+                                     3);
+}
+
+/** Return selected analysis mode
+* @return :: selected analysis mode
+*/
+std::string QtReflSettingsView::getAnalysisMode() const {
+
+  return m_ui.analysisModeComboBox->currentText().toStdString();
+}
+
+/** Return direct beam
+* @return :: direct beam range
+*/
+std::string QtReflSettingsView::getDirectBeam() const {
+
+  return m_ui.directBeamEdit->text().toStdString();
+}
+
+/** Return selected transmission run(s)
+* @return :: selected transmission run(s)
+*/
+std::string QtReflSettingsView::getTransmissionRuns() const {
+
+  return m_ui.transmissionRunsEdit->text().toStdString();
+}
+
+/** Return selected polarisation corrections
+* @return :: selected polarisation corrections
+*/
+std::string QtReflSettingsView::getPolarisationCorrections() const {
+
+  return m_ui.polCorrComboBox->currentText().toStdString();
+}
+
+/** Return CRho
+* @return :: polarization correction CRho
+*/
+std::string QtReflSettingsView::getCRho() const {
+
+  return m_ui.CRhoEdit->text().toStdString();
+}
+
+/** Return CAlpha
+* @return :: polarization correction CAlpha
+*/
+std::string QtReflSettingsView::getCAlpha() const {
+
+  return m_ui.CAlphaEdit->text().toStdString();
+}
+
+/** Return CAp
+* @return :: polarization correction CAp
+*/
+std::string QtReflSettingsView::getCAp() const {
+
+  return m_ui.CApEdit->text().toStdString();
+}
+
+/** Return CPp
+* @return :: polarization correction CPp
+*/
+std::string QtReflSettingsView::getCPp() const {
+
+  return m_ui.CPpEdit->text().toStdString();
+}
+
+/** Return momentum transfer limits
+* @return :: momentum transfer limits
+*/
+std::string QtReflSettingsView::getMomentumTransferStep() const {
+
+  return m_ui.momentumTransferStepEdit->text().toStdString();
+}
+
+/** Return scale factor
+* @return :: scale factor
+*/
+std::string QtReflSettingsView::getScaleFactor() const {
+
+  return m_ui.scaleFactorEdit->text().toStdString();
+}
+
+/** Return integrated monitors option
+* @return :: integrated monitors check
+*/
+std::string QtReflSettingsView::getIntMonCheck() const {
+
+  return m_ui.intMonCheckBox->isChecked() ? "1" : "0";
+}
+
+/** Return monitor integral wavelength min
+* @return :: monitor integral min
+*/
+std::string QtReflSettingsView::getMonitorIntegralMin() const {
+
+  return m_ui.monIntMinEdit->text().toStdString();
+}
+
+/** Return monitor integral wavelength max
+* @return :: monitor integral max
+*/
+std::string QtReflSettingsView::getMonitorIntegralMax() const {
+
+  return m_ui.monIntMaxEdit->text().toStdString();
+}
+
+/** Return monitor background wavelength min
+* @return :: monitor background min
+*/
+std::string QtReflSettingsView::getMonitorBackgroundMin() const {
+
+  return m_ui.monBgMinEdit->text().toStdString();
+}
+
+/** Return monitor background wavelength max
+* @return :: monitor background max
+*/
+std::string QtReflSettingsView::getMonitorBackgroundMax() const {
+
+  return m_ui.monBgMaxEdit->text().toStdString();
+}
+
+/** Return wavelength min
+* @return :: lambda min
+*/
+std::string QtReflSettingsView::getLambdaMin() const {
+
+  return m_ui.lamMinEdit->text().toStdString();
+}
+
+/** Return wavelength max
+* @return :: lambda max
+*/
+std::string QtReflSettingsView::getLambdaMax() const {
+
+  return m_ui.lamMaxEdit->text().toStdString();
+}
+
+/** Return I0MonitorIndex
+* @return :: I0MonitorIndex
+*/
+std::string QtReflSettingsView::getI0MonitorIndex() const {
+
+  return m_ui.I0MonIndexEdit->text().toStdString();
+}
+
+/** Return processing instructions
+* @return :: processing instructions
+*/
+std::string QtReflSettingsView::getProcessingInstructions() const {
+
+  return m_ui.procInstEdit->text().toStdString();
+}
+
+} // namespace CustomInterfaces
+} // namespace Mantid
diff --git a/MantidQt/CustomInterfaces/src/Reflectometry/ReflGenericDataProcessorPresenterFactory.cpp b/MantidQt/CustomInterfaces/src/Reflectometry/ReflGenericDataProcessorPresenterFactory.cpp
index 0b6d3a2f61b2a7bd463ad39dbe9106a4dea06991..28e4cd55933304b3b9f18bbffc3ca0f850e79fa6 100644
--- a/MantidQt/CustomInterfaces/src/Reflectometry/ReflGenericDataProcessorPresenterFactory.cpp
+++ b/MantidQt/CustomInterfaces/src/Reflectometry/ReflGenericDataProcessorPresenterFactory.cpp
@@ -102,8 +102,15 @@ ReflGenericDataProcessorPresenterFactory::create() {
       "Stitch1DMany", "IvsQ_",
       std::set<std::string>{"InputWorkspaces", "OutputWorkspace"});
 
+  // Post-processing instructions linking column names to properties of the
+  // post-processing algorithm
+  // Key is column name
+  // Value is property name of the post-processing algorithm
+  std::map<std::string, std::string> postprocessMap = {{"dQ/Q", "Params"}};
+
   return Mantid::Kernel::make_unique<GenericDataProcessorPresenter>(
-      whitelist, preprocessMap, processor, postprocessor, "LoadISISNexus");
+      whitelist, preprocessMap, processor, postprocessor, postprocessMap,
+      "LoadISISNexus");
 }
 }
 }
diff --git a/MantidQt/CustomInterfaces/src/Reflectometry/ReflLegacyTransferStrategy.cpp b/MantidQt/CustomInterfaces/src/Reflectometry/ReflLegacyTransferStrategy.cpp
index 015ff49e579f544f9ee1cf900f9ea6e9a195eb60..e6f10cce1e332e3a79735c7857cb1754c5dd68e5 100644
--- a/MantidQt/CustomInterfaces/src/Reflectometry/ReflLegacyTransferStrategy.cpp
+++ b/MantidQt/CustomInterfaces/src/Reflectometry/ReflLegacyTransferStrategy.cpp
@@ -20,8 +20,6 @@ TransferResults ReflLegacyTransferStrategy::transferRuns(
 
   // maps descriptions to runs. Multiple runs are joined with '+'
   std::map<std::string, std::string> runsByDesc;
-  // Counter used to feed fresh group ids
-  int nextGroupId = 0;
   // maps a description to a group. If descriptions only differ by theta,
   // they'll share a group
   std::map<std::string, std::string> groupsByDesc;
@@ -61,7 +59,7 @@ TransferResults ReflLegacyTransferStrategy::transferRuns(
     // If there isn't a group for this description (ignoring differences in
     // theta) yet, make one
     if (groupsByDesc[cleanDesc].empty())
-      groupsByDesc[cleanDesc] = boost::lexical_cast<std::string>(nextGroupId++);
+      groupsByDesc[cleanDesc] = desc.substr(0, desc.find("th") - 1);
 
     // Assign this description to the group it belongs to
     groupsByDesc[desc] = groupsByDesc[cleanDesc];
diff --git a/MantidQt/CustomInterfaces/src/Reflectometry/ReflMainWindowPresenter.cpp b/MantidQt/CustomInterfaces/src/Reflectometry/ReflMainWindowPresenter.cpp
index 91f04f6aba81dfe0bb1ecf63208a1161a4b4f3ad..b7568006bfce6a287534efd7b216205eaf365b09 100644
--- a/MantidQt/CustomInterfaces/src/Reflectometry/ReflMainWindowPresenter.cpp
+++ b/MantidQt/CustomInterfaces/src/Reflectometry/ReflMainWindowPresenter.cpp
@@ -2,6 +2,7 @@
 #include "MantidQtCustomInterfaces/Reflectometry/IReflMainWindowView.h"
 #include "MantidQtCustomInterfaces/Reflectometry/IReflRunsTabPresenter.h"
 #include "MantidQtCustomInterfaces/Reflectometry/IReflSettingsTabPresenter.h"
+#include "MantidQtCustomInterfaces/Reflectometry/IReflSaveTabPresenter.h"
 
 namespace MantidQt {
 namespace CustomInterfaces {
@@ -10,16 +11,19 @@ namespace CustomInterfaces {
 * @param view :: [input] The view we are managing
 * @param runsPresenter :: [input] A pointer to the 'Runs' tab presenter
 * @param settingsPresenter :: [input] A pointer to the 'Settings' tab presenter
+* @param savePresenter :: [input] A pointer to the 'Save ASCII' tab presenter
 */
 ReflMainWindowPresenter::ReflMainWindowPresenter(
     IReflMainWindowView *view, IReflRunsTabPresenter *runsPresenter,
-    IReflSettingsTabPresenter *settingsPresenter)
+    IReflSettingsTabPresenter *settingsPresenter,
+    IReflSaveTabPresenter *savePresenter)
     : m_view(view), m_runsPresenter(runsPresenter),
-      m_settingsPresenter(settingsPresenter) {
+      m_settingsPresenter(settingsPresenter), m_savePresenter(savePresenter) {
 
   // Tell the tab presenters that this is going to be the main presenter
   m_runsPresenter->acceptMainPresenter(this);
-  m_settingsPresenter->acceptMainPresenter(this);
+  m_savePresenter->acceptMainPresenter(this);
+  // Settings tab does not need a main presenter
 
   // Trigger the setting of the current instrument name in settings tab
   m_runsPresenter->notify(IReflRunsTabPresenter::InstrumentChangedFlag);
@@ -30,35 +34,44 @@ ReflMainWindowPresenter::ReflMainWindowPresenter(
 ReflMainWindowPresenter::~ReflMainWindowPresenter() {}
 
 /** Returns global options for 'CreateTransmissionWorkspaceAuto'
+*
+* @param group :: Index of the group in 'Settings' tab from which to get the
+*options
 * @return :: Global options for 'CreateTransmissionWorkspaceAuto'
 */
-std::string ReflMainWindowPresenter::getTransmissionOptions() const {
+std::string ReflMainWindowPresenter::getTransmissionOptions(int group) const {
 
   checkPtrValid(m_settingsPresenter);
 
-  return m_settingsPresenter->getTransmissionOptions();
+  return m_settingsPresenter->getTransmissionOptions(group);
 }
 
 /** Returns global processing options
+*
+* @param group :: Index of the group in 'Settings' tab from which to get the
+*options
 * @return :: Global processing options
 */
-std::string ReflMainWindowPresenter::getReductionOptions() const {
+std::string ReflMainWindowPresenter::getReductionOptions(int group) const {
 
   checkPtrValid(m_settingsPresenter);
 
   // Request global processing options to 'Settings' presenter
-  return m_settingsPresenter->getReductionOptions();
+  return m_settingsPresenter->getReductionOptions(group);
 }
 
 /** Returns global post-processing options
+*
+* @param group :: Index of the group in 'Settings' tab from which to get the
+*options
 * @return :: Global post-processing options
 */
-std::string ReflMainWindowPresenter::getStitchOptions() const {
+std::string ReflMainWindowPresenter::getStitchOptions(int group) const {
 
   checkPtrValid(m_settingsPresenter);
 
   // Request global post-processing options to 'Settings' presenter
-  return m_settingsPresenter->getStitchOptions();
+  return m_settingsPresenter->getStitchOptions(group);
 }
 
 /**
diff --git a/MantidQt/CustomInterfaces/src/Reflectometry/ReflMeasureTransferStrategy.cpp b/MantidQt/CustomInterfaces/src/Reflectometry/ReflMeasureTransferStrategy.cpp
index 4d6966ccbc6db49aa89e5caea3a1fe7477ca92cd..c0eea69281402814de1aa7d57a570d33b97b327e 100644
--- a/MantidQt/CustomInterfaces/src/Reflectometry/ReflMeasureTransferStrategy.cpp
+++ b/MantidQt/CustomInterfaces/src/Reflectometry/ReflMeasureTransferStrategy.cpp
@@ -95,10 +95,19 @@ MantidQt::CustomInterfaces::ReflMeasureTransferStrategy::transferRuns(
   for (auto group = mapOfMeasurements.begin(); group != mapOfMeasurements.end();
        ++group) {
 
+    std::string groupName;
+
     // Map keyed by subId to index of exisiting subid written.
     std::map<std::string, size_t> subIdMap;
     for (size_t i = 0; i < group->second.size(); ++i) {
       const MeasurementItem &measurementItem = group->second[i];
+
+      if (i == 0) {
+        std::string title = measurementItem.title();
+        groupName = std::to_string(nextGroupId) + " - " +
+                    title.substr(0, title.find(":th"));
+      }
+
       if (subIdMap.find(measurementItem.subId()) != subIdMap.end()) {
         // We already have that subid.
         const size_t rowIndex = subIdMap[measurementItem.subId()];
@@ -112,9 +121,7 @@ MantidQt::CustomInterfaces::ReflMeasureTransferStrategy::transferRuns(
         std::map<std::string, std::string> row;
         row[ReflTableSchema::RUNS] = measurementItem.run();
         row[ReflTableSchema::ANGLE] = measurementItem.angleStr();
-        std::stringstream buffer;
-        buffer << nextGroupId;
-        row[ReflTableSchema::GROUP] = buffer.str();
+        row[ReflTableSchema::GROUP] = groupName;
         // run was successful so add it to 'runs'
         results.addTransferRow(row);
         // get successful transfers to get size for subIdMap
diff --git a/MantidQt/CustomInterfaces/src/Reflectometry/ReflNexusMeasurementItemSource.cpp b/MantidQt/CustomInterfaces/src/Reflectometry/ReflNexusMeasurementItemSource.cpp
index 25787d49a8eccdd780ef7c2924dcc1a94d282010..e185395fa11461b875e2f4cf88999a3e9c869ce7 100644
--- a/MantidQt/CustomInterfaces/src/Reflectometry/ReflNexusMeasurementItemSource.cpp
+++ b/MantidQt/CustomInterfaces/src/Reflectometry/ReflNexusMeasurementItemSource.cpp
@@ -77,6 +77,12 @@ ReflNexusMeasurementItemSource::obtain(const std::string &definedPath,
         runNumber = match[0];
       }
     }
+    std::string runTitle;
+    try {
+      runTitle = run.getPropertyValueAsType<std::string>("run_title");
+    } catch (Exception::NotFoundError &) {
+      // OK, runTitle will be empty
+    }
 
     double theta = -1.0;
     try {
@@ -90,7 +96,7 @@ ReflNexusMeasurementItemSource::obtain(const std::string &definedPath,
 
     return MeasurementItem(measurementItemId, measurementItemSubId,
                            measurementItemLabel, measurementItemType, theta,
-                           runNumber);
+                           runNumber, runTitle);
 
   } catch (std::invalid_argument &ex) {
     std::stringstream buffer;
diff --git a/MantidQt/CustomInterfaces/src/Reflectometry/ReflRunsTabPresenter.cpp b/MantidQt/CustomInterfaces/src/Reflectometry/ReflRunsTabPresenter.cpp
index 1c0addb7f876cff44388053c50847e192a662fd8..9a2b9136106c95d3dc19b7050b8cac1df5adf2b5 100644
--- a/MantidQt/CustomInterfaces/src/Reflectometry/ReflRunsTabPresenter.cpp
+++ b/MantidQt/CustomInterfaces/src/Reflectometry/ReflRunsTabPresenter.cpp
@@ -34,21 +34,22 @@ namespace CustomInterfaces {
 /** Constructor
 * @param mainView :: [input] The view we're managing
 * @param progressableView :: [input] The view reporting progress
-* @param tablePresenter :: [input] The data processor presenter
+* @param tablePresenters :: [input] The data processor presenters
 * @param searcher :: [input] The search implementation
 */
 ReflRunsTabPresenter::ReflRunsTabPresenter(
     IReflRunsTabView *mainView, ProgressableView *progressableView,
-    DataProcessorPresenter *tablePresenter,
+    std::vector<DataProcessorPresenter *> tablePresenters,
     boost::shared_ptr<IReflSearcher> searcher)
     : m_view(mainView), m_progressView(progressableView),
-      m_tablePresenter(tablePresenter), m_mainPresenter(),
+      m_tablePresenters(tablePresenters), m_mainPresenter(),
       m_searcher(searcher) {
 
   // Register this presenter as the workspace receiver
-  // When doing so, the inner presenter will notify this
+  // When doing so, the inner presenters will notify this
   // presenter with the list of commands
-  m_tablePresenter->accept(this);
+  for (const auto &presenter : m_tablePresenters)
+    presenter->accept(this);
 
   // If we don't have a searcher yet, use ReflCatalogSearcher
   if (!m_searcher)
@@ -60,6 +61,9 @@ ReflRunsTabPresenter::ReflRunsTabPresenter(
   methods.insert(MeasureTransferMethod);
   m_view->setTransferMethods(methods);
 
+  // Set current transfer method
+  m_currentTransferMethod = m_view->getTransferMethod();
+
   // Set up the instrument selectors
   std::vector<std::string> instruments;
   instruments.emplace_back("INTER");
@@ -75,10 +79,12 @@ ReflRunsTabPresenter::ReflRunsTabPresenter(
   if (std::find(instruments.begin(), instruments.end(), defaultInst) !=
       instruments.end()) {
     m_view->setInstrumentList(instruments, defaultInst);
-    m_tablePresenter->setInstrumentList(instruments, defaultInst);
+    for (const auto &presenter : m_tablePresenters)
+      presenter->setInstrumentList(instruments, defaultInst);
   } else {
     m_view->setInstrumentList(instruments, "INTER");
-    m_tablePresenter->setInstrumentList(instruments, "INTER");
+    for (const auto &presenter : m_tablePresenters)
+      presenter->setInstrumentList(instruments, "INTER");
   }
 }
 
@@ -113,6 +119,9 @@ void ReflRunsTabPresenter::notify(IReflRunsTabPresenter::Flag flag) {
   case IReflRunsTabPresenter::InstrumentChangedFlag:
     m_mainPresenter->setInstrumentName(m_view->getSearchInstrument());
     break;
+  case IReflRunsTabPresenter::GroupChangedFlag:
+    pushCommands();
+    break;
   }
   // Not having a 'default' case is deliberate. gcc issues a warning if there's
   // a flag we aren't handling.
@@ -125,7 +134,8 @@ void ReflRunsTabPresenter::pushCommands() {
 
   // The expected number of commands
   const size_t nCommands = 27;
-  auto commands = m_tablePresenter->publishCommands();
+  auto commands =
+      m_tablePresenters.at(m_view->getSelectedGroup())->publishCommands();
   if (commands.size() != nCommands) {
     throw std::runtime_error("Invalid list of commands");
   }
@@ -197,6 +207,7 @@ void ReflRunsTabPresenter::search() {
 void ReflRunsTabPresenter::populateSearch(IAlgorithm_sptr searchAlg) {
   if (searchAlg->isExecuted()) {
     ITableWorkspace_sptr results = searchAlg->getProperty("OutputWorkspace");
+    m_currentTransferMethod = m_view->getTransferMethod();
     m_searchModel = ReflSearchModel_sptr(new ReflSearchModel(
         *getTransferStrategy(), results, m_view->getSearchInstrument()));
     m_view->showSearch(m_searchModel);
@@ -211,8 +222,20 @@ void ReflRunsTabPresenter::transfer() {
   SearchResultMap runs;
   auto selectedRows = m_view->getSelectedSearchRows();
 
-  // Do not begin transfer if nothing is selected
+  // Do not begin transfer if nothing is selected or if the transfer method does
+  // not match the one used for populating search
   if (selectedRows.size() == 0) {
+    m_mainPresenter->giveUserCritical(
+        "Error: Please select at least one run to transfer.",
+        "No runs selected");
+    return;
+  } else if (m_currentTransferMethod != m_view->getTransferMethod()) {
+    m_mainPresenter->giveUserCritical(
+        "Error: Method selected for transferring runs (" +
+            m_view->getTransferMethod() +
+            ") must match the method used for searching runs (" +
+            m_currentTransferMethod + ").",
+        "Transfer method mismatch");
     return;
   }
 
@@ -274,7 +297,8 @@ void ReflRunsTabPresenter::transfer() {
     }
   }
 
-  m_tablePresenter->transfer(results.getTransferRuns());
+  m_tablePresenters.at(m_view->getSelectedGroup())
+      ->transfer(results.getTransferRuns());
 }
 
 /**
@@ -284,9 +308,8 @@ void ReflRunsTabPresenter::transfer() {
 */
 std::unique_ptr<ReflTransferStrategy>
 ReflRunsTabPresenter::getTransferStrategy() {
-  const std::string currentMethod = m_view->getTransferMethod();
   std::unique_ptr<ReflTransferStrategy> rtnStrategy;
-  if (currentMethod == MeasureTransferMethod) {
+  if (m_currentTransferMethod == MeasureTransferMethod) {
 
     // We need catalog info overrides from the user-based config service
     std::unique_ptr<CatalogConfigService> catConfigService(
@@ -306,12 +329,12 @@ ReflRunsTabPresenter::getTransferStrategy() {
     rtnStrategy = Mantid::Kernel::make_unique<ReflMeasureTransferStrategy>(
         std::move(catInfo), std::move(source));
     return rtnStrategy;
-  } else if (currentMethod == LegacyTransferMethod) {
+  } else if (m_currentTransferMethod == LegacyTransferMethod) {
     rtnStrategy = make_unique<ReflLegacyTransferStrategy>();
     return rtnStrategy;
   } else {
     throw std::runtime_error("Unknown tranfer method selected: " +
-                             currentMethod);
+                             m_currentTransferMethod);
   }
 }
 
@@ -337,7 +360,8 @@ std::map<std::string, std::string>
 ReflRunsTabPresenter::getPreprocessingOptions() const {
 
   std::map<std::string, std::string> options;
-  options["Transmission Run(s)"] = m_mainPresenter->getTransmissionOptions();
+  options["Transmission Run(s)"] =
+      m_mainPresenter->getTransmissionOptions(m_view->getSelectedGroup());
 
   return options;
 }
@@ -347,7 +371,7 @@ ReflRunsTabPresenter::getPreprocessingOptions() const {
 * @return :: Global pre-processing options
 */
 std::string ReflRunsTabPresenter::getProcessingOptions() const {
-  return m_mainPresenter->getReductionOptions();
+  return m_mainPresenter->getReductionOptions(m_view->getSelectedGroup());
 }
 
 /** Requests global pre-processing options. Options are supplied by the main
@@ -355,7 +379,7 @@ std::string ReflRunsTabPresenter::getProcessingOptions() const {
 * @return :: Global pre-processing options
 */
 std::string ReflRunsTabPresenter::getPostprocessingOptions() const {
-  return m_mainPresenter->getStitchOptions();
+  return m_mainPresenter->getStitchOptions(m_view->getSelectedGroup());
 }
 
 /**
diff --git a/MantidQt/CustomInterfaces/src/Reflectometry/ReflSaveTabPresenter.cpp b/MantidQt/CustomInterfaces/src/Reflectometry/ReflSaveTabPresenter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..fd99e3a301765a566506b3cdef1aea8ce60479b3
--- /dev/null
+++ b/MantidQt/CustomInterfaces/src/Reflectometry/ReflSaveTabPresenter.cpp
@@ -0,0 +1,211 @@
+#include "MantidQtCustomInterfaces/Reflectometry/ReflSaveTabPresenter.h"
+#include "MantidQtCustomInterfaces/Reflectometry/IReflSaveTabView.h"
+#include "MantidQtCustomInterfaces/Reflectometry/IReflMainWindowPresenter.h"
+#include "MantidKernel/ConfigService.h"
+#include "MantidAPI/WorkspaceGroup.h"
+#include "MantidAPI/MatrixWorkspace.h"
+#include "MantidAPI/FrameworkManager.h"
+#include "MantidAPI/AlgorithmManager.h"
+#include "MantidAPI/Run.h"
+#include "Poco/File.h"
+#include "Poco/Path.h"
+
+#include <boost/regex.hpp>
+
+namespace MantidQt {
+namespace CustomInterfaces {
+
+using namespace Mantid::API;
+
+/** Constructor
+* @param view :: The view we are handling
+*/
+ReflSaveTabPresenter::ReflSaveTabPresenter(IReflSaveTabView *view)
+    : m_view(view), m_mainPresenter() {
+
+  m_saveAlgs = {"SaveReflCustomAscii", "SaveReflThreeColumnAscii",
+                "SaveANSTOAscii", "SaveILLCosmosAscii"};
+  m_saveExts = {".dat", ".dat", ".txt", ".mft"};
+}
+
+/** Destructor
+*/
+ReflSaveTabPresenter::~ReflSaveTabPresenter() {}
+
+/** Accept a main presenter
+* @param mainPresenter :: [input] The main presenter
+*/
+void ReflSaveTabPresenter::acceptMainPresenter(
+    IReflMainWindowPresenter *mainPresenter) {
+  m_mainPresenter = mainPresenter;
+}
+
+void ReflSaveTabPresenter::notify(IReflSaveTabPresenter::Flag flag) {
+  switch (flag) {
+  case populateWorkspaceListFlag:
+    populateWorkspaceList();
+    break;
+  case filterWorkspaceListFlag:
+    filterWorkspaceNames();
+    break;
+  case workspaceParamsFlag:
+    populateParametersList();
+    break;
+  case saveWorkspacesFlag:
+    saveWorkspaces();
+    break;
+  case suggestSaveDirFlag:
+    suggestSaveDir();
+    break;
+  }
+}
+
+/** Fills the 'List of Workspaces' widget with the names of all available
+* workspaces
+*/
+void ReflSaveTabPresenter::populateWorkspaceList() {
+  m_view->clearWorkspaceList();
+  m_view->setWorkspaceList(getAvailableWorkspaceNames());
+}
+
+/** Filters the names in the 'List of Workspaces' widget
+*/
+void ReflSaveTabPresenter::filterWorkspaceNames() {
+  m_view->clearWorkspaceList();
+
+  std::string filter = m_view->getFilter();
+  bool regexCheck = m_view->getRegexCheck();
+  auto wsNames = getAvailableWorkspaceNames();
+  std::vector<std::string> validNames(wsNames.size());
+  auto it = validNames.begin();
+
+  if (regexCheck) {
+    // Use regex search to find names that contain the filter sequence
+    try {
+      boost::regex rgx(filter);
+      it = std::copy_if(
+          wsNames.begin(), wsNames.end(), validNames.begin(),
+          [rgx](std::string s) { return boost::regex_search(s, rgx); });
+    } catch (boost::regex_error &) {
+      m_mainPresenter->giveUserCritical("Error, invalid regular expression\n",
+                                        "Invalid regex");
+    }
+  } else {
+    // Otherwise simply add names where the filter string is found in
+    it = std::copy_if(wsNames.begin(), wsNames.end(), validNames.begin(),
+                      [filter](std::string s) {
+                        return s.find(filter) != std::string::npos;
+                      });
+  }
+
+  validNames.resize(std::distance(validNames.begin(), it));
+  m_view->setWorkspaceList(validNames);
+}
+
+/** Fills the 'List of Logged Parameters' widget with the parameters of the
+* currently selected workspace
+*/
+void ReflSaveTabPresenter::populateParametersList() {
+  m_view->clearParametersList();
+
+  std::string wsName = m_view->getCurrentWorkspaceName();
+  std::vector<std::string> logs;
+  const auto &properties = AnalysisDataService::Instance()
+                               .retrieveWS<MatrixWorkspace>(wsName)
+                               ->run()
+                               .getProperties();
+  for (auto it = properties.begin(); it != properties.end(); it++) {
+    logs.push_back((*it)->name());
+  }
+  m_view->setParametersList(logs);
+}
+
+/** Saves selected workspaces
+*/
+void ReflSaveTabPresenter::saveWorkspaces() {
+  // Check that save directory is valid
+  std::string saveDir = m_view->getSavePath();
+  if (saveDir.empty() || Poco::File(saveDir).isDirectory() == false) {
+    m_mainPresenter->giveUserCritical("Directory specified doesn't exist or "
+                                      "was invalid for your operating system",
+                                      "Invalid directory");
+    return;
+  }
+
+  // Check that at least one workspace has been selected for saving
+  auto wsNames = m_view->getSelectedWorkspaces();
+  if (wsNames.empty()) {
+    m_mainPresenter->giveUserCritical("No workspaces selected. You must select "
+                                      "the workspaces to save.",
+                                      "No workspaces selected");
+  }
+
+  // Obtain workspace titles
+  std::vector<std::string> wsTitles(wsNames.size());
+  std::transform(wsNames.begin(), wsNames.end(), wsTitles.begin(),
+                 [](std::string s) {
+                   return AnalysisDataService::Instance()
+                       .retrieveWS<MatrixWorkspace>(s)
+                       ->getTitle();
+                 });
+
+  // Create the appropriate save algorithm
+  bool titleCheck = m_view->getTitleCheck();
+  auto selectedParameters = m_view->getSelectedParameters();
+  bool qResolutionCheck = m_view->getQResolutionCheck();
+  std::string separator = m_view->getSeparator();
+  std::string prefix = m_view->getPrefix();
+  int formatIndex = m_view->getFileFormatIndex();
+  std::string algName = m_saveAlgs[formatIndex];
+  std::string extension = m_saveExts[formatIndex];
+  IAlgorithm_sptr saveAlg = AlgorithmManager::Instance().create(algName);
+
+  for (size_t i = 0; i < wsNames.size(); i++) {
+    // Add any additional algorithm-specific properties and execute
+    if (algName != "SaveANSTOAscii") {
+      if (titleCheck)
+        saveAlg->setProperty("Title", wsTitles[i]);
+      saveAlg->setProperty("LogList", selectedParameters);
+    }
+    if (algName == "SaveReflCustomAscii") {
+      saveAlg->setProperty("WriteDeltaQ", qResolutionCheck);
+    }
+
+    auto path = Poco::Path(saveDir);
+    auto wsName = wsNames[i];
+    path.append(prefix + wsName + extension);
+    saveAlg->setProperty("Separator", separator);
+    saveAlg->setProperty("Filename", path.toString());
+    saveAlg->setProperty(
+        "InputWorkspace",
+        AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(wsName));
+    saveAlg->execute();
+  }
+}
+
+/** Suggests a save directory and sets it in the 'Save path' text field
+*/
+void ReflSaveTabPresenter::suggestSaveDir() {
+  std::string path = Mantid::Kernel::ConfigService::Instance().getString(
+      "defaultsave.directory");
+  m_view->setSavePath(path);
+}
+
+/** Obtains all available workspace names to save
+* @return :: list of workspace names
+*/
+std::vector<std::string> ReflSaveTabPresenter::getAvailableWorkspaceNames() {
+  auto allNames = AnalysisDataService::Instance().getObjectNames();
+  // Exclude workspace groups as they cannot be saved to ascii
+  std::vector<std::string> validNames(allNames.size());
+  auto it = std::copy_if(
+      allNames.begin(), allNames.end(), validNames.begin(), [](std::string s) {
+        return (AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>(s) ==
+                NULL);
+      });
+  validNames.resize(std::distance(validNames.begin(), it));
+
+  return validNames;
+}
+}
+}
\ No newline at end of file
diff --git a/MantidQt/CustomInterfaces/src/Reflectometry/ReflSettingsPresenter.cpp b/MantidQt/CustomInterfaces/src/Reflectometry/ReflSettingsPresenter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..338f5f9dc8577ab8f1ee4a7d8bf2774d42a8efa8
--- /dev/null
+++ b/MantidQt/CustomInterfaces/src/Reflectometry/ReflSettingsPresenter.cpp
@@ -0,0 +1,380 @@
+#include "MantidQtCustomInterfaces/Reflectometry/ReflSettingsPresenter.h"
+#include "MantidAPI/AlgorithmManager.h"
+#include "MantidAPI/AnalysisDataService.h"
+#include "MantidAPI/IAlgorithm.h"
+#include "MantidAPI/MatrixWorkspace.h"
+#include "MantidGeometry/Instrument.h"
+#include "MantidQtCustomInterfaces/Reflectometry/IReflSettingsTabPresenter.h"
+#include "MantidQtCustomInterfaces/Reflectometry/IReflSettingsView.h"
+#include "MantidQtMantidWidgets/AlgorithmHintStrategy.h"
+#include <boost/algorithm/string.hpp>
+
+namespace MantidQt {
+namespace CustomInterfaces {
+
+using namespace Mantid::API;
+using namespace MantidQt::MantidWidgets;
+using namespace Mantid::Geometry;
+
+/** Constructor
+* @param view :: The view we are handling
+*/
+ReflSettingsPresenter::ReflSettingsPresenter(IReflSettingsView *view)
+    : m_view(view) {
+
+  // Create the 'HintingLineEdits'
+  createStitchHints();
+}
+
+/** Destructor
+*/
+ReflSettingsPresenter::~ReflSettingsPresenter() {}
+
+/** Used by the view to tell the presenter something has changed
+*
+* @param flag :: A flag used by the view to tell the presenter what happened
+*/
+void ReflSettingsPresenter::notify(IReflSettingsPresenter::Flag flag) {
+  switch (flag) {
+  case IReflSettingsPresenter::ExpDefaultsFlag:
+    getExpDefaults();
+    break;
+  case IReflSettingsPresenter::InstDefaultsFlag:
+    getInstDefaults();
+    break;
+  }
+  // Not having a 'default' case is deliberate. gcc issues a warning if there's
+  // a flag we aren't handling.
+}
+
+/** Sets the current instrument name and changes accessibility status of
+* the polarisation corrections option in the view accordingly
+* @param instName :: [input] The name of the instrument to set to
+*/
+void ReflSettingsPresenter::setInstrumentName(const std::string &instName) {
+  m_currentInstrumentName = instName;
+  m_view->setPolarisationOptionsEnabled(instName != "INTER" &&
+                                        instName != "SURF");
+}
+
+/** Returns global options for 'CreateTransmissionWorkspaceAuto'
+* @return :: Global options for 'CreateTransmissionWorkspaceAuto'
+*/
+std::string ReflSettingsPresenter::getTransmissionOptions() const {
+
+  std::vector<std::string> options;
+
+  // Add analysis mode
+  auto analysisMode = m_view->getAnalysisMode();
+  if (!analysisMode.empty())
+    options.push_back("AnalysisMode=" + analysisMode);
+
+  // Add monitor integral min
+  auto monIntMin = m_view->getMonitorIntegralMin();
+  if (!monIntMin.empty())
+    options.push_back("MonitorIntegrationWavelengthMin=" + monIntMin);
+
+  // Add monitor integral max
+  auto monIntMax = m_view->getMonitorIntegralMax();
+  if (!monIntMax.empty())
+    options.push_back("MonitorIntegrationWavelengthMax=" + monIntMax);
+
+  // Add monitor background min
+  auto monBgMin = m_view->getMonitorBackgroundMin();
+  if (!monBgMin.empty())
+    options.push_back("MonitorBackgroundWavelengthMin=" + monBgMin);
+
+  // Add monitor background max
+  auto monBgMax = m_view->getMonitorBackgroundMax();
+  if (!monBgMax.empty())
+    options.push_back("MonitorBackgroundWavelengthMax=" + monBgMax);
+
+  // Add lambda min
+  auto lamMin = m_view->getLambdaMin();
+  if (!lamMin.empty())
+    options.push_back("WavelengthMin=" + lamMin);
+
+  // Add lambda max
+  auto lamMax = m_view->getLambdaMax();
+  if (!lamMax.empty())
+    options.push_back("WavelengthMax=" + lamMax);
+
+  // Add I0MonitorIndex
+  auto I0MonitorIndex = m_view->getI0MonitorIndex();
+  if (!I0MonitorIndex.empty())
+    options.push_back("I0MonitorIndex=" + I0MonitorIndex);
+
+  // Add detector limits
+  auto procInst = m_view->getProcessingInstructions();
+  if (!procInst.empty()) {
+    wrapWithQuotes(procInst);
+    options.push_back("ProcessingInstructions=" + procInst);
+  }
+
+  return boost::algorithm::join(options, ",");
+}
+
+/** Returns global options for 'ReflectometryReductionOneAuto'
+* @return :: Global options for 'ReflectometryReductionOneAuto'
+*/
+std::string ReflSettingsPresenter::getReductionOptions() const {
+
+  std::vector<std::string> options;
+
+  // Add analysis mode
+  auto analysisMode = m_view->getAnalysisMode();
+  if (!analysisMode.empty())
+    options.push_back("AnalysisMode=" + analysisMode);
+
+  // Add CRho
+  auto crho = m_view->getCRho();
+  if (!crho.empty()) {
+    wrapWithQuotes(crho);
+    options.push_back("CRho=" + crho);
+  }
+
+  // Add CAlpha
+  auto calpha = m_view->getCAlpha();
+  if (!calpha.empty()) {
+    wrapWithQuotes(calpha);
+    options.push_back("CAlpha=" + calpha);
+  }
+
+  // Add CAp
+  auto cap = m_view->getCAp();
+  if (!cap.empty()) {
+    wrapWithQuotes(cap);
+    options.push_back("CAp=" + cap);
+  }
+
+  // Add CPp
+  auto cpp = m_view->getCPp();
+  if (!cpp.empty()) {
+    wrapWithQuotes(cpp);
+    options.push_back("CPp=" + cpp);
+  }
+
+  // Add direct beam
+  auto dbnr = m_view->getDirectBeam();
+  if (!dbnr.empty()) {
+    wrapWithQuotes(dbnr);
+    options.push_back("RegionOfDirectBeam=" + dbnr);
+  }
+
+  // Add polarisation corrections
+  auto polCorr = m_view->getPolarisationCorrections();
+  if (!polCorr.empty())
+    options.push_back("PolarizationAnalysis=" + polCorr);
+
+  // Add integrated monitors option
+  auto intMonCheck = m_view->getIntMonCheck();
+  if (!intMonCheck.empty())
+    options.push_back("NormalizeByIntegratedMonitors=" + intMonCheck);
+
+  // Add monitor integral min
+  auto monIntMin = m_view->getMonitorIntegralMin();
+  if (!monIntMin.empty())
+    options.push_back("MonitorIntegrationWavelengthMin=" + monIntMin);
+
+  // Add monitor integral max
+  auto monIntMax = m_view->getMonitorIntegralMax();
+  if (!monIntMax.empty())
+    options.push_back("MonitorIntegrationWavelengthMax=" + monIntMax);
+
+  // Add monitor background min
+  auto monBgMin = m_view->getMonitorBackgroundMin();
+  if (!monBgMin.empty())
+    options.push_back("MonitorBackgroundWavelengthMin=" + monBgMin);
+
+  // Add monitor background max
+  auto monBgMax = m_view->getMonitorBackgroundMax();
+  if (!monBgMax.empty())
+    options.push_back("MonitorBackgroundWavelengthMax=" + monBgMax);
+
+  // Add lambda min
+  auto lamMin = m_view->getLambdaMin();
+  if (!lamMin.empty())
+    options.push_back("WavelengthMin=" + lamMin);
+
+  // Add lambda max
+  auto lamMax = m_view->getLambdaMax();
+  if (!lamMax.empty())
+    options.push_back("WavelengthMax=" + lamMax);
+
+  // Add I0MonitorIndex
+  auto I0MonitorIndex = m_view->getI0MonitorIndex();
+  if (!I0MonitorIndex.empty())
+    options.push_back("I0MonitorIndex=" + I0MonitorIndex);
+
+  // Add scale factor
+  auto scaleFactor = m_view->getScaleFactor();
+  if (!scaleFactor.empty())
+    options.push_back("ScaleFactor=" + scaleFactor);
+
+  // Add momentum transfer limits
+  auto qTransStep = m_view->getMomentumTransferStep();
+  if (!qTransStep.empty()) {
+    options.push_back("MomentumTransferStep=" + qTransStep);
+  }
+
+  // Add detector limits
+  auto procInst = m_view->getProcessingInstructions();
+  if (!procInst.empty()) {
+    wrapWithQuotes(procInst);
+    options.push_back("ProcessingInstructions=" + procInst);
+  }
+
+  // Add transmission runs
+  auto transRuns = this->getTransmissionRuns();
+  if (!transRuns.empty())
+    options.push_back(transRuns);
+
+  return boost::algorithm::join(options, ",");
+}
+
+/** Receives specified transmission runs from the view and loads them into the
+*ADS. Returns a string with transmission runs so that they are considered in the
+*reduction
+*
+* @return :: transmission run(s) as a string that will be used for the reduction
+*/
+std::string ReflSettingsPresenter::getTransmissionRuns() const {
+
+  auto runs = m_view->getTransmissionRuns();
+  if (runs.empty())
+    return "";
+
+  std::vector<std::string> transRuns;
+  boost::split(transRuns, runs, boost::is_any_of(","));
+
+  if (transRuns.size() > 2)
+    throw std::invalid_argument("Only one transmission run or two "
+                                "transmission runs separated by ',' "
+                                "are allowed.");
+
+  for (const auto &run : transRuns) {
+    if (AnalysisDataService::Instance().doesExist("TRANS_" + run))
+      continue;
+    // Load transmission runs and put them in the ADS
+    IAlgorithm_sptr alg = AlgorithmManager::Instance().create("LoadISISNexus");
+    alg->setProperty("Filename", run);
+    alg->setPropertyValue("OutputWorkspace", "TRANS_" + run);
+    alg->execute();
+  }
+
+  // Return them as options for reduction
+  std::string options = "FirstTransmissionRun=TRANS_" + transRuns[0];
+  if (transRuns.size() > 1)
+    options += ",SecondTransmissionRun=TRANS_" + transRuns[1];
+
+  return options;
+}
+
+/** Returns global options for 'Stitch1DMany'
+* @return :: Global options for 'Stitch1DMany'
+*/
+std::string ReflSettingsPresenter::getStitchOptions() const {
+
+  return m_view->getStitchOptions();
+}
+
+/** Creates hints for 'Stitch1DMany'
+*/
+void ReflSettingsPresenter::createStitchHints() {
+
+  // The algorithm
+  IAlgorithm_sptr alg = AlgorithmManager::Instance().create("Stitch1DMany");
+  // The blacklist
+  std::set<std::string> blacklist = {"InputWorkspaces", "OutputWorkspace",
+                                     "OutputWorkspace"};
+  AlgorithmHintStrategy strategy(alg, blacklist);
+
+  m_view->createStitchHints(strategy.createHints());
+}
+
+/** Fills experiment settings with default values
+*/
+void ReflSettingsPresenter::getExpDefaults() {
+  // Algorithm and instrument
+  auto alg = createReductionAlg();
+  auto inst = createEmptyInstrument(m_currentInstrumentName);
+
+  // Collect all default values and set them in view
+  std::vector<std::string> defaults(7);
+  defaults[0] = alg->getPropertyValue("AnalysisMode");
+  defaults[1] = alg->getPropertyValue("PolarizationAnalysis");
+
+  auto cRho = inst->getStringParameter("crho");
+  if (!cRho.empty())
+    defaults[2] = cRho[0];
+
+  auto cAlpha = inst->getStringParameter("calpha");
+  if (!cAlpha.empty())
+    defaults[3] = cAlpha[0];
+
+  auto cAp = inst->getStringParameter("cAp");
+  if (!cAp.empty())
+    defaults[4] = cAp[0];
+
+  auto cPp = inst->getStringParameter("cPp");
+  if (!cPp.empty())
+    defaults[5] = cPp[0];
+
+  defaults[6] = alg->getPropertyValue("ScaleFactor");
+
+  m_view->setExpDefaults(defaults);
+}
+
+/** Wraps string with quote marks if it does not already have them
+* @param str :: [input] The string to be wrapped
+*/
+void ReflSettingsPresenter::wrapWithQuotes(std::string &str) const {
+  if (str.front() != '\"')
+    str = "\"" + str;
+  if (str.back() != '\"')
+    str = str + "\"";
+}
+
+/** Fills instrument settings with default values
+*/
+void ReflSettingsPresenter::getInstDefaults() {
+  // Algorithm and instrument
+  auto alg = createReductionAlg();
+  auto inst = createEmptyInstrument(m_currentInstrumentName);
+
+  // Collect all default values
+  std::vector<double> defaults(8);
+  defaults[0] = boost::lexical_cast<double>(
+      alg->getPropertyValue("NormalizeByIntegratedMonitors"));
+  defaults[1] = inst->getNumberParameter("MonitorIntegralMin")[0];
+  defaults[2] = inst->getNumberParameter("MonitorIntegralMax")[0];
+  defaults[3] = inst->getNumberParameter("MonitorBackgroundMin")[0];
+  defaults[4] = inst->getNumberParameter("MonitorBackgroundMax")[0];
+  defaults[5] = inst->getNumberParameter("LambdaMin")[0];
+  defaults[6] = inst->getNumberParameter("LambdaMax")[0];
+  defaults[7] = inst->getNumberParameter("I0MonitorIndex")[0];
+
+  m_view->setInstDefaults(defaults);
+}
+
+/** Generates and returns an instance of the ReflectometryReductionOne algorithm
+*/
+IAlgorithm_sptr ReflSettingsPresenter::createReductionAlg() {
+  return AlgorithmManager::Instance().create("ReflectometryReductionOneAuto");
+}
+
+/** Creates and returns an example empty instrument given an instrument name
+*/
+Instrument_const_sptr
+ReflSettingsPresenter::createEmptyInstrument(const std::string &instName) {
+  IAlgorithm_sptr loadInst =
+      AlgorithmManager::Instance().create("LoadEmptyInstrument");
+  loadInst->setChild(true);
+  loadInst->setProperty("OutputWorkspace", "outWs");
+  loadInst->setProperty("InstrumentName", instName);
+  loadInst->execute();
+  MatrixWorkspace_const_sptr ws = loadInst->getProperty("OutputWorkspace");
+  return ws->getInstrument();
+}
+}
+}
\ No newline at end of file
diff --git a/MantidQt/CustomInterfaces/src/Reflectometry/ReflSettingsTabPresenter.cpp b/MantidQt/CustomInterfaces/src/Reflectometry/ReflSettingsTabPresenter.cpp
index 03ef0f433f58882597e3eedb7b8278419d4c464a..6e082f7d0d26a2e6ea2adcc0da2f15b2124a3cd1 100644
--- a/MantidQt/CustomInterfaces/src/Reflectometry/ReflSettingsTabPresenter.cpp
+++ b/MantidQt/CustomInterfaces/src/Reflectometry/ReflSettingsTabPresenter.cpp
@@ -1,358 +1,67 @@
 #include "MantidQtCustomInterfaces/Reflectometry/ReflSettingsTabPresenter.h"
 #include "MantidQtCustomInterfaces/Reflectometry/IReflMainWindowPresenter.h"
-#include "MantidQtCustomInterfaces/Reflectometry/IReflSettingsTabView.h"
+#include "MantidQtCustomInterfaces/Reflectometry/ReflSettingsPresenter.h"
 #include "MantidQtMantidWidgets/AlgorithmHintStrategy.h"
 #include "MantidAPI/AlgorithmManager.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/MatrixWorkspace.h"
 
+#include <boost/algorithm/string.hpp>
+
 namespace MantidQt {
 namespace CustomInterfaces {
 
-using namespace Mantid::API;
-using namespace MantidQt::MantidWidgets;
-using namespace Mantid::Geometry;
-
 /** Constructor
-* @param view :: The view we are handling
+*
+* @param presenters :: The presenters of each group as a vector
 */
-ReflSettingsTabPresenter::ReflSettingsTabPresenter(IReflSettingsTabView *view)
-    : m_view(view), m_mainPresenter() {
-
-  // Create the 'HintingLineEdits'
-  createStitchHints();
-}
+ReflSettingsTabPresenter::ReflSettingsTabPresenter(
+    std::vector<IReflSettingsPresenter *> presenters)
+    : m_settingsPresenters(presenters) {}
 
 /** Destructor
+*
 */
 ReflSettingsTabPresenter::~ReflSettingsTabPresenter() {}
 
-/** Accept a main presenter
-* @param mainPresenter :: [input] The main presenter
-*/
-void ReflSettingsTabPresenter::acceptMainPresenter(
-    IReflMainWindowPresenter *mainPresenter) {
-  m_mainPresenter = mainPresenter;
-}
-
-/** Used by the view to tell the presenter something has changed
-*/
-void ReflSettingsTabPresenter::notify(IReflSettingsTabPresenter::Flag flag) {
-  switch (flag) {
-  case IReflSettingsTabPresenter::ExpDefaultsFlag:
-    getExpDefaults();
-    break;
-  case IReflSettingsTabPresenter::InstDefaultsFlag:
-    getInstDefaults();
-    break;
-  }
-  // Not having a 'default' case is deliberate. gcc issues a warning if there's
-  // a flag we aren't handling.
-}
-
 /** Sets the current instrument name and changes accessibility status of
 * the polarisation corrections option in the view accordingly
+*
 * @param instName :: [input] The name of the instrument to set to
 */
-void ReflSettingsTabPresenter::setInstrumentName(const std::string instName) {
-  m_currentInstrumentName = instName;
-  m_view->setPolarisationOptionsEnabled(instName != "INTER" &&
-                                        instName != "SURF");
+void ReflSettingsTabPresenter::setInstrumentName(const std::string &instName) {
+  for (auto presenter : m_settingsPresenters)
+    presenter->setInstrumentName(instName);
 }
 
 /** Returns global options for 'CreateTransmissionWorkspaceAuto'
+*
+* @param group :: The group from which to get the options
 * @return :: Global options for 'CreateTransmissionWorkspaceAuto'
 */
-std::string ReflSettingsTabPresenter::getTransmissionOptions() const {
-
-  std::vector<std::string> options;
-
-  // Add analysis mode
-  auto analysisMode = m_view->getAnalysisMode();
-  if (!analysisMode.empty())
-    options.push_back("AnalysisMode=" + analysisMode);
-
-  // Add monitor integral min
-  auto monIntMin = m_view->getMonitorIntegralMin();
-  if (!monIntMin.empty())
-    options.push_back("MonitorIntegrationWavelengthMin=" + monIntMin);
-
-  // Add monitor integral max
-  auto monIntMax = m_view->getMonitorIntegralMax();
-  if (!monIntMax.empty())
-    options.push_back("MonitorIntegrationWavelengthMax=" + monIntMax);
-
-  // Add monitor background min
-  auto monBgMin = m_view->getMonitorBackgroundMin();
-  if (!monBgMin.empty())
-    options.push_back("MonitorBackgroundWavelengthMin=" + monBgMin);
-
-  // Add monitor background max
-  auto monBgMax = m_view->getMonitorBackgroundMax();
-  if (!monBgMax.empty())
-    options.push_back("MonitorBackgroundWavelengthMax=" + monBgMax);
-
-  // Add lambda min
-  auto lamMin = m_view->getLambdaMin();
-  if (!lamMin.empty())
-    options.push_back("WavelengthMin=" + lamMin);
+std::string ReflSettingsTabPresenter::getTransmissionOptions(int group) const {
 
-  // Add lambda max
-  auto lamMax = m_view->getLambdaMax();
-  if (!lamMax.empty())
-    options.push_back("WavelengthMax=" + lamMax);
-
-  // Add I0MonitorIndex
-  auto I0MonitorIndex = m_view->getI0MonitorIndex();
-  if (!I0MonitorIndex.empty())
-    options.push_back("I0MonitorIndex=" + I0MonitorIndex);
-
-  // Add detector limits
-  auto procInst = m_view->getProcessingInstructions();
-  if (!procInst.empty())
-    options.push_back("ProcessingInstructions=" + procInst);
-
-  return boost::algorithm::join(options, ",");
+  return m_settingsPresenters.at(group)->getTransmissionOptions();
 }
 
 /** Returns global options for 'ReflectometryReductionOneAuto'
-* @return :: Global options for 'ReflectometryReductionOneAuto'
-*/
-std::string ReflSettingsTabPresenter::getReductionOptions() const {
-
-  std::vector<std::string> options;
-
-  // Add analysis mode
-  auto analysisMode = m_view->getAnalysisMode();
-  if (!analysisMode.empty())
-    options.push_back("AnalysisMode=" + analysisMode);
-
-  // Add CRho
-  auto crho = m_view->getCRho();
-  if (!crho.empty())
-    options.push_back("CRho=" + crho);
-
-  // Add CAlpha
-  auto calpha = m_view->getCAlpha();
-  if (!calpha.empty())
-    options.push_back("CAlpha=" + calpha);
-
-  // Add CAp
-  auto cap = m_view->getCAp();
-  if (!cap.empty())
-    options.push_back("CAp=" + cap);
-
-  // Add CPp
-  auto cpp = m_view->getCPp();
-  if (!cpp.empty())
-    options.push_back("CPp=" + cpp);
-
-  // Add direct beam
-  auto dbnr = m_view->getDirectBeam();
-  if (!dbnr.empty())
-    options.push_back("RegionOfDirectBeam=" + dbnr);
-
-  // Add polarisation corrections
-  auto polCorr = m_view->getPolarisationCorrections();
-  if (!polCorr.empty())
-    options.push_back("PolarizationAnalysis=" + polCorr);
-
-  // Add integrated monitors option
-  auto intMonCheck = m_view->getIntMonCheck();
-  if (!intMonCheck.empty())
-    options.push_back("NormalizeByIntegratedMonitors=" + intMonCheck);
-
-  // Add monitor integral min
-  auto monIntMin = m_view->getMonitorIntegralMin();
-  if (!monIntMin.empty())
-    options.push_back("MonitorIntegrationWavelengthMin=" + monIntMin);
-
-  // Add monitor integral max
-  auto monIntMax = m_view->getMonitorIntegralMax();
-  if (!monIntMax.empty())
-    options.push_back("MonitorIntegrationWavelengthMax=" + monIntMax);
-
-  // Add monitor background min
-  auto monBgMin = m_view->getMonitorBackgroundMin();
-  if (!monBgMin.empty())
-    options.push_back("MonitorBackgroundWavelengthMin=" + monBgMin);
-
-  // Add monitor background max
-  auto monBgMax = m_view->getMonitorBackgroundMax();
-  if (!monBgMax.empty())
-    options.push_back("MonitorBackgroundWavelengthMax=" + monBgMax);
-
-  // Add lambda min
-  auto lamMin = m_view->getLambdaMin();
-  if (!lamMin.empty())
-    options.push_back("WavelengthMin=" + lamMin);
-
-  // Add lambda max
-  auto lamMax = m_view->getLambdaMax();
-  if (!lamMax.empty())
-    options.push_back("WavelengthMax=" + lamMax);
-
-  // Add I0MonitorIndex
-  auto I0MonitorIndex = m_view->getI0MonitorIndex();
-  if (!I0MonitorIndex.empty())
-    options.push_back("I0MonitorIndex=" + I0MonitorIndex);
-
-  // Add scale factor
-  auto scaleFactor = m_view->getScaleFactor();
-  if (!scaleFactor.empty())
-    options.push_back("ScaleFactor=" + scaleFactor);
-
-  // Add momentum transfer limits
-  auto qTransStep = m_view->getMomentumTransferStep();
-  if (!qTransStep.empty()) {
-    options.push_back("MomentumTransferStep=" + qTransStep);
-  }
-
-  // Add detector limits
-  auto procInst = m_view->getProcessingInstructions();
-  if (!procInst.empty())
-    options.push_back("ProcessingInstructions=" + procInst);
-
-  // Add transmission runs
-  auto transRuns = this->getTransmissionRuns();
-  if (!transRuns.empty())
-    options.push_back(transRuns);
-
-  return boost::algorithm::join(options, ",");
-}
-
-/** Receives specified transmission runs from the view and loads them into the
-*ADS. Returns a string with transmission runs so that they are considered in the
-*reduction
 *
-* @return :: transmission run(s) as a string that will be used for the reduction
+* @param group :: The group from which to get the options
+* @return :: Global options for 'ReflectometryReductionOneAuto'
 */
-std::string ReflSettingsTabPresenter::getTransmissionRuns() const {
-
-  auto runs = m_view->getTransmissionRuns();
-  if (runs.empty())
-    return "";
+std::string ReflSettingsTabPresenter::getReductionOptions(int group) const {
 
-  std::vector<std::string> transRuns;
-  boost::split(transRuns, runs, boost::is_any_of(","));
-
-  if (transRuns.size() > 2)
-    throw std::invalid_argument("Only one transmission run or two "
-                                "transmission runs separated by ',' "
-                                "are allowed.");
-
-  for (const auto &run : transRuns) {
-    if (AnalysisDataService::Instance().doesExist("TRANS_" + run))
-      continue;
-    // Load transmission runs and put them in the ADS
-    IAlgorithm_sptr alg = AlgorithmManager::Instance().create("LoadISISNexus");
-    alg->setProperty("Filename", run);
-    alg->setPropertyValue("OutputWorkspace", "TRANS_" + run);
-    alg->execute();
-  }
-
-  // Return them as options for reduction
-  std::string options = "FirstTransmissionRun=TRANS_" + transRuns[0];
-  if (transRuns.size() > 1)
-    options += ",SecondTransmissionRun=TRANS_" + transRuns[1];
-
-  return options;
+  return m_settingsPresenters.at(group)->getReductionOptions();
 }
 
 /** Returns global options for 'Stitch1DMany'
+*
+* @param group :: The group from which to get the options
 * @return :: Global options for 'Stitch1DMany'
 */
-std::string ReflSettingsTabPresenter::getStitchOptions() const {
-
-  return m_view->getStitchOptions();
-}
-
-/** Creates hints for 'Stitch1DMany'
-*/
-void ReflSettingsTabPresenter::createStitchHints() {
-
-  // The algorithm
-  IAlgorithm_sptr alg = AlgorithmManager::Instance().create("Stitch1DMany");
-  // The blacklist
-  std::set<std::string> blacklist = {"InputWorkspaces", "OutputWorkspace",
-                                     "OutputWorkspace"};
-  AlgorithmHintStrategy strategy(alg, blacklist);
-
-  m_view->createStitchHints(strategy.createHints());
-}
-
-/** Fills experiment settings with default values
-*/
-void ReflSettingsTabPresenter::getExpDefaults() {
-  // Algorithm and instrument
-  auto alg = createReductionAlg();
-  auto inst = createEmptyInstrument(m_currentInstrumentName);
-
-  // Collect all default values and set them in view
-  std::vector<std::string> defaults(7);
-  defaults[0] = alg->getPropertyValue("AnalysisMode");
-  defaults[1] = alg->getPropertyValue("PolarizationAnalysis");
-
-  auto cRho = inst->getStringParameter("crho");
-  if (!cRho.empty())
-    defaults[2] = cRho[0];
-
-  auto cAlpha = inst->getStringParameter("calpha");
-  if (!cAlpha.empty())
-    defaults[3] = cAlpha[0];
-
-  auto cAp = inst->getStringParameter("cAp");
-  if (!cAp.empty())
-    defaults[4] = cAp[0];
-
-  auto cPp = inst->getStringParameter("cPp");
-  if (!cPp.empty())
-    defaults[5] = cPp[0];
-
-  defaults[6] = alg->getPropertyValue("ScaleFactor");
-
-  m_view->setExpDefaults(defaults);
-}
-
-/** Fills instrument settings with default values
-*/
-void ReflSettingsTabPresenter::getInstDefaults() {
-  // Algorithm and instrument
-  auto alg = createReductionAlg();
-  auto inst = createEmptyInstrument(m_currentInstrumentName);
-
-  // Collect all default values
-  std::vector<double> defaults(8);
-  defaults[0] = boost::lexical_cast<double>(
-      alg->getPropertyValue("NormalizeByIntegratedMonitors"));
-  defaults[1] = inst->getNumberParameter("MonitorIntegralMin")[0];
-  defaults[2] = inst->getNumberParameter("MonitorIntegralMax")[0];
-  defaults[3] = inst->getNumberParameter("MonitorBackgroundMin")[0];
-  defaults[4] = inst->getNumberParameter("MonitorBackgroundMax")[0];
-  defaults[5] = inst->getNumberParameter("LambdaMin")[0];
-  defaults[6] = inst->getNumberParameter("LambdaMax")[0];
-  defaults[7] = inst->getNumberParameter("I0MonitorIndex")[0];
+std::string ReflSettingsTabPresenter::getStitchOptions(int group) const {
 
-  m_view->setInstDefaults(defaults);
+  return m_settingsPresenters.at(group)->getStitchOptions();
 }
-
-/** Generates and returns an instance of the ReflectometryReductionOne algorithm
-*/
-IAlgorithm_sptr ReflSettingsTabPresenter::createReductionAlg() {
-  return AlgorithmManager::Instance().create("ReflectometryReductionOneAuto");
-}
-
-/** Creates and returns an example empty instrument given an instrument name
-*/
-Instrument_const_sptr
-ReflSettingsTabPresenter::createEmptyInstrument(std::string instName) {
-  IAlgorithm_sptr loadInst =
-      AlgorithmManager::Instance().create("LoadEmptyInstrument");
-  loadInst->setChild(true);
-  loadInst->setProperty("OutputWorkspace", "outWs");
-  loadInst->setProperty("InstrumentName", instName);
-  loadInst->execute();
-  MatrixWorkspace_const_sptr ws = loadInst->getProperty("OutputWorkspace");
-  return ws->getInstrument();
 }
 }
-}
\ No newline at end of file
diff --git a/MantidQt/CustomInterfaces/src/SANSAddFiles.cpp b/MantidQt/CustomInterfaces/src/SANSAddFiles.cpp
index 23598d28162ee1e4bde5742e5a39990afa75e452..d8c0a534b33ce2a535446daa12dc9bdb2d7f9aff 100644
--- a/MantidQt/CustomInterfaces/src/SANSAddFiles.cpp
+++ b/MantidQt/CustomInterfaces/src/SANSAddFiles.cpp
@@ -4,6 +4,7 @@
 #include "MantidKernel/ConfigService.h"
 #include "MantidAPI/FileProperty.h"
 #include "MantidKernel/ArrayProperty.h"
+#include "MantidKernel/PropertyHelper.h"
 #include "MantidAPI/AlgorithmManager.h"
 
 #include <QStringList>
diff --git a/MantidQt/CustomInterfaces/src/SANSRunWindow.cpp b/MantidQt/CustomInterfaces/src/SANSRunWindow.cpp
index b9a5d746b3d1b694e7769c496fa580e50e3b1091..d247476b09bb59170add2a37d3e58c9e0f5ec223 100644
--- a/MantidQt/CustomInterfaces/src/SANSRunWindow.cpp
+++ b/MantidQt/CustomInterfaces/src/SANSRunWindow.cpp
@@ -17,7 +17,6 @@
 #include "MantidAPI/Run.h"
 #include "MantidAPI/WorkspaceGroup.h"
 
-#include "MantidQtAPI/FileDialogHandler.h"
 #include "MantidQtAPI/MantidDesktopServices.h"
 #include "MantidQtAPI/ManageUserDirectories.h"
 #include "MantidQtCustomInterfaces/SANSAddFiles.h"
@@ -25,6 +24,7 @@
 #include "MantidQtCustomInterfaces/SANSEventSlicing.h"
 
 #include <QClipboard>
+#include <QFileDialog>
 #include <QTemporaryFile>
 #include <QTextStream>
 #include <QUrl>
@@ -474,11 +474,9 @@ void SANSRunWindow::setupSaveBox() {
           SLOT(setUserFname()));
 
   // link the save option tick boxes to their save algorithm
-  m_savFormats.insert(m_uiForm.saveNex_check, "SaveNexus");
   m_savFormats.insert(m_uiForm.saveNIST_Qxy_check, "SaveNISTDAT");
   m_savFormats.insert(m_uiForm.saveCan_check, "SaveCanSAS1D");
   m_savFormats.insert(m_uiForm.saveRKH_check, "SaveRKH");
-  m_savFormats.insert(m_uiForm.saveCSV_check, "SaveCSV");
   m_savFormats.insert(m_uiForm.saveNXcanSAS_check, "SaveNXcanSAS");
 
   for (SavFormatsConstIt i = m_savFormats.begin(); i != m_savFormats.end();
@@ -733,13 +731,11 @@ void SANSRunWindow::readSettings() {
 */
 void SANSRunWindow::readSaveSettings(QSettings &valueStore) {
   valueStore.beginGroup("CustomInterfaces/SANSRunWindow/SaveOutput");
-  m_uiForm.saveNex_check->setChecked(valueStore.value("nexus", false).toBool());
   m_uiForm.saveCan_check->setChecked(
       valueStore.value("canSAS", false).toBool());
   m_uiForm.saveNIST_Qxy_check->setChecked(
       valueStore.value("NIST_Qxy", false).toBool());
   m_uiForm.saveRKH_check->setChecked(valueStore.value("RKH", false).toBool());
-  m_uiForm.saveCSV_check->setChecked(valueStore.value("CSV", false).toBool());
   m_uiForm.saveNXcanSAS_check->setChecked(
       valueStore.value("NXcanSAS", false).toBool());
 }
@@ -779,11 +775,9 @@ void SANSRunWindow::saveSettings() {
 */
 void SANSRunWindow::saveSaveSettings(QSettings &valueStore) {
   valueStore.beginGroup("CustomInterfaces/SANSRunWindow/SaveOutput");
-  valueStore.setValue("nexus", m_uiForm.saveNex_check->isChecked());
   valueStore.setValue("canSAS", m_uiForm.saveCan_check->isChecked());
   valueStore.setValue("NIST_Qxy", m_uiForm.saveNIST_Qxy_check->isChecked());
   valueStore.setValue("RKH", m_uiForm.saveRKH_check->isChecked());
-  valueStore.setValue("CSV", m_uiForm.saveCSV_check->isChecked());
   valueStore.setValue("NXcanSAS", m_uiForm.saveNXcanSAS_check->isChecked());
 }
 /**
@@ -1671,12 +1665,12 @@ void SANSRunWindow::setGeometryDetails() {
 
   if (boost::dynamic_pointer_cast<const IEventWorkspace>(ws)) {
     // EventWorkspaces have their monitors loaded into a separate workspace.
-    const std::string monitorWsName = ws->name() + "_monitors";
+    const std::string monitorWsName = ws->getName() + "_monitors";
 
     if (!ADS.doesExist(monitorWsName)) {
       g_log.error() << "Expected a sister monitor workspace called \""
                     << monitorWsName << "\" "
-                    << "for the EventWorkspace \"" << ws->name()
+                    << "for the EventWorkspace \"" << ws->getName()
                     << "\", but could not find one "
                     << "so unable to set geometry details.\n";
       return;
@@ -1703,7 +1697,7 @@ void SANSRunWindow::setGeometryDetails() {
     g_log.error() << "The reported incident monitor spectrum number \""
                   << monitorSpectrum
                   << "\" does not have a corresponding workspace index in \""
-                  << monitorWs->name()
+                  << monitorWs->getName()
                   << "\", so unable to set geometry details.\n";
     return;
   }
@@ -1847,7 +1841,7 @@ void SANSRunWindow::setSANS2DGeometry(
   QString code_to_run =
       QString("print ','.join([str(a) for a in "
               "i.ReductionSingleton().instrument.getDetValues('%1')])")
-          .arg(QString::fromStdString(workspace->name()));
+          .arg(QString::fromStdString(workspace->getName()));
 
   QStringList logvalues = runReduceScriptFunction(code_to_run).split(",");
 
@@ -1981,7 +1975,7 @@ void SANSRunWindow::saveFileBrowse() {
 
   const QString filter = ";;AllFiles (*)";
 
-  QString oFile = FileDialogHandler::getSaveFileName(
+  QString oFile = QFileDialog::getSaveFileName(
       this, title, prevPath + "/" + m_uiForm.outfile_edit->text());
 
   if (!oFile.isEmpty()) {
@@ -2177,8 +2171,8 @@ bool SANSRunWindow::handleLoadButtonClick() {
 *  @param RunStep name of the RunStep Python object
 *  @param output where the number will be displayed
 */
-void SANSRunWindow::readNumberOfEntries(
-    const QString &RunStep, MantidWidgets::MWRunFiles *const output) {
+void SANSRunWindow::readNumberOfEntries(const QString &RunStep,
+                                        API::MWRunFiles *const output) {
   QString periods = runReduceScriptFunction("print i.ReductionSingleton()." +
                                             RunStep + ".periods_in_file");
   output->setNumberOfEntries(periods.toInt());
@@ -2515,8 +2509,8 @@ void SANSRunWindow::handleReduceButtonClick(const QString &typeStr) {
 
     QString csv_file(m_uiForm.csv_filename->text());
     if (m_dirty_batch_grid) {
-      QString selected_file = MantidQt::API::FileDialogHandler::getSaveFileName(
-          this, "Save as CSV", m_last_dir);
+      QString selected_file =
+          QFileDialog::getSaveFileName(this, "Save as CSV", m_last_dir);
       csv_file = saveBatchGrid(selected_file);
     }
     py_code.prepend("import SANSBatchMode as batch\n");
@@ -3412,8 +3406,8 @@ void SANSRunWindow::resetDefaultOutput(const QString &wsName) {
 * present) file
 *  @param assignFn this is different for can or sample
 */
-bool SANSRunWindow::assignMonitorRun(MantidWidgets::MWRunFiles &trans,
-                                     MantidWidgets::MWRunFiles &direct,
+bool SANSRunWindow::assignMonitorRun(API::MWRunFiles &trans,
+                                     API::MWRunFiles &direct,
                                      const QString &assignFn) {
   // need something to place between names printed by Python that won't be
   // intepreted as the names or removed as white space
@@ -3461,7 +3455,7 @@ bool SANSRunWindow::assignMonitorRun(MantidWidgets::MWRunFiles &trans,
  * @param[in] assignFn the Python command to run
  * @return true if there were no Python errors, false otherwise
  */
-bool SANSRunWindow::assignDetBankRun(MantidWidgets::MWRunFiles &runFile,
+bool SANSRunWindow::assignDetBankRun(API::MWRunFiles &runFile,
                                      const QString &assignFn) {
   // need something to place between names printed by Python that won't be
   // intepreted as the names or removed as white space
@@ -4443,13 +4437,17 @@ bool SANSRunWindow::areSettingsValid(States type) {
   QString message;
   // ------------ GUI INPUT CHECKS ------------
 
-  // We currently do not allow a 2D reduction with a merged flag
+  // We currently do not allow a 2D reduction with a merged flag and fitting
+  // because we can only fit 1D functions
   auto isMergedReduction = m_uiForm.detbank_sel->currentIndex() == 3;
-  if (type == States::TwoD && isMergedReduction) {
+  auto hasFitEnabled = m_uiForm.frontDetShiftCB->isChecked() ||
+                       m_uiForm.frontDetRescaleCB->isChecked();
+  if (type == States::TwoD && isMergedReduction && hasFitEnabled) {
     isValid = false;
     message +=
-        "A merged Detector Bank selection is currently not supported for 2D "
-        "reductions.\n";
+        "A merged reduction with fitting is currently not supported for 2D "
+        "reductions. You can run a merged reduction wihthout fitting enabled"
+        " for 2D reductions.\n";
   }
 
   // R_MAX -- can be only >0 or -1
diff --git a/MantidQt/CustomInterfaces/src/StepScan.cpp b/MantidQt/CustomInterfaces/src/StepScan.cpp
index 0aafa658bc16f2589d0d53a564f685602205d5c7..0b2e381fea2290e61e834e648b3250ec8c9d2ed5 100644
--- a/MantidQt/CustomInterfaces/src/StepScan.cpp
+++ b/MantidQt/CustomInterfaces/src/StepScan.cpp
@@ -5,7 +5,9 @@
 #include "MantidAPI/InstrumentDataService.h"
 #include "MantidAPI/LiveListenerFactory.h"
 #include "MantidAPI/Run.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidKernel/InstrumentInfo.h"
+#include "MantidKernel/Strings.h"
 #include "MantidKernel/TimeSeriesProperty.h"
 #include <QFileInfo>
 #include <QUrl>
@@ -124,7 +126,6 @@ void StepScan::startLiveListener() {
         "This interface requires event data.\nThe live data for " +
             QString::fromStdString(m_instrument) + " is in histogram form");
     m_uiForm.mWRunFiles->liveButtonSetChecked(false);
-    m_uiForm.mWRunFiles->liveButtonSetEnabled(false);
     return;
   }
 
@@ -292,7 +293,7 @@ bool StepScan::mergeRuns() {
                    // within a group?)
     IAlgorithm_sptr addScanIndex =
         AlgorithmManager::Instance().create("AddSampleLog");
-    addScanIndex->setPropertyValue("Workspace", ws->name());
+    addScanIndex->setPropertyValue("Workspace", ws->getName());
     addScanIndex->setProperty("LogName", "scan_index");
     addScanIndex->setProperty("LogType", "Number Series");
     addScanIndex->setProperty("LogText", Strings::toString(i + 1));
diff --git a/MantidQt/CustomInterfaces/src/Tomography/EnergyBandsViewQtGUI.cpp b/MantidQt/CustomInterfaces/src/Tomography/EnergyBandsViewQtGUI.cpp
index 516633b5157f81df6afbee5c12695d37cb810c83..80a2a43378668f2843cb3acce51e5d8e21b7266f 100644
--- a/MantidQt/CustomInterfaces/src/Tomography/EnergyBandsViewQtGUI.cpp
+++ b/MantidQt/CustomInterfaces/src/Tomography/EnergyBandsViewQtGUI.cpp
@@ -132,6 +132,8 @@ void TomographyIfaceViewQtGUI::browseAggScriptClicked() {
 void TomographyIfaceViewQtGUI::runAggregateBands(
     Mantid::API::IAlgorithm_sptr alg) {
 
+  // reset any previous connections
+  m_aggAlgRunner.get()->disconnect();
   connect(m_aggAlgRunner.get(), SIGNAL(batchComplete(bool)), this,
           SLOT(finishedAggBands(bool)), Qt::QueuedConnection);
 
diff --git a/MantidQt/CustomInterfaces/src/Tomography/ImageROIPresenter.cpp b/MantidQt/CustomInterfaces/src/Tomography/ImageROIPresenter.cpp
index a739bdaf9691a550c6cf32d8ca2ece4f38bc7226..313daa2b592b86284466320169ec65c9cc927f1e 100644
--- a/MantidQt/CustomInterfaces/src/Tomography/ImageROIPresenter.cpp
+++ b/MantidQt/CustomInterfaces/src/Tomography/ImageROIPresenter.cpp
@@ -135,7 +135,7 @@ void ImageROIPresenter::processBrowseImage() {
     return;
 
   m_stackPath = path;
-  processNewStack(true);
+  processLoadSingleImage();
 }
 
 void ImageROIPresenter::processBrowseStack() {
@@ -145,7 +145,7 @@ void ImageROIPresenter::processBrowseStack() {
     return;
 
   m_stackPath = path;
-  processNewStack(false);
+  processLoadStackOfImages();
 }
 
 /**
@@ -177,62 +177,64 @@ StackOfImagesDirs ImageROIPresenter::checkInputStack(const std::string &path) {
   return soid;
 }
 
-void ImageROIPresenter::processNewStack(bool singleImg) {
-  if (!singleImg) {
-
-    StackOfImagesDirs soid("");
-    try {
-      soid = checkInputStack(m_stackPath);
-    } catch (std::exception &e) {
-      // Poco::FileNotFoundException: this should never happen, unless
-      // the open dir dialog misbehaves unexpectedly, or in tests
-      m_view->userWarning(
-          "Error trying to open directories/files",
-          "The path selected via the dialog cannot be openend or "
-          "there was a problem while trying to access it. This "
-          "is an unexpected inconsistency. Error details: " +
-              std::string(e.what()));
+void ImageROIPresenter::processLoadSingleImage() {
+  try {
+    auto &ads = Mantid::API::AnalysisDataService::Instance();
+    if (ads.doesExist(g_wsgName)) {
+      ads.remove(g_wsgName);
     }
-
-    if (!soid.isValid())
-      return;
-
-    std::vector<std::string> imgs = soid.sampleFiles();
-    if (0 >= imgs.size()) {
-      m_view->userWarning(
-          "Error while trying to find image/projection files in the stack "
-          "directories",
-          "Could not find any (image) file in the samples subdirectory: " +
-              soid.sampleImagesDir());
-      return;
+    if (ads.doesExist(g_wsgFlatsName)) {
+      ads.remove(g_wsgFlatsName);
+    }
+    if (ads.doesExist(g_wsgDarksName)) {
+      ads.remove(g_wsgDarksName);
     }
+  } catch (std::runtime_error &rexc) {
+    g_log.warning("There was a problem while trying to remove apparently "
+                  "existing workspaces. Error details: " +
+                  std::string(rexc.what()));
+  }
 
-    loadFITSStack(soid, g_wsgName, g_wsgFlatsName, g_wsgDarksName);
-    m_stackFlats = nullptr;
-    m_stackDarks = nullptr;
+  loadFITSImage(m_stackPath, g_wsgName);
+  setupAlgorithmRunnerAfterLoad();
+}
 
-  } else {
-    // TODO: find a better place for this
-    try {
-      auto &ads = Mantid::API::AnalysisDataService::Instance();
-      if (ads.doesExist(g_wsgName)) {
-        ads.remove(g_wsgName);
-      }
-      if (ads.doesExist(g_wsgFlatsName)) {
-        ads.remove(g_wsgFlatsName);
-      }
-      if (ads.doesExist(g_wsgDarksName)) {
-        ads.remove(g_wsgDarksName);
-      }
-    } catch (std::runtime_error &rexc) {
-      g_log.warning("There was a problem while trying to remove apparently "
-                    "existing workspaces. Error details: " +
-                    std::string(rexc.what()));
-    }
+void ImageROIPresenter::processLoadStackOfImages() {
+  StackOfImagesDirs soid("");
+  try {
+    soid = checkInputStack(m_stackPath);
+  } catch (std::exception &e) {
+    // Poco::FileNotFoundException: this should never happen, unless
+    // the open dir dialog misbehaves unexpectedly, or in tests
+    m_view->userWarning("Error trying to open directories/files",
+                        "The path selected via the dialog cannot be openend or "
+                        "there was a problem while trying to access it. This "
+                        "is an unexpected inconsistency. Error details: " +
+                            std::string(e.what()));
+  }
+
+  if (!soid.isValid())
+    return;
 
-    loadFITSImage(m_stackPath, g_wsgName);
+  std::vector<std::string> imgs = soid.sampleFiles();
+  if (0 >= imgs.size()) {
+    m_view->userWarning(
+        "Error while trying to find image/projection files in the stack "
+        "directories",
+        "Could not find any (image) file in the samples subdirectory: " +
+            soid.sampleImagesDir());
+    return;
   }
 
+  loadFITSStack(soid, g_wsgName, g_wsgFlatsName, g_wsgDarksName);
+  m_stackFlats = nullptr;
+  m_stackDarks = nullptr;
+  setupAlgorithmRunnerAfterLoad();
+}
+
+void ImageROIPresenter::setupAlgorithmRunnerAfterLoad() {
+  // reset any previous connections
+  m_algRunner.get()->disconnect();
   connect(m_algRunner.get(), SIGNAL(batchComplete(bool)), this,
           SLOT(finishedLoadStack(bool)), Qt::QueuedConnection);
 
diff --git a/MantidQt/CustomInterfaces/src/Tomography/ImageROIViewQtWidget.cpp b/MantidQt/CustomInterfaces/src/Tomography/ImageROIViewQtWidget.cpp
index 56e0b1ea8d526fb6703d6f404090f6c4d6f8c2c1..bc9839db3884a9c21bc54946ed02375e1b0c6538 100644
--- a/MantidQt/CustomInterfaces/src/Tomography/ImageROIViewQtWidget.cpp
+++ b/MantidQt/CustomInterfaces/src/Tomography/ImageROIViewQtWidget.cpp
@@ -481,6 +481,9 @@ void ImageROIViewQtWidget::refreshROIetAl() {
   if (!pp)
     return;
 
+  m_ui.label_img->setMaximumWidth(static_cast<int>(m_imgWidth));
+  m_ui.label_img->setMaximumHeight(static_cast<int>(m_imgHeight));
+
   QPixmap toDisplay(*m_basePixmap.get());
   QPainter painter(&toDisplay);
 
diff --git a/MantidQt/CustomInterfaces/src/Tomography/TomoToolConfigDialog.cpp b/MantidQt/CustomInterfaces/src/Tomography/TomoToolConfigDialog.cpp
deleted file mode 100644
index 4496f36783a6646cee1d0d309af1272cb9590d6f..0000000000000000000000000000000000000000
--- a/MantidQt/CustomInterfaces/src/Tomography/TomoToolConfigDialog.cpp
+++ /dev/null
@@ -1,49 +0,0 @@
-#include "MantidQtCustomInterfaces/Tomography/TomoToolConfigDialog.h"
-
-namespace MantidQt {
-namespace CustomInterfaces {
-
-TomoToolConfigTomoPy::TomoToolConfigTomoPy(QWidget *parent) : QDialog(parent) {}
-
-TomoToolConfigSavu::TomoToolConfigSavu(QWidget *parent) : QMainWindow(parent) {}
-
-TomoToolConfigAstra::TomoToolConfigAstra(QWidget *parent) : QDialog(parent) {}
-
-TomoToolConfigCustom::TomoToolConfigCustom(QWidget *parent) : QDialog(parent) {}
-
-TomoToolConfigDialog::TomoToolConfigDialog(QWidget *parent) : QDialog(parent) {
-  labelRun = new QLabel("Runnable script");
-  editRun = new QLineEdit("/work/imat/");
-  hRun = new QHBoxLayout();
-  hRun->addWidget(labelRun);
-  hRun->addWidget(editRun);
-
-  labelOpt = new QLabel("Command line options");
-  editOpt = new QLineEdit("/work/imat");
-  hOpt = new QHBoxLayout();
-  hOpt->addWidget(labelOpt);
-
-  hOpt->addWidget(editOpt);
-
-  okButton = new QPushButton("Ok");
-  cancelButton = new QPushButton("Cancel");
-  hBut = new QHBoxLayout();
-  hBut->insertStretch(0, 1);
-  hBut->addWidget(okButton);
-  hBut->addWidget(cancelButton);
-
-  layout = new QGridLayout();
-  layout->addLayout(hRun, 0, 0);
-  layout->addLayout(hOpt, 1, 0);
-  layout->addLayout(hOpt, 2, 0);
-
-  connect(okButton, SIGNAL(clicked()), this, SLOT(okClicked()));
-  connect(cancelButton, SIGNAL(clicked()), this, SLOT(cancelClicked()));
-}
-
-void TomoToolConfigDialog::okClicked() {}
-
-void TomoToolConfigDialog::cancelClicked() {}
-
-} // namespace CustomInterfaces
-} // namespace MantidQt
diff --git a/MantidQt/CustomInterfaces/src/Tomography/TomoToolConfigDialogAstra.cpp b/MantidQt/CustomInterfaces/src/Tomography/TomoToolConfigDialogAstra.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..61cf5f5c3ef14c6dc0e5b85cb14adcfffc8ece1c
--- /dev/null
+++ b/MantidQt/CustomInterfaces/src/Tomography/TomoToolConfigDialogAstra.cpp
@@ -0,0 +1,45 @@
+#include "MantidQtCustomInterfaces/Tomography/TomoToolConfigDialogAstra.h"
+#include "MantidQtCustomInterfaces/Tomography/ToolConfigAstraToolbox.h"
+#include "MantidQtCustomInterfaces/Tomography/TomoReconToolsUserSettings.h"
+
+namespace MantidQt {
+namespace CustomInterfaces {
+
+const std::string TomoToolConfigDialogAstra::DEFAULT_TOOL_NAME = "Astra";
+const std::string TomoToolConfigDialogAstra::DEFAULT_TOOL_METHOD = "FBP3D_CUDA";
+
+void TomoToolConfigDialogAstra::setupDialogUi() {
+  m_astraUi.setupUi(m_dialog);
+  m_astraUi.comboBox_method->clear();
+  const auto &methods = getToolMethods();
+  for (auto &method : methods) {
+    m_astraUi.comboBox_method->addItem(QString::fromStdString(method.second));
+  }
+}
+
+void TomoToolConfigDialogAstra::initialiseDialog() { m_dialog = new QDialog; }
+
+void TomoToolConfigDialogAstra::setupToolSettingsFromPaths() {
+  m_toolSettings = std::make_shared<ToolConfigAstraToolbox>(
+      m_runPath, m_pathOut + m_localOutNameAppendix, m_paths.pathDarks(),
+      m_paths.pathOpenBeam(), m_paths.pathSamples());
+}
+
+void TomoToolConfigDialogAstra::setupMethodSelected() {
+  const auto &methods = getToolMethods();
+
+  const int mi = m_astraUi.comboBox_method->currentIndex();
+  m_toolMethod = methods[mi].first;
+}
+
+/** Calls the execute of the QDialog
+*/
+int TomoToolConfigDialogAstra::executeQt() { return m_dialog->exec(); }
+
+std::vector<std::pair<std::string, std::string>>
+TomoToolConfigDialogAstra::getToolMethods() {
+  return ToolConfigAstraToolbox::methods();
+}
+
+} // CustomInterfaces
+} // MantidQt
\ No newline at end of file
diff --git a/MantidQt/CustomInterfaces/src/Tomography/TomoToolConfigDialogBase.cpp b/MantidQt/CustomInterfaces/src/Tomography/TomoToolConfigDialogBase.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5d95af10cf482b869de1302f72f7abe8a6bac7d9
--- /dev/null
+++ b/MantidQt/CustomInterfaces/src/Tomography/TomoToolConfigDialogBase.cpp
@@ -0,0 +1,36 @@
+#include "MantidQtCustomInterfaces/Tomography/TomoToolConfigDialogBase.h"
+#include "MantidQtCustomInterfaces/Tomography/TomoToolConfigDialogTomoPy.h"
+#include "MantidQtCustomInterfaces/Tomography/TomoToolConfigDialogAstra.h"
+#include "MantidQtCustomInterfaces/Tomography/TomoToolConfigDialogSavu.h"
+#include "MantidQtCustomInterfaces/Tomography/TomoToolConfigDialogCustom.h"
+
+#include "MantidKernel/make_unique.h"
+
+namespace MantidQt {
+namespace CustomInterfaces {
+
+std::unique_ptr<TomoToolConfigDialogBase>
+TomoToolConfigDialogBase::getToolDialogFor(const std::string &toolName) {
+
+  if (toolName == "TomoPy") {
+    return Mantid::Kernel::make_unique<TomoToolConfigDialogTomoPy>();
+  } else if (toolName == "Astra") {
+    return Mantid::Kernel::make_unique<TomoToolConfigDialogAstra>();
+  } else if (toolName == "Savu") {
+    return Mantid::Kernel::make_unique<TomoToolConfigDialogSavu>();
+  } else if (toolName == "Custom command") {
+    return Mantid::Kernel::make_unique<TomoToolConfigDialogCustom>();
+  }
+  // tool doesn't exist, return nullptr
+  return nullptr;
+}
+
+void TomoToolConfigDialogBase::handleDialogResult(const int result) {
+  if (QDialog::Accepted == result) {
+    // setup the new settings if the user has Accepted
+    setupMethodSelected();
+    setupToolSettingsFromPaths();
+  }
+}
+} // namespace CustomInterfaces
+} // namespace MantidQt
diff --git a/MantidQt/CustomInterfaces/src/Tomography/TomoToolConfigDialogCustom.cpp b/MantidQt/CustomInterfaces/src/Tomography/TomoToolConfigDialogCustom.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f8e31af5914780682614b4320f419963f59165bc
--- /dev/null
+++ b/MantidQt/CustomInterfaces/src/Tomography/TomoToolConfigDialogCustom.cpp
@@ -0,0 +1,71 @@
+#include "MantidQtCustomInterfaces/Tomography/TomoToolConfigDialogCustom.h"
+#include "MantidQtCustomInterfaces/Tomography/ToolConfigCustom.h"
+
+namespace MantidQt {
+namespace CustomInterfaces {
+
+const std::string TomoToolConfigDialogCustom::DEFAULT_TOOL_NAME =
+    "Custom command";
+
+// custom tool doesn't have a default method
+const std::string TomoToolConfigDialogCustom::DEFAULT_TOOL_METHOD = "";
+
+std::string TomoToolConfigDialogCustom::m_backupCommandLine = "";
+
+/** Reads the current strings in the dialogue and creates
+* the tool settings from them. If the dialogue is not initialised yet
+* the strings will be empty, thus we put the default values
+*/
+void TomoToolConfigDialogCustom::setupToolSettingsFromPaths() {
+
+  if (m_isInitialised) {
+    // None of the other paths matter, because the user could've changed
+    // them, so ignore them and load the current ones on the dialogue
+    const std::string run =
+        m_customUi.lineEdit_runnable->text().toStdString(); // current path
+    const std::string opts = m_customUi.textEdit_cl_opts->toPlainText()
+                                 .toStdString(); // current commands
+
+    // update the settings with the newest information
+    m_toolSettings = std::make_shared<ToolConfigCustom>(run, opts);
+  } else {
+    // create settings with the default values
+    m_toolSettings = std::make_shared<ToolConfigCustom>(m_runPath, "--help");
+  }
+}
+
+void TomoToolConfigDialogCustom::setupMethodSelected() {
+
+  // sets the current runnable path, overriding the default one
+  m_customUi.lineEdit_runnable->setText(QString::fromStdString(m_runPath));
+}
+
+void TomoToolConfigDialogCustom::setupDialogUi() {
+  m_customUi.setupUi(m_dialog);
+
+  if (m_backupCommandLine != "") {
+    m_customUi.textEdit_cl_opts->setText(
+        QString::fromStdString(m_backupCommandLine));
+  }
+
+  // get default options from command line
+  const std::string opts =
+      m_customUi.textEdit_cl_opts->toPlainText().toStdString();
+
+  // create the default settings
+  m_toolSettings = std::make_shared<ToolConfigCustom>(m_runPath, opts);
+}
+
+void TomoToolConfigDialogCustom::initialiseDialog() { m_dialog = new QDialog; }
+
+void TomoToolConfigDialogCustom::handleDialogResult(int result) {
+  if (QDialog::Accepted == result) {
+    // if accepted we want to save the information
+    m_backupCommandLine =
+        m_customUi.textEdit_cl_opts->toPlainText().toStdString();
+    setupToolSettingsFromPaths();
+  }
+}
+int TomoToolConfigDialogCustom::executeQt() { return m_dialog->exec(); }
+} // CustomInterfaces
+} // MantidQt
\ No newline at end of file
diff --git a/MantidQt/CustomInterfaces/src/Tomography/SavuConfigDialog.cpp b/MantidQt/CustomInterfaces/src/Tomography/TomoToolConfigDialogSavu.cpp
similarity index 58%
rename from MantidQt/CustomInterfaces/src/Tomography/SavuConfigDialog.cpp
rename to MantidQt/CustomInterfaces/src/Tomography/TomoToolConfigDialogSavu.cpp
index 0c2f23c5077750a3f4b96d257f574c8a3294f734..2d3aa5a774949080e47416c69eda0107444e5966 100644
--- a/MantidQt/CustomInterfaces/src/Tomography/SavuConfigDialog.cpp
+++ b/MantidQt/CustomInterfaces/src/Tomography/TomoToolConfigDialogSavu.cpp
@@ -1,23 +1,92 @@
-#include "MantidAPI/AlgorithmManager.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/ITableWorkspace.h"
 #include "MantidQtCustomInterfaces/Tomography/TomographyIfaceViewQtGUI.h"
 
 #include <boost/lexical_cast.hpp>
+#include "MantidQtCustomInterfaces/Tomography/TomoToolConfigDialogSavu.h"
+#include "MantidQtCustomInterfaces/Tomography/TomoReconToolsUserSettings.h"
 
+#include <MantidAPI/TableRow.h>
+#include <MantidAPI/WorkspaceFactory.h>
 #include <Poco/String.h>
-
+#include <json/reader.h>
+#include <MantidAPI/NotebookWriter.h>
 #include <QFileDialog>
 #include <QMessageBox>
+#include <MantidAPI/AlgorithmManager.h>
 
 using namespace Mantid::API;
 
 namespace MantidQt {
 namespace CustomInterfaces {
 
+TomoToolConfigDialogSavu::TomoToolConfigDialogSavu(QWidget *parent)
+    : QMainWindow(parent) {
+  // TODO init the 545231453t54 variables
+  m_availPlugins = Mantid::API::WorkspaceFactory::Instance().createTable();
+  m_availPlugins->addColumns("str", "name", 4);
+  m_currPlugins = Mantid::API::WorkspaceFactory::Instance().createTable();
+  m_currPlugins->addColumns("str", "name", 4);
+}
+
+int TomoToolConfigDialogSavu::executeQt() {
+  this->show();
+  QEventLoop el;
+  connect(this, SIGNAL(destroyed()), &el, SLOT(quit()));
+  return el.exec();
+}
+
+void TomoToolConfigDialogSavu::initialiseDialog() {
+  throw Mantid::Kernel::Exception::NotImplementedError(
+      "SAVU interface not implemented");
+}
+void TomoToolConfigDialogSavu::setupMethodSelected() {
+  throw Mantid::Kernel::Exception::NotImplementedError(
+      "SAVU interface not implemented");
+}
+void TomoToolConfigDialogSavu::setupToolSettingsFromPaths() {
+  throw Mantid::Kernel::Exception::NotImplementedError(
+      "SAVU interface not implemented");
+}
+
+void TomoToolConfigDialogSavu::setupDialogUi() {
+  m_savuUi.setupUi(this);
+  initSavuWindow();
+  this->setWindowModality(Qt::ApplicationModal);
+}
+
+void TomoToolConfigDialogSavu::initSavuWindow() {
+  // geometry, etc. niceties
+  // on the left (just plugin names) 1/2, right: 2/3
+  QList<int> sizes{100, 200};
+  m_savuUi.splitterPlugins->setSizes(std::move(sizes));
+
+  // Setup Parameter editor tab
+  loadAvailablePlugins();
+  m_savuUi.treeCurrentPlugins->setHeaderHidden(true);
+
+  // Connect slots
+  // Lists/trees
+  connect(m_savuUi.listAvailablePlugins, SIGNAL(itemSelectionChanged()), this,
+          SLOT(availablePluginSelected()));
+  connect(m_savuUi.treeCurrentPlugins, SIGNAL(itemSelectionChanged()), this,
+          SLOT(currentPluginSelected()));
+  connect(m_savuUi.treeCurrentPlugins, SIGNAL(itemExpanded(QTreeWidgetItem *)),
+          this, SLOT(expandedItem(QTreeWidgetItem *)));
+
+  // Buttons
+  connect(m_savuUi.btnTransfer, SIGNAL(released()), this,
+          SLOT(transferClicked()));
+  connect(m_savuUi.btnMoveUp, SIGNAL(released()), this, SLOT(moveUpClicked()));
+  connect(m_savuUi.btnMoveDown, SIGNAL(released()), this,
+          SLOT(moveDownClicked()));
+  connect(m_savuUi.btnRemove, SIGNAL(released()), this, SLOT(removeClicked()));
+}
+
 // TODO: what's in this file should become a class of its own,
 // 'SavuConfigDialog' or similar
 
-void TomographyIfaceViewQtGUI::loadAvailablePlugins() {
+void TomoToolConfigDialogSavu::loadAvailablePlugins() {
   // TODO:: load actual plugins when we know them
   // creating a few relatively realistic choices for now (should crossh check
   //  with the savu api when finalized).
@@ -61,48 +130,49 @@ void TomographyIfaceViewQtGUI::loadAvailablePlugins() {
 
 // Reloads the GUI list of available plugins from the data object ::
 // Populating only through this ensures correct indexing.
-void TomographyIfaceViewQtGUI::refreshAvailablePluginListUI() {
+void TomoToolConfigDialogSavu::refreshAvailablePluginListUI() {
   // Table WS structure, id/params/name/cite
-  m_uiSavu.listAvailablePlugins->clear();
-  for (size_t i = 0; i < m_availPlugins->rowCount(); ++i) {
-    QString str =
+  m_savuUi.listAvailablePlugins->clear();
+  const size_t rowcount = m_availPlugins->rowCount();
+  for (size_t i = 0; i < rowcount; ++i) {
+    const QString str =
         QString::fromStdString(m_availPlugins->cell<std::string>(i, 2));
-    m_uiSavu.listAvailablePlugins->addItem(str);
+    m_savuUi.listAvailablePlugins->addItem(std::move(str));
   }
 }
 
 // Reloads the GUI list of current plugins from the data object ::
 // Populating only through this ensures correct indexing.
-void TomographyIfaceViewQtGUI::refreshCurrentPluginListUI() {
+void TomoToolConfigDialogSavu::refreshCurrentPluginListUI() {
   // Table WS structure, id/params/name/cite
-  m_uiSavu.treeCurrentPlugins->clear();
+  m_savuUi.treeCurrentPlugins->clear();
   createPluginTreeEntries(m_currPlugins);
 }
 
 // Updates the selected plugin info from Available plugins list.
-void TomographyIfaceViewQtGUI::availablePluginSelected() {
-  if (m_uiSavu.listAvailablePlugins->selectedItems().count() != 0) {
-    size_t idx = static_cast<size_t>(
-        m_uiSavu.listAvailablePlugins->currentIndex().row());
+void TomoToolConfigDialogSavu::availablePluginSelected() {
+  if (m_savuUi.listAvailablePlugins->selectedItems().count() != 0) {
+    const size_t idx = static_cast<size_t>(
+        m_savuUi.listAvailablePlugins->currentIndex().row());
     if (idx < m_availPlugins->rowCount()) {
-      m_uiSavu.availablePluginDesc->setText(
+      m_savuUi.availablePluginDesc->setText(
           tableWSRowToString(m_availPlugins, idx));
     }
   }
 }
 
 // Updates the selected plugin info from Current plugins list.
-void TomographyIfaceViewQtGUI::currentPluginSelected() {
-  if (m_uiSavu.treeCurrentPlugins->selectedItems().count() != 0) {
-    auto currItem = m_uiSavu.treeCurrentPlugins->selectedItems()[0];
+void TomoToolConfigDialogSavu::currentPluginSelected() {
+  if (m_savuUi.treeCurrentPlugins->selectedItems().count() != 0) {
+    auto currItem = m_savuUi.treeCurrentPlugins->selectedItems()[0];
 
     while (currItem->parent() != NULL)
       currItem = currItem->parent();
 
     int topLevelIndex =
-        m_uiSavu.treeCurrentPlugins->indexOfTopLevelItem(currItem);
+        m_savuUi.treeCurrentPlugins->indexOfTopLevelItem(currItem);
 
-    m_uiSavu.currentPluginDesc->setText(
+    m_savuUi.currentPluginDesc->setText(
         tableWSRowToString(m_currPlugins, topLevelIndex));
   }
 }
@@ -134,7 +204,7 @@ private:
 };
 
 // On user editing a parameter tree item, update the data object to match.
-void TomographyIfaceViewQtGUI::paramValModified(QTreeWidgetItem *item,
+void TomoToolConfigDialogSavu::paramValModified(QTreeWidgetItem *item,
                                                 int /*column*/) {
   OwnTreeWidgetItem *ownItem = dynamic_cast<OwnTreeWidgetItem *>(item);
   if (!ownItem)
@@ -142,7 +212,7 @@ void TomographyIfaceViewQtGUI::paramValModified(QTreeWidgetItem *item,
 
   int topLevelIndex = -1;
   if (ownItem->getRootParent() != NULL) {
-    topLevelIndex = m_uiSavu.treeCurrentPlugins->indexOfTopLevelItem(
+    topLevelIndex = m_savuUi.treeCurrentPlugins->indexOfTopLevelItem(
         ownItem->getRootParent());
   }
   if (-1 == topLevelIndex)
@@ -169,7 +239,7 @@ void TomographyIfaceViewQtGUI::paramValModified(QTreeWidgetItem *item,
 
 // When a top level item is expanded, also expand its child items - if tree
 // items
-void TomographyIfaceViewQtGUI::expandedItem(QTreeWidgetItem *item) {
+void TomoToolConfigDialogSavu::expandedItem(QTreeWidgetItem *item) {
   if (item->parent() == NULL) {
     for (int i = 0; i < item->childCount(); ++i) {
       item->child(i)->setExpanded(true);
@@ -179,28 +249,31 @@ void TomographyIfaceViewQtGUI::expandedItem(QTreeWidgetItem *item) {
 
 // Adds one plugin from the available plugins list into the list of
 // current plugins
-void TomographyIfaceViewQtGUI::transferClicked() {
-  if (0 == m_uiSavu.listAvailablePlugins->selectedItems().count())
+void TomoToolConfigDialogSavu::transferClicked() {
+  if (0 == m_savuUi.listAvailablePlugins->selectedItems().count())
     return;
 
-  int idx = m_uiSavu.listAvailablePlugins->currentIndex().row();
+  const int idx = m_savuUi.listAvailablePlugins->currentIndex().row();
+  const size_t columnCount = m_currPlugins->columnCount();
+
   Mantid::API::TableRow row = m_currPlugins->appendRow();
-  for (size_t j = 0; j < m_currPlugins->columnCount(); ++j) {
+  for (size_t j = 0; j < columnCount; ++j) {
     row << m_availPlugins->cell<std::string>(idx, j);
   }
   createPluginTreeEntry(row);
 }
 
-void TomographyIfaceViewQtGUI::moveUpClicked() {
-  if (0 == m_uiSavu.treeCurrentPlugins->selectedItems().count())
+void TomoToolConfigDialogSavu::moveUpClicked() {
+  if (0 == m_savuUi.treeCurrentPlugins->selectedItems().count())
     return;
 
-  size_t idx =
-      static_cast<size_t>(m_uiSavu.treeCurrentPlugins->currentIndex().row());
+  const size_t idx =
+      static_cast<size_t>(m_savuUi.treeCurrentPlugins->currentIndex().row());
   if (idx > 0 && idx < m_currPlugins->rowCount()) {
     // swap row, all columns
-    for (size_t j = 0; j < m_currPlugins->columnCount(); ++j) {
-      std::string swap = m_currPlugins->cell<std::string>(idx, j);
+    const size_t columnCount = m_currPlugins->columnCount();
+    for (size_t j = 0; j < columnCount; ++j) {
+      const std::string swap = m_currPlugins->cell<std::string>(idx, j);
       m_currPlugins->cell<std::string>(idx, j) =
           m_currPlugins->cell<std::string>(idx - 1, j);
       m_currPlugins->cell<std::string>(idx - 1, j) = swap;
@@ -209,17 +282,19 @@ void TomographyIfaceViewQtGUI::moveUpClicked() {
   }
 }
 
-void TomographyIfaceViewQtGUI::moveDownClicked() {
+void TomoToolConfigDialogSavu::moveDownClicked() {
   // TODO: this can be done with the same function as above...
-  if (0 == m_uiSavu.treeCurrentPlugins->selectedItems().count())
+  if (0 == m_savuUi.treeCurrentPlugins->selectedItems().count())
     return;
 
-  size_t idx =
-      static_cast<size_t>(m_uiSavu.treeCurrentPlugins->currentIndex().row());
+  const size_t idx =
+      static_cast<size_t>(m_savuUi.treeCurrentPlugins->currentIndex().row());
   if (idx < m_currPlugins->rowCount() - 1) {
     // swap all columns
-    for (size_t j = 0; j < m_currPlugins->columnCount(); ++j) {
-      std::string swap = m_currPlugins->cell<std::string>(idx, j);
+
+    const size_t columnCount = m_currPlugins->columnCount();
+    for (size_t j = 0; j < columnCount; ++j) {
+      const std::string swap = m_currPlugins->cell<std::string>(idx, j);
       m_currPlugins->cell<std::string>(idx, j) =
           m_currPlugins->cell<std::string>(idx + 1, j);
       m_currPlugins->cell<std::string>(idx + 1, j) = swap;
@@ -228,18 +303,18 @@ void TomographyIfaceViewQtGUI::moveDownClicked() {
   }
 }
 
-void TomographyIfaceViewQtGUI::removeClicked() {
+void TomoToolConfigDialogSavu::removeClicked() {
   // Also clear ADS entries
-  if (0 == m_uiSavu.treeCurrentPlugins->selectedItems().count())
+  if (0 == m_savuUi.treeCurrentPlugins->selectedItems().count())
     return;
 
-  int idx = m_uiSavu.treeCurrentPlugins->currentIndex().row();
+  const int idx = m_savuUi.treeCurrentPlugins->currentIndex().row();
   m_currPlugins->removeRow(idx);
 
   refreshCurrentPluginListUI();
 }
 
-void TomographyIfaceViewQtGUI::menuOpenClicked() {
+void TomoToolConfigDialogSavu::menuOpenClicked() {
   QString s = QFileDialog::getOpenFileName(0, "Open file", QDir::currentPath(),
                                            "NeXus files (*.nxs);;All files (*)",
                                            new QString("NeXus files (*.nxs)"));
@@ -268,7 +343,37 @@ void TomographyIfaceViewQtGUI::menuOpenClicked() {
   }
 }
 
-void TomographyIfaceViewQtGUI::menuSaveClicked() {
+/**
+* Load a savu tomo config file into the current plugin list, overwriting it.
+* Uses the algorithm LoadSavuTomoConfig
+*/
+void TomoToolConfigDialogSavu::loadSavuTomoConfig(
+    std::string &filePath, Mantid::API::ITableWorkspace_sptr &currentPlugins) {
+  // try to load tomo reconstruction parametereization file
+  auto alg = Mantid::API::AlgorithmManager::Instance().createUnmanaged(
+      "LoadSavuTomoConfig");
+  alg->initialize();
+  alg->setPropertyValue("Filename", filePath);
+  alg->setPropertyValue("OutputWorkspace", createUniqueNameHidden());
+  try {
+    alg->execute();
+  } catch (std::runtime_error &e) {
+    throw std::runtime_error(
+        std::string("Error when trying to load tomographic reconstruction "
+                    "parameter file: ") +
+        e.what());
+  }
+
+  // new processing plugins list
+  try {
+    currentPlugins = alg->getProperty("OutputWorkspace");
+  } catch (std::exception &e) {
+    userError("Could not load config file", "Failed to load the file "
+                                            "with the following error: " +
+                                                std::string(e.what()));
+  }
+}
+void TomoToolConfigDialogSavu::menuSaveClicked() {
   if (m_currentParamPath.empty()) {
     menuSaveAsClicked();
     return;
@@ -282,7 +387,7 @@ void TomographyIfaceViewQtGUI::menuSaveClicked() {
   } else {
     AnalysisDataService::Instance().add(createUniqueNameHidden(),
                                         m_currPlugins);
-    std::string csvWorkspaceNames = m_currPlugins->name();
+    std::string csvWorkspaceNames = m_currPlugins->getName();
 
     auto alg = Mantid::API::AlgorithmManager::Instance().createUnmanaged(
         "SaveTomoConfig");
@@ -296,8 +401,21 @@ void TomographyIfaceViewQtGUI::menuSaveClicked() {
     }
   }
 }
+size_t TomoToolConfigDialogSavu::g_nameSeqNo = 0;
+
+// Build a unique (and hidden) name for the table ws
+std::string TomoToolConfigDialogSavu::createUniqueNameHidden() {
+  std::string name;
+  do {
+    // with __ prefix => hidden
+    name = "__TomoConfigTableWS_Seq_" +
+           boost::lexical_cast<std::string>(g_nameSeqNo++);
+  } while (AnalysisDataService::Instance().doesExist(name));
+
+  return name;
+}
 
-void TomographyIfaceViewQtGUI::menuSaveAsClicked() {
+void TomoToolConfigDialogSavu::menuSaveAsClicked() {
   QString s = QFileDialog::getSaveFileName(0, "Save file", QDir::currentPath(),
                                            "NeXus files (*.nxs);;All files (*)",
                                            new QString("NeXus files (*.nxs)"));
@@ -309,7 +427,7 @@ void TomographyIfaceViewQtGUI::menuSaveAsClicked() {
   menuSaveClicked();
 }
 
-QString TomographyIfaceViewQtGUI::tableWSRowToString(ITableWorkspace_sptr table,
+QString TomoToolConfigDialogSavu::tableWSRowToString(ITableWorkspace_sptr table,
                                                      size_t i) {
   std::stringstream msg;
   msg << "ID: " << table->cell<std::string>(i, 0)
@@ -320,11 +438,11 @@ QString TomographyIfaceViewQtGUI::tableWSRowToString(ITableWorkspace_sptr table,
 }
 
 /**
- * Creates a treewidget item for a row of a table workspace.
- *
- * @param row Row from a table workspace with each row specfying a savu plugin
- */
-void TomographyIfaceViewQtGUI::createPluginTreeEntry(TableRow &row) {
+* Creates a treewidget item for a row of a table workspace.
+*
+* @param row Row from a table workspace with each row specfying a savu plugin
+*/
+void TomoToolConfigDialogSavu::createPluginTreeEntry(TableRow &row) {
   QStringList idStr, nameStr, citeStr, paramsStr;
   idStr.push_back(QString::fromStdString("ID: " + row.cell<std::string>(0)));
   nameStr.push_back(
@@ -389,27 +507,27 @@ void TomographyIfaceViewQtGUI::createPluginTreeEntry(TableRow &row) {
       layout->addWidget(paramContainerTree);
 
       pluginParamsItem->addChild(container);
-      m_uiSavu.treeCurrentPlugins->setItemWidget(container, 0, w);
+      m_savuUi.treeCurrentPlugins->setItemWidget(container, 0, w);
     }
   }
 
   pluginBaseItem->addChildren(items);
-  m_uiSavu.treeCurrentPlugins->addTopLevelItem(pluginBaseItem);
+  m_savuUi.treeCurrentPlugins->addTopLevelItem(pluginBaseItem);
 }
 
 /**
- * This is a kind of .asString() method for arrays. It iterates
- * through the array elements and builds the string enclosed by [].
- *
- * @param jsonVal Value of a parameter that seems to be an array
- *(isArray()==true)
- * @param name Name of the parameter (to give informative messages)
- *
- * @return String with a parameter value(s), enclosed by [] and
- * separated by commas
- */
+* This is a kind of .asString() method for arrays. It iterates
+* through the array elements and builds the string enclosed by [].
+*
+* @param jsonVal Value of a parameter that seems to be an array
+*(isArray()==true)
+* @param name Name of the parameter (to give informative messages)
+*
+* @return String with a parameter value(s), enclosed by [] and
+* separated by commas
+*/
 std::string
-TomographyIfaceViewQtGUI::paramValStringFromArray(const Json::Value &jsonVal,
+TomoToolConfigDialogSavu::paramValStringFromArray(const Json::Value &jsonVal,
                                                   const std::string &name) {
   std::string s;
   s = "[";
@@ -442,16 +560,16 @@ TomographyIfaceViewQtGUI::paramValStringFromArray(const Json::Value &jsonVal,
 }
 
 /**
- * Build a string with the value of a parameter in a json
- * string. Works for scalar and list/array values.
- *
- * @param jsonVal Value of a parameter that seems to be an array
- * @param name Name of the parameter (to give informative messages)
- *
- * @return String with a parameter value
- */
+* Build a string with the value of a parameter in a json
+* string. Works for scalar and list/array values.
+*
+* @param jsonVal Value of a parameter that seems to be an array
+* @param name Name of the parameter (to give informative messages)
+*
+* @return String with a parameter value
+*/
 std::string
-TomographyIfaceViewQtGUI::pluginParamValString(const Json::Value &jsonVal,
+TomoToolConfigDialogSavu::pluginParamValString(const Json::Value &jsonVal,
                                                const std::string &name) {
   std::string s;
   // string and numeric values can (normally) be converted to string but arrays
@@ -474,13 +592,41 @@ TomographyIfaceViewQtGUI::pluginParamValString(const Json::Value &jsonVal,
   return s;
 }
 
-void TomographyIfaceViewQtGUI::createPluginTreeEntries(
-    ITableWorkspace_sptr table) {
+void TomoToolConfigDialogSavu::createPluginTreeEntries(
+    Mantid::API::ITableWorkspace_sptr table) {
   for (size_t i = 0; i < table->rowCount(); ++i) {
-    TableRow r = table->getRow(i);
+    Mantid::API::TableRow r = table->getRow(i);
     createPluginTreeEntry(r);
   }
 }
 
+/** TODO move into a class, extract from here and QtView interface
+* Show an error (serious) message to the user (pop up)
+*
+* @param err Basic error title
+* @param description More detailed explanation, hints, additional
+* information, etc.
+*/
+void TomoToolConfigDialogSavu::userError(const std::string &err,
+                                         const std::string &description) {
+  QMessageBox::critical(this, QString::fromStdString(err),
+                        QString::fromStdString(description), QMessageBox::Ok,
+                        QMessageBox::Ok);
+}
+
+/**
+* Show a warning message to the user (pop up)
+*
+* @param err Basic error title
+* @param description More detailed explanation, hints, additional
+* information, etc.
+*/
+void TomoToolConfigDialogSavu::userWarning(const std::string &err,
+                                           const std::string &description) {
+  QMessageBox::warning(this, QString::fromStdString(err),
+                       QString::fromStdString(description), QMessageBox::Ok,
+                       QMessageBox::Ok);
+}
+
 } // namespace CustomInterfaces
 } // namespace MantidQt
diff --git a/MantidQt/CustomInterfaces/src/Tomography/TomoToolConfigDialogTomoPy.cpp b/MantidQt/CustomInterfaces/src/Tomography/TomoToolConfigDialogTomoPy.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e20fafd4782e8e61a1469d7ace59ba25c7708055
--- /dev/null
+++ b/MantidQt/CustomInterfaces/src/Tomography/TomoToolConfigDialogTomoPy.cpp
@@ -0,0 +1,47 @@
+#include "MantidQtCustomInterfaces/Tomography/TomoToolConfigDialogTomoPy.h"
+#include "MantidQtCustomInterfaces/Tomography/ToolConfigTomoPy.h"
+
+namespace MantidQt {
+namespace CustomInterfaces {
+
+const std::string TomoToolConfigDialogTomoPy::DEFAULT_TOOL_NAME = "TomoPy";
+const std::string TomoToolConfigDialogTomoPy::DEFAULT_TOOL_METHOD = "gridrec";
+
+void TomoToolConfigDialogTomoPy::setupDialogUi() {
+  m_tomoPyUi.setupUi(m_dialog);
+  m_tomoPyUi.comboBox_method->clear();
+
+  const auto &methods = getToolMethods();
+  for (auto &method : methods) {
+    m_tomoPyUi.comboBox_method->addItem(QString::fromStdString(method.second));
+  }
+}
+
+void TomoToolConfigDialogTomoPy::initialiseDialog() { m_dialog = new QDialog; }
+
+void TomoToolConfigDialogTomoPy::setupToolSettingsFromPaths() {
+  // TODO: for the output path, probably better to take the sample path,
+  // then up one level
+  m_toolSettings = std::make_shared<ToolConfigTomoPy>(
+      m_runPath, m_pathOut + m_localOutNameAppendix, m_paths.pathDarks(),
+      m_paths.pathOpenBeam(), m_paths.pathSamples());
+}
+void TomoToolConfigDialogTomoPy::setupMethodSelected() {
+  // move to member/global variable and use more space OR keep here
+  const auto &methods = getToolMethods();
+
+  const int mi = m_tomoPyUi.comboBox_method->currentIndex();
+  // TODO maybe comboBox_method->currentText?
+  m_toolMethod = methods[mi].first;
+}
+
+/** Calls the execute of the QDialog
+*/
+int TomoToolConfigDialogTomoPy::executeQt() { return m_dialog->exec(); }
+
+std::vector<std::pair<std::string, std::string>>
+TomoToolConfigDialogTomoPy::getToolMethods() {
+  return ToolConfigTomoPy::methods();
+}
+} // Custominterfaces
+} // MantidQt
diff --git a/MantidQt/CustomInterfaces/src/Tomography/TomographyIfaceModel.cpp b/MantidQt/CustomInterfaces/src/Tomography/TomographyIfaceModel.cpp
index c28ce60e4d593a7c7b820a0a3356a80b34da820b..c6e7c57aafa63d0735d72980f1b578d653482e5f 100644
--- a/MantidQt/CustomInterfaces/src/Tomography/TomographyIfaceModel.cpp
+++ b/MantidQt/CustomInterfaces/src/Tomography/TomographyIfaceModel.cpp
@@ -1,13 +1,15 @@
-#include "MantidKernel/FacilityInfo.h"
-#include "MantidQtAPI/AlgorithmRunner.h"
 #include "MantidAPI/AlgorithmManager.h"
 #include "MantidAPI/MatrixWorkspace.h"
+#include "MantidAPI/WorkspaceGroup.h"
+#include "MantidKernel/FacilityInfo.h"
+#include "MantidQtAPI/AlgorithmRunner.h"
 #include "MantidQtCustomInterfaces/Tomography/TomographyIfaceModel.h"
 
-#include <Poco/Path.h>
-#include <Poco/Process.h>
+#include "MantidQtCustomInterfaces/Tomography/TomographyIfaceModel.h"
+#include "MantidQtCustomInterfaces/Tomography/TomographyProcess.h"
+#include "MantidQtCustomInterfaces/Tomography/TomographyThread.h"
 
-#include <QMutex>
+#include <Poco/Path.h>
 
 #ifndef _WIN32
 // This is exclusively for kill/waitpid (interim solution, see below)
@@ -27,10 +29,13 @@ Mantid::Kernel::Logger g_log("TomographyGUI");
 
 // names by which we know compute resourcess
 const std::string TomographyIfaceModel::g_SCARFName = "SCARF@STFC";
+const std::string TomographyIfaceModel::g_LocalResourceName = "Local";
 
 const std::string TomographyIfaceModel::g_mainReconstructionScript =
     "/Imaging/IMAT/tomo_reconstruct.py";
 
+const std::string TomographyIfaceModel::g_tomoScriptFolderPath = "/scripts";
+
 // names by which we know image/tomography reconstruction tools (3rd party)
 const std::string TomographyIfaceModel::g_TomoPyTool = "TomoPy";
 const std::string TomographyIfaceModel::g_AstraTool = "Astra";
@@ -44,23 +49,17 @@ const std::string TomographyIfaceModel::g_customCmdTool = "Custom command";
  * compute resource.
  */
 TomographyIfaceModel::TomographyIfaceModel()
-    : m_facility("ISIS"), m_localCompName("Local"), m_experimentRef("RB000000"),
-      m_loggedInUser(""), m_loggedInComp(""), m_computeRes(),
-      m_computeResStatus(), m_reconTools(), m_reconToolsStatus(),
-      m_jobsStatus(), m_SCARFtools(), m_toolsSettings(),
-      m_tomopyMethod("gridrec"), m_astraMethod("FBP3D_CUDA"),
-      m_prePostProcSettings(), m_imageStackPreParams(), m_statusMutex(NULL) {
+    : m_facility("ISIS"), m_experimentRef("RB000000"), m_loggedInUser(""),
+      m_loggedInComp(""), m_computeResStatus(), m_reconTools(),
+      m_reconToolsStatus(), m_jobsStatus(), m_prePostProcSettings(),
+      m_imageStackPreParams(), m_statusMutex(NULL) {
 
-  m_computeRes.push_back(g_SCARFName);
-  m_computeRes.push_back(m_localCompName);
+  m_computeRes = {g_SCARFName, g_LocalResourceName};
 
-  m_SCARFtools.push_back(g_TomoPyTool);
-  m_SCARFtools.push_back(g_AstraTool);
-  m_SCARFtools.push_back(g_CCPiTool);
-  m_SCARFtools.push_back(g_SavuTool);
-  m_SCARFtools.push_back(g_customCmdTool);
+  m_SCARFtools = {g_TomoPyTool, g_AstraTool, g_CCPiTool, g_SavuTool,
+                  g_customCmdTool};
 
-  m_currentTool = m_SCARFtools.front();
+  m_currentToolName = m_SCARFtools.front();
 
   m_statusMutex = new QMutex();
 }
@@ -97,13 +96,8 @@ void TomographyIfaceModel::cleanup() {
  */
 std::string
 TomographyIfaceModel::validateCompResource(const std::string &res) const {
-  if (res == m_localCompName) {
-    // Nothing yet
-    // throw std::runtime_error("There is no support for the local compute "
-    //                         "resource. You should not have got here.");
-    // all good at the moment - could do basic validation and checks for
-    // availability of absolutely necessary tools
-    return "local";
+  if (res == g_LocalResourceName) {
+    return g_LocalResourceName;
   }
 
   if (m_computeRes.size() <= 0) {
@@ -200,9 +194,7 @@ void TomographyIfaceModel::setupRunTool(const std::string &compRes) {
   // catch all the useable/relevant tools for the compute
   // resources. For the time being this is rather simple (just
   // SCARF) and will probably stay like this for a while.
-  std::string low = compRes;
-  std::transform(low.begin(), low.end(), low.begin(), tolower);
-  if ("local" == low ||
+  if (g_LocalResourceName == compRes ||
       ("ISIS" == m_facility && (compRes.empty() || g_SCARFName == compRes))) {
     m_reconTools = m_SCARFtools;
   } else {
@@ -334,27 +326,121 @@ void TomographyIfaceModel::doQueryJobStatus(const std::string &compRes,
 }
 
 /**
- * Handle the job submission request relies on a submit algorithm.
+ * Build the components of the command line to run on the remote or local
+ * compute resource. Produces a (normally full) path to a runnable, and
+ * the options (quite like $0 and $* in scripts).
+ *
+ * The local and remote command lines look a bit different:
+ * - local also has the interpreter path at the front: python /scriptPath/
+ * --params..
+ * - remote only has the script path: /scriptPathOnRemote/ --params..
+ *
+ * @param local Is the resource local or remote
+ * @param runnable Path to a runnable application (script, python module, etc.)
+ * @param args A vector that contains all the arguments
+ * @param allOpts The concatenated arguments in a single string
  */
-void TomographyIfaceModel::doSubmitReconstructionJob(
-    const std::string &compRes) {
-  std::string run;
-  std::vector<std::string> args;
-  try {
-    makeRunnableWithOptions(compRes, run, args);
-  } catch (std::exception &e) {
-    g_log.error() << "Could not prepare the requested reconstruction job "
-                     "submission. There was an error: " +
-                         std::string(e.what());
-    throw;
+void TomographyIfaceModel::prepareSubmissionArguments(
+    const bool local, std::string &runnable, std::vector<std::string> &args,
+    std::string &allOpts) {
+  if (!m_currentToolSettings) {
+    throw std::invalid_argument("Settings for tool not set up");
+  }
+  const std::string tool = usingTool();
+  const std::string cmd = m_currentToolSettings->toCommand();
+
+  std::string longOpt;
+  // this gets the runnable from the whole string
+  splitCmdLine(cmd, runnable, longOpt);
+
+  // this is discarded for all tools but the custom command
+  std::string trailingCommands;
+  if (local) {
+    std::string execScriptPath;
+    splitCmdLine(longOpt, execScriptPath, trailingCommands);
+    args.emplace_back(execScriptPath);
   }
 
-  if (run.empty()) {
-    throw std::runtime_error(
-        "The script or executable to run is not defined "
-        "(empty string). You need to setup the reconstruction tool.");
+  if (tool == g_customCmdTool) {
+    // if it's local we need to append the trailingCommands, as the
+    // external interpreter and script path are already appended, the script
+    // path has to be in a separate argument member otherwise running the
+    // external interpreter fails if remote we just want to append all of the
+    // options, the script path is already appended
+    args.emplace_back(local ? trailingCommands : longOpt);
+    allOpts = constructSingleStringFromVector(args);
+    return;
+  }
+
+  // appends the additional options tool name, algorithm name, filters, etc
+  makeTomoRecScriptOptions(local, args);
+
+  checkIfToolIsSetupProperly(tool, cmd, args);
+
+  // used for remote submission
+  allOpts = constructSingleStringFromVector(args);
+
+  logMsg("Running " + usingTool() + ", with binary: " + runnable +
+         ", with parameters: " + allOpts);
+}
+
+/**
+ * Build the command line options string in the way the tomorec
+ * scripts (remote and local) expect it.
+ *
+ * @param local whether to adapt the options for a local run (as
+ * opposed to a remote compute resource)
+ * @param opts The vector of arguments in which the additional
+ * arguments will be inserted
+ * @return command options ready for the tomorec script
+ */
+void TomographyIfaceModel::makeTomoRecScriptOptions(
+    const bool local, std::vector<std::string> &opts) const {
+  // options with all the info from filters and regions
+  // 9 is the current number of arguments being added
+  opts.reserve(9);
+
+  const std::string currentTool = usingTool();
+  const std::string toolNameArg = prepareToolNameForArgs(currentTool);
+
+  const std::string toolArgument = "--tool=" + toolNameArg;
+
+  opts.emplace_back(toolArgument);
+
+  opts.emplace_back("--algorithm=" + m_currentToolMethod);
+
+  // TODO fix proper iterations reading from the interface
+  opts.emplace_back("--num-iter=5");
+
+  filtersCfgToCmdOpts(m_prePostProcSettings, m_imageStackPreParams, local,
+                      opts);
+}
+
+/** Processes the tool name so that it is appropriate for the command line when
+ * executed
+ */
+std::string TomographyIfaceModel::prepareToolNameForArgs(
+    const std::string &toolName) const {
+
+  // the only processing we have for now is converting it to lower case
+  std::string outputString = toolName; // copy over the string
+  std::transform(toolName.cbegin(), toolName.cend(), outputString.begin(),
+                 ::tolower);
+  return outputString;
+}
+
+std::string TomographyIfaceModel::constructSingleStringFromVector(
+    const std::vector<std::string> args) const {
+  std::string allOpts;
+  for (const auto &arg : args) {
+    allOpts += arg + " ";
   }
+  return allOpts;
+}
 
+void TomographyIfaceModel::doRemoteRunReconstructionJob(
+    const std::string &compRes, const std::string &runnable,
+    const std::string &allOpts) {
   // with SCARF we use one (pseudo)-transaction for every submission
   auto transAlg = Mantid::API::AlgorithmManager::Instance().createUnmanaged(
       "StartRemoteTransaction");
@@ -376,11 +462,7 @@ void TomographyIfaceModel::doSubmitReconstructionJob(
   submitAlg->setProperty("ComputeResource", compRes);
   submitAlg->setProperty("TaskName", "Mantid tomographic reconstruction job");
   submitAlg->setProperty("TransactionID", tid);
-  submitAlg->setProperty("ScriptName", run);
-  std::string allOpts;
-  for (const auto &option : args) {
-    allOpts += option + " ";
-  }
+  submitAlg->setProperty("ScriptName", runnable);
   submitAlg->setProperty("ScriptParams", allOpts);
   try {
     submitAlg->execute();
@@ -391,6 +473,37 @@ void TomographyIfaceModel::doSubmitReconstructionJob(
   }
 }
 
+/** Starts the local thread with the external reconstruction process
+ * @param runnable Path to a runnable application (script, python module, etc.)
+ * @param args A vector that contains all the arguments
+ * @param allOpts The concatenated arguments in a single string
+ * @param thread This thread will be started after the worker is set up with the
+ *    runnable and the arguments
+ * @param worker The worker will only be set up with the runnable and arguments
+ */
+void TomographyIfaceModel::doLocalRunReconstructionJob(
+    const std::string &runnable, const std::vector<std::string> &args,
+    const std::string &allOpts, TomographyThread &thread,
+    TomographyProcess &worker) {
+
+  // Can only run one reconstruction at a time
+  // Qt doesn't use exceptions so we can't make sure it ran here
+  worker.setup(runnable, args, allOpts);
+  thread.start();
+}
+
+void TomographyIfaceModel::addJobToStatus(const qint64 pid,
+                                          const std::string &runnable,
+                                          const std::string &allOpts) {
+  Mantid::API::IRemoteJobManager::RemoteJobInfo info;
+  info.id = boost::lexical_cast<std::string>(pid);
+  info.name = pid > 0 ? "Mantid_Local" : "none";
+  info.status = pid > 0 ? "Starting" : "Exit";
+  info.cmdLine = runnable + " " + allOpts;
+  m_jobsStatusLocal.emplace_back(info);
+  doRefreshJobsInfo(g_LocalResourceName);
+}
+
 void TomographyIfaceModel::doCancelJobs(const std::string &compRes,
                                         const std::vector<std::string> &ids) {
   for (size_t i = 0; i < ids.size(); i++) {
@@ -414,7 +527,7 @@ void TomographyIfaceModel::doCancelJobs(const std::string &compRes,
 
 void TomographyIfaceModel::doRefreshJobsInfo(const std::string &compRes) {
 
-  if ("Local" == compRes) {
+  if (g_LocalResourceName == compRes) {
     refreshLocalJobsInfo();
     return;
   }
@@ -448,6 +561,17 @@ void TomographyIfaceModel::refreshLocalJobsInfo() {
   }
 }
 
+void TomographyIfaceModel::updateProcessInJobList(const qint64 pid,
+                                                  const int exitCode) {
+  // cast to string from qint64 so we can compare
+  const std::string processPID = std::to_string(pid);
+  for (auto &job : m_jobsStatusLocal) {
+    if (job.id == processPID && exitCode == 1) {
+      job.status = "Exit";
+    }
+  }
+}
+
 void TomographyIfaceModel::getJobStatusInfo(const std::string &compRes) {
   if (m_loggedInUser.empty())
     return;
@@ -522,9 +646,9 @@ void TomographyIfaceModel::checkDataPathsSet() const {
  *
  * @return running status
  */
-bool TomographyIfaceModel::processIsRunning(int pid) {
+bool TomographyIfaceModel::processIsRunning(qint64 pid) const {
 #ifdef _WIN32
-  HANDLE handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
+  HANDLE handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, static_cast<int>(pid));
   DWORD code;
   BOOL rc = GetExitCodeProcess(handle, &code);
   CloseHandle(handle);
@@ -533,164 +657,9 @@ bool TomographyIfaceModel::processIsRunning(int pid) {
   // zombie/defunct processes
   while (waitpid(-1, 0, WNOHANG) > 0) {
   }
-  return (0 == kill(pid, 0));
+  return (0 == kill(static_cast<int>(pid), 0));
 #endif
-}
-
-void TomographyIfaceModel::doRunReconstructionJobLocal() {
-  const std::string toolName = usingTool();
-  try {
-    std::string run;
-    std::vector<std::string> args;
-    makeRunnableWithOptions("local", run, args);
-
-    std::string allOpts;
-    for (const auto &option : args) {
-      allOpts += option + " ";
-    }
-
-    logMsg("Running " + toolName + ", with binary: " + run +
-           ", with parameters: " + allOpts);
-
-    // Mantid::Kernel::ConfigService::Instance().launchProcess(run, runArgs);
-    try {
-      Poco::ProcessHandle handle = Poco::Process::launch(run, args);
-      Poco::Process::PID pid = handle.id();
-      Mantid::API::IRemoteJobManager::RemoteJobInfo info;
-      info.id = boost::lexical_cast<std::string>(pid);
-      info.name = "Mantid_Local";
-      if (pid > 0) {
-        info.status = "Starting";
-      } else {
-        info.status = "Exit";
-      }
-      info.cmdLine = run + " " + allOpts;
-      m_jobsStatusLocal.emplace_back(info);
-    } catch (Poco::SystemException &sexc) {
-      g_log.error()
-          << "Execution failed. Could not run the tool. Error details: "
-          << std::string(sexc.what());
-      Mantid::API::IRemoteJobManager::RemoteJobInfo info;
-      info.id = "none";
-      info.name = "Mantid_Local";
-      info.status = "Exit";
-      info.cmdLine = run + " " + allOpts;
-      m_jobsStatusLocal.emplace_back(info);
-    }
-  } catch (std::runtime_error &rexc) {
-    logMsg("The execution of " + toolName + "failed. details: " +
-           std::string(rexc.what()));
-    g_log.error()
-        << "Execution failed. Coult not execute the tool. Error details: "
-        << std::string(rexc.what());
-  }
-
-  doRefreshJobsInfo("Local");
-}
-
-/**
- * Build the components of the command line to run on the remote or local
- * compute resource. Produces a (normally full) path to a runnable, and
- * the options (quite like $0 and $* in scripts).
- *
- * @param comp Compute resource for which the command line is being prepared
- * @param run Path to a runnable application (script, python module, etc.)
- * @param opt Command line options to the application
- */
-void TomographyIfaceModel::makeRunnableWithOptions(
-    const std::string &comp, std::string &run,
-    std::vector<std::string> &opt) const {
-  const std::string tool = usingTool();
-  // Special case. Just pass on user inputs.
-  if (tool == g_customCmdTool) {
-    const std::string cmd = m_toolsSettings.custom.toCommand();
-
-    opt.resize(1);
-    splitCmdLine(cmd, run, opt[0]);
-    return;
-  }
-
-  std::string cmd;
-  bool local = false;
-  // TODO this is still incomplete, not all tools ready
-  if ("local" == comp) {
-    local = true;
-    cmd = m_systemSettings.m_local.m_reconScriptsPath +
-          g_mainReconstructionScript;
-  } else if (tool == g_TomoPyTool) {
-    cmd = m_toolsSettings.tomoPy.toCommand();
-    // this will make something like:
-    // run = "/work/imat/z-tests-fedemp/scripts/tomopy/imat_recon_FBP.py";
-    // opt = "--input_dir " + base + currentPathFITS() + " " + "--dark " +
-    // base +
-    //      currentPathDark() + " " + "--white " + base + currentPathFlat();
-  } else if (tool == g_AstraTool) {
-    cmd = m_toolsSettings.astra.toCommand();
-    // this will produce something like this:
-    // run = "/work/imat/scripts/astra/astra-3d-SIRT3D.py";
-    // opt = base + currentPathFITS();
-  } else {
-    throw std::runtime_error(
-        "Unable to use this tool. "
-        "I do not know how to submit jobs to use this tool: " +
-        tool + ". It seems that this interface is "
-               "misconfigured or there has been an unexpected "
-               "failure.");
-  }
-
-  std::string longOpt;
-  splitCmdLine(cmd, run, longOpt);
-  checkWarningToolNotSetup(tool, cmd);
-
-  if (local) {
-    run = m_systemSettings.m_local.m_externalInterpreterPath;
-  } else {
-    // intentionally not using local style paths, as this goes to a server with
-    // unix file system
-    run = m_systemSettings.m_remote.m_basePathReconScripts +
-          g_mainReconstructionScript;
-  }
-  opt = makeTomoRecScriptOptions(local);
-}
-
-/**
- * Build the command line options string in the way the tomorec
- * scripts (remote and local) expect it.
- *
- * @param local whether to adapt the options for a local run (as
- * opposed to a remote compute resource)
- *
- * @return command options ready for the tomorec script
- */
-std::vector<std::string>
-TomographyIfaceModel::makeTomoRecScriptOptions(bool local) const {
-
-  // options with all the info from filters and regions
-  std::vector<std::string> opts;
-
-  if (local) {
-    Poco::Path base(m_systemSettings.m_local.m_reconScriptsPath);
-    base.append(g_mainReconstructionScript);
-    opts.emplace_back(base.toString());
-  }
-
-  const std::string toolName = usingTool();
-  if (g_TomoPyTool == toolName) {
-    opts.emplace_back("--tool=tomopy");
-    opts.emplace_back("--algorithm=" + m_tomopyMethod);
-  } else if (g_AstraTool == toolName) {
-    opts.emplace_back("--tool=astra");
-    opts.emplace_back("--algorithm=" + m_astraMethod);
-  }
-
-  if (g_TomoPyTool != toolName || m_tomopyMethod != "gridred" ||
-      m_tomopyMethod != "fbp")
-    opts.emplace_back("--num-iter=5");
-
-  filtersCfgToCmdOpts(m_prePostProcSettings, m_imageStackPreParams, local,
-                      opts);
-
-  return opts;
+  // return Poco::Process::isRunning(pid);
 }
 
 /**
@@ -700,10 +669,12 @@ TomographyIfaceModel::makeTomoRecScriptOptions(bool local) const {
  *
  * @param tool Name of the tool this warning applies to
  * @param cmd command/script/executable derived from the settings
+ * @param args All the arguments for the run
  */
-void TomographyIfaceModel::checkWarningToolNotSetup(
-    const std::string &tool, const std::string &cmd) const {
-  if (tool.empty() || cmd.empty()) {
+bool TomographyIfaceModel::checkIfToolIsSetupProperly(
+    const std::string &tool, const std::string &cmd,
+    const std::vector<std::string> &args) const {
+  if (tool.empty() || cmd.empty() || args.empty()) {
     const std::string detail =
         "Please define the settings of this tool. "
         "You have not defined any settings for this tool: " +
@@ -714,6 +685,7 @@ void TomographyIfaceModel::checkWarningToolNotSetup(
     throw std::runtime_error("Cannot run the tool " + tool +
                              " without setting it up." + detail);
   }
+  return true;
 }
 
 /**
@@ -721,16 +693,16 @@ void TomographyIfaceModel::checkWarningToolNotSetup(
  * when the code is reorganized to use the tool settings objects better.
  */
 void TomographyIfaceModel::splitCmdLine(const std::string &cmd,
-                                        std::string &run,
+                                        std::string &runnable,
                                         std::string &opts) const {
   if (cmd.empty())
     return;
 
-  const auto pos = cmd.find(' ');
+  const auto pos = cmd.find(" ");
   if (std::string::npos == pos)
     return;
 
-  run = cmd.substr(0, pos);
+  runnable = cmd.substr(0, pos);
   opts = cmd.substr(pos + 1);
 }
 
@@ -788,15 +760,17 @@ TomographyIfaceModel::loadFITSImage(const std::string &path) {
 
   // draw image from workspace
   if (wsg && ws &&
-      Mantid::API::AnalysisDataService::Instance().doesExist(ws->name())) {
+      Mantid::API::AnalysisDataService::Instance().doesExist(ws->getName())) {
     return wsg;
   } else {
     return WorkspaceGroup_sptr();
   }
 }
 
-void TomographyIfaceModel::logMsg(const std::string &msg) {
-  g_log.notice() << msg << '\n';
+void TomographyIfaceModel::logMsg(const std::string &msg) { g_log.notice(msg); }
+
+void TomographyIfaceModel::logErrMsg(const std::string &msg) {
+  g_log.error(msg);
 }
 
 /**
@@ -835,16 +809,13 @@ std::string boxCoordinatesToCSV(const ImageStackPreParams::Box2D &coords) {
  */
 void TomographyIfaceModel::filtersCfgToCmdOpts(
     const TomoReconFiltersSettings &filters,
-    const ImageStackPreParams &corRegions, bool local,
+    const ImageStackPreParams &corRegions, const bool local,
     std::vector<std::string> &opts) const {
 
   opts.emplace_back("--input-path=" + adaptInputPathForExecution(
                                           m_pathsConfig.pathSamples(), local));
-  std::string alg = "alg";
-  if (g_TomoPyTool == usingTool())
-    alg = m_tomopyMethod;
-  else if (g_AstraTool == usingTool())
-    alg = m_astraMethod;
+
+  const std::string alg = getCurrentToolMethod();
 
   // check the general enable option and the dataset specific enable
   if (filters.prep.normalizeByFlats && m_pathsConfig.m_pathOpenBeamEnabled) {
@@ -863,6 +834,8 @@ void TomographyIfaceModel::filtersCfgToCmdOpts(
 
   std::string openList;
   std::string closeList;
+  // TODOMODL how to handle this? we still need to know what the resource is,
+  // because local is windows and remote is linux
   if (local) {
     openList = "[";
     closeList = "]";
@@ -895,7 +868,7 @@ void TomographyIfaceModel::filtersCfgToCmdOpts(
   // one name for this particular reconstruction, like:
   // out_reconstruction_TomoPy_gridrec_
   const std::string reconName =
-      "reconstruction_" + m_currentTool + "_" + alg + "_" + timeAppendix;
+      "reconstruction_" + m_currentToolName + "_" + alg + "_" + timeAppendix;
 
   const std::string outOpt = outBase + "/" + reconName;
 
@@ -959,7 +932,7 @@ void TomographyIfaceModel::filtersCfgToCmdOpts(
  */
 std::string
 TomographyIfaceModel::adaptInputPathForExecution(const std::string &path,
-                                                 bool local) const {
+                                                 const bool local) const {
   if (local)
     return path;
 
@@ -983,10 +956,6 @@ TomographyIfaceModel::adaptInputPathForExecution(const std::string &path,
       else
         result = result.substr(2);
     }
-
-    // this appends the base path for the instrument data space on the
-    // remote (like '/work/imat' or similar)
-    result = m_systemSettings.m_remote.m_basePathTomoData + result;
   }
 
   return result;
diff --git a/MantidQt/CustomInterfaces/src/Tomography/TomographyIfacePresenter.cpp b/MantidQt/CustomInterfaces/src/Tomography/TomographyIfacePresenter.cpp
index e4988b9f90cc4de8b511a34232e417c732337853..4b02439d07c5d8734a372ced25054256f1fb8408 100644
--- a/MantidQt/CustomInterfaces/src/Tomography/TomographyIfacePresenter.cpp
+++ b/MantidQt/CustomInterfaces/src/Tomography/TomographyIfacePresenter.cpp
@@ -5,8 +5,11 @@
 #include "MantidKernel/ConfigService.h"
 #include "MantidKernel/FacilityInfo.h"
 #include "MantidQtCustomInterfaces/Tomography/ITomographyIfaceView.h"
+#include "MantidQtCustomInterfaces/Tomography/TomoToolConfigDialogBase.h"
 #include "MantidQtCustomInterfaces/Tomography/TomographyIfaceModel.h"
 #include "MantidQtCustomInterfaces/Tomography/TomographyIfacePresenter.h"
+#include "MantidQtCustomInterfaces/Tomography/TomographyProcess.h"
+#include "MantidQtCustomInterfaces/Tomography/TomographyThread.h"
 
 #include <boost/lexical_cast.hpp>
 
@@ -25,23 +28,33 @@ using namespace MantidQt::CustomInterfaces;
 namespace MantidQt {
 namespace CustomInterfaces {
 
+const std::string TomographyIfacePresenter::g_defOutPathLocal =
+#ifdef _WIN32
+    "D:/imat-data/";
+#else
+    "~/imat/";
+#endif
+
+const std::string TomographyIfacePresenter::g_defOutPathRemote =
+#ifdef _WIN32
+    "I:/imat/imat-data/";
+#else
+    "~/imat-data/";
+#endif
+
 TomographyIfacePresenter::TomographyIfacePresenter(ITomographyIfaceView *view)
-    : m_view(view), m_model(new TomographyIfaceModel()), m_statusMutex(NULL),
-      m_keepAliveTimer(NULL), m_keepAliveThread(NULL) {
+    : m_view(view), m_model(new TomographyIfaceModel()),
+      m_statusMutex(new QMutex()), m_keepAliveTimer(nullptr) {
   if (!m_view) {
     throw std::runtime_error("Severe inconsistency found. Presenter created "
                              "with an empty/null view (tomography interface). "
                              "Cannot continue.");
   }
-  m_statusMutex = new QMutex();
 }
 
 TomographyIfacePresenter::~TomographyIfacePresenter() {
   cleanup();
 
-  if (m_keepAliveThread)
-    delete m_keepAliveThread;
-
   if (m_keepAliveTimer)
     delete m_keepAliveTimer;
 
@@ -134,7 +147,10 @@ void TomographyIfacePresenter::notify(
 }
 
 void TomographyIfacePresenter::processSystemSettingsUpdated() {
-  m_model->updateSystemSettings(m_view->systemSettings());
+  m_model->setSystemSettings(m_view->systemSettings());
+
+  // update the tool information with the new system settings
+  setupConfigDialogSettingsAndUpdateModel(m_configDialog.get());
 }
 
 void TomographyIfacePresenter::processSetupResourcesAndTools() {
@@ -177,43 +193,187 @@ void TomographyIfacePresenter::processSetupResourcesAndTools() {
 void TomographyIfacePresenter::processCompResourceChanged() {
   const std::string comp = m_view->currentComputeResource();
 
+  // TODOPRES find a better way to set up the run tool in model
   m_model->setupRunTool(comp);
 
-  if ("Local" == comp) {
+  if (isLocalResourceSelected()) {
     m_view->enableLoggedActions(true);
   } else {
     const bool status = !m_model->loggedIn().empty();
     m_view->enableLoggedActions(status);
   }
+
+  // this will udpate the tool after a resource change
+  setupConfigDialogSettingsAndUpdateModel(m_configDialog.get());
 }
 
+/** Called when the event ToolChanged fires. It gets the name for the current
+ * tabToolTip and first tries to create it (if valid tool name), and if that
+ * succeeds then updates the tool's settings to hold the current path and
+ * afterwards updates the model's information about the tool's current settings
+ */
 void TomographyIfacePresenter::processToolChanged() {
-  const std::string tool = m_view->currentReconTool();
+  const std::string toolName = m_view->currentReconTool();
 
   // disallow reconstruct on tools that don't run yet: Savu and CCPi
-  if (TomographyIfaceModel::g_CCPiTool == tool) {
+  if (TomographyIfaceModel::g_CCPiTool == toolName) {
     m_view->enableRunReconstruct(false);
     m_view->enableConfigTool(false);
-  } else if (TomographyIfaceModel::g_SavuTool == tool) {
+  } else if (TomographyIfaceModel::g_SavuTool == toolName) {
     // for now, show setup dialog, but cannot run
     m_view->enableRunReconstruct(false);
     m_view->enableConfigTool(true);
   } else {
     // No need to be logged in anymore when local is selected
-    const bool runningLocally = "Local" == m_view->currentComputeResource();
+    const bool runningLocally = isLocalResourceSelected();
     m_view->enableRunReconstruct(runningLocally ||
                                  !(m_model->loggedIn().empty()));
     m_view->enableConfigTool(true);
   }
 
-  m_model->usingTool(tool);
+  // return if empty string
+  if ("" == toolName) {
+    return;
+  }
+
+  createConfigDialogUsingToolName(toolName);
+  // this will set the default settings for the dialog
+  setupConfigDialogSettingsAndUpdateModel(m_configDialog.get());
+}
+
+void TomographyIfacePresenter::setupConfigDialogSettingsAndUpdateModel(
+    TomoToolConfigDialogBase *dialog) {
+
+  // this check prevents a crash on initialisation where Qt passes a tool name
+  // of "" and then we have a nullptr dialogue
+  if (dialog) {
+    setupConfigDialogSettings(*dialog);
+    updateModelAfterToolChanged(*dialog);
+  }
+}
+
+/** Uses the static method in TomoToolConfigDialogBase to create the proper tool
+ * from the provided name
+ * @param toolName The string holding the tool's name
+ */
+void TomographyIfacePresenter::createConfigDialogUsingToolName(
+    const std::string &toolName) {
+  // free the previous dialogue pointer if any
+  m_configDialog.reset();
+  m_configDialog = TomoToolConfigDialogBase::getToolDialogFor(toolName);
+}
+
+/** Depending on whether local or remote resource is selected, do setup
+* the tool's run path, the paths out, the reconstruction index and
+* the localOutNameAppendix
+*
+* @param dialog The dialog pointer that will be set up
+*/
+void TomographyIfacePresenter::setupConfigDialogSettings(
+    TomoToolConfigDialogBase &dialog) {
+
+  if (isLocalResourceSelected()) {
+    setupConfigDialogSettingsForLocal(dialog);
+  } else {
+    setupConfigDialogSettingsForRemote(dialog);
+  }
+}
+
+/** Configures the dialog settings for local reconstruction, this means settings
+ * the run command, the pathOut and the name of the output folder
+ *
+ * @param dialog The raw dialog pointer that will be configured.
+ */
+void TomographyIfacePresenter::setupConfigDialogSettingsForLocal(
+    TomoToolConfigDialogBase &dialog) {
+  const std::string run = m_model->getExeternalInterpreterPath() + " " +
+                          m_model->getCurrentLocalScriptsBasePath() +
+                          m_model->getTomoScriptLocationPath();
+
+  const TomoPathsConfig paths = m_view->currentPathsConfig();
+
+  const std::string pathOut = Poco::Path::expand(
+      g_defOutPathLocal + "/" + m_model->getCurrentExperimentReference());
+  static size_t reconIdx = 1;
+  const std::string localOutNameAppendix =
+      std::string("/processed/") + "reconstruction_" + std::to_string(reconIdx);
+
+  dialog.setupDialog(run, paths, pathOut, localOutNameAppendix);
+}
+
+/** Configures the dialog settings for remote reconstruction, this means
+ * settings
+ * the run command, the pathOut and the name of the output folder
+ *
+ * Currently it does NOT take into account the remote, this is
+ * something that might be needed in the future if more remote reconstruction
+ * locations are added, as currently the only one is SCARF
+ *
+ * @param dialog The raw dialog pointer that will be configured.
+ */
+void TomographyIfacePresenter::setupConfigDialogSettingsForRemote(
+    TomoToolConfigDialogBase &dialog) {
+  // set up all the information we need for the dialog
+  const std::string run = m_model->getCurrentRemoteScriptsBasePath() +
+                          m_model->getTomoScriptFolderPath() +
+                          m_model->getTomoScriptLocationPath();
+
+  const TomoPathsConfig paths = m_view->currentPathsConfig();
+  const std::string pathOut = Poco::Path::expand(
+      g_defOutPathLocal + "/" + m_model->getCurrentExperimentReference());
+  static size_t reconIdx = 1;
+  const std::string localOutNameAppendix =
+      std::string("/processed/") + "reconstruction_" + std::to_string(reconIdx);
+
+  dialog.setupDialog(run, paths, pathOut, localOutNameAppendix);
+}
+
+/** Updated  the model's information about the current tool
+ * The settings that are updated are:
+ *  - the current tool name
+ *  - the current tool method
+ *  - the current tool settings
+ *
+ * @param dialog The raw dialog pointer that will be configured.
+ */
+void TomographyIfacePresenter::updateModelAfterToolChanged(
+    const TomoToolConfigDialogBase &dialog) {
+
+  // if passed an empty string don't remove the name
+  updateModelCurrentToolName(dialog);
+  updateModelCurrentToolMethod(dialog);
+  updateModelCurrentToolSettings(dialog);
+}
+
+/** Sets the model's current tool name by getting the tool name from the
+* dialogue itself
+*/
+void TomographyIfacePresenter::updateModelCurrentToolName(
+    const TomoToolConfigDialogBase &dialog) {
+  m_model->usingTool(dialog.getSelectedToolName());
+}
+/** Sets the model's current tool method by coyping the
+* string over to the model, getting it from the dialogue itself
+*/
+void TomographyIfacePresenter::updateModelCurrentToolMethod(
+    const TomoToolConfigDialogBase &dialog) {
+  m_model->setCurrentToolMethod(dialog.getSelectedToolMethod());
+}
+
+/** Shares the pointer with the model's tool settings. We don't want a
+* unique_ptr, because the dialogs don't die after they are closed, they die if
+* the tool is changed or the whole interface is closed
+*/
+void TomographyIfacePresenter::updateModelCurrentToolSettings(
+    const TomoToolConfigDialogBase &dialog) {
+  m_model->setCurrentToolSettings(dialog.getSelectedToolSettings());
 }
 
 /**
  * Simply take the paths that the user has provided.
  */
 void TomographyIfacePresenter::processTomoPathsChanged() {
-  m_model->updateTomoPathsConfig(m_view->currentPathsConfig());
+  m_model->setTomoPathsConfig(m_view->currentPathsConfig());
 }
 
 /**
@@ -239,7 +399,7 @@ void TomographyIfacePresenter::processTomoPathsEditedByUser() {
     m_model->logMsg(msg);
   }
 
-  m_model->updateTomoPathsConfig(cfg);
+  m_model->setTomoPathsConfig(cfg);
   m_view->updatePathsConfig(cfg);
 }
 
@@ -292,7 +452,7 @@ void TomographyIfacePresenter::processLogin() {
 
   std::string compRes = m_view->currentComputeResource();
   // if local is selected, just take the first remote resource
-  if ("Local" == compRes) {
+  if (isLocalResourceSelected()) {
     compRes = "SCARF@STFC";
   }
   try {
@@ -349,7 +509,7 @@ void TomographyIfacePresenter::processLogout() {
   try {
     std::string compRes = m_view->currentComputeResource();
     // if local is selected, just take the first remote resource
-    if ("Local" == compRes) {
+    if (isLocalResourceSelected()) {
       compRes = "SCARF@STFC";
     }
     m_model->doLogout(compRes, m_view->getUsername());
@@ -362,19 +522,21 @@ void TomographyIfacePresenter::processLogout() {
 }
 
 void TomographyIfacePresenter::processSetupReconTool() {
-  if (TomographyIfaceModel::g_CCPiTool != m_view->currentReconTool()) {
-    m_view->showToolConfig(m_view->currentReconTool());
-    m_model->updateReconToolsSettings(m_view->reconToolsSettings());
-
-    // TODO: this would make sense if the reconstruct action/button
-    // was only enabled after setting up at least one tool
-    // m_view->enableToolsSetupsActions(true);
+  const std::string &currentReconTool = m_view->currentReconTool();
+
+  // this check prevents a crash on initialisation where Qt passes a tool name
+  // of "" and then we have a nullptr dialogue
+  auto dialog = m_configDialog.get();
+  if (dialog) {
+    if (TomographyIfaceModel::g_CCPiTool != currentReconTool) {
+      // give pointer to showToolConfig, so it can run the dialogue
+      m_view->showToolConfig(*dialog);
+      updateModelAfterToolChanged(*dialog);
+    }
   }
 }
 
 void TomographyIfacePresenter::processRunRecon() {
-  // m_model->checkDataPathsSet();
-  // TODO: validate data path with additional rules/constraints?
   TomoPathsConfig paths = m_view->currentPathsConfig();
   if (paths.pathSamples().empty()) {
     m_view->userWarning("Sample images path not set!",
@@ -385,57 +547,130 @@ void TomographyIfacePresenter::processRunRecon() {
   }
 
   // pre-/post processing steps and filters
-  m_model->updatePrePostProcSettings(m_view->prePostProcSettings());
+  m_model->setPrePostProcSettings(m_view->prePostProcSettings());
   // center of rotation and regions
-  m_model->updateImageStackPreParams(m_view->currentROIEtcParams());
-  m_model->updateTomopyMethod(m_view->tomopyMethod());
-  m_model->updateAstraMethod(m_view->astraMethod());
-  const std::string &resource = m_view->currentComputeResource();
-  if (m_model->localComputeResource() == resource) {
-    subprocessRunReconLocal();
-  } else {
-    subprocessRunReconRemote();
+  m_model->setImageStackPreParams(m_view->currentROIEtcParams());
+
+  // we have to branch out to handle local and remote somewhere
+  try {
+    const bool local = isLocalResourceSelected();
+
+    std::string runnable;
+    std::vector<std::string> args;
+    std::string allOpts;
+
+    m_model->prepareSubmissionArguments(local, runnable, args, allOpts);
+    if (local) {
+      setupAndRunLocalReconstruction(runnable, args, allOpts);
+
+      // start the refresh jobs timer if not running
+      startKeepAliveMechanism(m_view->keepAlivePeriod());
+    } else {
+      // get the actual compute resource name
+      const std::string computingResouce = m_view->currentComputeResource();
+      m_model->doRemoteRunReconstructionJob(computingResouce, runnable,
+                                            allOpts);
+    }
+  } catch (std::exception &e) {
+    m_view->userWarning("Issue when trying to start a job", e.what());
   }
 
   processRefreshJobs();
 }
 
-void TomographyIfacePresenter::subprocessRunReconRemote() {
-  if (m_model->loggedIn().empty()) {
-    m_view->updateJobsInfoDisplay(m_model->jobsStatus(),
-                                  m_model->jobsStatusLocal());
-    return;
+bool TomographyIfacePresenter::userConfirmationToCancelRecon() {
+  if (m_reconRunning) {
+    const bool result = m_view->userConfirmation(
+        "Reconstruction is RUNNING",
+        "Are you sure you want to<br>cancel the running reconstruction?");
+
+    if (!result) {
+      // user clicked NO, so we don't terminate the running reconstruction and
+      // simply return
+      return false;
+    }
+    m_reconRunning = false;
   }
+  return true;
+}
 
-  try {
+void TomographyIfacePresenter::setupAndRunLocalReconstruction(
+    const std::string &runnable, const std::vector<std::string> &args,
+    const std::string &allOpts) {
 
-    m_model->doSubmitReconstructionJob(m_view->currentComputeResource());
-  } catch (std::exception &e) {
-    m_view->userWarning("Issue when trying to start a job", e.what());
+  if (!userConfirmationToCancelRecon()) {
+    // user didnt confirm
+    return;
   }
+
+  // this kills the previous thread forcefully
+  m_workerThread.reset();
+  auto *worker = new MantidQt::CustomInterfaces::TomographyProcess();
+  m_workerThread = Mantid::Kernel::make_unique<TomographyThread>(this, worker);
+
+  // we do this so the thread can independently read the process' output and
+  // only signal the presenter after it's done reading and has something to
+  // share so it doesn't block the presenter
+  connect(m_workerThread.get(), SIGNAL(stdOutReady(QString)), this,
+          SLOT(readWorkerStdOut(QString)));
+  connect(m_workerThread.get(), SIGNAL(stdErrReady(QString)), this,
+          SLOT(readWorkerStdErr(QString)));
+
+  // remove the user confirmation for running recon, if the recon has finished
+  connect(m_workerThread.get(), SIGNAL(workerFinished(qint64, int)), this,
+          SLOT(workerFinished(qint64, int)));
+
+  connect(worker, SIGNAL(started()), this, SLOT(addProcessToJobList()));
+
+  m_model->doLocalRunReconstructionJob(runnable, args, allOpts, *m_workerThread,
+                                       *worker);
+  m_reconRunning = true;
 }
 
-void TomographyIfacePresenter::subprocessRunReconLocal() {
-  m_model->doRunReconstructionJobLocal();
+/** Simply reset the switch that tracks if a recon is running and
+ * update the process job in the reconstruction list
+ */
+void TomographyIfacePresenter::workerFinished(const qint64 pid,
+                                              const int exitCode) {
+  m_reconRunning = false;
+  m_model->updateProcessInJobList(pid, exitCode);
+  processRefreshJobs();
 }
 
-void TomographyIfacePresenter::processRefreshJobs() {
-  // No need to be logged in, there can be local processes
-  if (m_model->loggedIn().empty()) {
-    m_model->doRefreshJobsInfo("Local");
-    m_view->updateJobsInfoDisplay(m_model->jobsStatus(),
-                                  m_model->jobsStatusLocal());
-    return;
-  }
+void TomographyIfacePresenter::reconProcessFailedToStart() {
+  m_view->userError("Reconstruction failed to start",
+                    "The reconstruction process has encountered an error and "
+                    "has failed to start.");
+}
 
-  std::string comp = m_view->currentComputeResource();
-  if ("Local" == comp) {
-    comp = "SCARF@STFC";
-  }
-  m_model->doRefreshJobsInfo(comp);
+void TomographyIfacePresenter::addProcessToJobList() {
+  auto *worker = qobject_cast<TomographyProcess *>(sender());
+  const qint64 pid = worker->getPID();
+  const auto runnable = worker->getRunnable();
+  const auto args = worker->getArgs();
+
+  m_workerThread->setProcessPID(pid);
+
+  m_model->addJobToStatus(pid, runnable, args);
+  processRefreshJobs();
+}
+
+void TomographyIfacePresenter::readWorkerStdOut(const QString &s) {
+  m_model->logMsg(s.toStdString());
+}
+
+void TomographyIfacePresenter::readWorkerStdErr(const QString &s) {
+  m_model->logErrMsg(s.toStdString());
+}
+
+bool TomographyIfacePresenter::isLocalResourceSelected() const {
+  return m_model->localComputeResource() == m_view->currentComputeResource();
+}
+
+void TomographyIfacePresenter::processRefreshJobs() {
+  m_model->doRefreshJobsInfo(m_view->currentComputeResource());
 
   {
-    // update widgets from that info
     QMutexLocker lockit(m_statusMutex);
 
     m_view->updateJobsInfoDisplay(m_model->jobsStatus(),
@@ -444,11 +679,11 @@ void TomographyIfacePresenter::processRefreshJobs() {
 }
 
 void TomographyIfacePresenter::processCancelJobs() {
-  if (m_model->loggedIn().empty())
-    return;
-
   const std::string &resource = m_view->currentComputeResource();
-  if (m_model->localComputeResource() != resource) {
+  if (isLocalResourceSelected() && userConfirmationToCancelRecon()) {
+    // if local and user confirmed
+    m_workerThread.reset();
+  } else {
     m_model->doCancelJobs(resource, m_view->processingJobsIDs());
   }
 }
@@ -460,7 +695,10 @@ void TomographyIfacePresenter::processVisualizeJobs() {
 void TomographyIfacePresenter::doVisualize(
     const std::vector<std::string> &ids) {
   m_model->logMsg(" Visualizing results from job: " + ids.front());
-  // TODO: open dialog, send to Paraview, etc.
+  m_view->userWarning("Visualizing not implemented", "Visualizing of the data "
+                                                     "has not been implemented "
+                                                     "yet and is unsupported");
+  // TODOPRES: open dialog, send to Paraview, etc.
 }
 
 void TomographyIfacePresenter::processLogMsg() {
@@ -602,6 +840,11 @@ void TomographyIfacePresenter::startKeepAliveMechanism(int period) {
     return;
   }
 
+  // timer is already running, so return
+  if (m_keepAliveTimer) {
+    return;
+  }
+
   m_model->logMsg(
       "Tomography GUI: starting mechanism to periodically query the "
       "status of jobs. This will update the status of running jobs every " +
@@ -611,22 +854,19 @@ void TomographyIfacePresenter::startKeepAliveMechanism(int period) {
       "also expected to keep sessions on remote compute resources "
       "alive after logging in.");
 
-  if (m_keepAliveThread)
-    delete m_keepAliveThread;
-  QThread *m_keepAliveThread = new QThread();
-
   if (m_keepAliveTimer)
     delete m_keepAliveTimer;
-  m_keepAliveTimer = new QTimer(NULL); // no-parent so it can be moveToThread
+  m_keepAliveTimer = new QTimer(this); // no-parent so it can be moveToThread
 
   m_keepAliveTimer->setInterval(1000 * period); // interval in ms
-  m_keepAliveTimer->moveToThread(m_keepAliveThread);
-  // direct connection from the thread
-  connect(m_keepAliveTimer, SIGNAL(timeout()), SLOT(processRefreshJobs()),
-          Qt::DirectConnection);
-  QObject::connect(m_keepAliveThread, SIGNAL(started()), m_keepAliveTimer,
-                   SLOT(start()));
-  m_keepAliveThread->start();
+
+  // remove previous connections
+  m_keepAliveTimer->disconnect();
+
+  connect(m_keepAliveTimer, SIGNAL(timeout()), this,
+          SLOT(processRefreshJobs()));
+
+  m_keepAliveTimer->start();
 }
 
 void TomographyIfacePresenter::killKeepAliveMechanism() {
diff --git a/MantidQt/CustomInterfaces/src/Tomography/TomographyIfaceViewQtGUI.cpp b/MantidQt/CustomInterfaces/src/Tomography/TomographyIfaceViewQtGUI.cpp
index 7947ea1b8c8001e5172ff8e751fc3bb8637e68a0..c445f51bc07df570c97ea90098d667e995af90bf 100644
--- a/MantidQt/CustomInterfaces/src/Tomography/TomographyIfaceViewQtGUI.cpp
+++ b/MantidQt/CustomInterfaces/src/Tomography/TomographyIfaceViewQtGUI.cpp
@@ -1,17 +1,20 @@
+#include "MantidKernel/ConfigService.h"
 #include "MantidAPI/AlgorithmManager.h"
-#include "MantidAPI/MatrixWorkspace.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/ITableWorkspace.h"
+#include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/Run.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidQtAPI/AlgorithmInputHistory.h"
 
 #include "MantidQtAPI/HelpWindow.h"
-#include "MantidQtCustomInterfaces/Tomography/TomographyIfaceViewQtGUI.h"
+#include "MantidQtCustomInterfaces/Tomography/TomoSystemSettings.h"
 #include "MantidQtCustomInterfaces/Tomography/TomographyIfacePresenter.h"
+#include "MantidQtCustomInterfaces/Tomography/TomographyIfaceViewQtGUI.h"
 #include "MantidQtCustomInterfaces/Tomography/ToolConfigAstraToolbox.h"
 #include "MantidQtCustomInterfaces/Tomography/ToolConfigCustom.h"
-#include "MantidQtCustomInterfaces/Tomography/ToolConfigTomoPy.h"
-#include "MantidQtCustomInterfaces/Tomography/TomoSystemSettings.h"
+
+#include "MantidQtCustomInterfaces/Tomography/TomoToolConfigDialogBase.h"
 
 using namespace Mantid::API;
 using namespace MantidQt::CustomInterfaces;
@@ -62,8 +65,6 @@ const std::string TomographyIfaceViewQtGUI::g_styleSheetOnline =
     "QPushButton:pressed { background-color: rgb(120, 255, 120); "
     "}";
 
-size_t TomographyIfaceViewQtGUI::g_nameSeqNo = 0;
-
 // For paths where Python third party tools are installed, if they're
 // not included in the system python path. For example you could have
 // put the AstraToolbox package in
@@ -74,9 +75,6 @@ size_t TomographyIfaceViewQtGUI::g_nameSeqNo = 0;
 // c:/local/Anaconda/Lib/site-packages/
 std::vector<std::string> TomographyIfaceViewQtGUI::g_defAddPathPython;
 
-const std::string TomographyIfaceViewQtGUI::g_defRemotePathScripts =
-    "/work/imat/phase_commissioning";
-
 const std::string TomographyIfaceViewQtGUI::g_SCARFName = "SCARF@STFC";
 const std::string TomographyIfaceViewQtGUI::g_defOutPathLocal =
 #ifdef _WIN32
@@ -85,7 +83,7 @@ const std::string TomographyIfaceViewQtGUI::g_defOutPathLocal =
     "~/imat/";
 #endif
 
-// TODO: could use ConfigService::isNetworkDrive(const std::string &)
+// TODOVIEW: could use ConfigService::isNetworkDrive(const std::string &)
 const std::string TomographyIfaceViewQtGUI::g_defOutPathRemote =
 #ifdef _WIN32
     "I:/imat/imat-data/";
@@ -125,13 +123,6 @@ const std::string TomographyIfaceViewQtGUI::g_defOctopusAppendPath =
 
 const std::string TomographyIfaceViewQtGUI::g_defProcessedSubpath = "processed";
 
-// names by which we know image/tomography reconstruction tools (3rd party)
-const std::string TomographyIfaceViewQtGUI::g_TomoPyTool = "TomoPy";
-const std::string TomographyIfaceViewQtGUI::g_AstraTool = "Astra";
-const std::string TomographyIfaceViewQtGUI::g_CCPiTool = "CCPi CGLS";
-const std::string TomographyIfaceViewQtGUI::g_SavuTool = "Savu";
-const std::string TomographyIfaceViewQtGUI::g_customCmdTool = "Custom command";
-
 // phase or cycle component, like: phase_commissioning, cycle_15_4, cycle_16_1
 const std::string TomographyIfaceViewQtGUI::g_defPathComponentPhase =
     "phase_commissioning";
@@ -165,24 +156,12 @@ DECLARE_SUBWINDOW(TomographyIfaceViewQtGUI)
 TomographyIfaceViewQtGUI::TomographyIfaceViewQtGUI(QWidget *parent)
     : UserSubWindow(parent), ITomographyIfaceView(), m_tabROIW(nullptr),
       m_tabImggFormats(nullptr), m_processingJobsIDs(), m_currentComputeRes(""),
-      m_currentReconTool(""), m_imgPath(""), m_logMsgs(), m_systemSettings(),
-      m_toolsSettings(), m_settings(),
+      m_currentReconTool("TomoPy"), m_imgPath(""), m_logMsgs(),
+      m_systemSettings(), m_settings(),
       m_settingsGroup("CustomInterfaces/Tomography"),
       m_settingsSubGroupEnergy(m_settingsGroup + "/EnergyBands"),
       m_aggAlgRunner(), m_availPlugins(), m_currPlugins(), m_currentParamPath(),
-      m_presenter(nullptr) {
-
-  // defaults from the tools
-  m_tomopyMethod = ToolConfigTomoPy::methods().front().first;
-  m_astraMethod = ToolConfigAstraToolbox::methods().front().first;
-
-  // TODO: find a better place for this Savu stuff when the tool is
-  // ready - see other TODOs
-  m_availPlugins = Mantid::API::WorkspaceFactory::Instance().createTable();
-  m_availPlugins->addColumns("str", "name", 4);
-  m_currPlugins = Mantid::API::WorkspaceFactory::Instance().createTable();
-  m_currPlugins->addColumns("str", "name", 4);
-}
+      m_presenter(nullptr) {}
 
 TomographyIfaceViewQtGUI::~TomographyIfaceViewQtGUI() {}
 
@@ -245,11 +224,6 @@ void TomographyIfaceViewQtGUI::initLayout() {
 }
 
 void TomographyIfaceViewQtGUI::doSetupGeneralWidgets() {
-  // Menu Items
-  connect(m_ui.actionOpen, SIGNAL(triggered()), this, SLOT(menuOpenClicked()));
-  connect(m_ui.actionSave, SIGNAL(triggered()), this, SLOT(menuSaveClicked()));
-  connect(m_ui.actionSaveAs, SIGNAL(triggered()), this,
-          SLOT(menuSaveAsClicked()));
 
   connect(m_ui.pushButton_help, SIGNAL(released()), this, SLOT(openHelpWin()));
   // note connection to the parent window, otherwise you'd be left
@@ -374,7 +348,7 @@ void TomographyIfaceViewQtGUI::doSetupSectionFilters() {
 }
 
 void TomographyIfaceViewQtGUI::doSetupSectionVisualize() {
-  // TODO: take g_def values first time, when Qsettings are empty, then from
+  // TODOVIEW: take g_def values first time, when Qsettings are empty, then from
   // QSettings
   m_setupParaviewPath = g_defParaviewPath;
   m_setupProcessedSubpath = g_defProcessedSubpath;
@@ -525,39 +499,6 @@ void TomographyIfaceViewQtGUI::setComputeResources(
   }
 }
 
-// This is here while savu becomes available and we find a better place for savu
-// stuff
-void TomographyIfaceViewQtGUI::doSetupSavu() {
-  // geometry, etc. niceties
-  // on the left (just plugin names) 1/2, right: 2/3
-  QList<int> sizes;
-  sizes.push_back(100);
-  sizes.push_back(200);
-  m_uiSavu.splitterPlugins->setSizes(sizes);
-
-  // Setup Parameter editor tab
-  loadAvailablePlugins();
-  m_uiSavu.treeCurrentPlugins->setHeaderHidden(true);
-
-  // Connect slots
-
-  // Lists/trees
-  connect(m_uiSavu.listAvailablePlugins, SIGNAL(itemSelectionChanged()), this,
-          SLOT(availablePluginSelected()));
-  connect(m_uiSavu.treeCurrentPlugins, SIGNAL(itemSelectionChanged()), this,
-          SLOT(currentPluginSelected()));
-  connect(m_uiSavu.treeCurrentPlugins, SIGNAL(itemExpanded(QTreeWidgetItem *)),
-          this, SLOT(expandedItem(QTreeWidgetItem *)));
-
-  // Buttons
-  connect(m_uiSavu.btnTransfer, SIGNAL(released()), this,
-          SLOT(transferClicked()));
-  connect(m_uiSavu.btnMoveUp, SIGNAL(released()), this, SLOT(moveUpClicked()));
-  connect(m_uiSavu.btnMoveDown, SIGNAL(released()), this,
-          SLOT(moveDownClicked()));
-  connect(m_uiSavu.btnRemove, SIGNAL(released()), this, SLOT(removeClicked()));
-}
-
 void TomographyIfaceViewQtGUI::setReconstructionTools(
     const std::vector<std::string> &tools, const std::vector<bool> &enabled) {
 
@@ -586,7 +527,7 @@ void TomographyIfaceViewQtGUI::setReconstructionTools(
  * cancel job, etc.
  */
 void TomographyIfaceViewQtGUI::enableLoggedActions(bool enable) {
-  // TODO: this may not make sense anymore when/if the "Local" compute
+  // TODOVIEW: this may not make sense anymore when/if the "Local" compute
   // resource is used in the future (except when none of the tools
   // supported are available/detected on "Local")
   std::vector<QPushButton *> buttons;
@@ -771,9 +712,9 @@ void TomographyIfaceViewQtGUI::readSettings() {
   TomoSystemSettings sysSettings;
   streamSys >> sysSettings;
   if (QDataStream::Ok == streamSys.status()) {
-    updateSystemSettings(sysSettings);
+    updateSystemSettingsTabFields(sysSettings);
   } else {
-    updateSystemSettings(TomoSystemSettings());
+    updateSystemSettingsTabFields(TomoSystemSettings());
   }
 
   // Get input paths (sample/dark/flats)
@@ -970,65 +911,18 @@ void TomographyIfaceViewQtGUI::saveSettings() const {
   qs.endGroup();
 }
 
-/**
- * Load a savu tomo config file into the current plugin list, overwriting it.
- * Uses the algorithm LoadSavuTomoConfig
- */
-void TomographyIfaceViewQtGUI::loadSavuTomoConfig(
-    std::string &filePath, Mantid::API::ITableWorkspace_sptr &currentPlugins) {
-  // try to load tomo reconstruction parametereization file
-  auto alg = Mantid::API::AlgorithmManager::Instance().createUnmanaged(
-      "LoadSavuTomoConfig");
-  alg->initialize();
-  alg->setPropertyValue("Filename", filePath);
-  alg->setPropertyValue("OutputWorkspace", createUniqueNameHidden());
-  try {
-    alg->execute();
-  } catch (std::runtime_error &e) {
-    throw std::runtime_error(
-        std::string("Error when trying to load tomographic reconstruction "
-                    "parameter file: ") +
-        e.what());
-  }
-
-  // new processing plugins list
-  try {
-    currentPlugins = alg->getProperty("OutputWorkspace");
-  } catch (std::exception &e) {
-    userError("Could not load config file", "Failed to load the file "
-                                            "with the following error: " +
-                                                std::string(e.what()));
-  }
-}
-
-// Build a unique (and hidden) name for the table ws
-std::string TomographyIfaceViewQtGUI::createUniqueNameHidden() {
-  std::string name;
-  do {
-    // with __ prefix => hidden
-    name = "__TomoConfigTableWS_Seq_" +
-           boost::lexical_cast<std::string>(g_nameSeqNo++);
-  } while (AnalysisDataService::Instance().doesExist(name));
-
-  return name;
-}
-
 /// needs to at least update the 'tool' combo box
 void TomographyIfaceViewQtGUI::compResourceIndexChanged(int /* i */) {
   QComboBox *rt = m_uiTabRun.comboBox_run_compute_resource;
   if (!rt)
     return;
 
-  // TODO validateCompResource(rt->currentText().toStdString());
   m_currentComputeRes = rt->currentText().toStdString();
   m_presenter->notify(ITomographyIfacePresenter::CompResourceChanged);
 }
 
 void TomographyIfaceViewQtGUI::runToolIndexChanged(int /* i */) {
   QComboBox *rt = m_uiTabRun.comboBox_run_tool;
-  if (!rt)
-    return;
-
   m_currentReconTool = rt->currentText().toStdString();
   m_presenter->notify(ITomographyIfacePresenter::ToolChanged);
 }
@@ -1101,7 +995,7 @@ void TomographyIfaceViewQtGUI::updatePathsConfig(const TomoPathsConfig &cfg) {
  * Updates the view/forms with new system settings (local and remote,
  * including multiple paths and path components)
  */
-void TomographyIfaceViewQtGUI::updateSystemSettings(
+void TomographyIfaceViewQtGUI::updateSystemSettingsTabFields(
     const TomoSystemSettings &setts) {
   // paths and related
   m_uiTabSystemSettings.lineEdit_path_comp_1st->setText(
@@ -1152,95 +1046,13 @@ void TomographyIfaceViewQtGUI::updateSystemSettings(
 /**
  * Displays and gets the results of a tool specific configuration dialog.
  *
- * @param name Name of the (tomographic reconstruction) tool
+ * @param dialog The pointer to the current dialog
  */
-void TomographyIfaceViewQtGUI::showToolConfig(const std::string &name) {
-  QString run = "/work/imat/phase_commissioning/scripts/Imaging/IMAT/"
-                "tomo_reconstruct.py"; // m_uiAstra.lineEdit_runnable->text();
-  static size_t reconIdx = 1;
-
-  const std::string localOutNameAppendix =
-      std::string("/processed/") + "reconstruction_" + std::to_string(reconIdx);
-
-  if (g_TomoPyTool == name) {
-    TomoToolConfigTomoPy tomopy;
-    m_uiTomoPy.setupUi(&tomopy);
-    m_uiTomoPy.comboBox_method->clear();
-    const auto methods = ToolConfigTomoPy::methods();
-    for (size_t i = 0; i < methods.size(); i++) {
-      m_uiTomoPy.comboBox_method->addItem(
-          QString::fromStdString(methods[i].second));
-    }
-    int res = tomopy.exec();
-
-    if (QDialog::Accepted == res) {
-      // TODO: move this
-      int mi = m_uiTomoPy.comboBox_method->currentIndex();
-
-      TomoPathsConfig paths = currentPathsConfig();
-      // TODO: for the output path, probably better to take the sample path,
-      // then up one level
-      m_toolsSettings.tomoPy = ToolConfigTomoPy(
-          run.toStdString(),
-          g_defOutPathLocal + "/" +
-              m_uiTabRun.lineEdit_experiment_reference->text().toStdString() +
-              localOutNameAppendix,
-          paths.pathDarks(), paths.pathOpenBeam(), paths.pathSamples());
-      m_tomopyMethod = methods[mi].first;
-    }
-  } else if (g_AstraTool == name) {
-    TomoToolConfigAstra astra;
-    m_uiAstra.setupUi(&astra);
-    m_uiAstra.comboBox_method->clear();
-    const auto methods = ToolConfigAstraToolbox::methods();
-    for (size_t i = 0; i < methods.size(); i++) {
-      m_uiAstra.comboBox_method->addItem(
-          QString::fromStdString(methods[i].second));
-    }
-    int res = astra.exec();
-
-    if (QDialog::Accepted == res) {
-      // TODO: move this
-      int mi = m_uiAstra.comboBox_method->currentIndex();
-
-      TomoPathsConfig paths = currentPathsConfig();
-      // TODO: for the output path, probably better to take the sample path,
-      // then up one level
-      m_toolsSettings.astra = ToolConfigAstraToolbox(
-          run.toStdString(),
-          Poco::Path::expand(
-              g_defOutPathLocal + "/" +
-              m_uiTabRun.lineEdit_experiment_reference->text().toStdString() +
-              localOutNameAppendix),
-          paths.pathDarks(), paths.pathOpenBeam(), paths.pathSamples());
-      m_astraMethod = methods[mi].first;
-    }
-  } else if (g_SavuTool == name) {
-    // TODO: savu not ready. This is a temporary kludge, it just shows
-    // the setup dialog so we can chat about it.
-    TomoToolConfigSavu savu;
-    m_uiSavu.setupUi(&savu);
-    doSetupSavu();
-    savu.setWindowModality(Qt::ApplicationModal);
-    savu.show();
-    QEventLoop el;
-    connect(this, SIGNAL(destroyed()), &el, SLOT(quit()));
-    el.exec();
-  } else if (g_customCmdTool == name) {
-    TomoToolConfigCustom cmd;
-    m_uiCustom.setupUi(&cmd);
-    int res = cmd.exec();
-
-    if (QDialog::Accepted == res) {
-      // TODO: move this
-      QString run = m_uiCustom.lineEdit_runnable->text();
-      QString opts = m_uiCustom.textEdit_cl_opts->toPlainText();
-
-      m_toolsSettings.custom =
-          ToolConfigCustom(run.toStdString(), opts.toStdString());
-    }
-  }
-  // TODO: 'CCPi CGLS' tool maybe in the future. Tool not ready.
+void TomographyIfaceViewQtGUI::showToolConfig(
+    TomoToolConfigDialogBase &dialog) {
+
+  // execute also intiialises all the parts of the GUI
+  dialog.initialiseGUIandExecute();
 }
 
 /**
@@ -1447,7 +1259,7 @@ std::string TomographyIfaceViewQtGUI::getPassword() const {
 void TomographyIfaceViewQtGUI::flatsPathCheckStatusChanged(int status) {
   bool enable = 0 != status;
   // Alternative behavior, whereby disabling would also imply clearing:
-  // TODO: not totally clear at the moment what users will prefer
+  // TODOVIEW: not totally clear at the moment what users will prefer
   // if (!enable) {
   //   m_pathsConfig.updatePathOpenBeam("");
   // } else {
@@ -1465,7 +1277,7 @@ void TomographyIfaceViewQtGUI::flatsPathCheckStatusChanged(int status) {
 void TomographyIfaceViewQtGUI::darksPathCheckStatusChanged(int status) {
   bool enable = 0 != status;
   // Alternative behavior, whereby disabling would also imply clearing:
-  // TODO: not totally clear at the moment what users will prefer
+  // TODOVIEW: not totally clear at the moment what users will prefer
   // if (!enable) {
   //   m_pathsConfig.updatePathDarks("");
   // } else {
@@ -1545,11 +1357,13 @@ void TomographyIfaceViewQtGUI::browseLocalReconScriptsDirClicked() {
                      "Select location of scripts (scripts subdirectory/folder "
                      "in the Mantid installation",
                      false);
+  systemSettingsEdited();
 }
 
 void TomographyIfaceViewQtGUI::browseLocalExternalInterpreterClicked() {
   checkUserBrowseFile(m_uiTabSystemSettings.lineEdit_local_external_interpreter,
                       "Select interpreter executable", false);
+  systemSettingsEdited();
 }
 
 /**
@@ -1607,7 +1421,7 @@ void TomographyIfaceViewQtGUI::showImage(const MatrixWorkspace_sptr &ws) {
   size_t width;
   try {
     width = boost::lexical_cast<size_t>(ws->run().getLogData("Axis1")->value());
-    // TODO: add a settings option for this (like max mem allocation for
+    // TODOVIEW: add a settings option for this (like max mem allocation for
     // images)?
     if (width >= MAXDIM)
       width = MAXDIM;
@@ -1715,7 +1529,7 @@ TomographyIfaceViewQtGUI::grabPrePostProcSettings() const {
   opts.prep.normalizeByAirRegion =
       m_uiTabFilters.checkBox_normalize_by_air_region->isChecked();
 
-  // TODO
+  // TODOVIEW
   // m_uiTabFilters.checkBox_normalize_by_proton_charge is disabled for now
   opts.prep.normalizeByProtonCharge = false;
 
@@ -1725,7 +1539,7 @@ TomographyIfaceViewQtGUI::grabPrePostProcSettings() const {
   opts.prep.normalizeByDarks =
       m_uiTabFilters.checkBox_normalize_by_darks->isChecked();
 
-  // TODO
+  // TODOVIEW
   // m_uiTabFilters.checkBox_corrections_MCP_detector is disabled for now
 
   opts.prep.medianFilterWidth = static_cast<size_t>(
@@ -1847,6 +1661,13 @@ TomographyIfaceViewQtGUI::grabSystemSettingsFromUser() const {
   setts.m_local.m_reconScriptsPath =
       m_uiTabSystemSettings.lineEdit_local_recon_scripts->text().toStdString();
 
+  setts.m_local.m_externalInterpreterPath =
+      m_uiTabSystemSettings.lineEdit_local_external_interpreter->text()
+          .toStdString();
+
+  setts.m_experimentReference =
+      m_uiTabRun.lineEdit_experiment_reference->text().toStdString();
+
   return setts;
 }
 
@@ -1860,7 +1681,7 @@ void TomographyIfaceViewQtGUI::sendToParaviewClicked() {
 }
 
 /**
- * Start a third party tool as a process. TODO: This is a very early
+ * Start a third party tool as a process. TODOVIEW: This is a very early
  * experimental implementation that should be moved out of this view.
  *
  * @param toolName Human understandable name of the tool/program
@@ -1955,7 +1776,7 @@ void TomographyIfaceViewQtGUI::defaultDirLocalVisualizeClicked() {
   if (!model)
     return;
 
-  // TODO: this should be moved to presenter?
+  // TODOVIEW: this should be moved to presenter?
   std::string checkedPath = checkDefaultVisualizeDir(
       m_uiTabSystemSettings.lineEdit_on_local_data_drive_or_path->text()
           .toStdString(),
@@ -1973,7 +1794,7 @@ void TomographyIfaceViewQtGUI::defaultDirRemoteVisualizeClicked() {
   if (!model)
     return;
 
-  // TODO: this should be moved to presenter?
+  // TODOVIEW: this should be moved to presenter?
   std::string checkedPath = checkDefaultVisualizeDir(
       m_uiTabSystemSettings.lineEdit_on_local_remote_data_drive_path->text()
           .toStdString(),
@@ -2098,19 +1919,33 @@ void TomographyIfaceViewQtGUI::systemSettingsNumericEdited() {
 }
 
 void TomographyIfaceViewQtGUI::resetSystemSettings() {
-  auto reply = QMessageBox::question(
-      this, "Reset Confirmation", "Are you sure you want to <br><strong>RESET "
-                                  "ALL</strong> System settings?<br>This "
-                                  "action cannot be undone!",
-      QMessageBox::Yes | QMessageBox::No);
+  const auto title = "Reset Confirmation";
+  const auto body = "Are you sure you want to <br><strong>RESET "
+                    "ALL</strong> System settings?<br>This "
+                    "action cannot be undone!";
   // default constructors with factory defaults
-  if (reply == QMessageBox::Yes) {
+  if (userConfirmation(title, body)) {
     // From factory defaults
     TomoSystemSettings defaults;
-    updateSystemSettings(defaults);
+    updateSystemSettingsTabFields(defaults);
   }
 }
 
+/**
+ * Prompts the user for confirmation with a yes/no dialogue.
+ * The body can use HTML formatting.
+ *
+ * @param title The title that the message has
+ * @param body The body that the message has. This CAN use HTML formatting
+ */
+bool TomographyIfaceViewQtGUI::userConfirmation(const std::string &title,
+                                                const std::string &body) {
+  auto reply = QMessageBox::question(this, QString::fromStdString(title),
+                                     QString::fromStdString(body),
+                                     QMessageBox::Yes | QMessageBox::No);
+  return reply == QMessageBox::Yes;
+}
+
 /**
 * Show a warning message to the user (pop up)
 *
@@ -2188,7 +2023,7 @@ void TomographyIfaceViewQtGUI::closeEvent(QCloseEvent *event) {
   }
 
   if (answer == QMessageBox::AcceptRole) {
-    // TODO? cleanup();
+    // TODOVIEW? cleanup();
     m_presenter->notify(ITomographyIfacePresenter::ShutDown);
     event->accept();
   } else {
diff --git a/MantidQt/CustomInterfaces/test/ALCPeakFittingPresenterTest.h b/MantidQt/CustomInterfaces/test/ALCPeakFittingPresenterTest.h
index 1efbd884c1dfbaf628f6699e7fccfc771749095e..8a48efdc0d1f463602cd282be2a09f65a5bccad7 100644
--- a/MantidQt/CustomInterfaces/test/ALCPeakFittingPresenterTest.h
+++ b/MantidQt/CustomInterfaces/test/ALCPeakFittingPresenterTest.h
@@ -139,7 +139,7 @@ public:
   }
 
   void test_fitEmptyFunction() {
-    auto ws = WorkspaceCreationHelper::Create2DWorkspace123(1, 3);
+    auto ws = WorkspaceCreationHelper::create2DWorkspace123(1, 3);
     ON_CALL(*m_model, data()).WillByDefault(Return(ws));
     ON_CALL(*m_view, function(QString("")))
         .WillByDefault(Return(IFunction_const_sptr()));
@@ -151,7 +151,7 @@ public:
   }
 
   void test_fit() {
-    auto ws = WorkspaceCreationHelper::Create2DWorkspace123(1, 3);
+    auto ws = WorkspaceCreationHelper::create2DWorkspace123(1, 3);
     ON_CALL(*m_model, data()).WillByDefault(Return(ws));
 
     IFunction_sptr peaks = createGaussian(1, 2, 3);
@@ -166,7 +166,7 @@ public:
   }
 
   void test_onDataChanged() {
-    auto ws = WorkspaceCreationHelper::Create2DWorkspace123(1, 3);
+    auto ws = WorkspaceCreationHelper::create2DWorkspace123(1, 3);
 
     ON_CALL(*m_model, data()).WillByDefault(Return(ws));
 
@@ -186,7 +186,7 @@ public:
     ON_CALL(*m_model, fittedPeaks())
         .WillByDefault(Return(createGaussian(1, 2, 3)));
 
-    auto ws = WorkspaceCreationHelper::Create2DWorkspace123(1, 3);
+    auto ws = WorkspaceCreationHelper::create2DWorkspace123(1, 3);
     ON_CALL(*m_model, data()).WillByDefault(Return(ws));
 
     // TODO: check better
@@ -200,7 +200,7 @@ public:
     ON_CALL(*m_model, fittedPeaks())
         .WillByDefault(Return(IFunction_const_sptr()));
 
-    auto ws = WorkspaceCreationHelper::Create2DWorkspace123(1, 3);
+    auto ws = WorkspaceCreationHelper::create2DWorkspace123(1, 3);
     ON_CALL(*m_model, data()).WillByDefault(Return(ws));
 
     EXPECT_CALL(*m_view, setFittedCurve(Property(&QwtData::size, 0)));
@@ -310,7 +310,7 @@ public:
    * Test that clicking "Plot guess" with no function set plots nothing
    */
   void test_plotGuess_noFunction() {
-    auto ws = WorkspaceCreationHelper::Create2DWorkspace123(1, 3);
+    auto ws = WorkspaceCreationHelper::create2DWorkspace123(1, 3);
     ON_CALL(*m_model, data()).WillByDefault(Return(ws));
     ON_CALL(*m_view, function(QString("")))
         .WillByDefault(Return(IFunction_const_sptr()));
@@ -334,7 +334,7 @@ public:
    * Test that "Plot guess" with a function set plots a function
    */
   void test_plotGuess() {
-    auto ws = WorkspaceCreationHelper::Create2DWorkspace123(1, 3);
+    auto ws = WorkspaceCreationHelper::create2DWorkspace123(1, 3);
     ON_CALL(*m_model, data()).WillByDefault(Return(ws));
     IFunction_sptr peaks = createGaussian(1, 2, 3);
     ON_CALL(*m_view, function(QString(""))).WillByDefault(Return(peaks));
diff --git a/MantidQt/CustomInterfaces/test/ImageROIPresenterTest.h b/MantidQt/CustomInterfaces/test/ImageROIPresenterTest.h
index e7a4db3c56b8abb409ac0067d878f343fbd5a727..852450bf411f86aef92c2a73eb93f7796aa9f4de 100644
--- a/MantidQt/CustomInterfaces/test/ImageROIPresenterTest.h
+++ b/MantidQt/CustomInterfaces/test/ImageROIPresenterTest.h
@@ -3,6 +3,7 @@
 
 #include "MantidAPI/FrameworkManager.h"
 #include "MantidAPI/MatrixWorkspace.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidQtCustomInterfaces/Tomography/ImageROIPresenter.h"
 #include "MantidTestHelpers/FakeObjects.h"
 
diff --git a/MantidQt/CustomInterfaces/test/MeasurementItemTest.h b/MantidQt/CustomInterfaces/test/MeasurementItemTest.h
index efd737ba924095c7387d9f3f3efb3f25822e278e..01527a6bc0344d5763166132d5d4ab0ca8279a6b 100644
--- a/MantidQt/CustomInterfaces/test/MeasurementItemTest.h
+++ b/MantidQt/CustomInterfaces/test/MeasurementItemTest.h
@@ -30,9 +30,11 @@ public:
     const std::string measurementType = "t";
     const double angle = 0.1;
     const std::string run = "123";
+    const std::string title = "title";
 
     MeasurementItem measurement(measurementId, measurementSubId,
-                                measurementLabel, measurementType, angle, run);
+                                measurementLabel, measurementType, angle, run,
+                                title);
 
     TS_ASSERT(measurement.isUseable());
     TS_ASSERT_EQUALS(measurementId, measurement.id());
@@ -46,7 +48,7 @@ public:
   void test_invalid_construction_when_measurementId_empty() {
 
     MeasurementItem measurement("", "measurementSubId", "measurementLabel",
-                                "measurementType", 0.1, "111");
+                                "measurementType", 0.1, "111", "title");
 
     TS_ASSERT(!measurement.isUseable());
   }
@@ -54,7 +56,7 @@ public:
   void test_invalid_construction_when_measurementSubId_empty() {
 
     MeasurementItem measurement("measurementId", "", "measurementLabel",
-                                "measurementType", 0.1, "111");
+                                "measurementType", 0.1, "111", "title");
 
     TS_ASSERT(!measurement.isUseable());
   }
@@ -62,17 +64,25 @@ public:
   void test_valid_construction_when_label_empty() {
 
     MeasurementItem measurement("measurementId", "measurementSubId", "",
-                                "measurementType", 0.1, "111");
+                                "measurementType", 0.1, "111", "title");
 
     TSM_ASSERT("Empty labels are not terminal", measurement.isUseable());
   }
 
   void test_valid_construction_when_type_empty() {
     MeasurementItem measurement("measurementId", "measurementSubId",
-                                "measurementLabel", "", 0.1, "111");
+                                "measurementLabel", "", 0.1, "111", "title");
 
     TSM_ASSERT("Empty type info is not terminal", measurement.isUseable());
   }
+
+  void test_valid_construction_when_title_empty() {
+    MeasurementItem measurement("measurementId", "measurementSubId",
+                                "measurementLabel", "measurementType", 0.1,
+                                "111", "");
+
+    TSM_ASSERT("Empty run title is not terminal", measurement.isUseable());
+  }
 };
 
 #endif /* MANTIDQT_CUSTOMINTERFACES_MEASUREMENTITEMTEST_H_ */
diff --git a/MantidQt/CustomInterfaces/test/MuonAnalysisFitDataPresenterTest.h b/MantidQt/CustomInterfaces/test/MuonAnalysisFitDataPresenterTest.h
index e7672354943ed6e5e00bd2e11f44576c4751e0b9..51875d3ccced55f00d688e8eab0143128c6c448b 100644
--- a/MantidQt/CustomInterfaces/test/MuonAnalysisFitDataPresenterTest.h
+++ b/MantidQt/CustomInterfaces/test/MuonAnalysisFitDataPresenterTest.h
@@ -39,7 +39,6 @@ class MockDataSelector : public IMuonFitDataSelector {
 public:
   GCC_DIAG_OFF_SUGGEST_OVERRIDE
   MOCK_CONST_METHOD0(getFilenames, QStringList());
-  MOCK_CONST_METHOD0(getWorkspaceIndex, unsigned int());
   MOCK_CONST_METHOD0(getStartTime, double());
   MOCK_CONST_METHOD0(getEndTime, double());
   MOCK_METHOD1(setNumPeriods, void(size_t));
@@ -49,7 +48,6 @@ public:
   MOCK_METHOD1(setAvailableGroups, void(const QStringList &));
   MOCK_CONST_METHOD0(getChosenGroups, QStringList());
   MOCK_METHOD1(setChosenGroup, void(const QString &));
-  MOCK_METHOD1(setWorkspaceIndex, void(unsigned int));
   MOCK_METHOD1(setStartTime, void(double));
   MOCK_METHOD1(setEndTime, void(double));
   MOCK_METHOD1(setStartTimeQuietly, void(double));
@@ -129,7 +127,6 @@ public:
   }
 
   void test_handleDataPropertiesChanged() {
-    ON_CALL(*m_dataSelector, getWorkspaceIndex()).WillByDefault(Return(0));
     ON_CALL(*m_dataSelector, getStartTime()).WillByDefault(Return(0.3));
     ON_CALL(*m_dataSelector, getEndTime()).WillByDefault(Return(9.9));
     EXPECT_CALL(*m_fitBrowser, setWorkspaceIndex(0)).Times(1);
@@ -178,7 +175,6 @@ public:
     const QString wsName("MUSR00015189; Pair; long; Asym; 1; #1");
     EXPECT_CALL(*m_dataSelector, setWorkspaceDetails(QString("00015189"),
                                                      QString("MUSR"))).Times(1);
-    EXPECT_CALL(*m_dataSelector, setWorkspaceIndex(0u)).Times(1);
     m_presenter->setAssignedFirstRun(wsName);
   }
 
@@ -187,7 +183,6 @@ public:
     const QString wsName("MUSR00015189-91; Pair; long; Asym; 1; #1");
     EXPECT_CALL(*m_dataSelector, setWorkspaceDetails(QString("00015189-91"),
                                                      QString("MUSR"))).Times(1);
-    EXPECT_CALL(*m_dataSelector, setWorkspaceIndex(0u)).Times(1);
     EXPECT_CALL(*m_dataSelector, setChosenGroup(QString("long"))).Times(1);
     EXPECT_CALL(*m_dataSelector, setChosenPeriod(QString("1"))).Times(1);
     m_presenter->setAssignedFirstRun(wsName);
@@ -199,7 +194,6 @@ public:
     EXPECT_CALL(*m_dataSelector,
                 setWorkspaceDetails(QString("00015189-91, 15193"),
                                     QString("MUSR"))).Times(1);
-    EXPECT_CALL(*m_dataSelector, setWorkspaceIndex(0u)).Times(1);
     EXPECT_CALL(*m_dataSelector, setChosenGroup(QString("long"))).Times(1);
     EXPECT_CALL(*m_dataSelector, setChosenPeriod(QString("1"))).Times(1);
     m_presenter->setAssignedFirstRun(wsName);
@@ -210,7 +204,6 @@ public:
     const QString wsName("MUSR00015189; Pair; long; Asym; 1; #1");
     m_presenter->setAssignedFirstRun(wsName);
     EXPECT_CALL(*m_dataSelector, setWorkspaceDetails(_, _)).Times(0);
-    EXPECT_CALL(*m_dataSelector, setWorkspaceIndex(_)).Times(0);
     EXPECT_CALL(*m_fitBrowser, allowSequentialFits(_)).Times(0);
     EXPECT_CALL(*m_dataSelector, setChosenGroup(QString("long"))).Times(0);
     EXPECT_CALL(*m_dataSelector, setChosenPeriod(QString("1"))).Times(0);
@@ -628,7 +621,6 @@ public:
     // Expect it will update the UI from workspace details
     EXPECT_CALL(*m_dataSelector, setWorkspaceDetails(QString("00015189-91"),
                                                      QString("MUSR"))).Times(1);
-    EXPECT_CALL(*m_dataSelector, setWorkspaceIndex(0)).Times(1);
     EXPECT_CALL(*m_dataSelector, setChosenGroup(QString("fwd"))).Times(1);
     EXPECT_CALL(*m_dataSelector, setChosenPeriod(QString("1"))).Times(1);
 
diff --git a/MantidQt/CustomInterfaces/test/MuonAnalysisFitFunctionPresenterTest.h b/MantidQt/CustomInterfaces/test/MuonAnalysisFitFunctionPresenterTest.h
index af09e408d59412eedb4ebc732a9ea59897732f48..438a1998e4cefebff40d7d712228ebaacd820ac2 100644
--- a/MantidQt/CustomInterfaces/test/MuonAnalysisFitFunctionPresenterTest.h
+++ b/MantidQt/CustomInterfaces/test/MuonAnalysisFitFunctionPresenterTest.h
@@ -13,6 +13,7 @@
 #include "MantidQtMantidWidgets/IMuonFitFunctionControl.h"
 
 using MantidQt::CustomInterfaces::MuonAnalysisFitFunctionPresenter;
+using MantidQt::CustomInterfaces::Muon::MultiFitState;
 using MantidQt::MantidWidgets::IFunctionBrowser;
 using MantidQt::MantidWidgets::IMuonFitFunctionControl;
 using namespace testing;
@@ -65,6 +66,9 @@ public:
   MOCK_METHOD1(userChangedDatasetIndex, void(int));
   MOCK_METHOD1(setMultiFittingMode, void(bool));
   MOCK_METHOD1(fitRawDataClicked, void(bool));
+  MOCK_METHOD0(doRemoveGuess, void());
+  MOCK_METHOD0(doPlotGuess, void());
+  MOCK_CONST_METHOD0(hasGuess, bool());
   GCC_DIAG_ON_SUGGEST_OVERRIDE
 };
 
@@ -212,14 +216,28 @@ public:
 
   void test_setMultiFitMode_On() {
     EXPECT_CALL(*m_fitBrowser, setMultiFittingMode(true)).Times(1);
-    m_presenter->setMultiFitState(
-        MantidQt::CustomInterfaces::Muon::MultiFitState::Enabled);
+    m_presenter->setMultiFitState(MultiFitState::Enabled);
   }
 
   void test_setMultiFitMode_Off() {
     EXPECT_CALL(*m_fitBrowser, setMultiFittingMode(false)).Times(1);
-    m_presenter->setMultiFitState(
-        MantidQt::CustomInterfaces::Muon::MultiFitState::Disabled);
+    m_presenter->setMultiFitState(MultiFitState::Disabled);
+  }
+
+  void test_setFunctionInModel_multiFitOn_hasGuess() {
+    doTest_setFunctionInModel(MultiFitState::Enabled, true);
+  }
+
+  void test_setFunctionInModel_multiFitOn_noGuess() {
+    doTest_setFunctionInModel(MultiFitState::Enabled, false);
+  }
+
+  void test_setFunctionInModel_multiFitOff_hasGuess() {
+    doTest_setFunctionInModel(MultiFitState::Disabled, true);
+  }
+
+  void test_setFunctionInModel_multiFitOff_noGuess() {
+    doTest_setFunctionInModel(MultiFitState::Disabled, false);
   }
 
 private:
@@ -227,7 +245,7 @@ private:
   void doTest_HandleFitFinishedOrUndone(const QString &wsName,
                                         bool compatibility) {
     const int times = compatibility ? 0 : 1;
-    const auto function = createFunction();
+    const auto &function = createFunction();
     ON_CALL(*m_fitBrowser, getFunction()).WillByDefault(Return(function));
     EXPECT_CALL(*m_fitBrowser, getFunction()).Times(times);
     EXPECT_CALL(*m_funcBrowser, updateMultiDatasetParameters(
@@ -235,6 +253,23 @@ private:
     m_presenter->handleFitFinished(wsName);
   }
 
+  /// Run a test of "setFunctionInModel" with the given options
+  void doTest_setFunctionInModel(MultiFitState multiState, bool hasGuess) {
+    m_presenter->setMultiFitState(multiState);
+    EXPECT_CALL(*m_fitBrowser, hasGuess())
+        .Times(AnyNumber())
+        .WillRepeatedly(Return(hasGuess));
+    const int times = multiState == MultiFitState::Enabled && hasGuess ? 1 : 0;
+    const auto &function = createFunction();
+    {
+      testing::InSequence s;
+      EXPECT_CALL(*m_fitBrowser, doRemoveGuess()).Times(times);
+      EXPECT_CALL(*m_fitBrowser, setFunction(function)).Times(1);
+      EXPECT_CALL(*m_fitBrowser, doPlotGuess()).Times(times);
+    }
+    m_presenter->setFunctionInModel(function);
+  }
+
   MockFunctionBrowser *m_funcBrowser;
   MockFitFunctionControl *m_fitBrowser;
   MuonAnalysisFitFunctionPresenter *m_presenter;
diff --git a/MantidQt/CustomInterfaces/test/MuonAnalysisHelperTest.h b/MantidQt/CustomInterfaces/test/MuonAnalysisHelperTest.h
index 6c7ac68b3a68eadb4221909f0b65c6b2eec3b32a..a99610cb87796108b85b2b51a6f64cb2fafd6195 100644
--- a/MantidQt/CustomInterfaces/test/MuonAnalysisHelperTest.h
+++ b/MantidQt/CustomInterfaces/test/MuonAnalysisHelperTest.h
@@ -11,6 +11,7 @@
 #include "MantidAPI/ScopedWorkspace.h"
 #include "MantidAPI/TableRow.h"
 #include "MantidAPI/WorkspaceFactory.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidGeometry/Instrument.h"
 #include "MantidKernel/TimeSeriesProperty.h"
 #include "MantidTestHelpers/WorkspaceCreationHelper.h"
@@ -124,11 +125,11 @@ public:
 
   void test_sumWorkspaces() {
     MatrixWorkspace_sptr ws1 =
-        WorkspaceCreationHelper::Create2DWorkspace123(1, 3);
+        WorkspaceCreationHelper::create2DWorkspace123(1, 3);
     MatrixWorkspace_sptr ws2 =
-        WorkspaceCreationHelper::Create2DWorkspace123(1, 3);
+        WorkspaceCreationHelper::create2DWorkspace123(1, 3);
     MatrixWorkspace_sptr ws3 =
-        WorkspaceCreationHelper::Create2DWorkspace123(1, 3);
+        WorkspaceCreationHelper::create2DWorkspace123(1, 3);
     DateAndTime start{"2015-12-23T15:32:40Z"};
     DateAndTime end{"2015-12-24T09:00:00Z"};
     addLog(ws1, "run_start", start.toSimpleString());
diff --git a/MantidQt/CustomInterfaces/test/ReflLegacyTransferStrategyTest.h b/MantidQt/CustomInterfaces/test/ReflLegacyTransferStrategyTest.h
index e01c9dd9ff2674bf21a08f4f211e446c12ed45e0..b24b560717714e2438467ebba8dbac31ef56fd16 100644
--- a/MantidQt/CustomInterfaces/test/ReflLegacyTransferStrategyTest.h
+++ b/MantidQt/CustomInterfaces/test/ReflLegacyTransferStrategyTest.h
@@ -38,19 +38,21 @@ public:
 
     expectedRow[ReflTableSchema::RUNS] = "1234";
     expectedRow[ReflTableSchema::ANGLE] = "";
-    expectedRow[ReflTableSchema::GROUP] = "0";
+    expectedRow[ReflTableSchema::GROUP] = "fictitious run on gold";
     expected.push_back(expectedRow);
 
     expectedRow[ReflTableSchema::RUNS] = "1235";
     expectedRow[ReflTableSchema::ANGLE] = "";
-    expectedRow[ReflTableSchema::GROUP] = "1";
+    expectedRow[ReflTableSchema::GROUP] = "fictitious run on silver";
     expected.push_back(expectedRow);
 
     expectedRow[ReflTableSchema::RUNS] = "1236";
     expectedRow[ReflTableSchema::ANGLE] = "";
-    expectedRow[ReflTableSchema::GROUP] = "2";
+    expectedRow[ReflTableSchema::GROUP] = "fictitious run on bronze";
     expected.push_back(expectedRow);
 
+    std::sort(expected.begin(), expected.end());
+
     ReflLegacyTransferStrategy strategy;
 
     MockProgressBase progress;
@@ -74,19 +76,21 @@ public:
 
     expectedRow[ReflTableSchema::RUNS] = "1233";
     expectedRow[ReflTableSchema::ANGLE] = "";
-    expectedRow[ReflTableSchema::GROUP] = "0";
+    expectedRow[ReflTableSchema::GROUP] = "fictitious run on platinum";
     expected.push_back(expectedRow);
 
     expectedRow[ReflTableSchema::RUNS] = "1234+1235";
     expectedRow[ReflTableSchema::ANGLE] = "";
-    expectedRow[ReflTableSchema::GROUP] = "1";
+    expectedRow[ReflTableSchema::GROUP] = "fictitious run on gold";
     expected.push_back(expectedRow);
 
     expectedRow[ReflTableSchema::RUNS] = "1236";
     expectedRow[ReflTableSchema::ANGLE] = "";
-    expectedRow[ReflTableSchema::GROUP] = "2";
+    expectedRow[ReflTableSchema::GROUP] = "fictitious run on silver";
     expected.push_back(expectedRow);
 
+    std::sort(expected.begin(), expected.end());
+
     ReflLegacyTransferStrategy strategy;
 
     MockProgressBase progress;
@@ -112,22 +116,22 @@ public:
 
     expectedRow[ReflTableSchema::RUNS] = "1234";
     expectedRow[ReflTableSchema::ANGLE] = "";
-    expectedRow[ReflTableSchema::GROUP] = "0";
+    expectedRow[ReflTableSchema::GROUP] = "fictitious run on gold";
     expected.push_back(expectedRow);
 
     expectedRow[ReflTableSchema::RUNS] = "1235";
     expectedRow[ReflTableSchema::ANGLE] = "3.14";
-    expectedRow[ReflTableSchema::GROUP] = "1";
+    expectedRow[ReflTableSchema::GROUP] = "fictitious run on silver in 3.14";
     expected.push_back(expectedRow);
 
     expectedRow[ReflTableSchema::RUNS] = "1236";
     expectedRow[ReflTableSchema::ANGLE] = "2.17";
-    expectedRow[ReflTableSchema::GROUP] = "2";
+    expectedRow[ReflTableSchema::GROUP] = "fictitious run on bronze";
     expected.push_back(expectedRow);
 
     expectedRow[ReflTableSchema::RUNS] = "1237";
     expectedRow[ReflTableSchema::ANGLE] = "1.23";
-    expectedRow[ReflTableSchema::GROUP] = "3";
+    expectedRow[ReflTableSchema::GROUP] = "fictitious run on platinum";
     expected.push_back(expectedRow);
 
     std::sort(expected.begin(), expected.end());
@@ -161,37 +165,37 @@ public:
 
     expectedRow[ReflTableSchema::RUNS] = "1230";
     expectedRow[ReflTableSchema::ANGLE] = "";
-    expectedRow[ReflTableSchema::GROUP] = "0";
+    expectedRow[ReflTableSchema::GROUP] = "fictitious run on gold";
     expected.push_back(expectedRow);
 
     expectedRow[ReflTableSchema::RUNS] = "1231+1232";
     expectedRow[ReflTableSchema::ANGLE] = "3.14";
-    expectedRow[ReflTableSchema::GROUP] = "1";
+    expectedRow[ReflTableSchema::GROUP] = "fictitious run on silver in 3.14";
     expected.push_back(expectedRow);
 
     expectedRow[ReflTableSchema::RUNS] = "1233";
     expectedRow[ReflTableSchema::ANGLE] = "2.17";
-    expectedRow[ReflTableSchema::GROUP] = "1";
+    expectedRow[ReflTableSchema::GROUP] = "fictitious run on silver in 3.14";
     expected.push_back(expectedRow);
 
     expectedRow[ReflTableSchema::RUNS] = "1234";
     expectedRow[ReflTableSchema::ANGLE] = "2.17";
-    expectedRow[ReflTableSchema::GROUP] = "2";
+    expectedRow[ReflTableSchema::GROUP] = "fictitious run on bronze";
     expected.push_back(expectedRow);
 
     expectedRow[ReflTableSchema::RUNS] = "1235";
     expectedRow[ReflTableSchema::ANGLE] = "1.23";
-    expectedRow[ReflTableSchema::GROUP] = "2";
+    expectedRow[ReflTableSchema::GROUP] = "fictitious run on bronze";
     expected.push_back(expectedRow);
 
     expectedRow[ReflTableSchema::RUNS] = "1236";
     expectedRow[ReflTableSchema::ANGLE] = "1.23";
-    expectedRow[ReflTableSchema::GROUP] = "3";
+    expectedRow[ReflTableSchema::GROUP] = "fictitious run on platinum";
     expected.push_back(expectedRow);
 
     expectedRow[ReflTableSchema::RUNS] = "1237";
     expectedRow[ReflTableSchema::ANGLE] = "";
-    expectedRow[ReflTableSchema::GROUP] = "4";
+    expectedRow[ReflTableSchema::GROUP] = "fictitious run on fool's gold";
     expected.push_back(expectedRow);
 
     std::sort(expected.begin(), expected.end());
diff --git a/MantidQt/CustomInterfaces/test/ReflMainWindowPresenterTest.h b/MantidQt/CustomInterfaces/test/ReflMainWindowPresenterTest.h
index 618a736e673933f27bbdadff1884b844a3628bf6..2db4b1e775569aeb85d268f4532ccd67ce89669e 100644
--- a/MantidQt/CustomInterfaces/test/ReflMainWindowPresenterTest.h
+++ b/MantidQt/CustomInterfaces/test/ReflMainWindowPresenterTest.h
@@ -31,12 +31,19 @@ public:
     MockMainWindowView mockView;
     MockRunsTabPresenter mockRunsPresenter;
     MockSettingsTabPresenter mockSettingsPresenter;
+    MockSaveTabPresenter mockSaveTabPresenter;
     ReflMainWindowPresenter presenter(&mockView, &mockRunsPresenter,
-                                      &mockSettingsPresenter);
+                                      &mockSettingsPresenter,
+                                      &mockSaveTabPresenter);
 
-    EXPECT_CALL(mockSettingsPresenter, getTransmissionOptions())
+    EXPECT_CALL(mockSettingsPresenter, getTransmissionOptions(0))
         .Times(Exactly(1));
-    presenter.getTransmissionOptions();
+    presenter.getTransmissionOptions(0);
+
+    EXPECT_CALL(mockSettingsPresenter, getTransmissionOptions(1))
+        .Times(Exactly(1));
+    presenter.getTransmissionOptions(1);
+
     TS_ASSERT(Mock::VerifyAndClearExpectations(&mockSettingsPresenter));
   }
 
@@ -44,11 +51,19 @@ public:
     MockMainWindowView mockView;
     MockRunsTabPresenter mockRunsPresenter;
     MockSettingsTabPresenter mockSettingsPresenter;
+    MockSaveTabPresenter mockSaveTabPresenter;
     ReflMainWindowPresenter presenter(&mockView, &mockRunsPresenter,
-                                      &mockSettingsPresenter);
+                                      &mockSettingsPresenter,
+                                      &mockSaveTabPresenter);
+
+    EXPECT_CALL(mockSettingsPresenter, getReductionOptions(0))
+        .Times(Exactly(1));
+    presenter.getReductionOptions(0);
+
+    EXPECT_CALL(mockSettingsPresenter, getReductionOptions(1))
+        .Times(Exactly(1));
+    presenter.getReductionOptions(1);
 
-    EXPECT_CALL(mockSettingsPresenter, getReductionOptions()).Times(Exactly(1));
-    presenter.getReductionOptions();
     TS_ASSERT(Mock::VerifyAndClearExpectations(&mockSettingsPresenter));
   }
 
@@ -56,11 +71,17 @@ public:
     MockMainWindowView mockView;
     MockRunsTabPresenter mockRunsPresenter;
     MockSettingsTabPresenter mockSettingsPresenter;
+    MockSaveTabPresenter mockSaveTabPresenter;
     ReflMainWindowPresenter presenter(&mockView, &mockRunsPresenter,
-                                      &mockSettingsPresenter);
+                                      &mockSettingsPresenter,
+                                      &mockSaveTabPresenter);
+
+    EXPECT_CALL(mockSettingsPresenter, getStitchOptions(0)).Times(Exactly(1));
+    presenter.getStitchOptions(0);
+
+    EXPECT_CALL(mockSettingsPresenter, getStitchOptions(1)).Times(Exactly(1));
+    presenter.getStitchOptions(1);
 
-    EXPECT_CALL(mockSettingsPresenter, getStitchOptions()).Times(Exactly(1));
-    presenter.getStitchOptions();
     TS_ASSERT(Mock::VerifyAndClearExpectations(&mockSettingsPresenter));
   }
 
@@ -68,8 +89,10 @@ public:
     MockMainWindowView mockView;
     MockRunsTabPresenter mockRunsPresenter;
     MockSettingsTabPresenter mockSettingsPresenter;
+    MockSaveTabPresenter mockSaveTabPresenter;
     ReflMainWindowPresenter presenter(&mockView, &mockRunsPresenter,
-                                      &mockSettingsPresenter);
+                                      &mockSettingsPresenter,
+                                      &mockSaveTabPresenter);
 
     EXPECT_CALL(mockView, askUserString("Prompt", "Title", "Value"))
         .Times(Exactly(1));
@@ -81,8 +104,10 @@ public:
     MockMainWindowView mockView;
     MockRunsTabPresenter mockRunsPresenter;
     MockSettingsTabPresenter mockSettingsPresenter;
+    MockSaveTabPresenter mockSaveTabPresenter;
     ReflMainWindowPresenter presenter(&mockView, &mockRunsPresenter,
-                                      &mockSettingsPresenter);
+                                      &mockSettingsPresenter,
+                                      &mockSaveTabPresenter);
 
     EXPECT_CALL(mockView, askUserYesNo("Prompt", "Title")).Times(Exactly(1));
     presenter.askUserYesNo("Prompt", "Title");
@@ -93,8 +118,10 @@ public:
     MockMainWindowView mockView;
     MockRunsTabPresenter mockRunsPresenter;
     MockSettingsTabPresenter mockSettingsPresenter;
+    MockSaveTabPresenter mockSaveTabPresenter;
     ReflMainWindowPresenter presenter(&mockView, &mockRunsPresenter,
-                                      &mockSettingsPresenter);
+                                      &mockSettingsPresenter,
+                                      &mockSaveTabPresenter);
 
     EXPECT_CALL(mockView, giveUserWarning("Prompt", "Title")).Times(Exactly(1));
     presenter.giveUserWarning("Prompt", "Title");
@@ -105,8 +132,10 @@ public:
     MockMainWindowView mockView;
     MockRunsTabPresenter mockRunsPresenter;
     MockSettingsTabPresenter mockSettingsPresenter;
+    MockSaveTabPresenter mockSaveTabPresenter;
     ReflMainWindowPresenter presenter(&mockView, &mockRunsPresenter,
-                                      &mockSettingsPresenter);
+                                      &mockSettingsPresenter,
+                                      &mockSaveTabPresenter);
 
     EXPECT_CALL(mockView, giveUserCritical("Prompt", "Title"))
         .Times(Exactly(1));
@@ -118,8 +147,10 @@ public:
     MockMainWindowView mockView;
     MockRunsTabPresenter mockRunsPresenter;
     MockSettingsTabPresenter mockSettingsPresenter;
+    MockSaveTabPresenter mockSaveTabPresenter;
     ReflMainWindowPresenter presenter(&mockView, &mockRunsPresenter,
-                                      &mockSettingsPresenter);
+                                      &mockSettingsPresenter,
+                                      &mockSaveTabPresenter);
 
     EXPECT_CALL(mockView, giveUserInfo("Prompt", "Title")).Times(Exactly(1));
     presenter.giveUserInfo("Prompt", "Title");
@@ -130,8 +161,10 @@ public:
     MockMainWindowView mockView;
     MockRunsTabPresenter mockRunsPresenter;
     MockSettingsTabPresenter mockSettingsPresenter;
+    MockSaveTabPresenter mockSaveTabPresenter;
     ReflMainWindowPresenter presenter(&mockView, &mockRunsPresenter,
-                                      &mockSettingsPresenter);
+                                      &mockSettingsPresenter,
+                                      &mockSaveTabPresenter);
 
     EXPECT_CALL(mockView, runPythonAlgorithm("Python code to run"))
         .Times(Exactly(1));
diff --git a/MantidQt/CustomInterfaces/test/ReflMeasureTransferStrategyTest.h b/MantidQt/CustomInterfaces/test/ReflMeasureTransferStrategyTest.h
index 85dc94244468eb72443e6b39f362ddae678dc2a5..54bcfb4b75b244d6fa158547a24dc9ccb0f84583 100644
--- a/MantidQt/CustomInterfaces/test/ReflMeasureTransferStrategyTest.h
+++ b/MantidQt/CustomInterfaces/test/ReflMeasureTransferStrategyTest.h
@@ -52,7 +52,7 @@ public:
     EXPECT_CALL(*mockMeasurementItemSource, obtain(_, _))
         .Times(Exactly(static_cast<int>(data.size())))
         .WillRepeatedly(
-            Return(MeasurementItem("a", "s_a", "l", "t", 0, "111")));
+            Return(MeasurementItem("a", "s_a", "l", "t", 0, "111", "title")));
 
     auto mockCatInfo = Mantid::Kernel::make_unique<MockICatalogInfo>();
     auto mockCatInfo_ptr = mockCatInfo.get();
@@ -95,9 +95,12 @@ public:
     // id
     EXPECT_CALL(*mockMeasurementItemSource, obtain(_, _))
         .Times(Exactly(static_cast<int>(data.size())))
-        .WillOnce(Return(MeasurementItem("m1", "s1", "l1", "t1", 0.1, "111")))
-        .WillOnce(Return(MeasurementItem("m1", "s2", "l1", "t1", 0.2, "122")))
-        .WillOnce(Return(MeasurementItem("m2", "s2", "l1", "t1", 0.2, "123")));
+        .WillOnce(Return(
+            MeasurementItem("m1", "s1", "l1", "t1", 0.1, "111", "title")))
+        .WillOnce(Return(
+            MeasurementItem("m1", "s2", "l1", "t1", 0.2, "122", "title")))
+        .WillOnce(Return(
+            MeasurementItem("m2", "s2", "l1", "t1", 0.2, "123", "title")));
 
     auto mockCatInfo = Mantid::Kernel::make_unique<MockICatalogInfo>();
     auto mockCatInfo_ptr = mockCatInfo.get();
@@ -132,10 +135,14 @@ public:
     TSM_ASSERT_EQUALS("Group should be the same for first two rows",
                       successfulRuns[0][ReflTableSchema::GROUP],
                       successfulRuns[1][ReflTableSchema::GROUP]);
+    TSM_ASSERT_EQUALS("Group should be '0 - title' for first two rows",
+                      successfulRuns[0][ReflTableSchema::GROUP], "0 - title");
 
     TSM_ASSERT_DIFFERS("Group should be different for last rows",
                        successfulRuns[0][ReflTableSchema::GROUP],
                        successfulRuns[2][ReflTableSchema::GROUP]);
+    TSM_ASSERT_EQUALS("Group should be '1 - title' for third row",
+                      successfulRuns[2][ReflTableSchema::GROUP], "1 - title");
 
     TS_ASSERT(Mock::VerifyAndClear(mockCatInfo_ptr));
     TS_ASSERT(Mock::VerifyAndClear(mockMeasurementItemSource_ptr));
@@ -158,9 +165,12 @@ public:
     // We have 2 with valid measurement ids and 1 with no measurement id
     EXPECT_CALL(*mockMeasurementItemSource, obtain(_, _))
         .Times(Exactly(static_cast<int>(data.size())))
-        .WillOnce(Return(MeasurementItem("", "s1", "l1", "t1", 0.1, "111")))
-        .WillOnce(Return(MeasurementItem("m1", "s1", "l1", "t1", 0.2, "122")))
-        .WillOnce(Return(MeasurementItem("m1", "s2", "l1", "t1", 0.2, "123")));
+        .WillOnce(
+             Return(MeasurementItem("", "s1", "l1", "t1", 0.1, "111", "title")))
+        .WillOnce(Return(
+            MeasurementItem("m1", "s1", "l1", "t1", 0.2, "122", "title")))
+        .WillOnce(Return(
+            MeasurementItem("m1", "s2", "l1", "t1", 0.2, "123", "title")));
 
     auto mockCatInfo = Mantid::Kernel::make_unique<MockICatalogInfo>();
     auto mockCatInfo_ptr = mockCatInfo.get();
@@ -219,9 +229,12 @@ public:
     // All 3 have same measurment id, but we also have 2 with same sub id.
     EXPECT_CALL(*mockMeasurementItemSource, obtain(_, _))
         .Times(Exactly(static_cast<int>(data.size())))
-        .WillOnce(Return(MeasurementItem("m1", "s1", "l1", "t1", 0.1, "111")))
-        .WillOnce(Return(MeasurementItem("m1", "s1", "l1", "t1", 0.2, "122")))
-        .WillOnce(Return(MeasurementItem("m1", "s2", "l1", "t1", 0.2, "123")));
+        .WillOnce(Return(
+            MeasurementItem("m1", "s1", "l1", "t1", 0.1, "111", "title")))
+        .WillOnce(Return(
+            MeasurementItem("m1", "s1", "l1", "t1", 0.2, "122", "title")))
+        .WillOnce(Return(
+            MeasurementItem("m1", "s2", "l1", "t1", 0.2, "123", "title")));
 
     auto mockCatInfo = Mantid::Kernel::make_unique<MockICatalogInfo>();
     auto mockCatInfo_ptr = mockCatInfo.get();
@@ -257,6 +270,8 @@ public:
       TSM_ASSERT_EQUALS("All should have the same group",
                         successfulRuns[0][ReflTableSchema::GROUP],
                         successfulRuns[i][ReflTableSchema::GROUP]);
+      TSM_ASSERT_EQUALS("Group should be '0 - title'",
+                        successfulRuns[i][ReflTableSchema::GROUP], "0 - title");
     }
 
     TS_ASSERT(Mock::VerifyAndClear(mockCatInfo_ptr));
@@ -283,11 +298,14 @@ public:
     // All 3 have same measurment id, but we also have 2 with same sub id.
     EXPECT_CALL(*mockMeasurementItemSource, obtain(_, _))
         .Times(Exactly(static_cast<int>(data.size())))
-        .WillOnce(Return(MeasurementItem("m1", "s1", "l1", "t1", 0.1, "14913")))
-        .WillOnce(Return(MeasurementItem("m1", "s1", "l1", "t1", 0.1, "14914")))
-        .WillOnce(Return(MeasurementItem("m2", "s1", "l1", "t1", 0.2, "14915")))
-        .WillOnce(
-            Return(MeasurementItem("m2", "s1", "l1", "t1", 0.2, "14916")));
+        .WillOnce(Return(
+            MeasurementItem("m1", "s1", "l1", "t1", 0.1, "14913", "title")))
+        .WillOnce(Return(
+            MeasurementItem("m1", "s1", "l1", "t1", 0.1, "14914", "title")))
+        .WillOnce(Return(
+            MeasurementItem("m2", "s1", "l1", "t1", 0.2, "14915", "title")))
+        .WillOnce(Return(
+            MeasurementItem("m2", "s1", "l1", "t1", 0.2, "14916", "title")));
 
     auto mockCatInfo = Mantid::Kernel::make_unique<MockICatalogInfo>();
     auto mockCatInfo_ptr = mockCatInfo.get();
@@ -319,6 +337,67 @@ public:
                       "14913+14914", successfulRuns[0][ReflTableSchema::RUNS]);
     TSM_ASSERT_EQUALS("Runs should be summed. Sub ids are the same.",
                       "14915+14916", successfulRuns[1][ReflTableSchema::RUNS]);
+    TSM_ASSERT_EQUALS("Group should be '0 - title'",
+                      successfulRuns[0][ReflTableSchema::GROUP], "0 - title");
+    TSM_ASSERT_EQUALS("Group should be '1 - title'",
+                      successfulRuns[1][ReflTableSchema::GROUP], "1 - title");
+
+    TS_ASSERT(Mock::VerifyAndClear(mockCatInfo_ptr));
+    TS_ASSERT(Mock::VerifyAndClear(mockMeasurementItemSource_ptr));
+  }
+
+  void test_same_id_but_different_title() {
+
+    SearchResultMap data;
+    data.insert(
+        std::make_pair<std::string, SearchResult>("14913", SearchResult()));
+    data.insert(
+        std::make_pair<std::string, SearchResult>("14914", SearchResult()));
+
+    auto mockMeasurementItemSource =
+        Mantid::Kernel::make_unique<MockReflMeasurementItemSource>();
+    auto mockMeasurementItemSource_ptr = mockMeasurementItemSource.get();
+
+    // Same measurment id but different title
+    EXPECT_CALL(*mockMeasurementItemSource, obtain(_, _))
+        .Times(Exactly(static_cast<int>(data.size())))
+        .WillOnce(Return(MeasurementItem("m1", "s1", "l1", "t1", 0.1, "14913",
+                                         "Sample 1 H=0.10")))
+        .WillOnce(Return(MeasurementItem("m1", "s2", "l1", "t1", 0.1, "14914",
+                                         "Sample 1 H=0.09")));
+
+    auto mockCatInfo = Mantid::Kernel::make_unique<MockICatalogInfo>();
+    auto mockCatInfo_ptr = mockCatInfo.get();
+    // We expect that every location will be translated/transformed to make it
+    // os specific
+    EXPECT_CALL(*mockCatInfo, transformArchivePath(_))
+        .Times(Exactly(static_cast<int>(data.size())))
+        .WillRepeatedly(Return(std::string()));
+
+    MockProgressBase progress;
+    // Expect a progress update
+    EXPECT_CALL(progress, doReport(_))
+        .Times(Exactly(static_cast<int>(data.size())));
+
+    // Make the transfer stragegy
+    ReflMeasureTransferStrategy strategy(std::move(mockCatInfo),
+                                         std::move(mockMeasurementItemSource));
+
+    // Do the transfer
+    auto transferResult = strategy.transferRuns(data, progress);
+    auto successfulRuns = transferResult.getTransferRuns();
+
+    // Check the transfer entries
+    TSM_ASSERT_EQUALS("Should have two rows", 2, successfulRuns.size());
+    TSM_ASSERT_DIFFERS("Runs should be the different for both columns",
+                       successfulRuns[0][ReflTableSchema::RUNS],
+                       successfulRuns[1][ReflTableSchema::RUNS]);
+    TSM_ASSERT_EQUALS("Group should be '0 - Sample 1 H=0.10'",
+                      successfulRuns[0][ReflTableSchema::GROUP],
+                      "0 - Sample 1 H=0.10");
+    TSM_ASSERT_EQUALS("Group should be '0 - Sample 1 H=0.10'",
+                      successfulRuns[1][ReflTableSchema::GROUP],
+                      "0 - Sample 1 H=0.10");
 
     TS_ASSERT(Mock::VerifyAndClear(mockCatInfo_ptr));
     TS_ASSERT(Mock::VerifyAndClear(mockMeasurementItemSource_ptr));
diff --git a/MantidQt/CustomInterfaces/test/ReflMockObjects.h b/MantidQt/CustomInterfaces/test/ReflMockObjects.h
index e1b7e200af8ef2d3baa45161b98ba7510f6919b0..54c76710396d004e918e1cf6c12ba732a33c04b6 100644
--- a/MantidQt/CustomInterfaces/test/ReflMockObjects.h
+++ b/MantidQt/CustomInterfaces/test/ReflMockObjects.h
@@ -8,8 +8,11 @@
 #include "MantidQtCustomInterfaces/Reflectometry/IReflMainWindowView.h"
 #include "MantidQtCustomInterfaces/Reflectometry/IReflRunsTabPresenter.h"
 #include "MantidQtCustomInterfaces/Reflectometry/IReflRunsTabView.h"
+#include "MantidQtCustomInterfaces/Reflectometry/IReflSettingsPresenter.h"
 #include "MantidQtCustomInterfaces/Reflectometry/IReflSettingsTabPresenter.h"
-#include "MantidQtCustomInterfaces/Reflectometry/IReflSettingsTabView.h"
+#include "MantidQtCustomInterfaces/Reflectometry/IReflSettingsView.h"
+#include "MantidQtCustomInterfaces/Reflectometry/IReflSaveTabView.h"
+#include "MantidQtCustomInterfaces/Reflectometry/IReflSaveTabPresenter.h"
 #include "MantidQtCustomInterfaces/Reflectometry/ReflSearchModel.h"
 #include "MantidQtMantidWidgets/DataProcessorUI/DataProcessorCommand.h"
 #include <gmock/gmock.h>
@@ -49,6 +52,7 @@ public:
   MOCK_CONST_METHOD0(getTransferMethod, std::string());
   MOCK_CONST_METHOD0(getAlgorithmRunner,
                      boost::shared_ptr<MantidQt::API::AlgorithmRunner>());
+  MOCK_CONST_METHOD0(getSelectedGroup, int());
   MOCK_METHOD1(setTransferMethods, void(const std::set<std::string> &));
   MOCK_METHOD0(setTableCommandsProxy, void());
   MOCK_METHOD0(setRowCommandsProxy, void());
@@ -58,10 +62,10 @@ public:
 
   // Calls we don't care about
   void showSearch(ReflSearchModel_sptr) override{};
-  IReflRunsTabPresenter *getPresenter() const override { return nullptr; }
+  IReflRunsTabPresenter *getPresenter() const override { return nullptr; };
 };
 
-class MockSettingsTabView : public IReflSettingsTabView {
+class MockSettingsView : public IReflSettingsView {
 public:
   // Global options
   MOCK_CONST_METHOD0(getTransmissionOptions, std::string());
@@ -94,7 +98,30 @@ public:
   createStitchHints(const std::map<std::string, std::string> &hints) override {
     UNUSED_ARG(hints);
   };
-  IReflSettingsTabPresenter *getPresenter() const override { return nullptr; }
+  IReflSettingsPresenter *getPresenter() const override { return nullptr; }
+};
+
+class MockSaveTabView : public IReflSaveTabView {
+public:
+  MOCK_CONST_METHOD1(setSavePath, void(const std::string &path));
+  MOCK_CONST_METHOD0(getSavePath, std::string());
+  MOCK_CONST_METHOD0(getPrefix, std::string());
+  MOCK_CONST_METHOD0(getFilter, std::string());
+  MOCK_CONST_METHOD0(getRegexCheck, bool());
+  MOCK_CONST_METHOD0(getCurrentWorkspaceName, std::string());
+  MOCK_CONST_METHOD0(getSelectedWorkspaces, std::vector<std::string>());
+  MOCK_CONST_METHOD0(getSelectedParameters, std::vector<std::string>());
+  MOCK_CONST_METHOD0(getFileFormatIndex, int());
+  MOCK_CONST_METHOD0(getTitleCheck, bool());
+  MOCK_CONST_METHOD0(getQResolutionCheck, bool());
+  MOCK_CONST_METHOD0(getSeparator, std::string());
+  MOCK_CONST_METHOD0(clearWorkspaceList, void());
+  MOCK_CONST_METHOD1(setWorkspaceList, void(const std::vector<std::string> &));
+  MOCK_CONST_METHOD0(clearParametersList, void());
+  MOCK_CONST_METHOD1(setParametersList, void(const std::vector<std::string> &));
+
+  // Calls we don't care about
+  IReflSaveTabPresenter *getPresenter() const override { return nullptr; }
 };
 
 class MockMainWindowView : public IReflMainWindowView {
@@ -122,29 +149,41 @@ public:
   ~MockRunsTabPresenter() override{};
 };
 
-class MockSettingsTabPresenter : public IReflSettingsTabPresenter {
+class MockSettingsPresenter : public IReflSettingsPresenter {
 public:
   MOCK_CONST_METHOD0(getTransmissionOptions, std::string());
   MOCK_CONST_METHOD0(getReductionOptions, std::string());
   MOCK_CONST_METHOD0(getStitchOptions, std::string());
-  // Other calls we don't care about
+  MOCK_METHOD1(setInstrumentName, void(const std::string &));
+  void notify(IReflSettingsPresenter::Flag flag) override { UNUSED_ARG(flag); }
+  ~MockSettingsPresenter() override{};
+};
+
+class MockSettingsTabPresenter : public IReflSettingsTabPresenter {
+public:
+  MOCK_CONST_METHOD1(getTransmissionOptions, std::string(int));
+  MOCK_CONST_METHOD1(getReductionOptions, std::string(int));
+  MOCK_CONST_METHOD1(getStitchOptions, std::string(int));
+  void setInstrumentName(const std::string &instName) override {
+    UNUSED_ARG(instName);
+  };
+  ~MockSettingsTabPresenter() override{};
+};
+
+class MockSaveTabPresenter : public IReflSaveTabPresenter {
+public:
+  void notify(IReflSaveTabPresenter::Flag flag) override { UNUSED_ARG(flag); };
   void acceptMainPresenter(IReflMainWindowPresenter *presenter) override {
     UNUSED_ARG(presenter);
   };
-  void notify(IReflSettingsTabPresenter::Flag flag) override {
-    UNUSED_ARG(flag);
-  };
-  void setInstrumentName(const std::string instName) override {
-    UNUSED_ARG(instName);
-  }
-  ~MockSettingsTabPresenter() override{};
+  ~MockSaveTabPresenter() override{};
 };
 
 class MockMainWindowPresenter : public IReflMainWindowPresenter {
 public:
-  MOCK_CONST_METHOD0(getTransmissionOptions, std::string());
-  MOCK_CONST_METHOD0(getReductionOptions, std::string());
-  MOCK_CONST_METHOD0(getStitchOptions, std::string());
+  MOCK_CONST_METHOD1(getTransmissionOptions, std::string(int));
+  MOCK_CONST_METHOD1(getReductionOptions, std::string(int));
+  MOCK_CONST_METHOD1(getStitchOptions, std::string(int));
   MOCK_CONST_METHOD0(getInstrumentName, std::string());
   MOCK_METHOD3(askUserString,
                std::string(const std::string &, const std::string &,
diff --git a/MantidQt/CustomInterfaces/test/ReflRunsTabPresenterTest.h b/MantidQt/CustomInterfaces/test/ReflRunsTabPresenterTest.h
index f42429c643fba381bfd9788a03c95b336b757cf5..b462c0d0237733ea26d3af46a493e6e38e7d180a 100644
--- a/MantidQt/CustomInterfaces/test/ReflRunsTabPresenterTest.h
+++ b/MantidQt/CustomInterfaces/test/ReflRunsTabPresenterTest.h
@@ -32,11 +32,9 @@ public:
   void test_constructor_sets_possible_transfer_methods() {
     NiceMock<MockRunsTabView> mockRunsTabView;
     MockProgressableView mockProgress;
-    MockDataProcessorPresenter mockTablePresenter;
-
-    // Expect that the table presenter accepts this presenter as a workspace
-    // receiver
-    EXPECT_CALL(mockTablePresenter, accept(_)).Times(Exactly(1));
+    NiceMock<MockDataProcessorPresenter> mockTablePresenter;
+    std::vector<DataProcessorPresenter *> tablePresenterVec;
+    tablePresenterVec.push_back(&mockTablePresenter);
 
     // Expect that the transfer methods get initialized on the view
     EXPECT_CALL(mockRunsTabView, setTransferMethods(_)).Times(Exactly(1));
@@ -45,20 +43,50 @@ public:
 
     // Constructor
     ReflRunsTabPresenter presenter(&mockRunsTabView, &mockProgress,
-                                   &mockTablePresenter);
+                                   tablePresenterVec);
 
     // Verify expectations
     TS_ASSERT(Mock::VerifyAndClearExpectations(&mockRunsTabView));
     TS_ASSERT(Mock::VerifyAndClearExpectations(&mockTablePresenter));
   }
 
-  void test_presenter_sets_commands_when_notified() {
+  void test_table_presenters_accept_this_presenter() {
+    NiceMock<MockRunsTabView> mockRunsTabView;
+    MockProgressableView mockProgress;
+    MockDataProcessorPresenter mockTablePresenter_1;
+    MockDataProcessorPresenter mockTablePresenter_2;
+    MockDataProcessorPresenter mockTablePresenter_3;
+    std::vector<DataProcessorPresenter *> tablePresenterVec;
+    tablePresenterVec.push_back(&mockTablePresenter_1);
+    tablePresenterVec.push_back(&mockTablePresenter_2);
+    tablePresenterVec.push_back(&mockTablePresenter_3);
+
+    // Expect that the table presenters accept this presenter as a workspace
+    // receiver
+    EXPECT_CALL(mockTablePresenter_1, accept(_)).Times(Exactly(1));
+    EXPECT_CALL(mockTablePresenter_2, accept(_)).Times(Exactly(1));
+    EXPECT_CALL(mockTablePresenter_3, accept(_)).Times(Exactly(1));
+
+    // Constructor
+    ReflRunsTabPresenter presenter(&mockRunsTabView, &mockProgress,
+                                   tablePresenterVec);
+
+    // Verify expectations
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&mockRunsTabView));
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&mockTablePresenter_1));
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&mockTablePresenter_2));
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&mockTablePresenter_3));
+  }
+
+  void test_presenter_sets_commands_when_ADS_changed() {
     NiceMock<MockRunsTabView> mockRunsTabView;
     MockProgressableView mockProgress;
     NiceMock<MockDataProcessorPresenter> mockTablePresenter;
+    std::vector<DataProcessorPresenter *> tablePresenterVec;
+    tablePresenterVec.push_back(&mockTablePresenter);
 
     ReflRunsTabPresenter presenter(&mockRunsTabView, &mockProgress,
-                                   &mockTablePresenter);
+                                   tablePresenterVec);
 
     // Expect that the view clears the list of commands
     EXPECT_CALL(mockRunsTabView, clearCommands()).Times(Exactly(1));
@@ -78,8 +106,11 @@ public:
     MockProgressableView mockProgress;
     NiceMock<MockDataProcessorPresenter> mockTablePresenter;
     MockMainWindowPresenter mockMainPresenter;
+    std::vector<DataProcessorPresenter *> tablePresenterVec;
+    tablePresenterVec.push_back(&mockTablePresenter);
+
     ReflRunsTabPresenter presenter(&mockRunsTabView, &mockProgress,
-                                   &mockTablePresenter);
+                                   tablePresenterVec);
     presenter.acceptMainPresenter(&mockMainPresenter);
 
     EXPECT_CALL(mockMainPresenter,
@@ -94,8 +125,10 @@ public:
     MockProgressableView mockProgress;
     NiceMock<MockDataProcessorPresenter> mockTablePresenter;
     MockMainWindowPresenter mockMainPresenter;
+    std::vector<DataProcessorPresenter *> tablePresenterVec;
+    tablePresenterVec.push_back(&mockTablePresenter);
     ReflRunsTabPresenter presenter(&mockRunsTabView, &mockProgress,
-                                   &mockTablePresenter);
+                                   tablePresenterVec);
     presenter.acceptMainPresenter(&mockMainPresenter);
 
     EXPECT_CALL(mockMainPresenter, askUserYesNo("Prompt", "Title")).Times(1);
@@ -109,8 +142,10 @@ public:
     MockProgressableView mockProgress;
     NiceMock<MockDataProcessorPresenter> mockTablePresenter;
     MockMainWindowPresenter mockMainPresenter;
+    std::vector<DataProcessorPresenter *> tablePresenterVec;
+    tablePresenterVec.push_back(&mockTablePresenter);
     ReflRunsTabPresenter presenter(&mockRunsTabView, &mockProgress,
-                                   &mockTablePresenter);
+                                   tablePresenterVec);
     presenter.acceptMainPresenter(&mockMainPresenter);
 
     EXPECT_CALL(mockMainPresenter, giveUserWarning("Prompt", "Warning Message"))
@@ -125,8 +160,10 @@ public:
     MockProgressableView mockProgress;
     NiceMock<MockDataProcessorPresenter> mockTablePresenter;
     MockMainWindowPresenter mockMainPresenter;
+    std::vector<DataProcessorPresenter *> tablePresenterVec;
+    tablePresenterVec.push_back(&mockTablePresenter);
     ReflRunsTabPresenter presenter(&mockRunsTabView, &mockProgress,
-                                   &mockTablePresenter);
+                                   tablePresenterVec);
     presenter.acceptMainPresenter(&mockMainPresenter);
 
     EXPECT_CALL(mockMainPresenter,
@@ -141,8 +178,10 @@ public:
     MockProgressableView mockProgress;
     NiceMock<MockDataProcessorPresenter> mockTablePresenter;
     MockMainWindowPresenter mockMainPresenter;
+    std::vector<DataProcessorPresenter *> tablePresenterVec;
+    tablePresenterVec.push_back(&mockTablePresenter);
     ReflRunsTabPresenter presenter(&mockRunsTabView, &mockProgress,
-                                   &mockTablePresenter);
+                                   tablePresenterVec);
     presenter.acceptMainPresenter(&mockMainPresenter);
 
     EXPECT_CALL(mockMainPresenter, runPythonAlgorithm("Python code to run"))
@@ -157,14 +196,21 @@ public:
     MockProgressableView mockProgress;
     NiceMock<MockDataProcessorPresenter> mockTablePresenter;
     MockMainWindowPresenter mockMainPresenter;
+    std::vector<DataProcessorPresenter *> tablePresenterVec;
+    tablePresenterVec.push_back(&mockTablePresenter);
     ReflRunsTabPresenter presenter(&mockRunsTabView, &mockProgress,
-                                   &mockTablePresenter);
+                                   tablePresenterVec);
     presenter.acceptMainPresenter(&mockMainPresenter);
 
-    EXPECT_CALL(mockMainPresenter, getTransmissionOptions()).Times(1);
+    int group = 199;
+    EXPECT_CALL(mockRunsTabView, getSelectedGroup())
+        .Times(Exactly(1))
+        .WillOnce(Return(group));
+    EXPECT_CALL(mockMainPresenter, getTransmissionOptions(group)).Times(1);
     presenter.getPreprocessingOptions();
 
     TS_ASSERT(Mock::VerifyAndClearExpectations(&mockMainPresenter));
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&mockRunsTabView));
   }
 
   void test_processingOptions() {
@@ -172,14 +218,21 @@ public:
     MockProgressableView mockProgress;
     NiceMock<MockDataProcessorPresenter> mockTablePresenter;
     MockMainWindowPresenter mockMainPresenter;
+    std::vector<DataProcessorPresenter *> tablePresenterVec;
+    tablePresenterVec.push_back(&mockTablePresenter);
     ReflRunsTabPresenter presenter(&mockRunsTabView, &mockProgress,
-                                   &mockTablePresenter);
+                                   tablePresenterVec);
     presenter.acceptMainPresenter(&mockMainPresenter);
 
-    EXPECT_CALL(mockMainPresenter, getReductionOptions()).Times(1);
+    int group = 199;
+    EXPECT_CALL(mockRunsTabView, getSelectedGroup())
+        .Times(Exactly(1))
+        .WillOnce(Return(group));
+    EXPECT_CALL(mockMainPresenter, getReductionOptions(group)).Times(1);
     presenter.getProcessingOptions();
 
     TS_ASSERT(Mock::VerifyAndClearExpectations(&mockMainPresenter));
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&mockRunsTabView));
   }
 
   void test_postprocessingOptions() {
@@ -187,14 +240,52 @@ public:
     MockProgressableView mockProgress;
     NiceMock<MockDataProcessorPresenter> mockTablePresenter;
     MockMainWindowPresenter mockMainPresenter;
+    std::vector<DataProcessorPresenter *> tablePresenterVec;
+    tablePresenterVec.push_back(&mockTablePresenter);
     ReflRunsTabPresenter presenter(&mockRunsTabView, &mockProgress,
-                                   &mockTablePresenter);
+                                   tablePresenterVec);
     presenter.acceptMainPresenter(&mockMainPresenter);
 
-    EXPECT_CALL(mockMainPresenter, getStitchOptions()).Times(1);
+    int group = 199;
+    EXPECT_CALL(mockRunsTabView, getSelectedGroup())
+        .Times(Exactly(1))
+        .WillOnce(Return(group));
+    EXPECT_CALL(mockMainPresenter, getStitchOptions(group)).Times(1);
     presenter.getPostprocessingOptions();
 
     TS_ASSERT(Mock::VerifyAndClearExpectations(&mockMainPresenter));
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&mockRunsTabView));
+  }
+
+  void test_when_group_changes_commands_are_updated() {
+    NiceMock<MockRunsTabView> mockRunsTabView;
+    MockProgressableView mockProgress;
+    NiceMock<MockDataProcessorPresenter> mockTablePresenter_0;
+    NiceMock<MockDataProcessorPresenter> mockTablePresenter_1;
+    NiceMock<MockDataProcessorPresenter> mockTablePresenter_2;
+    MockMainWindowPresenter mockMainPresenter;
+    std::vector<DataProcessorPresenter *> tablePresenterVec;
+    tablePresenterVec.push_back(&mockTablePresenter_0);
+    tablePresenterVec.push_back(&mockTablePresenter_1);
+    tablePresenterVec.push_back(&mockTablePresenter_2);
+
+    ReflRunsTabPresenter presenter(&mockRunsTabView, &mockProgress,
+                                   tablePresenterVec);
+    presenter.acceptMainPresenter(&mockMainPresenter);
+
+    EXPECT_CALL(mockRunsTabView, getSelectedGroup())
+        .Times(Exactly(1))
+        .WillOnce(Return(1));
+    // Commands should be updated with presenter of selected group
+    EXPECT_CALL(mockTablePresenter_0, publishCommandsMocked()).Times(0);
+    EXPECT_CALL(mockTablePresenter_1, publishCommandsMocked()).Times(1);
+    EXPECT_CALL(mockTablePresenter_2, publishCommandsMocked()).Times(0);
+    presenter.notify(IReflRunsTabPresenter::GroupChangedFlag);
+
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&mockMainPresenter));
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&mockTablePresenter_0));
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&mockTablePresenter_1));
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&mockTablePresenter_2));
   }
 };
 
diff --git a/MantidQt/CustomInterfaces/test/ReflSaveTabPresenterTest.h b/MantidQt/CustomInterfaces/test/ReflSaveTabPresenterTest.h
new file mode 100644
index 0000000000000000000000000000000000000000..b56f370f55f0286bc1f4f90d300f3b5de1b7db02
--- /dev/null
+++ b/MantidQt/CustomInterfaces/test/ReflSaveTabPresenterTest.h
@@ -0,0 +1,228 @@
+#ifndef MANTID_CUSTOMINTERFACES_REFLSAVETABPRESENTERTEST_H
+#define MANTID_CUSTOMINTERFACES_REFLSAVETABPRESENTERTEST_H
+
+#include <cxxtest/TestSuite.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "MantidTestHelpers/WorkspaceCreationHelper.h"
+#include "MantidQtCustomInterfaces/Reflectometry/ReflSaveTabPresenter.h"
+#include "MantidAPI/FrameworkManager.h"
+#include "MantidAPI/AlgorithmManager.h"
+#include "MantidAPI/MatrixWorkspace.h"
+#include "MantidAPI/Run.h"
+#include "ReflMockObjects.h"
+#include "Poco/File.h"
+#include "Poco/Path.h"
+
+using namespace MantidQt::CustomInterfaces;
+using namespace Mantid::API;
+using namespace testing;
+
+using Mantid::DataObjects::Workspace2D_sptr;
+
+//=====================================================================================
+// Functional tests
+//=====================================================================================
+class ReflSaveTabPresenterTest : public CxxTest::TestSuite {
+
+public:
+  // This pair of boilerplate methods prevent the suite being created statically
+  // This means the constructor isn't called when running other tests
+  static ReflSaveTabPresenterTest *createSuite() {
+    return new ReflSaveTabPresenterTest();
+  }
+  static void destroySuite(ReflSaveTabPresenterTest *suite) { delete suite; }
+
+  ReflSaveTabPresenterTest() { FrameworkManager::Instance(); }
+
+  void testPopulateWorkspaceList() {
+    MockSaveTabView mockView;
+    ReflSaveTabPresenter presenter(&mockView);
+
+    std::vector<std::string> wsNames = {"ws1", "ws2", "ws3"};
+    createWS(wsNames[0]);
+    createWS(wsNames[1]);
+    createWS(wsNames[2]);
+
+    // Group workspaces 1 and 2 together
+    IAlgorithm_sptr groupAlg =
+        AlgorithmManager::Instance().create("GroupWorkspaces");
+    groupAlg->setProperty("InputWorkspaces", {"ws1", "ws2"});
+    groupAlg->setProperty("OutputWorkspace", "groupWs");
+    groupAlg->execute();
+
+    EXPECT_CALL(mockView, clearWorkspaceList()).Times(Exactly(1));
+    // Workspace 'groupWs' should not be included in the workspace list
+    EXPECT_CALL(mockView, setWorkspaceList(wsNames)).Times(Exactly(1));
+    presenter.notify(IReflSaveTabPresenter::populateWorkspaceListFlag);
+    AnalysisDataService::Instance().clear();
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&mockView));
+  }
+
+  void testRefreshWorkspaceList() {
+    MockSaveTabView mockView;
+    ReflSaveTabPresenter presenter(&mockView);
+
+    createWS("ws1");
+
+    EXPECT_CALL(mockView, clearWorkspaceList()).Times(Exactly(2));
+    EXPECT_CALL(mockView, setWorkspaceList(std::vector<std::string>{"ws1"}))
+        .Times(Exactly(1));
+    EXPECT_CALL(mockView,
+                setWorkspaceList(std::vector<std::string>{"ws1", "ws2"}))
+        .Times(Exactly(1));
+    presenter.notify(IReflSaveTabPresenter::populateWorkspaceListFlag);
+    createWS("ws2");
+    presenter.notify(IReflSaveTabPresenter::populateWorkspaceListFlag);
+    AnalysisDataService::Instance().clear();
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&mockView));
+  }
+
+  void testFilterWorkspaceNoRegex() {
+    MockSaveTabView mockView;
+    ReflSaveTabPresenter presenter(&mockView);
+
+    createWS("anotherWs");
+    createWS("different");
+    createWS("someWsName");
+
+    EXPECT_CALL(mockView, clearWorkspaceList()).Times(Exactly(2));
+    EXPECT_CALL(mockView, setWorkspaceList(std::vector<std::string>{
+                              "anotherWs", "different", "someWsName"}))
+        .Times(Exactly(1));
+    EXPECT_CALL(mockView, getFilter()).Times(Exactly(1)).WillOnce(Return("Ws"));
+    EXPECT_CALL(mockView, getRegexCheck())
+        .Times(Exactly(1))
+        .WillOnce(Return(false));
+    EXPECT_CALL(mockView, setWorkspaceList(std::vector<std::string>{
+                              "anotherWs", "someWsName"})).Times(Exactly(1));
+    presenter.notify(IReflSaveTabPresenter::populateWorkspaceListFlag);
+    presenter.notify(IReflSaveTabPresenter::filterWorkspaceListFlag);
+    AnalysisDataService::Instance().clear();
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&mockView));
+  }
+
+  void testFilterWorkspaceWithRegex() {
+    MockSaveTabView mockView;
+    ReflSaveTabPresenter presenter(&mockView);
+
+    createWS("_42");
+    createWS("apple_113");
+    createWS("grape_");
+    createWS("pear_cut");
+
+    EXPECT_CALL(mockView, clearWorkspaceList()).Times(Exactly(2));
+    EXPECT_CALL(mockView, setWorkspaceList(std::vector<std::string>{
+                              "_42", "apple_113", "grape_", "pear_cut"}))
+        .Times(Exactly(1));
+    EXPECT_CALL(mockView, getFilter())
+        .Times(Exactly(1))
+        .WillOnce(Return("[a-zA-Z]*_[0-9]+"));
+    EXPECT_CALL(mockView, getRegexCheck())
+        .Times(Exactly(1))
+        .WillOnce(Return(true));
+    EXPECT_CALL(mockView,
+                setWorkspaceList(std::vector<std::string>{"_42", "apple_113"}))
+        .Times(Exactly(1));
+    presenter.notify(IReflSaveTabPresenter::populateWorkspaceListFlag);
+    presenter.notify(IReflSaveTabPresenter::filterWorkspaceListFlag);
+    AnalysisDataService::Instance().clear();
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&mockView));
+  }
+
+  void testPopulateParametersList() {
+    MockSaveTabView mockView;
+    ReflSaveTabPresenter presenter(&mockView);
+
+    createWS("ws1");
+    std::vector<std::string> logs;
+    const auto &properties = AnalysisDataService::Instance()
+                                 .retrieveWS<MatrixWorkspace>("ws1")
+                                 ->run()
+                                 .getProperties();
+    for (auto it = properties.begin(); it != properties.end(); it++) {
+      logs.push_back((*it)->name());
+    }
+
+    EXPECT_CALL(mockView, clearParametersList()).Times(Exactly(1));
+    EXPECT_CALL(mockView, getCurrentWorkspaceName())
+        .Times(Exactly(1))
+        .WillOnce(Return("ws1"));
+    EXPECT_CALL(mockView, setParametersList(logs)).Times(Exactly(1));
+    presenter.notify(IReflSaveTabPresenter::workspaceParamsFlag);
+    AnalysisDataService::Instance().clear();
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&mockView));
+  }
+
+  void testSaveWorkspaces() {
+    MockSaveTabView mockView;
+    ReflSaveTabPresenter presenter(&mockView);
+
+    std::string savePath = createSavePath();
+    std::vector<std::string> wsNames = {"ws1", "ws2", "ws3"};
+    createWS(wsNames[0]);
+    createWS(wsNames[1]);
+    createWS(wsNames[2]);
+
+    EXPECT_CALL(mockView, getSavePath())
+        .Times(Exactly(1))
+        .WillOnce(Return(savePath));
+    EXPECT_CALL(mockView, getTitleCheck())
+        .Times(Exactly(1))
+        .WillOnce(Return(false));
+    EXPECT_CALL(mockView, getSelectedParameters())
+        .Times(Exactly(1))
+        .WillOnce(Return(std::vector<std::string>()));
+    EXPECT_CALL(mockView, getQResolutionCheck())
+        .Times(Exactly(1))
+        .WillOnce(Return(false));
+    EXPECT_CALL(mockView, getSeparator())
+        .Times(Exactly(1))
+        .WillOnce(Return("comma"));
+    EXPECT_CALL(mockView, getPrefix()).Times(Exactly(1)).WillOnce(Return(""));
+    EXPECT_CALL(mockView, getFileFormatIndex())
+        .Times(Exactly(1))
+        .WillOnce(Return(0));
+    EXPECT_CALL(mockView, getSelectedWorkspaces())
+        .Times(Exactly(1))
+        .WillOnce(Return(wsNames));
+    presenter.notify(IReflSaveTabPresenter::saveWorkspacesFlag);
+    for (auto it = wsNames.begin(); it != wsNames.end(); it++) {
+      Poco::File(savePath + *it + ".dat").remove();
+    }
+    AnalysisDataService::Instance().clear();
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&mockView));
+  }
+
+  void testSuggestSaveDir() {
+    MockSaveTabView mockView;
+    ReflSaveTabPresenter presenter(&mockView);
+
+    std::string saveDir = Mantid::Kernel::ConfigService::Instance().getString(
+        "defaultsave.directory");
+
+    EXPECT_CALL(mockView, setSavePath(saveDir));
+    presenter.notify(IReflSaveTabPresenter::suggestSaveDirFlag);
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&mockView));
+  }
+
+private:
+  void createWS(std::string name) {
+    Workspace2D_sptr ws = WorkspaceCreationHelper::create2DWorkspace(10, 10);
+    AnalysisDataService::Instance().addOrReplace(name, ws);
+  }
+
+  std::string createSavePath() {
+    // First attempt to obtain path from default save directory
+    std::string savePath = Mantid::Kernel::ConfigService::Instance().getString(
+        "defaultsave.directory");
+    if (savePath.empty())
+      // Otherwise use current path as save directory
+      savePath = Poco::Path::current();
+
+    return savePath;
+  }
+};
+
+#endif /* MANTID_CUSTOMINTERFACES_REFLSAVETABPRESENTERTEST_H */
diff --git a/MantidQt/CustomInterfaces/test/ReflSettingsPresenterTest.h b/MantidQt/CustomInterfaces/test/ReflSettingsPresenterTest.h
new file mode 100644
index 0000000000000000000000000000000000000000..04529b96055ade06db1b55b57647f868f60cd6f8
--- /dev/null
+++ b/MantidQt/CustomInterfaces/test/ReflSettingsPresenterTest.h
@@ -0,0 +1,251 @@
+#ifndef MANTID_CUSTOMINTERFACES_REFLSETTINGSPRESENTERTEST_H
+#define MANTID_CUSTOMINTERFACES_REFLSETTINGSPRESENTERTEST_H
+
+#include <cxxtest/TestSuite.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "MantidAPI/AnalysisDataService.h"
+#include "MantidAPI/FrameworkManager.h"
+#include "MantidQtCustomInterfaces/Reflectometry/ReflSettingsPresenter.h"
+#include "ReflMockObjects.h"
+#include <boost/algorithm/string.hpp>
+
+using namespace MantidQt::CustomInterfaces;
+using namespace testing;
+
+namespace {
+class split_q {
+private:
+  mutable bool in_q;
+
+public:
+  split_q() : in_q(false) {}
+  bool operator()(char c) const {
+    if (c == '\"')
+      in_q = !in_q;
+    return !in_q && c == ',';
+  }
+};
+}
+
+//=====================================================================================
+// Functional tests
+//=====================================================================================
+class ReflSettingsPresenterTest : public CxxTest::TestSuite {
+
+public:
+  // This pair of boilerplate methods prevent the suite being created statically
+  // This means the constructor isn't called when running other tests
+  static ReflSettingsPresenterTest *createSuite() {
+    return new ReflSettingsPresenterTest();
+  }
+  static void destroySuite(ReflSettingsPresenterTest *suite) { delete suite; }
+
+  ReflSettingsPresenterTest() { FrameworkManager::Instance(); }
+
+  void testGetTransmissionOptions() {
+    MockSettingsView mockView;
+    ReflSettingsPresenter presenter(&mockView);
+
+    EXPECT_CALL(mockView, getAnalysisMode())
+        .Times(Exactly(1))
+        .WillOnce(Return("MultiDetectorAnalysis"));
+    EXPECT_CALL(mockView, getMonitorIntegralMin())
+        .Times(Exactly(1))
+        .WillOnce(Return("4"));
+    EXPECT_CALL(mockView, getMonitorIntegralMax())
+        .Times(Exactly(1))
+        .WillOnce(Return("10"));
+    EXPECT_CALL(mockView, getMonitorBackgroundMin())
+        .Times(Exactly(1))
+        .WillOnce(Return("12"));
+    EXPECT_CALL(mockView, getMonitorBackgroundMax())
+        .Times(Exactly(1))
+        .WillOnce(Return("17"));
+    EXPECT_CALL(mockView, getLambdaMin())
+        .Times(Exactly(1))
+        .WillOnce(Return("1"));
+    EXPECT_CALL(mockView, getLambdaMax())
+        .Times(Exactly(1))
+        .WillOnce(Return("15"));
+    EXPECT_CALL(mockView, getI0MonitorIndex())
+        .Times(Exactly(1))
+        .WillOnce(Return("2"));
+    EXPECT_CALL(mockView, getProcessingInstructions())
+        .Times(Exactly(1))
+        .WillOnce(Return("3,4"));
+    auto options = presenter.getTransmissionOptions();
+
+    std::vector<std::string> optionsVec;
+    boost::split(optionsVec, options, split_q());
+    TS_ASSERT_EQUALS(optionsVec[0], "AnalysisMode=MultiDetectorAnalysis");
+    TS_ASSERT_EQUALS(optionsVec[1], "MonitorIntegrationWavelengthMin=4");
+    TS_ASSERT_EQUALS(optionsVec[2], "MonitorIntegrationWavelengthMax=10");
+    TS_ASSERT_EQUALS(optionsVec[3], "MonitorBackgroundWavelengthMin=12");
+    TS_ASSERT_EQUALS(optionsVec[4], "MonitorBackgroundWavelengthMax=17");
+    TS_ASSERT_EQUALS(optionsVec[5], "WavelengthMin=1");
+    TS_ASSERT_EQUALS(optionsVec[6], "WavelengthMax=15");
+    TS_ASSERT_EQUALS(optionsVec[7], "I0MonitorIndex=2");
+    TS_ASSERT_EQUALS(optionsVec[8], "ProcessingInstructions=\"3,4\"");
+
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&mockView));
+  }
+
+  void testGetReductionOptions() {
+    MockSettingsView mockView;
+    ReflSettingsPresenter presenter(&mockView);
+
+    EXPECT_CALL(mockView, getAnalysisMode())
+        .Times(Exactly(1))
+        .WillOnce(Return("MultiDetectorAnalysis"));
+    EXPECT_CALL(mockView, getCRho())
+        .Times(Exactly(1))
+        .WillOnce(Return("2.5,0.4,1.1"));
+    EXPECT_CALL(mockView, getCAlpha())
+        .Times(Exactly(1))
+        .WillOnce(Return("0.6,0.9,1.2"));
+    EXPECT_CALL(mockView, getCAp())
+        .Times(Exactly(1))
+        .WillOnce(Return("100.0,17.0,44.0"));
+    EXPECT_CALL(mockView, getCPp())
+        .Times(Exactly(1))
+        .WillOnce(Return("0.54,0.33,1.81"));
+    EXPECT_CALL(mockView, getDirectBeam())
+        .Times(Exactly(1))
+        .WillOnce(Return("0,3"));
+    EXPECT_CALL(mockView, getPolarisationCorrections())
+        .Times(Exactly(1))
+        .WillOnce(Return("PNR"));
+    EXPECT_CALL(mockView, getIntMonCheck())
+        .Times(Exactly(1))
+        .WillOnce(Return("True"));
+    EXPECT_CALL(mockView, getMonitorIntegralMin())
+        .Times(Exactly(1))
+        .WillOnce(Return("4"));
+    EXPECT_CALL(mockView, getMonitorIntegralMax())
+        .Times(Exactly(1))
+        .WillOnce(Return("10"));
+    EXPECT_CALL(mockView, getMonitorBackgroundMin())
+        .Times(Exactly(1))
+        .WillOnce(Return("12"));
+    EXPECT_CALL(mockView, getMonitorBackgroundMax())
+        .Times(Exactly(1))
+        .WillOnce(Return("17"));
+    EXPECT_CALL(mockView, getLambdaMin())
+        .Times(Exactly(1))
+        .WillOnce(Return("1"));
+    EXPECT_CALL(mockView, getLambdaMax())
+        .Times(Exactly(1))
+        .WillOnce(Return("15"));
+    EXPECT_CALL(mockView, getI0MonitorIndex())
+        .Times(Exactly(1))
+        .WillOnce(Return("2"));
+    EXPECT_CALL(mockView, getScaleFactor())
+        .Times(Exactly(1))
+        .WillOnce(Return("2"));
+    EXPECT_CALL(mockView, getMomentumTransferStep())
+        .Times(Exactly(1))
+        .WillOnce(Return("-0.02"));
+    EXPECT_CALL(mockView, getProcessingInstructions())
+        .Times(Exactly(1))
+        .WillOnce(Return("3,4"));
+    EXPECT_CALL(mockView, getTransmissionRuns())
+        .Times(Exactly(1))
+        .WillOnce(Return("INTER00013463,INTER00013464"));
+    auto options = presenter.getReductionOptions();
+
+    std::vector<std::string> optionsVec;
+    boost::split(optionsVec, options, split_q());
+    TS_ASSERT_EQUALS(optionsVec[0], "AnalysisMode=MultiDetectorAnalysis");
+    TS_ASSERT_EQUALS(optionsVec[1], "CRho=\"2.5,0.4,1.1\"");
+    TS_ASSERT_EQUALS(optionsVec[2], "CAlpha=\"0.6,0.9,1.2\"");
+    TS_ASSERT_EQUALS(optionsVec[3], "CAp=\"100.0,17.0,44.0\"");
+    TS_ASSERT_EQUALS(optionsVec[4], "CPp=\"0.54,0.33,1.81\"");
+    TS_ASSERT_EQUALS(optionsVec[5], "RegionOfDirectBeam=\"0,3\"");
+    TS_ASSERT_EQUALS(optionsVec[6], "PolarizationAnalysis=PNR");
+    TS_ASSERT_EQUALS(optionsVec[7], "NormalizeByIntegratedMonitors=True");
+    TS_ASSERT_EQUALS(optionsVec[8], "MonitorIntegrationWavelengthMin=4");
+    TS_ASSERT_EQUALS(optionsVec[9], "MonitorIntegrationWavelengthMax=10");
+    TS_ASSERT_EQUALS(optionsVec[10], "MonitorBackgroundWavelengthMin=12");
+    TS_ASSERT_EQUALS(optionsVec[11], "MonitorBackgroundWavelengthMax=17");
+    TS_ASSERT_EQUALS(optionsVec[12], "WavelengthMin=1");
+    TS_ASSERT_EQUALS(optionsVec[13], "WavelengthMax=15");
+    TS_ASSERT_EQUALS(optionsVec[14], "I0MonitorIndex=2");
+    TS_ASSERT_EQUALS(optionsVec[15], "ScaleFactor=2");
+    TS_ASSERT_EQUALS(optionsVec[16], "MomentumTransferStep=-0.02");
+    TS_ASSERT_EQUALS(optionsVec[17], "ProcessingInstructions=\"3,4\"");
+    TS_ASSERT_EQUALS(optionsVec[18],
+                     "FirstTransmissionRun=TRANS_INTER00013463");
+    TS_ASSERT_EQUALS(optionsVec[19],
+                     "SecondTransmissionRun=TRANS_INTER00013464");
+
+    TS_ASSERT(AnalysisDataService::Instance().doesExist("TRANS_INTER00013463"));
+    TS_ASSERT(AnalysisDataService::Instance().doesExist("TRANS_INTER00013464"));
+    AnalysisDataService::Instance().clear();
+
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&mockView));
+  }
+
+  void testStitchOptions() {
+    MockSettingsView mockView;
+    ReflSettingsPresenter presenter(&mockView);
+
+    EXPECT_CALL(mockView, getStitchOptions()).Times(Exactly(1));
+    presenter.getStitchOptions();
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&mockView));
+  }
+
+  void testPolarisationOptionsEnabled() {
+    MockSettingsView mockView;
+    ReflSettingsPresenter presenter(&mockView);
+
+    EXPECT_CALL(mockView, setPolarisationOptionsEnabled(false))
+        .Times(Exactly(1));
+    presenter.setInstrumentName("INTER");
+    EXPECT_CALL(mockView, setPolarisationOptionsEnabled(true))
+        .Times(Exactly(1));
+    presenter.setInstrumentName("POLREF");
+  }
+
+  void testExperimentDefaults() {
+    MockSettingsView mockView;
+    ReflSettingsPresenter presenter(&mockView);
+    MockMainWindowPresenter mainPresenter;
+
+    // Set instrument to 'POLREF'
+    EXPECT_CALL(mockView, setPolarisationOptionsEnabled(true))
+        .Times(Exactly(1));
+    presenter.setInstrumentName("POLREF");
+
+    std::vector<std::string> defaults = {
+        "PointDetectorAnalysis", "None",
+        "1.006831,-0.011467,0.002244,-0.000095",
+        "1.017526,-0.017183,0.003136,-0.000140",
+        "0.917940,0.038265,-0.006645,0.000282",
+        "0.972762,0.001828,-0.000261,0.0", "1"};
+
+    EXPECT_CALL(mockView, setExpDefaults(defaults)).Times(1);
+    presenter.notify(IReflSettingsPresenter::ExpDefaultsFlag);
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&mockView));
+  }
+
+  void testInstrumentDefaults() {
+    MockSettingsView mockView;
+    MockMainWindowPresenter mainPresenter;
+    ReflSettingsPresenter presenter(&mockView);
+
+    // Set instrument to 'INTER'
+    EXPECT_CALL(mockView, setPolarisationOptionsEnabled(false))
+        .Times(Exactly(1));
+    presenter.setInstrumentName("INTER");
+
+    std::vector<double> defaults = {1., 4.0, 10., 15., 17., 1.0, 17., 2.0};
+
+    EXPECT_CALL(mockView, setInstDefaults(defaults)).Times(1);
+    presenter.notify(IReflSettingsPresenter::InstDefaultsFlag);
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&mockView));
+  }
+};
+
+#endif /* MANTID_CUSTOMINTERFACES_REFLSETTINGSPRESENTERTEST_H */
diff --git a/MantidQt/CustomInterfaces/test/ReflSettingsTabPresenterTest.h b/MantidQt/CustomInterfaces/test/ReflSettingsTabPresenterTest.h
index 992c5a7d530edac9c9ced79cf607c85d797fd9ca..8390fc7248d85a5e47a5caab038539f782ea8337 100644
--- a/MantidQt/CustomInterfaces/test/ReflSettingsTabPresenterTest.h
+++ b/MantidQt/CustomInterfaces/test/ReflSettingsTabPresenterTest.h
@@ -4,7 +4,9 @@
 #include <cxxtest/TestSuite.h>
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
+#include <boost/algorithm/string.hpp>
 
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/FrameworkManager.h"
 #include "MantidQtCustomInterfaces/Reflectometry/ReflSettingsTabPresenter.h"
 #include "ReflMockObjects.h"
@@ -12,21 +14,6 @@
 using namespace MantidQt::CustomInterfaces;
 using namespace testing;
 
-namespace {
-class split_q {
-private:
-  mutable bool in_q;
-
-public:
-  split_q() : in_q(false) {}
-  bool operator()(char c) const {
-    if (c == '\"')
-      in_q = !in_q;
-    return !in_q && c == ',';
-  }
-};
-}
-
 //=====================================================================================
 // Functional tests
 //=====================================================================================
@@ -44,207 +31,131 @@ public:
 
   ReflSettingsTabPresenterTest() { FrameworkManager::Instance(); }
 
-  void testGetTransmissionOptions() {
-    MockSettingsTabView mockView;
-    ReflSettingsTabPresenter presenter(&mockView);
-
-    EXPECT_CALL(mockView, getAnalysisMode())
-        .Times(Exactly(1))
-        .WillOnce(Return("MultiDetectorAnalysis"));
-    EXPECT_CALL(mockView, getMonitorIntegralMin())
-        .Times(Exactly(1))
-        .WillOnce(Return("4"));
-    EXPECT_CALL(mockView, getMonitorIntegralMax())
-        .Times(Exactly(1))
-        .WillOnce(Return("10"));
-    EXPECT_CALL(mockView, getMonitorBackgroundMin())
-        .Times(Exactly(1))
-        .WillOnce(Return("12"));
-    EXPECT_CALL(mockView, getMonitorBackgroundMax())
-        .Times(Exactly(1))
-        .WillOnce(Return("17"));
-    EXPECT_CALL(mockView, getLambdaMin())
-        .Times(Exactly(1))
-        .WillOnce(Return("1"));
-    EXPECT_CALL(mockView, getLambdaMax())
-        .Times(Exactly(1))
-        .WillOnce(Return("15"));
-    EXPECT_CALL(mockView, getI0MonitorIndex())
-        .Times(Exactly(1))
-        .WillOnce(Return("2"));
-    EXPECT_CALL(mockView, getProcessingInstructions())
-        .Times(Exactly(1))
-        .WillOnce(Return("\"3,4\""));
-    auto options = presenter.getTransmissionOptions();
-
-    std::vector<std::string> optionsVec;
-    boost::split(optionsVec, options, split_q());
-    TS_ASSERT_EQUALS(optionsVec[0], "AnalysisMode=MultiDetectorAnalysis");
-    TS_ASSERT_EQUALS(optionsVec[1], "MonitorIntegrationWavelengthMin=4");
-    TS_ASSERT_EQUALS(optionsVec[2], "MonitorIntegrationWavelengthMax=10");
-    TS_ASSERT_EQUALS(optionsVec[3], "MonitorBackgroundWavelengthMin=12");
-    TS_ASSERT_EQUALS(optionsVec[4], "MonitorBackgroundWavelengthMax=17");
-    TS_ASSERT_EQUALS(optionsVec[5], "WavelengthMin=1");
-    TS_ASSERT_EQUALS(optionsVec[6], "WavelengthMax=15");
-    TS_ASSERT_EQUALS(optionsVec[7], "I0MonitorIndex=2");
-    TS_ASSERT_EQUALS(optionsVec[8], "ProcessingInstructions=\"3,4\"");
-
-    TS_ASSERT(Mock::VerifyAndClearExpectations(&mockView));
-  }
+  void test_instrument_name() {
+    MockSettingsPresenter presenter_1;
+    MockSettingsPresenter presenter_2;
+    std::vector<IReflSettingsPresenter *> settingsPresenters;
+    settingsPresenters.push_back(&presenter_1);
+    settingsPresenters.push_back(&presenter_2);
+    ReflSettingsTabPresenter presenter(settingsPresenters);
 
-  void testGetReductionOptions() {
-    MockSettingsTabView mockView;
-    ReflSettingsTabPresenter presenter(&mockView);
-
-    EXPECT_CALL(mockView, getAnalysisMode())
-        .Times(Exactly(1))
-        .WillOnce(Return("MultiDetectorAnalysis"));
-    EXPECT_CALL(mockView, getCRho()).Times(Exactly(1)).WillOnce(Return("2.5"));
-    EXPECT_CALL(mockView, getCAlpha())
-        .Times(Exactly(1))
-        .WillOnce(Return("0.6"));
-    EXPECT_CALL(mockView, getCAp()).Times(Exactly(1)).WillOnce(Return("100.0"));
-    EXPECT_CALL(mockView, getCPp()).Times(Exactly(1)).WillOnce(Return("0.54"));
-    EXPECT_CALL(mockView, getDirectBeam())
-        .Times(Exactly(1))
-        .WillOnce(Return("\"0,3\""));
-    EXPECT_CALL(mockView, getPolarisationCorrections())
-        .Times(Exactly(1))
-        .WillOnce(Return("PNR"));
-    EXPECT_CALL(mockView, getIntMonCheck())
-        .Times(Exactly(1))
-        .WillOnce(Return("True"));
-    EXPECT_CALL(mockView, getMonitorIntegralMin())
-        .Times(Exactly(1))
-        .WillOnce(Return("4"));
-    EXPECT_CALL(mockView, getMonitorIntegralMax())
-        .Times(Exactly(1))
-        .WillOnce(Return("10"));
-    EXPECT_CALL(mockView, getMonitorBackgroundMin())
-        .Times(Exactly(1))
-        .WillOnce(Return("12"));
-    EXPECT_CALL(mockView, getMonitorBackgroundMax())
-        .Times(Exactly(1))
-        .WillOnce(Return("17"));
-    EXPECT_CALL(mockView, getLambdaMin())
-        .Times(Exactly(1))
-        .WillOnce(Return("1"));
-    EXPECT_CALL(mockView, getLambdaMax())
-        .Times(Exactly(1))
-        .WillOnce(Return("15"));
-    EXPECT_CALL(mockView, getI0MonitorIndex())
-        .Times(Exactly(1))
-        .WillOnce(Return("2"));
-    EXPECT_CALL(mockView, getScaleFactor())
-        .Times(Exactly(1))
-        .WillOnce(Return("2"));
-    EXPECT_CALL(mockView, getMomentumTransferStep())
-        .Times(Exactly(1))
-        .WillOnce(Return("-0.02"));
-    EXPECT_CALL(mockView, getProcessingInstructions())
-        .Times(Exactly(1))
-        .WillOnce(Return("\"3,4\""));
-    EXPECT_CALL(mockView, getTransmissionRuns())
-        .Times(Exactly(1))
-        .WillOnce(Return("INTER00013463,INTER00013464"));
-    auto options = presenter.getReductionOptions();
-
-    std::vector<std::string> optionsVec;
-    boost::split(optionsVec, options, split_q());
-    TS_ASSERT_EQUALS(optionsVec[0], "AnalysisMode=MultiDetectorAnalysis");
-    TS_ASSERT_EQUALS(optionsVec[1], "CRho=2.5");
-    TS_ASSERT_EQUALS(optionsVec[2], "CAlpha=0.6");
-    TS_ASSERT_EQUALS(optionsVec[3], "CAp=100.0");
-    TS_ASSERT_EQUALS(optionsVec[4], "CPp=0.54");
-    TS_ASSERT_EQUALS(optionsVec[5], "RegionOfDirectBeam=\"0,3\"");
-    TS_ASSERT_EQUALS(optionsVec[6], "PolarizationAnalysis=PNR");
-    TS_ASSERT_EQUALS(optionsVec[7], "NormalizeByIntegratedMonitors=True");
-    TS_ASSERT_EQUALS(optionsVec[8], "MonitorIntegrationWavelengthMin=4");
-    TS_ASSERT_EQUALS(optionsVec[9], "MonitorIntegrationWavelengthMax=10");
-    TS_ASSERT_EQUALS(optionsVec[10], "MonitorBackgroundWavelengthMin=12");
-    TS_ASSERT_EQUALS(optionsVec[11], "MonitorBackgroundWavelengthMax=17");
-    TS_ASSERT_EQUALS(optionsVec[12], "WavelengthMin=1");
-    TS_ASSERT_EQUALS(optionsVec[13], "WavelengthMax=15");
-    TS_ASSERT_EQUALS(optionsVec[14], "I0MonitorIndex=2");
-    TS_ASSERT_EQUALS(optionsVec[15], "ScaleFactor=2");
-    TS_ASSERT_EQUALS(optionsVec[16], "MomentumTransferStep=-0.02");
-    TS_ASSERT_EQUALS(optionsVec[17], "ProcessingInstructions=\"3,4\"");
-    TS_ASSERT_EQUALS(optionsVec[18],
-                     "FirstTransmissionRun=TRANS_INTER00013463");
-    TS_ASSERT_EQUALS(optionsVec[19],
-                     "SecondTransmissionRun=TRANS_INTER00013464");
-
-    TS_ASSERT(AnalysisDataService::Instance().doesExist("TRANS_INTER00013463"));
-    TS_ASSERT(AnalysisDataService::Instance().doesExist("TRANS_INTER00013464"));
-    AnalysisDataService::Instance().clear();
-
-    TS_ASSERT(Mock::VerifyAndClearExpectations(&mockView));
-  }
+    EXPECT_CALL(presenter_1, setInstrumentName("INSTRUMENT_NAME")).Times(1);
+    EXPECT_CALL(presenter_2, setInstrumentName("INSTRUMENT_NAME")).Times(1);
+    presenter.setInstrumentName("INSTRUMENT_NAME");
 
-  void testStitchOptions() {
-    MockSettingsTabView mockView;
-    ReflSettingsTabPresenter presenter(&mockView);
-
-    EXPECT_CALL(mockView, getStitchOptions()).Times(Exactly(1));
-    presenter.getStitchOptions();
-    TS_ASSERT(Mock::VerifyAndClearExpectations(&mockView));
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&presenter_1));
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&presenter_2));
   }
 
-  void testPolarisationOptionsEnabled() {
-    MockSettingsTabView mockView;
-    ReflSettingsTabPresenter presenter(&mockView);
-
-    EXPECT_CALL(mockView, setPolarisationOptionsEnabled(false))
-        .Times(Exactly(1));
-    presenter.setInstrumentName("INTER");
-    EXPECT_CALL(mockView, setPolarisationOptionsEnabled(true))
-        .Times(Exactly(1));
-    presenter.setInstrumentName("POLREF");
+  void test_transmission_options() {
+    MockSettingsPresenter presenter_0;
+    MockSettingsPresenter presenter_1;
+    MockSettingsPresenter presenter_2;
+
+    std::vector<IReflSettingsPresenter *> settingsPresenters;
+    settingsPresenters.push_back(&presenter_0);
+    settingsPresenters.push_back(&presenter_1);
+    settingsPresenters.push_back(&presenter_2);
+
+    ReflSettingsTabPresenter presenter(settingsPresenters);
+
+    EXPECT_CALL(presenter_0, getTransmissionOptions()).Times(1);
+    EXPECT_CALL(presenter_1, getTransmissionOptions()).Times(0);
+    EXPECT_CALL(presenter_2, getTransmissionOptions()).Times(0);
+    presenter.getTransmissionOptions(0);
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&presenter_0));
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&presenter_1));
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&presenter_2));
+
+    EXPECT_CALL(presenter_0, getTransmissionOptions()).Times(0);
+    EXPECT_CALL(presenter_1, getTransmissionOptions()).Times(1);
+    EXPECT_CALL(presenter_2, getTransmissionOptions()).Times(0);
+    presenter.getTransmissionOptions(1);
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&presenter_0));
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&presenter_1));
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&presenter_2));
+
+    EXPECT_CALL(presenter_0, getTransmissionOptions()).Times(0);
+    EXPECT_CALL(presenter_1, getTransmissionOptions()).Times(0);
+    EXPECT_CALL(presenter_2, getTransmissionOptions()).Times(1);
+    presenter.getTransmissionOptions(2);
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&presenter_0));
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&presenter_1));
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&presenter_2));
   }
 
-  void testExperimentDefaults() {
-    MockSettingsTabView mockView;
-    ReflSettingsTabPresenter presenter(&mockView);
-    MockMainWindowPresenter mainPresenter;
-
-    // This presenter accepts the main presenter
-    presenter.acceptMainPresenter(&mainPresenter);
-
-    // Set instrument to 'POLREF'
-    EXPECT_CALL(mockView, setPolarisationOptionsEnabled(true))
-        .Times(Exactly(1));
-    presenter.setInstrumentName("POLREF");
-
-    std::vector<std::string> defaults = {
-        "PointDetectorAnalysis", "None",
-        "1.006831,-0.011467,0.002244,-0.000095",
-        "1.017526,-0.017183,0.003136,-0.000140",
-        "0.917940,0.038265,-0.006645,0.000282",
-        "0.972762,0.001828,-0.000261,0.0", "1"};
-
-    EXPECT_CALL(mockView, setExpDefaults(defaults)).Times(1);
-    presenter.notify(IReflSettingsTabPresenter::ExpDefaultsFlag);
-    TS_ASSERT(Mock::VerifyAndClearExpectations(&mockView));
+  void test_reduction_options() {
+    MockSettingsPresenter presenter_0;
+    MockSettingsPresenter presenter_1;
+    MockSettingsPresenter presenter_2;
+
+    std::vector<IReflSettingsPresenter *> settingsPresenters;
+    settingsPresenters.push_back(&presenter_0);
+    settingsPresenters.push_back(&presenter_1);
+    settingsPresenters.push_back(&presenter_2);
+
+    ReflSettingsTabPresenter presenter(settingsPresenters);
+
+    EXPECT_CALL(presenter_0, getReductionOptions()).Times(1);
+    EXPECT_CALL(presenter_1, getReductionOptions()).Times(0);
+    EXPECT_CALL(presenter_2, getReductionOptions()).Times(0);
+    presenter.getReductionOptions(0);
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&presenter_0));
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&presenter_1));
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&presenter_2));
+
+    EXPECT_CALL(presenter_0, getReductionOptions()).Times(0);
+    EXPECT_CALL(presenter_1, getReductionOptions()).Times(1);
+    EXPECT_CALL(presenter_2, getReductionOptions()).Times(0);
+    presenter.getReductionOptions(1);
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&presenter_0));
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&presenter_1));
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&presenter_2));
+
+    EXPECT_CALL(presenter_0, getReductionOptions()).Times(0);
+    EXPECT_CALL(presenter_1, getReductionOptions()).Times(0);
+    EXPECT_CALL(presenter_2, getReductionOptions()).Times(1);
+    presenter.getReductionOptions(2);
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&presenter_0));
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&presenter_1));
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&presenter_2));
   }
 
-  void testInstrumentDefaults() {
-    MockSettingsTabView mockView;
-    MockMainWindowPresenter mainPresenter;
-    ReflSettingsTabPresenter presenter(&mockView);
-
-    // This presenter accepts the main presenter
-    presenter.acceptMainPresenter(&mainPresenter);
-
-    // Set instrument to 'INTER'
-    EXPECT_CALL(mockView, setPolarisationOptionsEnabled(false))
-        .Times(Exactly(1));
-    presenter.setInstrumentName("INTER");
-
-    std::vector<double> defaults = {1., 4.0, 10., 15., 17., 1.0, 17., 2.0};
-
-    EXPECT_CALL(mockView, setInstDefaults(defaults)).Times(1);
-    presenter.notify(IReflSettingsTabPresenter::InstDefaultsFlag);
-    TS_ASSERT(Mock::VerifyAndClearExpectations(&mockView));
+  void test_stitch_options() {
+    MockSettingsPresenter presenter_0;
+    MockSettingsPresenter presenter_1;
+    MockSettingsPresenter presenter_2;
+
+    std::vector<IReflSettingsPresenter *> settingsPresenters;
+    settingsPresenters.push_back(&presenter_0);
+    settingsPresenters.push_back(&presenter_1);
+    settingsPresenters.push_back(&presenter_2);
+
+    ReflSettingsTabPresenter presenter(settingsPresenters);
+
+    EXPECT_CALL(presenter_0, getStitchOptions()).Times(1);
+    EXPECT_CALL(presenter_1, getStitchOptions()).Times(0);
+    EXPECT_CALL(presenter_2, getStitchOptions()).Times(0);
+    presenter.getStitchOptions(0);
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&presenter_0));
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&presenter_1));
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&presenter_2));
+
+    EXPECT_CALL(presenter_0, getStitchOptions()).Times(0);
+    EXPECT_CALL(presenter_1, getStitchOptions()).Times(1);
+    EXPECT_CALL(presenter_2, getStitchOptions()).Times(0);
+    presenter.getStitchOptions(1);
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&presenter_0));
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&presenter_1));
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&presenter_2));
+
+    EXPECT_CALL(presenter_0, getStitchOptions()).Times(0);
+    EXPECT_CALL(presenter_1, getStitchOptions()).Times(0);
+    EXPECT_CALL(presenter_2, getStitchOptions()).Times(1);
+    presenter.getStitchOptions(2);
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&presenter_0));
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&presenter_1));
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&presenter_2));
   }
 };
 
diff --git a/MantidQt/CustomInterfaces/test/TomographyIfaceModelTest.h b/MantidQt/CustomInterfaces/test/TomographyIfaceModelTest.h
index 90b2182aace59ec6e3fb45e43297822f0345aac3..8abf9d97d9546073cef297ab918e06e752bd7ee1 100644
--- a/MantidQt/CustomInterfaces/test/TomographyIfaceModelTest.h
+++ b/MantidQt/CustomInterfaces/test/TomographyIfaceModelTest.h
@@ -3,11 +3,16 @@
 
 #include "MantidAPI/FrameworkManager.h"
 #include "MantidAPI/MatrixWorkspace.h"
+#include "MantidKernel/ConfigService.h"
 #include "MantidKernel/FacilityInfo.h"
+
 #include "MantidQtCustomInterfaces/Tomography/TomographyIfaceModel.h"
 
+#include "MantidQtCustomInterfaces/Tomography/TomoToolConfigDialogBase.h"
+
 #include <cxxtest/TestSuite.h>
 
+using namespace Mantid::API;
 using namespace MantidQt::CustomInterfaces;
 
 class TomographyIfaceModelTest : public CxxTest::TestSuite {
@@ -107,7 +112,7 @@ public:
     model.setupRunTool("Local");
 
     TSM_ASSERT_THROWS_NOTHING("Problem with experiment number",
-                              model.updateExperimentReference("RB0001234"));
+                              model.setExperimentReference("RB0001234"));
 
     auto sts = model.jobsStatus();
     TSM_ASSERT_EQUALS("Unexpected number of jobs", sts.size(), 0);
@@ -167,95 +172,234 @@ public:
     TS_ASSERT_EQUALS(cmds.size(), 0);
   }
 
-  void test_submitFailEmptyDefinition() {
+  void test_cancelFail() {
     TomographyIfaceModel model;
 
-    TSM_ASSERT_THROWS("Exception not thrown as expected - submit local",
-                      model.doSubmitReconstructionJob("Local"),
-                      std::invalid_argument);
+    TSM_ASSERT_EQUALS("Should not be logged in", model.loggedIn(), "");
+
+    const std::vector<std::string> ids = {"none", "inexistent"};
+    TSM_ASSERT_THROWS("Exception not thrown as expected - login local",
+                      model.doCancelJobs("Local", ids), std::invalid_argument);
   }
 
-  void test_submitFailWrongResource() {
+  void test_loadFITSFail() {
     TomographyIfaceModel model;
 
-    model.setupComputeResource();
-    model.setupRunTool("Local");
-    model.usingTool("TomoPy");
-    TSM_ASSERT_THROWS("Exception not thrown as expected - submit local",
-                      model.doSubmitReconstructionJob("Local"),
+    TSM_ASSERT_THROWS("Exception not thrown as expected - load FITS",
+                      model.loadFITSImage("/i_dont_exist.nope"),
                       std::invalid_argument);
   }
 
-  void test_cancelFail() {
-    TomographyIfaceModel model;
+  // this currently just transforms the names to lower case
+  void test_prepareToolNameForArgs() {
 
-    TSM_ASSERT_EQUALS("Should not be logged in", model.loggedIn(), "");
+    TestableTomographyIfaceModel model;
 
-    const std::vector<std::string> ids = {"none", "inexistent"};
-    TSM_ASSERT_THROWS("Exception not thrown as expected - login local",
-                      model.doCancelJobs("Local", ids), std::invalid_argument);
+    const std::string exp1 = model.prepareToolNameForArgs("TomoPy");
+    const std::string exp2 = model.prepareToolNameForArgs("Astra");
+    const std::string exp3 = model.prepareToolNameForArgs("Savu");
+    const std::string exp4 = model.prepareToolNameForArgs("Custom Command");
+
+    TS_ASSERT_EQUALS(exp1, "tomopy");
+    TS_ASSERT_EQUALS(exp2, "astra");
+    TS_ASSERT_EQUALS(exp3, "savu");
+    TS_ASSERT_EQUALS(exp4, "custom command");
+    // although custom command never reaches that function
   }
 
-  void test_runCustomCommandLocally() {
-    TomographyIfaceModel model;
+  void test_makeRemoteRunnableWithOptionsCustom() {
+    std::string inputRunnable = "/scriptPath/";
+    // the custom one just processes a single member
+    std::vector<std::string> inputArgsVector{
+        "--some params --some other params"};
 
-    model.setupComputeResource();
-    model.setupRunTool("Local");
-    model.usingTool("Custom command");
+    TestableTomographyIfaceModel model;
 
-    TomoReconToolsUserSettings toolsSettings;
-    toolsSettings.custom = ToolConfigCustom("fail", "some params");
-    model.updateReconToolsSettings(toolsSettings);
-    model.doRunReconstructionJobLocal();
-  }
+    std::string inputArgsString =
+        model.constructSingleStringFromVector(inputArgsVector);
 
-  void test_setupToolsTomoPy() { dryRunToolLocal("TomoPy", "gridrec"); }
+    std::shared_ptr<TomoRecToolConfig> d = std::shared_ptr<TomoRecToolConfig>(
+        new ToolConfigCustom(inputRunnable, inputArgsString));
 
-  void test_setupToolsAstra() { dryRunToolLocal("Astra", "FBP3D_CUDA"); }
+    model.usingTool(TestableTomographyIfaceModel::g_customCmdTool);
+    model.setCurrentToolMethod("gridrec");
 
-  void test_loadFITSFail() {
-    TomographyIfaceModel model;
+    model.setCurrentToolSettings(d);
 
-    TSM_ASSERT_THROWS("Exception not thrown as expected - load FITS",
-                      model.loadFITSImage("/i_dont_exist.nope"),
-                      std::invalid_argument);
+    const bool local = false;
+
+    std::string actualRunnable;
+    std::string allOpts;
+    std::vector<std::string> actualArgsVector;
+    model.prepareSubmissionArguments(local, actualRunnable, actualArgsVector,
+                                     allOpts);
+
+    std::string expectedRunnable = "/scriptPath/";
+    // the space at the end is necessary, because of how
+    // constructSingleStringFromVector works
+    std::vector<std::string> expectedArgsVector{
+        "--some params --some other params "};
+    doTestExpectedRunnableAndArguments(expectedRunnable, actualRunnable,
+                                       expectedArgsVector, actualArgsVector);
   }
 
-private:
-  void dryRunToolLocal(const std::string &tool, const std::string &method) {
-    TomographyIfaceModel model;
-    model.setupComputeResource();
-    model.setupRunTool(model.localComputeResource());
-    model.usingTool(tool);
-    model.updateTomopyMethod(method);
+  void test_makeLocalRunnableWithOptionsCustom() {
+    std::string inputRunnable = "python /scriptPath/";
+    // the custom one just processes a single member
+    std::vector<std::string> inputArgsVector{
+        "--some params --some other params"};
 
-    TSM_ASSERT_EQUALS("Unexpected number of reconstruction tools",
-                      model.reconTools().size(), 5);
+    TestableTomographyIfaceModel model;
 
-    auto localSts = model.jobsStatusLocal();
-    TSM_ASSERT_EQUALS("Unexpected number of jobs (local)", localSts.size(), 0);
+    std::string inputArgsString =
+        model.constructSingleStringFromVector(inputArgsVector);
 
-    // default/empty paths, to make sure nothing will be found
-    TomoPathsConfig paths;
-    model.updateTomoPathsConfig(paths);
+    std::shared_ptr<TomoRecToolConfig> d = std::shared_ptr<TomoRecToolConfig>(
+        new ToolConfigCustom(inputRunnable, inputArgsString));
 
-    // paths that don't make sense, so nothing gets executed even if you have a
-    // local installation of tomopy available
-    TomoSystemSettings settings;
-    settings.m_local.m_basePathTomoData = "/never_find_anything/";
-    settings.m_local.m_reconScriptsPath = "/dont_find_the_scripts/";
-    model.updateSystemSettings(settings);
+    model.usingTool(TestableTomographyIfaceModel::g_customCmdTool);
+    model.setCurrentToolMethod("gridrec");
 
-    TomoReconToolsUserSettings toolsSettings;
-    toolsSettings.tomoPy =
-        ToolConfigTomoPy("fail", "/out/", "/dark/", "/flat/", "/sample/");
-    model.updateReconToolsSettings(toolsSettings);
-    model.doRunReconstructionJobLocal();
+    model.setCurrentToolSettings(d);
 
-    model.refreshLocalJobsInfo();
-    localSts = model.jobsStatusLocal();
-    TSM_ASSERT_EQUALS("Unexpected number of jobs (local), after refreshing",
-                      localSts.size(), 1);
+    const bool local = true;
+
+    std::string actualRunnable;
+    std::string allOpts;
+
+    std::vector<std::string> actualArgsVector;
+    model.prepareSubmissionArguments(local, actualRunnable, actualArgsVector,
+                                     allOpts);
+
+    std::string expectedRunnable = "python";
+    // the space at the end is necessary, because of how
+    // constructSingleStringFromVector works
+    std::vector<std::string> expectedArgsVector{
+        "/scriptPath/", "--some params --some other params "};
+    doTestExpectedRunnableAndArguments(expectedRunnable, actualRunnable,
+                                       expectedArgsVector, actualArgsVector);
+  }
+
+  void test_makeRemoteRunnableWithOptions() {
+    std::string expectedRunnable =
+        "/work/imat/phase_commissioning/scripts/Imaging/"
+        "IMAT/tomo_reconstruct.py";
+    TomoPathsConfig pathConfig;
+
+    const std::string pathOut = "/work/imat";
+    static size_t reconIdx = 1;
+    const std::string localOutNameAppendix = std::string("/processed/") +
+                                             "reconstruction_" +
+                                             std::to_string(reconIdx);
+
+    std::shared_ptr<TomoRecToolConfig> d = std::shared_ptr<TomoRecToolConfig>(
+        new ToolConfigTomoPy(expectedRunnable, pathOut + localOutNameAppendix,
+                             pathConfig.pathDarks(), pathConfig.pathOpenBeam(),
+                             pathConfig.pathSamples()));
+
+    TestableTomographyIfaceModel model;
+
+    model.usingTool(TestableTomographyIfaceModel::g_TomoPyTool);
+    model.setCurrentToolMethod("gridrec");
+
+    model.setCurrentToolSettings(d);
+
+    const bool local = false;
+
+    std::string allOpts;
+    std::string actualRunnable;
+    std::vector<std::string> actualArgsVector;
+    model.prepareSubmissionArguments(local, actualRunnable, actualArgsVector,
+                                     allOpts);
+
+    std::vector<std::string> expectedArgsVector{
+        "--tool=tomopy", "--algorithm=gridrec", "--num-iter=5",
+        "--input-path=" + pathConfig.pathSamples(),
+        "--input-path-flat=" + pathConfig.pathOpenBeam(),
+        "--input-path-dark=" + pathConfig.pathDarks(),
+        "--output=\"/work/imat/phase_commissioning/processed/"
+        "reconstruction_TomoPy_gridrec_2016October20_113701_413275000",
+        "--median-filter-size=3", "--cor=0.000000", "--rotation=0",
+        "--max-angle=360.000000", "--circular-mask=0.940000",
+        "--out-img-format=png"};
+    doTestExpectedRunnableAndArguments(expectedRunnable, actualRunnable,
+                                       expectedArgsVector, actualArgsVector);
+  }
+
+  void test_makeLocalRunnableWithOptions() {
+    std::string inputRunnable = "python "
+                                "/work/imat/phase_commissioning/scripts/"
+                                "Imaging/IMAT/tomo_reconstruct.py";
+
+    TomoPathsConfig pathConfig;
+    const std::string pathOut = "~/imat/RB000XXX";
+    static size_t reconIdx = 1;
+    const std::string localOutNameAppendix = std::string("/processed/") +
+                                             "reconstruction_" +
+                                             std::to_string(reconIdx);
+
+    std::shared_ptr<TomoRecToolConfig> d = std::shared_ptr<TomoRecToolConfig>(
+        new ToolConfigTomoPy(inputRunnable, pathOut + localOutNameAppendix,
+                             pathConfig.pathDarks(), pathConfig.pathOpenBeam(),
+                             pathConfig.pathSamples()));
+
+    TestableTomographyIfaceModel model;
+
+    model.usingTool(TestableTomographyIfaceModel::g_TomoPyTool);
+    model.setCurrentToolMethod("gridrec");
+
+    model.setCurrentToolSettings(d);
+
+    const bool local = true;
+
+    // should be just the externalInterpretor path
+    std::string actualRunnable;
+    std::string allOpts;
+    std::vector<std::string> actualArgsVector;
+    model.prepareSubmissionArguments(local, actualRunnable, actualArgsVector,
+                                     allOpts);
+
+    std::string expectedRunnable = "python";
+    std::vector<std::string> expectedArgsVector{
+        "/work/imat/phase_commissioning/scripts/Imaging/IMAT/"
+        "tomo_reconstruct.py",
+        "--tool=tomopy", "--algorithm=gridrec", "--num-iter=5",
+        "--input-path=/work/imat/phase_commissioning/data",
+        "--input-path-flat=/work/imat/phase_commissioning/flat",
+        "--input-path-dark=/work/imat/phase_commissioning/dark",
+        "--output=/work/imat/phase_commissioning/processed/"
+        "reconstruction_TomoPy_gridrec_2016October20_113701_413275000",
+        "--median-filter-size=3", "--cor=0.000000", "--rotation=0",
+        "--max-angle=360.000000", "--circular-mask=0.940000",
+        "--out-img-format=png"};
+
+    doTestExpectedRunnableAndArguments(expectedRunnable, actualRunnable,
+                                       expectedArgsVector, actualArgsVector);
+  }
+
+private:
+  // inner class to access the model's protected functions
+  class TestableTomographyIfaceModel : public TomographyIfaceModel {
+    friend class TomographyIfaceModelTest;
+    TestableTomographyIfaceModel() : TomographyIfaceModel() {}
+  };
+
+  void doTestExpectedRunnableAndArguments(
+      const std::string &expectedRunnable, const std::string &actualRunnable,
+      const std::vector<std::string> &expectedArguments,
+      const std::vector<std::string> &actualArguments) {
+    TSM_ASSERT_EQUALS("Local interpreter executable not properly separated",
+                      actualRunnable, expectedRunnable);
+    TSM_ASSERT_EQUALS("Invalid argument size", expectedArguments.size(),
+                      actualArguments.size());
+
+    for (size_t i = 0; i < expectedArguments.size(); ++i) {
+      // this is the --output one that varies depending on time, so just skip
+      if (expectedArguments[i].substr(0, 8) == "--output") {
+        continue;
+      }
+      TS_ASSERT_EQUALS(expectedArguments[i], actualArguments[i]);
+    }
   }
 };
 
diff --git a/MantidQt/CustomInterfaces/test/TomographyIfacePresenterTest.h b/MantidQt/CustomInterfaces/test/TomographyIfacePresenterTest.h
index 954df7215e804a308554db800a20dae6ee6f1cab..9872b9e9366795bc841cff867aca6002c66a763d 100644
--- a/MantidQt/CustomInterfaces/test/TomographyIfacePresenterTest.h
+++ b/MantidQt/CustomInterfaces/test/TomographyIfacePresenterTest.h
@@ -5,8 +5,8 @@
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidQtCustomInterfaces/Tomography/TomographyIfacePresenter.h"
 
-#include <cxxtest/TestSuite.h>
 #include "TomographyViewMock.h"
+#include <cxxtest/TestSuite.h>
 
 using namespace MantidQt::CustomInterfaces;
 using testing::TypedEq;
@@ -26,8 +26,8 @@ public:
   }
 
   TomographyIfacePresenterTest() {
-    Mantid::API::FrameworkManager::Instance(); // make sure framework is
-                                               // initialized
+    // make sure the framework is initialized
+    Mantid::API::FrameworkManager::Instance();
   }
 
   void setUp() override {
@@ -120,7 +120,7 @@ public:
     // needs one tool at a very minimum
     EXPECT_CALL(mockView, currentReconTool()).Times(1).WillOnce(Return(g_ccpi));
     // and basic tools settings
-    EXPECT_CALL(mockView, reconToolsSettings()).Times(0);
+    EXPECT_CALL(mockView, currentPathsConfig()).Times(0);
 
     // tool config not available
     EXPECT_CALL(mockView, showToolConfig(testing::_)).Times(0);
@@ -133,31 +133,7 @@ public:
         testing::Mock::VerifyAndClearExpectations(&mockView))
   }
 
-  // does not really fail, but it cannot do any of the expected updates
-  void test_setupReconToolUnsupportedTool() {
-    testing::NiceMock<MockTomographyIfaceView> mockView;
-    MantidQt::CustomInterfaces::TomographyIfacePresenter pres(&mockView);
-
-    EXPECT_CALL(mockView, systemSettings()).Times(0);
-    EXPECT_CALL(mockView, currentReconTool())
-        .Times(1)
-        .WillRepeatedly(Return(g_ccpi));
-    EXPECT_CALL(mockView, reconToolsSettings()).Times(0);
-
-    // wrong tool => doesn't have a config dialog
-    EXPECT_CALL(mockView, showToolConfig(testing::_)).Times(0);
-
-    // No errors/warnings
-    EXPECT_CALL(mockView, userError(testing::_, testing::_)).Times(0);
-    EXPECT_CALL(mockView, userWarning(testing::_, testing::_)).Times(0);
-
-    pres.notify(ITomographyIfacePresenter::SetupReconTool);
-    TSM_ASSERT(
-        "Mock not used as expected. Some EXPECT_CALL conditions were not "
-        "satisfied.",
-        testing::Mock::VerifyAndClearExpectations(&mockView))
-  }
-
+  //   setup reconstruction tool now in preseter, have a unit test
   void test_setupReconToolGood() {
     testing::NiceMock<MockTomographyIfaceView> mockView;
     MantidQt::CustomInterfaces::TomographyIfacePresenter pres(&mockView);
@@ -168,10 +144,10 @@ public:
         .Times(2)
         .WillRepeatedly(Return("TomoPy"));
     // and basic tools settings
-    TomoReconToolsUserSettings toolsSettings;
-    EXPECT_CALL(mockView, reconToolsSettings())
+    TomoPathsConfig toolPaths;
+    EXPECT_CALL(mockView, currentPathsConfig())
         .Times(1)
-        .WillOnce(Return(toolsSettings));
+        .WillOnce(Return(toolPaths));
 
     EXPECT_CALL(mockView, showToolConfig(testing::_)).Times(1);
 
@@ -179,6 +155,7 @@ public:
     EXPECT_CALL(mockView, userError(testing::_, testing::_)).Times(0);
     EXPECT_CALL(mockView, userWarning(testing::_, testing::_)).Times(0);
 
+    pres.notify(ITomographyIfacePresenter::ToolChanged);
     pres.notify(ITomographyIfacePresenter::SetupReconTool);
     TSM_ASSERT(
         "Mock not used as expected. Some EXPECT_CALL conditions were not "
@@ -201,34 +178,6 @@ public:
         testing::Mock::VerifyAndClearExpectations(&mockView))
   }
 
-  void test_showImg_good() {
-    testing::NiceMock<MockTomographyIfaceView> mockView;
-    MantidQt::CustomInterfaces::TomographyIfacePresenter pres(&mockView);
-
-    const std::string path = "FITS_small_02.fits";
-    // needs image file name - re-uses a FITS from the unit tests
-    ON_CALL(mockView, showImagePath()).WillByDefault(Return(path));
-    EXPECT_CALL(mockView, showImagePath()).Times(1);
-
-    EXPECT_CALL(
-        mockView,
-        showImage(testing::Matcher<const Mantid::API::MatrixWorkspace_sptr &>(
-            testing::_))).Times(1);
-    EXPECT_CALL(mockView,
-                showImage(testing::Matcher<const std::string &>(testing::_)))
-        .Times(0);
-
-    // No errors, no warnings
-    EXPECT_CALL(mockView, userError(testing::_, testing::_)).Times(0);
-    EXPECT_CALL(mockView, userWarning(testing::_, testing::_)).Times(0);
-
-    pres.notify(ITomographyIfacePresenter::ViewImg);
-    TSM_ASSERT(
-        "Mock not used as expected. Some EXPECT_CALL conditions were not "
-        "satisfied.",
-        testing::Mock::VerifyAndClearExpectations(&mockView))
-  }
-
   void test_valuesAtInit() {
     testing::NiceMock<MockTomographyIfaceView> mockView;
     MantidQt::CustomInterfaces::TomographyIfacePresenter pres(&mockView);
@@ -257,7 +206,6 @@ public:
 
     // would need compute resource and username if logged in
     EXPECT_CALL(mockView, getUsername()).Times(0);
-    EXPECT_CALL(mockView, currentComputeResource()).Times(0);
     EXPECT_CALL(mockView, updateLoginControls(testing::_)).Times(0);
 
     // No errors, no warnings
@@ -275,24 +223,17 @@ public:
     testing::NiceMock<MockTomographyIfaceView> mockView;
     MantidQt::CustomInterfaces::TomographyIfacePresenter pres(&mockView);
 
-    std::vector<std::string> tools;
-    tools.emplace_back("Astra Toolbox");
-    tools.emplace_back("TomoPy");
-    tools.push_back(g_ccpi);
-    tools.emplace_back("Savu");
-
-    TSM_ASSERT_EQUALS("There should be 4 tools in this test", tools.size(), 4);
-    // up to this index the tools are supported
-    const size_t indexToolsWork = 1;
-    for (size_t i = 0; i < 3; i++) {
-      EXPECT_CALL(mockView, currentReconTool())
+    std::vector<std::string> tools{"Astra", "TomoPy"};
+
+    TomoPathsConfig toolPaths;
+    for (const auto &tool : tools) {
+      // expect the current paths config will be read only once
+      EXPECT_CALL(mockView, currentPathsConfig())
           .Times(1)
-          .WillOnce(Return(tools[i]));
-      if (i <= indexToolsWork) {
-        EXPECT_CALL(mockView, currentComputeResource()).Times(1);
-      } else {
-        EXPECT_CALL(mockView, currentComputeResource()).Times(0);
-      }
+          .WillOnce(Return(toolPaths));
+
+      // expect the current reconstruction tool will be called only once
+      EXPECT_CALL(mockView, currentReconTool()).Times(1).WillOnce(Return(tool));
 
       EXPECT_CALL(mockView, enableRunReconstruct(testing::_)).Times(1);
       EXPECT_CALL(mockView, enableConfigTool(testing::_)).Times(1);
@@ -313,9 +254,6 @@ public:
     testing::NiceMock<MockTomographyIfaceView> mockView;
     MantidQt::CustomInterfaces::TomographyIfacePresenter pres(&mockView);
 
-    EXPECT_CALL(mockView, currentComputeResource())
-        .Times(1)
-        .WillOnce(Return(g_scarfName));
     EXPECT_CALL(mockView, currentReconTool()).Times(0);
 
     // No errors, no warnings
@@ -481,7 +419,7 @@ public:
     EXPECT_CALL(mockView, userError(testing::_, testing::_)).Times(0);
     EXPECT_CALL(mockView, userWarning(testing::_, testing::_)).Times(0);
 
-    EXPECT_CALL(mockView, userWarning(testing::_, testing::_)).Times(0);
+    // EXPECT_CALL(mockView, userWarning(testing::_, testing::_)).Times(0);
     pres.notify(ITomographyIfacePresenter::SetupResourcesAndTools);
     TSM_ASSERT(
         "Mock not used as expected. Some EXPECT_CALL conditions were not "
@@ -514,7 +452,6 @@ public:
     testing::NiceMock<MockTomographyIfaceView> mockView;
     MantidQt::CustomInterfaces::TomographyIfacePresenter pres(&mockView);
 
-    EXPECT_CALL(mockView, currentComputeResource()).Times(0);
     EXPECT_CALL(mockView, updateJobsInfoDisplay(testing::_, testing::_))
         .Times(1);
 
@@ -533,7 +470,6 @@ public:
     testing::NiceMock<MockTomographyIfaceView> mockView;
     MantidQt::CustomInterfaces::TomographyIfacePresenter pres(&mockView);
 
-    EXPECT_CALL(mockView, currentComputeResource()).Times(0);
     EXPECT_CALL(mockView, updateJobsInfoDisplay(testing::_, testing::_))
         .Times(1);
 
@@ -729,10 +665,7 @@ public:
         testing::Mock::VerifyAndClearExpectations(&mockView))
   }
 
-  // An attempt at testing a sequence of steps from the user.
-  // TODO: more interesting sessions should follow, but how to do it
-  // without loading too many and too big files?
-  void test_sillySession() {
+  void test_sillySessionRemote() {
     // the user does a few silly things...
     testing::NiceMock<MockTomographyIfaceView> mockView;
     MantidQt::CustomInterfaces::TomographyIfacePresenter pres(&mockView);
@@ -745,9 +678,7 @@ public:
 
     // user changes some paths
     pres.notify(ITomographyIfacePresenter::TomoPathsChanged);
-
     EXPECT_CALL(mockView, currentComputeResource())
-        .Times(2)
         .WillRepeatedly(Return(g_scarfName));
 
     // user changes the compute resource
@@ -757,11 +688,13 @@ public:
         .Times(2)
         .WillRepeatedly(Return("TomoPy"));
 
-    TomoReconToolsUserSettings toolsSettings;
-    EXPECT_CALL(mockView, reconToolsSettings())
+    // and basic tools settings
+    EXPECT_CALL(mockView, currentPathsConfig())
         .Times(1)
-        .WillOnce(Return(toolsSettings));
+        .WillOnce(Return(TomoPathsConfig()));
 
+    // the tool changed event sets up the tool's paths
+    pres.notify(ITomographyIfacePresenter::ToolChanged);
     // user opens dialog and sets up a reconstruction tool
     pres.notify(ITomographyIfacePresenter::SetupReconTool);
 
@@ -775,9 +708,68 @@ public:
         .Times(1)
         .WillOnce(Return(roiEtc));
 
-    EXPECT_CALL(mockView, tomopyMethod()).Times(1).WillOnce(Return(""));
+    TomoReconFiltersSettings filters;
+    EXPECT_CALL(mockView, prePostProcSettings())
+        .Times(1)
+        .WillOnce(Return(filters));
+
+    // No errors, no warnings
+    EXPECT_CALL(mockView, userError(testing::_, testing::_)).Times(0);
+
+    // we get one warning from trying to submit a job to remote
+    EXPECT_CALL(mockView, userWarning(testing::_, testing::_)).Times(1);
+
+    // finally, user tries to run a reconstruction job
+    pres.notify(ITomographyIfacePresenter::RunReconstruct);
+    TSM_ASSERT(
+        "Mock not used as expected. Some EXPECT_CALL conditions were not "
+        "satisfied.",
+        testing::Mock::VerifyAndClearExpectations(&mockView))
+  }
+
+  void test_sillySessionLocal() {
+    // the user does a few silly things...
+    testing::NiceMock<MockTomographyIfaceView> mockView;
+    MantidQt::CustomInterfaces::TomographyIfacePresenter *pres =
+        new MantidQt::CustomInterfaces::TomographyIfacePresenter(&mockView);
+
+    EXPECT_CALL(mockView, systemSettings()).Times(0);
+
+    EXPECT_CALL(mockView, currentPathsConfig())
+        .Times(1)
+        .WillOnce(Return(TomoPathsConfig()));
+
+    // user changes some paths
+    pres->notify(ITomographyIfacePresenter::TomoPathsChanged);
+    EXPECT_CALL(mockView, currentComputeResource())
+        .WillRepeatedly(Return("Local"));
+
+    // user changes the compute resource
+    pres->notify(ITomographyIfacePresenter::CompResourceChanged);
+
+    EXPECT_CALL(mockView, currentReconTool())
+        .Times(2)
+        .WillRepeatedly(Return("TomoPy"));
+
+    // and basic tools settings
+    EXPECT_CALL(mockView, currentPathsConfig())
+        .Times(1)
+        .WillOnce(Return(TomoPathsConfig()));
+
+    // the tool changed event sets up the tool's paths
+    pres->notify(ITomographyIfacePresenter::ToolChanged);
+    // user opens dialog and sets up a reconstruction tool
+    pres->notify(ITomographyIfacePresenter::SetupReconTool);
+
+    TomoPathsConfig pathsCfg;
+    EXPECT_CALL(mockView, currentPathsConfig())
+        .Times(1)
+        .WillOnce(Return(pathsCfg));
 
-    EXPECT_CALL(mockView, astraMethod()).Times(1).WillOnce(Return(""));
+    ImageStackPreParams roiEtc;
+    EXPECT_CALL(mockView, currentROIEtcParams())
+        .Times(1)
+        .WillOnce(Return(roiEtc));
 
     TomoReconFiltersSettings filters;
     EXPECT_CALL(mockView, prePostProcSettings())
@@ -789,7 +781,8 @@ public:
     EXPECT_CALL(mockView, userWarning(testing::_, testing::_)).Times(0);
 
     // finally, user tries to run a reconstruction job
-    pres.notify(ITomographyIfacePresenter::RunReconstruct);
+    pres->notify(ITomographyIfacePresenter::RunReconstruct);
+
     TSM_ASSERT(
         "Mock not used as expected. Some EXPECT_CALL conditions were not "
         "satisfied.",
@@ -812,6 +805,34 @@ public:
         testing::Mock::VerifyAndClearExpectations(&mockView))
   }
 
+  void test_showImg_good() {
+    testing::NiceMock<MockTomographyIfaceView> mockView;
+    MantidQt::CustomInterfaces::TomographyIfacePresenter pres(&mockView);
+
+    const std::string path = "FITS_small_02.fits";
+    // needs image file name - re-uses a FITS from the unit tests
+    ON_CALL(mockView, showImagePath()).WillByDefault(Return(path));
+    EXPECT_CALL(mockView, showImagePath()).Times(1);
+
+    EXPECT_CALL(
+        mockView,
+        showImage(testing::Matcher<const Mantid::API::MatrixWorkspace_sptr &>(
+            testing::_))).Times(1);
+    EXPECT_CALL(mockView,
+                showImage(testing::Matcher<const std::string &>(testing::_)))
+        .Times(0);
+
+    // No errors, no warnings
+    EXPECT_CALL(mockView, userError(testing::_, testing::_)).Times(0);
+    EXPECT_CALL(mockView, userWarning(testing::_, testing::_)).Times(0);
+
+    pres.notify(ITomographyIfacePresenter::ViewImg);
+    TSM_ASSERT(
+        "Mock not used as expected. Some EXPECT_CALL conditions were not "
+        "satisfied.",
+        testing::Mock::VerifyAndClearExpectations(&mockView))
+  }
+
 private:
   // boost::shared_ptr
   boost::scoped_ptr<testing::NiceMock<MockTomographyIfaceView>> m_view;
diff --git a/MantidQt/CustomInterfaces/test/TomographyViewMock.h b/MantidQt/CustomInterfaces/test/TomographyViewMock.h
index 5c2b6de7ed042a732945b8b25955b42051dbb6d6..006a6263acd1222aed4659921114753970dbc6c7 100644
--- a/MantidQt/CustomInterfaces/test/TomographyViewMock.h
+++ b/MantidQt/CustomInterfaces/test/TomographyViewMock.h
@@ -57,12 +57,6 @@ public:
   // std::string currentReconTool() const {}
   MOCK_CONST_METHOD0(currentReconTool, std::string());
 
-  // std::string astraMethod() const {}
-  MOCK_CONST_METHOD0(astraMethod, std::string());
-
-  // std::string tomopyMethod() const {}
-  MOCK_CONST_METHOD0(tomopyMethod, std::string());
-
   // void updateLoginControls(bool loggedIn) {}
   MOCK_METHOD1(updateLoginControls, void(bool loggedIn));
 
@@ -97,7 +91,9 @@ public:
                      MantidQt::CustomInterfaces::ImageStackPreParams());
 
   // void showToolConfig(const std::string &name) {}
-  MOCK_METHOD1(showToolConfig, void(const std::string &name));
+  MOCK_METHOD1(
+      showToolConfig,
+      void(MantidQt::CustomInterfaces::TomoToolConfigDialogBase &dialog));
 
   // virtual void updateJobsInfoDisplay( const
   //    std::vector<Mantid::API::IRemoteJobManager::RemoteJobInfo>
@@ -115,11 +111,6 @@ public:
   MOCK_CONST_METHOD0(systemSettings,
                      MantidQt::CustomInterfaces::TomoSystemSettings());
 
-  // MantidQt::CustomInterfaces::TomoReconToolsUserSettings
-  // reconToolsSettings() const
-  MOCK_CONST_METHOD0(reconToolsSettings,
-                     MantidQt::CustomInterfaces::TomoReconToolsUserSettings());
-
   // MantidQt::CustomInterfaces::TomoReconToolsUserSettings
   // prePostProcSettings() const
   MOCK_CONST_METHOD0(prePostProcSettings,
@@ -134,6 +125,11 @@ public:
 
   // virtual void runAggregateBands(Mantid::API::IAlgorithm_sptr alg)
   MOCK_METHOD1(runAggregateBands, void(Mantid::API::IAlgorithm_sptr alg));
+
+  //   virtual bool userConfirmation(const std::string &title, const std::string
+  //   &body)
+  MOCK_METHOD2(userConfirmation,
+               bool(const std::string &title, const std::string &body));
 };
 
 GCC_DIAG_ON_SUGGEST_OVERRIDE
diff --git a/MantidQt/DesignerPlugins/inc/MantidQtDesignerPlugins/PluginCollectionInterface.h b/MantidQt/DesignerPlugins/inc/MantidQtDesignerPlugins/PluginCollectionInterface.h
index 35099a9826e15ccf8296cc26533dd41074860f5c..860f4dd1f0c5c021e96bc68ccfff4a539eb67658 100644
--- a/MantidQt/DesignerPlugins/inc/MantidQtDesignerPlugins/PluginCollectionInterface.h
+++ b/MantidQt/DesignerPlugins/inc/MantidQtDesignerPlugins/PluginCollectionInterface.h
@@ -7,7 +7,7 @@
 #include "MantidQtMantidWidgets/DataSelector.h"
 #include "MantidQtDesignerPlugins/DesignerPlugin.h"
 #include "MantidQtMantidWidgets/ScriptEditor.h"
-#include "MantidQtMantidWidgets/MWRunFiles.h"
+#include "MantidQtAPI/MWRunFiles.h"
 #include "MantidQtMantidWidgets/FitPropertyBrowser.h"
 #include "MantidQtMantidWidgets/MuonFitPropertyBrowser.h"
 #include "MantidQtMantidWidgets/InstrumentSelector.h"
@@ -97,7 +97,7 @@ DECLARE_WIDGET_PLUGIN(AlgorithmSelectorWidgetPlugin,
 DECLARE_WIDGET_PLUGIN(ScriptEditorPlugin, ScriptEditor,
                       "Widget for editing python script");
 
-DECLARE_WIDGET_PLUGIN(FileFinderPlugin, MantidQt::MantidWidgets::MWRunFiles,
+DECLARE_WIDGET_PLUGIN(FileFinderPlugin, MantidQt::API::MWRunFiles,
                       "Searches for the given files within the paths defined "
                       "by\nMantid's datasearch.directories property");
 
diff --git a/MantidQt/MantidWidgets/CMakeLists.txt b/MantidQt/MantidWidgets/CMakeLists.txt
index e1a947158e21eb28c66a71c498940b443a6c2189..8989abba481952157e03ef8faeb7b28d398de799 100644
--- a/MantidQt/MantidWidgets/CMakeLists.txt
+++ b/MantidQt/MantidWidgets/CMakeLists.txt
@@ -84,13 +84,12 @@ set ( SRC_FILES
 	src/InstrumentView/XIntegrationControl.cpp
 	src/LineEditWithClear.cpp
 	src/LogValueSelector.cpp
-	src/MantidTreeWidget.cpp
-	src/MantidTreeWidgetItem.cpp
 	src/MWDiag.cpp
-	src/MWRunFiles.cpp
 	src/MWView.cpp
 	src/MantidHelpWindow.cpp
 	src/MantidSurfacePlotDialog.cpp
+	src/MantidTreeWidget.cpp
+	src/MantidTreeWidgetItem.cpp
 	src/MantidWSIndexDialog.cpp
 	src/MessageDisplay.cpp
 	src/MultifitSetupDialog.cpp
@@ -101,6 +100,8 @@ set ( SRC_FILES
 	src/PeriodicTableWidget.cpp
 	src/PreviewPlot.cpp
 	src/ProcessingAlgoWidget.cpp
+        src/ProjectSavePresenter.cpp
+        src/ProjectSaveModel.cpp
 	src/PropertyHandler.cpp
 	src/RangeSelector.cpp
 	src/RenameParDialog.cpp
@@ -114,18 +115,19 @@ set ( SRC_FILES
 	src/SlitCalculator.cpp
 	src/StringDialogEditor.cpp
 	src/StringEditorFactory.cpp
+	src/TrackedAction.cpp
 	src/UserFunctionDialog.cpp
 	src/WorkspaceEditorFactory.cpp
+	src/WorkspacePresenter/ADSAdapter.cpp
+	src/WorkspacePresenter/QWorkspaceDockView.cpp
+	src/WorkspacePresenter/WorkspacePresenter.cpp
 	src/WorkspaceSelector.cpp
 	src/pqHelpWindow.cxx
 	src/pythonCalc.cpp
-    src/WorkspacePresenter/WorkspacePresenter.cpp
-    src/WorkspacePresenter/ADSAdapter.cpp
-	src/WorkspacePresenter/QWorkspaceDockView.cpp
 )
 
 # Header files with Q_OBJECT that qmake will "moc"
-set ( MOC_FILES 
+set ( MOC_FILES
     inc/MantidQtMantidWidgets/AlgorithmSelectorWidget.h
     inc/MantidQtMantidWidgets/CheckboxHeader.h
     inc/MantidQtMantidWidgets/ColorBarWidget.h
@@ -152,9 +154,10 @@ set ( MOC_FILES
     inc/MantidQtMantidWidgets/InstrumentSelector.h
     inc/MantidQtMantidWidgets/IndirectInstrumentConfig.h
     inc/MantidQtMantidWidgets/InputController.h
-	inc/MantidQtMantidWidgets/MantidSurfacePlotDialog.h
-	inc/MantidQtMantidWidgets/MantidWSIndexDialog.h
-	inc/MantidQtMantidWidgets/MantidTreeWidget.h
+    inc/MantidQtMantidWidgets/IProjectSaveView.h
+    inc/MantidQtMantidWidgets/MantidSurfacePlotDialog.h
+    inc/MantidQtMantidWidgets/MantidWSIndexDialog.h
+    inc/MantidQtMantidWidgets/MantidTreeWidget.h
     inc/MantidQtMantidWidgets/MantidHelpWindow.h
     inc/MantidQtMantidWidgets/MessageDisplay.h
     inc/MantidQtMantidWidgets/MultifitSetupDialog.h
@@ -162,7 +165,6 @@ set ( MOC_FILES
     inc/MantidQtMantidWidgets/MuonFitPropertyBrowser.h
     inc/MantidQtMantidWidgets/MuonFunctionBrowser.h
     inc/MantidQtMantidWidgets/MWDiag.h
-    inc/MantidQtMantidWidgets/MWRunFiles.h
     inc/MantidQtMantidWidgets/MWView.h
     inc/MantidQtMantidWidgets/PeakPicker.h
     inc/MantidQtMantidWidgets/PeriodicTableWidget.h
@@ -183,6 +185,7 @@ set ( MOC_FILES
     inc/MantidQtMantidWidgets/SlitCalculator.h
     inc/MantidQtMantidWidgets/StringDialogEditor.h
     inc/MantidQtMantidWidgets/StringEditorFactory.h
+    inc/MantidQtMantidWidgets/TrackedAction.h
     inc/MantidQtMantidWidgets/UserFunctionDialog.h
     inc/MantidQtMantidWidgets/WorkspaceEditorFactory.h
     inc/MantidQtMantidWidgets/WorkspaceSelector.h
@@ -208,125 +211,128 @@ set ( MOC_FILES
     inc/MantidQtMantidWidgets/InstrumentView/UnwrappedSurface.h
     inc/MantidQtMantidWidgets/InstrumentView/UCorrectionDialog.h
     inc/MantidQtMantidWidgets/InstrumentView/XIntegrationControl.h
-	inc/MantidQtMantidWidgets/LogValueSelector.h
-	inc/MantidQtMantidWidgets/WorkspacePresenter/QWorkspaceDockView.h
+    inc/MantidQtMantidWidgets/LogValueSelector.h
+    inc/MantidQtMantidWidgets/WorkspacePresenter/QWorkspaceDockView.h
 )
 
 # Add the include files are NOT already in MOC_FILES
 set ( INC_FILES
-	${MOC_FILES}
-	inc/MantidQtMantidWidgets/AlgorithmHintStrategy.h
-	inc/MantidQtMantidWidgets/CatalogHelper.h
-	inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorAppendGroupCommand.h
-	inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorAppendRowCommand.h
-	inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorClearSelectedCommand.h
-	inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorCommand.h
-	inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorCommandBase.h
-	inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorCopySelectedCommand.h
-	inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorCutSelectedCommand.h
-	inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorDeleteGroupCommand.h
-	inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorDeleteRowCommand.h
-	inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorExpandCommand.h
-	inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorExportTableCommand.h
-	inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorGenerateNotebook.h
-	inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorGroupRowsCommand.h
-	inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorImportTableCommand.h
-	inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorNewTableCommand.h
-	inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorOneLevelTreeManager.h
-	inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorOpenTableCommand.h
-	inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorOptionsCommand.h
-	inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorPasteSelectedCommand.h
-	inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorPlotGroupCommand.h
-	inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorPlotRowCommand.h
-	inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorPostprocessingAlgorithm.h
-	inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorPreprocessingAlgorithm.h
-	inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorPresenter.h
-	inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorProcessCommand.h
-	inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorProcessingAlgorithm.h
-	inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorProcessingAlgorithmBase.h
-	inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorSaveTableAsCommand.h
-	inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorSaveTableCommand.h
-	inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorTreeManager.h
-	inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorTwoLevelTreeManager.h
-	inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorVectorString.h
-	inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorView.h
-	inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorWhiteList.h
-	inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorWorkspaceCommand.h
-    inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorMainPresenter.h
-	inc/MantidQtMantidWidgets/DataProcessorUI/GenericDataProcessorPresenter.h
-	inc/MantidQtMantidWidgets/DataProcessorUI/GenericDataProcessorPresenterFactory.h
-	inc/MantidQtMantidWidgets/DataProcessorUI/ParseKeyValueString.h
-	inc/MantidQtMantidWidgets/ErrorCurve.h
-	inc/MantidQtMantidWidgets/HintStrategy.h
-	inc/MantidQtMantidWidgets/IFunctionBrowser.h
-	inc/MantidQtMantidWidgets/IMuonFitDataSelector.h
-	inc/MantidQtMantidWidgets/IMuonFitFunctionControl.h
-	inc/MantidQtMantidWidgets/IWorkspaceFitControl.h
-	inc/MantidQtMantidWidgets/InstrumentView/BinDialog.h
-	inc/MantidQtMantidWidgets/InstrumentView/CollapsiblePanel.h
-	inc/MantidQtMantidWidgets/InstrumentView/ColorMapWidget.h
-	inc/MantidQtMantidWidgets/InstrumentView/CompAssemblyActor.h
-	inc/MantidQtMantidWidgets/InstrumentView/ComponentActor.h
-	inc/MantidQtMantidWidgets/InstrumentView/DetXMLFile.h
-	inc/MantidQtMantidWidgets/InstrumentView/GLActor.h
-	inc/MantidQtMantidWidgets/InstrumentView/GLActorCollection.h
-	inc/MantidQtMantidWidgets/InstrumentView/GLActorVisitor.h
-	inc/MantidQtMantidWidgets/InstrumentView/GLColor.h
-	inc/MantidQtMantidWidgets/InstrumentView/GLObject.h
-	inc/MantidQtMantidWidgets/InstrumentView/ICompAssemblyActor.h
-	inc/MantidQtMantidWidgets/InstrumentView/InstrumentActor.h
-	inc/MantidQtMantidWidgets/InstrumentView/InstrumentTreeModel.h
-	inc/MantidQtMantidWidgets/InstrumentView/InstrumentTreeWidget.h
-	inc/MantidQtMantidWidgets/InstrumentView/InstrumentWidget.h
-	inc/MantidQtMantidWidgets/InstrumentView/InstrumentWidgetMaskTab.h
-	inc/MantidQtMantidWidgets/InstrumentView/InstrumentWidgetPickTab.h
-	inc/MantidQtMantidWidgets/InstrumentView/InstrumentWidgetRenderTab.h
-	inc/MantidQtMantidWidgets/InstrumentView/InstrumentWidgetTab.h
-	inc/MantidQtMantidWidgets/InstrumentView/InstrumentWidgetTreeTab.h
-	inc/MantidQtMantidWidgets/InstrumentView/InstrumentWidgetTypes.h
-	inc/MantidQtMantidWidgets/InstrumentView/MantidGLWidget.h
-	inc/MantidQtMantidWidgets/InstrumentView/MaskBinsData.h
-	inc/MantidQtMantidWidgets/InstrumentView/ObjCompAssemblyActor.h
-	inc/MantidQtMantidWidgets/InstrumentView/ObjComponentActor.h
-	inc/MantidQtMantidWidgets/InstrumentView/OneCurvePlot.h
-	inc/MantidQtMantidWidgets/InstrumentView/OpenGLError.h
-	inc/MantidQtMantidWidgets/InstrumentView/PanelsSurface.h
-	inc/MantidQtMantidWidgets/InstrumentView/PeakMarker2D.h
-	inc/MantidQtMantidWidgets/InstrumentView/PeakOverlay.h
-	inc/MantidQtMantidWidgets/InstrumentView/Projection3D.h
-	inc/MantidQtMantidWidgets/InstrumentView/ProjectionSurface.h
-	inc/MantidQtMantidWidgets/InstrumentView/RectF.h
-	inc/MantidQtMantidWidgets/InstrumentView/RectangularDetectorActor.h
-	inc/MantidQtMantidWidgets/InstrumentView/RotationSurface.h
-	inc/MantidQtMantidWidgets/InstrumentView/SampleActor.h
-	inc/MantidQtMantidWidgets/InstrumentView/Shape2D.h
-	inc/MantidQtMantidWidgets/InstrumentView/Shape2DCollection.h
-	inc/MantidQtMantidWidgets/InstrumentView/SimpleWidget.h
-	inc/MantidQtMantidWidgets/InstrumentView/StructuredDetectorActor.h
-	inc/MantidQtMantidWidgets/InstrumentView/UCorrectionDialog.h
-	inc/MantidQtMantidWidgets/InstrumentView/UnwrappedCylinder.h
-	inc/MantidQtMantidWidgets/InstrumentView/UnwrappedSphere.h
-	inc/MantidQtMantidWidgets/InstrumentView/UnwrappedSurface.h
-	inc/MantidQtMantidWidgets/InstrumentView/Viewport.h
-	inc/MantidQtMantidWidgets/InstrumentView/XIntegrationControl.h
-	inc/MantidQtMantidWidgets/LogValueSelector.h
-	inc/MantidQtMantidWidgets/MantidDisplayBase.h
-	inc/MantidQtMantidWidgets/MantidTreeWidgetItem.h
-	inc/MantidQtMantidWidgets/MuonFitDataSelector.h
-	inc/MantidQtMantidWidgets/MuonFunctionBrowser.h
-	inc/MantidQtMantidWidgets/ProgressPresenter.h
-    inc/MantidQtMantidWidgets/ProgressableView.h
-    inc/MantidQtMantidWidgets/ProgressPresenter.h
-    inc/MantidQtMantidWidgets/WorkspacePresenter/ViewNotifiable.h
-    inc/MantidQtMantidWidgets/WorkspacePresenter/WorkspaceProviderNotifiable.h
-    inc/MantidQtMantidWidgets/WorkspacePresenter/WorkspacePresenter.h
-    inc/MantidQtMantidWidgets/WorkspacePresenter/WorkspaceProvider.h
-    inc/MantidQtMantidWidgets/WorkspacePresenter/ADSAdapter.h
-    inc/MantidQtMantidWidgets/WorkspacePresenter/IWorkspaceDockView.h
+        ${MOC_FILES}
+        inc/MantidQtMantidWidgets/AlgorithmHintStrategy.h
+        inc/MantidQtMantidWidgets/CatalogHelper.h
+        inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorAppendGroupCommand.h
+        inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorAppendRowCommand.h
+        inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorClearSelectedCommand.h
+        inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorCommand.h
+        inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorCommandBase.h
+        inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorCopySelectedCommand.h
+        inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorCutSelectedCommand.h
+        inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorDeleteGroupCommand.h
+        inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorDeleteRowCommand.h
+        inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorExpandCommand.h
+        inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorExportTableCommand.h
+        inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorGenerateNotebook.h
+        inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorGroupRowsCommand.h
+        inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorImportTableCommand.h
+        inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorMainPresenter.h
+        inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorNewTableCommand.h
+        inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorOneLevelTreeManager.h
+        inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorOpenTableCommand.h
+        inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorOptionsCommand.h
+        inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorPasteSelectedCommand.h
+        inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorPlotGroupCommand.h
+        inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorPlotRowCommand.h
+        inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorPostprocessingAlgorithm.h
+        inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorPreprocessingAlgorithm.h
+        inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorPresenter.h
+        inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorProcessCommand.h
+        inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorProcessingAlgorithm.h
+        inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorProcessingAlgorithmBase.h
+        inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorSaveTableAsCommand.h
+        inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorSaveTableCommand.h
+        inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorTreeManager.h
+        inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorTwoLevelTreeManager.h
+        inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorVectorString.h
+        inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorView.h
+        inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorWhiteList.h
+        inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorWorkspaceCommand.h
+        inc/MantidQtMantidWidgets/DataProcessorUI/GenericDataProcessorPresenter.h
+        inc/MantidQtMantidWidgets/DataProcessorUI/GenericDataProcessorPresenterFactory.h
+        inc/MantidQtMantidWidgets/DataProcessorUI/ParseKeyValueString.h
+        inc/MantidQtMantidWidgets/ErrorCurve.h
+        inc/MantidQtMantidWidgets/HintStrategy.h
+        inc/MantidQtMantidWidgets/IFunctionBrowser.h
+        inc/MantidQtMantidWidgets/IMuonFitDataSelector.h
+        inc/MantidQtMantidWidgets/IMuonFitFunctionControl.h
+        inc/MantidQtMantidWidgets/IProjectSaveView.h
+        inc/MantidQtMantidWidgets/IWorkspaceFitControl.h
+        inc/MantidQtMantidWidgets/InstrumentView/BinDialog.h
+        inc/MantidQtMantidWidgets/InstrumentView/CollapsiblePanel.h
+        inc/MantidQtMantidWidgets/InstrumentView/ColorMapWidget.h
+        inc/MantidQtMantidWidgets/InstrumentView/CompAssemblyActor.h
+        inc/MantidQtMantidWidgets/InstrumentView/ComponentActor.h
+        inc/MantidQtMantidWidgets/InstrumentView/DetXMLFile.h
+        inc/MantidQtMantidWidgets/InstrumentView/GLActor.h
+        inc/MantidQtMantidWidgets/InstrumentView/GLActorCollection.h
+        inc/MantidQtMantidWidgets/InstrumentView/GLActorVisitor.h
+        inc/MantidQtMantidWidgets/InstrumentView/GLColor.h
+        inc/MantidQtMantidWidgets/InstrumentView/GLObject.h
+        inc/MantidQtMantidWidgets/InstrumentView/ICompAssemblyActor.h
+        inc/MantidQtMantidWidgets/InstrumentView/InstrumentActor.h
+        inc/MantidQtMantidWidgets/InstrumentView/InstrumentTreeModel.h
+        inc/MantidQtMantidWidgets/InstrumentView/InstrumentTreeWidget.h
+        inc/MantidQtMantidWidgets/InstrumentView/InstrumentWidget.h
+        inc/MantidQtMantidWidgets/InstrumentView/InstrumentWidgetMaskTab.h
+        inc/MantidQtMantidWidgets/InstrumentView/InstrumentWidgetPickTab.h
+        inc/MantidQtMantidWidgets/InstrumentView/InstrumentWidgetRenderTab.h
+        inc/MantidQtMantidWidgets/InstrumentView/InstrumentWidgetTab.h
+        inc/MantidQtMantidWidgets/InstrumentView/InstrumentWidgetTreeTab.h
+        inc/MantidQtMantidWidgets/InstrumentView/InstrumentWidgetTypes.h
+        inc/MantidQtMantidWidgets/InstrumentView/MantidGLWidget.h
+        inc/MantidQtMantidWidgets/InstrumentView/MaskBinsData.h
+        inc/MantidQtMantidWidgets/InstrumentView/ObjCompAssemblyActor.h
+        inc/MantidQtMantidWidgets/InstrumentView/ObjComponentActor.h
+        inc/MantidQtMantidWidgets/InstrumentView/OneCurvePlot.h
+        inc/MantidQtMantidWidgets/InstrumentView/OpenGLError.h
+        inc/MantidQtMantidWidgets/InstrumentView/PanelsSurface.h
+        inc/MantidQtMantidWidgets/InstrumentView/PeakMarker2D.h
+        inc/MantidQtMantidWidgets/InstrumentView/PeakOverlay.h
+        inc/MantidQtMantidWidgets/InstrumentView/Projection3D.h
+        inc/MantidQtMantidWidgets/InstrumentView/ProjectionSurface.h
+        inc/MantidQtMantidWidgets/InstrumentView/RectF.h
+        inc/MantidQtMantidWidgets/InstrumentView/RectangularDetectorActor.h
+        inc/MantidQtMantidWidgets/InstrumentView/RotationSurface.h
+        inc/MantidQtMantidWidgets/InstrumentView/SampleActor.h
+        inc/MantidQtMantidWidgets/InstrumentView/Shape2D.h
+        inc/MantidQtMantidWidgets/InstrumentView/Shape2DCollection.h
+        inc/MantidQtMantidWidgets/InstrumentView/SimpleWidget.h
+        inc/MantidQtMantidWidgets/InstrumentView/StructuredDetectorActor.h
+        inc/MantidQtMantidWidgets/InstrumentView/UCorrectionDialog.h
+        inc/MantidQtMantidWidgets/InstrumentView/UnwrappedCylinder.h
+        inc/MantidQtMantidWidgets/InstrumentView/UnwrappedSphere.h
+        inc/MantidQtMantidWidgets/InstrumentView/UnwrappedSurface.h
+        inc/MantidQtMantidWidgets/InstrumentView/Viewport.h
+        inc/MantidQtMantidWidgets/InstrumentView/XIntegrationControl.h
+        inc/MantidQtMantidWidgets/LogValueSelector.h
+        inc/MantidQtMantidWidgets/MantidDisplayBase.h
+        inc/MantidQtMantidWidgets/MantidTreeWidgetItem.h
+        inc/MantidQtMantidWidgets/MuonFitDataSelector.h
+        inc/MantidQtMantidWidgets/MuonFunctionBrowser.h
+        inc/MantidQtMantidWidgets/ProgressableView.h
+        inc/MantidQtMantidWidgets/ProgressPresenter.h
+        inc/MantidQtMantidWidgets/ProjectSavePresenter.h
+        inc/MantidQtMantidWidgets/ProjectSaveModel.h
+        inc/MantidQtMantidWidgets/ProgressableView.h
+        inc/MantidQtMantidWidgets/WorkspacePresenter/ADSAdapter.h
+        inc/MantidQtMantidWidgets/WorkspacePresenter/IWorkspaceDockView.h
+        inc/MantidQtMantidWidgets/WorkspacePresenter/ViewNotifiable.h
+        inc/MantidQtMantidWidgets/WorkspacePresenter/WorkspacePresenter.h
+        inc/MantidQtMantidWidgets/WorkspacePresenter/WorkspaceProvider.h
+        inc/MantidQtMantidWidgets/WorkspacePresenter/WorkspaceProviderNotifiable.h
 )
 
 # QtDesigner UI files to process
-set ( UI_FILES 
+set ( UI_FILES
     inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorOptionsDialog.ui
     inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorWidget.ui
     inc/MantidQtMantidWidgets/DataSelector.ui
@@ -335,9 +341,8 @@ set ( UI_FILES
     inc/MantidQtMantidWidgets/ColorBarWidget.ui
     inc/MantidQtMantidWidgets/DisplayCurveFit.ui
     inc/MantidQtMantidWidgets/IndirectInstrumentConfig.ui
-	inc/MantidQtMantidWidgets/LogValueSelector.ui
+    inc/MantidQtMantidWidgets/LogValueSelector.ui
     inc/MantidQtMantidWidgets/MWDiag.ui
-    inc/MantidQtMantidWidgets/MWRunFiles.ui
     inc/MantidQtMantidWidgets/MWView.ui
     inc/MantidQtMantidWidgets/MultifitSetupDialog.ui
     inc/MantidQtMantidWidgets/MuonFitDataSelector.ui
@@ -354,28 +359,26 @@ set ( UI_FILES
     inc/MantidQtMantidWidgets/InstrumentView/UCorrectionDialog.ui
 )
 
-# Python unit tests
-set ( TEST_PY_FILES
-  test/MWRunFilesTest.py
-)
-
 set ( TEST_FILES
-  AlgorithmHintStrategyTest.h
-  DataProcessorUI/DataProcessorPostprocessingAlgorithmTest.h
-  DataProcessorUI/DataProcessorPreprocessingAlgorithmTest.h
-  DataProcessorUI/DataProcessorProcessingAlgorithmBaseTest.h
-  DataProcessorUI/DataProcessorProcessingAlgorithmTest.h
-  DataProcessorUI/DataProcessorCommandsTest.h
-  DataProcessorUI/DataProcessorGenerateNotebookTest.h
-  DataProcessorUI/DataProcessorOneLevelTreeManagerTest.h
-  DataProcessorUI/DataProcessorTwoLevelTreeManagerTest.h
-  DataProcessorUI/DataProcessorWhiteListTest.h
-  DataProcessorUI/GenericDataProcessorPresenterTest.h
-  DataProcessorUI/ParseKeyValueStringTest.h
-  DataProcessorUI/QDataProcessorOneLevelTreeModelTest.h
-  DataProcessorUI/QDataProcessorTwoLevelTreeModelTest.h
-  WorkspacePresenter/WorkspacePresenterTest.h
-  WorkspacePresenter/ADSAdapterTest.h
+        AlgorithmHintStrategyTest.h
+        TrackedActionTest.h
+        DataProcessorUI/DataProcessorCommandsTest.h
+        DataProcessorUI/DataProcessorGenerateNotebookTest.h
+        DataProcessorUI/DataProcessorOneLevelTreeManagerTest.h
+        DataProcessorUI/DataProcessorPostprocessingAlgorithmTest.h
+        DataProcessorUI/DataProcessorPreprocessingAlgorithmTest.h
+        DataProcessorUI/DataProcessorProcessingAlgorithmBaseTest.h
+        DataProcessorUI/DataProcessorProcessingAlgorithmTest.h
+        DataProcessorUI/DataProcessorTwoLevelTreeManagerTest.h
+        DataProcessorUI/DataProcessorWhiteListTest.h
+        DataProcessorUI/GenericDataProcessorPresenterTest.h
+        DataProcessorUI/ParseKeyValueStringTest.h
+        DataProcessorUI/QDataProcessorOneLevelTreeModelTest.h
+        DataProcessorUI/QDataProcessorTwoLevelTreeModelTest.h
+        ProjectSaveModelTest.h
+        ProjectSavePresenterTest.h
+        WorkspacePresenter/ADSAdapterTest.h
+        WorkspacePresenter/WorkspacePresenterTest.h
 )
 
 find_package (Qt4 REQUIRED QtHelp QtWebKit QtNetwork QUIET)
@@ -391,7 +394,7 @@ qt4_wrap_cpp ( MOCCED_FILES ${MOC_FILES} )
 
 set ( ALL_SRC ${SRC_FILES} ${MOCCED_FILES} )
 
-qt4_wrap_ui ( UI_HDRS ${UI_FILES} ) 
+qt4_wrap_ui ( UI_HDRS ${UI_FILES} )
 qt4_add_resources ( RES_FILES ${PROJECT_SOURCE_DIR}/images/MantidWidgets.qrc )
 
 include_directories ( ${QSCINTILLA_INCLUDE_DIR} )
@@ -410,7 +413,7 @@ if (OSX_VERSION VERSION_GREATER 10.8)
   set_target_properties ( MantidWidgets PROPERTIES INSTALL_RPATH "@loader_path/../MacOS")
 endif ()
 
-target_link_libraries ( MantidWidgets LINK_PRIVATE ${TCMALLOC_LIBRARIES_LINKTIME} 
+target_link_libraries ( MantidWidgets LINK_PRIVATE ${TCMALLOC_LIBRARIES_LINKTIME}
             MantidQtAPI
             QtPropertyBrowser
             ${CORE_MANTIDLIBS}
diff --git a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorMockObjects.h b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorMockObjects.h
index 05341ea16a0283f10960843278af07c38b65f509..fe44edda61a55fd1eb293f65309d0e9d134b865d 100644
--- a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorMockObjects.h
+++ b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/DataProcessorMockObjects.h
@@ -108,17 +108,20 @@ public:
                      bool(const std::string &prompt, const std::string &title));
   MOCK_CONST_METHOD2(giveUserWarning,
                      void(const std::string &prompt, const std::string &title));
+  MOCK_METHOD0(publishCommandsMocked, void());
 
 private:
   // Calls we don't care about
   const std::map<std::string, QVariant> &options() const override {
     return m_options;
   };
+
   std::vector<DataProcessorCommand_uptr> publishCommands() override {
     std::vector<DataProcessorCommand_uptr> commands;
     for (size_t i = 0; i < 27; i++)
       commands.push_back(
           Mantid::Kernel::make_unique<DataProcessorAppendRowCommand>(this));
+    publishCommandsMocked();
     return commands;
   };
   std::set<std::string> getTableList() const {
diff --git a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/GenericDataProcessorPresenter.h b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/GenericDataProcessorPresenter.h
index d2f1d5843d11b0ac75ff8a3abe0c3b6915bc1f1c..fc6883de2303be7431ea83ce6304920427d793a2 100644
--- a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/GenericDataProcessorPresenter.h
+++ b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataProcessorUI/GenericDataProcessorPresenter.h
@@ -60,6 +60,8 @@ public:
           preprocessMap,
       const DataProcessorProcessingAlgorithm &processor,
       const DataProcessorPostprocessingAlgorithm &postprocessor,
+      const std::map<std::string, std::string> &postprocessMap =
+          std::map<std::string, std::string>(),
       const std::string &loader = "Load");
   // Constructor: no pre-processing, post-processing
   GenericDataProcessorPresenter(
@@ -124,6 +126,8 @@ private:
   DataProcessorProcessingAlgorithm m_processor;
   // Post-processing algorithm
   DataProcessorPostprocessingAlgorithm m_postprocessor;
+  // Post-processing map
+  std::map<std::string, std::string> m_postprocessMap;
   // Loader
   std::string m_loader;
   // A boolean indicating whether a post-processing algorithm has been defined
diff --git a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataSelector.h b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataSelector.h
index 63ca54e5b9dbf8b6e40fa4309cbee17bc7fd10a7..947741de94f6f3e93489bd8e5b437fbf537a1869 100644
--- a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataSelector.h
+++ b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataSelector.h
@@ -12,8 +12,8 @@
 namespace MantidQt {
 namespace MantidWidgets {
 
-using ButtonOpts = MWRunFiles::ButtonOpts;
-using LiveButtonOpts = MWRunFiles::LiveButtonOpts;
+using ButtonOpts = API::MWRunFiles::ButtonOpts;
+using LiveButtonOpts = API::MWRunFiles::LiveButtonOpts;
 
 /**
 This class defines a widget for selecting a workspace of file path by using a
@@ -81,6 +81,7 @@ class EXPORT_OPT_MANTIDQT_MANTIDWIDGETS DataSelector
                  setWorkspaceTypes)
   Q_PROPERTY(bool ShowHidden READ showHiddenWorkspaces WRITE
                  showHiddenWorkspaces)
+  Q_PROPERTY(bool ShowGroups READ showWorkspaceGroups WRITE showWorkspaceGroups)
   Q_PROPERTY(QString Algorithm READ getValidatingAlgorithm WRITE
                  setValidatingAlgorithm)
 
@@ -95,6 +96,8 @@ public:
 
   /// Get the current file path in the MWRunFiles widget
   QString getFullFilePath() const;
+  /// Get the workspace name from the list of files
+  QString getWsNameFromFiles() const;
   /// Get the currently available file or workspace name
   QString getCurrentDataName() const;
   /// Get whether the file selector is currently being shown
@@ -364,6 +367,24 @@ public:
     m_uiForm.wsWorkspaceInput->showHiddenWorkspaces(show);
   }
 
+  /**
+   * Gets if the workspace selector shows group workspaces
+   *
+   * @return Boolean flag if group workspaces are shown
+   */
+  bool showWorkspaceGroups() const {
+    return m_uiForm.wsWorkspaceInput->showWorkspaceGroups();
+  }
+
+  /**
+   * Sets if the workspace selector shows workspace groups
+   *
+   * @param show :: Boolean flag if group workspaces are shown
+   */
+  void showWorkspaceGroups(bool show) {
+    m_uiForm.wsWorkspaceInput->showWorkspaceGroups(show);
+  }
+
   /**
    * Gets if the validating algorithm of workspace selector
    *
diff --git a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataSelector.ui b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataSelector.ui
index bf3851e6db163a01bee74fc633da23e3e2eb9ba0..0c377292159ce19bbc6d3db604e73bfdaac554d3 100644
--- a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataSelector.ui
+++ b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/DataSelector.ui
@@ -48,7 +48,7 @@
         <number>0</number>
        </property>
        <item>
-        <widget class="MantidQt::MantidWidgets::MWRunFiles" name="rfFileInput" native="true">
+        <widget class="MantidQt::API::MWRunFiles" name="rfFileInput" native="true">
          <property name="label" stdset="0">
           <string/>
          </property>
@@ -101,9 +101,9 @@
  </widget>
  <customwidgets>
   <customwidget>
-   <class>MantidQt::MantidWidgets::MWRunFiles</class>
+   <class>MantidQt::API::MWRunFiles</class>
    <extends>QWidget</extends>
-   <header>MantidQtMantidWidgets/MWRunFiles.h</header>
+   <header>MantidQtAPI/MWRunFiles.h</header>
   </customwidget>
   <customwidget>
    <class>MantidQt::MantidWidgets::WorkspaceSelector</class>
diff --git a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/FitOptionsBrowser.h b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/FitOptionsBrowser.h
index 0ca9c6f49759c18d65f0dc5ffc6674a66a8622aa..952c7bee461b06cdfe4e74a637759aad0d66c18d 100644
--- a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/FitOptionsBrowser.h
+++ b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/FitOptionsBrowser.h
@@ -135,6 +135,8 @@ private:
   QtProperty *m_maxIterations;
   /// EvaluationType property
   QtProperty *m_evaluationType;
+  /// Peak radius property
+  QtProperty *m_peakRadius;
 
   // Fit properties
   /// Output property
diff --git a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/FitPropertyBrowser.h b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/FitPropertyBrowser.h
index d333b85018a54e1ec190425df60636c2e125adc8..d0e88e72c1c9e4060a2721e8cdadaa7e3ab91f5c 100644
--- a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/FitPropertyBrowser.h
+++ b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/FitPropertyBrowser.h
@@ -151,6 +151,8 @@ public:
   void normaliseData(bool on) { m_shouldBeNormalised = on; }
   /// Get the max number of iterations
   int maxIterations() const;
+  /// Get the peak radius for peak functions
+  int getPeakRadius() const;
 
   /// Get the start X
   double startX() const;
@@ -413,6 +415,7 @@ protected:
   QtProperty *m_ignoreInvalidData;
   QtProperty *m_costFunction;
   QtProperty *m_maxIterations;
+  QtProperty *m_peakRadius;
   QtProperty *m_logValue;
   QtProperty *m_plotDiff;
   QtProperty *m_plotCompositeMembers;
diff --git a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/IMuonFitDataSelector.h b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/IMuonFitDataSelector.h
index 58d9296a3da8f6431c21944a0d007c8c07c0a9c0..e5fa14d3e39194bd7347c829863e8c57963a5c12 100644
--- a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/IMuonFitDataSelector.h
+++ b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/IMuonFitDataSelector.h
@@ -18,7 +18,6 @@ public:
   enum class FitType { Single, CoAdd, Simultaneous };
   virtual ~IMuonFitDataSelector() {}
   virtual QStringList getFilenames() const = 0;
-  virtual unsigned int getWorkspaceIndex() const = 0;
   virtual double getStartTime() const = 0;
   virtual double getEndTime() const = 0;
   virtual void setNumPeriods(size_t numPeriods) = 0;
@@ -29,7 +28,6 @@ public:
   virtual void setAvailableGroups(const QStringList &groupNames) = 0;
   virtual QStringList getChosenGroups() const = 0;
   virtual void setChosenGroup(const QString &group) = 0;
-  virtual void setWorkspaceIndex(unsigned int index) = 0;
   virtual void setStartTime(double start) = 0;
   virtual void setEndTime(double end) = 0;
   virtual void setStartTimeQuietly(double start) = 0;
diff --git a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/IMuonFitFunctionControl.h b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/IMuonFitFunctionControl.h
index e8ecab2867523d04f41f10f98fb726b8cfd951a8..09fd6ca74c18500b5a8638dc9257afe6382ab365 100644
--- a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/IMuonFitFunctionControl.h
+++ b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/IMuonFitFunctionControl.h
@@ -42,6 +42,9 @@ public:
   virtual Mantid::API::IFunction_sptr getFunction() const = 0;
   virtual std::vector<std::string> getWorkspaceNamesToFit() const = 0;
   virtual void setMultiFittingMode(bool enabled) = 0;
+  virtual void doRemoveGuess() = 0;
+  virtual void doPlotGuess() = 0;
+  virtual bool hasGuess() const = 0;
 signals:
   virtual void functionUpdateRequested() = 0;
   virtual void functionUpdateAndFitRequested(bool sequential) = 0;
diff --git a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/IProjectSaveView.h b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/IProjectSaveView.h
new file mode 100644
index 0000000000000000000000000000000000000000..104ce5aee9d63c441a641d9515b69843cdd6f04d
--- /dev/null
+++ b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/IProjectSaveView.h
@@ -0,0 +1,74 @@
+#ifndef MANTID_CUSTOMINTERFACES_IPROJECTSAVEVIEW_H
+#define MANTID_CUSTOMINTERFACES_IPROJECTSAVEVIEW_H
+
+#include "MantidQtAPI/IProjectSerialisable.h"
+
+#include <QMainWindow>
+#include <QWidget>
+#include <set>
+#include <string>
+#include <vector>
+
+namespace MantidQt {
+namespace MantidWidgets {
+
+struct WindowInfo;
+struct WorkspaceInfo;
+
+/** @class IProjectSaveView
+
+IProjectSaveView is the interface for defining the functions that the project
+save view needs to implement.
+
+Copyright &copy; 2011-14 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>
+*/
+class IProjectSaveView {
+public:
+  /// Get all window handles passed to the view
+  virtual std::vector<MantidQt::API::IProjectSerialisable *> getWindows() = 0;
+  /// Get the names of all checked workspaces
+  virtual std::vector<std::string> getCheckedWorkspaceNames() = 0;
+  /// Get the names of all unchecked workspaces
+  virtual std::vector<std::string> getUncheckedWorkspaceNames() = 0;
+  /// Get the project path
+  virtual QString getProjectPath() = 0;
+  /// Set the project path
+  virtual void setProjectPath(const QString &path) = 0;
+  /// Update the workspaces list with a collection of workspace info items
+  virtual void
+  updateWorkspacesList(const std::vector<WorkspaceInfo> &workspaces) = 0;
+  /// Update the included windows list with a collection of window info items
+  virtual void
+  updateIncludedWindowsList(const std::vector<WindowInfo> &windows) = 0;
+  /// Update the excluded windows list with a collection of window info items
+  virtual void
+  updateExcludedWindowsList(const std::vector<WindowInfo> &windows) = 0;
+  /// Remove items from the included window list
+  virtual void
+  removeFromIncludedWindowsList(const std::vector<std::string> &windows) = 0;
+  /// Remove items from the excluded window list
+  virtual void
+  removeFromExcludedWindowsList(const std::vector<std::string> &windows) = 0;
+};
+}
+}
+#endif /* MANTID_CUSTOMINTERFACES_IPROJECTSAVEVIEW_H */
diff --git a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/InstrumentView/InstrumentWidget.h b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/InstrumentView/InstrumentWidget.h
index d3bf033cfff2659719377a5ed0b641790467c7ce..78386bdfe43ff1eef9ab2a0d232c402fdc52ff0f 100644
--- a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/InstrumentView/InstrumentWidget.h
+++ b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/InstrumentView/InstrumentWidget.h
@@ -3,13 +3,18 @@
 
 #include "InstrumentWidgetTypes.h"
 #include "MantidGLWidget.h"
-#include <MantidQtMantidWidgets/WidgetDllOption.h>
+#include "UnwrappedSurface.h"
 
 #include "MantidAPI/AlgorithmObserver.h"
+#include "MantidAPI/IMaskWorkspace.h"
+#include "MantidAPI/IPeaksWorkspace.h"
 #include "MantidAPI/IPeaksWorkspace_fwd.h"
+#include "MantidAPI/ITableWorkspace.h"
 #include "MantidAPI/Workspace.h"
 #include "MantidQtAPI/GraphOptions.h"
 #include "MantidQtAPI/WorkspaceObserver.h"
+
+#include <MantidQtMantidWidgets/WidgetDllOption.h>
 #include <boost/shared_ptr.hpp>
 
 namespace Mantid {
@@ -88,6 +93,7 @@ public:
   std::string getWorkspaceNameStdString() const;
   void renameWorkspace(const std::string &workspace);
   SurfaceType getSurfaceType() const { return m_surfaceType; }
+  Mantid::Kernel::V3D getSurfaceAxis(const int surfaceType) const;
   /// Get pointer to the projection surface
   boost::shared_ptr<ProjectionSurface> getSurface() const;
   /// True if the GL instrument display is currently on
@@ -152,6 +158,7 @@ signals:
   void requestSelectComponent(const QString &);
   void preDeletingHandle();
   void clearingHandle();
+  void maskedWorkspaceOverlayed();
 
 protected:
   /// Implements AlgorithmObserver's finish handler
@@ -287,7 +294,16 @@ private:
   void renameHandle(const std::string &oldName,
                     const std::string &newName) override;
   void clearADSHandle() override;
-
+  /// overlay a peaks workspace on the projection surface
+  void overlayPeaksWorkspace(Mantid::API::IPeaksWorkspace_sptr ws);
+  /// overlay a masked workspace on the projection surface
+  void overlayMaskedWorkspace(Mantid::API::IMaskWorkspace_sptr ws);
+  /// overlay a table workspace with shape parameters on the projection surface
+  void overlayShapesWorkspace(Mantid::API::ITableWorkspace_sptr);
+  /// get a workspace from the ADS
+  Mantid::API::Workspace_sptr getWorkspaceFromADS(const std::string &name);
+  /// get a handle to the unwrapped surface
+  boost::shared_ptr<UnwrappedSurface> getUnwrappedSurface();
   /// Load tabs on the widget form a project file
   void loadTabs(const std::string &lines) const;
   /// Save tabs on the widget to a string
diff --git a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/InstrumentView/InstrumentWidgetMaskTab.h b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/InstrumentView/InstrumentWidgetMaskTab.h
index a8719e43ad483aecab06d9f1721a28c307af7abc..b52f31104694d8d6c7d74e694c6b48adc5638765 100644
--- a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/InstrumentView/InstrumentWidgetMaskTab.h
+++ b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/InstrumentView/InstrumentWidgetMaskTab.h
@@ -95,6 +95,7 @@ protected slots:
   void storeBinMask();
   void storeMask();
   void clearMask();
+  void saveShapesToTable() const;
   void saveInvertedMaskToWorkspace();
   void saveInvertedMaskToFile();
   void saveMaskToWorkspace();
@@ -108,7 +109,7 @@ protected slots:
   void saveExcludeGroupToFile();
   void showSaveMenuTooltip(QAction *);
   void toggleMaskGroup();
-
+  void enableApplyButtons();
   void doubleChanged(QtProperty *);
 
 protected:
@@ -123,7 +124,6 @@ protected:
   void saveMaskingToCalFile(bool invertMask = false);
   void saveMaskingToTableWorkspace(bool invertMask = false);
   std::string generateMaskWorkspaceName(bool temp = false) const;
-  void enableApplyButtons();
   void setSelectActivity();
   Mode getMode() const;
   /// Get mask/group border color
@@ -165,6 +165,7 @@ protected:
 
   QPushButton *m_applyToData;
   QPushButton *m_applyToView;
+  QPushButton *m_saveShapesToTable;
   QPushButton *m_clearAll;
   QPushButton *m_saveButton;
   bool m_maskBins;
diff --git a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/InstrumentView/InstrumentWidgetPickTab.h b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/InstrumentView/InstrumentWidgetPickTab.h
index 5c397db17c1e72561f541434d9bafb207f4737d6..d74cd3487381601498df34c6465e37b20f9b9c06 100644
--- a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/InstrumentView/InstrumentWidgetPickTab.h
+++ b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/InstrumentView/InstrumentWidgetPickTab.h
@@ -86,6 +86,7 @@ public:
   bool addToDisplayContextMenu(QMenu &) const override;
   void selectTool(const ToolType tool);
   boost::shared_ptr<ProjectionSurface> getSurface() const;
+  const InstrumentWidget *getInstrumentWidget() const;
   /// Load settings for the pick tab from a project file
   virtual void loadFromProject(const std::string &lines) override;
   /// Save settings for the pick tab to a project file
@@ -104,8 +105,9 @@ private slots:
   void removeCurve(const QString &);
   void singleComponentTouched(size_t pickID);
   void singleComponentPicked(size_t pickID);
-  void comparePeaks(const std::pair<Mantid::Geometry::IPeak *,
-                                    Mantid::Geometry::IPeak *> &peaks);
+  void
+  comparePeaks(const std::pair<std::vector<Mantid::Geometry::IPeak *>,
+                               std::vector<Mantid::Geometry::IPeak *>> &peaks);
   void updateSelectionInfoDisplay();
   void shapeCreated();
   void updatePlotMultipleDetectors();
@@ -185,15 +187,16 @@ public:
 public slots:
   void displayInfo(size_t pickID);
   void displayComparePeaksInfo(
-      std::pair<Mantid::Geometry::IPeak *, Mantid::Geometry::IPeak *> peaks);
+      const std::pair<std::vector<Mantid::Geometry::IPeak *>,
+                      std::vector<Mantid::Geometry::IPeak *>> &peaks);
   void clear();
 
 private:
   QString displayDetectorInfo(Mantid::detid_t detid);
   QString displayNonDetectorInfo(Mantid::Geometry::ComponentID compID);
   QString displayPeakInfo(Mantid::Geometry::IPeak *peak);
-  QString displayPeakAngles(
-      std::pair<Mantid::Geometry::IPeak *, Mantid::Geometry::IPeak *> peaks);
+  QString displayPeakAngles(const std::pair<Mantid::Geometry::IPeak *,
+                                            Mantid::Geometry::IPeak *> &peaks);
   QString getParameterInfo(Mantid::Geometry::IComponent_const_sptr comp);
   QString getPeakOverlayInfo();
 
diff --git a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/InstrumentView/ProjectionSurface.h b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/InstrumentView/ProjectionSurface.h
index 074b64bd3dba59115d495806e44c5e6f861cde42..1f69d6204f269c9eb7b84d1fb5aa6454614e9919 100644
--- a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/InstrumentView/ProjectionSurface.h
+++ b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/InstrumentView/ProjectionSurface.h
@@ -227,6 +227,10 @@ public:
   void changeBorderColor(const QColor &color) {
     m_maskShapes.changeBorderColor(color);
   }
+  /// Save masks to a table workspace
+  void saveShapesToTableWorkspace();
+  /// Load masks from a table workspace
+  void loadShapesFromTableWorkspace(Mantid::API::ITableWorkspace_const_sptr ws);
 
   //-----------------------------------
   //    Peaks overlay methods
@@ -272,8 +276,8 @@ signals:
   // peaks
   void peaksWorkspaceAdded();
   void peaksWorkspaceDeleted();
-  void comparePeaks(
-      const std::pair<Mantid::Geometry::IPeak *, Mantid::Geometry::IPeak *> &);
+  void comparePeaks(const std::pair<std::vector<Mantid::Geometry::IPeak *>,
+                                    std::vector<Mantid::Geometry::IPeak *>> &);
 
   // other
   void redrawRequired(); ///< request redrawing of self
@@ -339,8 +343,8 @@ protected:
   bool m_showPeakRelativeIntensity; ///< flag to show peak hkl labels
   mutable int m_peakShapesStyle; ///< index of a default PeakMarker2D style to
   std::pair<QPointF, QPointF> m_selectedMarkers;
-  std::pair<Mantid::Geometry::IPeak *, Mantid::Geometry::IPeak *>
-      m_selectedPeaks;
+  std::pair<std::vector<Mantid::Geometry::IPeak *>,
+            std::vector<Mantid::Geometry::IPeak *>> m_selectedPeaks;
   /// use with a new PeakOverlay.
 
 private:
@@ -352,6 +356,8 @@ private:
   void drawMaskShapes(QPainter &painter) const;
   /// Draw the selection rectangle to the surface
   void drawSelectionRect(QPainter &painter) const;
+  /// Check if a peak is visible at a given point
+  bool peakVisibleAtPoint(const QPointF &point) const;
   /// Get the current input controller
   MantidQt::MantidWidgets::InputController *getController() const;
 
diff --git a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/InstrumentView/Shape2DCollection.h b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/InstrumentView/Shape2DCollection.h
index a817239b347ff514d8a960b6bc023a8ae796f087..20fdd8ba9a6de41439f87ff74f29405c5bbde8ae 100644
--- a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/InstrumentView/Shape2DCollection.h
+++ b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/InstrumentView/Shape2DCollection.h
@@ -1,6 +1,8 @@
 #ifndef MANTIDPLOT_SHAPE2DCOLLECTION_H_
 #define MANTIDPLOT_SHAPE2DCOLLECTION_H_
 
+#include "MantidAPI/ITableWorkspace.h"
+
 #include "Shape2D.h"
 #include "RectF.h"
 
@@ -53,6 +55,7 @@ public:
   void keyPressEvent(QKeyEvent *);
 
   bool selectAtXY(int x, int y, bool edit = true);
+  bool selectAtXY(const QPointF &point, bool edit = true);
   void deselectAtXY(int x, int y);
   bool selectIn(const QRect &rect);
   void removeCurrentShape();
@@ -85,6 +88,10 @@ public:
 
   /// Change border color of all shapes.
   void changeBorderColor(const QColor &color);
+  /// Save shape collection to a Table workspace
+  void saveToTableWorkspace();
+  /// Load shape collectio from a Table workspace
+  void loadFromTableWorkspace(Mantid::API::ITableWorkspace_const_sptr ws);
   /// Load settings for the shape 2D collection from a project file
   virtual void loadFromProject(const std::string &lines);
   /// Save settings for the shape 2D collection to a project file
diff --git a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/MWDiag.ui b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/MWDiag.ui
index d673e5af0a836359b75fb78d00d2dfe0a9229381..6b482e6d48d4cc344df276bcf9ac6aca7b4711e0 100644
--- a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/MWDiag.ui
+++ b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/MWDiag.ui
@@ -20,7 +20,7 @@
    <item>
     <layout class="QHBoxLayout" name="horizontalLayout">
      <item>
-      <widget class="MantidQt::MantidWidgets::MWRunFiles" name="maskFileFinder">
+      <widget class="MantidQt::API::MWRunFiles" name="maskFileFinder">
        <property name="toolTip">
         <string>A file containing a list of spectra numbers which we aleady know should be masked</string>
        </property>
@@ -158,7 +158,7 @@
      </property>
      <layout class="QVBoxLayout" name="verticalLayout">
       <item>
-       <widget class="MantidQt::MantidWidgets::MWRunFiles" name="white_file">
+       <widget class="MantidQt::API::MWRunFiles" name="white_file">
         <property name="label" stdset="0">
          <string>Detector Van 1</string>
         </property>
@@ -228,7 +228,7 @@
      </property>
      <layout class="QVBoxLayout" name="verticalLayout_2">
       <item>
-       <widget class="MantidQt::MantidWidgets::MWRunFiles" name="white_file_2">
+       <widget class="MantidQt::API::MWRunFiles" name="white_file_2">
         <property name="label" stdset="0">
          <string>Detector Van 2</string>
         </property>
@@ -421,9 +421,9 @@
  </widget>
  <customwidgets>
   <customwidget>
-   <class>MantidQt::MantidWidgets::MWRunFiles</class>
+   <class>MantidQt::API::MWRunFiles</class>
    <extends>QWidget</extends>
-   <header>MantidQtMantidWidgets/MWRunFiles.h</header>
+   <header>MantidQtAPI/MWRunFiles.h</header>
   </customwidget>
  </customwidgets>
  <resources/>
diff --git a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/MantidWSIndexDialog.h b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/MantidWSIndexDialog.h
index dc12a80cef3d927e77a66a457843a90a082344f3..8dc059adc3396d61a3ec97398598206603d13238 100644
--- a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/MantidWSIndexDialog.h
+++ b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/MantidWSIndexDialog.h
@@ -6,6 +6,7 @@
 //----------------------------------
 #include "MantidQtMantidWidgets/WidgetDllOption.h"
 #include <QCheckBox>
+#include <QComboBox>
 #include <QDialog>
 #include <QLabel>
 #include <QLineEdit>
@@ -323,7 +324,7 @@ private:
   QLineEditWithErrorMark *m_wsField, *m_spectraField;
   QVBoxLayout *m_outer, *m_wsBox, *m_spectraBox;
   QHBoxLayout *m_optionsBox;
-  QCheckBox *m_waterfallOpt, *m_tiledOpt;
+  QComboBox *m_plotOptions;
 
   /// A list of names of workspaces which are to be plotted.
   QList<QString> m_wsNames;
diff --git a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/MuonFitDataSelector.h b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/MuonFitDataSelector.h
index 9fecf3c37ffb7fc2c8872bbbfbe749088b909d06..e83480ce4490b0d277e041a48262646ffb725e14 100644
--- a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/MuonFitDataSelector.h
+++ b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/MuonFitDataSelector.h
@@ -54,8 +54,6 @@ public:
   // --- IMuonFitDataSelector methods
   /// Get selected filenames
   QStringList getFilenames() const override;
-  /// Get selected workspace index
-  unsigned int getWorkspaceIndex() const override;
   /// Get selected start time
   double getStartTime() const override;
   /// Get selected end time
@@ -95,8 +93,6 @@ public slots:
                            const QString &instName) override;
   /// Set names of available groups
   void setAvailableGroups(const QStringList &groupNames) override;
-  /// Set selected workspace index
-  void setWorkspaceIndex(unsigned int index) override;
   /// Set start time for fit
   void setStartTime(double start) override;
   /// Set end time for fit
@@ -115,7 +111,7 @@ public slots:
   void checkForMultiGroupPeriodSelection();
 
 signals:
-  /// Edited the ws index, start or end fields
+  /// Edited the start or end fields
   void dataPropertiesChanged();
   /// Changed the groups selection
   void selectedGroupsChanged();
diff --git a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/MuonFitDataSelector.ui b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/MuonFitDataSelector.ui
index 46d756198fe56e2486f6e69340dabaddbfa5ceba..c889629f62a539fc5dbf15890af182410ae221a9 100644
--- a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/MuonFitDataSelector.ui
+++ b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/MuonFitDataSelector.ui
@@ -38,7 +38,7 @@
               </widget>
              </item>
              <item>
-              <widget class="MantidQt::MantidWidgets::MWRunFiles" name="runs" native="true">
+              <widget class="MantidQt::API::MWRunFiles" name="runs" native="true">
                <property name="sizePolicy">
                 <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
                  <horstretch>0</horstretch>
@@ -92,29 +92,16 @@
             </layout>
            </item>
            <item>
-            <layout class="QHBoxLayout" name="horizontalLayoutWSIndex">
+            <layout class="QHBoxLayout" name="horizontalLayoutTime">
              <item>
-              <widget class="QLabel" name="lblWSIndex">
+              <widget class="QLabel" name="lblStart">
                <property name="text">
-                <string>Workspace index:</string>
+                <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Start (us):&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</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="QLineEdit" name="txtWSIndex">
+              <widget class="QLineEdit" name="txtStart">
                <property name="sizePolicy">
                 <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
                  <horstretch>0</horstretch>
@@ -123,19 +110,8 @@
                </property>
               </widget>
              </item>
-            </layout>
-           </item>
-           <item>
-            <layout class="QHBoxLayout" name="horizontalLayoutStartTime">
-             <item>
-              <widget class="QLabel" name="lblStart">
-               <property name="text">
-                <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Start (us):&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-               </property>
-              </widget>
-             </item>
              <item>
-              <spacer name="horizontalSpacerStart">
+              <spacer name="horizontalSpacerTime">
                <property name="orientation">
                 <enum>Qt::Horizontal</enum>
                </property>
@@ -147,20 +123,6 @@
                </property>
               </spacer>
              </item>
-             <item>
-              <widget class="QLineEdit" name="txtStart">
-               <property name="sizePolicy">
-                <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
-                 <horstretch>0</horstretch>
-                 <verstretch>0</verstretch>
-                </sizepolicy>
-               </property>
-              </widget>
-             </item>
-            </layout>
-           </item>
-           <item>
-            <layout class="QHBoxLayout" name="horizontalLayoutEndTime">
              <item>
               <widget class="QLabel" name="lblEnd">
                <property name="text">
@@ -168,19 +130,6 @@
                </property>
               </widget>
              </item>
-             <item>
-              <spacer name="horizontalSpacerEnd">
-               <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="QLineEdit" name="txtEnd">
                <property name="sizePolicy">
@@ -385,9 +334,9 @@
  </widget>
  <customwidgets>
   <customwidget>
-   <class>MantidQt::MantidWidgets::MWRunFiles</class>
+   <class>MantidQt::API::MWRunFiles</class>
    <extends>QWidget</extends>
-   <header>MantidQtMantidWidgets/MWRunFiles.h</header>
+   <header>MantidQtAPI/MWRunFiles.h</header>
   </customwidget>
  </customwidgets>
  <resources/>
diff --git a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/MuonFitPropertyBrowser.h b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/MuonFitPropertyBrowser.h
index 7cf05623a771b2197036b504bc6ad66b4d28a6c2..03bd2d8d47c8cf1274516a44727add1348f6225a 100644
--- a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/MuonFitPropertyBrowser.h
+++ b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/MuonFitPropertyBrowser.h
@@ -76,6 +76,12 @@ public:
   }
   /// Set multiple fitting mode on or off
   void setMultiFittingMode(bool enabled) override;
+  /// Remove a plotted guess
+  void doRemoveGuess() override { emit removeGuess(); }
+  /// Plot a guess function
+  void doPlotGuess() override { emit plotGuess(); }
+  /// Whether a guess is plotted or not
+  bool hasGuess() const override;
 
 public slots:
   /// Perform the fit algorithm
@@ -113,10 +119,8 @@ private:
   /// workspaces
   void finishAfterSimultaneousFit(const Mantid::API::IAlgorithm *fitAlg,
                                   const int nWorkspaces) const;
-  /// Layout for extra widgets
-  QVBoxLayout *m_additionalLayout;
-  /// Splitter for additional widgets
-  QSplitter *m_widgetSplitter;
+  /// Splitter for additional widgets and splitter between this and browser
+  QSplitter *m_widgetSplitter, *m_mainSplitter;
   /// Names of workspaces to fit
   std::vector<std::string> m_workspacesToFit;
   /// Label to use for simultaneous fits
diff --git a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/PreviewPlot.h b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/PreviewPlot.h
index 7fc240e5522749d63481e80cf77352e7576e2a06..fb8699ca92b92bd9eee2e17c068b53fa0fdfc488 100644
--- a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/PreviewPlot.h
+++ b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/PreviewPlot.h
@@ -8,8 +8,11 @@
 #include "MantidQtMantidWidgets/RangeSelector.h"
 #include "MantidQtAPI/MantidWidget.h"
 
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/MatrixWorkspace.h"
 
+#include <Poco/NObserver.h>
+
 #include <QActionGroup>
 #include <QHBoxLayout>
 #include <QLabel>
diff --git a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/ProjectSaveModel.h b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/ProjectSaveModel.h
new file mode 100644
index 0000000000000000000000000000000000000000..3411ff4282480ec0597c3d166d638281661fc4cc
--- /dev/null
+++ b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/ProjectSaveModel.h
@@ -0,0 +1,82 @@
+#ifndef MANTIDQT_MANTIDWIDGETS_PROJECTSAVEMODEL_H
+#define MANTIDQT_MANTIDWIDGETS_PROJECTSAVEMODEL_H
+
+#include "MantidAPI/Workspace.h"
+#include "MantidQtAPI/IProjectSerialisable.h"
+#include "MantidQtAPI/pixmaps.h"
+
+#include "WidgetDllOption.h"
+#include <unordered_map>
+#include <vector>
+
+namespace MantidQt {
+namespace MantidWidgets {
+
+// POD structs to pass information to the view
+//==============================================================================
+
+struct WorkspaceInfo {
+  std::string name;
+  std::string type;
+  std::string size;
+  std::string icon_id;
+  size_t numWindows;
+  std::vector<WorkspaceInfo> subWorkspaces;
+
+  bool operator==(const WorkspaceInfo &b) const { return name == b.name; }
+};
+
+struct WindowInfo {
+  std::string name;
+  std::string type;
+  std::string icon_id;
+
+  bool operator==(const WindowInfo &b) const { return name == b.name; }
+};
+
+// Model definition
+//==============================================================================
+
+class EXPORT_OPT_MANTIDQT_MANTIDWIDGETS ProjectSaveModel {
+public:
+  /// Construct a new model instance with vector of window handles
+  ProjectSaveModel(std::vector<MantidQt::API::IProjectSerialisable *> windows);
+
+  /// Check if a workspace has any windows attached to it
+  bool hasWindows(const std::string &ws) const;
+  /// Get all window names for a collection of workspace names
+  std::vector<std::string>
+  getWindowNames(const std::vector<std::string> &wsNames) const;
+  /// Get all workspace names
+  std::vector<std::string> getWorkspaceNames() const;
+  /// Get all window information for a collection of workspaces
+  std::vector<WindowInfo>
+  getWindowInformation(const std::vector<std::string> &wsNames) const;
+  /// Get all workspace information
+  std::vector<WorkspaceInfo> getWorkspaceInformation() const;
+  /// Get all window handles for this workspace
+  std::vector<MantidQt::API::IProjectSerialisable *>
+  getWindows(const std::string &wsName) const;
+  /// Get all window handles for a collection of workspace names
+  std::vector<MantidQt::API::IProjectSerialisable *>
+  getUniqueWindows(const std::vector<std::string> &wsNames) const;
+  /// Get all workspaces from the ADS
+  std::vector<Mantid::API::Workspace_sptr> getWorkspaces() const;
+
+private:
+  /// Create a workspace info object for this workspace
+  WorkspaceInfo
+  makeWorkspaceInfoObject(Mantid::API::Workspace_const_sptr ws) const;
+
+  // Instance variables
+
+  /// Map to hold which windows are associated with a workspace
+  std::unordered_map<std::string,
+                     std::vector<MantidQt::API::IProjectSerialisable *>>
+      m_workspaceWindows;
+};
+
+} // CustomInterfaces
+} // MantidQt
+
+#endif // MANTIDQT_MANTIDWIDGETS_PROJECTSAVEMODEL_H
diff --git a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/ProjectSavePresenter.h b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/ProjectSavePresenter.h
new file mode 100644
index 0000000000000000000000000000000000000000..d55e71a77d798340170515a7fb7c0df4de1e2935
--- /dev/null
+++ b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/ProjectSavePresenter.h
@@ -0,0 +1,73 @@
+#ifndef MANTIDQT_MANTIDWIDGETS_PROJECTSAVEPRESENTER_H
+#define MANTIDQT_MANTIDWIDGETS_PROJECTSAVEPRESENTER_H
+
+#include "MantidAPI/Workspace.h"
+#include "MantidQtAPI/IProjectSerialisable.h"
+#include "MantidQtMantidWidgets/IProjectSaveView.h"
+#include "MantidQtMantidWidgets/ProjectSaveModel.h"
+
+#include "WidgetDllOption.h"
+#include <vector>
+
+//------------------------------------------------
+
+namespace MantidQt {
+namespace MantidWidgets {
+
+/**
+Implements a presenter for the project saving dialog.
+
+Copyright &copy; 2010 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>
+*/
+class EXPORT_OPT_MANTIDQT_MANTIDWIDGETS ProjectSavePresenter {
+public:
+  enum class Notification {
+    UncheckWorkspace,
+    CheckWorkspace,
+    PrepareProjectFolder
+  };
+
+  /// Construct a new presenter with a view
+  ProjectSavePresenter(IProjectSaveView *view);
+  /// Notify the presenter to do something
+  void notify(Notification notification);
+
+private:
+  /// Update the view to add included windows for a workspace
+  void includeWindowsForCheckedWorkspace();
+  /// Update the view to add excluded windows for a workspace
+  void excludeWindowsForUncheckedWorkspace();
+  /// Prepare a project folder given the path
+  void prepareProjectFolder();
+
+  // Instance Variables
+
+  /// Handle to the view for this presenter
+  IProjectSaveView *m_view;
+  /// Hold an instance of the model
+  ProjectSaveModel m_model;
+};
+
+} // CustomInterfaces
+} // MantidQt
+
+#endif // PROJECTSAVEPRESENTER_H
diff --git a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/TrackedAction.h b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/TrackedAction.h
new file mode 100644
index 0000000000000000000000000000000000000000..9186fc6da17ae45f30c3562941efb8352b596942
--- /dev/null
+++ b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/TrackedAction.h
@@ -0,0 +1,64 @@
+#ifndef MANTID_MANTIDWIDGETS_TRACKEDACTION_H_
+#define MANTID_MANTIDWIDGETS_TRACKEDACTION_H_
+
+#include "WidgetDllOption.h"
+#include <QAction>
+
+namespace MantidQt {
+namespace MantidWidgets {
+
+/** TrackedAction : This is a version of QAction that tracks usage through the
+  Mantid usage service
+
+  Copyright &copy; 2016 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>
+*/
+class EXPORT_OPT_MANTIDQT_MANTIDWIDGETS TrackedAction : public QAction {
+  Q_OBJECT
+public:
+  TrackedAction(QObject *parent);
+  TrackedAction(const QString &text, QObject *parent);
+  TrackedAction(const QIcon &icon, const QString &text, QObject *parent);
+  virtual ~TrackedAction() = default;
+
+  void setTrackingName(const std::string &name);
+  std::string getTrackingName() const;
+
+  void setIsTracking(const bool enableTracking);
+  bool getIsTracking() const;
+
+protected:
+  virtual std::string generateTrackingName() const;
+  virtual void registerUsage(const std::string &name);
+
+private:
+  void setupTracking();
+  bool m_isTracking;
+  mutable std::string m_trackingName;
+
+public slots:
+  void trackActivation(const bool checked);
+};
+
+} // namespace MantidWidgets
+} // namespace Mantid
+
+#endif /* MANTID_MANTIDWIDGETS_TRACKEDACTION_H_ */
\ No newline at end of file
diff --git a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/WorkspaceSelector.h b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/WorkspaceSelector.h
index 5556ba18f057efb782ecc2336c28f5e7907eaa54..14a5d5df3b56772e51c1a3bab43962885b53b8c7 100644
--- a/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/WorkspaceSelector.h
+++ b/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/WorkspaceSelector.h
@@ -66,6 +66,7 @@ class EXPORT_OPT_MANTIDQT_MANTIDWIDGETS WorkspaceSelector : public QComboBox {
                  setWorkspaceTypes)
   Q_PROPERTY(bool ShowHidden READ showHiddenWorkspaces WRITE
                  showHiddenWorkspaces)
+  Q_PROPERTY(bool ShowGroups READ showWorkspaceGroups WRITE showWorkspaceGroups)
   Q_PROPERTY(bool Optional READ isOptional WRITE setOptional)
   Q_PROPERTY(QStringList Suffix READ getSuffixes WRITE setSuffixes)
   Q_PROPERTY(QString Algorithm READ getValidatingAlgorithm WRITE
@@ -82,6 +83,8 @@ public:
   void setWorkspaceTypes(const QStringList &types);
   bool showHiddenWorkspaces() const;
   void showHiddenWorkspaces(bool show);
+  bool showWorkspaceGroups() const;
+  void showWorkspaceGroups(bool show);
   bool isOptional() const;
   void setOptional(bool optional);
   QStringList getSuffixes() const;
@@ -132,6 +135,8 @@ private:
   QStringList m_workspaceTypes;
   /// Whether to show "hidden" workspaces
   bool m_showHidden;
+  // show/hide workspace groups
+  bool m_showGroups;
   bool m_optional; ///< Whether to add an extra empty entry to the combobox
   // suffix
   QStringList m_suffix;
diff --git a/MantidQt/MantidWidgets/src/DataProcessorUI/DataProcessorOneLevelTreeManager.cpp b/MantidQt/MantidWidgets/src/DataProcessorUI/DataProcessorOneLevelTreeManager.cpp
index c8a059e20d30de80a26a0cac200cacc0130a63e4..5bc413b37a6d64298b90c830028ef35883217365 100644
--- a/MantidQt/MantidWidgets/src/DataProcessorUI/DataProcessorOneLevelTreeManager.cpp
+++ b/MantidQt/MantidWidgets/src/DataProcessorUI/DataProcessorOneLevelTreeManager.cpp
@@ -20,6 +20,7 @@
 #include "MantidQtMantidWidgets/DataProcessorUI/DataProcessorSeparatorCommand.h"
 #include "MantidQtMantidWidgets/DataProcessorUI/QDataProcessorOneLevelTreeModel.h"
 #include "MantidKernel/make_unique.h"
+#include <boost/algorithm/string/classification.hpp>
 #include <boost/algorithm/string/join.hpp>
 #include <boost/algorithm/string/split.hpp>
 
diff --git a/MantidQt/MantidWidgets/src/DataProcessorUI/DataProcessorTwoLevelTreeManager.cpp b/MantidQt/MantidWidgets/src/DataProcessorUI/DataProcessorTwoLevelTreeManager.cpp
index 250a97c49295091c612e6ef33aa46cd60a19c0f4..4e201ad6808585ebe19e1d02d0619fcf8304da6c 100644
--- a/MantidQt/MantidWidgets/src/DataProcessorUI/DataProcessorTwoLevelTreeManager.cpp
+++ b/MantidQt/MantidWidgets/src/DataProcessorUI/DataProcessorTwoLevelTreeManager.cpp
@@ -25,6 +25,7 @@
 #include "MantidQtMantidWidgets/DataProcessorUI/DataProcessorSeparatorCommand.h"
 #include "MantidQtMantidWidgets/DataProcessorUI/QDataProcessorTwoLevelTreeModel.h"
 #include "MantidKernel/make_unique.h"
+#include <boost/algorithm/string/classification.hpp>
 #include <boost/algorithm/string/join.hpp>
 #include <boost/algorithm/string/split.hpp>
 
@@ -367,6 +368,10 @@ void DataProcessorTwoLevelTreeManager::pasteSelected(const std::string &text) {
 void DataProcessorTwoLevelTreeManager::newTable(
     const DataProcessorWhiteList &whitelist) {
 
+  size_t nrows = m_ws->rowCount();
+  for (size_t row = 0; row < nrows; row++)
+    m_ws->removeRow(0);
+
   m_model.reset(new QDataProcessorTwoLevelTreeModel(
       createDefaultWorkspace(whitelist), whitelist));
 }
diff --git a/MantidQt/MantidWidgets/src/DataProcessorUI/GenericDataProcessorPresenter.cpp b/MantidQt/MantidWidgets/src/DataProcessorUI/GenericDataProcessorPresenter.cpp
index 60daa5fb87046a219565aa4596fc9c51b1fdd91a..c8098f33ffa28d8281aecd75e8cfcc23ae6acaec 100644
--- a/MantidQt/MantidWidgets/src/DataProcessorUI/GenericDataProcessorPresenter.cpp
+++ b/MantidQt/MantidWidgets/src/DataProcessorUI/GenericDataProcessorPresenter.cpp
@@ -42,6 +42,8 @@ namespace MantidWidgets {
 * @param processor : A DataProcessorProcessingAlgorithm
 * @param postprocessor : A DataProcessorPostprocessingAlgorithm
 * workspaces
+* @param postprocessMap : A map containing instructions for post-processing.
+* This map links column name to properties of the post-processing algorithm
 * @param loader : The algorithm responsible for loading data
 */
 GenericDataProcessorPresenter::GenericDataProcessorPresenter(
@@ -50,11 +52,13 @@ GenericDataProcessorPresenter::GenericDataProcessorPresenter(
         preprocessMap,
     const DataProcessorProcessingAlgorithm &processor,
     const DataProcessorPostprocessingAlgorithm &postprocessor,
+    const std::map<std::string, std::string> &postprocessMap,
     const std::string &loader)
     : WorkspaceObserver(), m_view(nullptr), m_progressView(nullptr),
       m_whitelist(whitelist), m_preprocessMap(preprocessMap),
-      m_processor(processor), m_postprocessor(postprocessor), m_loader(loader),
-      m_postprocess(true), m_mainPresenter(), m_tableDirty(false) {
+      m_processor(processor), m_postprocessor(postprocessor),
+      m_postprocessMap(postprocessMap), m_loader(loader), m_postprocess(true),
+      m_mainPresenter(), m_tableDirty(false) {
 
   // Column Options must be added to the whitelist
   m_whitelist.addElement("Options", "Options",
@@ -190,6 +194,10 @@ void GenericDataProcessorPresenter::process() {
 
   const auto items = m_manager->selectedData(true);
 
+  // Don't bother continuing if there are no items to process
+  if (items.size() == 0)
+    return;
+
   // Progress: each group and each row within count as a progress step.
   int progress = 0;
   int maxProgress = (int)(items.size());
@@ -329,6 +337,21 @@ void GenericDataProcessorPresenter::postProcessGroup(
     }
   }
 
+  // Options specified via post-process map
+  for (const auto &prop : m_postprocessMap) {
+    const std::string propName = prop.second;
+    const std::string propValueStr =
+        groupData.begin()->second[m_whitelist.colIndexFromColName(prop.first)];
+    if (!propValueStr.empty()) {
+      // Warning: we take minus the value of the properties because in
+      // Reflectometry this property refers to the rebin step, and they want a
+      // logarithmic binning. If other technique areas need to use a
+      // post-process map we'll need to re-think how to do this.
+      double propValue = boost::lexical_cast<double>(propValueStr);
+      alg->setPropertyValue(propName, std::to_string(-propValue));
+    }
+  }
+
   alg->execute();
 
   if (!alg->isExecuted())
@@ -374,8 +397,9 @@ Workspace_sptr GenericDataProcessorPresenter::prepareRunWorkspace(
   IAlgorithm_sptr alg =
       AlgorithmManager::Instance().create(preprocessor.name());
   alg->initialize();
-  alg->setProperty(preprocessor.lhsProperty(),
-                   loadRun(runs[0], instrument, preprocessor.prefix())->name());
+  alg->setProperty(
+      preprocessor.lhsProperty(),
+      loadRun(runs[0], instrument, preprocessor.prefix())->getName());
   alg->setProperty(preprocessor.outputProperty(), outputName);
 
   // Drop the first run from the runs list
@@ -396,7 +420,7 @@ Workspace_sptr GenericDataProcessorPresenter::prepareRunWorkspace(
 
       alg->setProperty(
           preprocessor.rhsProperty(),
-          loadRun(*runIt, instrument, preprocessor.prefix())->name());
+          loadRun(*runIt, instrument, preprocessor.prefix())->getName());
       alg->execute();
 
       if (runIt != --runs.end()) {
@@ -585,7 +609,7 @@ GenericDataProcessorPresenter::reduceRow(const std::vector<std::string> &data) {
 
         auto optionsMap = parseKeyValueString(options);
         auto runWS = prepareRunWorkspace(runStr, preprocessor, optionsMap);
-        alg->setProperty(propertyName, runWS->name());
+        alg->setProperty(propertyName, runWS->getName());
       }
     } else {
       // No pre-processing needed
diff --git a/MantidQt/MantidWidgets/src/DataProcessorUI/QDataProcessorWidget.cpp b/MantidQt/MantidWidgets/src/DataProcessorUI/QDataProcessorWidget.cpp
index 73d2f0d176ff5a9c14b4f2d86af7dda51a55dec2..afc2cc5cca755254d96d4c4a19a27b4b3a1562fd 100644
--- a/MantidQt/MantidWidgets/src/DataProcessorUI/QDataProcessorWidget.cpp
+++ b/MantidQt/MantidWidgets/src/DataProcessorUI/QDataProcessorWidget.cpp
@@ -1,5 +1,4 @@
 #include "MantidQtMantidWidgets/DataProcessorUI/QDataProcessorWidget.h"
-#include "MantidQtAPI/FileDialogHandler.h"
 #include "MantidQtAPI/MantidWidget.h"
 #include "MantidQtMantidWidgets/DataProcessorUI/DataProcessorCommandAdapter.h"
 #include "MantidQtMantidWidgets/DataProcessorUI/DataProcessorPresenter.h"
@@ -184,7 +183,7 @@ std::string QDataProcessorWidget::requestNotebookPath() {
 
   // We won't use QFileDialog directly here as using the NativeDialog option
   // causes problems on MacOS.
-  QString qfilename = API::FileDialogHandler::getSaveFileName(
+  QString qfilename = QFileDialog::getSaveFileName(
       this, "Save notebook file", QDir::currentPath(),
       "IPython Notebook files (*.ipynb);;All files (*)",
       new QString("IPython Notebook files (*.ipynb)"));
diff --git a/MantidQt/MantidWidgets/src/DataSelector.cpp b/MantidQt/MantidWidgets/src/DataSelector.cpp
index 2f8a78a62de1ab22cc952222271f2fe609fccc5c..eeefe858173a8317fd86523fc1f164121fa4276a 100644
--- a/MantidQt/MantidWidgets/src/DataSelector.cpp
+++ b/MantidQt/MantidWidgets/src/DataSelector.cpp
@@ -173,8 +173,7 @@ QString DataSelector::getProblem() const {
  */
 void DataSelector::autoLoadFile(const QString &filepath) {
   using namespace Mantid::API;
-  QFileInfo qfio(filepath);
-  QString baseName = qfio.completeBaseName();
+  QString baseName = getWsNameFromFiles();
 
   // create instance of load algorithm
   const Algorithm_sptr loadAlg =
@@ -193,12 +192,9 @@ void DataSelector::autoLoadFile(const QString &filepath) {
  */
 void DataSelector::handleAutoLoadComplete(bool error) {
   if (!error) {
-    QString filename(this->getFullFilePath());
-    QFileInfo qfio(filename);
-    QString baseName = qfio.completeBaseName();
 
     // emit that we got a valid workspace/file to work with
-    emit dataReady(baseName);
+    emit dataReady(getWsNameFromFiles());
   } else {
     m_uiForm.rfFileInput->setFileProblem(
         "Could not load file. See log for details.");
@@ -251,13 +247,33 @@ QString DataSelector::getFullFilePath() const {
   return m_uiForm.rfFileInput->getUserInput().toString();
 }
 
+/**
+ * Gets the workspace name that is created after loading the files
+ *
+ * @return The workspace name that is created after loading the files
+ */
+QString DataSelector::getWsNameFromFiles() const {
+  QString filepath = DataSelector::getFullFilePath();
+  QFileInfo qfio(filepath);
+  QString baseName = qfio.completeBaseName();
+
+  // make up a name for the group workspace, if multiple files are specified
+  if (m_uiForm.rfFileInput->allowMultipleFiles() && filepath.count(",") > 0) {
+    baseName += "_group";
+  }
+
+  return baseName;
+}
+
 /**
  * Gets the name of item selected in the DataSelector.
  *
- * This will either return the base name of the filepath or
- * the currently selected item in the workspace selector depending
- * on what view is available. If there is no valid input the method returns
- * an empty string.
+ * This will return the currently selected item in the workspace selector,
+ * if the workspace view is active.
+ * If the file view is active, it will return the basename of the file.
+ * If multiple files are allowed, and auto-loading is off, it will return the
+ * full user input.
+ * If there is no valid input the method returns an empty string.
  *
  * @return The name of the current data item
  */
@@ -270,7 +286,13 @@ QString DataSelector::getCurrentDataName() const {
   case 0:
     // the file selector is visible
     if (m_uiForm.rfFileInput->isValid()) {
-      filename = m_uiForm.rfFileInput->getUserInput().toString();
+      if (m_uiForm.rfFileInput->allowMultipleFiles() && !m_autoLoad) {
+        // if multiple files are allowed, auto-loading is not on, return the
+        // full user input
+        filename = getFullFilePath();
+      } else {
+        filename = getWsNameFromFiles();
+      }
     }
     break;
   case 1:
diff --git a/MantidQt/MantidWidgets/src/DisplayCurveFit.cpp b/MantidQt/MantidWidgets/src/DisplayCurveFit.cpp
index b49b7c0bf8248b56b421722544d5b4715d7199ef..0bd9ce452547871120807290cb8b01160d2ad5a7 100644
--- a/MantidQt/MantidWidgets/src/DisplayCurveFit.cpp
+++ b/MantidQt/MantidWidgets/src/DisplayCurveFit.cpp
@@ -1,3 +1,4 @@
+#include "MantidKernel/Logger.h"
 #include "MantidQtMantidWidgets/DisplayCurveFit.h"
 // includes for workspace handling
 
@@ -100,7 +101,7 @@ QPair<double, double> DisplayCurveFit::getCurveRange(
   curveTypes typesFound = this->getCurvesForWorkspace(workspace);
   if (typesFound.size() == 0) {
     throw std::runtime_error("No fitting curves associated to workspace" +
-                             workspace->name());
+                             workspace->getName());
   }
   return getCurveRange(typesFound[0]);
 }
diff --git a/MantidQt/MantidWidgets/src/DoubleDialogEditor.cpp b/MantidQt/MantidWidgets/src/DoubleDialogEditor.cpp
index d45b46f7c6976f9ab1c87c8ee6ba747efc3badcc..7c68cae72a15ace3a33d13e0209596850eff1480 100644
--- a/MantidQt/MantidWidgets/src/DoubleDialogEditor.cpp
+++ b/MantidQt/MantidWidgets/src/DoubleDialogEditor.cpp
@@ -3,7 +3,6 @@
 #include <QHBoxLayout>
 #include <QLineEdit>
 #include <QPushButton>
-#include <QFileDialog>
 #include <QLabel>
 #include <QDialog>
 #include <QSettings>
diff --git a/MantidQt/MantidWidgets/src/FitOptionsBrowser.cpp b/MantidQt/MantidWidgets/src/FitOptionsBrowser.cpp
index 1ed2d41fbd275cd37c417f4bac0b3ffd25271413..a3b9bedbbe12411be85b4709ad902e9ad7e1476f 100644
--- a/MantidQt/MantidWidgets/src/FitOptionsBrowser.cpp
+++ b/MantidQt/MantidWidgets/src/FitOptionsBrowser.cpp
@@ -201,6 +201,15 @@ void FitOptionsBrowser::createCommonProperties() {
                 &FitOptionsBrowser::getStringEnumProperty,
                 &FitOptionsBrowser::setStringEnumProperty);
   }
+  // Create PeakRadius property
+  m_peakRadius = m_intManager->addProperty("Peak Radius");
+  {
+    m_intManager->setValue(m_peakRadius, 0);
+    m_intManager->setMinimum(m_peakRadius, 0);
+    m_browser->addProperty(m_peakRadius);
+    addProperty("PeakRadius", m_peakRadius, &FitOptionsBrowser::getIntProperty,
+                &FitOptionsBrowser::setIntProperty);
+  }
 }
 
 void FitOptionsBrowser::createSimultaneousFitProperties() {
diff --git a/MantidQt/MantidWidgets/src/FitPropertyBrowser.cpp b/MantidQt/MantidWidgets/src/FitPropertyBrowser.cpp
index b7db9d66fd463475f605545d76d633f18529a24d..d2b71f940712a0cf907eba61a8ba3f00fe2c0b64 100644
--- a/MantidQt/MantidWidgets/src/FitPropertyBrowser.cpp
+++ b/MantidQt/MantidWidgets/src/FitPropertyBrowser.cpp
@@ -55,6 +55,7 @@
 #include <QUrl>
 
 #include <algorithm>
+#include <iostream>
 
 namespace MantidQt {
 using API::MantidDesktopServices;
@@ -67,29 +68,31 @@ namespace MantidWidgets {
  * @param mantidui :: The UI form for MantidPlot
  */
 FitPropertyBrowser::FitPropertyBrowser(QWidget *parent, QObject *mantidui)
-    : QDockWidget("Fit Function", parent), m_workspaceIndex(NULL),
-      m_startX(NULL), m_endX(NULL), m_output(NULL), m_minimizer(NULL),
-      m_ignoreInvalidData(NULL), m_costFunction(NULL), m_maxIterations(NULL),
-      m_logValue(NULL), m_plotDiff(NULL), m_plotCompositeMembers(NULL),
-      m_convolveMembers(NULL), m_rawData(NULL), m_xColumn(NULL),
-      m_yColumn(NULL), m_errColumn(NULL), m_showParamErrors(NULL),
-      m_evaluationType(nullptr), m_compositeFunction(), m_browser(NULL),
-      m_fitActionUndoFit(NULL), m_fitActionSeqFit(NULL), m_fitActionFit(NULL),
-      m_fitActionEvaluate(NULL), m_functionsGroup(NULL), m_settingsGroup(NULL),
-      m_customSettingsGroup(NULL), m_changeSlotsEnabled(false),
+    : QDockWidget("Fit Function", parent), m_workspaceIndex(nullptr),
+      m_startX(nullptr), m_endX(nullptr), m_output(nullptr),
+      m_minimizer(nullptr), m_ignoreInvalidData(nullptr),
+      m_costFunction(nullptr), m_maxIterations(nullptr), m_peakRadius(nullptr),
+      m_logValue(nullptr), m_plotDiff(nullptr), m_plotCompositeMembers(nullptr),
+      m_convolveMembers(nullptr), m_rawData(nullptr), m_xColumn(nullptr),
+      m_yColumn(nullptr), m_errColumn(nullptr), m_showParamErrors(nullptr),
+      m_evaluationType(nullptr), m_compositeFunction(), m_browser(nullptr),
+      m_fitActionUndoFit(nullptr), m_fitActionSeqFit(nullptr),
+      m_fitActionFit(nullptr), m_fitActionEvaluate(nullptr),
+      m_functionsGroup(nullptr), m_settingsGroup(nullptr),
+      m_customSettingsGroup(nullptr), m_changeSlotsEnabled(false),
       m_guessOutputName(true),
       m_updateObserver(*this, &FitPropertyBrowser::handleFactoryUpdate),
-      m_fitMapper(NULL), m_fitMenu(NULL), m_displayActionPlotGuess(NULL),
-      m_displayActionQuality(NULL), m_displayActionClearAll(NULL),
-      m_setupActionCustomSetup(NULL), m_setupActionRemove(NULL), m_tip(NULL),
-      m_fitSelector(NULL), m_fitTree(NULL), m_currentHandler(0),
-      m_defaultFunction("Gaussian"), m_defaultPeak("Gaussian"),
-      m_defaultBackground("LinearBackground"), m_index_(0), m_peakToolOn(false),
-      m_auto_back(false),
+      m_fitMapper(nullptr), m_fitMenu(nullptr),
+      m_displayActionPlotGuess(nullptr), m_displayActionQuality(nullptr),
+      m_displayActionClearAll(nullptr), m_setupActionCustomSetup(nullptr),
+      m_setupActionRemove(nullptr), m_tip(nullptr), m_fitSelector(nullptr),
+      m_fitTree(nullptr), m_currentHandler(0), m_defaultFunction("Gaussian"),
+      m_defaultPeak("Gaussian"), m_defaultBackground("LinearBackground"),
+      m_index_(0), m_peakToolOn(false), m_auto_back(false),
       m_autoBgName(QString::fromStdString(
           Mantid::Kernel::ConfigService::Instance().getString(
               "curvefitting.autoBackground"))),
-      m_autoBackground(NULL), m_decimals(-1), m_mantidui(mantidui),
+      m_autoBackground(nullptr), m_decimals(-1), m_mantidui(mantidui),
       m_shouldBeNormalised(false) {
   // Make sure plugins are loaded
   std::string libpath =
@@ -177,7 +180,7 @@ void FitPropertyBrowser::init() {
                << "Conjugate gradient (Fletcher-Reeves imp.)"
                << "Conjugate gradient (Polak-Ribiere imp.)"
                << "BFGS"
-               << "Damping";
+               << "Damped GaussNewton";
 
   m_ignoreInvalidData = m_boolManager->addProperty("Ignore invalid data");
   setIgnoreInvalidData(settings.value("Ignore invalid data", false).toBool());
@@ -192,6 +195,10 @@ void FitPropertyBrowser::init() {
   m_intManager->setValue(m_maxIterations,
                          settings.value("Max Iterations", 500).toInt());
 
+  m_peakRadius = m_intManager->addProperty("Peak Radius");
+  m_intManager->setValue(m_peakRadius,
+                         settings.value("Peak Radius", 0).toInt());
+
   m_plotDiff = m_boolManager->addProperty("Plot Difference");
   bool plotDiff = settings.value("Plot Difference", QVariant(true)).toBool();
   m_boolManager->setValue(m_plotDiff, plotDiff);
@@ -240,6 +247,7 @@ void FitPropertyBrowser::init() {
   settingsGroup->addSubProperty(m_ignoreInvalidData);
   settingsGroup->addSubProperty(m_costFunction);
   settingsGroup->addSubProperty(m_maxIterations);
+  settingsGroup->addSubProperty(m_peakRadius);
   settingsGroup->addSubProperty(m_plotDiff);
   settingsGroup->addSubProperty(m_plotCompositeMembers);
   settingsGroup->addSubProperty(m_convolveMembers);
@@ -670,7 +678,7 @@ void FitPropertyBrowser::acceptFit() {
   if (items.size() != 1)
     return;
 
-  if (items[0]->parent() == NULL)
+  if (items[0]->parent() == nullptr)
     return;
 
   PropertyHandler *h = getHandler()->findHandler(cf);
@@ -690,7 +698,7 @@ void FitPropertyBrowser::createCompositeFunction(
     const Mantid::API::IFunction_sptr func) {
   if (m_compositeFunction) {
     emit functionRemoved();
-    m_autoBackground = NULL;
+    m_autoBackground = nullptr;
   }
   if (!func) {
     m_compositeFunction.reset(new Mantid::API::CompositeFunction);
@@ -748,7 +756,7 @@ void FitPropertyBrowser::popupMenu(const QPoint &) {
   bool isFunctionsGroup = ci == m_functionsGroup;
   bool isSettingsGroup = ci == m_settingsGroup;
   bool isASetting = ci->parent() == m_settingsGroup;
-  bool isFunction = getHandler()->findFunction(ci) != NULL;
+  bool isFunction = getHandler()->findFunction(ci) != nullptr;
   bool isCompositeFunction =
       isFunction && getHandler()->findCompositeFunction(ci);
 
@@ -1145,6 +1153,11 @@ int FitPropertyBrowser::maxIterations() const {
   return m_intManager->value(m_maxIterations);
 }
 
+/// Get the peak radius for peak functions
+int FitPropertyBrowser::getPeakRadius() const {
+  return m_intManager->value(m_peakRadius);
+}
+
 /// Get the registered function names
 void FitPropertyBrowser::populateFunctionNames() {
   const std::vector<std::string> names =
@@ -1272,11 +1285,14 @@ void FitPropertyBrowser::intChanged(QtProperty *prop) {
     if (!h)
       return;
     h->setFunctionWorkspace();
-  } else if (prop == m_maxIterations) {
+  } else if (prop == m_maxIterations || prop == m_peakRadius) {
     QSettings settings;
     settings.beginGroup("Mantid/FitBrowser");
     int val = m_intManager->value(prop);
     settings.setValue(prop->propertyName(), val);
+    if (prop == m_peakRadius) {
+      sendParameterChanged(m_compositeFunction.get());
+    }
   } else { // it could be an attribute
     PropertyHandler *h = getHandler()->findHandler(prop);
     if (!h)
@@ -1523,6 +1539,7 @@ void FitPropertyBrowser::doFit(int maxIterations) {
     alg->setProperty("IgnoreInvalidData", ignoreInvalidData());
     alg->setPropertyValue("CostFunction", costFunction());
     alg->setProperty("MaxIterations", maxIterations);
+    alg->setProperty("PeakRadius", getPeakRadius());
     if (!isHistogramFit()) {
       alg->setProperty("Normalise", m_shouldBeNormalised);
       // Always output each composite function but not necessarily plot it
@@ -1762,7 +1779,7 @@ void FitPropertyBrowser::currentItemChanged(QtBrowserItem *current) {
   if (current) {
     m_currentHandler = getHandler()->findHandler(current->property());
   } else {
-    m_currentHandler = NULL;
+    m_currentHandler = nullptr;
   }
   emit currentChanged();
 }
@@ -2013,7 +2030,7 @@ void FitPropertyBrowser::hasConstraints(QtProperty *parProp, bool &hasTie,
   }
 }
 
-/** Returns the tie property for a parameter property, or NULL
+/** Returns the tie property for a parameter property, or nullptr
  * @param parProp :: parameter property
  */
 QtProperty *FitPropertyBrowser::getTieProperty(QtProperty *parProp) const {
@@ -2023,7 +2040,7 @@ QtProperty *FitPropertyBrowser::getTieProperty(QtProperty *parProp) const {
       return subs[i];
     }
   }
-  return NULL;
+  return nullptr;
 }
 
 /**
@@ -2159,7 +2176,7 @@ void FitPropertyBrowser::clearAllPlots() { emit removeFitCurves(); }
 QtProperty *
 FitPropertyBrowser::addDoubleProperty(const QString &name,
                                       QtDoublePropertyManager *manager) const {
-  if (manager == NULL)
+  if (manager == nullptr)
     manager = m_doubleManager;
   QtProperty *prop = manager->addProperty(name);
   manager->setDecimals(prop, m_decimals);
@@ -2327,11 +2344,11 @@ void FitPropertyBrowser::addAutoBackground() {
   PropertyHandler *ch = currentHandler();
   if (m_autoBackground) { // remove old background
     if (ch == m_autoBackground) {
-      ch = NULL;
+      ch = nullptr;
     }
     hasPlot = m_autoBackground->hasPlot();
     m_autoBackground->removeFunction();
-    m_autoBackground = NULL;
+    m_autoBackground = nullptr;
   }
   // Create the function
   PropertyHandler *h = getHandler()->addFunction(m_autoBgName.toStdString());
@@ -2445,7 +2462,7 @@ void FitPropertyBrowser::removeLogValue() {
   if (isWorkspaceAGroup())
     return;
   m_settingsGroup->property()->removeSubProperty(m_logValue);
-  m_logValue = NULL;
+  m_logValue = nullptr;
 }
 
 void FitPropertyBrowser::sequentialFit() {
@@ -2747,24 +2764,31 @@ void FitPropertyBrowser::setWorkspaceProperties() {
   if (!ws)
     return;
 
-  m_settingsGroup->property()->removeSubProperty(m_evaluationType);
+  // If this is a MuonFitPropertyBrowser, "evaluation type" goes in the Custom
+  // Settings group.
+  // If not, there is no Custom Settings group and it goes in the regular
+  // Settings group.
+  auto *settings =
+      m_customSettingsGroup ? m_customSettingsGroup : m_settingsGroup;
+
+  settings->property()->removeSubProperty(m_evaluationType);
   m_evaluationType->setEnabled(false);
   // if it is a MatrixWorkspace insert WorkspaceIndex
-  if (m_browser->isItemVisible(m_settingsGroup)) {
-    auto mws = boost::dynamic_pointer_cast<Mantid::API::MatrixWorkspace>(ws);
-    if (mws) {
+  auto mws = boost::dynamic_pointer_cast<Mantid::API::MatrixWorkspace>(ws);
+  if (mws) {
+    if (m_browser->isItemVisible(m_settingsGroup)) {
       if (!m_settingsGroup->property()->subProperties().contains(
               m_workspaceIndex)) {
         m_settingsGroup->property()->insertSubProperty(m_workspaceIndex,
                                                        m_workspace);
       }
-      auto isHistogram = mws->isHistogramData();
-      m_evaluationType->setEnabled(isHistogram);
-      if (isHistogram) {
-        m_settingsGroup->property()->addSubProperty(m_evaluationType);
-      }
-      return;
     }
+    auto isHistogram = mws->isHistogramData();
+    m_evaluationType->setEnabled(isHistogram);
+    if (isHistogram) {
+      settings->property()->addSubProperty(m_evaluationType);
+    }
+    return;
   }
 
   // if it is a TableWorkspace insert the column properties
@@ -2842,7 +2866,8 @@ FitPropertyBrowser::createMatrixFromTableWorkspace() const {
       return boost::shared_ptr<Mantid::API::Workspace>();
     const size_t rowCount = tws->rowCount();
     if (rowCount == 0) {
-      QMessageBox::critical(NULL, "Mantid - Error", "TableWorkspace is empty.");
+      QMessageBox::critical(nullptr, "Mantid - Error",
+                            "TableWorkspace is empty.");
       return boost::shared_ptr<Mantid::API::Workspace>();
     }
 
@@ -2851,7 +2876,8 @@ FitPropertyBrowser::createMatrixFromTableWorkspace() const {
     // get the x column
     int ix = m_columnManager->value(m_xColumn);
     if (ix >= static_cast<int>(columns.size())) {
-      QMessageBox::critical(NULL, "Mantid - Error", "X column was not found.");
+      QMessageBox::critical(nullptr, "Mantid - Error",
+                            "X column was not found.");
       return boost::shared_ptr<Mantid::API::Workspace>();
     }
     auto xcol = tws->getColumn(columns[ix]);
@@ -2859,7 +2885,8 @@ FitPropertyBrowser::createMatrixFromTableWorkspace() const {
     // get the y column
     int iy = m_columnManager->value(m_yColumn);
     if (iy >= static_cast<int>(columns.size())) {
-      QMessageBox::critical(NULL, "Mantid - Error", "Y column was not found.");
+      QMessageBox::critical(nullptr, "Mantid - Error",
+                            "Y column was not found.");
       return boost::shared_ptr<Mantid::API::Workspace>();
     }
     auto ycol = tws->getColumn(columns[iy]);
@@ -2868,7 +2895,7 @@ FitPropertyBrowser::createMatrixFromTableWorkspace() const {
     int ie =
         m_columnManager->value(m_errColumn) - 1; // first entry is empty string
     if (ie >= 0 && ie >= static_cast<int>(columns.size())) {
-      QMessageBox::critical(NULL, "Mantid - Error",
+      QMessageBox::critical(nullptr, "Mantid - Error",
                             "Error column was not found.");
       return boost::shared_ptr<Mantid::API::Workspace>();
     }
@@ -2890,7 +2917,7 @@ FitPropertyBrowser::createMatrixFromTableWorkspace() const {
 
     return mws;
   } catch (std::exception &e) {
-    QMessageBox::critical(NULL, "Mantid - Error", e.what());
+    QMessageBox::critical(nullptr, "Mantid - Error", e.what());
     return boost::shared_ptr<Mantid::API::Workspace>();
   }
 }
@@ -2946,7 +2973,7 @@ void FitPropertyBrowser::minimizerChanged() {
   auto &properties = minzer->getProperties();
   for (auto it = properties.begin(); it != properties.end(); ++it) {
     QString propName = QString::fromStdString((**it).name());
-    QtProperty *prop = NULL;
+    QtProperty *prop = nullptr;
     if (auto prp =
             dynamic_cast<Mantid::Kernel::PropertyWithValue<bool> *>(*it)) {
       prop = m_boolManager->addProperty(propName);
diff --git a/MantidQt/MantidWidgets/src/FormulaDialogEditor.cpp b/MantidQt/MantidWidgets/src/FormulaDialogEditor.cpp
index 253787cd1a23547c671b1f7849875f39dc289608..b35535076cbed264ae02905ebbfb3b5b66c10b9b 100644
--- a/MantidQt/MantidWidgets/src/FormulaDialogEditor.cpp
+++ b/MantidQt/MantidWidgets/src/FormulaDialogEditor.cpp
@@ -1,7 +1,6 @@
 #include "MantidQtMantidWidgets/FormulaDialogEditor.h"
 #include "MantidQtMantidWidgets/UserFunctionDialog.h"
 
-#include <QFileDialog>
 #include <QSettings>
 
 namespace MantidQt {
diff --git a/MantidQt/MantidWidgets/src/FunctionBrowser.cpp b/MantidQt/MantidWidgets/src/FunctionBrowser.cpp
index 549e42b145966af368d7086d8b74eb8496757959..f4d523be29d3dae76e2497473db785c7606ae802 100644
--- a/MantidQt/MantidWidgets/src/FunctionBrowser.cpp
+++ b/MantidQt/MantidWidgets/src/FunctionBrowser.cpp
@@ -37,6 +37,7 @@
 #include <QMetaMethod>
 #include <QTreeWidget>
 
+#include <boost/lexical_cast.hpp>
 #include <algorithm>
 
 namespace {
diff --git a/MantidQt/MantidWidgets/src/InstrumentView/InstrumentActor.cpp b/MantidQt/MantidWidgets/src/InstrumentView/InstrumentActor.cpp
index 7824ad8d701be064879232d01bc4478d04a020c1..5f325aa7118f15aee09f388e3543459f4fb38ef0 100644
--- a/MantidQt/MantidWidgets/src/InstrumentView/InstrumentActor.cpp
+++ b/MantidQt/MantidWidgets/src/InstrumentView/InstrumentActor.cpp
@@ -16,6 +16,7 @@
 #include "MantidAPI/IAlgorithm.h"
 #include "MantidAPI/IMaskWorkspace.h"
 #include "MantidAPI/MatrixWorkspace.h"
+#include "MantidAPI/SpectrumInfo.h"
 #include "MantidAPI/WorkspaceFactory.h"
 
 #include "MantidGeometry/Objects/Object.h"
@@ -281,7 +282,7 @@ IMaskWorkspace_sptr InstrumentActor::getMaskWorkspaceIfExists() const {
 * Apply mask stored in the helper mask workspace to the data workspace.
 */
 void InstrumentActor::applyMaskWorkspace() {
-  auto wsName = getWorkspace()->name();
+  auto wsName = getWorkspace()->getName();
   if (m_maskWorkspace) {
     // Mask detectors
     try {
@@ -634,8 +635,8 @@ void InstrumentActor::resetColors() {
   m_colors.resize(m_specIntegrs.size());
 
   auto sharedWorkspace = getWorkspace();
+  const auto &spectrumInfo = sharedWorkspace->spectrumInfo();
 
-  Instrument_const_sptr inst = getInstrument();
   IMaskWorkspace_sptr mask = getMaskWorkspaceIfExists();
 
   for (int iwi = 0; iwi < int(m_specIntegrs.size()); iwi++) {
@@ -649,7 +650,7 @@ void InstrumentActor::resetColors() {
       if (mask) {
         masked = mask->isMasked(dets);
       } else {
-        masked = inst->isDetectorMasked(dets);
+        masked = spectrumInfo.hasDetectors(wi) && spectrumInfo.isMasked(wi);
       }
 
       if (masked) {
@@ -867,7 +868,7 @@ Mantid::API::MatrixWorkspace_sptr InstrumentActor::extractCurrentMask() const {
   Mantid::API::IAlgorithm *alg =
       Mantid::API::FrameworkManager::Instance().createAlgorithm("ExtractMask",
                                                                 -1);
-  alg->setPropertyValue("InputWorkspace", getWorkspace()->name());
+  alg->setPropertyValue("InputWorkspace", getWorkspace()->getName());
   alg->setPropertyValue("OutputWorkspace", maskName);
   alg->execute();
 
diff --git a/MantidQt/MantidWidgets/src/InstrumentView/InstrumentWidget.cpp b/MantidQt/MantidWidgets/src/InstrumentView/InstrumentWidget.cpp
index aef9bea4e6f2dfff6267cde040cc2571741ac060..95dad948c853297da64ceecfcd4a0d205c62bd67 100644
--- a/MantidQt/MantidWidgets/src/InstrumentView/InstrumentWidget.cpp
+++ b/MantidQt/MantidWidgets/src/InstrumentView/InstrumentWidget.cpp
@@ -9,6 +9,7 @@
 #include "MantidQtMantidWidgets/InstrumentView/InstrumentWidgetTreeTab.h"
 
 #include "MantidAPI/Axis.h"
+#include "MantidAPI/IMaskWorkspace.h"
 #include "MantidAPI/IPeaksWorkspace.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/Workspace.h"
@@ -51,8 +52,6 @@
 #include <QVBoxLayout>
 #include <QWidget>
 
-#include "MantidQtAPI/FileDialogHandler.h"
-
 #include <numeric>
 #include <stdexcept>
 
@@ -205,6 +204,30 @@ void InstrumentWidget::renameWorkspace(const std::string &workspace) {
   m_workspaceName = QString::fromStdString(workspace);
 }
 
+/**
+ * Get the axis vector for the surface projection type.
+ * @param surfaceType :: Surface type for this projection
+ * @return a V3D for the axis being projected on
+ */
+Mantid::Kernel::V3D
+InstrumentWidget::getSurfaceAxis(const int surfaceType) const {
+  Mantid::Kernel::V3D axis;
+
+  // define the axis
+  if (surfaceType == SPHERICAL_Y || surfaceType == CYLINDRICAL_Y) {
+    axis = Mantid::Kernel::V3D(0, 1, 0);
+  } else if (surfaceType == SPHERICAL_Z || surfaceType == CYLINDRICAL_Z) {
+    axis = Mantid::Kernel::V3D(0, 0, 1);
+  } else if (surfaceType == SPHERICAL_X || surfaceType == CYLINDRICAL_X) {
+    axis = Mantid::Kernel::V3D(1, 0, 0);
+  } else // SIDE_BY_SIDE
+  {
+    axis = Mantid::Kernel::V3D(0, 0, 1);
+  }
+
+  return axis;
+}
+
 /**
 * Init the geometry and colour map outside constructor to prevent creating a
 * broken MdiSubwindow.
@@ -317,8 +340,8 @@ InstrumentWidgetTab *InstrumentWidget::getTab(const Tab tab) const {
 QString InstrumentWidget::getSaveFileName(const QString &title,
                                           const QString &filters,
                                           QString *selectedFilter) {
-  QString filename = MantidQt::API::FileDialogHandler::getSaveFileName(
-      this, title, m_savedialog_dir, filters, selectedFilter);
+  QString filename = QFileDialog::getSaveFileName(this, title, m_savedialog_dir,
+                                                  filters, selectedFilter);
 
   // If its empty, they cancelled the dialog
   if (!filename.isEmpty()) {
@@ -382,18 +405,7 @@ void InstrumentWidget::setSurfaceType(int type) {
         throw InstrumentHasNoSampleError();
       }
       Mantid::Kernel::V3D sample_pos = sample->getPos();
-      Mantid::Kernel::V3D axis;
-      // define the axis
-      if (surfaceType == SPHERICAL_Y || surfaceType == CYLINDRICAL_Y) {
-        axis = Mantid::Kernel::V3D(0, 1, 0);
-      } else if (surfaceType == SPHERICAL_Z || surfaceType == CYLINDRICAL_Z) {
-        axis = Mantid::Kernel::V3D(0, 0, 1);
-      } else if (surfaceType == SPHERICAL_X || surfaceType == CYLINDRICAL_X) {
-        axis = Mantid::Kernel::V3D(1, 0, 0);
-      } else // SIDE_BY_SIDE
-      {
-        axis = Mantid::Kernel::V3D(0, 0, 1);
-      }
+      auto axis = getSurfaceAxis(surfaceType);
 
       // create the surface
       if (surfaceType == FULL3D) {
@@ -676,9 +688,9 @@ void InstrumentWidget::saveImage(QString filename) {
 * Use the file dialog to select a filename to save grouping.
 */
 QString InstrumentWidget::getSaveGroupingFilename() {
-  QString filename = MantidQt::API::FileDialogHandler::getSaveFileName(
-      this, "Save grouping file", m_savedialog_dir,
-      "Grouping (*.xml);;All files (*)");
+  QString filename =
+      QFileDialog::getSaveFileName(this, "Save grouping file", m_savedialog_dir,
+                                   "Grouping (*.xml);;All files (*)");
 
   // If its empty, they cancelled the dialog
   if (!filename.isEmpty()) {
@@ -936,39 +948,30 @@ void InstrumentWidget::setColorMapAutoscaling(bool on) {
 */
 bool InstrumentWidget::overlay(const QString &wsName) {
   using namespace Mantid::API;
-  Workspace_sptr workspace;
-  bool success(false);
-  try {
-    workspace = AnalysisDataService::Instance().retrieve(wsName.toStdString());
-  } catch (std::runtime_error) {
-    QMessageBox::warning(this, "MantidPlot - Warning",
-                         "No workspace called '" + wsName + "' found. ");
-    return success;
-  }
+
+  auto workspace = getWorkspaceFromADS(wsName.toStdString());
 
   auto pws = boost::dynamic_pointer_cast<IPeaksWorkspace>(workspace);
-  if (!pws) {
+  auto table = boost::dynamic_pointer_cast<ITableWorkspace>(workspace);
+  auto mask = boost::dynamic_pointer_cast<IMaskWorkspace>(workspace);
+
+  if (!pws && !table && !mask) {
     QMessageBox::warning(this, "MantidPlot - Warning",
                          "Work space called '" + wsName +
                              "' is not suitable."
                              " Please select another workspace. ");
-    return success;
+    return false;
   }
 
-  auto surface = boost::dynamic_pointer_cast<UnwrappedSurface>(getSurface());
-  if (!surface) {
-    QMessageBox::warning(
-        this, "MantidPlot - Warning",
-        "Please change to an unwrapped view to see peak labels.");
-    return success;
+  if (pws) {
+    overlayPeaksWorkspace(pws);
+  } else if (table) {
+    overlayShapesWorkspace(table);
+  } else if (mask) {
+    overlayMaskedWorkspace(mask);
   }
 
-  if (pws && surface) {
-    surface->setPeaksWorkspace(pws);
-    updateInstrumentView();
-    success = true;
-  }
-  return success;
+  return true;
 }
 
 /**
@@ -1282,6 +1285,76 @@ void InstrumentWidget::clearADSHandle() {
   close();
 }
 
+/**
+ * Overlay a peaks workspace on the surface projection
+ * @param ws :: peaks workspace to overlay
+ */
+void InstrumentWidget::overlayPeaksWorkspace(IPeaksWorkspace_sptr ws) {
+  auto surface = getUnwrappedSurface();
+  surface->setPeaksWorkspace(ws);
+  updateInstrumentView();
+}
+
+/**
+ * Overlay a mask workspace on the surface projection
+ * @param ws :: mask workspace to overlay
+ */
+void InstrumentWidget::overlayMaskedWorkspace(IMaskWorkspace_sptr ws) {
+  auto actor = getInstrumentActor();
+  actor->setMaskMatrixWorkspace(
+      boost::dynamic_pointer_cast<Mantid::API::MatrixWorkspace>(ws));
+  actor->updateColors();
+  updateInstrumentDetectors();
+  emit maskedWorkspaceOverlayed();
+}
+
+/**
+ * Overlay a table workspace containing shape parameters
+ * @param ws :: a workspace of shape parameters to create
+ */
+void InstrumentWidget::overlayShapesWorkspace(ITableWorkspace_sptr ws) {
+  auto surface = getUnwrappedSurface();
+  if (surface) {
+    surface->loadShapesFromTableWorkspace(ws);
+    updateInstrumentView();
+  }
+}
+
+/**
+ * Get a workspace from the ADS using its name
+ * @param name :: name of the workspace
+ * @return a handle to the workspace (null if not found)
+ */
+Workspace_sptr InstrumentWidget::getWorkspaceFromADS(const std::string &name) {
+  Workspace_sptr workspace;
+
+  try {
+    workspace = AnalysisDataService::Instance().retrieve(name);
+  } catch (std::runtime_error) {
+    QMessageBox::warning(this, "MantidPlot - Warning",
+                         "No workspace called '" +
+                             QString::fromStdString(name) + "' found. ");
+    return nullptr;
+  }
+
+  return workspace;
+}
+
+/**
+ * Get an unwrapped surface
+ * @return a handle to the unwrapped surface (or null if view was not found).
+ */
+boost::shared_ptr<UnwrappedSurface> InstrumentWidget::getUnwrappedSurface() {
+  auto surface = boost::dynamic_pointer_cast<UnwrappedSurface>(getSurface());
+  if (!surface) {
+    QMessageBox::warning(
+        this, "MantidPlot - Warning",
+        "Please change to an unwrapped view to overlay a workspace.");
+    return nullptr;
+  }
+  return surface;
+}
+
 int InstrumentWidget::getCurrentTab() const {
   return mControlsTab->currentIndex();
 }
diff --git a/MantidQt/MantidWidgets/src/InstrumentView/InstrumentWidgetMaskTab.cpp b/MantidQt/MantidWidgets/src/InstrumentView/InstrumentWidgetMaskTab.cpp
index e78ba4deb84688dc8aa2cbdb972c0b92eb28f4f9..bc0ad4bb5263d191adf8737cfce1997746634210 100644
--- a/MantidQt/MantidWidgets/src/InstrumentView/InstrumentWidgetMaskTab.cpp
+++ b/MantidQt/MantidWidgets/src/InstrumentView/InstrumentWidgetMaskTab.cpp
@@ -39,7 +39,6 @@
 #include <QAction>
 #include <QApplication>
 #include <QCheckBox>
-#include <QFileDialog>
 #include <QGridLayout>
 #include <QGroupBox>
 #include <QHBoxLayout>
@@ -201,6 +200,12 @@ InstrumentWidgetMaskTab::InstrumentWidgetMaskTab(InstrumentWidget *instrWidget)
   m_applyToView->setToolTip("Apply current mask to the view.");
   connect(m_applyToView, SIGNAL(clicked()), this, SLOT(applyMaskToView()));
 
+  m_saveShapesToTable = new QPushButton("Save Shapes to Table");
+  m_saveShapesToTable->setToolTip(
+      "Store the current Mask/ROI/Group shapes as a table");
+  connect(m_saveShapesToTable, SIGNAL(clicked()), this,
+          SLOT(saveShapesToTable()));
+
   m_clearAll = new QPushButton("Clear All");
   m_clearAll->setToolTip(
       "Clear all masking that have not been applied to the data.");
@@ -314,8 +319,9 @@ InstrumentWidgetMaskTab::InstrumentWidgetMaskTab(InstrumentWidget *instrWidget)
   QGroupBox *box = new QGroupBox("View");
   QGridLayout *buttons = new QGridLayout();
   buttons->addWidget(m_applyToView, 0, 0, 1, 2);
-  buttons->addWidget(m_saveButton, 1, 0);
-  buttons->addWidget(m_clearAll, 1, 1);
+  buttons->addWidget(m_saveShapesToTable, 1, 0, 1, 2);
+  buttons->addWidget(m_saveButton, 2, 0);
+  buttons->addWidget(m_clearAll, 2, 1);
 
   box->setLayout(buttons);
   layout->addWidget(box);
@@ -325,6 +331,9 @@ InstrumentWidgetMaskTab::InstrumentWidgetMaskTab(InstrumentWidget *instrWidget)
   buttons->addWidget(m_applyToData, 0, 0);
   box->setLayout(buttons);
   layout->addWidget(box);
+
+  connect(m_instrWidget, SIGNAL(maskedWorkspaceOverlayed()), this,
+          SLOT(enableApplyButtons()));
 }
 
 /**
@@ -579,6 +588,13 @@ void InstrumentWidgetMaskTab::setProperties() {
   shapeChanged();
 }
 
+/**
+ * Save shapes to a table workspace
+ */
+void InstrumentWidgetMaskTab::saveShapesToTable() const {
+  m_instrWidget->getSurface()->saveShapesToTableWorkspace();
+}
+
 void InstrumentWidgetMaskTab::doubleChanged(QtProperty *prop) {
   if (!m_userEditing)
     return;
@@ -859,7 +875,7 @@ void InstrumentWidgetMaskTab::saveMaskingToFile(bool invertMask) {
       alg->setPropertyValue("OutputFile", fileName.toStdString());
       alg->execute();
     }
-    Mantid::API::AnalysisDataService::Instance().remove(outputWS->name());
+    Mantid::API::AnalysisDataService::Instance().remove(outputWS->getName());
   }
   enableApplyButtons();
   QApplication::restoreOverrideCursor();
@@ -887,12 +903,12 @@ void InstrumentWidgetMaskTab::saveMaskingToCalFile(bool invertMask) {
       Mantid::API::IAlgorithm_sptr alg =
           Mantid::API::AlgorithmManager::Instance().create(
               "MaskWorkspaceToCalFile", -1);
-      alg->setPropertyValue("InputWorkspace", outputWS->name());
+      alg->setPropertyValue("InputWorkspace", outputWS->getName());
       alg->setPropertyValue("OutputFile", fileName.toStdString());
       alg->setProperty("Invert", false);
       alg->execute();
     }
-    Mantid::API::AnalysisDataService::Instance().remove(outputWS->name());
+    Mantid::API::AnalysisDataService::Instance().remove(outputWS->getName());
   }
   enableApplyButtons();
   QApplication::restoreOverrideCursor();
@@ -1046,6 +1062,7 @@ void InstrumentWidgetMaskTab::enableApplyButtons() {
     m_applyToData->setEnabled(false);
     m_applyToView->setEnabled(false);
   }
+  m_saveShapesToTable->setEnabled(hasMaskShapes);
   m_saveButton->setEnabled(hasDetectorMask && (!enableBinMasking));
   m_clearAll->setEnabled(hasMask);
   setActivity();
@@ -1269,7 +1286,7 @@ InstrumentWidgetMaskTab::loadMask(const std::string &fileName) {
   auto workspace = actor->getWorkspace();
   auto instrument = workspace->getInstrument();
   auto instrumentName = instrument->getName();
-  auto tempName = "__" + workspace->name() + "MaskView";
+  auto tempName = "__" + workspace->getName() + "MaskView";
 
   // load the mask from the project folder
   try {
diff --git a/MantidQt/MantidWidgets/src/InstrumentView/InstrumentWidgetPickTab.cpp b/MantidQt/MantidWidgets/src/InstrumentView/InstrumentWidgetPickTab.cpp
index 01b289330a7df10789d1b209996366c336f55d3e..b31c6fc84d1282ff6fdfc9ce2fba8a9a85446f30 100644
--- a/MantidQt/MantidWidgets/src/InstrumentView/InstrumentWidgetPickTab.cpp
+++ b/MantidQt/MantidWidgets/src/InstrumentView/InstrumentWidgetPickTab.cpp
@@ -544,12 +544,12 @@ void InstrumentWidgetPickTab::initSurface() {
   connect(surface, SIGNAL(singleComponentPicked(size_t)), this,
           SLOT(singleComponentPicked(size_t)));
   connect(
-      surface,
-      SIGNAL(comparePeaks(
-          std::pair<Mantid::Geometry::IPeak *, Mantid::Geometry::IPeak *>)),
-      this,
-      SLOT(comparePeaks(
-          std::pair<Mantid::Geometry::IPeak *, Mantid::Geometry::IPeak *>)));
+      surface, SIGNAL(comparePeaks(
+                   const std::pair<std::vector<Mantid::Geometry::IPeak *>,
+                                   std::vector<Mantid::Geometry::IPeak *>> &)),
+      this, SLOT(comparePeaks(
+                const std::pair<std::vector<Mantid::Geometry::IPeak *>,
+                                std::vector<Mantid::Geometry::IPeak *>> &)));
   connect(surface, SIGNAL(peaksWorkspaceAdded()), this,
           SLOT(updateSelectionInfoDisplay()));
   connect(surface, SIGNAL(peaksWorkspaceDeleted()), this,
@@ -584,6 +584,10 @@ InstrumentWidgetPickTab::getSurface() const {
   return m_instrWidget->getSurface();
 }
 
+const InstrumentWidget *InstrumentWidgetPickTab::getInstrumentWidget() const {
+  return m_instrWidget;
+}
+
 /**
 * Save tab's persistent settings to the provided QSettings instance
 */
@@ -677,8 +681,9 @@ void InstrumentWidgetPickTab::singleComponentPicked(size_t pickID) {
   m_plotController->updatePlot();
 }
 
-void InstrumentWidgetPickTab::comparePeaks(const std::pair<
-    Mantid::Geometry::IPeak *, Mantid::Geometry::IPeak *> &peaks) {
+void InstrumentWidgetPickTab::comparePeaks(
+    const std::pair<std::vector<Mantid::Geometry::IPeak *>,
+                    std::vector<Mantid::Geometry::IPeak *>> &peaks) {
   m_infoController->displayComparePeaksInfo(peaks);
 }
 
@@ -921,42 +926,43 @@ ComponentInfoController::displayPeakInfo(Mantid::Geometry::IPeak *peak) {
   return QString::fromStdString(text.str());
 }
 
-QString ComponentInfoController::displayPeakAngles(
-    std::pair<Mantid::Geometry::IPeak *, Mantid::Geometry::IPeak *> peaks) {
+QString ComponentInfoController::displayPeakAngles(const std::pair<
+    Mantid::Geometry::IPeak *, Mantid::Geometry::IPeak *> &peaks) {
   std::stringstream text;
   auto peak1 = peaks.first;
   auto peak2 = peaks.second;
 
-  auto pos1 = peak1->getDetector()->getPos();
-  auto pos2 = peak2->getDetector()->getPos();
-
-  auto angle = pos1.angle(pos2) * double_constants::radian;
-  auto distance = pos1 - pos2;
-  auto dirAngles = distance.directionAngles();
+  auto pos1 = peak1->getQSampleFrame();
+  auto pos2 = peak2->getQSampleFrame();
+  auto angle = pos1.angle(pos2);
+  angle *= double_constants::radian;
 
-  text << "Angle between: " << angle << "\n";
-  text << "Direction angles: ";
-  text << " a: " << dirAngles[0];
-  text << " b: " << dirAngles[1];
-  text << " c: " << dirAngles[2];
-  text << "\n";
+  text << "Angle: " << angle << "\n";
 
   return QString::fromStdString(text.str());
 }
 
 void ComponentInfoController::displayComparePeaksInfo(
-    std::pair<Mantid::Geometry::IPeak *, Mantid::Geometry::IPeak *> peaks) {
+    const std::pair<std::vector<Mantid::Geometry::IPeak *>,
+                    std::vector<Mantid::Geometry::IPeak *>> &peaks) {
   std::stringstream text;
-  auto peak1 = peaks.first;
-  auto peak2 = peaks.second;
 
-  text << "First Peak \n";
-  text << displayPeakInfo(peak1).toStdString();
+  text << "Comparison Information\n";
+  auto peaksFromDetectors =
+      std::make_pair(peaks.first.front(), peaks.second.front());
+  text << displayPeakAngles(peaksFromDetectors).toStdString();
+
   text << "-------------------------------\n";
-  text << "Second Peak \n";
-  text << displayPeakInfo(peak2).toStdString();
+  text << "First Detector Peaks \n";
+  for (auto peak : peaks.first)
+    text << displayPeakInfo(peak).toStdString();
+
   text << "-------------------------------\n";
-  text << displayPeakAngles(peaks).toStdString();
+  text << "Second Detector Peaks \n";
+  for (auto peak : peaks.second)
+    text << displayPeakInfo(peak).toStdString();
+
+  text << "\n";
 
   m_selectionInfoDisplay->setText(QString::fromStdString(text.str()));
 }
@@ -1584,7 +1590,7 @@ void DetectorPlotController::savePlotToWorkspace() {
     alg->setProperty("DataE", E);
     alg->setProperty("NSpec", static_cast<int>(X.size() / nbins));
     alg->setProperty("UnitX", unitX);
-    alg->setPropertyValue("ParentWorkspace", parentWorkspace->name());
+    alg->setPropertyValue("ParentWorkspace", parentWorkspace->getName());
     alg->execute();
 
     if (!detids.empty()) {
@@ -1697,7 +1703,7 @@ void DetectorPlotController::addPeak(double x, double y) {
     std::string peakTableName;
     bool newPeaksWorkspace = false;
     if (tw) {
-      peakTableName = tw->name();
+      peakTableName = tw->getName();
     } else {
       peakTableName = "SingleCrystalPeakTable";
       // This does need to get the instrument from the workspace as it's doing
@@ -1735,7 +1741,7 @@ void DetectorPlotController::addPeak(double x, double y) {
     // Run the AddPeak algorithm
     auto alg =
         Mantid::API::FrameworkManager::Instance().createAlgorithm("AddPeak");
-    alg->setPropertyValue("RunWorkspace", ws->name());
+    alg->setPropertyValue("RunWorkspace", ws->getName());
     alg->setPropertyValue("PeaksWorkspace", peakTableName);
     alg->setProperty("DetectorID", m_currentDetID);
     alg->setProperty("TOF", x);
diff --git a/MantidQt/MantidWidgets/src/InstrumentView/InstrumentWidgetRenderTab.cpp b/MantidQt/MantidWidgets/src/InstrumentView/InstrumentWidgetRenderTab.cpp
index bac87256e2ef321ea30d470e2d73b6a50d5c6f6f..02d89b5281a1d4f5f4d885ee279d02390fb8c0f2 100644
--- a/MantidQt/MantidWidgets/src/InstrumentView/InstrumentWidgetRenderTab.cpp
+++ b/MantidQt/MantidWidgets/src/InstrumentView/InstrumentWidgetRenderTab.cpp
@@ -12,7 +12,6 @@
 #include <QLabel>
 #include <QComboBox>
 #include <QCheckBox>
-#include <QFileDialog>
 #include <QFileInfo>
 #include <QSettings>
 #include <QAction>
diff --git a/MantidQt/MantidWidgets/src/InstrumentView/PanelsSurface.cpp b/MantidQt/MantidWidgets/src/InstrumentView/PanelsSurface.cpp
index 32bd39b561a4a3a99c5f7f2dd40d08bc1e93c42c..2bc9a8f9eb61b223616e581c03d4815592dfbc7c 100644
--- a/MantidQt/MantidWidgets/src/InstrumentView/PanelsSurface.cpp
+++ b/MantidQt/MantidWidgets/src/InstrumentView/PanelsSurface.cpp
@@ -5,6 +5,8 @@
 #include "MantidQtMantidWidgets/InstrumentView/RectangularDetectorActor.h"
 #include "MantidQtMantidWidgets/InstrumentView/StructuredDetectorActor.h"
 
+#include "MantidAPI/DetectorInfo.h"
+#include "MantidAPI/MatrixWorkspace.h"
 #include "MantidGeometry/Instrument/ObjCompAssembly.h"
 #include "MantidKernel/Logger.h"
 #include "MantidKernel/Tolerance.h"
@@ -426,6 +428,7 @@ void PanelsSurface::addCompAssembly(ComponentID bankId) {
   Mantid::Kernel::V3D pos0;
   bool normalFound = false;
   QList<ComponentID> detectors;
+  const auto &detectorInfo = m_instrActor->getWorkspace()->detectorInfo();
   for (size_t i = 0; i < nelem; ++i) {
     auto elem = assembly->getChild((int)i);
     Mantid::Geometry::IDetector_const_sptr det =
@@ -433,9 +436,10 @@ void PanelsSurface::addCompAssembly(ComponentID bankId) {
     if (!det) {
       return;
     }
-    if (det->isMonitor())
+    size_t detIndex = detectorInfo.indexOf(det->getID());
+    if (detectorInfo.isMonitor(detIndex))
       continue;
-    Mantid::Kernel::V3D pos = det->getPos();
+    Mantid::Kernel::V3D pos = detectorInfo.position(detIndex);
     if (i == 0) {
       pos0 = pos;
     } else if (i == 1) {
diff --git a/MantidQt/MantidWidgets/src/InstrumentView/PeakOverlay.cpp b/MantidQt/MantidWidgets/src/InstrumentView/PeakOverlay.cpp
index 87ecc5fe7790aaac35ef64888c8c71d4558867e7..c4d55cc971e6fc120533af1968dc5e6da7f5ba64 100644
--- a/MantidQt/MantidWidgets/src/InstrumentView/PeakOverlay.cpp
+++ b/MantidQt/MantidWidgets/src/InstrumentView/PeakOverlay.cpp
@@ -205,7 +205,7 @@ void PeakOverlay::removeShapes(const QList<Shape2D *> &shapeList) {
   // Run the DeleteTableRows algorithm to delete the peak.
   auto alg =
       Mantid::API::AlgorithmManager::Instance().create("DeleteTableRows", -1);
-  alg->setPropertyValue("TableWorkspace", m_peaksWorkspace->name());
+  alg->setPropertyValue("TableWorkspace", m_peaksWorkspace->getName());
   alg->setProperty("Rows", rows);
   emit executeAlgorithm(alg);
 }
diff --git a/MantidQt/MantidWidgets/src/InstrumentView/ProjectionSurface.cpp b/MantidQt/MantidWidgets/src/InstrumentView/ProjectionSurface.cpp
index 99f4d7b8e58f784cb2db13a6a189e83408c9d419..b38d004e2ff72b6f17b90fc7f202d9eaa1e48f50 100644
--- a/MantidQt/MantidWidgets/src/InstrumentView/ProjectionSurface.cpp
+++ b/MantidQt/MantidWidgets/src/InstrumentView/ProjectionSurface.cpp
@@ -316,11 +316,15 @@ void ProjectionSurface::updateView(bool picking) {
 }
 
 void ProjectionSurface::updateDetectors() {
+  // updating detectors should not reset the view rect
+  // cache the value here are reapply after updating the detectors
+  auto viewRectCache = m_viewRect;
   clear();
   this->init();
   // if integration range in the instrument actor has changed
   // update visiblity of peak markers
   setPeakVisibility();
+  m_viewRect = viewRectCache;
 }
 
 /// Send a redraw request to the surface owner
@@ -515,21 +519,54 @@ void ProjectionSurface::setPeakVisibility() const {
   }
 }
 
+/** Check a peak is visible at the given point
+ *
+ * Will return true if any peak in any overlay was found to be positioned at
+ * the given point.
+ *
+ * @param point :: the point to check for peaks
+ * @return true if any peaks was found at the given point
+ */
+bool ProjectionSurface::peakVisibleAtPoint(const QPointF &point) const {
+  bool visible = false;
+  for (const auto po : m_peakShapes) {
+    po->selectAtXY(point);
+    auto markers = po->getSelectedPeakMarkers();
+    visible =
+        std::any_of(markers.begin(), markers.end(),
+                    [](PeakMarker2D *marker) { return marker->isVisible(); });
+
+    if (visible)
+      return true;
+  }
+
+  return false;
+}
+
 /**
  * Draw a line between peak markers being compared
  * @param painter :: The QPainter object to draw the line with
  */
 void ProjectionSurface::drawPeakComparisonLine(QPainter &painter) const {
-  if (!m_selectedMarkers.first.isNull() && !m_selectedMarkers.second.isNull()) {
-    QTransform transform;
-    auto windowRect = getSurfaceBounds();
-    windowRect.findTransform(transform, painter.viewport());
-    auto p1 = transform.map(m_selectedMarkers.first);
-    auto p2 = transform.map(m_selectedMarkers.second);
+  const auto &firstOrigin = m_selectedMarkers.first;
+  const auto &secondOrigin = m_selectedMarkers.second;
 
-    painter.setPen(Qt::red);
-    painter.drawLine(p1, p2);
-  }
+  // Check is user has selected enough peaks
+  if (firstOrigin.isNull() || secondOrigin.isNull())
+    return;
+
+  // Check if the integration range is such that some peaks are visible
+  if (!peakVisibleAtPoint(firstOrigin) || !peakVisibleAtPoint(secondOrigin))
+    return;
+
+  // Draw line between peaks
+  QTransform transform;
+  auto windowRect = getSurfaceBounds();
+  windowRect.findTransform(transform, painter.viewport());
+  auto p1 = transform.map(firstOrigin);
+  auto p2 = transform.map(secondOrigin);
+  painter.setPen(Qt::red);
+  painter.drawLine(p1, p2);
 }
 
 /**
@@ -593,6 +630,22 @@ void ProjectionSurface::startCreatingFreeShape(const QColor &borderColor,
   emit signalToStartCreatingFreeShape(borderColor, fillColor);
 }
 
+/**
+ * Save shapes drawn on the view to a table workspace
+ */
+void ProjectionSurface::saveShapesToTableWorkspace() {
+  m_maskShapes.saveToTableWorkspace();
+}
+
+/**
+ * Load shapes from a table workspace on to the view.
+ * @param ws :: table workspace to load shapes from
+ */
+void ProjectionSurface::loadShapesFromTableWorkspace(
+    Mantid::API::ITableWorkspace_const_sptr ws) {
+  m_maskShapes.loadFromTableWorkspace(ws);
+}
+
 /**
 * Return a combined list of peak parkers from all overlays
 * @param detID :: The detector ID of interest
@@ -647,6 +700,10 @@ void ProjectionSurface::clearPeakOverlays() {
     m_peakShapesStyle = 0;
     emit peaksWorkspaceDeleted();
   }
+  m_selectedPeaks.first.clear();
+  m_selectedPeaks.second.clear();
+  m_selectedMarkers.first = QPointF();
+  m_selectedMarkers.second = QPointF();
 }
 
 /**
@@ -738,47 +795,67 @@ void ProjectionSurface::touchComponentAt(int x, int y) {
 void ProjectionSurface::erasePeaks(const QRect &rect) {
   foreach (PeakOverlay *po, m_peakShapes) {
     po->selectIn(rect);
+    auto peakMarkers = po->getSelectedPeakMarkers();
+
+    // clear selected peak markers
+    for (const auto &marker : peakMarkers) {
+      auto peak = po->getPeaksWorkspace()->getPeakPtr(marker->getRow());
+      if (m_selectedPeaks.first.front() == peak ||
+          m_selectedPeaks.second.front() == peak) {
+        m_selectedPeaks.first.clear();
+        m_selectedPeaks.second.clear();
+        m_selectedMarkers.first = QPointF();
+        m_selectedMarkers.second = QPointF();
+      }
+    }
+
     po->removeSelectedShapes();
   }
 }
 
 void ProjectionSurface::comparePeaks(const QRect &rect) {
   // Find the selected peak across all of the peak overlays.
-  // If more than one peak was found in the selection area just
-  // take the first peak.
-  PeakMarker2D *marker = nullptr;
-  Mantid::Geometry::IPeak *peak = nullptr;
   QPointF origin;
-  foreach (PeakOverlay *po, m_peakShapes) {
+  std::vector<Mantid::Geometry::IPeak *> peaks;
+  for (auto *po : m_peakShapes) {
     po->selectIn(rect);
     const auto markers = po->getSelectedPeakMarkers();
-    if (markers.length() > 0) {
-      marker = markers.first();
-      origin = marker->origin();
-      peak = po->getPeaksWorkspace()->getPeakPtr(marker->getRow());
-      break;
+
+    // make the assumption that the first peak found in the recticle is the one
+    // we wanted.
+    if (markers.length() > 0 && origin.isNull()) {
+      origin = markers.first()->origin();
+    }
+
+    for (const auto &marker : markers) {
+      // only collect peaks in the same detector & with the same origin
+      if (marker->origin() == origin) {
+        auto peak = po->getPeaksWorkspace()->getPeakPtr(marker->getRow());
+        peaks.push_back(peak);
+      }
     }
   }
 
-  if (!m_selectedPeaks.first) {
+  if (m_selectedPeaks.first.empty()) {
     // No peaks have been selected yet
-    m_selectedPeaks.first = peak;
+    m_selectedPeaks.first = peaks;
     m_selectedMarkers.first = origin;
-  } else if (!m_selectedPeaks.second) {
+  } else if (m_selectedPeaks.second.empty()) {
     // Two peaks have now been selected
-    m_selectedPeaks.second = peak;
+    m_selectedPeaks.second = peaks;
     m_selectedMarkers.second = origin;
-  } else if (m_selectedPeaks.first && m_selectedPeaks.second) {
+  } else if (!m_selectedPeaks.first.empty() &&
+             !m_selectedPeaks.second.empty()) {
     // Two peaks have already been selected. Clear the pair and store
     // the new peak as the first entry
-    m_selectedPeaks.first = peak;
+    m_selectedPeaks.first = peaks;
     m_selectedMarkers.first = origin;
-    m_selectedPeaks.second = nullptr;
+    m_selectedPeaks.second.clear();
     m_selectedMarkers.second = QPointF();
   }
 
   // Only emit the signal to update when we have two peaks
-  if (m_selectedPeaks.first && m_selectedPeaks.second) {
+  if (!m_selectedPeaks.first.empty() && !m_selectedPeaks.second.empty()) {
     emit comparePeaks(m_selectedPeaks);
   }
 }
@@ -795,7 +872,7 @@ void ProjectionSurface::enableLighting(bool on) { m_isLightingOn = on; }
 QStringList ProjectionSurface::getPeaksWorkspaceNames() const {
   QStringList names;
   foreach (PeakOverlay *po, m_peakShapes) {
-    names << QString::fromStdString(po->getPeaksWorkspace()->name());
+    names << QString::fromStdString(po->getPeaksWorkspace()->getName());
   }
   return names;
 }
diff --git a/MantidQt/MantidWidgets/src/InstrumentView/RotationSurface.cpp b/MantidQt/MantidWidgets/src/InstrumentView/RotationSurface.cpp
index 3efd92014dfb5a5a8fabf494fe699b9a3789bec6..65b053cb448e923448c40e046a63fb98f019597a 100644
--- a/MantidQt/MantidWidgets/src/InstrumentView/RotationSurface.cpp
+++ b/MantidQt/MantidWidgets/src/InstrumentView/RotationSurface.cpp
@@ -1,5 +1,7 @@
 #include "MantidQtMantidWidgets/InstrumentView/RotationSurface.h"
 #include "MantidKernel/Logger.h"
+#include "MantidAPI/DetectorInfo.h"
+#include "MantidAPI/MatrixWorkspace.h"
 
 #include <QCursor>
 #include <QMessageBox>
@@ -76,6 +78,8 @@ void RotationSurface::init() {
   m_u_min = -DBL_MAX;
   m_u_max = DBL_MAX;
 
+  const auto &detectorInfo = m_instrActor->getWorkspace()->detectorInfo();
+
   // Set if one of the threads in the following loop
   // throws an exception
   bool exceptionThrown = false;
@@ -99,7 +103,10 @@ void RotationSurface::init() {
                                   Mantid::Kernel::Exception::NotFoundError &) {
                               }
 
-                              if (!det || det->isMonitor() || (id < 0)) {
+                              if (!det ||
+                                  detectorInfo.isMonitor(
+                                      detectorInfo.indexOf(id)) ||
+                                  (id < 0)) {
                                 // Not a detector or a monitor
                                 // Make some blank, empty thing that won't draw
                                 m_unwrappedDetectors[i] = UnwrappedDetector();
diff --git a/MantidQt/MantidWidgets/src/InstrumentView/Shape2DCollection.cpp b/MantidQt/MantidWidgets/src/InstrumentView/Shape2DCollection.cpp
index e9240f8787d1accc77a95a276b3adf059e83ff27..ce8b5b96df60219b2542be28b44b1e9297f4b2e0 100644
--- a/MantidQt/MantidWidgets/src/InstrumentView/Shape2DCollection.cpp
+++ b/MantidQt/MantidWidgets/src/InstrumentView/Shape2DCollection.cpp
@@ -1,4 +1,8 @@
 #include "MantidQtMantidWidgets/InstrumentView/Shape2DCollection.h"
+#include "MantidAPI/AnalysisDataService.h"
+#include "MantidAPI/ITableWorkspace.h"
+#include "MantidAPI/TableRow.h"
+#include "MantidAPI/WorkspaceFactory.h"
 
 #include <QPainter>
 #include <QMouseEvent>
@@ -300,13 +304,20 @@ void Shape2DCollection::touchShapeOrControlPointAt(int x, int y) {
 * Select a shape which contains a point (x,y) of the screen.
 */
 bool Shape2DCollection::selectAtXY(int x, int y, bool edit) {
+  const auto point = m_transform.inverted().map(QPointF(x, y));
+  return selectAtXY(point, edit);
+}
+
+/**
+* Select a shape which contains a point (x, y) of the world.
+*/
+bool Shape2DCollection::selectAtXY(const QPointF &point, bool edit) {
   if (edit) {
     // if shape has to be edited (resized) it must be the only selection
     deselectAll();
   }
-  QPointF p = m_transform.inverted().map(QPointF(x, y));
   foreach (Shape2D *shape, m_shapes) {
-    bool picked = shape->selectAt(p);
+    bool picked = shape->selectAt(point);
     if (picked) {
       addToSelection(shape);
       return true;
@@ -621,6 +632,56 @@ void Shape2DCollection::changeBorderColor(const QColor &color) {
   foreach (Shape2D *shape, m_shapes) { shape->setColor(color); }
 }
 
+/**
+ * Save this shape collection to a table workspace
+ *
+ * This will create a table workspace called MaskShapes with one column for the
+ * index of the shape and one containing the serialised parameters of the shape
+ */
+void Shape2DCollection::saveToTableWorkspace() {
+  using namespace Mantid::API;
+  auto table = WorkspaceFactory::Instance().createTable();
+  table->addColumn("str", "Index");
+  table->addColumn("str", "Parameters");
+
+  size_t count = 0;
+  for (auto shape : m_shapes) {
+    auto shapeStr = shape->saveToProject();
+    TableRow row = table->appendRow();
+    row << std::to_string(count) << shapeStr;
+    ++count;
+  }
+
+  AnalysisDataService::Instance().addOrReplace("MaskShapes", table);
+}
+
+/**
+ * Load a collection of shapes from a table workspace
+ *
+ * This expects a table workspace with a column called parameters from which to
+ * load collection of shapes from.
+ *
+ * @param ws :: table workspace to load shapes from.
+ */
+void Shape2DCollection::loadFromTableWorkspace(
+    Mantid::API::ITableWorkspace_const_sptr ws) {
+  using namespace Mantid::API;
+  auto columnNames = ws->getColumnNames();
+
+  // Check if the column exists
+  if (std::find(columnNames.cbegin(), columnNames.cend(), "Parameters") ==
+      columnNames.cend())
+    return;
+
+  ConstColumnVector<std::string> col = ws->getVector("Parameters");
+  for (size_t i = 0; i < ws->rowCount(); ++i) {
+    const auto params = col[i];
+    auto shape = Shape2D::loadFromProject(params);
+    m_shapes.append(shape);
+  }
+  emit shapeCreated();
+}
+
 /**
 * Add a Shape2D object allowing free drawing.
 * @param poly :: Initial shape.
@@ -672,7 +733,8 @@ void Shape2DCollection::loadFromProject(const std::string &lines) {
   API::TSVSerialiser tsv(lines);
   for (auto shapeLines : tsv.sections("shape")) {
     Shape2D *shape = Shape2D::loadFromProject(shapeLines);
-    addShape(shape, false);
+    m_shapes.push_back(shape);
+    emit shapeCreated();
   }
 }
 
diff --git a/MantidQt/MantidWidgets/src/InstrumentView/UnwrappedSurface.cpp b/MantidQt/MantidWidgets/src/InstrumentView/UnwrappedSurface.cpp
index 930732bec1e34e61f486de23a3e0a4747133c534..342c685e426ad04d452cde037c896cd33ba137e0 100644
--- a/MantidQt/MantidWidgets/src/InstrumentView/UnwrappedSurface.cpp
+++ b/MantidQt/MantidWidgets/src/InstrumentView/UnwrappedSurface.cpp
@@ -781,7 +781,7 @@ std::string UnwrappedSurface::saveToProject() const {
 
   tsv.writeLine("PeaksWorkspaces");
   for (auto overlay : m_peakShapes) {
-    tsv << overlay->getPeaksWorkspace()->name();
+    tsv << overlay->getPeaksWorkspace()->getName();
   }
 
   return tsv.outputLines();
diff --git a/MantidQt/MantidWidgets/src/MWDiag.cpp b/MantidQt/MantidWidgets/src/MWDiag.cpp
index bc6867f12cb989ac9cdb25828204bd7c4c1452df..346a19a16e7789f55b90f1ee45de918fb808924b 100644
--- a/MantidQt/MantidWidgets/src/MWDiag.cpp
+++ b/MantidQt/MantidWidgets/src/MWDiag.cpp
@@ -1,8 +1,7 @@
 #include "MantidQtMantidWidgets/MWDiag.h"
 #include "MantidQtMantidWidgets/DiagResults.h"
-#include "MantidQtMantidWidgets/MWRunFiles.h"
+#include "MantidQtAPI/MWRunFiles.h"
 #include "MantidQtAPI/AlgorithmInputHistory.h"
-#include "MantidQtAPI/FileDialogHandler.h"
 #include "MantidAPI/FrameworkManager.h"
 #include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/MatrixWorkspace.h"
@@ -492,7 +491,7 @@ QString MWDiag::openFileDialog(const bool save, const QStringList &exts) {
 
   QString filename;
   if (save) {
-    filename = FileDialogHandler::getSaveFileName(
+    filename = QFileDialog::getSaveFileName(
         this, "Save file", m_prevSets.value("save file dir", "").toString(),
         filter);
     if (!filename.isEmpty()) {
diff --git a/MantidQt/MantidWidgets/src/MantidTreeWidget.cpp b/MantidQt/MantidWidgets/src/MantidTreeWidget.cpp
index 9235dcb6a134ef47a3d326c88020076fb71f4643..3cf6cd9acaf41f703e59465d40174db4cc830a13 100644
--- a/MantidQt/MantidWidgets/src/MantidTreeWidget.cpp
+++ b/MantidQt/MantidWidgets/src/MantidTreeWidget.cpp
@@ -234,7 +234,8 @@ MantidWSIndexWidget::UserInput MantidTreeWidget::chooseSpectrumFromSelected(
   auto selectedMatrixWsList = getSelectedMatrixWorkspaces();
   QList<QString> selectedMatrixWsNameList;
   foreach (const auto matrixWs, selectedMatrixWsList) {
-    selectedMatrixWsNameList.append(QString::fromStdString(matrixWs->name()));
+    selectedMatrixWsNameList.append(
+        QString::fromStdString(matrixWs->getName()));
   }
 
   // Check to see if all workspaces have only a single spectrum ...
@@ -251,7 +252,7 @@ MantidWSIndexWidget::UserInput MantidTreeWidget::chooseSpectrumFromSelected(
     const std::set<int> SINGLE_SPECTRUM = {0};
     QMultiMap<QString, std::set<int>> spectrumToPlot;
     foreach (const auto selectedMatrixWs, selectedMatrixWsList) {
-      spectrumToPlot.insert(QString::fromStdString(selectedMatrixWs->name()),
+      spectrumToPlot.insert(QString::fromStdString(selectedMatrixWs->getName()),
                             SINGLE_SPECTRUM);
     }
     MantidWSIndexWidget::UserInput selections;
@@ -282,7 +283,8 @@ MantidTreeWidget::choosePlotOptions(const QString &type,
   auto selectedMatrixWsList = getSelectedMatrixWorkspaces();
   QList<QString> selectedMatrixWsNameList;
   foreach (const auto matrixWs, selectedMatrixWsList) {
-    selectedMatrixWsNameList.append(QString::fromStdString(matrixWs->name()));
+    selectedMatrixWsNameList.append(
+        QString::fromStdString(matrixWs->getName()));
   }
   auto *dlg =
       m_mantidUI->createSurfacePlotDialog(0, selectedMatrixWsNameList, type);
diff --git a/MantidQt/MantidWidgets/src/MantidTreeWidgetItem.cpp b/MantidQt/MantidWidgets/src/MantidTreeWidgetItem.cpp
index eed5ee7694e3f0f25a8f75263acd06e986e33218..3febd4801807e6f68728b8703c7b0f9267cf90c3 100644
--- a/MantidQt/MantidWidgets/src/MantidTreeWidgetItem.cpp
+++ b/MantidQt/MantidWidgets/src/MantidTreeWidgetItem.cpp
@@ -2,6 +2,7 @@
 #include "MantidQtMantidWidgets/MantidTreeWidget.h"
 
 #include <MantidAPI/Workspace.h>
+#include "MantidAPI/WorkspaceHistory.h"
 
 using namespace Mantid::Kernel;
 using namespace Mantid::API;
diff --git a/MantidQt/MantidWidgets/src/MantidWSIndexDialog.cpp b/MantidQt/MantidWidgets/src/MantidWSIndexDialog.cpp
index 03f7883d3fa109d5d25c265d37a265b4ab05a476..773488d66b4a99b78c679031a8ca1e428a111070 100644
--- a/MantidQt/MantidWidgets/src/MantidWSIndexDialog.cpp
+++ b/MantidQt/MantidWidgets/src/MantidWSIndexDialog.cpp
@@ -1,7 +1,5 @@
-//----------------------------------
-// Includes
-//----------------------------------
 #include "MantidQtMantidWidgets/MantidWSIndexDialog.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Axis.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/SpectraDetectorTypes.h"
@@ -24,8 +22,8 @@ namespace MantidWidgets {
  * @param parent :: The owning dialog
  * @param flags :: Window flags that are passed the the QWidget constructor
  * @param wsNames :: the names of the workspaces to be plotted
- * @param showWaterfallOption :: If true the waterfall checkbox is created
- * @param showTiledOption :: If true the "Tiled" checkbox is created
+ * @param showWaterfallOption :: true if waterfall plot enabled
+ * @param showTiledOption :: true if tiled plot enabled
  */
 MantidWSIndexWidget::MantidWSIndexWidget(QWidget *parent, Qt::WFlags flags,
                                          QList<QString> wsNames,
@@ -33,9 +31,8 @@ MantidWSIndexWidget::MantidWSIndexWidget(QWidget *parent, Qt::WFlags flags,
                                          const bool showTiledOption)
     : QWidget(parent, flags), m_spectra(false),
       m_waterfall(showWaterfallOption), m_tiled(showTiledOption),
-      m_waterfallOpt(nullptr), m_tiledOpt(nullptr), m_wsNames(wsNames),
-      m_wsIndexIntervals(), m_spectraNumIntervals(), m_wsIndexChoice(),
-      m_spectraIdChoice() {
+      m_plotOptions(), m_wsNames(wsNames), m_wsIndexIntervals(),
+      m_spectraNumIntervals(), m_wsIndexChoice(), m_spectraIdChoice() {
   checkForSpectraAxes();
   // Generate the intervals allowed to be plotted by the user.
   generateWsIndexIntervals();
@@ -110,7 +107,7 @@ QMultiMap<QString, std::set<int>> MantidWSIndexWidget::getPlots() const {
  * @returns True if waterfall plot selected
  */
 bool MantidWSIndexWidget::isWaterfallPlotSelected() const {
-  return m_waterfallOpt ? m_waterfallOpt->isChecked() : false;
+  return (m_plotOptions->currentText() == "Waterfall Plot");
 }
 
 /**
@@ -118,7 +115,7 @@ bool MantidWSIndexWidget::isWaterfallPlotSelected() const {
  * @returns True if tiled plot selected
  */
 bool MantidWSIndexWidget::isTiledPlotSelected() const {
-  return m_tiledOpt ? m_tiledOpt->isChecked() : false;
+  return (m_plotOptions->currentText() == "Tiled Plot");
 }
 
 /**
@@ -245,14 +242,17 @@ void MantidWSIndexWidget::initSpectraBox() {
  */
 void MantidWSIndexWidget::initOptionsBoxes() {
   m_optionsBox = new QHBoxLayout;
-  if (m_waterfall) {
-    m_waterfallOpt = new QCheckBox("Waterfall Plot");
-    m_optionsBox->addWidget(m_waterfallOpt);
-  }
 
-  if (m_tiled) {
-    m_tiledOpt = new QCheckBox("Tiled Plot");
-    m_optionsBox->addWidget(m_tiledOpt);
+  if (m_waterfall || m_tiled) {
+    m_plotOptions = new QComboBox();
+    m_plotOptions->addItem(tr("1D Plot"));
+    if (m_waterfall) {
+      m_plotOptions->addItem(tr("Waterfall Plot"));
+    }
+    if (m_tiled) {
+      m_plotOptions->addItem(tr("Tiled Plot"));
+    }
+    m_optionsBox->addWidget(m_plotOptions);
   }
 
   m_outer->addItem(m_optionsBox);
diff --git a/MantidQt/MantidWidgets/src/MuonFitDataSelector.cpp b/MantidQt/MantidWidgets/src/MuonFitDataSelector.cpp
index 4d709e45a8eeb4219df919e976fe8029b320029f..a19f8ec1a6b8738313ae3c00f71c2e0b39003950 100644
--- a/MantidQt/MantidWidgets/src/MuonFitDataSelector.cpp
+++ b/MantidQt/MantidWidgets/src/MuonFitDataSelector.cpp
@@ -26,7 +26,7 @@ MuonFitDataSelector::MuonFitDataSelector(QWidget *parent)
   // Disable "Browse" button - use case is that first run will always be the one
   // selected on front tab. User will type in the runs they want rather than
   // using the Browse button. (If they want to "Browse" they can use front tab).
-  m_ui.runs->doButtonOpt(MWRunFiles::ButtonOpts::None);
+  m_ui.runs->doButtonOpt(API::MWRunFiles::ButtonOpts::None);
 }
 
 /**
@@ -55,8 +55,6 @@ void MuonFitDataSelector::setUpConnections() {
   connect(m_ui.runs, SIGNAL(filesFound()), this, SLOT(userChangedRuns()));
   connect(m_ui.rbCoAdd, SIGNAL(toggled(bool)), this,
           SLOT(fitTypeChanged(bool)));
-  connect(m_ui.txtWSIndex, SIGNAL(editingFinished()), this,
-          SIGNAL(dataPropertiesChanged()));
   connect(m_ui.txtStart, SIGNAL(editingFinished()), this,
           SIGNAL(dataPropertiesChanged()));
   connect(m_ui.txtEnd, SIGNAL(editingFinished()), this,
@@ -132,26 +130,6 @@ void MuonFitDataSelector::setAvailableGroups(const QStringList &groups) {
   }
 }
 
-/**
- * Get the user's supplied workspace index (default 0)
- * Returns an unsigned int so it can be put into a QVariant
- * @returns :: Workspace index input by user
- */
-unsigned int MuonFitDataSelector::getWorkspaceIndex() const {
-  // Validator ensures this can be cast to a positive integer
-  const QString index = m_ui.txtWSIndex->text();
-  return index.toUInt();
-}
-
-/**
- * Set the workspace index in the UI
- * @param index :: [input] Workspace index to set
- */
-void MuonFitDataSelector::setWorkspaceIndex(unsigned int index) {
-  m_ui.txtWSIndex->setText(QString::number(index));
-  emit dataPropertiesChanged();
-}
-
 /**
  * Get the user's supplied start time (default 0)
  * @returns :: start time input by user in microseconds
@@ -219,8 +197,6 @@ QStringList MuonFitDataSelector::getFilenames() const {
  * e.g. some boxes should only accept numeric input
  */
 void MuonFitDataSelector::setUpValidators() {
-  // WS index: non-negative integers only
-  m_ui.txtWSIndex->setValidator(new QIntValidator(0, 1000, this));
   // Start/end times: numeric values only
   m_ui.txtStart->setValidator(new QDoubleValidator(this));
   m_ui.txtEnd->setValidator(new QDoubleValidator(this));
@@ -258,7 +234,6 @@ void MuonFitDataSelector::setWorkspaceDetails(const QString &runNumbers,
 void MuonFitDataSelector::setDefaultValues() {
   m_ui.lblStart->setText(QString("Start (%1s)").arg(QChar(0x03BC)));
   m_ui.lblEnd->setText(QString("End (%1s)").arg(QChar(0x03BC)));
-  this->setWorkspaceIndex(0);
   this->setStartTime(0.0);
   this->setEndTime(0.0);
   setPeriodCombination(false);
@@ -475,7 +450,6 @@ void MuonFitDataSelector::setChosenPeriod(const QString &period) {
 QVariant MuonFitDataSelector::getUserInput() const {
   QVariant ret(QVariant::Map);
   auto map = ret.toMap();
-  map.insert("Workspace index", getWorkspaceIndex());
   map.insert("Start", getStartTime());
   map.insert("End", getEndTime());
   map.insert("Runs", getRuns());
@@ -499,9 +473,6 @@ QVariant MuonFitDataSelector::getUserInput() const {
 void MuonFitDataSelector::setUserInput(const QVariant &value) {
   if (value.canConvert(QVariant::Map)) {
     const auto map = value.toMap();
-    if (map.contains("Workspace index")) {
-      setWorkspaceIndex(map.value("Workspace index").toUInt());
-    }
     if (map.contains("Start")) {
       setStartTime(map.value("Start").toDouble());
     }
diff --git a/MantidQt/MantidWidgets/src/MuonFitPropertyBrowser.cpp b/MantidQt/MantidWidgets/src/MuonFitPropertyBrowser.cpp
index 2e13796c66c23f06451205bac19087201a6875c8..b84ca5fb4e21a80321ea0da2d00496bae05eac05 100644
--- a/MantidQt/MantidWidgets/src/MuonFitPropertyBrowser.cpp
+++ b/MantidQt/MantidWidgets/src/MuonFitPropertyBrowser.cpp
@@ -4,6 +4,7 @@
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/ITableWorkspace.h"
 #include "MantidAPI/TableRow.h"
+#include "MantidAPI/WorkspaceGroup.h"
 #include "MantidQtMantidWidgets/StringEditorFactory.h"
 
 // Suppress a warning coming out of code that isn't ours
@@ -61,8 +62,8 @@ const std::string MuonFitPropertyBrowser::SIMULTANEOUS_PREFIX{"MuonSimulFit_"};
 */
 MuonFitPropertyBrowser::MuonFitPropertyBrowser(QWidget *parent,
                                                QObject *mantidui)
-    : FitPropertyBrowser(parent, mantidui), m_additionalLayout(nullptr),
-      m_widgetSplitter(nullptr) {}
+    : FitPropertyBrowser(parent, mantidui), m_widgetSplitter(nullptr),
+      m_mainSplitter(nullptr) {}
 
 /**
 * Initialise the muon fit property browser.
@@ -156,20 +157,28 @@ void MuonFitPropertyBrowser::init() {
   // Initialise the layout.
   initLayout(w);
 
-  // Create an empty layout that can hold extra widgets
-  // and add it after the buttons but before the browser
-  m_additionalLayout = new QVBoxLayout();
+  // Create an empty splitter that can hold extra widgets
+  m_widgetSplitter = new QSplitter(Qt::Vertical, w);
+  m_widgetSplitter->setSizePolicy(QSizePolicy::Policy::Expanding,
+                                  QSizePolicy::Policy::Expanding);
+
+  // This splitter separates the "extra widgets" region from the browser
+  m_mainSplitter = new QSplitter(Qt::Vertical, w);
+  m_mainSplitter->insertWidget(0, m_widgetSplitter);
+  m_mainSplitter->insertWidget(1, m_browser);
+  m_mainSplitter->setStretchFactor(0, 1);
+  m_mainSplitter->setStretchFactor(1, 0);
+
+  // Insert after the buttons
   auto parentLayout = qobject_cast<QVBoxLayout *>(w->layout());
   if (parentLayout) {
-    const int index = parentLayout->count() - 2;
+    const int index = parentLayout->count() - 1;
     constexpr int stretchFactor = 10; // so these widgets get any extra space
-    parentLayout->insertLayout(index, m_additionalLayout, stretchFactor);
+    parentLayout->insertWidget(index, m_mainSplitter, stretchFactor);
+    parentLayout->setSpacing(0);
+    parentLayout->setMargin(0);
+    parentLayout->setContentsMargins(0, 0, 0, 0);
   }
-  m_widgetSplitter = new QSplitter(w);
-  m_widgetSplitter->setOrientation(Qt::Vertical);
-  m_widgetSplitter->setSizePolicy(QSizePolicy::Policy::Expanding,
-                                  QSizePolicy::Policy::Expanding);
-  m_additionalLayout->addWidget(m_widgetSplitter);
 }
 
 /**
@@ -396,7 +405,7 @@ void MuonFitPropertyBrowser::showEvent(QShowEvent *e) {
   * @param ws :: The workspace
   */
 bool MuonFitPropertyBrowser::isWorkspaceValid(Workspace_sptr ws) const {
-  QString workspaceName(QString::fromStdString(ws->name()));
+  QString workspaceName(QString::fromStdString(ws->getName()));
 
   if ((workspaceName.contains("_Raw")) ||
       (workspaceName.contains("MuonAnalysis")))
@@ -503,7 +512,7 @@ void MuonFitPropertyBrowser::finishAfterSimultaneousFit(
 void MuonFitPropertyBrowser::addExtraWidget(QWidget *widget) {
   widget->setSizePolicy(QSizePolicy::Policy::Expanding,
                         QSizePolicy::Policy::Expanding);
-  if (m_additionalLayout && m_widgetSplitter) {
+  if (m_widgetSplitter) {
     m_widgetSplitter->addWidget(widget);
   }
 }
@@ -566,12 +575,26 @@ void MuonFitPropertyBrowser::setMultiFittingMode(bool enabled) {
   m_browser->setItemVisible(m_settingsGroup, !enabled);
 
   // Show or hide additional widgets
-  for (int i = 0; i < m_additionalLayout->count(); ++i) {
-    if (auto *widget = m_additionalLayout->itemAt(i)->widget()) {
+  for (int i = 0; i < m_widgetSplitter->count(); ++i) {
+    if (auto *widget = m_widgetSplitter->widget(i)) {
       widget->setVisible(enabled);
     }
   }
 }
 
+/**
+ * Returns whether or not a guess is plotted
+ * @returns :: True if a plot guess is plotted, false if not.
+ */
+bool MuonFitPropertyBrowser::hasGuess() const {
+  auto *handler = getHandler();
+  if (handler) {
+    const bool hasPlot = handler->hasPlot(); // don't allow caller to modify
+    return hasPlot;
+  } else {
+    return false;
+  }
+}
+
 } // MantidQt
 } // API
diff --git a/MantidQt/MantidWidgets/src/ProcessingAlgoWidget.cpp b/MantidQt/MantidWidgets/src/ProcessingAlgoWidget.cpp
index f7b08ce64b7621d3bb0432b0026ad3ebac7e76f6..b6b356851b6aa264b658d7baad5771112b395fa4 100644
--- a/MantidQt/MantidWidgets/src/ProcessingAlgoWidget.cpp
+++ b/MantidQt/MantidWidgets/src/ProcessingAlgoWidget.cpp
@@ -2,7 +2,6 @@
 #include <Qsci/qscilexerpython.h>
 #include "MantidAPI/Algorithm.h"
 #include "MantidAPI/AlgorithmManager.h"
-#include "MantidQtAPI/FileDialogHandler.h"
 #include <iosfwd>
 #include <fstream>
 #include <QFileInfo>
@@ -75,7 +74,7 @@ void ProcessingAlgoWidget::saveSettings() {
 /** Slot called when the save button is clicked */
 void ProcessingAlgoWidget::btnSaveClicked() {
   // Save to a .py file
-  QString fileselection = MantidQt::API::FileDialogHandler::getSaveFileName(
+  QString fileselection = QFileDialog::getSaveFileName(
       this, "Save a Python Script", QFileInfo(m_lastFile).absoluteFilePath(),
       "Python scripts (*.py);;All files (*)");
   if (!fileselection.isEmpty()) {
diff --git a/MantidQt/MantidWidgets/src/ProjectSaveModel.cpp b/MantidQt/MantidWidgets/src/ProjectSaveModel.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d08b23d296a2fbc1e9b883f79172e3b7cc5f9a1b
--- /dev/null
+++ b/MantidQt/MantidWidgets/src/ProjectSaveModel.cpp
@@ -0,0 +1,185 @@
+#include "MantidQtMantidWidgets/ProjectSaveModel.h"
+#include "MantidAPI/AnalysisDataService.h"
+#include "MantidAPI/Workspace.h"
+#include "MantidAPI/WorkspaceGroup.h"
+#include "MantidQtAPI/WindowIcons.h"
+#include "MantidQtAPI/WorkspaceIcons.h"
+
+#include <unordered_set>
+
+using namespace Mantid::API;
+using namespace MantidQt::API;
+using namespace MantidQt::MantidWidgets;
+
+/**
+ * Construct a new model with a list of window handles
+ * @param windows :: vector of handles to windows open in Mantid
+ */
+ProjectSaveModel::ProjectSaveModel(
+    std::vector<IProjectSerialisable *> windows) {
+  auto workspaces = getWorkspaces();
+  for (auto &ws : workspaces) {
+    std::pair<std::string, std::vector<IProjectSerialisable *>> item(
+        ws->getName(), std::vector<IProjectSerialisable *>());
+    m_workspaceWindows.insert(item);
+  }
+
+  for (auto window : windows) {
+    auto wsNames = window->getWorkspaceNames();
+    for (auto &name : wsNames) {
+      m_workspaceWindows[name].push_back(window);
+    }
+  }
+}
+
+/**
+ * Get windows which are associated with a given workspace name
+ * @param wsName :: the name of the workspace to get window for
+ * @return vector of window handles for the workspace
+ */
+std::vector<IProjectSerialisable *>
+ProjectSaveModel::getWindows(const std::string &wsName) const {
+  if (hasWindows(wsName)) {
+    return m_workspaceWindows.at(wsName);
+  }
+
+  return std::vector<IProjectSerialisable *>();
+}
+
+/**
+ * Get unique windows for a list of workspace names
+ * @param wsNames :: vector of workspace names to get associated windows for
+ * @return an ordered vector of unique window handles sorted by window name
+ */
+std::vector<IProjectSerialisable *> ProjectSaveModel::getUniqueWindows(
+    const std::vector<std::string> &wsNames) const {
+  std::unordered_set<IProjectSerialisable *> uniqueWindows;
+
+  for (auto &name : wsNames) {
+    for (auto window : getWindows(name)) {
+      uniqueWindows.insert(window);
+    }
+  }
+
+  std::vector<IProjectSerialisable *> windows(uniqueWindows.cbegin(),
+                                              uniqueWindows.cend());
+  std::sort(windows.begin(), windows.end(),
+            [](IProjectSerialisable *lhs, IProjectSerialisable *rhs) {
+              return lhs->getWindowName() < rhs->getWindowName();
+            });
+
+  return windows;
+}
+
+/**
+ * Get all unique window names for a list of workspaces
+ *
+ * @param wsNames :: vector of workspace names to get associated window names
+ * for
+ * @return an ordered vector of unique window names sorted alphabetically
+ */
+std::vector<std::string> ProjectSaveModel::getWindowNames(
+    const std::vector<std::string> &wsNames) const {
+  std::vector<std::string> names;
+  auto windows = getUniqueWindows(wsNames);
+  for (auto window : windows) {
+    names.push_back(window->getWindowName());
+  }
+  return names;
+}
+
+/**
+ * Get all workspace names in the model
+ * @return vector of all workspace names in the model
+ */
+std::vector<std::string> ProjectSaveModel::getWorkspaceNames() const {
+  std::vector<std::string> names;
+  for (auto &item : m_workspaceWindows) {
+    names.push_back(item.first);
+  }
+
+  std::sort(names.begin(), names.end());
+  return names;
+}
+
+/**
+ * Get window information for a selection of workspaces
+ * @param wsNames :: vector of workspace names to find associated windows for
+ * @return vector of window info objects associated with the workpaces
+ */
+std::vector<WindowInfo> ProjectSaveModel::getWindowInformation(
+    const std::vector<std::string> &wsNames) const {
+  std::vector<WindowInfo> winInfo;
+  WindowIcons icons;
+
+  for (auto window : getUniqueWindows(wsNames)) {
+    WindowInfo info;
+    info.name = window->getWindowName();
+    info.type = window->getWindowType();
+    info.icon_id = icons.getIconID(window->getWindowType());
+    winInfo.push_back(info);
+  }
+
+  return winInfo;
+}
+
+/**
+ * Get workspace information for all workspaces
+ * @return vector of workspace info objects for all workspaces
+ */
+std::vector<WorkspaceInfo> ProjectSaveModel::getWorkspaceInformation() const {
+  std::vector<WorkspaceInfo> wsInfo;
+
+  auto items = AnalysisDataService::Instance().topLevelItems();
+  for (auto item : items) {
+    auto ws = item.second;
+    auto info = makeWorkspaceInfoObject(ws);
+
+    if (ws->id() == "WorkspaceGroup") {
+      auto group = boost::dynamic_pointer_cast<WorkspaceGroup>(ws);
+      for (int i = 0; i < group->getNumberOfEntries(); ++i) {
+        auto subInfo = makeWorkspaceInfoObject(group->getItem(i));
+        info.subWorkspaces.push_back(subInfo);
+      }
+    }
+
+    wsInfo.push_back(info);
+  }
+
+  return wsInfo;
+}
+
+/**
+ * Get all workspaces from the ADS
+ * @return vector of workspace handles from the ADS
+ */
+std::vector<Workspace_sptr> ProjectSaveModel::getWorkspaces() const {
+  auto &ads = AnalysisDataService::Instance();
+  return ads.getObjects();
+}
+
+WorkspaceInfo
+ProjectSaveModel::makeWorkspaceInfoObject(Workspace_const_sptr ws) const {
+  WorkspaceIcons icons;
+  WorkspaceInfo info;
+  info.name = ws->getName();
+  info.numWindows = getWindows(ws->getName()).size();
+  info.size = ws->getMemorySizeAsStr();
+  info.icon_id = icons.getIconID(ws->id());
+  info.type = ws->id();
+  return info;
+}
+
+/**
+ * Check is a workspace has any windows associated with it
+ * @param wsName :: the name of workspace
+ * @return whether the workspace has > 0 windows associated with it
+ */
+bool ProjectSaveModel::hasWindows(const std::string &wsName) const {
+  auto item = m_workspaceWindows.find(wsName);
+  if (item != m_workspaceWindows.end()) {
+    return item->second.size() > 0;
+  }
+
+  return false;
+}
diff --git a/MantidQt/MantidWidgets/src/ProjectSavePresenter.cpp b/MantidQt/MantidWidgets/src/ProjectSavePresenter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f698a399ef29e7c96409561b09876e7dd1c3de88
--- /dev/null
+++ b/MantidQt/MantidWidgets/src/ProjectSavePresenter.cpp
@@ -0,0 +1,96 @@
+#include "MantidQtMantidWidgets/ProjectSavePresenter.h"
+#include "MantidAPI/AnalysisDataService.h"
+#include "MantidAPI/Workspace.h"
+
+#include <QDir>
+#include <QFileInfo>
+
+#include <algorithm>
+#include <iterator>
+#include <vector>
+
+using namespace MantidQt::MantidWidgets;
+using namespace Mantid::API;
+
+/**
+ * Construct a new presenter with the given view
+ * @param view :: a handle to a view for this presenter
+ */
+ProjectSavePresenter::ProjectSavePresenter(IProjectSaveView *view)
+    : m_view(view), m_model(m_view->getWindows()) {
+  auto workspaceNames = m_model.getWorkspaceNames();
+  auto info = m_model.getWorkspaceInformation();
+  auto winInfo = m_model.getWindowInformation(workspaceNames);
+  m_view->updateIncludedWindowsList(winInfo);
+  m_view->updateWorkspacesList(info);
+}
+
+/**
+ * Notify the presenter to perform an action
+ * @param notification :: notification to choose the action to perform
+ */
+void ProjectSavePresenter::notify(Notification notification) {
+  switch (notification) {
+  case Notification::CheckWorkspace:
+    includeWindowsForCheckedWorkspace();
+    break;
+  case Notification::UncheckWorkspace:
+    excludeWindowsForUncheckedWorkspace();
+    break;
+  case Notification::PrepareProjectFolder:
+    prepareProjectFolder();
+  }
+}
+
+/**
+ * Update the view with a new list of windows that are included in project
+ * saving based on the currently checked workspaces
+ */
+void ProjectSavePresenter::includeWindowsForCheckedWorkspace() {
+  auto wsNames = m_view->getCheckedWorkspaceNames();
+  auto names = m_model.getWindowNames(wsNames);
+  auto info = m_model.getWindowInformation(wsNames);
+  m_view->updateIncludedWindowsList(info);
+  m_view->removeFromExcludedWindowsList(names);
+}
+
+/**
+ * Update the view with a new list of windows that are excluded from project
+ * saving based on the currently checked workspaces
+ */
+void ProjectSavePresenter::excludeWindowsForUncheckedWorkspace() {
+  auto wsNames = m_view->getUncheckedWorkspaceNames();
+  auto names = m_model.getWindowNames(wsNames);
+  auto info = m_model.getWindowInformation(wsNames);
+  m_view->updateExcludedWindowsList(info);
+  m_view->removeFromIncludedWindowsList(names);
+}
+
+/**
+ * Prepare a project folder for serialistion
+ *
+ * This will check the file path and if necessary create a new project folder
+ */
+void ProjectSavePresenter::prepareProjectFolder() {
+  auto path = m_view->getProjectPath();
+
+  QFileInfo fileInfo(path);
+  bool isFile = fileInfo.filePath().endsWith(".mantid") ||
+                fileInfo.filePath().endsWith(".mantid.gz");
+
+  if (!isFile) {
+    QDir directory(path);
+    if (!directory.exists()) {
+      // Make the directory
+      directory.mkdir(path);
+    }
+
+    auto projectFileName = directory.dirName();
+    projectFileName.append(".mantid");
+    path = directory.absoluteFilePath(projectFileName);
+  } else {
+    path = fileInfo.absoluteFilePath();
+  }
+
+  m_view->setProjectPath(path);
+}
diff --git a/MantidQt/MantidWidgets/src/PropertyHandler.cpp b/MantidQt/MantidWidgets/src/PropertyHandler.cpp
index 370f86eec316334561034732e27eeb27282ce247..55f74879f2f003389e78f1d4e07cdc1ed9a20eae 100644
--- a/MantidQt/MantidWidgets/src/PropertyHandler.cpp
+++ b/MantidQt/MantidWidgets/src/PropertyHandler.cpp
@@ -136,8 +136,7 @@ public:
 protected:
   /// Create string property
   QtProperty *apply(const std::string &str) const override {
-    QtProperty *prop = NULL;
-    prop = m_browser->addStringProperty(m_name);
+    QtProperty *prop = m_browser->addStringProperty(m_name);
     m_browser->setStringPropertyValue(prop, QString::fromStdString(str));
     return prop;
   }
@@ -1016,12 +1015,10 @@ void PropertyHandler::addTie(const QString &tieStr) {
   std::string name = parts[0].trimmed().toStdString();
   std::string expr = parts[1].trimmed().toStdString();
   try {
-    Mantid::API::ParameterTie *tie =
-        m_browser->compositeFunction()->tie(name, expr);
-    if (tie == NULL)
-      return;
+    auto &cfun = *m_browser->compositeFunction();
+    cfun.tie(name, expr);
     QString parName = QString::fromStdString(
-        tie->getFunction()->parameterName(static_cast<int>(tie->getIndex())));
+        cfun.parameterLocalName(cfun.parameterIndex(name)));
     foreach (QtProperty *parProp, m_parameters) {
       if (parProp->propertyName() == parName) {
         m_browser->m_changeSlotsEnabled = false;
@@ -1319,10 +1316,10 @@ void PropertyHandler::addConstraint(QtProperty *parProp, bool lo, bool up,
 
   m_constraints.insert(parProp->propertyName(), cnew);
 
-  Mantid::API::IConstraint *c =
+  auto c = std::unique_ptr<Mantid::API::IConstraint>(
       Mantid::API::ConstraintFactory::Instance().createInitialized(m_fun.get(),
-                                                                   ostr.str());
-  m_fun->addConstraint(c);
+                                                                   ostr.str()));
+  m_fun->addConstraint(std::move(c));
   m_browser->m_changeSlotsEnabled = true;
 }
 
diff --git a/MantidQt/MantidWidgets/src/SaveWorkspaces.cpp b/MantidQt/MantidWidgets/src/SaveWorkspaces.cpp
index e0582c8b5fdf186f37fc6543e36a1f463532942e..cc154e6ab83949e117c63ff2ca290232e3075210 100644
--- a/MantidQt/MantidWidgets/src/SaveWorkspaces.cpp
+++ b/MantidQt/MantidWidgets/src/SaveWorkspaces.cpp
@@ -2,7 +2,6 @@
 // Includes
 //----------------------
 #include "MantidQtMantidWidgets/SaveWorkspaces.h"
-#include "MantidQtAPI/FileDialogHandler.h"
 #include "MantidAPI/AlgorithmManager.h"
 #include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/FileProperty.h"
@@ -11,16 +10,17 @@
 #include "MantidGeometry/Instrument.h"
 #include "MantidKernel/ConfigService.h"
 
-#include <QLabel>
-#include <QHBoxLayout>
-#include <QVBoxLayout>
-#include <QPushButton>
-#include <QDoubleValidator>
 #include <QCloseEvent>
-#include <QShowEvent>
+#include <QDoubleValidator>
+#include <QFileDialog>
 #include <QGroupBox>
-#include <QSettings>
+#include <QHBoxLayout>
+#include <QLabel>
 #include <QMessageBox>
+#include <QPushButton>
+#include <QSettings>
+#include <QShowEvent>
+#include <QVBoxLayout>
 
 namespace {
 void setDetectorNamesOnCanSasFormat(QString &saveCommands,
@@ -127,19 +127,16 @@ void SaveWorkspaces::setupLine2(
   QPushButton *cancel = new QPushButton("Cancel");
   connect(cancel, SIGNAL(clicked()), this, SLOT(close()));
 
-  QCheckBox *saveNex = new QCheckBox("Nexus");
-  QCheckBox *saveNXcanSAS = new QCheckBox("NxCanSAS");
   QCheckBox *saveNIST = new QCheckBox("NIST Qxy");
-  QCheckBox *saveCan = new QCheckBox("CanSAS");
   QCheckBox *saveRKH = new QCheckBox("RKH");
-  QCheckBox *saveCSV = new QCheckBox("CSV");
+  QCheckBox *saveNXcanSAS = new QCheckBox("NXcanSAS");
+  QCheckBox *saveCan = new QCheckBox("CanSAS");
+
   // link the save option tick boxes to their save algorithm
-  m_savFormats.insert(saveNex, "SaveNexus");
-  m_savFormats.insert(saveNXcanSAS, "SaveNXcanSAS");
   m_savFormats.insert(saveNIST, "SaveNISTDAT");
-  m_savFormats.insert(saveCan, "SaveCanSAS1D");
   m_savFormats.insert(saveRKH, "SaveRKH");
-  m_savFormats.insert(saveCSV, "SaveCSV");
+  m_savFormats.insert(saveNXcanSAS, "SaveNXcanSAS");
+  m_savFormats.insert(saveCan, "SaveCanSAS1D");
   setupFormatTicks(defSavs);
 
   m_append = new QCheckBox("Append");
@@ -153,12 +150,10 @@ void SaveWorkspaces::setupLine2(
   ly_saveConts->addStretch();
 
   QVBoxLayout *ly_saveFormats = new QVBoxLayout;
-  ly_saveFormats->addWidget(saveNex);
-  ly_saveFormats->addWidget(saveNXcanSAS);
   ly_saveFormats->addWidget(saveNIST);
-  ly_saveFormats->addWidget(saveCan);
   ly_saveFormats->addWidget(saveRKH);
-  ly_saveFormats->addWidget(saveCSV);
+  ly_saveFormats->addWidget(saveNXcanSAS);
+  ly_saveFormats->addWidget(saveCan);
   QGroupBox *gb_saveForms = new QGroupBox(tr("Save Formats"));
   gb_saveForms->setLayout(ly_saveFormats);
   ly_saveConts->addWidget(gb_saveForms);
@@ -172,12 +167,10 @@ void SaveWorkspaces::setupLine2(
   gb_saveForms->setToolTip(formatsTip);
   save->setToolTip(formatsTip);
   cancel->setToolTip(formatsTip);
-  saveNex->setToolTip(formatsTip);
   saveNXcanSAS->setToolTip(formatsTip);
   saveNIST->setToolTip(formatsTip);
   saveCan->setToolTip(formatsTip);
   saveRKH->setToolTip(formatsTip);
-  saveCSV->setToolTip(formatsTip);
   m_append->setToolTip(formatsTip);
 }
 /** Sets up some controls from what is in the QSettings
@@ -277,8 +270,7 @@ QString SaveWorkspaces::saveList(const QList<QListWidgetItem *> &wspaces,
       outFile += exten;
     }
     saveCommands += outFile + "'";
-    if (algorithm != "SaveCSV" && algorithm != "SaveNISTDAT" &&
-        algorithm != "SaveNXcanSAS") {
+    if (algorithm != "SaveNISTDAT" && algorithm != "SaveNXcanSAS") {
       saveCommands += ", Append=";
       saveCommands += toAppend ? "True" : "False";
     }
@@ -332,11 +324,6 @@ void SaveWorkspaces::saveSel() {
     if (i.key()->isChecked()) { // we need to save in this format
 
       bool toAppend = m_append->isChecked();
-      if (toAppend) { // SaveCSV doesn't support appending
-        if (i.value() == "SaveCSV") {
-          toAppend = false;
-        }
-      }
 
       try {
         saveCommands += saveList(m_workspaces->selectedItems(), i.value(),
@@ -387,8 +374,8 @@ void SaveWorkspaces::saveFileBrowse() {
   QFileDialog::Option userCon = m_append->isChecked()
                                     ? QFileDialog::DontConfirmOverwrite
                                     : static_cast<QFileDialog::Option>(0);
-  QString oFile = API::FileDialogHandler::getSaveFileName(
-      this, title, prevPath, filter, NULL, userCon);
+  QString oFile = QFileDialog::getSaveFileName(this, title, prevPath, filter,
+                                               NULL, userCon);
 
   if (!oFile.isEmpty()) {
     m_fNameEdit->setText(oFile);
diff --git a/MantidQt/MantidWidgets/src/ScriptEditor.cpp b/MantidQt/MantidWidgets/src/ScriptEditor.cpp
index 8b1abc4605119336449d7ae817dd3411022c9db2..2eabd6fcbabc29a9293750129b0c0bc1b6360068 100644
--- a/MantidQt/MantidWidgets/src/ScriptEditor.cpp
+++ b/MantidQt/MantidWidgets/src/ScriptEditor.cpp
@@ -3,12 +3,10 @@
 //-----------------------------------------------
 #include "MantidQtMantidWidgets/ScriptEditor.h"
 #include "MantidQtMantidWidgets/FindReplaceDialog.h"
-#include "MantidQtAPI/FileDialogHandler.h"
 
 // Qt
 #include <QApplication>
 #include <QFile>
-#include <QFileInfo>
 #include <QFileDialog>
 
 #include <QTextStream>
@@ -260,8 +258,8 @@ QSize ScriptEditor::sizeHint() const { return QSize(600, 500); }
 void ScriptEditor::saveAs() {
   QString selectedFilter;
   QString filter = "Scripts (*.py *.PY);;All Files (*)";
-  QString filename = MantidQt::API::FileDialogHandler::getSaveFileName(
-      NULL, "MantidPlot - Save", "", filter, &selectedFilter);
+  QString filename = QFileDialog::getSaveFileName(NULL, "MantidPlot - Save", "",
+                                                  filter, &selectedFilter);
 
   if (filename.isEmpty()) {
     throw SaveCancelledException();
diff --git a/MantidQt/MantidWidgets/src/SelectWorkspacesDialog.cpp b/MantidQt/MantidWidgets/src/SelectWorkspacesDialog.cpp
index 0674c3f23ed93886feb5f0e5332847b36efad709..b29e8617dcd76c75a2de35bbacb7b289cf6fe7b2 100644
--- a/MantidQt/MantidWidgets/src/SelectWorkspacesDialog.cpp
+++ b/MantidQt/MantidWidgets/src/SelectWorkspacesDialog.cpp
@@ -65,7 +65,7 @@ SelectWorkspacesDialog::SelectWorkspacesDialog(
   for (VecWorkspaces::const_iterator it = workspaces.begin();
        it != workspaces.end(); ++it) {
     // if(useFilter && ADS::
-    tmp << QString::fromStdString((*it)->name());
+    tmp << QString::fromStdString((*it)->getName());
   }
 
   m_wsList->addItems(tmp);
diff --git a/MantidQt/MantidWidgets/src/StringDialogEditor.cpp b/MantidQt/MantidWidgets/src/StringDialogEditor.cpp
index c9da15cc8c0a8ae5634104bc8c3c64574b8fa047..2254036b33141aee89a81565e5a422427feb98bf 100644
--- a/MantidQt/MantidWidgets/src/StringDialogEditor.cpp
+++ b/MantidQt/MantidWidgets/src/StringDialogEditor.cpp
@@ -3,7 +3,6 @@
 #include <QHBoxLayout>
 #include <QLineEdit>
 #include <QPushButton>
-#include <QFileDialog>
 #include <QLabel>
 #include <QDialog>
 #include <QSettings>
diff --git a/MantidQt/MantidWidgets/src/TrackedAction.cpp b/MantidQt/MantidWidgets/src/TrackedAction.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d94c3259e5cf0fc5cb329df7ae51c1d670b95b8e
--- /dev/null
+++ b/MantidQt/MantidWidgets/src/TrackedAction.cpp
@@ -0,0 +1,100 @@
+#include "MantidQtMantidWidgets/TrackedAction.h"
+#include "MantidKernel/UsageService.h"
+#include <QCoreApplication>
+
+namespace MantidQt {
+namespace MantidWidgets {
+
+/** Constructor
+*   @param parent The parent of this action
+**/
+TrackedAction::TrackedAction(QObject *parent)
+    : QAction(parent), m_isTracking(true), m_trackingName() {
+  setupTracking();
+}
+
+/** Constructor
+*   @param text The text for the action
+*   @param parent The parent of this action
+**/
+TrackedAction::TrackedAction(const QString &text, QObject *parent)
+    : QAction(text, parent), m_isTracking(true), m_trackingName() {
+  setupTracking();
+}
+
+/** Constructor
+*   @param icon The icon for the action
+*   @param text The text for the action
+*   @param parent The parent of this action
+**/
+TrackedAction::TrackedAction(const QIcon &icon, const QString &text,
+                             QObject *parent)
+    : QAction(icon, text, parent), m_isTracking(true), m_trackingName() {
+  setupTracking();
+}
+
+/** Sets the tracking name for this action
+*   @param name the tracking name for this action
+**/
+void TrackedAction::setTrackingName(const std::string &name) {
+  m_trackingName = name;
+}
+
+/** Gets the tracking name for this action
+*   If the tacking name is not set a default name will be generated using
+*   generateTrackingName
+*   @returns The tracking name for this action
+**/
+std::string TrackedAction::getTrackingName() const {
+  if (m_trackingName.empty()) {
+    m_trackingName = generateTrackingName();
+  }
+  return m_trackingName;
+}
+
+/** Sets whether this action is tracking usage
+*   @param enableTracking True if the action should tracking usage
+**/
+void TrackedAction::setIsTracking(const bool enableTracking) {
+  m_isTracking = enableTracking;
+}
+
+/** Gets whether this action is tracking usage
+*   @returns True if the action is tracking usage
+**/
+bool TrackedAction::getIsTracking() const { return m_isTracking; }
+
+/** Sets up tracking for the class
+**/
+void TrackedAction::setupTracking() {
+  connect(this, SIGNAL(triggered(bool)), this, SLOT(trackActivation(bool)));
+}
+
+/** Creates a tracking name from the action text
+*   @returns A generated name using ApplicationName->ActionText
+**/
+std::string TrackedAction::generateTrackingName() const {
+  return QCoreApplication::applicationName().toStdString() + "->" +
+         QAction::text().remove("&").remove(" ").toStdString();
+}
+
+/** Registers the feature usage if usage is enabled
+*   @param checked Whether the QAction is checked
+**/
+void TrackedAction::trackActivation(const bool checked) {
+  UNUSED_ARG(checked);
+  if (m_isTracking) {
+    // do tracking
+    registerUsage(getTrackingName());
+  }
+}
+
+/** Registers the feature usage with the usage service
+*   @param name The name to use when registering usage
+**/
+void TrackedAction::registerUsage(const std::string &name) {
+  Mantid::Kernel::UsageService::Instance().registerFeatureUsage("Feature", name,
+                                                                false);
+}
+} // namespace MantidWidgets
+} // namespace Mantid
diff --git a/MantidQt/MantidWidgets/src/WorkspacePresenter/QWorkspaceDockView.cpp b/MantidQt/MantidWidgets/src/WorkspacePresenter/QWorkspaceDockView.cpp
index a3ffcf9f7478e12d704464e658cc5d80c7a266b4..1a7ed1fa4e9b064d706635f877bcb958662d377d 100644
--- a/MantidQt/MantidWidgets/src/WorkspacePresenter/QWorkspaceDockView.cpp
+++ b/MantidQt/MantidWidgets/src/WorkspacePresenter/QWorkspaceDockView.cpp
@@ -766,7 +766,7 @@ void QWorkspaceDockView::populateChildData(QTreeWidgetItem *item) {
     const size_t nmembers = group->getNumberOfEntries();
     for (size_t i = 0; i < nmembers; ++i) {
       auto ws = group->getItem(i);
-      auto *node = addTreeEntry(std::make_pair(ws->name(), ws), item);
+      auto *node = addTreeEntry(std::make_pair(ws->getName(), ws), item);
       excludeItemFromSort(node);
       if (shouldBeSelected(node->text(0)))
         node->setSelected(true);
diff --git a/MantidQt/MantidWidgets/src/WorkspaceSelector.cpp b/MantidQt/MantidWidgets/src/WorkspaceSelector.cpp
index 7ca310cf09247a97ac751c4a96e5f62e8ec37ec4..1dff9c842d32e748c17c8f467493aba251b6d05c 100644
--- a/MantidQt/MantidWidgets/src/WorkspaceSelector.cpp
+++ b/MantidQt/MantidWidgets/src/WorkspaceSelector.cpp
@@ -10,6 +10,7 @@
 
 #include "MantidAPI/AlgorithmManager.h"
 #include "MantidAPI/MatrixWorkspace.h"
+#include "MantidAPI/WorkspaceGroup.h"
 
 #include <QDropEvent>
 #include <QMimeData>
@@ -30,8 +31,9 @@ WorkspaceSelector::WorkspaceSelector(QWidget *parent, bool init)
       m_clearObserver(*this, &WorkspaceSelector::handleClearEvent),
       m_renameObserver(*this, &WorkspaceSelector::handleRenameEvent),
       m_replaceObserver(*this, &WorkspaceSelector::handleReplaceEvent),
-      m_init(init), m_workspaceTypes(), m_showHidden(false), m_optional(false),
-      m_suffix(), m_algName(), m_algPropName(), m_algorithm() {
+      m_init(init), m_workspaceTypes(), m_showHidden(false), m_showGroups(true),
+      m_optional(false), m_suffix(), m_algName(), m_algPropName(),
+      m_algorithm() {
   setEditable(false);
   if (init) {
     Mantid::API::AnalysisDataServiceImpl &ads =
@@ -90,6 +92,17 @@ void WorkspaceSelector::showHiddenWorkspaces(bool show) {
   }
 }
 
+bool WorkspaceSelector::showWorkspaceGroups() const { return m_showGroups; }
+
+void WorkspaceSelector::showWorkspaceGroups(bool show) {
+  if (show != m_showGroups) {
+    m_showGroups = show;
+    if (m_init) {
+      refresh();
+    }
+  }
+}
+
 bool WorkspaceSelector::isValid() const { return (this->currentText() != ""); }
 
 bool WorkspaceSelector::isOptional() const { return m_optional; }
@@ -234,6 +247,11 @@ bool WorkspaceSelector::checkEligibility(
     return false;
   } else if (!hasValidSuffix(name)) {
     return false;
+  } else if (!m_showGroups) {
+    auto group =
+        boost::dynamic_pointer_cast<Mantid::API::WorkspaceGroup>(object);
+    if (group != nullptr)
+      return false;
   }
 
   return true;
diff --git a/MantidQt/MantidWidgets/test/DataProcessorUI/DataProcessorGenerateNotebookTest.h b/MantidQt/MantidWidgets/test/DataProcessorUI/DataProcessorGenerateNotebookTest.h
index b3c7f4b3ec37c10b448fa69d4bdd1124411b9c9b..e411fe24dcaf46a3d2f5a8846f411dce334f5f7d 100644
--- a/MantidQt/MantidWidgets/test/DataProcessorUI/DataProcessorGenerateNotebookTest.h
+++ b/MantidQt/MantidWidgets/test/DataProcessorUI/DataProcessorGenerateNotebookTest.h
@@ -5,6 +5,10 @@
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
+#include <boost/algorithm/string/classification.hpp>
+#include <boost/algorithm/string/join.hpp>
+#include <boost/algorithm/string/split.hpp>
+
 #include "MantidAPI/FrameworkManager.h"
 #include "MantidQtMantidWidgets/DataProcessorUI/DataProcessorGenerateNotebook.h"
 #include "MantidQtMantidWidgets/DataProcessorUI/DataProcessorVectorString.h"
diff --git a/MantidQt/MantidWidgets/test/DataProcessorUI/DataProcessorTwoLevelTreeManagerTest.h b/MantidQt/MantidWidgets/test/DataProcessorUI/DataProcessorTwoLevelTreeManagerTest.h
index 36caca5e12dfe14ebd689a5ad0613825f15f37ed..680b9238846271ee6d88e7b599dc990f417909ee 100644
--- a/MantidQt/MantidWidgets/test/DataProcessorUI/DataProcessorTwoLevelTreeManagerTest.h
+++ b/MantidQt/MantidWidgets/test/DataProcessorUI/DataProcessorTwoLevelTreeManagerTest.h
@@ -319,6 +319,19 @@ public:
     TS_ASSERT_EQUALS(data[1][1], fourthRow);
   }
 
+  void test_new_table_clears_model() {
+    NiceMock<MockDataProcessorPresenter> presenter;
+    auto table = reflTable();
+    auto whitelist = reflWhitelist();
+    DataProcessorTwoLevelTreeManager manager(&presenter, whitelist);
+
+    TS_ASSERT_THROWS_NOTHING(manager.newTable(table, whitelist));
+    TS_ASSERT_EQUALS(manager.getTableWorkspace()->rowCount(), 4);
+
+    TS_ASSERT_THROWS_NOTHING(manager.newTable(whitelist));
+    TS_ASSERT_EQUALS(manager.getTableWorkspace()->rowCount(), 0);
+  }
+
   void test_transfer_fails_no_group() {
     NiceMock<MockDataProcessorPresenter> presenter;
     DataProcessorTwoLevelTreeManager manager(&presenter, reflWhitelist());
diff --git a/MantidQt/MantidWidgets/test/DataProcessorUI/GenericDataProcessorPresenterTest.h b/MantidQt/MantidWidgets/test/DataProcessorUI/GenericDataProcessorPresenterTest.h
index 8654fc169506182d7ddf1eeae10ffce87e8581a5..3aeeb10f48c34cea04b3e1c0c329598cacd4728c 100644
--- a/MantidQt/MantidWidgets/test/DataProcessorUI/GenericDataProcessorPresenterTest.h
+++ b/MantidQt/MantidWidgets/test/DataProcessorUI/GenericDataProcessorPresenterTest.h
@@ -131,8 +131,7 @@ private:
         << "1.6"
         << "0.04"
         << "1"
-
-        << "";
+        << "ProcessingInstructions='0', CorrectDetectorPositions=0";
     row = ws->appendRow();
     row << "0"
         << "12346"
@@ -142,7 +141,7 @@ private:
         << "2.9"
         << "0.04"
         << "1"
-        << "";
+        << "ProcessingInstructions='0'";
     row = ws->appendRow();
     row << "1"
         << "24681"
@@ -1284,9 +1283,9 @@ public:
   }
 
   /*
-   * Test processing workspaces with non-standard names, with
-   * and without run_number information in the sample log.
-   */
+  * Test processing workspaces with non-standard names, with
+  * and without run_number information in the sample log.
+  */
   void testProcessCustomNames() {
 
     NiceMock<MockDataProcessorView> mockDataProcessorView;
@@ -1307,8 +1306,8 @@ public:
         << "0.1"
         << "1.6"
         << "0.04"
-
-        << "1";
+        << "1"
+        << "ProcessingInstructions='0', CorrectDetectorPositions=0";
     row = ws->appendRow();
     row << "1"
         << "dataB"
@@ -1317,8 +1316,8 @@ public:
         << "1.4"
         << "2.9"
         << "0.04"
-
-        << "1";
+        << "1"
+        << "ProcessingInstructions='0', CorrectDetectorPositions=0";
 
     createTOFWorkspace("dataA");
     createTOFWorkspace("dataB");
@@ -2188,7 +2187,8 @@ public:
     std::map<int, std::set<int>> rowlist;
     rowlist[0].insert(1);
 
-    const std::string expected = "0\t12346\t1.5\t\t1.4\t2.9\t0.04\t1\t";
+    const std::string expected =
+        "0\t12346\t1.5\t\t1.4\t2.9\t0.04\t1\tProcessingInstructions='0'";
 
     // The user hits "copy selected" with the second and third rows selected
     EXPECT_CALL(mockDataProcessorView, setClipboard(expected));
@@ -2244,10 +2244,12 @@ public:
     rowlist[1].insert(0);
     rowlist[1].insert(1);
 
-    const std::string expected = "0\t12345\t0.5\t\t0.1\t1.6\t0.04\t1\t\n"
-                                 "0\t12346\t1.5\t\t1.4\t2.9\t0.04\t1\t\n"
-                                 "1\t24681\t0.5\t\t0.1\t1.6\t0.04\t1\t\n"
-                                 "1\t24682\t1.5\t\t1.4\t2.9\t0.04\t1\t";
+    const std::string expected =
+        "0\t12345\t0.5\t\t0.1\t1.6\t0.04\t1\tProcessingInstructions='0', "
+        "CorrectDetectorPositions=0\n"
+        "0\t12346\t1.5\t\t1.4\t2.9\t0.04\t1\tProcessingInstructions='0'\n"
+        "1\t24681\t0.5\t\t0.1\t1.6\t0.04\t1\t\n"
+        "1\t24682\t1.5\t\t1.4\t2.9\t0.04\t1\t";
 
     // The user hits "copy selected" with the second and third rows selected
     EXPECT_CALL(mockDataProcessorView, setClipboard(expected));
@@ -2279,7 +2281,8 @@ public:
     std::map<int, std::set<int>> rowlist;
     rowlist[0].insert(1);
 
-    const std::string expected = "0\t12346\t1.5\t\t1.4\t2.9\t0.04\t1\t";
+    const std::string expected =
+        "0\t12346\t1.5\t\t1.4\t2.9\t0.04\t1\tProcessingInstructions='0'";
 
     // The user hits "copy selected" with the second and third rows selected
     EXPECT_CALL(mockDataProcessorView, setClipboard(expected));
@@ -2324,9 +2327,11 @@ public:
     rowlist[0].insert(1);
     rowlist[1].insert(0);
 
-    const std::string expected = "0\t12345\t0.5\t\t0.1\t1.6\t0.04\t1\t\n"
-                                 "0\t12346\t1.5\t\t1.4\t2.9\t0.04\t1\t\n"
-                                 "1\t24681\t0.5\t\t0.1\t1.6\t0.04\t1\t";
+    const std::string expected =
+        "0\t12345\t0.5\t\t0.1\t1.6\t0.04\t1\tProcessingInstructions='0', "
+        "CorrectDetectorPositions=0\n"
+        "0\t12346\t1.5\t\t1.4\t2.9\t0.04\t1\tProcessingInstructions='0'\n"
+        "1\t24681\t0.5\t\t0.1\t1.6\t0.04\t1\t";
 
     // The user hits "copy selected" with the second and third rows selected
     EXPECT_CALL(mockDataProcessorView, setClipboard(expected));
@@ -3142,6 +3147,92 @@ public:
                          std::map<int, std::vector<std::string>>()),
                      std::runtime_error);
   }
+
+  void testPostprocessMap() {
+    NiceMock<MockDataProcessorView> mockDataProcessorView;
+    NiceMock<MockProgressableView> mockProgress;
+    NiceMock<MockMainPresenter> mockMainPresenter;
+
+    std::map<std::string, std::string> postprocesssMap = {{"dQ/Q", "Params"}};
+    GenericDataProcessorPresenter presenter(
+        createReflectometryWhiteList(), createReflectometryPreprocessMap(),
+        createReflectometryProcessor(), createReflectometryPostprocessor(),
+        postprocesssMap);
+    presenter.acceptViews(&mockDataProcessorView, &mockProgress);
+    presenter.accept(&mockMainPresenter);
+
+    // Open a table
+    createPrefilledWorkspace("TestWorkspace", presenter.getWhiteList());
+    EXPECT_CALL(mockDataProcessorView, getWorkspaceToOpen())
+        .Times(1)
+        .WillRepeatedly(Return("TestWorkspace"));
+    presenter.notify(DataProcessorPresenter::OpenTableFlag);
+
+    createTOFWorkspace("12345", "12345");
+    createTOFWorkspace("12346", "12346");
+
+    std::set<int> grouplist;
+    grouplist.insert(0);
+
+    // We should not receive any errors
+    EXPECT_CALL(mockMainPresenter, giveUserCritical(_, _)).Times(0);
+
+    // The user hits the "process" button with the first group selected
+    EXPECT_CALL(mockDataProcessorView, getSelectedChildren())
+        .Times(1)
+        .WillRepeatedly(Return(std::map<int, std::set<int>>()));
+    EXPECT_CALL(mockDataProcessorView, getSelectedParents())
+        .Times(1)
+        .WillRepeatedly(Return(grouplist));
+    EXPECT_CALL(mockMainPresenter, getPreprocessingOptions())
+        .Times(2)
+        .WillRepeatedly(Return(std::map<std::string, std::string>()));
+    EXPECT_CALL(mockMainPresenter, getProcessingOptions())
+        .Times(2)
+        .WillRepeatedly(Return(""));
+    EXPECT_CALL(mockMainPresenter, getPostprocessingOptions())
+        .Times(1)
+        .WillOnce(Return("Params='-0.10'"));
+    EXPECT_CALL(mockDataProcessorView, getEnableNotebook())
+        .Times(1)
+        .WillRepeatedly(Return(false));
+    EXPECT_CALL(mockDataProcessorView, requestNotebookPath()).Times(0);
+
+    presenter.notify(DataProcessorPresenter::ProcessFlag);
+
+    // Check output workspace was stitched with params = '-0.04'
+    TS_ASSERT(
+        AnalysisDataService::Instance().doesExist("IvsQ_TOF_12345_TOF_12346"));
+
+    MatrixWorkspace_sptr out =
+        AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(
+            "IvsQ_TOF_12345_TOF_12346");
+    TSM_ASSERT_DELTA(
+        "Logarithmic rebinning should have been applied, with param 0.04",
+        out->x(0)[0], 0.100, 1e-5);
+    TSM_ASSERT_DELTA(
+        "Logarithmic rebinning should have been applied, with param 0.04",
+        out->x(0)[1], 0.104, 1e-5);
+    TSM_ASSERT_DELTA(
+        "Logarithmic rebinning should have been applied, with param 0.04",
+        out->x(0)[2], 0.10816, 1e-5);
+    TSM_ASSERT_DELTA(
+        "Logarithmic rebinning should have been applied, with param 0.04",
+        out->x(0)[3], 0.11248, 1e-5);
+
+    // Tidy up
+    AnalysisDataService::Instance().remove("TestWorkspace");
+    AnalysisDataService::Instance().remove("IvsQ_TOF_12345");
+    AnalysisDataService::Instance().remove("IvsLam_TOF_12345");
+    AnalysisDataService::Instance().remove("12345");
+    AnalysisDataService::Instance().remove("IvsQ_TOF_12346");
+    AnalysisDataService::Instance().remove("IvsLam_TOF_12346");
+    AnalysisDataService::Instance().remove("12346");
+    AnalysisDataService::Instance().remove("IvsQ_TOF_12345_TOF_12346");
+
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&mockDataProcessorView));
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&mockMainPresenter));
+  }
 };
 
 #endif /* MANTID_MANTIDWIDGETS_GENERICDATAPROCESSORPRESENTERTEST_H */
diff --git a/MantidQt/MantidWidgets/test/ProjectSaveMockObjects.h b/MantidQt/MantidWidgets/test/ProjectSaveMockObjects.h
new file mode 100644
index 0000000000000000000000000000000000000000..039d455e8935ab3231eef43de8d9f9b6576934fa
--- /dev/null
+++ b/MantidQt/MantidWidgets/test/ProjectSaveMockObjects.h
@@ -0,0 +1,56 @@
+#ifndef MANTIDQT_MANTIDWIDGETS_PROJECTSAVEMOCKOBJECTS_H
+#define MANTIDQT_MANTIDWIDGETS_PROJECTSAVEMOCKOBJECTS_H
+
+#include "MantidKernel/WarningSuppressions.h"
+#include "MantidQtAPI/IProjectSerialisable.h"
+#include "MantidQtMantidWidgets/IProjectSaveView.h"
+
+#include <gmock/gmock.h>
+
+using namespace MantidQt::API;
+using namespace MantidQt::MantidWidgets;
+
+GCC_DIAG_OFF_SUGGEST_OVERRIDE
+
+class MockProjectSaveView : public IProjectSaveView {
+public:
+  MOCK_METHOD0(getWindows, std::vector<IProjectSerialisable *>());
+  MOCK_METHOD0(getCheckedWorkspaceNames, std::vector<std::string>());
+  MOCK_METHOD0(getUncheckedWorkspaceNames, std::vector<std::string>());
+  MOCK_METHOD0(getProjectPath, QString());
+  MOCK_METHOD1(setProjectPath, void(const QString &));
+  MOCK_METHOD1(updateWorkspacesList, void(const std::vector<WorkspaceInfo> &));
+  MOCK_METHOD1(updateIncludedWindowsList,
+               void(const std::vector<WindowInfo> &));
+  MOCK_METHOD1(updateExcludedWindowsList,
+               void(const std::vector<WindowInfo> &));
+  MOCK_METHOD1(removeFromIncludedWindowsList,
+               void(const std::vector<std::string> &));
+  MOCK_METHOD1(removeFromExcludedWindowsList,
+               void(const std::vector<std::string> &));
+};
+
+//==============================================================================
+
+class WindowStub : public IProjectSerialisable {
+private:
+  std::string m_name;
+  std::vector<std::string> m_wsNames;
+
+public:
+  WindowStub(const std::string &name, const std::vector<std::string> &wsNames)
+      : m_name(name), m_wsNames(wsNames.cbegin(), wsNames.cend()) {}
+
+  std::string saveToProject(ApplicationWindow *app) override {
+    UNUSED_ARG(app);
+    return "";
+  }
+
+  std::vector<std::string> getWorkspaceNames() override { return m_wsNames; }
+
+  std::string getWindowName() override { return m_name; }
+
+  std::string getWindowType() override { return "Matrix"; }
+};
+
+#endif
diff --git a/MantidQt/MantidWidgets/test/ProjectSaveModelTest.h b/MantidQt/MantidWidgets/test/ProjectSaveModelTest.h
new file mode 100644
index 0000000000000000000000000000000000000000..ec618c11b49a5709d4f532efd611ec962166c8c6
--- /dev/null
+++ b/MantidQt/MantidWidgets/test/ProjectSaveModelTest.h
@@ -0,0 +1,254 @@
+#ifndef MANTIDQT_MANTIDWIDGETS_PROJECTSAVEMODELTEST_H
+#define MANTIDQT_MANTIDWIDGETS_PROJECTSAVEMODELTEST_H
+
+#include <cxxtest/TestSuite.h>
+
+#include "MantidQtAPI/IProjectSerialisable.h"
+#include "MantidQtMantidWidgets/ProjectSaveModel.h"
+#include "MantidQtMantidWidgets/ProjectSavePresenter.h"
+#include "MantidTestHelpers/WorkspaceCreationHelper.h"
+#include "ProjectSaveMockObjects.h"
+
+using namespace MantidQt::API;
+using namespace MantidQt::MantidWidgets;
+
+//=====================================================================================
+// Functional tests
+//=====================================================================================
+class ProjectSaveModelTest : public CxxTest::TestSuite {
+
+public:
+  void setUp() override {
+    auto ws1 = WorkspaceCreationHelper::create1DWorkspaceRand(10);
+    WorkspaceCreationHelper::storeWS("ws1", ws1);
+    auto ws2 = WorkspaceCreationHelper::create1DWorkspaceRand(10);
+    WorkspaceCreationHelper::storeWS("ws2", ws2);
+  }
+
+  void tearDown() override {
+    WorkspaceCreationHelper::removeWS("ws1");
+    WorkspaceCreationHelper::removeWS("ws2");
+  }
+
+  void testConstructNoWorkspacesNoWindows() {
+    tearDown(); // remove workspaces setup by default
+    std::vector<MantidQt::API::IProjectSerialisable *> windows;
+    TS_ASSERT_THROWS_NOTHING(ProjectSaveModel model(windows));
+  }
+
+  void testConstructOneWorkspaceNoWindows() {
+    std::vector<MantidQt::API::IProjectSerialisable *> windows;
+
+    ProjectSaveModel model(windows);
+    TS_ASSERT(!model.hasWindows("ws1"));
+    TS_ASSERT_EQUALS(model.getWindows("ws1").size(), 0);
+  }
+
+  void testGetWindowsForWorkspaceNoWindows() {
+    std::vector<MantidQt::API::IProjectSerialisable *> windows;
+
+    ProjectSaveModel model(windows);
+    TS_ASSERT(!model.hasWindows("ws1"));
+    TS_ASSERT_EQUALS(model.getWindows("ws1").size(), 0);
+  }
+
+  void testGetWindowsForWorkspaceOneWindow() {
+    std::vector<MantidQt::API::IProjectSerialisable *> windows;
+    WindowStub win1("window1", {"ws1"});
+    windows.push_back(&win1);
+
+    ProjectSaveModel model(windows);
+    TS_ASSERT(model.hasWindows("ws1"));
+    TS_ASSERT_EQUALS(model.getWindows("ws1").size(), 1);
+  }
+
+  void testGetWindowsForWorkspaceTwoWindows() {
+    std::vector<MantidQt::API::IProjectSerialisable *> windows;
+    WindowStub win1("window1", {"ws1"});
+    WindowStub win2("window2", {"ws1"});
+    windows.push_back(&win1);
+    windows.push_back(&win2);
+
+    ProjectSaveModel model(windows);
+    TS_ASSERT(model.hasWindows("ws1"));
+    TS_ASSERT_EQUALS(model.getWindows("ws1").size(), 2);
+  }
+
+  void testGetWindowsForTwoWorkspacesAndTwoWindows() {
+    std::vector<MantidQt::API::IProjectSerialisable *> windows;
+    WindowStub win1("window1", {"ws1"});
+    WindowStub win2("window2", {"ws2"});
+    windows.push_back(&win1);
+    windows.push_back(&win2);
+
+    ProjectSaveModel model(windows);
+    TS_ASSERT(model.hasWindows("ws1"));
+    TS_ASSERT_EQUALS(model.getWindows("ws1").size(), 1);
+    TS_ASSERT(model.hasWindows("ws2"));
+    TS_ASSERT_EQUALS(model.getWindows("ws2").size(), 1);
+  }
+
+  void testGetWorkspaceNames() {
+    std::vector<MantidQt::API::IProjectSerialisable *> windows;
+
+    ProjectSaveModel model(windows);
+    TS_ASSERT(!model.hasWindows("ws1"));
+    TS_ASSERT(!model.hasWindows("ws2"));
+
+    auto names = model.getWorkspaceNames();
+    TS_ASSERT_EQUALS(names.size(), 2);
+    TS_ASSERT_EQUALS(names[0], "ws1");
+    TS_ASSERT_EQUALS(names[1], "ws2");
+  }
+
+  void testGetWindowNames() {
+    std::vector<MantidQt::API::IProjectSerialisable *> windows;
+
+    WindowStub win1("window1", {"ws1"});
+    WindowStub win2("window2", {"ws2"});
+    WindowStub win3("window3", {"ws1", "ws2"});
+    WindowStub win4("window4", {});
+    windows.push_back(&win1);
+    windows.push_back(&win2);
+    windows.push_back(&win3);
+    windows.push_back(&win4);
+
+    ProjectSaveModel model(windows);
+    auto names = model.getWindowNames({"ws1", "ws2"});
+    TS_ASSERT_EQUALS(names.size(), 3);
+    TS_ASSERT_EQUALS(names[0], "window1");
+    TS_ASSERT_EQUALS(names[1], "window2");
+    TS_ASSERT_EQUALS(names[2], "window3");
+
+    names = model.getWindowNames({"ws1"});
+    TS_ASSERT_EQUALS(names.size(), 2);
+    TS_ASSERT_EQUALS(names[0], "window1");
+    TS_ASSERT_EQUALS(names[1], "window3");
+
+    names = model.getWindowNames({"ws2"});
+    TS_ASSERT_EQUALS(names.size(), 2);
+    TS_ASSERT_EQUALS(names[0], "window2");
+    TS_ASSERT_EQUALS(names[1], "window3");
+  }
+
+  void testGetWindows() {
+    std::vector<MantidQt::API::IProjectSerialisable *> windows;
+
+    WindowStub win1("window1", {"ws1"});
+    WindowStub win2("window2", {"ws2"});
+    WindowStub win3("window3", {"ws1", "ws2"});
+    WindowStub win4("window4", {});
+    windows.push_back(&win1);
+    windows.push_back(&win2);
+    windows.push_back(&win3);
+    windows.push_back(&win4);
+
+    ProjectSaveModel model(windows);
+    auto windowsSubset = model.getUniqueWindows({"ws1", "ws2"});
+    TS_ASSERT_EQUALS(windowsSubset.size(), 3);
+    TS_ASSERT_EQUALS(windowsSubset[0], &win1);
+    TS_ASSERT_EQUALS(windowsSubset[1], &win2);
+    TS_ASSERT_EQUALS(windowsSubset[2], &win3);
+
+    windowsSubset = model.getUniqueWindows({"ws1"});
+    TS_ASSERT_EQUALS(windowsSubset.size(), 2);
+    TS_ASSERT_EQUALS(windowsSubset[0], &win1);
+    TS_ASSERT_EQUALS(windowsSubset[1], &win3);
+
+    windowsSubset = model.getUniqueWindows({"ws2"});
+    TS_ASSERT_EQUALS(windowsSubset.size(), 2);
+    TS_ASSERT_EQUALS(windowsSubset[0], &win2);
+    TS_ASSERT_EQUALS(windowsSubset[1], &win3);
+  }
+
+  void testGetWorkspaceInformation() {
+    ProjectSaveModel model({});
+    auto wsInfo = model.getWorkspaceInformation();
+
+    TS_ASSERT_EQUALS(wsInfo.size(), 2);
+
+    TS_ASSERT_EQUALS(wsInfo[0].name, "ws1");
+    TS_ASSERT_EQUALS(wsInfo[0].type, "Workspace2D");
+    TS_ASSERT_EQUALS(wsInfo[0].size, "0 kB");
+    TS_ASSERT_EQUALS(wsInfo[0].icon_id, "mantid_matrix_xpm");
+    TS_ASSERT_EQUALS(wsInfo[0].numWindows, 0);
+
+    TS_ASSERT_EQUALS(wsInfo[1].name, "ws2");
+    TS_ASSERT_EQUALS(wsInfo[1].type, "Workspace2D");
+    TS_ASSERT_EQUALS(wsInfo[1].size, "0 kB");
+    TS_ASSERT_EQUALS(wsInfo[1].icon_id, "mantid_matrix_xpm");
+    TS_ASSERT_EQUALS(wsInfo[1].numWindows, 0);
+  }
+
+  void testGetWorkspaceInformationWithGroup() {
+    auto group =
+        WorkspaceCreationHelper::createWorkspaceGroup(3, 1, 10, "ws-group");
+
+    ProjectSaveModel model({});
+    auto wsInfo = model.getWorkspaceInformation();
+
+    TS_ASSERT_EQUALS(wsInfo.size(), 3);
+
+    TS_ASSERT_EQUALS(wsInfo[0].name, "ws-group");
+    TS_ASSERT_EQUALS(wsInfo[0].type, "WorkspaceGroup");
+    TS_ASSERT_EQUALS(wsInfo[0].size, "0 kB");
+    TS_ASSERT_EQUALS(wsInfo[0].icon_id, "mantid_wsgroup_xpm");
+    TS_ASSERT_EQUALS(wsInfo[0].numWindows, 0);
+    TS_ASSERT_EQUALS(wsInfo[0].subWorkspaces.size(), 3);
+
+    int count = 0;
+    for (auto &item : wsInfo[0].subWorkspaces) {
+      TS_ASSERT_EQUALS(item.name, "ws-group_" + std::to_string(count));
+      TS_ASSERT_EQUALS(item.type, "Workspace2D");
+      TS_ASSERT_EQUALS(item.size, "0 kB");
+      TS_ASSERT_EQUALS(item.icon_id, "mantid_matrix_xpm");
+      TS_ASSERT_EQUALS(item.numWindows, 0);
+      ++count;
+    }
+
+    TS_ASSERT_EQUALS(wsInfo[1].name, "ws1");
+    TS_ASSERT_EQUALS(wsInfo[1].type, "Workspace2D");
+    TS_ASSERT_EQUALS(wsInfo[1].size, "0 kB");
+    TS_ASSERT_EQUALS(wsInfo[1].icon_id, "mantid_matrix_xpm");
+    TS_ASSERT_EQUALS(wsInfo[1].numWindows, 0);
+    TS_ASSERT_EQUALS(wsInfo[1].subWorkspaces.size(), 0);
+
+    TS_ASSERT_EQUALS(wsInfo[2].name, "ws2");
+    TS_ASSERT_EQUALS(wsInfo[2].type, "Workspace2D");
+    TS_ASSERT_EQUALS(wsInfo[2].size, "0 kB");
+    TS_ASSERT_EQUALS(wsInfo[2].icon_id, "mantid_matrix_xpm");
+    TS_ASSERT_EQUALS(wsInfo[2].numWindows, 0);
+    TS_ASSERT_EQUALS(wsInfo[2].subWorkspaces.size(), 0);
+
+    WorkspaceCreationHelper::removeWS("ws-group");
+  }
+
+  void testGetWindowInformation() {
+    std::vector<MantidQt::API::IProjectSerialisable *> windows;
+
+    WindowStub win1("window1", {"ws1"});
+    WindowStub win2("window2", {"ws2"});
+    WindowStub win3("window3", {"ws1", "ws2"});
+    WindowStub win4("window4", {});
+    windows.push_back(&win1);
+    windows.push_back(&win2);
+    windows.push_back(&win3);
+    windows.push_back(&win4);
+
+    ProjectSaveModel model(windows);
+
+    auto winInfo = model.getWindowInformation({"ws1"});
+
+    TS_ASSERT_EQUALS(winInfo.size(), 2);
+
+    TS_ASSERT_EQUALS(winInfo[0].name, "window1");
+    TS_ASSERT_EQUALS(winInfo[0].type, "Matrix");
+    TS_ASSERT_EQUALS(winInfo[0].icon_id, "matrix_xpm");
+
+    TS_ASSERT_EQUALS(winInfo[1].name, "window3");
+    TS_ASSERT_EQUALS(winInfo[1].type, "Matrix");
+    TS_ASSERT_EQUALS(winInfo[1].icon_id, "matrix_xpm");
+  }
+};
+
+#endif // MANTIDQT_MANTIDWIDGETS_PROJECTSAVEMODELTEST_H
diff --git a/MantidQt/MantidWidgets/test/ProjectSavePresenterTest.h b/MantidQt/MantidWidgets/test/ProjectSavePresenterTest.h
new file mode 100644
index 0000000000000000000000000000000000000000..9d5d869714a4615d25db38dd376915684f8b8547
--- /dev/null
+++ b/MantidQt/MantidWidgets/test/ProjectSavePresenterTest.h
@@ -0,0 +1,357 @@
+
+#ifndef MANTIDQT_MANTIDWIDGETS_PROJECTSAVEPRESENTERTEST_H
+#define MANTIDQT_MANTIDWIDGETS_PROJECTSAVEPRESENTERTEST_H
+
+#include <cxxtest/TestSuite.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <QDir>
+#include <QFileInfo>
+
+#include "MantidQtMantidWidgets/ProjectSavePresenter.h"
+#include "MantidTestHelpers/WorkspaceCreationHelper.h"
+#include "ProjectSaveMockObjects.h"
+
+using namespace MantidQt::API;
+using namespace MantidQt::MantidWidgets;
+using namespace testing;
+
+//=====================================================================================
+// Functional tests
+//=====================================================================================
+
+class ProjectSavePresenterTest : public CxxTest::TestSuite {
+
+private:
+  NiceMock<MockProjectSaveView> m_view;
+
+public:
+  // This pair of boilerplate methods prevent the suite being created statically
+  // This means the constructor isn't called when running other tests
+  static ProjectSavePresenterTest *createSuite() {
+    return new ProjectSavePresenterTest();
+  }
+
+  static void destroySuite(ProjectSavePresenterTest *suite) { delete suite; }
+
+  ProjectSavePresenterTest() {}
+
+  // Tests
+  // ---------------------------------------------------
+
+  void testConstructWithNoWorkspacesAndNoWindows() {
+    std::vector<MantidQt::API::IProjectSerialisable *> windows;
+    std::vector<WindowInfo> winInfo;
+    std::vector<WorkspaceInfo> wsInfo;
+
+    // View should be passed what workspaces exist and what windows
+    // are currently included.
+    // As the ADS is empty at this point all lists should be empty
+    ON_CALL(m_view, getWindows()).WillByDefault(Return(windows));
+    EXPECT_CALL(m_view, getWindows()).WillOnce(Return(windows));
+    EXPECT_CALL(m_view, updateWorkspacesList(wsInfo)).Times(Exactly(1));
+    EXPECT_CALL(m_view, updateIncludedWindowsList(winInfo)).Times(Exactly(1));
+    EXPECT_CALL(m_view, updateExcludedWindowsList(winInfo)).Times(Exactly(0));
+
+    ProjectSavePresenter presenter(&m_view);
+
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&m_view));
+  }
+
+  void testConstructWithSingleWorkspaceAndNoWindows() {
+    std::vector<WindowInfo> winInfo;
+    auto workspaces = setUpWorkspaces({"ws1"});
+    std::vector<MantidQt::API::IProjectSerialisable *> windows;
+
+    // View should be passed what workspaces exist and what windows
+    // are currently included names.
+    ON_CALL(m_view, getWindows()).WillByDefault(Return(windows));
+    EXPECT_CALL(m_view, getWindows()).WillOnce(Return(windows));
+    EXPECT_CALL(m_view, updateWorkspacesList(workspaces)).Times(Exactly(1));
+    EXPECT_CALL(m_view, updateIncludedWindowsList(winInfo)).Times(Exactly(1));
+    EXPECT_CALL(m_view, updateExcludedWindowsList(winInfo)).Times(Exactly(0));
+
+    ProjectSavePresenter presenter(&m_view);
+
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&m_view));
+    tearDownWorkspaces(workspaces);
+  }
+
+  void testConstructWithTwoWorkspacesAndNoWindows() {
+    auto workspaces = setUpWorkspaces({"ws1", "ws2"});
+    std::vector<MantidQt::API::IProjectSerialisable *> windows;
+    std::vector<WindowInfo> winInfo;
+
+    // View should be passed what workspaces exist and what windows
+    // are currently included.
+    ON_CALL(m_view, getWindows()).WillByDefault(Return(windows));
+    EXPECT_CALL(m_view, getWindows()).WillRepeatedly(Return(windows));
+    EXPECT_CALL(m_view, updateWorkspacesList(workspaces)).Times(Exactly(1));
+    EXPECT_CALL(m_view, updateIncludedWindowsList(winInfo)).Times(Exactly(1));
+
+    ProjectSavePresenter presenter(&m_view);
+
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&m_view));
+    tearDownWorkspaces(workspaces);
+  }
+
+  void testConstructWithOneWorkspaceAndOneWindow() {
+    auto workspaces = setUpWorkspaces({"ws1"});
+
+    WindowInfo info;
+    info.name = "WindowName1Workspace";
+    WindowStub window(info.name, {"ws1"});
+
+    std::vector<MantidQt::API::IProjectSerialisable *> windows = {&window};
+    std::vector<WindowInfo> winInfo = {info};
+
+    // View should be passed what workspaces exist and what windows
+    // are currently included.
+    ON_CALL(m_view, getWindows()).WillByDefault(Return(windows));
+    EXPECT_CALL(m_view, getWindows()).WillOnce(Return(windows));
+    EXPECT_CALL(m_view, updateWorkspacesList(workspaces)).Times(Exactly(1));
+    EXPECT_CALL(m_view, updateIncludedWindowsList(winInfo)).Times(Exactly(1));
+
+    ProjectSavePresenter presenter(&m_view);
+
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&m_view));
+    tearDownWorkspaces(workspaces);
+  }
+
+  void testConstructWithOneWorkspaceAndTwoWindows() {
+    std::vector<std::string> wsNames = {"ws1"};
+    auto workspaces = setUpWorkspaces(wsNames);
+
+    WindowInfo win1Info, win2Info;
+    win1Info.name = "WindowName1Workspace";
+    win2Info.name = "WindowName2Workspace";
+
+    WindowStub window1(win1Info.name, wsNames);
+    WindowStub window2(win2Info.name, wsNames);
+
+    std::vector<MantidQt::API::IProjectSerialisable *> windows = {&window1,
+                                                                  &window2};
+    std::vector<WindowInfo> winInfo = {win1Info, win2Info};
+
+    // View should be passed what workspaces exist and what windows
+    // are currently included.
+    ON_CALL(m_view, getWindows()).WillByDefault(Return(windows));
+    EXPECT_CALL(m_view, getWindows()).WillOnce(Return(windows));
+    EXPECT_CALL(m_view, updateWorkspacesList(workspaces)).Times(Exactly(1));
+    EXPECT_CALL(m_view, updateIncludedWindowsList(winInfo)).Times(Exactly(1));
+
+    ProjectSavePresenter presenter(&m_view);
+
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&m_view));
+    tearDownWorkspaces(workspaces);
+  }
+
+  void testConstructWithTwoWorkspacesAndOneWindow() {
+    std::vector<std::string> wsNames = {"ws1", "ws2"};
+    auto workspaces = setUpWorkspaces(wsNames);
+
+    WindowInfo info;
+    info.name = "Windowname2Workspaces";
+    WindowStub window(info.name, wsNames);
+
+    std::vector<MantidQt::API::IProjectSerialisable *> windows = {&window};
+    std::vector<WindowInfo> winInfo = {info};
+
+    // View should be passed what workspaces exist and what windows
+    // are currently included.
+    ON_CALL(m_view, getWindows()).WillByDefault(Return(windows));
+    EXPECT_CALL(m_view, getWindows()).WillOnce(Return(windows));
+    EXPECT_CALL(m_view, updateWorkspacesList(workspaces)).Times(Exactly(1));
+    EXPECT_CALL(m_view, updateIncludedWindowsList(winInfo)).Times(Exactly(1));
+
+    ProjectSavePresenter presenter(&m_view);
+
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&m_view));
+    tearDownWorkspaces(workspaces);
+  }
+
+  void testConstructWithTwoWorkspacesAndTwoWindows() {
+    std::vector<std::string> wsNames = {"ws1", "ws2"};
+    auto workspaces = setUpWorkspaces(wsNames);
+
+    WindowInfo win1Info, win2Info;
+    win1Info.name = "WindowName1Workspace";
+    win2Info.name = "WindowName2Workspace";
+
+    WindowStub window1(win1Info.name, {wsNames[0]});
+    WindowStub window2(win2Info.name, {wsNames[1]});
+
+    std::vector<MantidQt::API::IProjectSerialisable *> windows = {&window1,
+                                                                  &window2};
+    std::vector<WindowInfo> winInfo = {win1Info, win2Info};
+
+    // View should be passed what workspaces exist and what windows
+    // are currently included.
+    ON_CALL(m_view, getWindows()).WillByDefault(Return(windows));
+    EXPECT_CALL(m_view, getWindows()).WillOnce(Return(windows));
+    EXPECT_CALL(m_view, updateWorkspacesList(workspaces)).Times(Exactly(1));
+    EXPECT_CALL(m_view, updateIncludedWindowsList(winInfo)).Times(Exactly(1));
+
+    ProjectSavePresenter presenter(&m_view);
+
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&m_view));
+    tearDownWorkspaces(workspaces);
+  }
+
+  void testDeselectWorkspaceWithAWindow() {
+    std::vector<std::string> wsNames = {"ws1"};
+    auto workspaces = setUpWorkspaces(wsNames);
+
+    WindowInfo info;
+    info.name = "WindowName1Workspaces";
+    WindowStub window(info.name, wsNames);
+
+    std::vector<MantidQt::API::IProjectSerialisable *> windows = {&window};
+    std::vector<std::string> windowNames = {info.name};
+    std::vector<WindowInfo> winInfo = {info};
+
+    // View should be passed what workspaces exist and what windows
+    // are currently included.
+    ON_CALL(m_view, getWindows()).WillByDefault(Return(windows));
+    ON_CALL(m_view, getUncheckedWorkspaceNames())
+        .WillByDefault(Return(wsNames));
+
+    EXPECT_CALL(m_view, getWindows()).WillOnce(Return(windows));
+    EXPECT_CALL(m_view, updateWorkspacesList(workspaces)).Times(Exactly(1));
+    EXPECT_CALL(m_view, updateIncludedWindowsList(winInfo)).Times(Exactly(1));
+    EXPECT_CALL(m_view, getUncheckedWorkspaceNames()).WillOnce(Return(wsNames));
+    EXPECT_CALL(m_view, updateExcludedWindowsList(winInfo)).Times(Exactly(1));
+    EXPECT_CALL(m_view, removeFromIncludedWindowsList(windowNames))
+        .Times(Exactly(1));
+
+    ProjectSavePresenter presenter(&m_view);
+    presenter.notify(ProjectSavePresenter::Notification::UncheckWorkspace);
+
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&m_view));
+    tearDownWorkspaces(workspaces);
+  }
+
+  void testReselectWorkspaceWithAWindow() {
+    std::vector<std::string> wsNames = {"ws1"};
+    auto workspaces = setUpWorkspaces(wsNames);
+
+    WindowInfo info;
+    info.name = "WindowName1Workspaces";
+    WindowStub window(info.name, wsNames);
+
+    std::vector<MantidQt::API::IProjectSerialisable *> windows = {&window};
+    std::vector<std::string> windowNames = {info.name};
+    std::vector<WindowInfo> winInfo = {info};
+
+    ON_CALL(m_view, getWindows()).WillByDefault(Return(windows));
+    ON_CALL(m_view, getUncheckedWorkspaceNames())
+        .WillByDefault(Return(wsNames));
+    ON_CALL(m_view, getCheckedWorkspaceNames()).WillByDefault(Return(wsNames));
+
+    EXPECT_CALL(m_view, getWindows()).WillOnce(Return(windows));
+    EXPECT_CALL(m_view, updateWorkspacesList(workspaces)).Times(Exactly(1));
+    EXPECT_CALL(m_view, updateIncludedWindowsList(winInfo)).Times(Exactly(2));
+    EXPECT_CALL(m_view, getUncheckedWorkspaceNames()).WillOnce(Return(wsNames));
+    EXPECT_CALL(m_view, updateExcludedWindowsList(winInfo)).Times(Exactly(1));
+    EXPECT_CALL(m_view, getCheckedWorkspaceNames()).WillOnce(Return(wsNames));
+    EXPECT_CALL(m_view, removeFromIncludedWindowsList(windowNames))
+        .Times(Exactly(1));
+    EXPECT_CALL(m_view, removeFromExcludedWindowsList(windowNames))
+        .Times(Exactly(1));
+
+    ProjectSavePresenter presenter(&m_view);
+    presenter.notify(ProjectSavePresenter::Notification::UncheckWorkspace);
+    presenter.notify(ProjectSavePresenter::Notification::CheckWorkspace);
+
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&m_view));
+    tearDownWorkspaces(workspaces);
+  }
+
+  void testPrepareProjectFolder_withFile() {
+    std::vector<WindowInfo> winInfo;
+    std::vector<WorkspaceInfo> wsInfo;
+    std::vector<MantidQt::API::IProjectSerialisable *> windows;
+    QFileInfo fi(".");
+    QString filePath =
+        fi.absolutePath() + "/mantidprojecttest/mantidprojecttest.mantid";
+
+    ON_CALL(m_view, getWindows()).WillByDefault(Return(windows));
+    ON_CALL(m_view, getProjectPath()).WillByDefault(Return(filePath));
+
+    EXPECT_CALL(m_view, getWindows()).WillOnce(Return(windows));
+    EXPECT_CALL(m_view, updateWorkspacesList(wsInfo)).Times(Exactly(1));
+    EXPECT_CALL(m_view, updateIncludedWindowsList(winInfo)).Times(Exactly(1));
+
+    EXPECT_CALL(m_view, getProjectPath()).Times(Exactly(1));
+    EXPECT_CALL(m_view, setProjectPath(filePath)).Times(Exactly(1));
+
+    ProjectSavePresenter presenter(&m_view);
+    presenter.notify(ProjectSavePresenter::Notification::PrepareProjectFolder);
+
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&m_view));
+  }
+
+  void testPrepareProjectFolder_withFolder() {
+    std::vector<WindowInfo> winInfo;
+    std::vector<WorkspaceInfo> wsInfo;
+    std::vector<MantidQt::API::IProjectSerialisable *> windows;
+    QFileInfo fi(".");
+    QString filePath = fi.absolutePath() + "/mantidprojecttest";
+
+    ON_CALL(m_view, getWindows()).WillByDefault(Return(windows));
+    ON_CALL(m_view, getProjectPath()).WillByDefault(Return(filePath));
+
+    EXPECT_CALL(m_view, getWindows()).WillOnce(Return(windows));
+    EXPECT_CALL(m_view, updateWorkspacesList(wsInfo)).Times(Exactly(1));
+    EXPECT_CALL(m_view, updateIncludedWindowsList(winInfo)).Times(Exactly(1));
+
+    EXPECT_CALL(m_view, getProjectPath()).Times(Exactly(1));
+    EXPECT_CALL(m_view, setProjectPath(filePath + "/mantidprojecttest.mantid"))
+        .Times(Exactly(1));
+
+    ProjectSavePresenter presenter(&m_view);
+    presenter.notify(ProjectSavePresenter::Notification::PrepareProjectFolder);
+
+    TS_ASSERT(Mock::VerifyAndClearExpectations(&m_view));
+
+    // clean up
+    fi.absoluteDir().rmdir(filePath);
+  }
+
+  //============================================================================
+  // Test Helper Methods
+  //============================================================================
+
+  /**
+ * Create some workspaces and add them to the ADS
+ * @param workspaces :: List of workspace names
+ * @return a vector of workspace info structs
+ */
+  std::vector<WorkspaceInfo>
+  setUpWorkspaces(const std::vector<std::string> &workspaces) {
+    std::vector<WorkspaceInfo> wsInfo;
+
+    for (auto &name : workspaces) {
+      auto ws = WorkspaceCreationHelper::create1DWorkspaceRand(10);
+      WorkspaceCreationHelper::storeWS(name, ws);
+      WorkspaceInfo info;
+      info.name = name;
+      wsInfo.push_back(info);
+    }
+
+    return wsInfo;
+  }
+
+  /**
+ * Remove a list of workspaces from the ADS
+ * @param workspaces :: List of workspace names
+ */
+  void tearDownWorkspaces(const std::vector<WorkspaceInfo> &workspaces) {
+    for (auto &info : workspaces) {
+      WorkspaceCreationHelper::removeWS(info.name);
+    }
+  }
+};
+
+#endif
diff --git a/MantidQt/MantidWidgets/test/TrackedActionTest.h b/MantidQt/MantidWidgets/test/TrackedActionTest.h
new file mode 100644
index 0000000000000000000000000000000000000000..5be95a63207ef5de85c46b378721e3321cd47e7c
--- /dev/null
+++ b/MantidQt/MantidWidgets/test/TrackedActionTest.h
@@ -0,0 +1,80 @@
+#ifndef MANTID_MANTIDWIDGETS_TRACKEDACTIONEST_H_
+#define MANTID_MANTIDWIDGETS_TRACKEDACTIONEST_H_
+
+#include <cxxtest/TestSuite.h>
+
+#include "MantidQtMantidWidgets/TrackedAction.h"
+#include <QCoreApplication>
+
+using MantidQt::MantidWidgets::TrackedAction;
+
+class TrackedActionTest : public CxxTest::TestSuite {
+  // inner class
+  class TestableTrackedAction : public TrackedAction {
+  public:
+    TestableTrackedAction(QObject *parent)
+        : TrackedAction(parent), m_lastName(){};
+    TestableTrackedAction(const QString &text, QObject *parent)
+        : TrackedAction(text, parent), m_lastName(){};
+    TestableTrackedAction(const QIcon &icon, const QString &text,
+                          QObject *parent)
+        : TrackedAction(icon, text, parent), m_lastName(){};
+
+    std::string getLastUsedName() const { return m_lastName; };
+
+  protected:
+    void registerUsage(const std::string &name) override { m_lastName = name; };
+
+  private:
+    std::string m_lastName;
+  };
+
+public:
+  // This pair of boilerplate methods prevent the suite being created statically
+  // This means the constructor isn't called when running other tests
+  static TrackedActionTest *createSuite() { return new TrackedActionTest(); }
+  static void destroySuite(TrackedActionTest *suite) { delete suite; }
+
+  void testIsTrackingGetSetGet() {
+    QObject parent;
+    TestableTrackedAction action(&parent);
+
+    TS_ASSERT_EQUALS(action.getIsTracking(), true); // default state
+    action.setIsTracking(false);
+    TS_ASSERT_EQUALS(action.getIsTracking(), false); // altered state
+  }
+
+  void testTrackingNameGetSetGet() {
+    QObject parent;
+    TestableTrackedAction action(QString::fromStdString("TestName"), &parent);
+
+    std::string appNamePrefix =
+        QCoreApplication::applicationName().toStdString() + "->";
+
+    TS_ASSERT_EQUALS(action.getTrackingName(),
+                     appNamePrefix + "TestName"); // default state
+    action.setTrackingName("TestName2");
+    TS_ASSERT_EQUALS(action.getTrackingName(), "TestName2"); // altered state
+  }
+
+  void testTrackingCallLogic() {
+    QObject parent;
+    TestableTrackedAction action(QString::fromStdString("TestName"), &parent);
+
+    // tracking should be on by default
+    TS_ASSERT_EQUALS(action.getIsTracking(), true); // default state
+    TS_ASSERT_EQUALS(action.getLastUsedName(), ""); // default state
+
+    action.setTrackingName("ShouldTrack");
+    action.trigger();
+    TS_ASSERT_EQUALS(action.getLastUsedName(),
+                     "ShouldTrack"); // tracking occurred state
+    action.setIsTracking(false);
+    action.setTrackingName("ShouldNotTrack");
+    action.trigger();
+    TS_ASSERT_DIFFERS(action.getLastUsedName(),
+                      "ShouldNotTrack"); // Should not have tracked
+  }
+};
+
+#endif /* MANTID_MANTIDWIDGETS_TRACKEDACTIONEST_H_ */
\ No newline at end of file
diff --git a/MantidQt/MantidWidgets/test/WorkspacePresenter/ADSAdapterTest.h b/MantidQt/MantidWidgets/test/WorkspacePresenter/ADSAdapterTest.h
index 6aa92ce63da6c4259520973f87b30423874ecd3c..b113580f74fc8b734db9e21f8c94b001c6c1409a 100644
--- a/MantidQt/MantidWidgets/test/WorkspacePresenter/ADSAdapterTest.h
+++ b/MantidQt/MantidWidgets/test/WorkspacePresenter/ADSAdapterTest.h
@@ -26,7 +26,7 @@ public:
   }
 
   void testLoadWorkspaceIntoADS() {
-    auto wksp = WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+    auto wksp = WorkspaceCreationHelper::create2DWorkspace(10, 10);
 
     EXPECT_CALL(*mockPresenter.get(),
                 notifyFromWorkspaceProvider(NotifyFlag::WorkspaceLoaded))
@@ -38,7 +38,7 @@ public:
   }
 
   void testRemoveWorkspaceFromADS() {
-    auto wksp = WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+    auto wksp = WorkspaceCreationHelper::create2DWorkspace(10, 10);
 
     AnalysisDataService::Instance().add("wksp", wksp);
 
@@ -52,8 +52,8 @@ public:
   }
 
   void testClearADS() {
-    auto wksp1 = WorkspaceCreationHelper::Create2DWorkspace(10, 10);
-    auto wksp2 = WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+    auto wksp1 = WorkspaceCreationHelper::create2DWorkspace(10, 10);
+    auto wksp2 = WorkspaceCreationHelper::create2DWorkspace(10, 10);
 
     AnalysisDataService::Instance().add("wksp1", wksp1);
     AnalysisDataService::Instance().add("wksp2", wksp2);
@@ -68,7 +68,7 @@ public:
   }
 
   void testRenameWorkspace() {
-    auto wksp = WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+    auto wksp = WorkspaceCreationHelper::create2DWorkspace(10, 10);
     AnalysisDataService::Instance().add("wksp", wksp);
     EXPECT_CALL(*mockPresenter.get(),
                 notifyFromWorkspaceProvider(NotifyFlag::WorkspaceRenamed))
@@ -102,12 +102,12 @@ public:
   }
 
   void testWorkspaceGroupUpdated() {
-    auto wksp1 = WorkspaceCreationHelper::Create2DWorkspace(10, 10);
-    auto wksp2 = WorkspaceCreationHelper::Create2DWorkspace(10, 10);
-    auto wksp3 = WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+    auto wksp1 = WorkspaceCreationHelper::create2DWorkspace(10, 10);
+    auto wksp2 = WorkspaceCreationHelper::create2DWorkspace(10, 10);
+    auto wksp3 = WorkspaceCreationHelper::create2DWorkspace(10, 10);
 
     auto group =
-        WorkspaceCreationHelper::CreateWorkspaceGroup(0, 10, 10, "group");
+        WorkspaceCreationHelper::createWorkspaceGroup(0, 10, 10, "group");
 
     AnalysisDataService::Instance().add("wksp1", wksp1);
     AnalysisDataService::Instance().add("wksp2", wksp2);
@@ -127,4 +127,4 @@ public:
 private:
   boost::shared_ptr<NiceMock<MockWorkspaceProviderNotifiable>> mockPresenter;
   ADSAdapter adapter;
-};
\ No newline at end of file
+};
diff --git a/MantidQt/MantidWidgets/test/WorkspacePresenter/WorkspacePresenterTest.h b/MantidQt/MantidWidgets/test/WorkspacePresenter/WorkspacePresenterTest.h
index e014cfd3f3c222d670ea9e9609e36ca0ecd4fb45..3d0ebddeca4e12019690b0a6ac1515edfe5d09cf 100644
--- a/MantidQt/MantidWidgets/test/WorkspacePresenter/WorkspacePresenterTest.h
+++ b/MantidQt/MantidWidgets/test/WorkspacePresenter/WorkspacePresenterTest.h
@@ -8,6 +8,7 @@
 #include <MantidAPI/AlgorithmManager.h>
 #include <MantidAPI/AnalysisDataService.h>
 #include <MantidAPI/FrameworkManager.h>
+#include <MantidAPI/WorkspaceGroup.h>
 #include <MantidTestHelpers/WorkspaceCreationHelper.h>
 
 #include <algorithm>
@@ -52,7 +53,7 @@ public:
   }
 
   void testLoadWorkspaceExternal() {
-    auto wksp = WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+    auto wksp = WorkspaceCreationHelper::create2DWorkspace(10, 10);
 
     EXPECT_CALL(*mockView.get(), updateTree(_)).Times(AtLeast(1));
 
@@ -64,8 +65,8 @@ public:
   }
 
   void testDeleteWorkspacesFromDockWithPrompt() {
-    auto ws1 = WorkspaceCreationHelper::Create2DWorkspace(10, 10);
-    auto ws2 = WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+    auto ws1 = WorkspaceCreationHelper::create2DWorkspace(10, 10);
+    auto ws2 = WorkspaceCreationHelper::create2DWorkspace(10, 10);
     AnalysisDataService::Instance().add("ws1", ws1);
     AnalysisDataService::Instance().add("ws2", ws2);
 
@@ -88,8 +89,8 @@ public:
   }
 
   void testDeleteWorkspacesFromDockWithPromptUserDecline() {
-    auto ws1 = WorkspaceCreationHelper::Create2DWorkspace(10, 10);
-    auto ws2 = WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+    auto ws1 = WorkspaceCreationHelper::create2DWorkspace(10, 10);
+    auto ws2 = WorkspaceCreationHelper::create2DWorkspace(10, 10);
     AnalysisDataService::Instance().add("ws1", ws1);
     AnalysisDataService::Instance().add("ws2", ws2);
 
@@ -110,8 +111,8 @@ public:
   }
 
   void testDeleteWorkspacesFromDockWithoutPrompt() {
-    auto ws1 = WorkspaceCreationHelper::Create2DWorkspace(10, 10);
-    auto ws2 = WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+    auto ws1 = WorkspaceCreationHelper::create2DWorkspace(10, 10);
+    auto ws2 = WorkspaceCreationHelper::create2DWorkspace(10, 10);
     AnalysisDataService::Instance().add("ws1", ws1);
     AnalysisDataService::Instance().add("ws2", ws2);
 
@@ -144,7 +145,7 @@ public:
   }
 
   void testDeleteWorkspacesExternal() {
-    auto wksp = WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+    auto wksp = WorkspaceCreationHelper::create2DWorkspace(10, 10);
 
     AnalysisDataService::Instance().add("wksp", wksp);
 
@@ -156,7 +157,7 @@ public:
   }
 
   void testADSCleared() {
-    auto wksp = WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+    auto wksp = WorkspaceCreationHelper::create2DWorkspace(10, 10);
 
     AnalysisDataService::Instance().add("wksp", wksp);
 
@@ -180,7 +181,7 @@ public:
   }
 
   void testRenameWorkspaceExternal() {
-    auto wksp = WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+    auto wksp = WorkspaceCreationHelper::create2DWorkspace(10, 10);
 
     AnalysisDataService::Instance().add("wksp", wksp);
 
@@ -194,8 +195,8 @@ public:
   }
 
   void testWorkspacesGrouped() {
-    auto ws1 = WorkspaceCreationHelper::Create2DWorkspace(10, 10);
-    auto ws2 = WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+    auto ws1 = WorkspaceCreationHelper::create2DWorkspace(10, 10);
+    auto ws2 = WorkspaceCreationHelper::create2DWorkspace(10, 10);
     AnalysisDataService::Instance().add("ws1", ws1);
     AnalysisDataService::Instance().add("ws2", ws2);
     ::testing::DefaultValue<StringList>::Set(StringList{"ws1", "ws2"});
@@ -235,8 +236,8 @@ public:
 
   void testGroupAlreadyExistsUserConfirm() {
     createGroup("NewGroup");
-    auto ws1 = WorkspaceCreationHelper::Create2DWorkspace(10, 10);
-    auto ws2 = WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+    auto ws1 = WorkspaceCreationHelper::create2DWorkspace(10, 10);
+    auto ws2 = WorkspaceCreationHelper::create2DWorkspace(10, 10);
     AnalysisDataService::Instance().add("ws1", ws1);
     AnalysisDataService::Instance().add("ws2", ws2);
 
@@ -356,7 +357,7 @@ public:
     std::string groupName = "group";
     createGroup(groupName);
 
-    auto wksp = WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+    auto wksp = WorkspaceCreationHelper::create2DWorkspace(10, 10);
     AnalysisDataService::Instance().add("wksp", wksp);
 
     EXPECT_CALL(*mockView.get(), updateTree(_)).Times(AtLeast(1));
@@ -629,7 +630,7 @@ public:
 
   void testClearUBMatrix() {
     ::testing::DefaultValue<StringList>::Set(StringList{"ws1"});
-    auto ws1 = WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+    auto ws1 = WorkspaceCreationHelper::create2DWorkspace(10, 10);
     AnalysisDataService::Instance().add("ws1", ws1);
 
     // Setup a UB matrix before attempting to remove it
@@ -665,9 +666,9 @@ private:
 
   void createGroup(std::string groupName) {
     auto group =
-        WorkspaceCreationHelper::CreateWorkspaceGroup(0, 10, 10, groupName);
-    auto wksp1 = WorkspaceCreationHelper::Create2DWorkspace(10, 10);
-    auto wksp2 = WorkspaceCreationHelper::Create2DWorkspace(10, 10);
+        WorkspaceCreationHelper::createWorkspaceGroup(0, 10, 10, groupName);
+    auto wksp1 = WorkspaceCreationHelper::create2DWorkspace(10, 10);
+    auto wksp2 = WorkspaceCreationHelper::create2DWorkspace(10, 10);
 
     AnalysisDataService::Instance().add("wksp1", wksp1);
     AnalysisDataService::Instance().add("wksp2", wksp2);
@@ -678,4 +679,4 @@ private:
   void removeGroup(std::string groupName) {
     AnalysisDataService::Instance().deepRemoveGroup(groupName);
   }
-};
\ No newline at end of file
+};
diff --git a/MantidQt/Python/mantidqt.sip b/MantidQt/Python/mantidqt.sip
index fc5742a3eb07377e0c3c092aaea7e22381d7851f..1f856727652291959773c2d0fa0a251595707319 100644
--- a/MantidQt/Python/mantidqt.sip
+++ b/MantidQt/Python/mantidqt.sip
@@ -84,7 +84,7 @@ namespace GraphOptions
   enum ScaleType {Linear, Log10};
 
   enum Axis{Left, Right, Bottom, Top};
-  
+
   enum CurveType {
   Line,
   Scatter,
@@ -194,13 +194,13 @@ public:
 
 };
 
-namespace MantidWidgets
+namespace API
 {
 
 class MWRunFiles : QWidget
 {
 %TypeHeaderCode
-#include "MantidQtMantidWidgets/MWRunFiles.h"
+#include "MantidQtAPI/MWRunFiles.h"
 %End
 public:
 void setLabelMinWidth(const int);
@@ -1356,6 +1356,7 @@ MantidQt::SliceViewer::SliceViewer* WidgetFactory::createSliceViewer(const QStri
 
 
 private:
+  WidgetFactory(const MantidQt::Factory::WidgetFactory&);
   WidgetFactory();
 %Docstring
 WidgetFactory::WidgetFactory()
diff --git a/MantidQt/RefDetectorViewer/src/RefMatrixWSImageView.cpp b/MantidQt/RefDetectorViewer/src/RefMatrixWSImageView.cpp
index bffc65231b13fa68deae4972de28d18d21b1e40d..28d73d639fb48ebb0cce65961e3c0f00631f5b29 100644
--- a/MantidQt/RefDetectorViewer/src/RefMatrixWSImageView.cpp
+++ b/MantidQt/RefDetectorViewer/src/RefMatrixWSImageView.cpp
@@ -1,6 +1,7 @@
 #include "MantidQtRefDetectorViewer/RefMatrixWSImageView.h"
 #include "MantidQtSpectrumViewer/ArrayDataSource.h"
 #include "MantidQtRefDetectorViewer/RefIVConnections.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/WorkspaceProperty.h"
 #include "MantidAPI/Algorithm.h"
 #include "MantidKernel/System.h"
diff --git a/MantidQt/SliceViewer/CMakeLists.txt b/MantidQt/SliceViewer/CMakeLists.txt
index 654440c0df0ac79327f3db680a00f766b108bc47..3f208408b2cf35fcfa18ed4ceab0dff8b0173cf6 100644
--- a/MantidQt/SliceViewer/CMakeLists.txt
+++ b/MantidQt/SliceViewer/CMakeLists.txt
@@ -1,6 +1,7 @@
 set ( SRC_FILES
 	src/CompositePeaksPresenter.cpp
 	src/ConcretePeaksPresenter.cpp
+	src/CoordinateTransform.cpp
 	src/CustomTools.cpp
 	src/DimensionSliceWidget.cpp
 	src/EllipsoidPlaneSliceCalculator.cpp
@@ -28,12 +29,15 @@ set ( SRC_FILES
 	src/SnapToGridDialog.cpp
 	src/XYLimitsDialog.cpp
 	src/LinePlotOptions.cpp
+	src/NonOrthogonalOverlay.cpp
+	src/QwtScaleDrawNonOrthogonal.cpp
 )
 
 # Include files aren't required, but this makes them appear in Visual Studio
 set ( INC_FILES
 	inc/MantidQtSliceViewer/CompositePeaksPresenter.h
 	inc/MantidQtSliceViewer/ConcretePeaksPresenter.h
+	inc/MantidQtSliceViewer/CoordinateTransform.h
 	inc/MantidQtSliceViewer/CustomTools.h
 	inc/MantidQtSliceViewer/DimensionSliceWidget.h
 	inc/MantidQtSliceViewer/EllipsoidPlaneSliceCalculator.h
@@ -42,6 +46,7 @@ set ( INC_FILES
 	inc/MantidQtSliceViewer/LinePlotOptions.h
 	inc/MantidQtSliceViewer/LineViewer.h
 	inc/MantidQtSliceViewer/NullPeaksPresenter.h
+	inc/MantidQtSliceViewer/NonOrthogonalOverlay.h
 	inc/MantidQtSliceViewer/PeakEditMode.h
         inc/MantidQtSliceViewer/PeakBoundingBox.h
         inc/MantidQtSliceViewer/PeakOverlayInteractive.h
@@ -72,6 +77,7 @@ set ( INC_FILES
 	inc/MantidQtSliceViewer/XYLimitsDialog.h
 	inc/MantidQtSliceViewer/ZoomableOnDemand.h
 	inc/MantidQtSliceViewer/ZoomablePeaksView.h
+	inc/MantidQtSliceViewer/QwtScaleDrawNonOrthogonal.h
 )
 
 set ( MOC_FILES 
@@ -80,6 +86,7 @@ set ( MOC_FILES
 	inc/MantidQtSliceViewer/LineOverlay.h
 	inc/MantidQtSliceViewer/LineViewer.h
 	inc/MantidQtSliceViewer/LinePlotOptions.h
+	inc/MantidQtSliceViewer/NonOrthogonalOverlay.h
         inc/MantidQtSliceViewer/PeakOverlayInteractive.h
 	inc/MantidQtSliceViewer/PeaksTableColumnsDialog.h
 	inc/MantidQtSliceViewer/SliceViewer.h
@@ -106,6 +113,7 @@ set ( UI_FILES
 
 set ( TEST_FILES
     test/CompositePeaksPresenterTest.h
+    test/CoordinateTransformTest.h
     test/ConcretePeaksPresenterTest.h
     test/EllipsoidPlaneSliceCalculatorTest.h
     test/PeakBoundingBoxTest.h
diff --git a/MantidQt/SliceViewer/icons/Nonorthogonal 32x32.png b/MantidQt/SliceViewer/icons/Nonorthogonal 32x32.png
new file mode 100644
index 0000000000000000000000000000000000000000..50cb9196129f4109fcbbdf70db0da8a4416d8a7d
Binary files /dev/null and b/MantidQt/SliceViewer/icons/Nonorthogonal 32x32.png differ
diff --git a/MantidQt/SliceViewer/icons/SliceViewerIcons.qrc b/MantidQt/SliceViewer/icons/SliceViewerIcons.qrc
index af9c94bc2749ab6d3fe7942ac6cd44e9b60ce202..5208eab9ce9af622c1877ee4603e86970d3f555b 100644
--- a/MantidQt/SliceViewer/icons/SliceViewerIcons.qrc
+++ b/MantidQt/SliceViewer/icons/SliceViewerIcons.qrc
@@ -30,5 +30,6 @@
         <file>peak_sphere.png</file>
         <file>peak_ellipsoid.png</file>
         <file>peak_cross.png</file>
+		<file>Nonorthogonal 32x32.png</file>
     </qresource>
 </RCC>
diff --git a/MantidQt/SliceViewer/inc/MantidQtSliceViewer/CoordinateTransform.h b/MantidQt/SliceViewer/inc/MantidQtSliceViewer/CoordinateTransform.h
new file mode 100644
index 0000000000000000000000000000000000000000..0c1d806f16d35b85ab8aead65ad95d86fab98f4e
--- /dev/null
+++ b/MantidQt/SliceViewer/inc/MantidQtSliceViewer/CoordinateTransform.h
@@ -0,0 +1,50 @@
+#ifndef MANTIDQT_SLICEVIEWER_COORDINATETRANSFORM_H
+#define MANTIDQT_SLICEVIEWER_COORDINATETRANSFORM_H
+
+#include "MantidKernel/VMD.h"
+#include "MantidAPI/IMDWorkspace.h"
+#include "DllOption.h"
+#include <memory>
+
+namespace MantidQt {
+namespace SliceViewer {
+class EXPORT_OPT_MANTIDQT_SLICEVIEWER CoordinateTransform {
+public:
+  virtual ~CoordinateTransform(){};
+  virtual void transform(Mantid::Kernel::VMD &coords, size_t dimX, size_t dimY,
+                         size_t missingHKLDim) = 0;
+  virtual void checkDimensionsForHKL(Mantid::API::IMDWorkspace_sptr ws,
+                                     size_t dimX, size_t dimY) = 0;
+};
+
+class EXPORT_OPT_MANTIDQT_SLICEVIEWER NullTransform
+    : public CoordinateTransform {
+public:
+  void transform(Mantid::Kernel::VMD &coords, size_t dimX, size_t dimY,
+                 size_t missingHKLDim) override;
+  void checkDimensionsForHKL(Mantid::API::IMDWorkspace_sptr ws, size_t dimX,
+                             size_t dimY) override;
+};
+
+class EXPORT_OPT_MANTIDQT_SLICEVIEWER NonOrthogonalTransform
+    : public CoordinateTransform {
+public:
+  ~NonOrthogonalTransform();
+  NonOrthogonalTransform(Mantid::API::IMDWorkspace_sptr ws, size_t dimX,
+                         size_t dimY);
+  void transform(Mantid::Kernel::VMD &coords, size_t dimX, size_t dimY,
+                 size_t missingHKLDim) override;
+  void checkDimensionsForHKL(Mantid::API::IMDWorkspace_sptr ws, size_t dimX,
+                             size_t dimY) override;
+
+private:
+  bool m_dimensionsHKL;
+  Mantid::coord_t m_skewMatrix[9];
+};
+
+std::unique_ptr<CoordinateTransform> EXPORT_OPT_MANTIDQT_SLICEVIEWER
+createCoordinateTransform(Mantid::API::IMDWorkspace_sptr ws, size_t dimX,
+                          size_t dimY);
+}
+}
+#endif
diff --git a/MantidQt/SliceViewer/inc/MantidQtSliceViewer/NonOrthogonalOverlay.h b/MantidQt/SliceViewer/inc/MantidQtSliceViewer/NonOrthogonalOverlay.h
new file mode 100644
index 0000000000000000000000000000000000000000..cff7fddd1d853625986ad7c9a043270293552288
--- /dev/null
+++ b/MantidQt/SliceViewer/inc/MantidQtSliceViewer/NonOrthogonalOverlay.h
@@ -0,0 +1,94 @@
+#ifndef MANTID_SLICEVIEWER_NONORTHOGONALOVERLAY_H_
+#define MANTID_SLICEVIEWER_NONORTHOGONALOVERLAY_H_
+
+#include "DllOption.h"
+#include <QtCore/QtCore>
+#include <QtGui/qwidget.h>
+#include <qwt_plot.h>
+#include <qwt_valuelist.h>
+#include <qpainter.h>
+#include "MantidKernel/System.h"
+#include "MantidQtAPI/QwtRasterDataMD.h"
+#include "MantidQtAPI/QwtRasterDataMDNonOrthogonal.h"
+#include "MantidAPI/IMDEventWorkspace.h"
+#include "MantidAPI/IMDHistoWorkspace.h"
+#include "MantidAPI/IMDWorkspace.h"
+#include "MantidQtAPI/NonOrthogonal.h"
+#include "MantidKernel/Matrix.h"
+
+namespace MantidQt {
+namespace SliceViewer {
+
+/** GUI for overlaying a nonorthogonal axes onto the plot
+  in the SliceViewer. Should be generic to overlays on any QwtPlot.
+
+  @date 2016-08-23
+
+  Copyright &copy; 2011 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>
+*/
+class EXPORT_OPT_MANTIDQT_SLICEVIEWER NonOrthogonalOverlay : public QWidget {
+  Q_OBJECT
+
+public:
+  NonOrthogonalOverlay(QwtPlot *plot, QWidget *parent);
+  ~NonOrthogonalOverlay() override;
+
+  void enable();
+
+  void disable();
+
+  void updateXGridlines(QwtValueList xAxisTicks, double xAngle);
+  void updateYGridlines(QwtValueList yAxisTicks, double yAngle);
+
+private:
+  QSize sizeHint() const override;
+  QSize size() const;
+
+  int height() const;
+  int width() const;
+
+  QPoint transform(QPointF coords) const;
+  QPointF invTransform(QPoint pixels) const;
+
+  void drawYLines(QPainter &painter, QPen &gridPen, int widthScreen,
+                  QwtValueList yAxisTicks, double yAngle);
+
+  void drawXLines(QPainter &painter, QPen &gridPen, int heightScreen,
+                  QwtValueList xAxisTicks, double xAngle);
+
+  void paintEvent(QPaintEvent *event) override;
+
+  bool m_enabled;
+
+  QwtPlot *m_plot;
+  Mantid::API::IMDWorkspace_sptr *m_ws;
+
+  QwtValueList m_xAxisTicks;
+  double m_xAngle;
+  QwtValueList m_yAxisTicks;
+  double m_yAngle;
+};
+
+} // namespace SliceViewer
+} // namespace Mantid
+
+#endif /* MANTID_SLICEVIEWER_NONORTHOGONALOVERLAY_H_ */
diff --git a/MantidQt/SliceViewer/inc/MantidQtSliceViewer/QwtScaleDrawNonOrthogonal.h b/MantidQt/SliceViewer/inc/MantidQtSliceViewer/QwtScaleDrawNonOrthogonal.h
new file mode 100644
index 0000000000000000000000000000000000000000..b031db8690f5d78592afdef261e0cec0e8724cd4
--- /dev/null
+++ b/MantidQt/SliceViewer/inc/MantidQtSliceViewer/QwtScaleDrawNonOrthogonal.h
@@ -0,0 +1,63 @@
+#ifndef QWT_SCALE_DRAW_NON_ORTHOGONAL_H
+#define QWT_SCALE_DRAW_NON_ORTHOGONAL_H
+
+#include "MantidQtSliceViewer/NonOrthogonalOverlay.h"
+#include "MantidGeometry/MDGeometry/MDTypes.h"
+#include "MantidKernel/VMD.h"
+#include "MantidAPI/IMDWorkspace.h"
+#include "qwt_scale_draw.h"
+#include "qwt_plot.h"
+#include <functional>
+
+class QwtScaleDrawNonOrthogonal : public QwtScaleDraw {
+public:
+  enum class ScreenDimension { X, Y };
+
+  QwtScaleDrawNonOrthogonal(
+      QwtPlot *plot, ScreenDimension screenDimension,
+      Mantid::API::IMDWorkspace_sptr workspace, size_t dimX, size_t dimY,
+      Mantid::Kernel::VMD slicePoint,
+      MantidQt::SliceViewer::NonOrthogonalOverlay *gridPlot);
+
+  void draw(QPainter *painter, const QPalette &palette) const override;
+
+  void drawLabelNonOrthogonal(QPainter *painter, double labelValue,
+                              double labelPos) const;
+
+  void updateSlicePoint(Mantid::Kernel::VMD newSlicepoint);
+
+private:
+  void setTransformationMatrices(Mantid::API::IMDWorkspace_sptr workspace);
+  qreal getScreenBottomInXyz() const;
+  qreal getScreenLeftInXyz() const;
+
+  QPoint fromXyzToScreen(QPointF xyz) const;
+  QPointF fromScreenToXyz(QPoint screen) const;
+  QPointF fromMixedCoordinatesToHkl(double x, double y) const;
+  double fromXtickInHklToXyz(double tick) const;
+  double fromYtickInHklToXyz(double tick) const;
+
+  Mantid::Kernel::VMD fromHklToXyz(const Mantid::Kernel::VMD &hkl) const;
+
+  void applyGridLinesX(const QwtValueList &majorTicksXyz) const;
+  void applyGridLinesY(const QwtValueList &majorTicksXyz) const;
+
+  Mantid::coord_t m_fromHklToXyz[9];
+  Mantid::coord_t m_fromXyzToHkl[9];
+
+  // Non-owning pointer to the QwtPlot
+  QwtPlot *m_plot;
+
+  ScreenDimension m_screenDimension;
+
+  // Non-orthogoanal information
+  size_t m_dimX;
+  size_t m_dimY;
+  size_t m_missingDimension;
+  Mantid::Kernel::VMD m_slicePoint;
+  double m_angleX;
+  double m_angleY;
+  MantidQt::SliceViewer::NonOrthogonalOverlay *m_gridPlot;
+};
+
+#endif
diff --git a/MantidQt/SliceViewer/inc/MantidQtSliceViewer/SliceViewer.h b/MantidQt/SliceViewer/inc/MantidQtSliceViewer/SliceViewer.h
index aad26e7d11d31c2084455e87caed909ec2229743..bfcb3f6c5c34500bf1be28765e7410e75f2e7a73 100644
--- a/MantidQt/SliceViewer/inc/MantidQtSliceViewer/SliceViewer.h
+++ b/MantidQt/SliceViewer/inc/MantidQtSliceViewer/SliceViewer.h
@@ -13,9 +13,12 @@
 #include "MantidQtAPI/MdSettings.h"
 #include "MantidQtMantidWidgets/SafeQwtPlot.h"
 #include "MantidQtAPI/SyncedCheckboxes.h"
+#include "MantidQtSliceViewer/CoordinateTransform.h"
 #include "MantidQtSliceViewer/LineOverlay.h"
+#include "MantidQtSliceViewer/NonOrthogonalOverlay.h"
 #include "MantidQtSliceViewer/PeaksPresenter.h"
 #include "MantidQtSliceViewer/ZoomablePeaksView.h"
+#include "MantidQtSliceViewer/QwtScaleDrawNonOrthogonal.h"
 #include "MantidQtAPI/QwtRasterDataMD.h"
 #include "ui_SliceViewer.h"
 #include <qwt_color_map.h>
@@ -86,7 +89,6 @@ public:
   Mantid::Kernel::VMD getSlicePoint() const { return m_slicePoint; }
   int getDimX() const;
   int getDimY() const;
-
   /// Methods for Python bindings
   QString getWorkspaceName() const;
   void setXYDim(int indexX, int indexY);
@@ -167,8 +169,10 @@ public slots:
   void helpPeaksViewer();
   void setFastRender(bool fast);
   void showInfoAt(double, double);
-
   // Change in view slots
+  void checkForHKLDimension();
+  void switchQWTRaster(bool useNonOrthogonal);
+  void switchAxis();
   void changedShownDim(int index, int dim, int oldDim);
   void updateDisplaySlot(int index, double value);
   void resetZoom();
@@ -196,7 +200,9 @@ public slots:
   void saveImage(const QString &filename = QString());
   void copyImageToClipboard();
   void onPeaksViewerOverlayOptions();
-
+  // Non Orthogonal
+  void setNonOrthogonalbtn();
+  void disableOrthogonalAnalysisTools(bool checked);
   // Synced checkboxes
   void LineMode_toggled(bool);
   void SnapToGrid_toggled(bool);
@@ -258,6 +264,12 @@ private:
   /// Extracts and applies the color scaling for the current slice
   void applyColorScalingForCurrentSliceIfRequired();
 
+  /// Apply the non orthogonal axis scale draw
+  void applyNonOrthogonalAxisScaleDraw();
+
+  /// Apply the orthogonal axis scale draw
+  void applyOrthogonalAxisScaleDraw();
+
 private:
   // -------------------------- Widgets ----------------------------
 
@@ -285,6 +297,11 @@ private:
   /// The LineOverlay widget for drawing the outline of the rebinned workspace
   LineOverlay *m_overlayWSOutline;
 
+  // PeakOverlay * m_peakOverlay;
+
+  // NonOrthogonal Overlay for drawing axes
+  NonOrthogonalOverlay *m_nonOrthogonalOverlay;
+
   /// Object for running algorithms in the background
   MantidQt::API::AlgorithmRunner *m_algoRunner;
 
@@ -306,7 +323,7 @@ private:
   std::vector<Mantid::Geometry::MDHistoDimension_sptr> m_dimensions;
 
   /// Data presenter
-  API::QwtRasterDataMD *m_data;
+  std::unique_ptr<API::QwtRasterDataMD> m_data;
 
   /// The X and Y dimensions being plotted
   Mantid::Geometry::IMDDimension_const_sptr m_X;
@@ -371,6 +388,16 @@ private:
   /// Logger
   Mantid::Kernel::Logger m_logger;
 
+  /// NonOrthogonal Fields
+  std::unique_ptr<CoordinateTransform> m_coordinateTransform;
+  bool m_firstNonOrthogonalWorkspaceOpen;
+  bool m_nonOrthogonalDefault; // sets whether nonOrthogonalview should be shown
+                               // as a default
+  bool m_oldDimNonOrthogonal; // sets whether previous dimensions were displayed
+  // as nonorthogonal, so if dims switch from orth -> nonOrth,
+  // then nonOrth should default be shown again
+  bool m_canSwitchScales; // stops qwtScaleDraw() from occuring in first set up
+
   // -------------------------- Controllers ------------------------
   boost::shared_ptr<CompositePeaksPresenter> m_peaksPresenter;
 
@@ -390,6 +417,9 @@ private:
   static const QString NumEventsNormalizationKey;
 
   AspectRatioType m_aspectRatioType;
+  AspectRatioType m_lastRatioState;
+  QwtScaleDrawNonOrthogonal *m_nonOrthAxis0;
+  QwtScaleDrawNonOrthogonal *m_nonOrthAxis1;
 };
 
 } // namespace SliceViewer
diff --git a/MantidQt/SliceViewer/inc/MantidQtSliceViewer/SliceViewer.ui b/MantidQt/SliceViewer/inc/MantidQtSliceViewer/SliceViewer.ui
index ee3545f152cb2c3ecfbc0b3d8b8677be57a9fcea..bd812209dcbcf34350bbac9cdcf68870e55190d3 100644
--- a/MantidQt/SliceViewer/inc/MantidQtSliceViewer/SliceViewer.ui
+++ b/MantidQt/SliceViewer/inc/MantidQtSliceViewer/SliceViewer.ui
@@ -543,8 +543,79 @@
             </property>
            </widget>
           </item>
+           <item>
+             <spacer name="horizontalSpacer_6">
+               <property name="orientation">
+                 <enum>Qt::Horizontal</enum>
+               </property>
+               <property name="sizeType">
+                 <enum>QSizePolicy::Fixed</enum>
+               </property>
+               <property name="sizeHint" stdset="0">
+                 <size>
+                   <width>8</width>
+                   <height>8</height>
+                 </size>
+               </property>
+             </spacer>
+           </item>
+           <item>
+             <widget class="QToolButton" name="btnNonOrthogonalToggle">
+               <property name="enabled">
+                 <bool>true</bool>
+               </property>
+               <property name="minimumSize">
+                 <size>
+                   <width>45</width>
+                   <height>45</height>
+                 </size>
+               </property>
+               <property name="maximumSize">
+                 <size>
+                   <width>45</width>
+                   <height>45</height>
+                 </size>
+               </property>
+               <property name="toolTip">
+                 <string>NonOrthogonal axes view</string>
+               </property>
+               <property name="text">
+                 <string>...</string>
+               </property>
+               <property name="icon">
+                 <iconset resource="../../icons/SliceViewerIcons.qrc">
+                   <normaloff>:/SliceViewer/icons/Nonorthogonal 32x32.png</normaloff>:/SliceViewer/icons/Peak List 32x32.png
+                 </iconset>
+               </property>
+               <property name="iconSize">
+                 <size>
+                   <width>32</width>
+                   <height>32</height>
+                 </size>
+               </property>
+               <property name="checkable">
+                 <bool>true</bool>
+               </property>
+             </widget>
+           </item>
+           <item>
+             <spacer name="horizontalSpacer_7">
+               <property name="orientation">
+                 <enum>Qt::Horizontal</enum>
+               </property>
+               <property name="sizeType">
+                 <enum>QSizePolicy::Fixed</enum>
+               </property>
+               <property name="sizeHint" stdset="0">
+                 <size>
+                   <width>8</width>
+                   <height>8</height>
+                 </size>
+               </property>
+             </spacer>
+           </item>
           <item>
-           <spacer name="horizontalSpacer_6">
+           <spacer name="horizontalSpacer_8">
             <property name="orientation">
              <enum>Qt::Horizontal</enum>
             </property>
diff --git a/MantidQt/SliceViewer/inc/MantidQtSliceViewer/SliceViewerWindow.h b/MantidQt/SliceViewer/inc/MantidQtSliceViewer/SliceViewerWindow.h
index ef71331e1ebbca50d3e25d1c6ae01a0012bd7691..0f4beca61f287c9d8ea67fc270090f68c88fdcf1 100644
--- a/MantidQt/SliceViewer/inc/MantidQtSliceViewer/SliceViewerWindow.h
+++ b/MantidQt/SliceViewer/inc/MantidQtSliceViewer/SliceViewerWindow.h
@@ -43,6 +43,12 @@ public:
                                                     const int fileVersion);
   /// Save the state of the slice viewer to a Mantid project file
   virtual std::string saveToProject(ApplicationWindow *app) override;
+  /// Get the name of the window
+  std::string getWindowName() override;
+  /// Get the workspaces associated with this window
+  std::vector<std::string> getWorkspaceNames() override;
+  /// Get the window type as a string
+  std::string getWindowType() override;
 
 private:
   void setLineViewerValues(QPointF start2D, QPointF end2D, double width);
diff --git a/MantidQt/SliceViewer/src/CompositePeaksPresenter.cpp b/MantidQt/SliceViewer/src/CompositePeaksPresenter.cpp
index 2e9534377ed3d28964255c5f68fcd7706c9bd31f..e8e278330cf108bf8fce7c4c53b6ace2228ed526 100644
--- a/MantidQt/SliceViewer/src/CompositePeaksPresenter.cpp
+++ b/MantidQt/SliceViewer/src/CompositePeaksPresenter.cpp
@@ -477,7 +477,7 @@ private:
 public:
   explicit MatchWorkspaceName(const QString &name) : m_wsName(name) {}
   bool operator()(SetPeaksWorkspaces::value_type ws) {
-    const std::string wsName = ws->name();
+    const std::string &wsName = ws->getName();
     const std::string toMatch = m_wsName.toStdString();
     const bool result = (wsName == toMatch);
     return result;
diff --git a/MantidQt/SliceViewer/src/ConcretePeaksPresenter.cpp b/MantidQt/SliceViewer/src/ConcretePeaksPresenter.cpp
index f4853f6d04b2db3bfeb2fd99e8e95b14eca077ab..f93acf95741e09278c5719660cd296b641c42248 100644
--- a/MantidQt/SliceViewer/src/ConcretePeaksPresenter.cpp
+++ b/MantidQt/SliceViewer/src/ConcretePeaksPresenter.cpp
@@ -628,7 +628,8 @@ ConcretePeaksPresenter::findVisiblePeakIndexes(const PeakBoundingBox &box) {
     alg->setRethrows(true);
     alg->initialize();
     alg->setProperty("InputWorkspace", peaksWS);
-    alg->setProperty("OutputWorkspace", peaksWS->name() + "_peaks_in_region");
+    alg->setProperty("OutputWorkspace",
+                     peaksWS->getName() + "_peaks_in_region");
     alg->setProperty("Extents", transformedViewableRegion.toExtents());
     alg->setProperty("CheckPeakExtents", false); // consider all peaks as points
     alg->setProperty("PeakRadius", radius);
diff --git a/MantidQt/SliceViewer/src/CoordinateTransform.cpp b/MantidQt/SliceViewer/src/CoordinateTransform.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8325b2449afb788f596a696a3371d09f9ff5d532
--- /dev/null
+++ b/MantidQt/SliceViewer/src/CoordinateTransform.cpp
@@ -0,0 +1,62 @@
+#include "MantidQtSliceViewer/CoordinateTransform.h"
+#include "MantidQtAPI/NonOrthogonal.h"
+#include "MantidKernel/make_unique.h"
+#include "MantidGeometry/MDGeometry/HKL.h"
+
+namespace MantidQt {
+namespace SliceViewer {
+
+void NullTransform::transform(Mantid::Kernel::VMD &coords, size_t dimX,
+                              size_t dimY, size_t missingHKLDim) {
+  (void)coords;
+  (void)dimX;
+  (void)dimY;
+  (void)missingHKLDim;
+}
+void NullTransform::checkDimensionsForHKL(Mantid::API::IMDWorkspace_sptr ws,
+                                          size_t dimX, size_t dimY) {
+  (void)ws;
+  (void)dimX;
+  (void)dimY;
+}
+
+NonOrthogonalTransform::~NonOrthogonalTransform() {}
+
+NonOrthogonalTransform::NonOrthogonalTransform(
+    Mantid::API::IMDWorkspace_sptr ws, size_t dimX, size_t dimY)
+    : m_dimensionsHKL(true) {
+  // Set the skewMatrix for the non-orthogonal data
+  auto numberOfDimensions = ws->getNumDims();
+  Mantid::Kernel::DblMatrix skewMatrix(numberOfDimensions, numberOfDimensions,
+                                       true);
+  API::provideSkewMatrix(skewMatrix, ws);
+  API::transformFromDoubleToCoordT(skewMatrix, m_skewMatrix);
+  checkDimensionsForHKL(ws, dimX, dimY);
+}
+void NonOrthogonalTransform::checkDimensionsForHKL(
+    Mantid::API::IMDWorkspace_sptr ws, size_t dimX, size_t dimY) {
+  bool dimensionHKL = API::isHKLDimensions(ws, dimX, dimY);
+  m_dimensionsHKL = dimensionHKL;
+}
+void NonOrthogonalTransform::transform(Mantid::Kernel::VMD &coords, size_t dimX,
+                                       size_t dimY, size_t missingHKLDim) {
+  if (m_dimensionsHKL) {
+    API::transformLookpointToWorkspaceCoordGeneric(coords, m_skewMatrix, dimX,
+                                                   dimY, missingHKLDim);
+  }
+}
+
+std::unique_ptr<CoordinateTransform>
+createCoordinateTransform(Mantid::API::IMDWorkspace_sptr ws, size_t dimX,
+                          size_t dimY) {
+  std::unique_ptr<CoordinateTransform> coordinateTransform;
+  if (API::requiresSkewMatrix(ws)) {
+    coordinateTransform =
+        Mantid::Kernel::make_unique<NonOrthogonalTransform>(ws, dimX, dimY);
+  } else {
+    coordinateTransform = Mantid::Kernel::make_unique<NullTransform>();
+  }
+  return coordinateTransform;
+}
+}
+}
diff --git a/MantidQt/SliceViewer/src/LinePlotOptions.cpp b/MantidQt/SliceViewer/src/LinePlotOptions.cpp
index cf8e90709dc88ace4dd9989d9c064a4c0806e41b..959c39b6fded0ca09420718f4a18ebd3d4ddb38b 100644
--- a/MantidQt/SliceViewer/src/LinePlotOptions.cpp
+++ b/MantidQt/SliceViewer/src/LinePlotOptions.cpp
@@ -1,3 +1,4 @@
+#include "MantidGeometry/MDGeometry/IMDDimension.h"
 #include "../inc/MantidQtSliceViewer/LinePlotOptions.h"
 #include "MantidQtAPI/TSVSerialiser.h"
 
diff --git a/MantidQt/SliceViewer/src/LineViewer.cpp b/MantidQt/SliceViewer/src/LineViewer.cpp
index 39a66108343a0b48f230bb3e1277ff9c32ce6ead..838dcfbfc66bb22b9e9461f1d4547bfef4fd49b2 100644
--- a/MantidQt/SliceViewer/src/LineViewer.cpp
+++ b/MantidQt/SliceViewer/src/LineViewer.cpp
@@ -6,6 +6,7 @@
 #include "MantidAPI/IMDHistoWorkspace.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidGeometry/MDGeometry/IMDDimension.h"
+#include "MantidKernel/Strings.h"
 #include "MantidKernel/UsageService.h"
 #include "MantidKernel/VMD.h"
 #include "MantidQtAPI/AlgorithmRunner.h"
@@ -1160,7 +1161,7 @@ std::string LineViewer::saveToProject() const {
   if (!m_sliceWS)
     return "";
 
-  tsv.writeLine("SliceWorkspace") << m_sliceWS->name();
+  tsv.writeLine("SliceWorkspace") << m_sliceWS->getName();
   tsv.writeLine("XDim") << m_freeDimX;
   tsv.writeLine("YDim") << m_freeDimY;
   tsv.writeLine("AllFreeDims") << m_allDimsFree;
diff --git a/MantidQt/SliceViewer/src/NonOrthogonalOverlay.cpp b/MantidQt/SliceViewer/src/NonOrthogonalOverlay.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f39221fad1ef6706756ae4a803913156d39a7759
--- /dev/null
+++ b/MantidQt/SliceViewer/src/NonOrthogonalOverlay.cpp
@@ -0,0 +1,156 @@
+#include "MantidQtSliceViewer/NonOrthogonalOverlay.h"
+#include <qwt_plot.h>
+#include <qwt_plot_canvas.h>
+#include <qpainter.h>
+#include <QRect>
+#include <QShowEvent>
+#include <qwt_scale_div.h>
+#include "MantidKernel/Utils.h"
+#include "MantidAPI/IMDEventWorkspace.h"
+#include "MantidAPI/IMDHistoWorkspace.h"
+#include "MantidAPI/IMDWorkspace.h"
+#include "MantidQtAPI/NonOrthogonal.h"
+#include <numeric>
+
+using namespace Mantid::Kernel;
+
+namespace MantidQt {
+namespace SliceViewer {
+
+//----------------------------------------------------------------------------------------------
+/** Constructor
+ */
+NonOrthogonalOverlay::NonOrthogonalOverlay(QwtPlot *plot, QWidget *parent)
+    : QWidget(parent), m_plot(plot), m_xAngle(0.), m_yAngle(0.) {}
+
+//----------------------------------------------------------------------------------------------
+/** Destructor
+ */
+NonOrthogonalOverlay::~NonOrthogonalOverlay() {}
+
+/// Return the recommended size of the widget
+QSize NonOrthogonalOverlay::sizeHint() const {
+  // TODO: Is there a smarter way to find the right size?
+  return QSize(20000, 20000);
+}
+
+QSize NonOrthogonalOverlay::size() const { return m_plot->canvas()->size(); }
+int NonOrthogonalOverlay::height() const { return m_plot->canvas()->height(); }
+int NonOrthogonalOverlay::width() const { return m_plot->canvas()->width(); }
+
+//----------------------------------------------------------------------------------------------
+/** Tranform from plot coordinates to pixel coordinates
+ * @param coords :: coordinate point in plot coordinates
+ * @return pixel coordinates */
+QPoint NonOrthogonalOverlay::transform(QPointF coords) const {
+  auto xA = m_plot->transform(QwtPlot::xBottom, coords.x());
+  auto yA = m_plot->transform(QwtPlot::yLeft, coords.y());
+  return QPoint(xA, yA);
+}
+
+//----------------------------------------------------------------------------------------------
+/** Inverse transform: from pixels to plot coords
+ * @param pixels :: location in pixels
+ * @return plot coordinates (float)   */
+QPointF NonOrthogonalOverlay::invTransform(QPoint pixels) const {
+  auto xA = m_plot->invTransform(QwtPlot::xBottom, pixels.x());
+  auto yA = m_plot->invTransform(QwtPlot::yLeft, pixels.y());
+  return QPointF(xA, yA);
+}
+
+void NonOrthogonalOverlay::updateXGridlines(QwtValueList xAxisTicks,
+                                            double xAngle) {
+  m_xAxisTicks = xAxisTicks;
+  m_xAngle = xAngle;
+  auto size = xAxisTicks.size();
+  if (m_xAngle != 0 && size >= 1) {
+    double firstTick;
+    double lastTick;
+    double diff;
+    firstTick = xAxisTicks.at(0);
+    lastTick = xAxisTicks.last();
+    diff = xAxisTicks.at(1) - firstTick;
+    for (auto j = 0; j < size * 2; j++) {
+      auto tick = firstTick - diff * j;
+      m_xAxisTicks.append(tick);
+      tick = lastTick + diff * j;
+      m_xAxisTicks.append(tick);
+    }
+  }
+}
+
+void NonOrthogonalOverlay::updateYGridlines(QwtValueList yAxisTicks,
+                                            double yAngle) {
+  m_yAxisTicks = yAxisTicks;
+  m_yAngle = yAngle;
+  auto size = yAxisTicks.size();
+  if (m_yAngle != 0 && size >= 1) {
+    double firstTick;
+    double lastTick;
+    double diff;
+    firstTick = yAxisTicks.at(0);
+    lastTick = yAxisTicks.last();
+    diff = yAxisTicks.at(1) - firstTick;
+    for (auto j = 0; j < size * 2; j++) {
+      auto tick = firstTick - diff * j;
+      m_yAxisTicks.append(tick);
+      tick = lastTick + diff * j;
+      m_yAxisTicks.append(tick);
+    }
+  }
+}
+
+//----------------------------------------------------------------------------------------------
+/// Paint the overlay
+void NonOrthogonalOverlay::paintEvent(QPaintEvent * /*event*/) {
+
+  if (m_enabled) {
+    QPainter painter(this);
+
+    QPen gridPen(QColor(100, 100, 100, 100)); // grey
+    gridPen.setWidth(1);
+    gridPen.setCapStyle(Qt::FlatCap);
+    gridPen.setStyle(Qt::DashLine);
+
+    const auto widthScreen = width();
+    const auto heightScreen = height();
+
+    drawYLines(painter, gridPen, widthScreen, m_yAxisTicks, m_yAngle);
+    drawXLines(painter, gridPen, heightScreen, m_xAxisTicks, m_xAngle);
+  }
+}
+
+void NonOrthogonalOverlay::drawYLines(QPainter &painter, QPen &gridPen,
+                                      int widthScreen, QwtValueList yAxisTicks,
+                                      double yAngle) {
+
+  auto offset = yAngle == 0. ? 0. : widthScreen * tan(yAngle);
+  painter.setPen(gridPen);
+  for (auto &tick : yAxisTicks) {
+    auto tickScreen = m_plot->transform(QwtPlot::yLeft, tick);
+    auto start = QPointF(0, tickScreen);
+    auto end = QPointF(widthScreen, tickScreen - offset);
+    painter.drawLine(start, end);
+  }
+}
+
+void NonOrthogonalOverlay::drawXLines(QPainter &painter, QPen &gridPen,
+                                      int heightScreen, QwtValueList xAxisTicks,
+                                      double xAngle) {
+  xAngle *= -1.f;
+  auto offset = xAngle == 0. ? 0. : heightScreen * tan(xAngle);
+  painter.setPen(gridPen);
+  for (auto &tick : xAxisTicks) {
+    auto tickScreen = m_plot->transform(QwtPlot::xBottom, tick);
+    auto start = QPointF(tickScreen, heightScreen);
+    auto end = QPointF(tickScreen + offset, 0);
+    painter.drawLine(start, end);
+  }
+}
+
+void NonOrthogonalOverlay::enable() { m_enabled = true; }
+
+void NonOrthogonalOverlay::disable() { m_enabled = false; }
+
+} // namespace Mantid
+} // namespace SliceViewer
diff --git a/MantidQt/SliceViewer/src/PeakView.cpp b/MantidQt/SliceViewer/src/PeakView.cpp
index 5096c69d4df8c0dcc0db3bab56f6adb80da9546b..663b6f1c0f71c4a040d75d51d72bc96b28daad40 100644
--- a/MantidQt/SliceViewer/src/PeakView.cpp
+++ b/MantidQt/SliceViewer/src/PeakView.cpp
@@ -15,8 +15,8 @@ PeakView::PeakView(PeaksPresenter *const presenter, QwtPlot *plot,
                    PeakViewColor foregroundColor, PeakViewColor backgroundColor,
                    double largestEffectiveRadius)
     : PeakOverlayInteractive(presenter, plot, plotXIndex, plotYIndex, parent),
-      m_peaks(vecPeakRepresentation), m_cachedOccupancyIntoView(0),
-      m_cachedOccupancyInView(0), m_showBackground(false),
+      m_peaks(vecPeakRepresentation), m_cachedOccupancyIntoView(0.015),
+      m_cachedOccupancyInView(0.015), m_showBackground(false),
       m_foregroundColor(foregroundColor), m_backgroundColor(backgroundColor),
       m_largestEffectiveRadius(largestEffectiveRadius) {}
 
@@ -133,7 +133,7 @@ void PeakView::takeSettingsFrom(const PeakOverlayView *const source) {
   // cross-type peak
   this->showBackgroundRadius(source->isBackgroundShown());
 
-  // Pass on the information which only concerns the cross-type peak
+  // Pass on the information which only concerns the cross-type peak.
   this->changeOccupancyIntoView(source->getOccupancyIntoView());
   this->changeOccupancyInView(source->getOccupancyInView());
 }
diff --git a/MantidQt/SliceViewer/src/PeaksViewer.cpp b/MantidQt/SliceViewer/src/PeaksViewer.cpp
index d7391cb253d875da7b5b7538993c77d859614d50..68bfd14a0724203d32fac343495842287b98650a 100644
--- a/MantidQt/SliceViewer/src/PeaksViewer.cpp
+++ b/MantidQt/SliceViewer/src/PeaksViewer.cpp
@@ -289,8 +289,8 @@ std::string PeaksViewer::saveToProject() const {
     auto zoomedWorkspaces = (*zoomPresenter)->presentedWorkspaces();
     tsv.writeLine("ZoomedPeakIndex") << m_presenter->getZoomedPeakIndex();
     tsv.writeLine("ZoomedPeakWorkspaces");
-    for (auto ws : zoomedWorkspaces) {
-      tsv << ws->name();
+    for (const auto &ws : zoomedWorkspaces) {
+      tsv << ws->getName();
     }
   }
 
@@ -317,7 +317,7 @@ std::string PeaksViewer::saveToProject() const {
 std::string PeaksViewer::savePresentedWorkspace(
     Mantid::API::IPeaksWorkspace_const_sptr ws) const {
   API::TSVSerialiser tsv;
-  tsv.writeLine("Name") << ws->name();
+  tsv.writeLine("Name") << ws->getName();
   tsv.writeLine("ShowBackground") << m_presenter->getShowBackground(ws);
 
   tsv.writeLine("Foreground");
@@ -439,7 +439,7 @@ void PeaksViewer::performUpdate() {
         if (optionalZoomedPresenter.is_initialized()) {
           // Is the zoomed peaks workspace the current workspace.
           if (optionalZoomedPresenter.get().get() ==
-              m_presenter->getPeaksPresenter(ws->name().c_str())) {
+              m_presenter->getPeaksPresenter(ws->getName().c_str())) {
             candidateWidget->setSelectedPeak(optionalZoomedIndex);
           }
         }
diff --git a/MantidQt/SliceViewer/src/PeaksWorkspaceWidget.cpp b/MantidQt/SliceViewer/src/PeaksWorkspaceWidget.cpp
index 19fdc90d6a82a06d94d050e6a6cd6cde98e06216..34498f48d173b13320872eed2b948084895edf4f 100644
--- a/MantidQt/SliceViewer/src/PeaksWorkspaceWidget.cpp
+++ b/MantidQt/SliceViewer/src/PeaksWorkspaceWidget.cpp
@@ -148,7 +148,7 @@ void PeaksWorkspaceWidget::createTableMVC() {
 }
 
 void PeaksWorkspaceWidget::populate() {
-  m_nameText = QString(m_ws->name().c_str());
+  m_nameText = QString(m_ws->getName().c_str());
   ui.lblWorkspaceName->setText(m_nameText);
   ui.lblWorkspaceName->setToolTip(m_nameText);
 
diff --git a/MantidQt/SliceViewer/src/QwtScaleDrawNonOrthogonal.cpp b/MantidQt/SliceViewer/src/QwtScaleDrawNonOrthogonal.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..06af6eac9cab86db9e4e5da54f35df4abf6f26ea
--- /dev/null
+++ b/MantidQt/SliceViewer/src/QwtScaleDrawNonOrthogonal.cpp
@@ -0,0 +1,333 @@
+#include "MantidQtSliceViewer/QwtScaleDrawNonOrthogonal.h"
+
+#include "MantidQtAPI/NonOrthogonal.h"
+#include <QPainter>
+#include <QPalette>
+#include "qwt_layout_metrics.h"
+#include "qwt_painter.h"
+#include "qwt_scale_draw.h"
+#include "qwt_scale_engine.h"
+#include "qwt_plot_canvas.h"
+
+#include <qmatrix.h>
+#define QwtMatrix QMatrix
+
+QwtScaleDrawNonOrthogonal::QwtScaleDrawNonOrthogonal(
+    QwtPlot *plot, ScreenDimension screenDimension,
+    Mantid::API::IMDWorkspace_sptr workspace, size_t dimX, size_t dimY,
+    Mantid::Kernel::VMD slicePoint,
+    MantidQt::SliceViewer::NonOrthogonalOverlay *gridPlot)
+    : m_plot(plot), m_screenDimension(screenDimension), m_dimX(dimX),
+      m_dimY(dimY), m_slicePoint(slicePoint), m_gridPlot(gridPlot) {
+  m_fromHklToXyz[0] = 1.0;
+  m_fromHklToXyz[1] = 0.0;
+  m_fromHklToXyz[2] = 0.0;
+  m_fromHklToXyz[3] = 0.0;
+  m_fromHklToXyz[4] = 1.0;
+  m_fromHklToXyz[5] = 0.0;
+  m_fromHklToXyz[6] = 0.0;
+  m_fromHklToXyz[7] = 0.0;
+  m_fromHklToXyz[8] = 1.0;
+
+  m_fromXyzToHkl[0] = 1.0;
+  m_fromXyzToHkl[1] = 0.0;
+  m_fromXyzToHkl[2] = 0.0;
+  m_fromXyzToHkl[3] = 0.0;
+  m_fromXyzToHkl[4] = 1.0;
+  m_fromXyzToHkl[5] = 0.0;
+  m_fromXyzToHkl[6] = 0.0;
+  m_fromXyzToHkl[7] = 0.0;
+  m_fromXyzToHkl[8] = 1.0;
+
+  // Set up the transformation matrix
+  setTransformationMatrices(workspace);
+
+  // Set up the angles
+  // set the angles for the two dimensions
+  auto angles =
+      MantidQt::API::getGridLineAnglesInRadian(m_fromHklToXyz, m_dimX, m_dimY);
+  m_angleX = static_cast<double>(angles.first);
+  m_angleY = static_cast<double>(angles.second);
+}
+
+void QwtScaleDrawNonOrthogonal::draw(QPainter *painter,
+                                     const QPalette &palette) const {
+  // Get the ScaleDiv element information, such as min_xyz and max_xyz
+  const auto &scaleDivEntries = scaleDiv();
+  const auto minXyz = scaleDivEntries.lowerBound();
+  const auto maxXyz = scaleDivEntries.upperBound();
+
+  // Get the bottom and left side of the screen in Xyz
+  const auto bottomInXyz = getScreenBottomInXyz();
+  const auto leftInXyz = getScreenLeftInXyz();
+
+  // Calculate the min_hkl and max_hkl
+  double minHkl = 0;
+  double maxHkl = 0;
+  if (m_screenDimension == ScreenDimension::X) {
+    minHkl = fromMixedCoordinatesToHkl(minXyz, bottomInXyz).x();
+    maxHkl = fromMixedCoordinatesToHkl(maxXyz, bottomInXyz).x();
+  } else if (m_screenDimension == ScreenDimension::Y) {
+    minHkl = fromMixedCoordinatesToHkl(leftInXyz, minXyz).y();
+    maxHkl = fromMixedCoordinatesToHkl(leftInXyz, maxXyz).y();
+  } else {
+    throw std::runtime_error(
+        "QwtScaleDrawNonOrthogonal: The provided screen "
+        "dimension is not valid. It has to be either X or Y.");
+  }
+
+  // Calculate appropriate tick mark locations and values in hkl coordinates.
+  const auto selectedAxis = m_screenDimension == ScreenDimension::X
+                                ? QwtPlot::xBottom
+                                : QwtPlot::yLeft;
+  const auto maxMajorSteps = m_plot->axisMaxMajor(selectedAxis);
+  const auto maxMinorSteps = m_plot->axisMaxMinor(selectedAxis);
+  const auto stepSize = m_plot->axisStepSize(selectedAxis);
+  const auto *axisScaleEngine = m_plot->axisScaleEngine(selectedAxis);
+  const auto scaleDivHkl = axisScaleEngine->divideScale(
+      minHkl, maxHkl, maxMajorSteps, maxMinorSteps, stepSize);
+
+  // Transform the scale for tick marks back to xyz. We need to pass the point
+  // where to draw in xyz.
+  const auto &majorTicksHkl = scaleDivHkl.ticks(QwtScaleDiv::MajorTick);
+  const auto &minorTicksHkl = scaleDivHkl.ticks(QwtScaleDiv::MinorTick);
+  QwtValueList majorTicksXyz;
+  QwtValueList minorTicksXyz;
+
+  if (m_screenDimension == ScreenDimension::X) {
+    for (auto &tick : majorTicksHkl) {
+      double majorTickXyz = static_cast<double>(fromXtickInHklToXyz(tick));
+      majorTicksXyz.push_back(majorTickXyz);
+    }
+    for (auto &tick : minorTicksHkl) {
+      double minorTickXyz = static_cast<double>(fromXtickInHklToXyz(tick));
+      minorTicksXyz.push_back(minorTickXyz);
+    }
+  } else {
+    for (auto &tick : majorTicksHkl) {
+      double majorTickXyz = static_cast<double>(fromYtickInHklToXyz(tick));
+      majorTicksXyz.push_back(majorTickXyz);
+    }
+    for (auto &tick : minorTicksHkl) {
+      double minorTickXyz = static_cast<double>(fromYtickInHklToXyz(tick));
+      minorTicksXyz.push_back(minorTickXyz);
+    }
+  }
+
+  // ***********
+  // Draw labels
+  // ***********
+
+  if (hasComponent(QwtAbstractScaleDraw::Labels)) {
+    painter->save();
+    painter->setPen(palette.color(QPalette::Text)); // ignore pen style
+    for (int i = 0; i < (int)majorTicksHkl.count(); ++i) {
+      drawLabelNonOrthogonal(painter, majorTicksHkl[i], majorTicksXyz[i]);
+    }
+
+    painter->restore();
+  }
+
+  // **************
+  // Draw tickmarks
+  // **************
+  if (hasComponent(QwtAbstractScaleDraw::Ticks)) {
+    painter->save();
+
+    QPen pen = painter->pen();
+    pen.setColor(palette.color(QPalette::Foreground));
+    painter->setPen(pen);
+
+    // Draw major ticks
+    for (int i = 0; i < (int)majorTicksXyz.count(); i++) {
+      drawTick(painter, majorTicksXyz[i], tickLength(QwtScaleDiv::MajorTick));
+    }
+
+    // Draw minor ticks
+    for (int i = 0; i < (int)minorTicksXyz.count(); i++) {
+      drawTick(painter, minorTicksXyz[i], tickLength(QwtScaleDiv::MinorTick));
+    }
+
+    painter->restore();
+  }
+
+  // **************
+  // Draw backbone
+  // **************
+  if (hasComponent(QwtAbstractScaleDraw::Backbone)) {
+    painter->save();
+    QPen pen = painter->pen();
+    pen.setColor(palette.color(QPalette::Foreground));
+    painter->setPen(pen);
+    drawBackbone(painter);
+    painter->restore();
+  }
+
+  // ****************
+  // Apply grid lines
+  // ****************
+  if (m_screenDimension == ScreenDimension::X) {
+    applyGridLinesX(majorTicksXyz);
+  } else {
+    applyGridLinesY(majorTicksXyz);
+  };
+}
+
+void QwtScaleDrawNonOrthogonal::drawLabelNonOrthogonal(QPainter *painter,
+                                                       double labelValue,
+                                                       double labelPos) const {
+  QwtText lbl = tickLabel(painter->font(), labelValue);
+  if (lbl.isEmpty())
+    return;
+
+  QPoint pos = labelPosition(labelPos);
+
+  QSize labelSize = lbl.textSize(painter->font());
+  if (labelSize.height() % 2)
+    labelSize.setHeight(labelSize.height() + 1);
+
+  const QwtMetricsMap metricsMap = QwtPainter::metricsMap();
+  QwtPainter::resetMetricsMap();
+
+  labelSize = metricsMap.layoutToDevice(labelSize);
+  pos = metricsMap.layoutToDevice(pos);
+
+  const QwtMatrix m = labelMatrix(pos, labelSize);
+
+  painter->save();
+  painter->setMatrix(m, true);
+  lbl.draw(painter, QRect(QPoint(0, 0), labelSize));
+  QwtPainter::setMetricsMap(metricsMap); // restore metrics map
+  painter->restore();
+}
+
+void QwtScaleDrawNonOrthogonal::applyGridLinesX(
+    const QwtValueList &majorTicksXyz) const {
+  auto angle = m_angleY;
+  m_gridPlot->updateXGridlines(majorTicksXyz, angle);
+  // We need the -1 since we the angle is defined in the mathematical positive
+  // sense but we are taking the angle against the y axis in the mathematical
+  // negative sense.
+}
+
+void QwtScaleDrawNonOrthogonal::applyGridLinesY(
+    const QwtValueList &majorTicksXyz) const {
+  auto angle = m_angleX;
+  m_gridPlot->updateYGridlines(majorTicksXyz, angle);
+}
+
+/** Tranform from plot coordinates to pixel coordinates
+ * @param xyz :: coordinate point in plot coordinates
+ * @return pixel coordinates
+*/
+QPoint QwtScaleDrawNonOrthogonal::fromXyzToScreen(QPointF xyz) const {
+  auto xScreen = m_plot->transform(QwtPlot::xBottom, xyz.x());
+  auto yScreen = m_plot->transform(QwtPlot::yLeft, xyz.y());
+  return QPoint(xScreen, yScreen);
+}
+
+/** Inverse transform: from pixels to plot coords
+ * @param screen :: location in pixels
+ * @return plot coordinates (float)
+*/
+QPointF QwtScaleDrawNonOrthogonal::fromScreenToXyz(QPoint screen) const {
+  auto x = m_plot->invTransform(QwtPlot::xBottom, screen.x());
+  auto y = m_plot->invTransform(QwtPlot::yLeft, screen.y());
+  return QPointF(x, y);
+}
+
+QPointF QwtScaleDrawNonOrthogonal::fromMixedCoordinatesToHkl(double x,
+                                                             double y) const {
+  Mantid::Kernel::VMD coords = m_slicePoint;
+  coords[m_dimX] = static_cast<Mantid::Kernel::VMD_t>(x);
+  coords[m_dimY] = static_cast<Mantid::Kernel::VMD_t>(y);
+  MantidQt::API::transformLookpointToWorkspaceCoordGeneric(
+      coords, m_fromXyzToHkl, m_dimX, m_dimY, m_missingDimension);
+  auto coord1 = coords[m_dimX];
+  auto coord2 = coords[m_dimY];
+  return QPointF(coord1, coord2);
+}
+
+double QwtScaleDrawNonOrthogonal::fromXtickInHklToXyz(double tick) const {
+  // First we convert everything to hkl. Here the m_dimY coordiante
+  // is in xyz, so we need to bring it to hkl
+  auto tickPointHkl = m_slicePoint;
+  tickPointHkl[m_dimX] = static_cast<float>(tick);
+  auto heightScreenInXyz =
+      m_plot->invTransform(QwtPlot::yLeft, m_plot->canvas()->height());
+  tickPointHkl[m_dimY] = static_cast<float>(heightScreenInXyz);
+
+  tickPointHkl[m_dimY] =
+      (tickPointHkl[m_dimY] -
+       m_fromHklToXyz[3 * m_dimY + m_dimX] * tickPointHkl[m_dimX] -
+       m_fromHklToXyz[3 * m_dimY + m_missingDimension] *
+           tickPointHkl[m_missingDimension]) /
+      m_fromHklToXyz[3 * m_dimY + m_dimY];
+
+  // convert from hkl to xyz
+  auto tickPointXyz = fromHklToXyz(tickPointHkl);
+  return tickPointXyz[m_dimX];
+}
+
+double QwtScaleDrawNonOrthogonal::fromYtickInHklToXyz(double tick) const {
+  // First we convert everything to hkl. Here the m_dimX coordiante
+  // is in xyz, so we need to bring it to hkl
+  auto tickPointHkl = m_slicePoint;
+  tickPointHkl[m_dimY] = static_cast<float>(tick);
+
+  auto widthScreenInXyz = m_plot->invTransform(QwtPlot::xBottom, 0);
+  tickPointHkl[m_dimX] = static_cast<float>(widthScreenInXyz);
+
+  tickPointHkl[m_dimX] =
+      (tickPointHkl[m_dimX] -
+       m_fromHklToXyz[3 * m_dimX + m_dimY] * tickPointHkl[m_dimY] -
+       m_fromHklToXyz[3 * m_dimX + m_missingDimension] *
+           tickPointHkl[m_missingDimension]) /
+      m_fromHklToXyz[3 * m_dimX + m_dimX];
+
+  // convert from hkl to xyz
+  auto tickPointXyz = fromHklToXyz(tickPointHkl);
+  return tickPointXyz[m_dimY];
+}
+
+Mantid::Kernel::VMD
+QwtScaleDrawNonOrthogonal::fromHklToXyz(const Mantid::Kernel::VMD &hkl) const {
+  Mantid::Kernel::VMD xyz(hkl);
+  for (int i = 0; i < 3; ++i) {
+    xyz[i] = 0;
+    for (int j = 0; j < 3; ++j) {
+      xyz[i] += m_fromHklToXyz[j + i * 3] * hkl[j];
+    }
+  }
+  return xyz;
+}
+
+void QwtScaleDrawNonOrthogonal::setTransformationMatrices(
+    Mantid::API::IMDWorkspace_sptr workspace) {
+  m_missingDimension =
+      MantidQt::API::getMissingHKLDimensionIndex(workspace, m_dimX, m_dimY);
+
+  if (MantidQt::API::isHKLDimensions(workspace, m_dimX, m_dimY)) {
+    Mantid::Kernel::DblMatrix skewMatrix(3, 3, true);
+    MantidQt::API::provideSkewMatrix(skewMatrix, workspace);
+    MantidQt::API::transformFromDoubleToCoordT(skewMatrix, m_fromXyzToHkl);
+    skewMatrix.Invert();
+    MantidQt::API::transformFromDoubleToCoordT(skewMatrix, m_fromHklToXyz);
+  }
+}
+
+qreal QwtScaleDrawNonOrthogonal::getScreenBottomInXyz() const {
+  auto screenBottomY = m_plot->canvas()->height();
+  QPoint screenBottom(0, screenBottomY);
+  return fromScreenToXyz(screenBottom).y();
+}
+
+qreal QwtScaleDrawNonOrthogonal::getScreenLeftInXyz() const {
+  QPoint screenLeft(0, 0);
+  return fromScreenToXyz(screenLeft).x();
+}
+
+void QwtScaleDrawNonOrthogonal::updateSlicePoint(
+    Mantid::Kernel::VMD newSlicepoint) {
+  m_slicePoint = newSlicepoint;
+}
diff --git a/MantidQt/SliceViewer/src/SliceViewer.cpp b/MantidQt/SliceViewer/src/SliceViewer.cpp
index b58a99e996165e71230e6ac98b3978a678e8c203..4d98448e0c3664e3f8b0c32120c27ff155ae11c2 100644
--- a/MantidQt/SliceViewer/src/SliceViewer.cpp
+++ b/MantidQt/SliceViewer/src/SliceViewer.cpp
@@ -3,8 +3,10 @@
 #include <sstream>
 #include <vector>
 #include <boost/make_shared.hpp>
-
+#include "MantidKernel/Strings.h"
+#include <boost/math/special_functions/fpclassify.hpp>
 #include "MantidKernel/UsageService.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/CoordTransform.h"
 #include "MantidAPI/IMDHistoWorkspace.h"
 #include "MantidAPI/IMDIterator.h"
@@ -20,13 +22,14 @@
 #include "MantidGeometry/MDGeometry/MDHistoDimension.h"
 #include "MantidGeometry/MDGeometry/MDTypes.h"
 #include "MantidKernel/ReadLock.h"
-#include "MantidQtAPI/FileDialogHandler.h"
 #include "MantidQtAPI/PlotAxis.h"
 #include "MantidQtAPI/MantidDesktopServices.h"
 #include "MantidQtAPI/MdSettings.h"
 #include "MantidQtAPI/SignalBlocker.h"
 #include "MantidQtAPI/SignalRange.h"
 #include "MantidQtAPI/TSVSerialiser.h"
+#include "MantidQtAPI/NonOrthogonal.h"
+#include "MantidQtAPI/QwtRasterDataMDNonOrthogonal.h"
 #include "MantidQtSliceViewer/SliceViewer.h"
 #include "MantidQtSliceViewer/CustomTools.h"
 #include "MantidQtSliceViewer/DimensionSliceWidget.h"
@@ -78,15 +81,23 @@ const QString SliceViewer::NumEventsNormalizationKey = "# Events";
 /** Constructor */
 SliceViewer::SliceViewer(QWidget *parent)
     : QWidget(parent), m_ws(), m_firstWorkspaceOpen(false), m_dimensions(),
-      m_data(NULL), m_X(), m_Y(), m_dimX(0), m_dimY(1), m_logColor(false),
+      m_data(nullptr), m_X(), m_Y(), m_dimX(0), m_dimY(1), m_logColor(false),
       m_fastRender(true), m_rebinMode(false), m_rebinLocked(true),
       m_mdSettings(new MantidQt::API::MdSettings()), m_logger("SliceViewer"),
+      m_firstNonOrthogonalWorkspaceOpen(true), m_nonOrthogonalDefault(false),
+      m_oldDimNonOrthogonal(false), m_canSwitchScales(false),
       m_peaksPresenter(boost::make_shared<CompositePeaksPresenter>(this)),
       m_proxyPeaksPresenter(
           boost::make_shared<ProxyCompositePeaksPresenter>(m_peaksPresenter)),
-      m_peaksSliderWidget(NULL) {
+      m_peaksSliderWidget(NULL), m_lastRatioState(Guess) {
 
   ui.setupUi(this);
+  std::string enableNonOrthogonal;
+  Kernel::ConfigService::Instance().getValue("sliceviewer.nonorthogonal",
+                                             enableNonOrthogonal);
+  if (enableNonOrthogonal == "true") {
+    m_nonOrthogonalDefault = true;
+  }
 
   m_inf = std::numeric_limits<double>::infinity();
 
@@ -103,10 +114,9 @@ SliceViewer::SliceViewer(QWidget *parent)
                    this, SLOT(colorRangeChanged()));
 
   // ---- Set the color map on the data ------
-  m_data = new API::QwtRasterDataMD();
+  m_data = Kernel::make_unique<API::QwtRasterDataMD>();
   m_spect->setColorMap(m_colorBar->getColorMap());
   m_plot->autoRefresh();
-
   // Make the splitter use the minimum size for the controls and not stretch out
   ui.splitter->setStretchFactor(0, 0);
   ui.splitter->setStretchFactor(1, 1);
@@ -153,6 +163,9 @@ SliceViewer::SliceViewer(QWidget *parent)
 
   updateDisplay();
 
+  m_nonOrthogonalOverlay = new NonOrthogonalOverlay(m_plot, m_plot->canvas());
+  m_nonOrthogonalOverlay->disable();
+
   // -------- Line Overlay ----------------
   m_lineOverlay = new LineOverlay(m_plot, m_plot->canvas());
   m_lineOverlay->setShown(false);
@@ -184,10 +197,10 @@ void SliceViewer::updateAspectRatios() {
 
   if (m_aspectRatioType == Guess) {
     /* Lock aspect ratios, if that feature has been enabled, and if the plot x
- * and
- * y units
- * are suitable.
-*/
+    * and
+    * y units
+    * are suitable.
+    */
     lockAspectRatios =
         m_X->getMDUnits().isQUnit() && m_Y->getMDUnits().isQUnit();
 
@@ -208,7 +221,6 @@ void SliceViewer::updateAspectRatios() {
 /// Destructor
 SliceViewer::~SliceViewer() {
   saveSettings();
-  delete m_data;
   delete m_rescaler;
   // Don't delete Qt objects, I think these are auto-deleted
 }
@@ -542,6 +554,7 @@ void SliceViewer::initMenus() {
 //------------------------------------------------------------------------------
 /** Intialize the zooming/panning tools */
 void SliceViewer::initZoomer() {
+
   QwtPlotPicker *zoomer = new QwtPlotPicker(m_plot->canvas());
   zoomer->setSelectionFlags(QwtPicker::RectSelection |
                             QwtPicker::DragSelection);
@@ -564,7 +577,6 @@ void SliceViewer::initZoomer() {
   // Hook-up listener to rescaled event
   QObject::connect(magnif, SIGNAL(rescaled(double)), this,
                    SLOT(magnifierRescaled(double)));
-
   // Pan using the right mouse button + drag
   QwtPlotPanner *panner = new QwtPlotPanner(m_plot->canvas());
   panner->setMouseButton(Qt::RightButton);
@@ -581,9 +593,9 @@ void SliceViewer::initZoomer() {
 
 //------------------------------------------------------------------------------
 /** Programmatically show/hide the controls (sliders etc)
- *
- * @param visible :: true if you want to show the controls.
- */
+*
+* @param visible :: true if you want to show the controls.
+*/
 void SliceViewer::showControls(bool visible) {
   ui.frmControls->setVisible(visible);
 }
@@ -681,16 +693,51 @@ void SliceViewer::updateDimensionSliceWidgets() {
   }
 }
 
+//------------------------------------------
+void SliceViewer::switchQWTRaster(bool useNonOrthogonal) {
+  m_coordinateTransform = createCoordinateTransform(m_ws, m_dimX, m_dimY);
+
+  if (useNonOrthogonal && ui.btnNonOrthogonalToggle->isChecked()) {
+    m_data = Kernel::make_unique<API::QwtRasterDataMDNonOrthogonal>();
+    applyNonOrthogonalAxisScaleDraw();
+  } else {
+    applyOrthogonalAxisScaleDraw();
+    m_data = Kernel::make_unique<API::QwtRasterDataMD>();
+  }
+
+  m_coordinateTransform = createCoordinateTransform(m_ws, m_dimX, m_dimY);
+  m_data->setWorkspace(m_ws);
+  this->setTransparentZeros(false);
+
+  if (m_firstNonOrthogonalWorkspaceOpen && m_nonOrthogonalDefault) {
+    m_firstNonOrthogonalWorkspaceOpen = false;
+    ui.btnNonOrthogonalToggle->toggle();
+  }
+  updateDisplay();
+}
+
 //------------------------------------------------------------------------------
 /** Set the displayed workspace. Updates UI.
- *
- * @param ws :: IMDWorkspace to show.
- */
+*
+* @param ws :: IMDWorkspace to show.
+*/
 void SliceViewer::setWorkspace(Mantid::API::IMDWorkspace_sptr ws) {
   m_ws = ws;
+
+  m_coordinateTransform = createCoordinateTransform(ws, m_dimX, m_dimY);
+  // disconnect and reconnect here
+  QObject::connect(this, SIGNAL(changedShownDim(size_t, size_t)), this,
+                   SLOT(checkForHKLDimension()));
+  QObject::connect(this, SIGNAL(changedShownDim(size_t, size_t)), this,
+                   SLOT(switchAxis()));
+  QObject::connect(ui.btnNonOrthogonalToggle, SIGNAL(toggled(bool)), this,
+                   SLOT(switchQWTRaster(bool)));
+  QObject::connect(ui.btnNonOrthogonalToggle, SIGNAL(toggled(bool)), this,
+                   SLOT(setNonOrthogonalbtn()));
+  m_firstNonOrthogonalWorkspaceOpen = true;
   m_data->setWorkspace(ws);
   m_plot->setWorkspace(ws);
-
+  autoRebinIfRequired();
   // Set the normalization appropriate
   this->setNormalization(ws->displayNormalization(), false);
 
@@ -797,20 +844,20 @@ void SliceViewer::setWorkspace(Mantid::API::IMDWorkspace_sptr ws) {
   // Enable peaks overlays according to the dimensionality and the displayed
   // dimensions.
   enablePeakOverlaysIfAppropriate();
-
   // Send out a signal
   emit changedShownDim(m_dimX, m_dimY);
+  m_canSwitchScales = true;
 }
 
 //------------------------------------------------------------------------------
 /** Set the workspace to view using its name.
- * The workspace should be a MDHistoWorkspace or a MDEventWorkspace,
- * with at least 2 dimensions.
- *
- * @param wsName :: name of the MDWorkspace to look for
- * @throw std::runtime_error if the workspace is not found or is a
- *MatrixWorkspace
- */
+* The workspace should be a MDHistoWorkspace or a MDEventWorkspace,
+* with at least 2 dimensions.
+*
+* @param wsName :: name of the MDWorkspace to look for
+* @throw std::runtime_error if the workspace is not found or is a
+*MatrixWorkspace
+*/
 void SliceViewer::setWorkspace(const QString &wsName) {
   IMDWorkspace_sptr ws = boost::dynamic_pointer_cast<IMDWorkspace>(
       AnalysisDataService::Instance().retrieve(wsName.toStdString()));
@@ -829,9 +876,9 @@ Mantid::API::IMDWorkspace_sptr SliceViewer::getWorkspace() { return m_ws; }
 
 //------------------------------------------------------------------------------
 /** Load a color map from a file
- *
- * @param filename :: file to open; empty to ask via a dialog box.
- */
+*
+* @param filename :: file to open; empty to ask via a dialog box.
+*/
 void SliceViewer::loadColorMap(QString filename) {
   QString fileselection;
   if (filename.isEmpty()) {
@@ -856,9 +903,9 @@ void SliceViewer::loadColorMap(QString filename) {
 
 //------------------------------------------------------------------------------
 /** Automatically sets the min/max of the color scale,
- * using the limits in the entire data set of the workspace
- * (every bin, even those not currently visible).
- */
+* using the limits in the entire data set of the workspace
+* (every bin, even those not currently visible).
+*/
 void SliceViewer::setColorScaleAutoFull() {
   this->findRangeFull();
   m_colorBar->setViewRange(m_colorRangeFull);
@@ -867,10 +914,10 @@ void SliceViewer::setColorScaleAutoFull() {
 
 //------------------------------------------------------------------------------
 /** Automatically sets the min/max of the color scale,
- * using the limits in the data that is currently visible
- * in the plot (only the bins in this slice and within the
- * view limits)
- */
+* using the limits in the data that is currently visible
+* in the plot (only the bins in this slice and within the
+* view limits)
+*/
 void SliceViewer::setColorScaleAutoSlice() {
   this->findRangeSlice();
   m_colorBar->setViewRange(m_colorRangeSlice);
@@ -907,9 +954,9 @@ void SliceViewer::colorRangeChanged() {
 
 //------------------------------------------------------------------------------
 /** Set whether to display 0 signal as "transparent" color.
- *
- * @param transparent :: true if you want zeros to be transparent.
- */
+*
+* @param transparent :: true if you want zeros to be transparent.
+*/
 void SliceViewer::setTransparentZeros(bool transparent) {
   SignalBlocker<QAction> transparentZeros(m_actionTransparentZeros);
   transparentZeros->setChecked(transparent);
@@ -933,9 +980,9 @@ void SliceViewer::changeNormalizationNumEvents() {
 }
 
 /**
- * @brief Slot to handle change in normalization kicked-off from the combo box.
- * @param normalizationKey : Text key for type of normalization switched to.
- */
+* @brief Slot to handle change in normalization kicked-off from the combo box.
+* @param normalizationKey : Text key for type of normalization switched to.
+*/
 void SliceViewer::onNormalizationChanged(const QString &normalizationKey) {
   if (normalizationKey == SliceViewer::NoNormalizationKey) {
     changeNormalizationNone();
@@ -948,11 +995,11 @@ void SliceViewer::onNormalizationChanged(const QString &normalizationKey) {
 
 //------------------------------------------------------------------------------
 /** Set the normalization mode for viewing the data
- *
- * @param norm :: MDNormalization enum. 0=none; 1=volume; 2=# of events
- * @param update :: update the displayed image. If false, just sets it and shows
- *the checkboxes.
- */
+*
+* @param norm :: MDNormalization enum. 0=none; 1=volume; 2=# of events
+* @param update :: update the displayed image. If false, just sets it and shows
+*the checkboxes.
+*/
 void SliceViewer::setNormalization(Mantid::API::MDNormalization norm,
                                    bool update) {
 
@@ -991,12 +1038,12 @@ Mantid::API::MDNormalization SliceViewer::getNormalization() const {
 
 //------------------------------------------------------------------------------
 /** Set the thickness (above and below the plane) for dynamic rebinning.
- *
- * @param dim :: index of the dimension to adjust
- * @param thickness :: thickness to set, in units of the dimension.
- * @throw runtime_error if the dimension index is invalid or the thickness is <=
- *0.0.
- */
+*
+* @param dim :: index of the dimension to adjust
+* @param thickness :: thickness to set, in units of the dimension.
+* @throw runtime_error if the dimension index is invalid or the thickness is <=
+*0.0.
+*/
 void SliceViewer::setRebinThickness(int dim, double thickness) {
   if (dim < 0 || dim >= static_cast<int>(m_dimWidgets.size()))
     throw std::runtime_error(
@@ -1009,11 +1056,11 @@ void SliceViewer::setRebinThickness(int dim, double thickness) {
 
 //------------------------------------------------------------------------------
 /** Set the number of bins for dynamic rebinning.
- *
- * @param xBins :: number of bins in the viewed X direction
- * @param yBins :: number of bins in the viewed Y direction
- * @throw runtime_error if the number of bins is < 1
- */
+*
+* @param xBins :: number of bins in the viewed X direction
+* @param yBins :: number of bins in the viewed Y direction
+* @throw runtime_error if the number of bins is < 1
+*/
 void SliceViewer::setRebinNumBins(int xBins, int yBins) {
   if (xBins < 1 || yBins < 1)
     throw std::runtime_error(
@@ -1024,13 +1071,13 @@ void SliceViewer::setRebinNumBins(int xBins, int yBins) {
 
 //------------------------------------------------------------------------------
 /** Sets the SliceViewer in dynamic rebin mode.
- * In this mode, the current view area (see setXYLimits()) is used as the
- * limits to rebin.
- * See setRebinNumBins() to adjust the number of bins in the X/Y dimensions.
- * See setRebinThickness() to adjust the thickness in other dimensions.
- *
- * @param mode :: true for rebinning mode
- */
+* In this mode, the current view area (see setXYLimits()) is used as the
+* limits to rebin.
+* See setRebinNumBins() to adjust the number of bins in the X/Y dimensions.
+* See setRebinThickness() to adjust the thickness in other dimensions.
+*
+* @param mode :: true for rebinning mode
+*/
 void SliceViewer::setRebinMode(bool mode) {
   // The events associated with these controls will trigger a re-draw
   m_syncRebinMode->toggle(mode);
@@ -1038,9 +1085,9 @@ void SliceViewer::setRebinMode(bool mode) {
 
 //------------------------------------------------------------------------------
 /** When in dynamic rebinning mode, this refreshes the rebinned area to be the
- * currently viewed area. See setXYLimits(), setRebinNumBins(),
- * setRebinThickness()
- */
+* currently viewed area. See setXYLimits(), setRebinNumBins(),
+* setRebinThickness()
+*/
 void SliceViewer::refreshRebin() { this->rebinParamsChanged(); }
 
 //------------------------------------------------------------------------------
@@ -1070,9 +1117,9 @@ void SliceViewer::LineMode_toggled(bool checked) {
 
 //------------------------------------------------------------------------------
 /** Toggle "line-drawing" mode (to draw 1D lines using the mouse)
- *
- * @param lineMode :: True to go into line mode, False to exit it.
- */
+*
+* @param lineMode :: True to go into line mode, False to exit it.
+*/
 void SliceViewer::toggleLineMode(bool lineMode) {
   // This should send events to start line mode
   m_syncLineMode->toggle(lineMode);
@@ -1131,6 +1178,7 @@ void SliceViewer::RebinMode_toggled(bool checked) {
     this->m_data->setOverlayWorkspace(m_overlayWS);
     // Set the normalization from the original workspace
     this->setNormalization(m_ws->displayNormalization());
+    m_overlayWSOutline->setShown(false);
   } else {
     setIconFromString(ui.btnRebinMode, g_iconRebinOn, QIcon::Normal, QIcon::On);
     // Start the rebin
@@ -1147,14 +1195,17 @@ void SliceViewer::zoomInSlot() { this->zoomBy(1.1); }
 void SliceViewer::zoomOutSlot() { this->zoomBy(1.0 / 1.1); }
 
 /** Slot called when zooming using QwtPlotZoomer (rubber-band method)
- *
- * @param rect :: rectangle to zoom to
- */
+*
+* @param rect :: rectangle to zoom to
+*/
 void SliceViewer::zoomRectSlot(const QwtDoubleRect &rect) {
   if ((rect.width() == 0) || (rect.height() == 0))
     return;
   this->setXYLimits(rect.left(), rect.right(), rect.top(), rect.bottom());
   autoRebinIfRequired();
+  if (ui.btnNonOrthogonalToggle->isChecked()) {
+    adjustSize();
+  }
 }
 
 /// Slot for opening help page
@@ -1179,10 +1230,10 @@ void SliceViewer::helpPeaksViewer() {
 
 //------------------------------------------------------------------------------
 /** Automatically resets the zoom view to full axes.
- * This will reset the XY limits to the full range of the workspace.
- * Use zoomBy() or setXYLimits() to modify the view range.
- * This corresponds to the "View Extents" button.
- */
+* This will reset the XY limits to the full range of the workspace.
+* Use zoomBy() or setXYLimits() to modify the view range.
+* This corresponds to the "View Extents" button.
+*/
 void SliceViewer::resetZoom() {
   // Reset the 2 axes to full scale
   resetAxis(m_spect->xAxis(), m_X);
@@ -1191,6 +1242,9 @@ void SliceViewer::resetZoom() {
   m_plot->replot();
   autoRebinIfRequired();
   updatePeaksOverlay();
+  if (ui.btnNonOrthogonalToggle->isChecked()) {
+    adjustSize();
+  }
 }
 
 //------------------------------------------------------------------------------
@@ -1231,12 +1285,12 @@ void SliceViewer::loadColorMapSlot() { this->loadColorMap(QString()); }
 
 //------------------------------------------------------------------------------
 /** Grab the 2D view as an image. The image is rendered at the current window
- * size, with the color scale but without the text boxes for changing them.
- *
- * See also saveImage() and copyImageToClipboard()
- *
- * @return QPixmap containing the image.
- */
+* size, with the color scale but without the text boxes for changing them.
+*
+* See also saveImage() and copyImageToClipboard()
+*
+* @return QPixmap containing the image.
+*/
 QPixmap SliceViewer::getImage() {
 
   // Switch to full resolution rendering
@@ -1261,7 +1315,7 @@ QPixmap SliceViewer::getImage() {
 
 //------------------------------------------------------------------------------
 /** Copy the rendered 2D image to the clipboard
- */
+*/
 void SliceViewer::copyImageToClipboard() {
   // Create the image
   QPixmap pix = this->getImage();
@@ -1270,11 +1324,11 @@ void SliceViewer::copyImageToClipboard() {
 }
 
 /**
- * Adds .png extension if not already included
- *
- * @param fname :: a file name to save an (png) image
- * @return input file name with '.png' appended if needed
- **/
+* Adds .png extension if not already included
+*
+* @param fname :: a file name to save an (png) image
+* @return input file name with '.png' appended if needed
+**/
 QString SliceViewer::ensurePngExtension(const QString &fname) const {
   const QString goodExt = "png";
 
@@ -1287,15 +1341,15 @@ QString SliceViewer::ensurePngExtension(const QString &fname) const {
 
 //------------------------------------------------------------------------------
 /** Save the rendered 2D slice to an image file.
- *
- * @param filename :: full path to the file to save, including extension
- *        (e.g. .png). If not specified or empty, then a dialog will prompt
- *        the user to pick a file.
- */
+*
+* @param filename :: full path to the file to save, including extension
+*        (e.g. .png). If not specified or empty, then a dialog will prompt
+*        the user to pick a file.
+*/
 void SliceViewer::saveImage(const QString &filename) {
   QString fileselection;
   if (filename.isEmpty()) {
-    fileselection = MantidQt::API::FileDialogHandler::getSaveFileName(
+    fileselection = QFileDialog::getSaveFileName(
         this, tr("Pick a file to which to save the image"),
         QFileInfo(m_lastSavedFile).absoluteFilePath(),
         tr("PNG files(*.png *.png)"));
@@ -1319,10 +1373,10 @@ void SliceViewer::saveImage(const QString &filename) {
 //==============================================================================
 //==============================================================================
 /** Zoom in or out, keeping the center of the plot in the same position.
- *
- * @param factor :: double, if > 1 : zoom in by this factor.
- *                  if < 1 : it will zoom out.
- */
+*
+* @param factor :: double, if > 1 : zoom in by this factor.
+*                  if < 1 : it will zoom out.
+*/
 void SliceViewer::zoomBy(double factor) {
   QwtDoubleInterval xint = this->getXLimits();
   QwtDoubleInterval yint = this->getYLimits();
@@ -1346,13 +1400,13 @@ void SliceViewer::zoomBy(double factor) {
 
 //------------------------------------------------------------------------------
 /** Manually set the center of the plot, in X Y coordinates.
- * This keeps the plot the same size as previously.
- * Use setXYLimits() to modify the size of the plot by setting the X/Y edges,
- * or you can use zoomBy() to zoom in/out
- *
- * @param x :: new position of the center in X
- * @param y :: new position of the center in Y
- */
+* This keeps the plot the same size as previously.
+* Use setXYLimits() to modify the size of the plot by setting the X/Y edges,
+* or you can use zoomBy() to zoom in/out
+*
+* @param x :: new position of the center in X
+* @param y :: new position of the center in Y
+*/
 void SliceViewer::setXYCenter(double x, double y) {
   QwtDoubleInterval xint = this->getXLimits();
   QwtDoubleInterval yint = this->getYLimits();
@@ -1365,10 +1419,10 @@ void SliceViewer::setXYCenter(double x, double y) {
 
 //------------------------------------------------------------------------------
 /** Reset the axis and scale it
- *
- * @param axis :: int for X or Y
- * @param dim :: dimension to show
- */
+*
+* @param axis :: int for X or Y
+* @param dim :: dimension to show
+*/
 void SliceViewer::resetAxis(int axis, const IMDDimension_const_sptr &dim) {
   m_plot->setAxisScale(axis, dim->getMinimum(), dim->getMaximum());
   m_plot->setAxisTitle(axis, API::PlotAxis(*dim).title());
@@ -1476,10 +1530,10 @@ void SliceViewer::findRangeSlice() {
 
 //------------------------------------------------------------------------------
 /** Slot to show the mouse info at the mouse position
- *
- * @param x :: position of the mouse in plot coords
- * @param y :: position of the mouse in plot coords
- */
+*
+* @param x :: position of the mouse in plot coords
+* @param y :: position of the mouse in plot coords
+*/
 void SliceViewer::showInfoAt(double x, double y) {
   // Show the coordinates in the viewed workspace
   if (!m_ws)
@@ -1487,12 +1541,21 @@ void SliceViewer::showInfoAt(double x, double y) {
   VMD coords(m_ws->getNumDims());
   for (size_t d = 0; d < m_ws->getNumDims(); d++)
     coords[d] = VMD_t(m_dimWidgets[d]->getSlicePoint());
+
   coords[m_dimX] = VMD_t(x);
   coords[m_dimY] = VMD_t(y);
+
+  if (ui.btnNonOrthogonalToggle->isChecked()) {
+    // Perform non-orthogonal correction if required
+    auto missingHKLDim = API::getMissingHKLDimensionIndex(m_ws, m_dimX, m_dimY);
+    m_coordinateTransform->transform(coords, m_dimX, m_dimY, missingHKLDim);
+  }
+
   signal_t signal =
       m_ws->getSignalWithMaskAtVMD(coords, this->m_data->getNormalization());
-  ui.lblInfoX->setText(QString::number(x, 'g', 4));
-  ui.lblInfoY->setText(QString::number(y, 'g', 4));
+
+  ui.lblInfoX->setText(QString::number(coords[m_dimX], 'g', 4));
+  ui.lblInfoY->setText(QString::number(coords[m_dimY], 'g', 4));
   ui.lblInfoSignal->setText(QString::number(signal, 'g', 4));
 
   // Now show the coords in the original workspace
@@ -1503,7 +1566,6 @@ void SliceViewer::showInfoAt(double x, double y) {
     if (toOrig) {
       // Transform the coordinates
       VMD orig = toOrig->applyVMD(coords);
-
       QString text;
       for (size_t d = 0; d < origWS->getNumDims(); d++) {
         text += QString::fromStdString(origWS->getDimension(d)->getName());
@@ -1526,8 +1588,6 @@ void SliceViewer::updateDisplay(bool resetAxes) {
   size_t oldX = m_dimX;
   size_t oldY = m_dimY;
 
-  m_dimX = 0;
-  m_dimY = 1;
   std::vector<coord_t> slicePoint;
 
   for (size_t d = 0; d < m_ws->getNumDims(); d++) {
@@ -1558,7 +1618,6 @@ void SliceViewer::updateDisplay(bool resetAxes) {
     // The dimensionality has changed. It might no longer be possible to plot
     // peaks.
     enablePeakOverlaysIfAppropriate();
-
     // Transform the peak overlays according to the new plotting.
     m_peaksPresenter->changeShownDim();
 
@@ -1572,10 +1631,6 @@ void SliceViewer::updateDisplay(bool resetAxes) {
   // Set the color range
   m_data->setRange(m_colorBar->getViewRange());
 
-  //  m_colorBar->setColorMap(m_colorRange, m_colorMap);
-  //  m_plot->setAxisScale(QwtPlot::yRight, m_colorRange.minValue(),
-  //  m_colorRange.maxValue() );
-
   // Is the overlay workspace visible at all from this slice point?
   if (m_overlayWS) {
     bool overlayInSlice = true;
@@ -1598,15 +1653,21 @@ void SliceViewer::updateDisplay(bool resetAxes) {
 
   // Send out a signal
   emit changedSlicePoint(m_slicePoint);
+  bool canShowSkewedWS = API::isHKLDimensions(m_ws, m_dimX, m_dimY);
+  if (canShowSkewedWS && ui.btnNonOrthogonalToggle->isChecked()) {
+    m_nonOrthAxis0->updateSlicePoint(m_slicePoint);
+    m_nonOrthAxis1->updateSlicePoint(m_slicePoint);
+    m_plot->update();
+  }
 }
 
 //------------------------------------------------------------------------------
 /** The user changed the shown dimension somewhere.
- *
- * @param index :: index of the dimension
- * @param dim :: shown dimension, 0=X, 1=Y, -1 sliced
- * @param oldDim :: previous shown dimension, 0=X, 1=Y, -1 sliced
- */
+*
+* @param index :: index of the dimension
+* @param dim :: shown dimension, 0=X, 1=Y, -1 sliced
+* @param oldDim :: previous shown dimension, 0=X, 1=Y, -1 sliced
+*/
 void SliceViewer::changedShownDim(int index, int dim, int oldDim) {
   if (dim >= 0) {
     // Swap from X to Y
@@ -1634,13 +1695,34 @@ void SliceViewer::changedShownDim(int index, int dim, int oldDim) {
   emit changedShownDim(m_dimX, m_dimY);
 }
 
+void SliceViewer::checkForHKLDimension() {
+
+  if (API::requiresSkewMatrix(m_ws)) {
+    m_coordinateTransform->checkDimensionsForHKL(m_ws, m_dimX, m_dimY);
+    auto isHKL = API::isHKLDimensions(m_ws, m_dimX, m_dimY);
+    auto isNonOrthogonalQWTRasterData =
+        dynamic_cast<API::QwtRasterDataMDNonOrthogonal *>(m_data.get()) !=
+        nullptr;
+    // 4 cases to consider
+    // isHKL true and is isNonOrthgonalQWT true -> do nothing
+    // isHKL false and isNonOrthgonalQWT false -> do nothing
+    // isHKL false and isNonOrthgonalQWT true -> switch out new QWTRasterData
+    // isHKL true and isNonOrthgonalQWT false -> switch out new
+    // QWTRasterDataNonorthogonal
+    if (isHKL ^ isNonOrthogonalQWTRasterData) {
+      const auto useNonOrthogonal = isHKL;
+      switchQWTRaster(useNonOrthogonal);
+    }
+  }
+  emit setNonOrthogonalbtn();
+}
 //==============================================================================
 //================================ PYTHON METHODS ==============================
 //==============================================================================
 
 /** @return the name of the workspace selected, or a blank string
- * if no workspace is set.
- */
+* if no workspace is set.
+*/
 QString SliceViewer::getWorkspaceName() const {
   if (m_ws)
     return QString::fromStdString(m_ws->getName());
@@ -1650,26 +1732,26 @@ QString SliceViewer::getWorkspaceName() const {
 
 //------------------------------------------------------------------------------
 /** @return the index of the dimension that is currently
- * being shown as the X axis of the plot.
- */
+* being shown as the X axis of the plot.
+*/
 int SliceViewer::getDimX() const { return int(m_dimX); }
 
 /** @return the index of the dimension that is currently
- * being shown as the Y axis of the plot.
- */
+* being shown as the Y axis of the plot.
+*/
 int SliceViewer::getDimY() const { return int(m_dimY); }
 
 //------------------------------------------------------------------------------
 /** Set the index of the dimensions that will be shown as
- * the X and Y axis of the plot.
- * You cannot set both axes to be the same.
- *
- * To be called from Python, primarily.
- *
- * @param indexX :: index of the X dimension, from 0 to NDims-1.
- * @param indexY :: index of the Y dimension, from 0 to NDims-1.
- * @throw std::invalid_argument if an index is invalid or repeated.
- */
+* the X and Y axis of the plot.
+* You cannot set both axes to be the same.
+*
+* To be called from Python, primarily.
+*
+* @param indexX :: index of the X dimension, from 0 to NDims-1.
+* @param indexY :: index of the Y dimension, from 0 to NDims-1.
+* @throw std::invalid_argument if an index is invalid or repeated.
+*/
 void SliceViewer::setXYDim(int indexX, int indexY) {
   if (indexX >= int(m_dimWidgets.size()) || indexX < 0)
     throw std::invalid_argument("There is no dimension # " +
@@ -1699,13 +1781,13 @@ void SliceViewer::setXYDim(int indexX, int indexY) {
 
 //------------------------------------------------------------------------------
 /** Set the dimensions that will be shown as the X and Y axes
- *
- * @param dimX :: name of the X dimension. Must match the workspace dimension
- *names.
- * @param dimY :: name of the Y dimension. Must match the workspace dimension
- *names.
- * @throw std::runtime_error if the dimension name is not found.
- */
+*
+* @param dimX :: name of the X dimension. Must match the workspace dimension
+*names.
+* @param dimY :: name of the Y dimension. Must match the workspace dimension
+*names.
+* @throw std::runtime_error if the dimension name is not found.
+*/
 void SliceViewer::setXYDim(const QString &dimX, const QString &dimY) {
   if (!m_ws)
     return;
@@ -1716,14 +1798,14 @@ void SliceViewer::setXYDim(const QString &dimX, const QString &dimY) {
 
 //------------------------------------------------------------------------------
 /** Sets the slice point in the given dimension:
- * that is, what is the position of the plane in that dimension
- *
- * @param dim :: index of the dimension to change
- * @param value :: value of the slice point, in the units of the given
- *dimension.
- *        This should be within the range of min/max for that dimension.
- * @throw std::invalid_argument if the index is invalid
- */
+* that is, what is the position of the plane in that dimension
+*
+* @param dim :: index of the dimension to change
+* @param value :: value of the slice point, in the units of the given
+*dimension.
+*        This should be within the range of min/max for that dimension.
+* @throw std::invalid_argument if the index is invalid
+*/
 void SliceViewer::setSlicePoint(int dim, double value) {
   if (dim >= int(m_dimWidgets.size()) || dim < 0)
     throw std::invalid_argument("There is no dimension # " +
@@ -1733,12 +1815,12 @@ void SliceViewer::setSlicePoint(int dim, double value) {
 
 //------------------------------------------------------------------------------
 /** Returns the slice point in the given dimension
- *
- * @param dim :: index of the dimension
- * @return slice point for that dimension. Value has no significance for the
- *         X or Y display dimensions.
- * @throw std::invalid_argument if the index is invalid
- */
+*
+* @param dim :: index of the dimension
+* @return slice point for that dimension. Value has no significance for the
+*         X or Y display dimensions.
+* @throw std::invalid_argument if the index is invalid
+*/
 double SliceViewer::getSlicePoint(int dim) const {
   if (dim >= int(m_dimWidgets.size()) || dim < 0)
     throw std::invalid_argument("There is no dimension # " +
@@ -1748,14 +1830,14 @@ double SliceViewer::getSlicePoint(int dim) const {
 
 //------------------------------------------------------------------------------
 /** Sets the slice point in the given dimension:
- * that is, what is the position of the plane in that dimension
- *
- * @param dim :: name of the dimension to change
- * @param value :: value of the slice point, in the units of the given
- *dimension.
- *        This should be within the range of min/max for that dimension.
- * @throw std::runtime_error if the name is not found in the workspace
- */
+* that is, what is the position of the plane in that dimension
+*
+* @param dim :: name of the dimension to change
+* @param value :: value of the slice point, in the units of the given
+*dimension.
+*        This should be within the range of min/max for that dimension.
+* @throw std::runtime_error if the name is not found in the workspace
+*/
 void SliceViewer::setSlicePoint(const QString &dim, double value) {
   if (!m_ws)
     return;
@@ -1765,12 +1847,12 @@ void SliceViewer::setSlicePoint(const QString &dim, double value) {
 
 //------------------------------------------------------------------------------
 /** Returns the slice point in the given dimension
- *
- * @param dim :: name of the dimension
- * @return slice point for that dimension. Value has no significance for the
- *         X or Y display dimensions.
- * @throw std::runtime_error if the name is not found in the workspace
- */
+*
+* @param dim :: name of the dimension
+* @return slice point for that dimension. Value has no significance for the
+*         X or Y display dimensions.
+* @throw std::runtime_error if the name is not found in the workspace
+*/
 double SliceViewer::getSlicePoint(const QString &dim) const {
   if (!m_ws)
     return 0;
@@ -1780,16 +1862,16 @@ double SliceViewer::getSlicePoint(const QString &dim) const {
 
 //------------------------------------------------------------------------------
 /** Set the color scale limits and log mode via a method call.
- *  Here for backwards compatibility, setColorScale(double min, double max, int
- *type)
- *  should be used instead.
- *
- * @param min :: minimum value corresponding to the lowest color on the map
- * @param max :: maximum value corresponding to the highest color on the map
- * @param log :: true for a log color scale, false for linear
- * @throw std::invalid_argument if max < min or if the values are
- *        inconsistent with a log color scale
- */
+*  Here for backwards compatibility, setColorScale(double min, double max, int
+*type)
+*  should be used instead.
+*
+* @param min :: minimum value corresponding to the lowest color on the map
+* @param max :: maximum value corresponding to the highest color on the map
+* @param log :: true for a log color scale, false for linear
+* @throw std::invalid_argument if max < min or if the values are
+*        inconsistent with a log color scale
+*/
 void SliceViewer::setColorScale(double min, double max, bool log) {
   if (max <= min)
     throw std::invalid_argument("Color scale maximum must be > minimum.");
@@ -1803,13 +1885,13 @@ void SliceViewer::setColorScale(double min, double max, bool log) {
 
 //------------------------------------------------------------------------------
 /** Set the color scale limits and type via a method call.
- *
- * @param min :: minimum value corresponding to the lowest color on the map
- * @param max :: maximum value corresponding to the highest color on the map
- * @param type :: 0 for linear, 1 for log, 2 for power
- * @throw std::invalid_argument if max < min or if the values are
- *        inconsistent with a log color scale
- */
+*
+* @param min :: minimum value corresponding to the lowest color on the map
+* @param max :: maximum value corresponding to the highest color on the map
+* @param type :: 0 for linear, 1 for log, 2 for power
+* @throw std::invalid_argument if max < min or if the values are
+*        inconsistent with a log color scale
+*/
 void SliceViewer::setColorScale(double min, double max, int type) {
   if (max <= min)
     throw std::invalid_argument("Color scale maximum must be > minimum.");
@@ -1823,18 +1905,18 @@ void SliceViewer::setColorScale(double min, double max, int type) {
 
 //------------------------------------------------------------------------------
 /** Set the "background" color to use in the color map. Default is white.
- *
- * This is the color that is shown when:
- *
- *  - The coordinate is out of bounds of the workspace.
- *  - When a signal is NAN (not-a-number).
- *  - When the signal is Zero, if that option is selected using
- *setTransparentZeros()
- *
- * @param r :: red component, from 0-255
- * @param g :: green component, from 0-255
- * @param b :: blue component, from 0-255
- */
+*
+* This is the color that is shown when:
+*
+*  - The coordinate is out of bounds of the workspace.
+*  - When a signal is NAN (not-a-number).
+*  - When the signal is Zero, if that option is selected using
+*setTransparentZeros()
+*
+* @param r :: red component, from 0-255
+* @param g :: green component, from 0-255
+* @param b :: blue component, from 0-255
+*/
 void SliceViewer::setColorMapBackground(int r, int g, int b) {
   m_colorBar->getColorMap().setNanColor(r, g, b);
   this->colorRangeChanged();
@@ -1842,40 +1924,40 @@ void SliceViewer::setColorMapBackground(int r, int g, int b) {
 
 //------------------------------------------------------------------------------
 /** Set the minimum value corresponding to the lowest color on the map
- *
- * @param min :: minimum value corresponding to the lowest color on the map
- * @throw std::invalid_argument if max < min or if the values are
- *        inconsistent with a log color scale
- */
+*
+* @param min :: minimum value corresponding to the lowest color on the map
+* @throw std::invalid_argument if max < min or if the values are
+*        inconsistent with a log color scale
+*/
 void SliceViewer::setColorScaleMin(double min) {
   this->setColorScale(min, this->getColorScaleMax(), this->getColorScaleType());
 }
 
 //------------------------------------------------------------------------------
 /** Get the colormap scale type
- *
- * @return int corresponding to the selected scale type
- */
+*
+* @return int corresponding to the selected scale type
+*/
 int SliceViewer::getColorScaleType() { return m_colorBar->getScale(); }
 
 //------------------------------------------------------------------------------
 /** Set the maximum value corresponding to the lowest color on the map
- *
- * @param max :: maximum value corresponding to the lowest color on the map
- * @throw std::invalid_argument if max < min or if the values are
- *        inconsistent with a log color scale
- */
+*
+* @param max :: maximum value corresponding to the lowest color on the map
+* @throw std::invalid_argument if max < min or if the values are
+*        inconsistent with a log color scale
+*/
 void SliceViewer::setColorScaleMax(double max) {
   this->setColorScale(this->getColorScaleMin(), max, this->getColorScaleType());
 }
 
 //------------------------------------------------------------------------------
 /** Set whether the color scale is logarithmic
- *
- * @param log :: true for a log color scale, false for linear
- * @throw std::invalid_argument if the min/max values are inconsistent
- *        with a log color scale
- */
+*
+* @param log :: true for a log color scale, false for linear
+* @throw std::invalid_argument if the min/max values are inconsistent
+*        with a log color scale
+*/
 void SliceViewer::setColorScaleLog(bool log) {
   this->setColorScale(this->getColorScaleMin(), this->getColorScaleMax(),
                       (int)log);
@@ -1897,15 +1979,15 @@ bool SliceViewer::getColorScaleLog() const { return m_colorBar->getLog(); }
 
 //------------------------------------------------------------------------------
 /** Sets whether the image should be rendered in "fast" mode, where
- * the workspace's resolution is used to guess how many pixels to render.
- *
- * If false, each pixel on screen will be rendered. This is the most
- * accurate view but the slowest.
- *
- * This redraws the screen.
- *
- * @param fast :: true to use "fast" rendering mode.
- */
+* the workspace's resolution is used to guess how many pixels to render.
+*
+* If false, each pixel on screen will be rendered. This is the most
+* accurate view but the slowest.
+*
+* This redraws the screen.
+*
+* @param fast :: true to use "fast" rendering mode.
+*/
 void SliceViewer::setFastRender(bool fast) {
   m_fastRender = fast;
   m_data->setFastMode(m_fastRender);
@@ -1913,29 +1995,29 @@ void SliceViewer::setFastRender(bool fast) {
 }
 
 /** Return true if the image is in "fast" rendering mode.
- *
- * In "fast" mode, the workspace's resolution is used to guess how many
- * pixels to render. If false, each pixel on screen will be rendered.
- * This is the most accurate view but the slowest.
- *
- * @return True if the image is in "fast" rendering mode.
- */
+*
+* In "fast" mode, the workspace's resolution is used to guess how many
+* pixels to render. If false, each pixel on screen will be rendered.
+* This is the most accurate view but the slowest.
+*
+* @return True if the image is in "fast" rendering mode.
+*/
 bool SliceViewer::getFastRender() const { return m_fastRender; }
 
 //------------------------------------------------------------------------------
 /** Set the limits in X and Y to be shown in the plot.
- * The X and Y values are in the units of their respective dimensions.
- * You can change the mapping from X/Y in the plot to specific
- * dimensions in the displayed workspace using setXYDim().
- *
- * You can flip the direction of the scale if you specify,
- * e.g., xleft > xright.
- *
- * @param xleft   :: x-value on the left side of the graph
- * @param xright  :: x-value on the right side of the graph
- * @param ybottom :: y-value on the bottom of the graph
- * @param ytop    :: y-value on the top of the graph
- */
+* The X and Y values are in the units of their respective dimensions.
+* You can change the mapping from X/Y in the plot to specific
+* dimensions in the displayed workspace using setXYDim().
+*
+* You can flip the direction of the scale if you specify,
+* e.g., xleft > xright.
+*
+* @param xleft   :: x-value on the left side of the graph
+* @param xright  :: x-value on the right side of the graph
+* @param ybottom :: y-value on the bottom of the graph
+* @param ytop    :: y-value on the top of the graph
+*/
 void SliceViewer::setXYLimits(double xleft, double xright, double ybottom,
                               double ytop) {
   // Set the limits in X and Y
@@ -1959,11 +2041,11 @@ QwtDoubleInterval SliceViewer::getYLimits() const {
 
 //------------------------------------------------------------------------------
 /** Opens a workspace and sets the view and slice points
- * given the XML from the MultiSlice view in XML format.
- *
- * @param xml :: string describing workspace, slice point, etc.
- * @throw std::runtime_error if error in parsing XML
- */
+* given the XML from the MultiSlice view in XML format.
+*
+* @param xml :: string describing workspace, slice point, etc.
+* @throw std::runtime_error if error in parsing XML
+*/
 void SliceViewer::openFromXML(const QString &xml) {
   // Set up the DOM parser and parse xml file
   DOMParser pParser;
@@ -1986,8 +2068,7 @@ void SliceViewer::openFromXML(const QString &xml) {
         "SliceViewer::openFromXML(): No root element in XML string.");
 
   // ------- Find the workspace ------------
-  Poco::XML::Element *cur = NULL;
-  cur = pRootElem->getChildElement("MDWorkspaceName");
+  Poco::XML::Element *cur = pRootElem->getChildElement("MDWorkspaceName");
   if (!cur)
     throw std::runtime_error(
         "SliceViewer::openFromXML(): No MDWorkspaceName element.");
@@ -2109,7 +2190,7 @@ void SliceViewer::openFromXML(const QString &xml) {
 
   VMD slicePoint(m_ws->getNumDims());
   slicePoint *= 0; // clearnormalDim
-  // The plane origin in the 3D view
+                   // The plane origin in the 3D view
   slicePoint[normalDim] = planeOrigin;
   // The "time" of the paraview view
   if (dimMap[3] > 0)
@@ -2143,8 +2224,8 @@ void SliceViewer::openFromXML(const QString &xml) {
 
 //------------------------------------------------------------------------------
 /** This slot is called when the dynamic rebinning parameters are changed.
- * It recalculates the dynamically rebinned workspace and plots it
- */
+* It recalculates the dynamically rebinned workspace and plots it
+*/
 void SliceViewer::rebinParamsChanged() {
   if (!m_ws)
     return;
@@ -2174,7 +2255,6 @@ void SliceViewer::rebinParamsChanged() {
     double min = 0;
     double max = 1;
     int numBins = 1;
-
     if (widget->getShownDim() < 0) {
       // Slice point. So integrate with a thickness
       min = widget->getSlicePoint() - widget->getThickness();
@@ -2223,10 +2303,10 @@ void SliceViewer::rebinParamsChanged() {
 
 //------------------------------------------------------------------------------
 /** Slot called by the observer when the BinMD call has completed.
- * This returns the execution to the main GUI thread, and
- * so can update the GUI.
- * @param error :: true if the algorithm died with an error.
- */
+* This returns the execution to the main GUI thread, and
+* so can update the GUI.
+* @param error :: true if the algorithm died with an error.
+*/
 void SliceViewer::dynamicRebinComplete(bool error) {
   // If there was an error, clear the workspace
   m_overlayWS.reset();
@@ -2266,7 +2346,6 @@ void SliceViewer::panned(int, int) {
   autoRebinIfRequired();
 
   applyColorScalingForCurrentSliceIfRequired();
-
   this->updatePeaksOverlay();
 }
 
@@ -2275,7 +2354,6 @@ Event handler for changing magnification.
 */
 void SliceViewer::magnifierRescaled(double) {
   autoRebinIfRequired();
-
   this->updatePeaksOverlay();
 }
 
@@ -2300,20 +2378,117 @@ bool SliceViewer::isAutoRebinSet() const {
 Auto rebin the workspace according the the current-view + rebin parameters if
 that option has been set.
 */
-void SliceViewer::autoRebinIfRequired() {
+void SliceViewer::autoRebinIfRequired() { // probably rename this if forcing it
+                                          // to do 2 things
   if (isAutoRebinSet()) {
     rebinParamsChanged();
   }
 }
+/** NON ORTHOGONAL STUFF **/
+
+void SliceViewer::setNonOrthogonalbtn() {
+  bool canShowSkewedWS = API::isHKLDimensions(m_ws, m_dimX, m_dimY);
+  if (!canShowSkewedWS && ui.btnNonOrthogonalToggle->isChecked()) {
+    ui.btnNonOrthogonalToggle->toggle();
+    m_oldDimNonOrthogonal = true;
+  }
+
+  if (canShowSkewedWS && m_oldDimNonOrthogonal &&
+      !ui.btnNonOrthogonalToggle->isChecked()) {
+    ui.btnNonOrthogonalToggle->toggle();
+    m_oldDimNonOrthogonal = false;
+  }
+  if (ui.btnPeakOverlay->isChecked()) {
+    ui.btnNonOrthogonalToggle->setDisabled(true);
+    ui.btnNonOrthogonalToggle->setToolTip(
+        QString("NonOrthogonal view disabled when peakview enabled"));
+  } else {
+    ui.btnNonOrthogonalToggle->setDisabled(!canShowSkewedWS);
+    if (canShowSkewedWS) {
+      ui.btnNonOrthogonalToggle->setToolTip(QString("NonOrthogonal axes view"));
+    } else {
+      ui.btnNonOrthogonalToggle->setToolTip(
+          QString("NonOrthogonal view requires HKL axes"));
+    }
+  };
+
+  // temporary to disable if peak overlay is on
+  emit disableOrthogonalAnalysisTools(ui.btnNonOrthogonalToggle->isChecked());
+}
+
+void SliceViewer::disableOrthogonalAnalysisTools(bool checked) {
+  if (ui.btnDoLine->isChecked()) {
+    ui.btnDoLine->toggle();
+  }
+  if (ui.btnRebinMode->isChecked()) {
+    ui.btnRebinMode->toggle();
+  }
+
+  if (checked) {
+    m_nonOrthogonalOverlay->enable();
+    adjustSize();
+  } else {
+    m_nonOrthogonalOverlay->disable();
+  }
+
+  if (checked) { // change tooltips to explain why buttons are disabled
+    ui.btnDoLine->setToolTip(
+        QString("Cut line is disabled in NonOrthogonal view"));
+    ui.btnSnapToGrid->setToolTip(
+        QString("Cut line is disabled in NonOrthogonal view"));
+    ui.btnClearLine->setToolTip(
+        QString("Cut line is disabled in NonOrthogonal view"));
+    ui.btnPeakOverlay->setToolTip(
+        QString("Peak overlay is disabled in NonOrthogonal view"));
+
+  } else {
+    ui.btnDoLine->setToolTip(QString("Draw a 1D cut line"));
+    ui.btnSnapToGrid->setToolTip(QString("Snap to grid when drawing cut line"));
+    ui.btnClearLine->setToolTip(QString("Remove the current cut line"));
+    ui.btnPeakOverlay->setToolTip(QString("Overlay Peaks"));
+  }
+
+  ui.btnDoLine->setDisabled(checked);
+  ui.btnSnapToGrid->setDisabled(checked);
+  ui.btnClearLine->setDisabled(checked);
+  ui.btnPeakOverlay->setDisabled(checked);
+
+  if (m_lockAspectRatiosActionAll->isChecked() && checked) {
+    m_lastRatioState = All;
+  }
+
+  if (m_lockAspectRatiosActionGuess->isChecked() && checked) {
+    // disable this only if nonOrthogonal button is selected
+    m_lockAspectRatiosActionGuess->setChecked(!checked);
+    m_lastRatioState = Guess;
+    changeAspectRatioAll();
+  }
+  m_lockAspectRatiosActionGuess->setEnabled(!checked);
+
+  if (m_lockAspectRatiosActionUnlock->isChecked() && checked) {
+    // disable this only if nonOrthogonal button is selected
+    m_lockAspectRatiosActionUnlock->setChecked(!checked);
+    m_lastRatioState = Unlock;
+    changeAspectRatioAll();
+  }
+  m_lockAspectRatiosActionUnlock->setEnabled(!checked);
+
+  if (!checked) {
+    setAspectRatio(m_lastRatioState);
+  }
+
+  m_nonOrthogonalOverlay->update();
+  m_plot->updateLayout();
+}
 
 /**
- * Convenience function for removing all displayed peaks workspaces.
- */
+* Convenience function for removing all displayed peaks workspaces.
+*/
 void SliceViewer::clearPeaksWorkspaces() { this->disablePeakOverlays(); }
 
 /**
- * Helper function to rest the SliceViewer into a no-peak overlay mode.
- */
+* Helper function to rest the SliceViewer into a no-peak overlay mode.
+*/
 void SliceViewer::disablePeakOverlays() {
   // Un-check the button for consistency.
   m_peaksPresenter->clear();
@@ -2326,9 +2501,9 @@ void SliceViewer::disablePeakOverlays() {
 }
 
 /**
- * Show a collection of peaks workspaces as overplots
- * @param list : List of peak workspace names to show.
- */
+* Show a collection of peaks workspaces as overplots
+* @param list : List of peak workspace names to show.
+*/
 ProxyCompositePeaksPresenter *
 SliceViewer::setPeaksWorkspaces(const QStringList &list) {
 
@@ -2425,6 +2600,7 @@ void SliceViewer::peakOverlay_clicked() {
                       QIcon::Off);
     ui.btnPeakOverlay->setChecked(false);
   }
+  setNonOrthogonalbtn(); // currently disabling nonOrthogonal when peaks view on
 }
 
 /**
@@ -2451,9 +2627,9 @@ void SliceViewer::updatePeakOverlaySliderWidget() {
 }
 
 /**
- * Update the peaks presenter. Use the slice position as well as the plot region
- * to update the collection of peaks presetners.
- */
+* Update the peaks presenter. Use the slice position as well as the plot region
+* to update the collection of peaks presetners.
+*/
 void SliceViewer::updatePeaksOverlay() {
   if (m_peaksSliderWidget != NULL) {
     auto xInterval = getXLimits();
@@ -2522,13 +2698,13 @@ void SliceViewer::zoomToRectangle(const PeakBoundingBox &boundingBox) {
 }
 
 /**
- * Reset the original view.
- */
+* Reset the original view.
+*/
 void SliceViewer::resetView() { this->resetZoom(); }
 
 /**
- * @brief Detach this sliceviewer from the peaksviewer
- */
+* @brief Detach this sliceviewer from the peaksviewer
+*/
 void SliceViewer::detach() { this->disablePeakOverlays(); }
 
 void SliceViewer::peakWorkspaceChanged(
@@ -2579,9 +2755,9 @@ void SliceViewer::dropEvent(QDropEvent *e) {
 }
 
 /**
- * Set autoscaling for the color bar on or off
- * @param autoscale :: [input] On/off status for autoscaling
- */
+* Set autoscaling for the color bar on or off
+* @param autoscale :: [input] On/off status for autoscaling
+*/
 void SliceViewer::setColorBarAutoScale(bool autoscale) {
   m_colorBar->setAutoScale(autoscale);
 }
@@ -2599,9 +2775,9 @@ void SliceViewer::applyColorScalingForCurrentSliceIfRequired() {
 }
 
 /**
- * Load the state of the slice viewer from a Mantid project file
- * @param lines :: lines from the project file to load state from
- */
+* Load the state of the slice viewer from a Mantid project file
+* @param lines :: lines from the project file to load state from
+*/
 void SliceViewer::loadFromProject(const std::string &lines) {
   API::TSVSerialiser tsv(lines);
 
@@ -2698,8 +2874,8 @@ void SliceViewer::loadFromProject(const std::string &lines) {
 }
 
 /** Load the current state of the dimension widgets from a string
- * @param lines :: a string containing the state of the widgets
- */
+* @param lines :: a string containing the state of the widgets
+*/
 void SliceViewer::loadDimensionWidgets(const std::string &lines) {
   API::TSVSerialiser tsv(lines);
 
@@ -2721,9 +2897,9 @@ void SliceViewer::loadDimensionWidgets(const std::string &lines) {
 }
 
 /**
- * Save the state of th slice viewer to a Mantid project file
- * @return a string representing the current state
- */
+* Save the state of th slice viewer to a Mantid project file
+* @return a string representing the current state
+*/
 std::string SliceViewer::saveToProject() const {
   API::TSVSerialiser tsv;
 
@@ -2748,14 +2924,14 @@ std::string SliceViewer::saveToProject() const {
   tsv.writeSection("overlay", m_lineOverlay->saveToProject());
 
   if (m_overlayWS)
-    tsv.writeLine("OverlayWorkspace") << m_overlayWS->name();
+    tsv.writeLine("OverlayWorkspace") << m_overlayWS->getName();
 
   return tsv.outputLines();
 }
 
 /** Save the current state of the dimension widgets to string
- * @return a string containing the state of the widgets
- */
+* @return a string containing the state of the widgets
+*/
 std::string SliceViewer::saveDimensionWidgets() const {
   API::TSVSerialiser tsv;
   tsv.writeLine("NumDimensions") << m_dimWidgets.size();
@@ -2768,5 +2944,37 @@ std::string SliceViewer::saveDimensionWidgets() const {
   return tsv.outputLines();
 }
 
+void SliceViewer::switchAxis() {
+  if (m_canSwitchScales) { // cannot be called when sliceviewer first
+                           // initialised because axis is inaccurate
+    auto isHKL = API::isHKLDimensions(m_ws, m_dimX, m_dimY);
+    if (isHKL) {
+      applyNonOrthogonalAxisScaleDraw();
+    } else {
+      applyOrthogonalAxisScaleDraw();
+    }
+  }
+}
+
+/// Apply the non orthogonal axis scale draw
+void SliceViewer::applyNonOrthogonalAxisScaleDraw() {
+  m_nonOrthAxis0 = new QwtScaleDrawNonOrthogonal(
+      m_plot, QwtScaleDrawNonOrthogonal::ScreenDimension::X, m_ws, m_dimX,
+      m_dimY, m_slicePoint, m_nonOrthogonalOverlay);
+  m_nonOrthAxis1 = new QwtScaleDrawNonOrthogonal(
+      m_plot, QwtScaleDrawNonOrthogonal::ScreenDimension::Y, m_ws, m_dimX,
+      m_dimY, m_slicePoint, m_nonOrthogonalOverlay);
+  m_plot->setAxisScaleDraw(QwtPlot::xBottom, m_nonOrthAxis0);
+  m_plot->setAxisScaleDraw(QwtPlot::yLeft, m_nonOrthAxis1);
+}
+
+/// Apply the orthogonal axis scale draw
+void SliceViewer::applyOrthogonalAxisScaleDraw() {
+  auto *axis0 = new QwtScaleDraw();
+  auto *axis1 = new QwtScaleDraw();
+  m_plot->setAxisScaleDraw(QwtPlot::xBottom, axis0);
+  m_plot->setAxisScaleDraw(QwtPlot::yLeft, axis1);
+}
+
 } // namespace
 }
diff --git a/MantidQt/SliceViewer/src/SliceViewerWindow.cpp b/MantidQt/SliceViewer/src/SliceViewerWindow.cpp
index 068e4f5da26ceb24a4d27ca32c142d1de908cc5d..b674993dfffaf53414b0800c0f7716c39986a7f0 100644
--- a/MantidQt/SliceViewer/src/SliceViewerWindow.cpp
+++ b/MantidQt/SliceViewer/src/SliceViewerWindow.cpp
@@ -521,7 +521,7 @@ std::string SliceViewerWindow::saveToProject(ApplicationWindow *app) {
   UNUSED_ARG(app);
   MantidQt::API::TSVSerialiser tsv, tab;
   tab.writeLine("geometry") << geometry();
-  tab.writeLine("Workspace") << m_ws->name();
+  tab.writeLine("Workspace") << m_ws->getName();
   tab.writeLine("Label") << m_label;
   tab.writeRaw(m_slicer->saveToProject());
 
@@ -535,5 +535,15 @@ std::string SliceViewerWindow::saveToProject(ApplicationWindow *app) {
   return tsv.outputLines();
 }
 
+std::string SliceViewerWindow::getWindowName() {
+  return "Slice Viewer (" + m_wsName + ")";
+}
+
+std::vector<std::string> SliceViewerWindow::getWorkspaceNames() {
+  return {m_ws->getName()};
+}
+
+std::string SliceViewerWindow::getWindowType() { return "SliceViewer"; }
+
 } // namespace SliceViewer
 } // namespace MantidQt
diff --git a/MantidQt/SliceViewer/test/CMakeLists.txt b/MantidQt/SliceViewer/test/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..20c0ebf6d6f564474b2cfa67889d6879cbd89c71
--- /dev/null
+++ b/MantidQt/SliceViewer/test/CMakeLists.txt
@@ -0,0 +1,35 @@
+if ( CXXTEST_FOUND )
+    include_directories ( SYSTEM ${CXXTEST_INCLUDE_DIR} ${GMOCK_INCLUDE_DIR} ${GTEST_INCLUDE_DIR} )
+
+    include_directories ( ../../../Framework/TestHelpers/inc
+                          ../../../Framework/DataObjects/inc )
+    
+    # This variable is used within the cxxtest_add_test macro to build these helper classes into the test executable.
+    # It will go out of scope at the end of this file so doesn't need un-setting
+    set ( TESTHELPER_SRCS ../../../Framework/TestHelpers/src/TearDownWorld.cpp
+                          ../../../Framework/TestHelpers/src/ComponentCreationHelper.cpp
+                          ../../../Framework/TestHelpers/src/InstrumentCreationHelper.cpp
+                          ../../../Framework/TestHelpers/src/WorkspaceCreationHelper.cpp
+        )
+    
+    cxxtest_add_test ( SliceViewerTest ${TEST_FILES} )
+    target_link_libraries( SliceViewerTest LINK_PRIVATE ${TCMALLOC_LIBRARIES_LINKTIME}
+            SliceViewer
+            Crystal
+            MantidQtAPI
+            API
+            DataObjects
+            Geometry
+            HistogramData
+            Kernel
+            ${QT_LIBRARIES}
+            ${QWT_LIBRARIES}
+            ${Boost_LIBRARIES}
+            ${POCO_LIBRARIES}
+            ${GMOCK_LIBRARIES}
+            ${GTEST_LIBRARIES} )
+    add_dependencies( GUITests SliceViewerTest )
+    
+    # Add to the 'UnitTests' group in VS
+    set_property( TARGET SliceViewerTest PROPERTY FOLDER "UnitTests" )
+endif ()
diff --git a/MantidQt/SliceViewer/test/CompositePeaksPresenterTest.h b/MantidQt/SliceViewer/test/CompositePeaksPresenterTest.h
index 7bca2c99e66e46df18b2b7fb44e6b840d095856c..f7a9bf7d1aa29ac95e5389be8016cb2f0cfb534c 100644
--- a/MantidQt/SliceViewer/test/CompositePeaksPresenterTest.h
+++ b/MantidQt/SliceViewer/test/CompositePeaksPresenterTest.h
@@ -6,6 +6,7 @@
 #include "MantidQtSliceViewer/CompositePeaksPresenter.h"
 #include "MantidQtSliceViewer/NullPeaksPresenter.h"
 #include "MantidDataObjects/PeaksWorkspace.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MockObjects.h"
 
 using namespace MantidQt::SliceViewer;
diff --git a/MantidQt/SliceViewer/test/CoordinateTransformTest.h b/MantidQt/SliceViewer/test/CoordinateTransformTest.h
new file mode 100644
index 0000000000000000000000000000000000000000..a66c7eee23ed09cc666f9a23d75dcc08003517c2
--- /dev/null
+++ b/MantidQt/SliceViewer/test/CoordinateTransformTest.h
@@ -0,0 +1,263 @@
+#ifndef MANTIDQT_SLICEVIEWER_COORDINATETRANSFORM_TEST_H
+#define MANTIDQT_SLICEVIEWER_COORDINATETRANSFORM_TEST_H
+
+#include <cxxtest/TestSuite.h>
+#include "MantidAPI/FrameworkManager.h"
+#include "MantidQtSliceViewer/CoordinateTransform.h"
+#include "MantidAPI/IMDEventWorkspace.h"
+#include "MantidKernel/MDUnitFactory.h"
+#include "MantidGeometry/MDGeometry/HKL.h"
+#include "MantidTestHelpers/MDEventsTestHelper.h"
+#include "MantidKernel/Unit.h"
+#include "MantidKernel/UnitLabelTypes.h"
+#include "MantidGeometry/MDGeometry/QSample.h"
+#include "MantidDataObjects/CoordTransformAffine.h"
+#include "MantidTestHelpers/MDEventsTestHelper.h"
+#include "MantidAPI/FrameworkManager.h"
+#include "MantidKernel/PropertyWithValue.h"
+#include "MantidAPI/AlgorithmManager.h"
+#include "MantidCrystal/SetUB.h"
+#include "MantidAPI/ExperimentInfo.h"
+#include "MantidAPI/Run.h"
+#include "MantidKernel/Matrix.h"
+#include "MantidKernel/MDUnit.h"
+
+class CoordinateTransformTest : public CxxTest::TestSuite {
+private:
+  Mantid::API::IMDEventWorkspace_sptr getOrthogonalEventWorkspace() {
+    Mantid::Kernel::ReciprocalLatticeUnitFactory factory;
+    auto product = factory.create(Mantid::Kernel::Units::Symbol::RLU);
+    Mantid::Geometry::HKL frame(product);
+    auto workspace =
+        Mantid::DataObjects::MDEventsTestHelper::makeMDEWWithFrames<3>(
+            5, -10, 10, frame);
+    return workspace;
+  }
+  size_t m_dimX = 0;
+  size_t m_dimY = 1;
+  size_t m_sliceDim = 2;
+
+  Mantid::API::IMDEventWorkspace_sptr getNonOrthogonalEventWorkspace(
+      bool wrongCoords = false, bool forgetUB = false, bool forgetWmat = false,
+      bool forgetAffmat = false, double scale = 1.0) {
+    Mantid::API::IMDEventWorkspace_sptr ws;
+    std::string wsName = "simpleWS";
+    if (wrongCoords) {
+      Mantid::Geometry::QSample frame;
+      ws = Mantid::DataObjects::MDEventsTestHelper::makeAnyMDEWWithFrames<
+          Mantid::DataObjects::MDEvent<4>, 4>(1, 0.0, 1.0, frame, 1, wsName);
+    } else {
+      Mantid::Kernel::ReciprocalLatticeUnitFactory factory;
+      auto product = factory.create(Mantid::Kernel::Units::Symbol::RLU);
+      Mantid::Geometry::HKL frame(product);
+      ws = Mantid::DataObjects::MDEventsTestHelper::makeAnyMDEWWithFrames<
+          Mantid::DataObjects::MDEvent<4>, 4>(1, 0.0, 1.0, frame, 1, wsName);
+    }
+    if (!forgetUB) {
+      // add UB Matrix
+      Mantid::API::IAlgorithm_sptr alg =
+          Mantid::API::AlgorithmManager::Instance().create("SetUB");
+      alg->initialize();
+      alg->setRethrows(true);
+      alg->setProperty("Workspace", wsName);
+      alg->setProperty("a", 3.643 * scale);
+      alg->setProperty("b", 3.643);
+      alg->setProperty("c", 5.781);
+      alg->setProperty("alpha", 90.0);
+      alg->setProperty("beta", 90.0);
+      alg->setProperty("gamma", 120.0);
+      std::vector<double> uVec;
+      uVec.push_back(1 * scale);
+      uVec.push_back(1);
+      uVec.push_back(0);
+      std::vector<double> vVec;
+      vVec.push_back(0);
+      vVec.push_back(0);
+      vVec.push_back(1);
+      alg->setProperty("u", uVec);
+      alg->setProperty("v", vVec);
+      alg->execute();
+    }
+
+    // Create the coordinate transformation information
+    std::vector<Mantid::coord_t> affMatVals{1, 0, 0, 0, 0, 0, 0, 1, 0,
+                                            0, 0, 0, 0, 1, 0, 0, 1, 0,
+                                            0, 0, 0, 0, 0, 0, 1};
+
+    Mantid::DataObjects::CoordTransformAffine affMat(4, 4);
+    affMat.setMatrix(Mantid::Kernel::Matrix<Mantid::coord_t>(affMatVals));
+    if (!forgetAffmat) {
+      ws->setTransformToOriginal(affMat.clone(), 0);
+    }
+    // Create the transform (W) matrix
+    // Need it as a vector
+    std::vector<double> wMat;
+    Mantid::Kernel::DblMatrix temp(3, 3, true);
+    wMat = temp.getVector();
+    if (!forgetWmat) {
+      Mantid::Kernel::PropertyWithValue<std::vector<double>> *p;
+      p = new Mantid::Kernel::PropertyWithValue<std::vector<double>>("W_MATRIX",
+                                                                     wMat);
+      ws->getExperimentInfo(0)->mutableRun().addProperty(p, true);
+    }
+    return ws;
+  }
+
+  bool skewWithinTolerance(Mantid::Kernel::VMD_t coord, double target) {
+    if ((coord >= target - 0.000005) && (coord <= target + 0.000005)) {
+      return true;
+    } else
+      return false;
+  }
+
+public:
+  static CoordinateTransformTest *createSuite() {
+    Mantid::API::FrameworkManager::Instance();
+    Mantid::API::AlgorithmManager::Instance();
+    return new CoordinateTransformTest();
+  }
+
+  static void destroySuite(CoordinateTransformTest *suite) { delete suite; }
+
+  void test_NullTransformDoesNotTransform() {
+    // Arrange
+
+    auto eventWorkspace = getOrthogonalEventWorkspace();
+    Mantid::Kernel::VMD coords = eventWorkspace->getNumDims();
+
+    // Act
+    auto m_coordinateTransform =
+        MantidQt::SliceViewer::createCoordinateTransform(eventWorkspace, m_dimX,
+                                                         m_dimY);
+    m_coordinateTransform->transform(coords, m_dimX, m_dimY, m_sliceDim);
+
+    // cast into null
+    TSM_ASSERT("Orthogonal workspaces should not be transformed",
+               dynamic_cast<MantidQt::SliceViewer::NullTransform *>(
+                   m_coordinateTransform.get()));
+  }
+
+  void test_NonOrthogonalTransform() {
+    // Arrange
+    auto eventWorkspace = getNonOrthogonalEventWorkspace();
+    Mantid::Kernel::VMD coords = eventWorkspace->getNumDims();
+
+    // Act
+    auto m_coordinateTransform =
+        MantidQt::SliceViewer::createCoordinateTransform(eventWorkspace, m_dimX,
+                                                         m_dimY);
+    m_coordinateTransform->transform(coords, m_dimX, m_dimY, m_sliceDim);
+
+    // Assert
+    TSM_ASSERT("Orthogonal workspaces should not be transformed",
+               dynamic_cast<MantidQt::SliceViewer::NonOrthogonalTransform *>(
+                   m_coordinateTransform.get()));
+  }
+
+  void test_NonOrthogonalZeroReturnsZero() {
+    // arrange
+    auto eventWorkspace = getNonOrthogonalEventWorkspace();
+    Mantid::Kernel::VMD coords = eventWorkspace->getNumDims();
+    for (size_t d = 0; d < eventWorkspace->getNumDims();
+         d++) // change to num dims of eventworkspace
+    {
+      coords[d] = Mantid::Kernel::VMD_t(0.0);
+    }
+
+    // act
+    auto m_coordinateTransform =
+        MantidQt::SliceViewer::createCoordinateTransform(eventWorkspace, m_dimX,
+                                                         m_dimY);
+    m_coordinateTransform->transform(coords, m_dimX, m_dimY, m_sliceDim);
+
+    // assert
+    TSM_ASSERT_EQUALS("Zero coords should not be changed by skew matrix",
+                      coords[0], 0.0);
+  }
+
+  void test_NonOrthogonalSkewCorrectness() {
+    // Arrange
+    auto eventWorkspace = getNonOrthogonalEventWorkspace();
+    Mantid::Kernel::VMD coords = eventWorkspace->getNumDims();
+
+    for (size_t d = 0; d < eventWorkspace->getNumDims(); d++) {
+      coords[d] = Mantid::Kernel::VMD_t(1.5);
+    }
+
+    // Act
+    auto m_coordinateTransform =
+        MantidQt::SliceViewer::createCoordinateTransform(eventWorkspace, m_dimX,
+                                                         m_dimY);
+    m_coordinateTransform->transform(coords, m_dimX, m_dimY, m_sliceDim);
+    double expectedValue = 0.75;
+    bool skewCorrect = skewWithinTolerance(coords[0], expectedValue);
+    TSM_ASSERT("Coords not skewed within limits", skewCorrect);
+  }
+
+  void test_ThrowsSimpleDatasetWrongCoords() {
+    // Arrange
+    auto eventWorkspace = getNonOrthogonalEventWorkspace(true);
+    Mantid::Kernel::VMD coords = eventWorkspace->getNumDims();
+
+    // Act
+    auto m_coordinateTransform =
+        MantidQt::SliceViewer::createCoordinateTransform(eventWorkspace, m_dimX,
+                                                         m_dimY);
+    m_coordinateTransform->transform(coords, m_dimX, m_dimY, m_sliceDim);
+    // Assert
+    TSM_ASSERT(
+        "Datasets with wrong coordinates (non HKL) should not be transformed",
+        dynamic_cast<MantidQt::SliceViewer::NullTransform *>(
+            m_coordinateTransform.get()));
+  }
+
+  void test_ThrowsSimpleDatasetNoUBMatrix() {
+    // Arrange
+    auto eventWorkspace = getNonOrthogonalEventWorkspace(false, true);
+    Mantid::Kernel::VMD coords = eventWorkspace->getNumDims();
+
+    // Act
+    auto m_coordinateTransform =
+        MantidQt::SliceViewer::createCoordinateTransform(eventWorkspace, m_dimX,
+                                                         m_dimY);
+    m_coordinateTransform->transform(coords, m_dimX, m_dimY, m_sliceDim);
+    // Assert
+    TSM_ASSERT("Datasets without a UBmatrix should not be transformed",
+               dynamic_cast<MantidQt::SliceViewer::NullTransform *>(
+                   m_coordinateTransform.get()));
+  }
+
+  void test_ThrowsSimpleDatasetNoWMatrix() {
+    // Arrange
+    auto eventWorkspace = getNonOrthogonalEventWorkspace(false, false, true);
+    Mantid::Kernel::VMD coords = eventWorkspace->getNumDims();
+
+    // Act
+    auto m_coordinateTransform =
+        MantidQt::SliceViewer::createCoordinateTransform(eventWorkspace, m_dimX,
+                                                         m_dimY);
+    m_coordinateTransform->transform(coords, m_dimX, m_dimY, m_sliceDim);
+    // Assert
+    TSM_ASSERT("Datasets without a Wmatrix should not be transformed",
+               dynamic_cast<MantidQt::SliceViewer::NullTransform *>(
+                   m_coordinateTransform.get()));
+  }
+
+  void test_ThrowsSimpleDatasetNoAffMatrix() {
+    // Arrange
+    auto eventWorkspace =
+        getNonOrthogonalEventWorkspace(false, false, false, true);
+    Mantid::Kernel::VMD coords = eventWorkspace->getNumDims();
+
+    // Act
+    auto m_coordinateTransform =
+        MantidQt::SliceViewer::createCoordinateTransform(eventWorkspace, m_dimX,
+                                                         m_dimY);
+    m_coordinateTransform->transform(coords, m_dimX, m_dimY, m_sliceDim);
+    // Assert
+    TSM_ASSERT("Datasets without a Affmatrix should still be transformed",
+               dynamic_cast<MantidQt::SliceViewer::NonOrthogonalTransform *>(
+                   m_coordinateTransform.get()));
+  }
+};
+#endif
diff --git a/MantidQt/SliceViewer/test/MockObjects.h b/MantidQt/SliceViewer/test/MockObjects.h
index e0e55c75e222408b01bf4019c306de5801c54852..4a5146c96ab4a94ab7bae8b8b237efae83224911 100644
--- a/MantidQt/SliceViewer/test/MockObjects.h
+++ b/MantidQt/SliceViewer/test/MockObjects.h
@@ -6,6 +6,7 @@
 #include "MantidGeometry/Crystal/IPeak.h"
 #include "MantidGeometry/Crystal/PeakTransform.h"
 #include "MantidGeometry/Crystal/PeakTransformFactory.h"
+#include "MantidGeometry/MDGeometry/IMDDimension.h"
 #include "MantidKernel/UnitLabel.h"
 #include "MantidKernel/WarningSuppressions.h"
 #include "MantidQtSliceViewer/PeakOverlayView.h"
@@ -240,7 +241,7 @@ public:
   MOCK_CONST_METHOD0(getUnits, const Mantid::Kernel::UnitLabel());
   MOCK_CONST_METHOD0(getMDFrame, const Mantid::Geometry::MDFrame &());
   MOCK_CONST_METHOD0(getMDUnits, const Mantid::Kernel::MDUnit &());
-  MOCK_CONST_METHOD0(getDimensionId, std::string());
+  MOCK_CONST_METHOD0(getDimensionId, const std::string &());
   MOCK_CONST_METHOD0(getMaximum, coord_t());
   MOCK_CONST_METHOD0(getMinimum, coord_t());
   MOCK_CONST_METHOD0(getNBins, size_t());
diff --git a/MantidQt/SliceViewer/test/SliceViewerPythonInterfaceTest.py b/MantidQt/SliceViewer/test/SliceViewerPythonInterfaceTest.py
index 207431eacd4da771c0cd38f62765782f1ff11559..f28ad28cc8a0ed3d04a3988ccde9b2e960708a1c 100644
--- a/MantidQt/SliceViewer/test/SliceViewerPythonInterfaceTest.py
+++ b/MantidQt/SliceViewer/test/SliceViewerPythonInterfaceTest.py
@@ -376,7 +376,7 @@ class SliceViewerPythonInterfaceTest(unittest.TestCase):
     def _getPlotXAxisName(self, lv, ws):
         index = lv.getXAxisDimensionIndex()
         dim = ws.getDimension(index)
-        return dim.getName()
+        return dim.name
 
     def test_mdhistoAutoAxisAssignmentWhenNoIntegration(self):
         CreateMDWorkspace(Dimensions='3',Extents='0,10,0,10,0,10',Names='A,B,C',Units='A,A,A',OutputWorkspace='original')
diff --git a/MantidQt/SpectrumViewer/inc/MantidQtSpectrumViewer/MatrixWSDataSource.h b/MantidQt/SpectrumViewer/inc/MantidQtSpectrumViewer/MatrixWSDataSource.h
index 320b4e4c4f517a35aac345080e716228877726f6..dbcd7731cb8dd70f6a9e6691046479b3028a8aca 100644
--- a/MantidQt/SpectrumViewer/inc/MantidQtSpectrumViewer/MatrixWSDataSource.h
+++ b/MantidQt/SpectrumViewer/inc/MantidQtSpectrumViewer/MatrixWSDataSource.h
@@ -14,6 +14,9 @@ namespace Geometry {
 class IComponent;
 class Instrument;
 }
+namespace API {
+class SpectrumInfo;
+}
 }
 
 namespace MantidQt {
@@ -97,6 +100,7 @@ private:
   boost::shared_ptr<const Mantid::Geometry::Instrument> m_instrument;
   boost::shared_ptr<const Mantid::Geometry::IComponent> m_source;
   boost::shared_ptr<const Mantid::Geometry::IComponent> m_sample;
+  const Mantid::API::SpectrumInfo &m_spectrumInfo;
 };
 
 typedef boost::shared_ptr<MatrixWSDataSource> MatrixWSDataSource_sptr;
diff --git a/MantidQt/SpectrumViewer/inc/MantidQtSpectrumViewer/SpectrumView.h b/MantidQt/SpectrumViewer/inc/MantidQtSpectrumViewer/SpectrumView.h
index 96b9a7c2cabe621190be17e66d3e1f7c48fef3e3..6ff82e82631e650bde07e52a335c181aa0467949 100644
--- a/MantidQt/SpectrumViewer/inc/MantidQtSpectrumViewer/SpectrumView.h
+++ b/MantidQt/SpectrumViewer/inc/MantidQtSpectrumViewer/SpectrumView.h
@@ -82,6 +82,12 @@ public:
                                                     const int fileVersion);
   /// Save the state of the spectrum viewer to a Mantid project file
   virtual std::string saveToProject(ApplicationWindow *app) override;
+  /// Get the name of the window
+  std::string getWindowName() override;
+  /// Get the workspaces associated with this window
+  std::vector<std::string> getWorkspaceNames() override;
+  /// Get the window type as a string
+  std::string getWindowType() override;
 
 signals:
   void spectrumDisplayChanged(SpectrumDisplay *);
diff --git a/MantidQt/SpectrumViewer/src/MatrixWSDataSource.cpp b/MantidQt/SpectrumViewer/src/MatrixWSDataSource.cpp
index 998a2b34757dc97815b994bd4abf4e935414009f..95b0715007ebbb004df85c939aef291860585c82 100644
--- a/MantidQt/SpectrumViewer/src/MatrixWSDataSource.cpp
+++ b/MantidQt/SpectrumViewer/src/MatrixWSDataSource.cpp
@@ -15,11 +15,13 @@
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/ISpectrum.h"
 #include "MantidGeometry/Instrument/Detector.h"
+#include "MantidGeometry/Instrument/Goniometer.h"
 #include "MantidGeometry/Instrument.h"
 #include "MantidKernel/Logger.h"
 #include "MantidKernel/Unit.h"
 #include "MantidKernel/UnitFactory.h"
 #include "MantidAPI/Run.h"
+#include "MantidAPI/SpectrumInfo.h"
 
 using namespace Mantid;
 using namespace Kernel;
@@ -40,7 +42,7 @@ namespace SpectrumView {
  */
 MatrixWSDataSource::MatrixWSDataSource(MatrixWorkspace_const_sptr matWs)
     : SpectrumDataSource(0.0, 1.0, 0.0, 1.0, 0, 0), m_matWs(matWs),
-      m_emodeHandler(NULL) {
+      m_emodeHandler(NULL), m_spectrumInfo(m_matWs->spectrumInfo()) {
   m_totalXMin = matWs->getXMin();
   m_totalXMax = matWs->getXMax();
 
@@ -266,23 +268,18 @@ std::vector<std::string> MatrixWSDataSource::getInfoList(double x, double y) {
       return list;
     }
 
-    auto det = m_matWs->getDetector(row);
-    if (det == 0) {
+    if (!m_spectrumInfo.hasDetectors(row)) {
       g_log.debug() << "No DETECTOR for row " << row << " in MatrixWorkspace\n";
       return list;
     }
 
-    double l1 = m_source->getDistance(*m_sample);
-    double l2 = 0.0;
-    double two_theta = 0.0;
-    double azi = 0.0;
-    if (det->isMonitor()) {
-      l2 = det->getDistance(*m_source);
-      l2 = l2 - l1;
-    } else {
-      l2 = det->getDistance(*m_sample);
-      two_theta = m_matWs->detectorTwoTheta(*det);
-      azi = det->getPhi();
+    double l1 = m_spectrumInfo.l1();
+    double l2 = m_spectrumInfo.l2(row);
+    double two_theta = m_spectrumInfo.twoTheta(row);
+    double azi = m_spectrumInfo.detector(row).getPhi();
+    if (m_spectrumInfo.isMonitor(row)) {
+      two_theta = 0.0;
+      azi = 0.0;
     }
     SVUtils::PushNameValue("L2", 8, 4, l2, list);
     SVUtils::PushNameValue("TwoTheta", 8, 2, two_theta * rad2deg, list);
@@ -330,17 +327,18 @@ std::vector<std::string> MatrixWSDataSource::getInfoList(double x, double y) {
     // Finally, try getting indirect geometry information from the detector
     // object
     if (efixed == 0) {
-      if (!(det->isMonitor() && det->hasParameter("Efixed"))) {
+      const auto &det = m_spectrumInfo.detector(row);
+      if (!(m_spectrumInfo.isMonitor(row) && det.hasParameter("Efixed"))) {
         try {
           const ParameterMap &pmap = m_matWs->constInstrumentParameters();
-          Parameter_sptr par = pmap.getRecursive(det.get(), "Efixed");
+          Parameter_sptr par = pmap.getRecursive(&det, "Efixed");
           if (par) {
             efixed = par->value<double>();
             emode = 2;
           }
         } catch (std::runtime_error &) {
           g_log.debug() << "Failed to get Efixed from detector ID: "
-                        << det->getID() << " in MatrixWSDataSource\n";
+                        << det.getID() << " in MatrixWSDataSource\n";
           efixed = 0;
         }
       }
diff --git a/MantidQt/SpectrumViewer/src/SpectrumView.cpp b/MantidQt/SpectrumViewer/src/SpectrumView.cpp
index d24c0988042c96f1e5bf20893f3fed135696e9e6..8c4279063902564227655894308e113b1e8a52fc 100644
--- a/MantidQt/SpectrumViewer/src/SpectrumView.cpp
+++ b/MantidQt/SpectrumViewer/src/SpectrumView.cpp
@@ -113,7 +113,7 @@ void SpectrumView::renderWorkspace(
   if (isFirstPlot) {
     m_ui->imageTabs->setTabText(
         m_ui->imageTabs->indexOf(m_ui->imageTabs->currentWidget()),
-        QString::fromStdString(wksp->name()));
+        QString::fromStdString(wksp->getName()));
     m_hGraph = boost::make_shared<GraphDisplay>(m_ui->h_graphPlot,
                                                 m_ui->h_graph_table, false);
     m_vGraph = boost::make_shared<GraphDisplay>(m_ui->v_graphPlot,
@@ -124,7 +124,8 @@ void SpectrumView::renderWorkspace(
     auto layout = new QHBoxLayout();
     layout->addWidget(spectrumPlot);
     widget->setLayout(layout);
-    tab = m_ui->imageTabs->addTab(widget, QString::fromStdString(wksp->name()));
+    tab = m_ui->imageTabs->addTab(widget,
+                                  QString::fromStdString(wksp->getName()));
     m_ui->imageTabs->setTabsClosable(true);
   }
 
@@ -366,7 +367,7 @@ std::string SpectrumView::saveToProject(ApplicationWindow *app) {
 
   spec.writeLine("Workspaces");
   for (auto source : m_dataSource) {
-    spec << source->getWorkspace()->name();
+    spec << source->getWorkspace()->getName();
   }
 
   int index = m_ui->imageTabs->currentIndex();
@@ -388,6 +389,20 @@ std::string SpectrumView::saveToProject(ApplicationWindow *app) {
   return tsv.outputLines();
 }
 
+std::string SpectrumView::getWindowName() {
+  return this->windowTitle().toStdString();
+}
+
+std::vector<std::string> SpectrumView::getWorkspaceNames() {
+  std::vector<std::string> names;
+  for (auto source : m_dataSource) {
+    names.push_back(source->getWorkspace()->getName());
+  }
+  return names;
+}
+
+std::string SpectrumView::getWindowType() { return "SpectrumView"; }
+
 void SpectrumView::changeTracking(bool on) {
   if (m_spectrumDisplay.isEmpty()) {
     return;
diff --git a/Testing/Data/DocTest/ILL/IN16B/090661.nxs.md5 b/Testing/Data/DocTest/ILL/IN16B/090661.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..24c0a2021b7e4dc761f364e0a267e2afacad2ce8
--- /dev/null
+++ b/Testing/Data/DocTest/ILL/IN16B/090661.nxs.md5
@@ -0,0 +1 @@
+227a30f45939151ecf719eaa1c1bc024
diff --git a/Testing/Data/DocTest/ILL/IN16B/136553.nxs.md5 b/Testing/Data/DocTest/ILL/IN16B/136553.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..84bccc4b499e20702275ae5b0a60aece17f8f019
--- /dev/null
+++ b/Testing/Data/DocTest/ILL/IN16B/136553.nxs.md5
@@ -0,0 +1 @@
+027ea4d6613e997d6bd95067a98b726f
diff --git a/Testing/Data/DocTest/ILL/IN16B/136554.nxs.md5 b/Testing/Data/DocTest/ILL/IN16B/136554.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..e9f5ed81c5789d646e8d6ff78cfd82958e7d5a6e
--- /dev/null
+++ b/Testing/Data/DocTest/ILL/IN16B/136554.nxs.md5
@@ -0,0 +1 @@
+e523405329a22857f69ebc00fe6b7c64
diff --git a/Testing/Data/DocTest/ILL/IN16B/136555.nxs.md5 b/Testing/Data/DocTest/ILL/IN16B/136555.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..b67a4db5c45d6d9c33151bc65bbe59fe37bb1904
--- /dev/null
+++ b/Testing/Data/DocTest/ILL/IN16B/136555.nxs.md5
@@ -0,0 +1 @@
+35638f91467c622e57f314571788f105
diff --git a/Testing/Data/DocTest/irs26173_graphite002_res.nxs.md5 b/Testing/Data/DocTest/irs26173_graphite002_res.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..aa2d96902ede5702e7222176253c07dac9d17915
--- /dev/null
+++ b/Testing/Data/DocTest/irs26173_graphite002_res.nxs.md5
@@ -0,0 +1 @@
+4a322a634e527c87fbef27f1cc9559d2
diff --git a/Testing/Data/UnitTest/mcstas_event_hist.h5.md5 b/Testing/Data/DocTest/mcstas_event_hist.h5.md5
similarity index 100%
rename from Testing/Data/UnitTest/mcstas_event_hist.h5.md5
rename to Testing/Data/DocTest/mcstas_event_hist.h5.md5
diff --git a/Testing/Data/SystemTest/ENGINX193749_calibration_spec651.nxs.md5 b/Testing/Data/SystemTest/ENGINX193749_calibration_spec651.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..08de317c6839811bcfd49e5a88a462a541fb5d26
--- /dev/null
+++ b/Testing/Data/SystemTest/ENGINX193749_calibration_spec651.nxs.md5
@@ -0,0 +1 @@
+cf09048bb10e7e10c381c92db5373225
diff --git a/Testing/Data/SystemTest/ENGINX236516_vanadium_bank1.nxs.md5 b/Testing/Data/SystemTest/ENGINX236516_vanadium_bank1.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..1503e40c721663cac288cd83fa32eae2c5a6f13c
--- /dev/null
+++ b/Testing/Data/SystemTest/ENGINX236516_vanadium_bank1.nxs.md5
@@ -0,0 +1 @@
+e5262f4b8faee3aeb0670dc6a6a79c70
diff --git a/Testing/Data/SystemTest/EVS14188-90_peaks.nxs.md5 b/Testing/Data/SystemTest/EVS14188-90_peaks.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..c78bd5e0903037b655801518b920b48f52296ccd
--- /dev/null
+++ b/Testing/Data/SystemTest/EVS14188-90_peaks.nxs.md5
@@ -0,0 +1 @@
+ad4f858fb125ca3baeb53e176a84f725
diff --git a/Testing/Data/SystemTest/FittingTestProblems/CUTEst/DIAMON2D.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/CUTEst/DIAMON2D.dat.md5
new file mode 100644
index 0000000000000000000000000000000000000000..51fe156bfa8fc9cb9bf315e6095c47fc69d4fe18
--- /dev/null
+++ b/Testing/Data/SystemTest/FittingTestProblems/CUTEst/DIAMON2D.dat.md5
@@ -0,0 +1 @@
+6932c34dc495a3dff1b9922e312695f3
diff --git a/Testing/Data/SystemTest/FittingTestProblems/CUTEst/DMN15102LS.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/CUTEst/DMN15102LS.dat.md5
new file mode 100644
index 0000000000000000000000000000000000000000..dc0dc9d49667a41bd04bb827b704909b5107b7a2
--- /dev/null
+++ b/Testing/Data/SystemTest/FittingTestProblems/CUTEst/DMN15102LS.dat.md5
@@ -0,0 +1 @@
+82099c7fbc6dc3a8de4b9217ae563ed5
diff --git a/Testing/Data/SystemTest/FittingTestProblems/CUTEst/PALMER6C.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/CUTEst/PALMER6C.dat.md5
new file mode 100644
index 0000000000000000000000000000000000000000..0aeaf584df8229b0ec0a53b56160613e46e2607a
--- /dev/null
+++ b/Testing/Data/SystemTest/FittingTestProblems/CUTEst/PALMER6C.dat.md5
@@ -0,0 +1 @@
+da35838eaec5e81808242156059412a0
diff --git a/Testing/Data/SystemTest/FittingTestProblems/CUTEst/PALMER7C.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/CUTEst/PALMER7C.dat.md5
new file mode 100644
index 0000000000000000000000000000000000000000..1b5f52b11b677af80fcde7db5b85665c36ef8745
--- /dev/null
+++ b/Testing/Data/SystemTest/FittingTestProblems/CUTEst/PALMER7C.dat.md5
@@ -0,0 +1 @@
+6a995d22ba05590931b142e9feab0d88
diff --git a/Testing/Data/SystemTest/FittingTestProblems/CUTEst/PALMER8C.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/CUTEst/PALMER8C.dat.md5
new file mode 100644
index 0000000000000000000000000000000000000000..553bf242eda15c07a79145b6eaceffb2fdf4d878
--- /dev/null
+++ b/Testing/Data/SystemTest/FittingTestProblems/CUTEst/PALMER8C.dat.md5
@@ -0,0 +1 @@
+2ab8ce743107eb738ba99094c9957cb7
diff --git a/Testing/Data/SystemTest/FittingTestProblems/CUTEst/VESUVIOLS.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/CUTEst/VESUVIOLS.dat.md5
new file mode 100644
index 0000000000000000000000000000000000000000..92928d169bc74d5f766629c1f1cf1bcaeb81472e
--- /dev/null
+++ b/Testing/Data/SystemTest/FittingTestProblems/CUTEst/VESUVIOLS.dat.md5
@@ -0,0 +1 @@
+58c89b19a947308dd4609e6743f26434
diff --git a/Testing/Data/SystemTest/FittingTestProblems/CUTEst/VIBRBEAM.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/CUTEst/VIBRBEAM.dat.md5
new file mode 100644
index 0000000000000000000000000000000000000000..51fe156bfa8fc9cb9bf315e6095c47fc69d4fe18
--- /dev/null
+++ b/Testing/Data/SystemTest/FittingTestProblems/CUTEst/VIBRBEAM.dat.md5
@@ -0,0 +1 @@
+6932c34dc495a3dff1b9922e312695f3
diff --git a/Testing/Data/SystemTest/FittingTestProblems/CUTEst/YFITU.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/CUTEst/YFITU.dat.md5
new file mode 100644
index 0000000000000000000000000000000000000000..582f18effd743287f207425d817e48d3b98fe1fe
--- /dev/null
+++ b/Testing/Data/SystemTest/FittingTestProblems/CUTEst/YFITU.dat.md5
@@ -0,0 +1 @@
+8a9dd1453a5133b7f273838ebf932482
diff --git a/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Bennett5.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Bennett5.dat.md5
new file mode 100644
index 0000000000000000000000000000000000000000..51fe156bfa8fc9cb9bf315e6095c47fc69d4fe18
--- /dev/null
+++ b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Bennett5.dat.md5
@@ -0,0 +1 @@
+6932c34dc495a3dff1b9922e312695f3
diff --git a/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/BoxBOD.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/BoxBOD.dat.md5
new file mode 100644
index 0000000000000000000000000000000000000000..5cb9652e59f25ca445e4c978d5545a4f625c744c
--- /dev/null
+++ b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/BoxBOD.dat.md5
@@ -0,0 +1 @@
+be28381269aeec353f6272ebc50d378e
diff --git a/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Chwirut1.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Chwirut1.dat.md5
new file mode 100644
index 0000000000000000000000000000000000000000..391b51d07825b50d45de7b7f56463aad8bb3b920
--- /dev/null
+++ b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Chwirut1.dat.md5
@@ -0,0 +1 @@
+fe023591c01067f2ba0b4a2f71da39b6
diff --git a/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Chwirut2.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Chwirut2.dat.md5
new file mode 100644
index 0000000000000000000000000000000000000000..c41cfaad110eb6958b12641f9e851bf004e16697
--- /dev/null
+++ b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Chwirut2.dat.md5
@@ -0,0 +1 @@
+03c03c5ce0965a569e9c5eb79a275ed0
diff --git a/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/DanWood.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/DanWood.dat.md5
new file mode 100644
index 0000000000000000000000000000000000000000..07efbd62ffb3a666eabd50e8c7e9be645f037e36
--- /dev/null
+++ b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/DanWood.dat.md5
@@ -0,0 +1 @@
+3021097cf0fae99affd670d1e8e0ffa4
diff --git a/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/ENSO.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/ENSO.dat.md5
new file mode 100644
index 0000000000000000000000000000000000000000..f4fb9ce4df0f0d5c29584b399b8744c0ebff03ad
--- /dev/null
+++ b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/ENSO.dat.md5
@@ -0,0 +1 @@
+4a09069042123934377380f82dae3b05
diff --git a/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Eckerle4.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Eckerle4.dat.md5
new file mode 100644
index 0000000000000000000000000000000000000000..3fd84a8abf876cf1501153e8b996de4a0be61650
--- /dev/null
+++ b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Eckerle4.dat.md5
@@ -0,0 +1 @@
+d5c6719f27ca3177fbe207455b95b8ed
diff --git a/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Gauss1.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Gauss1.dat.md5
new file mode 100644
index 0000000000000000000000000000000000000000..5745b7d6cceba8e3907368ce02b239cc44ae61a9
--- /dev/null
+++ b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Gauss1.dat.md5
@@ -0,0 +1 @@
+8192d4256dc45613dd1e44e115330f5e
diff --git a/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Gauss2.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Gauss2.dat.md5
new file mode 100644
index 0000000000000000000000000000000000000000..6436dc8037c16ccc9b9da7b9ef5458ecc503a910
--- /dev/null
+++ b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Gauss2.dat.md5
@@ -0,0 +1 @@
+09e1e27e2df64ea776d60b04e4f8e56a
diff --git a/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Gauss3.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Gauss3.dat.md5
new file mode 100644
index 0000000000000000000000000000000000000000..e9ca6d92c5c65500d247ec9a742824d0e72a354c
--- /dev/null
+++ b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Gauss3.dat.md5
@@ -0,0 +1 @@
+63f81fbacbb68705d4cc3e34b40d0f5e
diff --git a/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Hahn1.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Hahn1.dat.md5
new file mode 100644
index 0000000000000000000000000000000000000000..ca3ad5c0e96de9a0037a97a5e2084c302a10622e
--- /dev/null
+++ b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Hahn1.dat.md5
@@ -0,0 +1 @@
+490de048c82e4e2e4a2ce93500ea3dc9
diff --git a/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Kirby2.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Kirby2.dat.md5
new file mode 100644
index 0000000000000000000000000000000000000000..2bba9aaa8b0f6c0b51b6cb8031f3c7900b88dd0d
--- /dev/null
+++ b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Kirby2.dat.md5
@@ -0,0 +1 @@
+527d973fc9afbb3f5dc2461071ddc854
diff --git a/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Lanczos1.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Lanczos1.dat.md5
new file mode 100644
index 0000000000000000000000000000000000000000..7d318d06287b41514b11072347b0776b7473d6bf
--- /dev/null
+++ b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Lanczos1.dat.md5
@@ -0,0 +1 @@
+294e0a2ee9e98d13f707b76fb139e364
diff --git a/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Lanczos2.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Lanczos2.dat.md5
new file mode 100644
index 0000000000000000000000000000000000000000..f97dd2c9cb610861a791df25c0b6c98145ca2a2c
--- /dev/null
+++ b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Lanczos2.dat.md5
@@ -0,0 +1 @@
+cde7f529948475c64f733f1de64c428e
diff --git a/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Lanczos3.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Lanczos3.dat.md5
new file mode 100644
index 0000000000000000000000000000000000000000..22df8dcd95a68020c876e4e118a7c4b6be15911e
--- /dev/null
+++ b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Lanczos3.dat.md5
@@ -0,0 +1 @@
+22653ff912c702db9c769eb9352427fe
diff --git a/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/MGH09.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/MGH09.dat.md5
new file mode 100644
index 0000000000000000000000000000000000000000..62949647dc8c58fb617d35277e2676a648f566c6
--- /dev/null
+++ b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/MGH09.dat.md5
@@ -0,0 +1 @@
+38fb721b88ab95ecbd39bbc31c7b80ea
diff --git a/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/MGH10.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/MGH10.dat.md5
new file mode 100644
index 0000000000000000000000000000000000000000..317c0ad767661188889ef9a86b2d3785a7e06c37
--- /dev/null
+++ b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/MGH10.dat.md5
@@ -0,0 +1 @@
+a615c3047d837b06598dd34b6a0df56c
diff --git a/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/MGH17.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/MGH17.dat.md5
new file mode 100644
index 0000000000000000000000000000000000000000..c35f10855d39ee4bb144e86d812498baf1abeebb
--- /dev/null
+++ b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/MGH17.dat.md5
@@ -0,0 +1 @@
+3bc29da66158998faecec51f3cdd9dd6
diff --git a/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Misra1a.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Misra1a.dat.md5
new file mode 100644
index 0000000000000000000000000000000000000000..e1da9bd946ef1c56b06738eac7579cc06542ab6a
--- /dev/null
+++ b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Misra1a.dat.md5
@@ -0,0 +1 @@
+984c8d2b2efdd3d3e24efeba48a9fd92
diff --git a/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Misra1b.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Misra1b.dat.md5
new file mode 100644
index 0000000000000000000000000000000000000000..3afa276210a262dfbea8beaa5ed3dfde43f0169a
--- /dev/null
+++ b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Misra1b.dat.md5
@@ -0,0 +1 @@
+28b7e399c1588c77b12e241780c91040
diff --git a/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Misra1c.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Misra1c.dat.md5
new file mode 100644
index 0000000000000000000000000000000000000000..57f69bfd22edbe0383602b872717b72014589f54
--- /dev/null
+++ b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Misra1c.dat.md5
@@ -0,0 +1 @@
+06cde8a4e094c290a618dc7bb7b6fcc3
diff --git a/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Misra1d.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Misra1d.dat.md5
new file mode 100644
index 0000000000000000000000000000000000000000..3b1dfd0812037d2266cab6d3d39c85c42b16e74a
--- /dev/null
+++ b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Misra1d.dat.md5
@@ -0,0 +1 @@
+1e7286e296105a708ad93c891614e307
diff --git a/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Nelson.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Nelson.dat.md5
new file mode 100644
index 0000000000000000000000000000000000000000..c44dab0c7ed9f7156e26855a77fe238acbca98b3
--- /dev/null
+++ b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Nelson.dat.md5
@@ -0,0 +1 @@
+7aa2c811325939e074dad698053b5412
diff --git a/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Rat42.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Rat42.dat.md5
new file mode 100644
index 0000000000000000000000000000000000000000..c77bc76f40a563bb19ceaac009c9be8e24c11776
--- /dev/null
+++ b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Rat42.dat.md5
@@ -0,0 +1 @@
+cca8ea6f5087b155060c8f243d02e9cd
diff --git a/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Rat43.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Rat43.dat.md5
new file mode 100644
index 0000000000000000000000000000000000000000..9b63e65b352695e4c4faefb90e950d476967c7f8
--- /dev/null
+++ b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Rat43.dat.md5
@@ -0,0 +1 @@
+b0d1db54d68fec53a4d998cc4f69927a
diff --git a/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Roszman1.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Roszman1.dat.md5
new file mode 100644
index 0000000000000000000000000000000000000000..01ce65814f851796da32ed09581e2c34d4c83997
--- /dev/null
+++ b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Roszman1.dat.md5
@@ -0,0 +1 @@
+ce3f6494693655f59b49714c30ccd219
diff --git a/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Thurber.dat.md5 b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Thurber.dat.md5
new file mode 100644
index 0000000000000000000000000000000000000000..f41a064e3d372ba0637102d192a0080b90b4ee2e
--- /dev/null
+++ b/Testing/Data/SystemTest/FittingTestProblems/NIST_nonlinear_regression/Thurber.dat.md5
@@ -0,0 +1 @@
+96fd4140cf2abc03ac4cad8b113895a1
diff --git a/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/ENGINX193749_calibration_peak19.txt.md5 b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/ENGINX193749_calibration_peak19.txt.md5
new file mode 100644
index 0000000000000000000000000000000000000000..6a8ae3f42c96e524ab42e4835b2f7c8f52ee0b08
--- /dev/null
+++ b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/ENGINX193749_calibration_peak19.txt.md5
@@ -0,0 +1 @@
+b268192abbc9c076a51e47234fef04d6
diff --git a/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/ENGINX193749_calibration_peak20.txt.md5 b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/ENGINX193749_calibration_peak20.txt.md5
new file mode 100644
index 0000000000000000000000000000000000000000..b5d5f45fce93f4e1453cbf8ccf202fcf06c2a051
--- /dev/null
+++ b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/ENGINX193749_calibration_peak20.txt.md5
@@ -0,0 +1 @@
+0b042ae6660bd794774847c13e4316c8
diff --git a/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/ENGINX193749_calibration_peak23.txt.md5 b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/ENGINX193749_calibration_peak23.txt.md5
new file mode 100644
index 0000000000000000000000000000000000000000..076027fde429d181ef3d798cb830a9aa78984e8e
--- /dev/null
+++ b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/ENGINX193749_calibration_peak23.txt.md5
@@ -0,0 +1 @@
+c154a8fe628c0db7c10921a7babfafbe
diff --git a/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/ENGINX193749_calibration_peak5.txt.md5 b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/ENGINX193749_calibration_peak5.txt.md5
new file mode 100644
index 0000000000000000000000000000000000000000..890edc97ae79032ec5cc643f713bcf16f8fe53af
--- /dev/null
+++ b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/ENGINX193749_calibration_peak5.txt.md5
@@ -0,0 +1 @@
+5ff4214f4e5e9f45a0632045e502d6ff
diff --git a/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/ENGINX193749_calibration_peak6.txt.md5 b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/ENGINX193749_calibration_peak6.txt.md5
new file mode 100644
index 0000000000000000000000000000000000000000..267878e2bf72585cd8c47ced6dee0d4818a7ec24
--- /dev/null
+++ b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/ENGINX193749_calibration_peak6.txt.md5
@@ -0,0 +1 @@
+c02038557722f6f601a11641c13b8f55
diff --git a/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/ENGINX236516_vanadium_bank1_10brk.txt.md5 b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/ENGINX236516_vanadium_bank1_10brk.txt.md5
new file mode 100644
index 0000000000000000000000000000000000000000..ffd53c9261d7e90ddead7c467706ca5cb7c42b73
--- /dev/null
+++ b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/ENGINX236516_vanadium_bank1_10brk.txt.md5
@@ -0,0 +1 @@
+80561f35628e26b957fd8fbab5502d93
diff --git a/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/ENGINX236516_vanadium_bank1_20brk.txt.md5 b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/ENGINX236516_vanadium_bank1_20brk.txt.md5
new file mode 100644
index 0000000000000000000000000000000000000000..bc381407d5b4b92845a823352128426b75b33808
--- /dev/null
+++ b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/ENGINX236516_vanadium_bank1_20brk.txt.md5
@@ -0,0 +1 @@
+68bf0586cce1d875e162423a2447b9b5
diff --git a/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/EVS14188-90_Gaussian_peaks_1.txt.md5 b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/EVS14188-90_Gaussian_peaks_1.txt.md5
new file mode 100644
index 0000000000000000000000000000000000000000..0cce87070041d390e557819869f4ee0a10253710
--- /dev/null
+++ b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/EVS14188-90_Gaussian_peaks_1.txt.md5
@@ -0,0 +1 @@
+05994950f8867e839a687a536b677595
diff --git a/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/EVS14188-90_Gaussian_peaks_2.txt.md5 b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/EVS14188-90_Gaussian_peaks_2.txt.md5
new file mode 100644
index 0000000000000000000000000000000000000000..0307a07e4e514ac8a77a8fb5f6251dce7cf9e610
--- /dev/null
+++ b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/EVS14188-90_Gaussian_peaks_2.txt.md5
@@ -0,0 +1 @@
+139c8317571234cda311afbef9a286f5
diff --git a/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/GEMpeak1.txt.md5 b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/GEMpeak1.txt.md5
new file mode 100644
index 0000000000000000000000000000000000000000..7cca87602774f12f15b50b5d023d7a64de96f541
--- /dev/null
+++ b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/GEMpeak1.txt.md5
@@ -0,0 +1 @@
+39a5f5d5585fb2821d9b887d18e80197
diff --git a/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/WISH17701_peak1.txt.md5 b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/WISH17701_peak1.txt.md5
new file mode 100644
index 0000000000000000000000000000000000000000..fe852094540c203dbea2f3c827552e956ee13ec3
--- /dev/null
+++ b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/WISH17701_peak1.txt.md5
@@ -0,0 +1 @@
+9d6bc75a57b064126aab14e7c5eb32ea
diff --git a/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/WISH17701_peak2.txt.md5 b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/WISH17701_peak2.txt.md5
new file mode 100644
index 0000000000000000000000000000000000000000..f3915ecf82b0d35195f89fd3c3d17e9c5ad29425
--- /dev/null
+++ b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/WISH17701_peak2.txt.md5
@@ -0,0 +1 @@
+61fb6cec75bdd035361dbaea6710e96c
diff --git a/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/WISH17701_peak3.txt.md5 b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/WISH17701_peak3.txt.md5
new file mode 100644
index 0000000000000000000000000000000000000000..ff5ea373233eb3831910caf5145033f27d36946b
--- /dev/null
+++ b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/WISH17701_peak3.txt.md5
@@ -0,0 +1 @@
+655d1a9f81d2e2b0095dd108819d918a
diff --git a/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/WISH17701_peak4.txt.md5 b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/WISH17701_peak4.txt.md5
new file mode 100644
index 0000000000000000000000000000000000000000..96c3969ea0c0f95a7a17865e8d4ce9a180616812
--- /dev/null
+++ b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/WISH17701_peak4.txt.md5
@@ -0,0 +1 @@
+f41f1751f64e2c895d9dddaf0a8dbbce
diff --git a/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/WISH17701_peak5.txt.md5 b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/WISH17701_peak5.txt.md5
new file mode 100644
index 0000000000000000000000000000000000000000..7237c12ba27659d616aa75dc03aa520563f6ae25
--- /dev/null
+++ b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/WISH17701_peak5.txt.md5
@@ -0,0 +1 @@
+25620760fec116854cd419e7aad4b047
diff --git a/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/WISH17701_peak6.txt.md5 b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/WISH17701_peak6.txt.md5
new file mode 100644
index 0000000000000000000000000000000000000000..5c3b9f825d57229ef73decfa5de9a0eca05144ae
--- /dev/null
+++ b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/WISH17701_peak6.txt.md5
@@ -0,0 +1 @@
+046092c6b317018ca4f21af0cf6a11fb
diff --git a/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/WISH17701_peak7.txt.md5 b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/WISH17701_peak7.txt.md5
new file mode 100644
index 0000000000000000000000000000000000000000..d85f9fda11f316e745a3c93b36cbec3da3c68066
--- /dev/null
+++ b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/WISH17701_peak7.txt.md5
@@ -0,0 +1 @@
+eb629c8b1b5fceb83fcd92f97598ef00
diff --git a/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/WISH17701_peak8.txt.md5 b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/WISH17701_peak8.txt.md5
new file mode 100644
index 0000000000000000000000000000000000000000..81ce182db601f672d2fa89ebb17f1f82c093c0a5
--- /dev/null
+++ b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/WISH17701_peak8.txt.md5
@@ -0,0 +1 @@
+7e013fa7700c776316a6643b4185a203
diff --git a/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/WISH17701_peak9.txt.md5 b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/WISH17701_peak9.txt.md5
new file mode 100644
index 0000000000000000000000000000000000000000..67a6df33aa1e77b462a0a01666ba10effd27f78b
--- /dev/null
+++ b/Testing/Data/SystemTest/FittingTestProblems/Neutron_data/WISH17701_peak9.txt.md5
@@ -0,0 +1 @@
+0350effd9980b5f25823d8b67bb6c7d3
diff --git a/Testing/Data/SystemTest/GEM63437_focused_bank3.nxs.md5 b/Testing/Data/SystemTest/GEM63437_focused_bank3.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..4849a0bb040c8fe38eb3162a5f1e102cc91efccb
--- /dev/null
+++ b/Testing/Data/SystemTest/GEM63437_focused_bank3.nxs.md5
@@ -0,0 +1 @@
+14aa520da8b7aa7421db00d42a08e2dc
diff --git a/Testing/Data/SystemTest/ILL/IN16B/136553.nxs.md5 b/Testing/Data/SystemTest/ILL/IN16B/136553.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..84bccc4b499e20702275ae5b0a60aece17f8f019
--- /dev/null
+++ b/Testing/Data/SystemTest/ILL/IN16B/136553.nxs.md5
@@ -0,0 +1 @@
+027ea4d6613e997d6bd95067a98b726f
diff --git a/Testing/Data/SystemTest/ILL/IN16B/136554.nxs.md5 b/Testing/Data/SystemTest/ILL/IN16B/136554.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..e9f5ed81c5789d646e8d6ff78cfd82958e7d5a6e
--- /dev/null
+++ b/Testing/Data/SystemTest/ILL/IN16B/136554.nxs.md5
@@ -0,0 +1 @@
+e523405329a22857f69ebc00fe6b7c64
diff --git a/Testing/Data/SystemTest/ILL/IN16B/136555.nxs.md5 b/Testing/Data/SystemTest/ILL/IN16B/136555.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..b67a4db5c45d6d9c33151bc65bbe59fe37bb1904
--- /dev/null
+++ b/Testing/Data/SystemTest/ILL/IN16B/136555.nxs.md5
@@ -0,0 +1 @@
+35638f91467c622e57f314571788f105
diff --git a/Testing/Data/SystemTest/ILL/IN16B/136556.nxs.md5 b/Testing/Data/SystemTest/ILL/IN16B/136556.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..cee851f8d6651418a2a738f092e8c93f0b595ab4
--- /dev/null
+++ b/Testing/Data/SystemTest/ILL/IN16B/136556.nxs.md5
@@ -0,0 +1 @@
+1f1e52f7222671cdf399a3cab538163b
diff --git a/Testing/Data/SystemTest/ILL/IN16B/136558.nxs.md5 b/Testing/Data/SystemTest/ILL/IN16B/136558.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..3782eb6e819d484d3a634a02b2d099973c75ce3e
--- /dev/null
+++ b/Testing/Data/SystemTest/ILL/IN16B/136558.nxs.md5
@@ -0,0 +1 @@
+548c95d89b28145e3184748840c77103
diff --git a/Testing/Data/SystemTest/ILL/IN16B/136559.nxs.md5 b/Testing/Data/SystemTest/ILL/IN16B/136559.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..2d37742e09ced53e0b16e916fcd7f9e4bc2c2d08
--- /dev/null
+++ b/Testing/Data/SystemTest/ILL/IN16B/136559.nxs.md5
@@ -0,0 +1 @@
+8b44d4f73a4c0574292f43786f746779
diff --git a/Testing/Data/SystemTest/ILL/IN16B/136599.nxs.md5 b/Testing/Data/SystemTest/ILL/IN16B/136599.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..60be896e379c5470f3eb75cb1c6448e1f5cfdb94
--- /dev/null
+++ b/Testing/Data/SystemTest/ILL/IN16B/136599.nxs.md5
@@ -0,0 +1 @@
+a8f5b9701f0236df214e3c3c21a57767
diff --git a/Testing/Data/SystemTest/ILL/IN16B/136600.nxs.md5 b/Testing/Data/SystemTest/ILL/IN16B/136600.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..482a991775bc49205835c3de88907f6ad3717c7a
--- /dev/null
+++ b/Testing/Data/SystemTest/ILL/IN16B/136600.nxs.md5
@@ -0,0 +1 @@
+6f70f813287b0373cfff935eba253ba3
diff --git a/Testing/Data/SystemTest/ILL/IN16B/143720.nxs.md5 b/Testing/Data/SystemTest/ILL/IN16B/143720.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..4a8af5dc66f3569134d7b7d55445ec84e8056be9
--- /dev/null
+++ b/Testing/Data/SystemTest/ILL/IN16B/143720.nxs.md5
@@ -0,0 +1 @@
+9a219e396d5889690e9c74e6fc557914
diff --git a/Testing/Data/SystemTest/ILL/IN16B/143721.nxs.md5 b/Testing/Data/SystemTest/ILL/IN16B/143721.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..8bebeaa582ea4ab1d82a80c893f79125891b9124
--- /dev/null
+++ b/Testing/Data/SystemTest/ILL/IN16B/143721.nxs.md5
@@ -0,0 +1 @@
+a46570cbe3ba0fca49c3d938c33de4a6
diff --git a/Testing/Data/SystemTest/ILL/IN16B/143722.nxs.md5 b/Testing/Data/SystemTest/ILL/IN16B/143722.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..2ac4ffed764b46943e1788f6ff2335e9027d0007
--- /dev/null
+++ b/Testing/Data/SystemTest/ILL/IN16B/143722.nxs.md5
@@ -0,0 +1 @@
+9df9e38aff06f2fc15ba6e4805afe2b9
diff --git a/Testing/Data/SystemTest/ILL/IN16B/143723.nxs.md5 b/Testing/Data/SystemTest/ILL/IN16B/143723.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..b7ddad0a05c17e5b4df0046aba668a2575228cab
--- /dev/null
+++ b/Testing/Data/SystemTest/ILL/IN16B/143723.nxs.md5
@@ -0,0 +1 @@
+3ddadf75ad33f7ac064ca9097fddcf69
diff --git a/Testing/Data/SystemTest/ILL/IN16B/143724.nxs.md5 b/Testing/Data/SystemTest/ILL/IN16B/143724.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..715f79b82ebac40d787c43ba994f29b3d22f531b
--- /dev/null
+++ b/Testing/Data/SystemTest/ILL/IN16B/143724.nxs.md5
@@ -0,0 +1 @@
+3048732a755d23b03484de2c939ab2cb
diff --git a/Testing/Data/SystemTest/ILL/IN16B/143725.nxs.md5 b/Testing/Data/SystemTest/ILL/IN16B/143725.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..d0583e8fa777c0bf101425588bd9ecb3632c1046
--- /dev/null
+++ b/Testing/Data/SystemTest/ILL/IN16B/143725.nxs.md5
@@ -0,0 +1 @@
+9fb760b6b9e46d552df3f5f158c5ab1e
diff --git a/Testing/Data/SystemTest/ILL/IN16B/143726.nxs.md5 b/Testing/Data/SystemTest/ILL/IN16B/143726.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..d7bacaa2bbaae562c5e6bace8aff4b837419772d
--- /dev/null
+++ b/Testing/Data/SystemTest/ILL/IN16B/143726.nxs.md5
@@ -0,0 +1 @@
+5603ac48072cab2fd050e1998bcb7808
diff --git a/Testing/Data/SystemTest/ILL/IN16B/143727.nxs.md5 b/Testing/Data/SystemTest/ILL/IN16B/143727.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..e5ea1eecb428789f7a9e9907c99dddb786fc97e5
--- /dev/null
+++ b/Testing/Data/SystemTest/ILL/IN16B/143727.nxs.md5
@@ -0,0 +1 @@
+4a97c2a72813c45b5d600305da8e9e13
diff --git a/Testing/Data/SystemTest/ILL/IN16B/143728.nxs.md5 b/Testing/Data/SystemTest/ILL/IN16B/143728.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..19014f79cb45d96748502ec51e9ffa35279d755e
--- /dev/null
+++ b/Testing/Data/SystemTest/ILL/IN16B/143728.nxs.md5
@@ -0,0 +1 @@
+3de4c5218f5fac93d0bc1147d2a775df
diff --git a/Testing/Data/SystemTest/ILL/IN16B/143729.nxs.md5 b/Testing/Data/SystemTest/ILL/IN16B/143729.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..8a100a6f3cbcab2e5d60ad2ac59258631a8375c3
--- /dev/null
+++ b/Testing/Data/SystemTest/ILL/IN16B/143729.nxs.md5
@@ -0,0 +1 @@
+f1a183cbef078b63c1eaaef3ca8c60a8
diff --git a/Testing/Data/SystemTest/ILL/IN16B/165944.nxs.md5 b/Testing/Data/SystemTest/ILL/IN16B/165944.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..1a5d48673fb1c893523f5e7d21c239195e06dc82
--- /dev/null
+++ b/Testing/Data/SystemTest/ILL/IN16B/165944.nxs.md5
@@ -0,0 +1 @@
+b368008091f5bebb0ca75a3c14a65959
diff --git a/Testing/Data/SystemTest/ILL/IN16B/165945.nxs.md5 b/Testing/Data/SystemTest/ILL/IN16B/165945.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..f45ffdb0050b9e03713517a876b6d5cf4a5272bc
--- /dev/null
+++ b/Testing/Data/SystemTest/ILL/IN16B/165945.nxs.md5
@@ -0,0 +1 @@
+18c1892f05657656dbdef0bd78a3d4bf
diff --git a/Testing/Data/SystemTest/ILL/IN16B/165946.nxs.md5 b/Testing/Data/SystemTest/ILL/IN16B/165946.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..b95e1792351e9e59d7d070964835e4e85ab758ba
--- /dev/null
+++ b/Testing/Data/SystemTest/ILL/IN16B/165946.nxs.md5
@@ -0,0 +1 @@
+67fe3f993bbc6096267ec73de99814c6
diff --git a/Testing/Data/SystemTest/ILL/IN16B/165947.nxs.md5 b/Testing/Data/SystemTest/ILL/IN16B/165947.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..94fc8465900bbcdb40f60b7bdaf2c901ca3dac93
--- /dev/null
+++ b/Testing/Data/SystemTest/ILL/IN16B/165947.nxs.md5
@@ -0,0 +1 @@
+531d2ecc7074df0032f4d7a7a8992a26
diff --git a/Testing/Data/SystemTest/ILL/IN16B/165948.nxs.md5 b/Testing/Data/SystemTest/ILL/IN16B/165948.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..89849467953c38abf399bada86d54e70e01d8d1f
--- /dev/null
+++ b/Testing/Data/SystemTest/ILL/IN16B/165948.nxs.md5
@@ -0,0 +1 @@
+699016c86046ba9ba739c94a03a7ff6b
diff --git a/Testing/Data/SystemTest/ILL/IN16B/165949.nxs.md5 b/Testing/Data/SystemTest/ILL/IN16B/165949.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..399f911569b02fc28be6f2cbc651a0c00995d2b8
--- /dev/null
+++ b/Testing/Data/SystemTest/ILL/IN16B/165949.nxs.md5
@@ -0,0 +1 @@
+2602fbc6ca590088182b282ccdbc1a76
diff --git a/Testing/Data/SystemTest/ILL/IN16B/165950.nxs.md5 b/Testing/Data/SystemTest/ILL/IN16B/165950.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..215b9aa591544f2e4191a7b169898b69ca36209b
--- /dev/null
+++ b/Testing/Data/SystemTest/ILL/IN16B/165950.nxs.md5
@@ -0,0 +1 @@
+7b7f7054d68320ee943313a78c5f4a78
diff --git a/Testing/Data/SystemTest/ILL/IN16B/165951.nxs.md5 b/Testing/Data/SystemTest/ILL/IN16B/165951.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..fcb28cd7837cc1e4637a4f08c5fa155571405fab
--- /dev/null
+++ b/Testing/Data/SystemTest/ILL/IN16B/165951.nxs.md5
@@ -0,0 +1 @@
+ab39b147e556f81a1066f42cde362149
diff --git a/Testing/Data/SystemTest/ILL/IN16B/165952.nxs.md5 b/Testing/Data/SystemTest/ILL/IN16B/165952.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..003e1c5f8dbe6c275504a26857f5bd99b04c1c37
--- /dev/null
+++ b/Testing/Data/SystemTest/ILL/IN16B/165952.nxs.md5
@@ -0,0 +1 @@
+dc6e854dbed6089f441f30ba97f92a4f
diff --git a/Testing/Data/SystemTest/ILL/IN16B/165953.nxs.md5 b/Testing/Data/SystemTest/ILL/IN16B/165953.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..1f19ba18b2929c30e5ea9b66c0277ff0efa62582
--- /dev/null
+++ b/Testing/Data/SystemTest/ILL/IN16B/165953.nxs.md5
@@ -0,0 +1 @@
+e2f962ce055c9b4d320770382c06edff
diff --git a/Testing/Data/SystemTest/ILL/IN16B/170257.nxs.md5 b/Testing/Data/SystemTest/ILL/IN16B/170257.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..9dceb3c4defecf325d0ee5ff4f40a35b40582e7d
--- /dev/null
+++ b/Testing/Data/SystemTest/ILL/IN16B/170257.nxs.md5
@@ -0,0 +1 @@
+1ed58132907d70ac13c32c4e1a24e10a
diff --git a/Testing/Data/SystemTest/ILL/IN16B/170258.nxs.md5 b/Testing/Data/SystemTest/ILL/IN16B/170258.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..02d604c734d57b3fdcdb56c9e1062dc4fa9a5eac
--- /dev/null
+++ b/Testing/Data/SystemTest/ILL/IN16B/170258.nxs.md5
@@ -0,0 +1 @@
+cab2ac9431b65835ed6caa16ad710794
diff --git a/Testing/Data/SystemTest/POLARIS/test/GrpOff/offsets_2011_cycle111b.cal.md5 b/Testing/Data/SystemTest/POLARIS/Calibration/15_2/offsets_2011_cycle111b.cal.md5
similarity index 100%
rename from Testing/Data/SystemTest/POLARIS/test/GrpOff/offsets_2011_cycle111b.cal.md5
rename to Testing/Data/SystemTest/POLARIS/Calibration/15_2/offsets_2011_cycle111b.cal.md5
diff --git a/Testing/Data/SystemTest/POLARIS/VanaPeaks.dat.md5 b/Testing/Data/SystemTest/POLARIS/Calibration/VanaPeaks.dat.md5
similarity index 100%
rename from Testing/Data/SystemTest/POLARIS/VanaPeaks.dat.md5
rename to Testing/Data/SystemTest/POLARIS/Calibration/VanaPeaks.dat.md5
diff --git a/Testing/Data/SystemTest/POLARIS/test/Cycle_15_2/Mantid_tester/UserPrefFile_15_2.pref.md5 b/Testing/Data/SystemTest/POLARIS/test/Cycle_15_2/Mantid_tester/UserPrefFile_15_2.pref.md5
deleted file mode 100644
index 5f00f0b12a968849c91aa5f03bc5d803976bedb4..0000000000000000000000000000000000000000
--- a/Testing/Data/SystemTest/POLARIS/test/Cycle_15_2/Mantid_tester/UserPrefFile_15_2.pref.md5
+++ /dev/null
@@ -1 +0,0 @@
-181cdee947912603c3b77087d84691e8
diff --git a/Testing/Data/SystemTest/POLARIS/test/Cycle_15_2_exist_v/Calibration/POL_2015_2_5mm_vrod_78338_152_calfile-0.nxs.md5 b/Testing/Data/SystemTest/POLARIS/test/Cycle_15_2_exist_v/Calibration/POL_2015_2_5mm_vrod_78338_152_calfile-0.nxs.md5
deleted file mode 100644
index ad6162139772984b37367498256abfc0974e5029..0000000000000000000000000000000000000000
--- a/Testing/Data/SystemTest/POLARIS/test/Cycle_15_2_exist_v/Calibration/POL_2015_2_5mm_vrod_78338_152_calfile-0.nxs.md5
+++ /dev/null
@@ -1 +0,0 @@
-f1e3660587195e6d3523cc73ee7d4bf2
diff --git a/Testing/Data/SystemTest/POLARIS/test/Cycle_15_2_exist_v/Calibration/POL_2015_2_5mm_vrod_78338_152_calfile-1.nxs.md5 b/Testing/Data/SystemTest/POLARIS/test/Cycle_15_2_exist_v/Calibration/POL_2015_2_5mm_vrod_78338_152_calfile-1.nxs.md5
deleted file mode 100644
index 3e9fe6d905582601adfad6e4c3a60acc08c59290..0000000000000000000000000000000000000000
--- a/Testing/Data/SystemTest/POLARIS/test/Cycle_15_2_exist_v/Calibration/POL_2015_2_5mm_vrod_78338_152_calfile-1.nxs.md5
+++ /dev/null
@@ -1 +0,0 @@
-6087091d1c7d283a81b75b3cd88f321d
diff --git a/Testing/Data/SystemTest/POLARIS/test/Cycle_15_2_exist_v/Calibration/POL_2015_2_5mm_vrod_78338_152_calfile-2.nxs.md5 b/Testing/Data/SystemTest/POLARIS/test/Cycle_15_2_exist_v/Calibration/POL_2015_2_5mm_vrod_78338_152_calfile-2.nxs.md5
deleted file mode 100644
index 0708b3cae65043ba6cfa93008894d6cbc63a839f..0000000000000000000000000000000000000000
--- a/Testing/Data/SystemTest/POLARIS/test/Cycle_15_2_exist_v/Calibration/POL_2015_2_5mm_vrod_78338_152_calfile-2.nxs.md5
+++ /dev/null
@@ -1 +0,0 @@
-77ae05f72e0f0802f95fd2ba3fccd087
diff --git a/Testing/Data/SystemTest/POLARIS/test/Cycle_15_2_exist_v/Calibration/POL_2015_2_5mm_vrod_78338_152_calfile-3.nxs.md5 b/Testing/Data/SystemTest/POLARIS/test/Cycle_15_2_exist_v/Calibration/POL_2015_2_5mm_vrod_78338_152_calfile-3.nxs.md5
deleted file mode 100644
index 5dd840956eafa62659145b9067f674cf7c6f884a..0000000000000000000000000000000000000000
--- a/Testing/Data/SystemTest/POLARIS/test/Cycle_15_2_exist_v/Calibration/POL_2015_2_5mm_vrod_78338_152_calfile-3.nxs.md5
+++ /dev/null
@@ -1 +0,0 @@
-510197d1d44fa3b279f4fc981ce703ac
diff --git a/Testing/Data/SystemTest/POLARIS/test/Cycle_15_2_exist_v/Calibration/POL_2015_2_5mm_vrod_78338_152_calfile-4.nxs.md5 b/Testing/Data/SystemTest/POLARIS/test/Cycle_15_2_exist_v/Calibration/POL_2015_2_5mm_vrod_78338_152_calfile-4.nxs.md5
deleted file mode 100644
index aa74d7e3cad5652519d86cb8c938f19c39b72db7..0000000000000000000000000000000000000000
--- a/Testing/Data/SystemTest/POLARIS/test/Cycle_15_2_exist_v/Calibration/POL_2015_2_5mm_vrod_78338_152_calfile-4.nxs.md5
+++ /dev/null
@@ -1 +0,0 @@
-8ba462ec3983bb903fc39cc1f3a3b0b6
diff --git a/Testing/Data/SystemTest/POLARIS/test/Cycle_15_2_exist_v/Mantid_tester/UserPrefFile_15_2_original.pref.md5 b/Testing/Data/SystemTest/POLARIS/test/Cycle_15_2_exist_v/Mantid_tester/UserPrefFile_15_2_original.pref.md5
deleted file mode 100644
index 6f97e4a99d0e40a8b418cb455c890893524888ac..0000000000000000000000000000000000000000
--- a/Testing/Data/SystemTest/POLARIS/test/Cycle_15_2_exist_v/Mantid_tester/UserPrefFile_15_2_original.pref.md5
+++ /dev/null
@@ -1 +0,0 @@
-3fbc605d28a75a557d4e4303ffca85f5
diff --git a/Testing/Data/SystemTest/POLARIS/test/Cycle_16_1/Mantid_tester/UserPrefFile_16_1_si_calfile_from_all_spectra_emptysub.pref.md5 b/Testing/Data/SystemTest/POLARIS/test/Cycle_16_1/Mantid_tester/UserPrefFile_16_1_si_calfile_from_all_spectra_emptysub.pref.md5
deleted file mode 100644
index a7fa86ecc10fd1aa763ef050ac3fb4271582d0a5..0000000000000000000000000000000000000000
--- a/Testing/Data/SystemTest/POLARIS/test/Cycle_16_1/Mantid_tester/UserPrefFile_16_1_si_calfile_from_all_spectra_emptysub.pref.md5
+++ /dev/null
@@ -1 +0,0 @@
-4a9ebc458ba4da83daf75b62e67f25b9
diff --git a/Testing/Data/SystemTest/POLARIS/test/GrpOff/Cycle_12_2_group_masked_collimator.cal.md5 b/Testing/Data/SystemTest/POLARIS/test/GrpOff/Cycle_12_2_group_masked_collimator.cal.md5
deleted file mode 100644
index 34294ada8e941c6d6f3e40e85bbd04e10ab31b83..0000000000000000000000000000000000000000
--- a/Testing/Data/SystemTest/POLARIS/test/GrpOff/Cycle_12_2_group_masked_collimator.cal.md5
+++ /dev/null
@@ -1 +0,0 @@
-c2fa198cf2c4a1cdf86350cafba365fe
diff --git a/Testing/Data/SystemTest/POLARIS/test/GrpOff/Cycle_12_2_group_masked_collimator_no_b5mod6.cal.md5 b/Testing/Data/SystemTest/POLARIS/test/GrpOff/Cycle_12_2_group_masked_collimator_no_b5mod6.cal.md5
deleted file mode 100644
index e53853c8aa73f2b50b14b55a0e8fa9ac39c49c59..0000000000000000000000000000000000000000
--- a/Testing/Data/SystemTest/POLARIS/test/GrpOff/Cycle_12_2_group_masked_collimator_no_b5mod6.cal.md5
+++ /dev/null
@@ -1 +0,0 @@
-ba22e9d51e4fb5b4615eb9704dacbd0e
diff --git a/Testing/Data/SystemTest/POLARIS/test/GrpOff/cycle_15_2_silicon_all_spectra.cal.md5 b/Testing/Data/SystemTest/POLARIS/test/GrpOff/cycle_15_2_silicon_all_spectra.cal.md5
deleted file mode 100644
index 9e0d18b9170c45b166ea6f13ad9393e39620dc84..0000000000000000000000000000000000000000
--- a/Testing/Data/SystemTest/POLARIS/test/GrpOff/cycle_15_2_silicon_all_spectra.cal.md5
+++ /dev/null
@@ -1 +0,0 @@
-a2fa4fdacf3981540787a0ccd5a6ce2c
diff --git a/Testing/Data/SystemTest/POLARIS/test/GrpOff/cycle_16_1_silicon_all_spectra.cal.md5 b/Testing/Data/SystemTest/POLARIS/test/GrpOff/cycle_16_1_silicon_all_spectra.cal.md5
deleted file mode 100644
index c38af736896e08941e5b0728878373eb7c36b2d6..0000000000000000000000000000000000000000
--- a/Testing/Data/SystemTest/POLARIS/test/GrpOff/cycle_16_1_silicon_all_spectra.cal.md5
+++ /dev/null
@@ -1 +0,0 @@
-3e6766a5dc14c34f400884027bba82b8
diff --git a/Testing/Data/SystemTest/WISH17701_calibration_panel103_tube3.nxs.md5 b/Testing/Data/SystemTest/WISH17701_calibration_panel103_tube3.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..493e99c0d094050cce0d657d4513fdf1d793ad22
--- /dev/null
+++ b/Testing/Data/SystemTest/WISH17701_calibration_panel103_tube3.nxs.md5
@@ -0,0 +1 @@
+a32c3ce038d1c0cb85a08b8bddab5101
diff --git a/Testing/Data/SystemTest/WISH30541_integrated.nxs.md5 b/Testing/Data/SystemTest/WISH30541_integrated.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..093588464563304a3846c5134accbb5690dcacca
--- /dev/null
+++ b/Testing/Data/SystemTest/WISH30541_integrated.nxs.md5
@@ -0,0 +1 @@
+5b13fd61ca4f9b7312b3e920367fdfdf
diff --git a/Testing/Data/UnitTest/6749948083a1d97757b56cb5924415b4 b/Testing/Data/UnitTest/6749948083a1d97757b56cb5924415b4
deleted file mode 100644
index ba8b60e4f5cfd8dcb94931e88877f58844a6af5d..0000000000000000000000000000000000000000
Binary files a/Testing/Data/UnitTest/6749948083a1d97757b56cb5924415b4 and /dev/null differ
diff --git a/Testing/Data/UnitTest/ILL/IN16B/083072.nxs.md5 b/Testing/Data/UnitTest/ILL/IN16B/083072.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..8cb7bd805f56a90296d22e1e4fa4499d7107ca94
--- /dev/null
+++ b/Testing/Data/UnitTest/ILL/IN16B/083072.nxs.md5
@@ -0,0 +1 @@
+9b7ec5c7d60f909f238ea044c4fff868
diff --git a/Testing/Data/UnitTest/ILL/IN16B/083073.nxs.md5 b/Testing/Data/UnitTest/ILL/IN16B/083073.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..cb7bbc29814ea823c959948d135c2c9fc40c916d
--- /dev/null
+++ b/Testing/Data/UnitTest/ILL/IN16B/083073.nxs.md5
@@ -0,0 +1 @@
+68137440a0a015bde36b1048636e0180
diff --git a/Testing/Data/UnitTest/ILL/IN16B/083074.nxs.md5 b/Testing/Data/UnitTest/ILL/IN16B/083074.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..4b310a70015cdd2137cabc656930c592a5287bda
--- /dev/null
+++ b/Testing/Data/UnitTest/ILL/IN16B/083074.nxs.md5
@@ -0,0 +1 @@
+94060de1d70493916eee6c893841ddff
diff --git a/Testing/Data/UnitTest/ILL/IN16B/083075.nxs.md5 b/Testing/Data/UnitTest/ILL/IN16B/083075.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..3250d631d2817f1ec1428a50160462553dc534a5
--- /dev/null
+++ b/Testing/Data/UnitTest/ILL/IN16B/083075.nxs.md5
@@ -0,0 +1 @@
+9e6124a01647404668ce67e561c5cdc5
diff --git a/Testing/Data/UnitTest/ILL/IN16B/083076.nxs.md5 b/Testing/Data/UnitTest/ILL/IN16B/083076.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..77dfaf8e824fa795c96bc2326537032b5333c2fb
--- /dev/null
+++ b/Testing/Data/UnitTest/ILL/IN16B/083076.nxs.md5
@@ -0,0 +1 @@
+ef115ee9c951c223fc621423841dc3d6
diff --git a/Testing/Data/UnitTest/ILL/IN16B/083077.nxs.md5 b/Testing/Data/UnitTest/ILL/IN16B/083077.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..fa8c4b957cadd14603df832438f01796f559271b
--- /dev/null
+++ b/Testing/Data/UnitTest/ILL/IN16B/083077.nxs.md5
@@ -0,0 +1 @@
+0c6e646c58481e51e842c3b4657e361e
diff --git a/Testing/Data/UnitTest/ILL/IN16B/090661.nxs.md5 b/Testing/Data/UnitTest/ILL/IN16B/090661.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..24c0a2021b7e4dc761f364e0a267e2afacad2ce8
--- /dev/null
+++ b/Testing/Data/UnitTest/ILL/IN16B/090661.nxs.md5
@@ -0,0 +1 @@
+227a30f45939151ecf719eaa1c1bc024
diff --git a/Testing/Data/UnitTest/ILL/IN16B/136558.nxs.md5 b/Testing/Data/UnitTest/ILL/IN16B/136558.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..3782eb6e819d484d3a634a02b2d099973c75ce3e
--- /dev/null
+++ b/Testing/Data/UnitTest/ILL/IN16B/136558.nxs.md5
@@ -0,0 +1 @@
+548c95d89b28145e3184748840c77103
diff --git a/Testing/Data/UnitTest/ILL/IN16B/136559.nxs.md5 b/Testing/Data/UnitTest/ILL/IN16B/136559.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..2d37742e09ced53e0b16e916fcd7f9e4bc2c2d08
--- /dev/null
+++ b/Testing/Data/UnitTest/ILL/IN16B/136559.nxs.md5
@@ -0,0 +1 @@
+8b44d4f73a4c0574292f43786f746779
diff --git a/Testing/Data/UnitTest/ILL/IN16B/143720.nxs.md5 b/Testing/Data/UnitTest/ILL/IN16B/143720.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..4a8af5dc66f3569134d7b7d55445ec84e8056be9
--- /dev/null
+++ b/Testing/Data/UnitTest/ILL/IN16B/143720.nxs.md5
@@ -0,0 +1 @@
+9a219e396d5889690e9c74e6fc557914
diff --git a/Testing/Data/UnitTest/ILL/IN16B/170257.nxs.md5 b/Testing/Data/UnitTest/ILL/IN16B/170257.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..9dceb3c4defecf325d0ee5ff4f40a35b40582e7d
--- /dev/null
+++ b/Testing/Data/UnitTest/ILL/IN16B/170257.nxs.md5
@@ -0,0 +1 @@
+1ed58132907d70ac13c32c4e1a24e10a
diff --git a/Testing/Data/UnitTest/ILL/IN16B/170258.nxs.md5 b/Testing/Data/UnitTest/ILL/IN16B/170258.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..02d604c734d57b3fdcdb56c9e1062dc4fa9a5eac
--- /dev/null
+++ b/Testing/Data/UnitTest/ILL/IN16B/170258.nxs.md5
@@ -0,0 +1 @@
+cab2ac9431b65835ed6caa16ad710794
diff --git a/Testing/Data/UnitTest/ILL/IN16B/170299.nxs.md5 b/Testing/Data/UnitTest/ILL/IN16B/170299.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..f7555bc90fadca14a90445bafd55807f4c46c0ae
--- /dev/null
+++ b/Testing/Data/UnitTest/ILL/IN16B/170299.nxs.md5
@@ -0,0 +1 @@
+c4f7cb05d6524559d7735dcd452fb7fc
diff --git a/Testing/Data/UnitTest/ILL/IN16B/170300.nxs.md5 b/Testing/Data/UnitTest/ILL/IN16B/170300.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..dad726d5c04bd67be9729b43c32aab352c282201
--- /dev/null
+++ b/Testing/Data/UnitTest/ILL/IN16B/170300.nxs.md5
@@ -0,0 +1 @@
+12b1e5f2d32862f4f9d65926e72a4bec
diff --git a/Testing/Data/UnitTest/ILL/IN16B/170301.nxs.md5 b/Testing/Data/UnitTest/ILL/IN16B/170301.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..3fba0980a784181da11a006edd7b0b647216a499
--- /dev/null
+++ b/Testing/Data/UnitTest/ILL/IN16B/170301.nxs.md5
@@ -0,0 +1 @@
+7021a39c1d93450a9923f45feb6f8899
diff --git a/Testing/Data/UnitTest/ILL/IN16B/170302.nxs.md5 b/Testing/Data/UnitTest/ILL/IN16B/170302.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..98a91129e07795848d3c88d70659696189a9844a
--- /dev/null
+++ b/Testing/Data/UnitTest/ILL/IN16B/170302.nxs.md5
@@ -0,0 +1 @@
+2f0a5a9a7ac549142452d71bdb2df407
diff --git a/Testing/Data/UnitTest/ILL/IN16B/170303.nxs.md5 b/Testing/Data/UnitTest/ILL/IN16B/170303.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..47ce69eeb611fe1bf6fe8e27219819e7ee9564f6
--- /dev/null
+++ b/Testing/Data/UnitTest/ILL/IN16B/170303.nxs.md5
@@ -0,0 +1 @@
+278e5ac75214c46e9ce0292a852c5a30
diff --git a/Testing/Data/UnitTest/ILL/IN16B/170304.nxs.md5 b/Testing/Data/UnitTest/ILL/IN16B/170304.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..7ac52266f41aa5588a3611851907e7ae22ff73b0
--- /dev/null
+++ b/Testing/Data/UnitTest/ILL/IN16B/170304.nxs.md5
@@ -0,0 +1 @@
+1a53475772e856d0c0d97db5464a0538
diff --git a/Testing/Data/UnitTest/LARMOR00002260.nxs.md5 b/Testing/Data/UnitTest/LARMOR00002260.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..d49f44b50a2d6cd916a5940a9375dd471541ab71
--- /dev/null
+++ b/Testing/Data/UnitTest/LARMOR00002260.nxs.md5
@@ -0,0 +1 @@
+ecedafb102297a4db6b28d98c7269911
diff --git a/Testing/Data/UnitTest/LOQ74044.nxs.md5 b/Testing/Data/UnitTest/LOQ74044.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..8d152470cffe576ab959f68c1363f713a32d8190
--- /dev/null
+++ b/Testing/Data/UnitTest/LOQ74044.nxs.md5
@@ -0,0 +1 @@
+79020b3973e727f535dd90295773b589
diff --git a/Testing/Data/UnitTest/OSIRIS00100320.nxs.md5 b/Testing/Data/UnitTest/OSIRIS00100320.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..5ab22446e5f3e952ecb0e2310eb45839308346d6
--- /dev/null
+++ b/Testing/Data/UnitTest/OSIRIS00100320.nxs.md5
@@ -0,0 +1 @@
+e180bbc8da57ffeae72ebfbefc42b87a
diff --git a/Testing/Data/UnitTest/OSIRIS00100321.nxs.md5 b/Testing/Data/UnitTest/OSIRIS00100321.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..93c18d1f8f270af0aa892eb79479691158a86b58
--- /dev/null
+++ b/Testing/Data/UnitTest/OSIRIS00100321.nxs.md5
@@ -0,0 +1 @@
+eb9d9c7ed33feb38cb1b7e49f8306934
diff --git a/Testing/Data/UnitTest/PG3_char_2016_02_15-PAC-extras.txt.md5 b/Testing/Data/UnitTest/PG3_char_2016_02_15-PAC-extras.txt.md5
new file mode 100644
index 0000000000000000000000000000000000000000..653779ae3bb21c28ed5e19bf9756f748fe651980
--- /dev/null
+++ b/Testing/Data/UnitTest/PG3_char_2016_02_15-PAC-extras.txt.md5
@@ -0,0 +1 @@
+f967a10877197e2001bbc9b0fc97a35f
diff --git a/Testing/Data/UnitTest/PG3_char_2016_02_15-PAC-single.txt.md5 b/Testing/Data/UnitTest/PG3_char_2016_02_15-PAC-single.txt.md5
new file mode 100644
index 0000000000000000000000000000000000000000..171a6052c6c2250c31d8a06874a5de116ee1a8b9
--- /dev/null
+++ b/Testing/Data/UnitTest/PG3_char_2016_02_15-PAC-single.txt.md5
@@ -0,0 +1 @@
+0e43e0df640fd2942e63eaed6eded61a
diff --git a/Testing/Data/UnitTest/SANS2D00022024.nxs.md5 b/Testing/Data/UnitTest/SANS2D00022024.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..750d54bfc729cbd04462c301426a745e9823f5b4
--- /dev/null
+++ b/Testing/Data/UnitTest/SANS2D00022024.nxs.md5
@@ -0,0 +1 @@
+d8df0c8d545bb4462e88e501f1677170
diff --git a/Testing/Data/UnitTest/SANS2D00022048.nxs.md5 b/Testing/Data/UnitTest/SANS2D00022048.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..1f3de952d451eef3f09710a6f23ef5e1d4fea3e3
--- /dev/null
+++ b/Testing/Data/UnitTest/SANS2D00022048.nxs.md5
@@ -0,0 +1 @@
+bb63c083b4fb7373f1a2a33d1b8946bb
diff --git a/Testing/Data/UnitTest/Test_characterizations_focus_and_char2.txt.md5 b/Testing/Data/UnitTest/Test_characterizations_focus_and_char2.txt.md5
index 2b5dbb8e19433df4227649c582fd41f4fc503784..4723faeca4f9b41e52b1b78b430409788e807261 100644
--- a/Testing/Data/UnitTest/Test_characterizations_focus_and_char2.txt.md5
+++ b/Testing/Data/UnitTest/Test_characterizations_focus_and_char2.txt.md5
@@ -1 +1 @@
-41818fb1ca9c7b626b5c9e835be9f102
+f50c1ba7ce539b45c22d80d0df3ef587
diff --git a/Testing/Data/UnitTest/fa47dee6f10804d3f6ecae4c0f5cc8a6 b/Testing/Data/UnitTest/fa47dee6f10804d3f6ecae4c0f5cc8a6
deleted file mode 100644
index 44b7ab4d605633004b2abb5a91ce1de829734536..0000000000000000000000000000000000000000
Binary files a/Testing/Data/UnitTest/fa47dee6f10804d3f6ecae4c0f5cc8a6 and /dev/null differ
diff --git a/Testing/PerformanceTests/analysis.py b/Testing/PerformanceTests/analysis.py
index ce43ba06434efbc0a5b71581835756661f8ac687..db63df60163ade9215664910d82e858c6a506caf 100644
--- a/Testing/PerformanceTests/analysis.py
+++ b/Testing/PerformanceTests/analysis.py
@@ -14,7 +14,21 @@ import datetime
 import random
 
 # This is the date string format as returned by the database
-DATE_STR_FORMAT = "%Y-%m-%d %H:%M:%S.%f"
+DATE_STR_FORMAT_MICRO = "%Y-%m-%d %H:%M:%S.%f"
+DATE_STR_FORMAT_NO_MICRO = "%Y-%m-%d %H:%M:%S"
+
+#============================================================================================
+def to_datetime(formatted_str):
+    """Return a datetime object from a formatted string
+
+    It deals with the possible absence of a microseconds field
+    """
+    try:
+        date = datetime.datetime.strptime(formatted_str, DATE_STR_FORMAT_MICRO)
+    except ValueError:
+        date = datetime.datetime.strptime(formatted_str, DATE_STR_FORMAT_NO_MICRO)
+
+    return date
 
 #============================================================================================
 def get_orderby_clause(last_num):
@@ -112,8 +126,7 @@ def smart_ticks(index, values):
         dates = []
         for val in values:
             try:
-                datetime.datetime.strptime(val, DATE_STR_FORMAT)
-                dates.append(val)
+                dates.append(to_datetime(val))
             except:
                 pass
         if len(dates) == 0: return
@@ -402,7 +415,7 @@ def how_long_ago(timestr):
     in human-friendly way """
     import time
     now = datetime.datetime.now()
-    then = datetime.datetime.strptime(timestr, DATE_STR_FORMAT)
+    then = to_datetime(timestr)
     td = (now-then)
     sec = td.seconds
     min = int(sec / 60)
@@ -454,7 +467,7 @@ def get_html_summary_table(test_names):
             html += """<td>%s</td>""" % res['status']
 
             # Friendly date
-            date = datetime.datetime.strptime(res['date'], DATE_STR_FORMAT)
+            date = to_datetime(res['date'])
             html += """<td>%s</td>""" %  date.strftime("%b %d, %H:%M:%S")
 
             html += """<td>%s</td>""" % res['runtime']
@@ -670,4 +683,3 @@ if __name__ == "__main__":
 #    plot_runtime(name='MyFakeTest', x_field='date')
 #    plot_success_count()
 #    show()
-
diff --git a/Testing/SystemTests/lib/systemtests/stresstesting.py b/Testing/SystemTests/lib/systemtests/stresstesting.py
index d58a2e48fb0a7ffdea5779f5e1115e463cf799ac..681ed17de152a0e7a17d0ae289b863e091eb9d22 100644
--- a/Testing/SystemTests/lib/systemtests/stresstesting.py
+++ b/Testing/SystemTests/lib/systemtests/stresstesting.py
@@ -22,6 +22,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 File change history is stored at: <https://github.com/mantidproject/systemtests>.
 '''
+from __future__ import (absolute_import, division, print_function)
 import datetime
 import imp
 import inspect
@@ -34,6 +35,7 @@ import sys
 import tempfile
 import time
 import unittest
+from six import PY3
 
 # Path to this file
 THIS_MODULE_DIR = os.path.dirname(os.path.realpath(__file__))
@@ -140,7 +142,7 @@ class MantidStressTest(unittest.TestCase):
             for item in candidates:
                 if os.path.exists(item):
                     return True
-        except RuntimeError, e:
+        except RuntimeError as e:
             return False
                 
 
@@ -161,7 +163,7 @@ class MantidStressTest(unittest.TestCase):
         # check that all of the files exist
         for filename in reqFiles:
             if not self.__verifyRequiredFile(filename):
-                print "Missing required file: '%s'" % filename
+                print("Missing required file: '%s'" % filename)
                 foundAll = False
 
         if not foundAll:
@@ -177,7 +179,7 @@ class MantidStressTest(unittest.TestCase):
         from mantid.kernel import MemoryStats
         MB_avail = MemoryStats().availMem()/(1024.)
         if (MB_avail < required):
-            print "Insufficient memory available to run test! %g MB available, need %g MB." % (MB_avail,required)
+            print("Insufficient memory available to run test! %g MB available, need %g MB." % (MB_avail,required))
             sys.exit(TestRunner.SKIP_TEST)
 
     def execute(self):
@@ -244,9 +246,9 @@ class MantidStressTest(unittest.TestCase):
                 msg = "(whitespace striped from ends)"
             else:
                 msg = ""
-            print "******************* Difference in files", msg
-            print "\n".join(result)
-            print "*******************"
+            print("******************* Difference in files", msg)
+            print("\n".join(result))
+            print("*******************")
             return False
         else:
             return True
@@ -275,7 +277,7 @@ class MantidStressTest(unittest.TestCase):
 
             if not(self.validateWorkspaces(valPair,mismatchName)):
                 validationResult = False;
-                print 'Workspace {0} not equal to its reference file'.format(valNames[ik]);
+                print('Workspace {0} not equal to its reference file'.format(valNames[ik]));
         #end check All results
 
         return validationResult;
@@ -311,7 +313,7 @@ class MantidStressTest(unittest.TestCase):
             checker.setPropertyValue("Check"+d,"0")
         checker.execute()
         if checker.getPropertyValue("Result") != 'Success!':
-            print self.__class__.__name__
+            print(self.__class__.__name__)
             if mismatchName:
                 SaveNexus(InputWorkspace=valNames[0],Filename=self.__class__.__name__+mismatchName+'-mismatch.nxs')
             else:
@@ -445,6 +447,12 @@ class TestResult(object):
         self.output = ''
         self.err = ''
     
+    def __eq__(self, other):
+        return self.name == other.name
+
+    def __lt__(self, other):
+        return self.name < other.name
+
     def addItem(self, item):
         '''
         Add an item to the store, this should be a list containing 2 entries: [Name, Value]
@@ -487,10 +495,10 @@ class TextResultReporter(ResultReporter):
         Print the results to standard out
         '''
         nstars = 30
-        print '*' * nstars
+        print('*' * nstars)
         for t in result.resultLogs():
-            print '\t' + str(t[0]).ljust(15) + '->  ', str(t[1])
-        print '*' * nstars
+            print('\t' + str(t[0]).ljust(15) + '->  ', str(t[1]))
+        print('*' * nstars)
 
 #########################################################################
 # A class to report results as junit xml
@@ -545,7 +553,7 @@ class TestRunner(object):
         tmp_file.write(script.asString())
         tmp_file.close()
         cmd = exec_call + ' ' + tmp_file.name
-        print "Executing test script '%s'" % (cmd)
+        print("Executing test script '%s'" % (cmd))
         results = self.spawnSubProcess(cmd)
         os.remove(tmp_file.name)
         return results
@@ -623,7 +631,7 @@ class TestSuite(object):
         self._result.status = 'skipped'
 
     def execute(self, runner):
-        print time.strftime("%a, %d %b %Y %H:%M:%S", time.localtime()) + ': Executing ' + self._fqtestname
+        print(time.strftime("%a, %d %b %Y %H:%M:%S", time.localtime()) + ': Executing ' + self._fqtestname)
         if self._test_cls_name is not None:
           script = TestScript(self._test_dir, self._modname, self._test_cls_name)
           # Start the new process and wait until it finishes
@@ -653,7 +661,10 @@ class TestSuite(object):
         self._result.status = status
         self._result.addItem(['status', status])
         # Dump std out so we know what happened
-        print output
+        if PY3:
+            if isinstance(output, bytes):
+                output = output.decode()
+        print(output)
         self._result.output = output
         all_lines = output.split('\n')
         # Find the test results
@@ -694,7 +705,7 @@ class TestManager(object):
             self._tests = self.loadTestsFromDir(test_dir)
         else:
             if os.path.exists(test_loc) == False:
-                print 'Cannot find file ' + test_loc + '.py. Please check the path.'
+                print('Cannot find file ' + test_loc + '.py. Please check the path.')
                 exit(2)
             test_dir = os.path.abspath(os.path.dirname(test_loc)).replace('\\','/')
             sys.path.append(test_dir)
@@ -702,7 +713,7 @@ class TestManager(object):
             self._tests = self.loadTestsFromModule(os.path.basename(test_loc))
 
         if len(self._tests) == 0:
-            print 'No tests defined in ' + test_dir + '. Please ensure all test classes sub class stresstesting.MantidStressTest.'
+            print('No tests defined in ' + test_dir + '. Please ensure all test classes sub class stresstesting.MantidStressTest.')
             exit(2)
 
         self._passedTests = 0
@@ -778,8 +789,8 @@ class TestManager(object):
                 if self.isValidTestClass(value):
                     test_name = key
                     tests.append(TestSuite(self._runner.getTestDir(), modname, test_name, filename))
-        except Exception, exc:
-            print "Error importing module '%s': %s" % (modname, str(exc))
+        except Exception as exc:
+            print("Error importing module '%s': %s" % (modname, str(exc)))
             # Error loading the source, add fake unnamed test so that an error
             # will get generated when the tests are run and it will be counted properly
             tests.append(TestSuite(self._runner.getTestDir(), modname, None, filename))
@@ -821,7 +832,7 @@ class MantidFrameworkConfig:
         # setup the rest of the magic directories
         self.__saveDir = save_dir
         if not os.path.exists(save_dir):
-            print "Making directory %s to save results" % save_dir
+            print("Making directory %s to save results" % save_dir)
             os.mkdir(save_dir)
 
         else:
diff --git a/Testing/SystemTests/lib/systemtests/xmlreporter.py b/Testing/SystemTests/lib/systemtests/xmlreporter.py
index a991fe30f7df74415e523740cc7ee4abcbabc15a..046f777f2376708df39a750c48458e3139ccd466 100644
--- a/Testing/SystemTests/lib/systemtests/xmlreporter.py
+++ b/Testing/SystemTests/lib/systemtests/xmlreporter.py
@@ -1,3 +1,4 @@
+from __future__ import (absolute_import, division, print_function)
 import os
 import sys
 from xml.dom.minidom import getDOMImplementation
@@ -20,15 +21,15 @@ class XmlResultReporter(stresstesting.ResultReporter):
 		# print the command line summary version of the results
 		self._failures.sort()
 		self._skipped.sort()
-		print
+		print()
 		if self._show_skipped and len(self._skipped) > 0:
-			print "SKIPPED:"
+			print("SKIPPED:")
 			for test in self._skipped:
-				print test.name
+				print(test.name)
 		if len(self._failures) > 0:
-			print "FAILED:"
+			print("FAILED:")
 			for test in self._failures:
-				print test.name
+				print(test.name)
 
 		# return the xml document version
 		docEl = self._doc.documentElement
diff --git a/Testing/SystemTests/scripts/runSystemTests.py b/Testing/SystemTests/scripts/runSystemTests.py
index dfa0df192a229ea3eab90216904d7869fa95b063..8218d96370de0188d15d19bb130dd049b42261b2 100755
--- a/Testing/SystemTests/scripts/runSystemTests.py
+++ b/Testing/SystemTests/scripts/runSystemTests.py
@@ -1,5 +1,6 @@
 #!/usr/bin/env python
 
+from __future__ import (absolute_import, division, print_function)
 import optparse
 import os
 import sys
@@ -97,15 +98,15 @@ xml_report.close()
 if options.makeprop:
   mtdconf.restoreconfig()
 
-print
+print()
 if mgr.skippedTests == mgr.totalTests:
-  print "All tests were skipped"
+  print("All tests were skipped")
   success = False # fail if everything was skipped
 else:
   percent = 1.-float(mgr.failedTests)/float(mgr.totalTests-mgr.skippedTests)
   percent = int(100. * percent)
-  print "%d%s tests passed, %d tests failed out of %d (%d skipped)" % \
-      (percent, '%', mgr.failedTests, (mgr.totalTests-mgr.skippedTests), mgr.skippedTests)
-print 'All tests passed? ' + str(success)
+  print("%d%s tests passed, %d tests failed out of %d (%d skipped)" % \
+      (percent, '%', mgr.failedTests, (mgr.totalTests-mgr.skippedTests), mgr.skippedTests))
+print('All tests passed? ' + str(success))
 if not success:
   sys.exit(1)
diff --git a/Testing/SystemTests/tests/analysis/Diffraction_Workflow_Test.py b/Testing/SystemTests/tests/analysis/Diffraction_Workflow_Test.py
index cf31d80448fa53a39f138af632729d32f5840608..8bf30b29f873b6903f4672a570b0b28069d2460a 100644
--- a/Testing/SystemTests/tests/analysis/Diffraction_Workflow_Test.py
+++ b/Testing/SystemTests/tests/analysis/Diffraction_Workflow_Test.py
@@ -75,7 +75,7 @@ class Diffraction_Workflow_Test(stresstesting.MantidStressTest):
         ## TODO conventional cell
 
         # And index to HKL
-        dummy_alg = IndexPeaks(PeaksWorkspace=ws+'_peaksFFT', Tolerance='0.12')
+        IndexPeaks(PeaksWorkspace=ws+'_peaksFFT', Tolerance='0.12')
 
         # Integrate peaks in Q space using spheres
         IntegratePeaksMD(InputWorkspace=ws+'_MD2',PeakRadius='0.12',
diff --git a/Testing/SystemTests/tests/analysis/DirectInelasticDiagnostic.py b/Testing/SystemTests/tests/analysis/DirectInelasticDiagnostic.py
index 609b5476ed90dc964e0117cb2fcccd048c2f40ad..804d2d3ad6c8ccd6851e7fc95f5dfe9a944fa03e 100644
--- a/Testing/SystemTests/tests/analysis/DirectInelasticDiagnostic.py
+++ b/Testing/SystemTests/tests/analysis/DirectInelasticDiagnostic.py
@@ -49,8 +49,9 @@ class DirectInelasticDiagnostic(MantidStressTest):
         # Save the masked spectra nmubers to a simple ASCII file for comparison
         self.saved_diag_file = os.path.join(ms.config['defaultsave.directory'], 'CurrentDirectInelasticDiag.txt')
         handle = file(self.saved_diag_file, 'w')
+        spectrumInfo = sample_ws.spectrumInfo()
         for index in range(sample_ws.getNumberHistograms()):
-            if sample_ws.getDetector(index).isMasked():
+            if spectrumInfo.isMasked(index):
                 spec_no = sample_ws.getSpectrum(index).getSpectrumNo()
                 handle.write(str(spec_no) + '\n')
         handle.close()
diff --git a/Testing/SystemTests/tests/analysis/DirectInelasticDiagnostic2.py b/Testing/SystemTests/tests/analysis/DirectInelasticDiagnostic2.py
index 2b002c01a0a5740143bfa445b6d6a42b8168fca8..3c79e78655b74815194651e8506eb1f7376533a4 100644
--- a/Testing/SystemTests/tests/analysis/DirectInelasticDiagnostic2.py
+++ b/Testing/SystemTests/tests/analysis/DirectInelasticDiagnostic2.py
@@ -71,8 +71,9 @@ class DirectInelasticDiagnostic2(MantidStressTest):
         self.saved_diag_file = os.path.join(config['defaultsave.directory'],
                                             'CurrentDirectInelasticDiag2.txt')
         handle = file(self.saved_diag_file, 'w')
+        spectrumInfo = sample.spectrumInfo()
         for index in range(sample.getNumberHistograms()):
-            if sample.getDetector(index).isMasked():
+            if spectrumInfo.isMasked(index):
                 spec_no = sample.getSpectrum(index).getSpectrumNo()
                 handle.write(str(spec_no) + '\n')
         handle.close()
diff --git a/Testing/SystemTests/tests/analysis/EnggCalibrationTest.py b/Testing/SystemTests/tests/analysis/EnggCalibrationTest.py
index 64617343118bda8249b89c1131094167e414b2e2..51971cb36097c9111a61cadc9a91c40848e79b0b 100644
--- a/Testing/SystemTests/tests/analysis/EnggCalibrationTest.py
+++ b/Testing/SystemTests/tests/analysis/EnggCalibrationTest.py
@@ -74,21 +74,21 @@ class EnginXFocusWithVanadiumCorrection(stresstesting.MantidStressTest):
 
     def validate(self):
         out_ws = mtd[self.out_ws_name]
-        self.assertEquals(out_ws.getName(), self.out_ws_name)
+        self.assertEquals(out_ws.name(), self.out_ws_name)
         self.assertEqual(out_ws.getNumberHistograms(), 1)
         self.assertEqual(out_ws.blocksize(), 10186)
         self.assertEqual(out_ws.getNEvents(), 10186)
         self.assertEqual(out_ws.getNumDims(), 2)
         self.assertEqual(out_ws.YUnit(), 'Counts')
         dimX = out_ws.getXDimension()
-        self.assertEqual(dimX.getName(), 'Time-of-flight')
+        self.assertEqual(dimX.name, 'Time-of-flight')
         self.assertEqual(dimX.getUnits(), 'microsecond')
         dimY = out_ws.getYDimension()
         self.assertEqual(dimY.getName(), 'Spectrum')
         self.assertEqual(dimY.getUnits(), '')
 
         van_out_ws = mtd[self.van_bank_curves_name]
-        self.assertEquals(van_out_ws.getName(), self.van_bank_curves_name)
+        self.assertEquals(van_out_ws.name(), self.van_bank_curves_name)
         self.assertTrue(van_out_ws.getNumberHistograms(), 3)
         self.assertEqual(out_ws.blocksize(), 10186)
 
diff --git a/Testing/SystemTests/tests/analysis/FittingBenchmarks.py b/Testing/SystemTests/tests/analysis/FittingBenchmarks.py
new file mode 100644
index 0000000000000000000000000000000000000000..ea2d43b7efa47b6a92cfd895e731bd24737d24fa
--- /dev/null
+++ b/Testing/SystemTests/tests/analysis/FittingBenchmarks.py
@@ -0,0 +1,152 @@
+"""
+This systemtest tests that the fit executes with different minimizers for the fitting test problems used for benchmarking minimizers.
+
+Note the complete benchmarking suite is not tested here since I find this takes too long, but enough to provide
+an additional health test of Mantid fitting and to test that the scripts used for fit minimizer benchmarking are working.
+
+Fitting problem are stored as follows in the FittingTestProblems directory:
+
+        CUTEst/
+        NIST_nonlinear_regression/
+        Neutron_data/
+
+For more information what these problems are see the Mantid FittingMinimizers concept page.
+"""
+from __future__ import (absolute_import, division, print_function)
+
+import unittest
+import stresstesting
+
+import os
+
+import mantid.simpleapi as msapi
+import fitting_benchmarking as fitbk
+import results_output as fitout
+
+
+class FittingBenchmarkTests(unittest.TestCase):
+
+    def setUp(self):
+        self.color_scale = [(1.1, 'ranking-top-1'),
+                            (1.33, 'ranking-top-2'),
+                            (1.75, 'ranking-med-3'),
+                            (3, 'ranking-low-4'),
+                            (float('nan'), 'ranking-low-5')
+                            ]
+
+        # Create the path for the specific fitting test files location
+        input_data_dir = msapi.config['datasearch.directories'].split(';')[0]
+        self.base_problem_files_dir = os.path.join(input_data_dir, 'FittingTestProblems')
+
+    def test_all_nist_problem(self):
+        """
+        Runs benchmark on all NIST problems on about half of the available Mantid minimizers
+        and without using weights.
+        """
+
+        minimizers = ['BFGS', 'Conjugate gradient (Fletcher-Reeves imp.)',
+                      'Conjugate gradient (Polak-Ribiere imp.)', 'Damped GaussNewton']
+        group_names = ['NIST, "lower" difficulty', 'NIST, "average" difficulty', 'NIST, "higher" difficulty']
+        group_suffix_names = ['nist_lower', 'nist_average', 'nist_higher']
+
+        use_errors = False
+
+        nist_group_dir = os.path.join(self.base_problem_files_dir, 'NIST_nonlinear_regression')
+
+        # test that fit executes on all NIST problems against a number of different minimizers
+        problems, results_per_group = fitbk.do_fitting_benchmark(nist_group_dir=nist_group_dir,
+                                                                 minimizers=minimizers, use_errors=use_errors)
+
+        # test that can print individual group tables
+        for idx, group_results in enumerate(results_per_group):
+            print("\n\n")
+            print("********************************************************")
+            print("**************** RESULTS FOR GROUP {0}, {1} ************".format(idx+1,
+                                                                                    group_names[idx]))
+            print("********************************************************")
+            fitout.print_group_results_tables(minimizers, group_results, problems[idx],
+                                              group_name=group_suffix_names[idx], use_errors=use_errors,
+                                              simple_text=True, rst=True, save_to_file=False,
+                                              color_scale=self.color_scale)
+
+        # test that can print summary tables
+        header = '\n\n**************** OVERALL SUMMARY - ALL GROUPS ******** \n\n'
+        print(header)
+        fitout.print_overall_results_table(minimizers, results_per_group, problems, group_names,
+                                           use_errors=use_errors, save_to_file=False)
+
+    def test_all_cutest_problem(self):
+        """
+        Runs benchmark on all CUTEst problems on about half of the available Mantid minimizers
+        and with using weights.
+        """
+        minimizers = ['Levenberg-Marquardt', 'Levenberg-MarquardtMD',
+                      'Simplex', 'SteepestDescent', 'Trust Region']
+        group_suffix_names = ['cutest']
+
+        use_errors = True
+
+        cutest_group_dir = os.path.join(self.base_problem_files_dir, 'CUTEst')
+
+        # test that fit executes on all NIST problems against a number of different minimizers
+        problems, results_per_group = fitbk.do_fitting_benchmark(cutest_group_dir=cutest_group_dir,
+                                                                 minimizers=minimizers, use_errors=use_errors)
+
+        # test that can print individual group table
+        for idx, group_results in enumerate(results_per_group):
+            fitout.print_group_results_tables(minimizers, group_results, problems[idx],
+                                              group_name=group_suffix_names[idx], use_errors=use_errors,
+                                              simple_text=True, rst=True, save_to_file=False,
+                                              color_scale=self.color_scale)
+
+    def test_all_neutron_data_problem(self):
+        """
+        Runs benchmark on all neutron data problems on one minimizers
+        and using weights.
+        """
+        minimizers = ['Trust Region']
+        group_suffix_names = ['neutron_data']
+
+        use_errors = True
+
+        neutron_data_group_dirs = [os.path.join(self.base_problem_files_dir, 'Neutron_data')]
+
+        # test that fit executes on all Neutron data problems
+        problems, results_per_group = fitbk.do_fitting_benchmark(neutron_data_group_dirs=neutron_data_group_dirs,
+                                                                 minimizers=minimizers, use_errors=use_errors)
+
+        # test that can print individual group table
+        for idx, group_results in enumerate(results_per_group):
+            fitout.print_group_results_tables(minimizers, group_results, problems[idx],
+                                              group_name=group_suffix_names[idx], use_errors=use_errors,
+                                              simple_text=True, rst=True, save_to_file=False,
+                                              color_scale=self.color_scale)
+
+
+# Run the unittest tests defined above as a Mantid system test
+class FittingBenchmars(stresstesting.MantidStressTest):
+
+    _success = False
+
+    def __init__(self, *args, **kwargs):
+        # super(FittingBenchmarkTests, self).__init__(*args, **kwargs)
+        # old-style
+        stresstesting.MantidStressTest.__init__(self, *args, **kwargs)
+        self._success = False
+
+    def requiredFile(self):
+        return None
+
+    def runTest(self):
+
+        self._success = False
+        # Custom code to create and run this single test suite
+        suite = unittest.TestSuite()
+        suite.addTest(unittest.makeSuite(FittingBenchmarkTests, "test") )
+        runner = unittest.TextTestRunner()
+        # Run and check success
+        res = runner.run(suite)
+        self._success = res.wasSuccessful()
+
+    def validate(self):
+        return self._success
diff --git a/Testing/SystemTests/tests/analysis/HFIRTestsAPIv2.py b/Testing/SystemTests/tests/analysis/HFIRTestsAPIv2.py
index 69f9c6e42822a6d88c577547b90cc19377f0bac6..760a51642fbfd05c86d10d2f42aa2267b3c174a0 100644
--- a/Testing/SystemTests/tests/analysis/HFIRTestsAPIv2.py
+++ b/Testing/SystemTests/tests/analysis/HFIRTestsAPIv2.py
@@ -508,8 +508,8 @@ class HFIRTestsAPIv2(stresstesting.MantidStressTest):
         AzimuthalAverage(binning="0.01,0.001,0.11", error_weighting=True)
         Reduce1D()
 
-        property_manager = PropertyManagerDataService.retrieve(ReductionSingleton().get_reduction_table_name())
-        _p = property_manager.getProperty("TransmissionAlgorithm")
+        #property_manager = PropertyManagerDataService.retrieve(ReductionSingleton().get_reduction_table_name())
+        #_p = property_manager.getProperty("TransmissionAlgorithm")
 
         ws = AnalysisDataService.retrieve("BioSANS_test_data_Iq")
         self.assertTrue(_check_result(ws, TEST_DIR + "reduced_transmission.txt", 0.0001))
diff --git a/Testing/SystemTests/tests/analysis/ILLIN4Test.py b/Testing/SystemTests/tests/analysis/ILLIN4Test.py
index 8d3d0f227d28afd958045a86a47deb6b9beac217..9ba2b366af829575e302cfa5624541c0c626a9ff 100644
--- a/Testing/SystemTests/tests/analysis/ILLIN4Test.py
+++ b/Testing/SystemTests/tests/analysis/ILLIN4Test.py
@@ -48,7 +48,7 @@ class ILLIN4Tests(unittest.TestCase):
         """
         ILL Loader
         """
-        ms.LoadILL(Filename=dataFile,OutputWorkspace=self.ws_name)
+        ms.LoadILLTOF(Filename=dataFile,OutputWorkspace=self.ws_name)
         self._do_ads_check(self.ws_name)
 
     def _do_ads_check(self, name):
diff --git a/Testing/SystemTests/tests/analysis/ILLIN5Test.py b/Testing/SystemTests/tests/analysis/ILLIN5Test.py
index 9ea1d0778bbc987b2c0e0dcf6b4f5e7b1ca70ca4..419b1b48313d2c339d4c4a4c38804155575cdd4d 100644
--- a/Testing/SystemTests/tests/analysis/ILLIN5Test.py
+++ b/Testing/SystemTests/tests/analysis/ILLIN5Test.py
@@ -61,7 +61,7 @@ class ILLIN5Tests(unittest.TestCase):
         """
         ILL Loader
         """
-        LoadILL(Filename=dataFile,FilenameVanadium=None,WorkspaceVanadium=None,OutputWorkspace=outWSName)
+        LoadILLTOF(Filename=dataFile,FilenameVanadium=None,WorkspaceVanadium=None,OutputWorkspace=outWSName)
         self._do_ads_check(outWSName)
 
     def _do_ads_check(self, name):
diff --git a/Testing/SystemTests/tests/analysis/ILLIndirectReductionFWS.py b/Testing/SystemTests/tests/analysis/ILLIndirectReductionFWS.py
new file mode 100644
index 0000000000000000000000000000000000000000..e7029d6609511bd0fc4e89281c2d030a18257137
--- /dev/null
+++ b/Testing/SystemTests/tests/analysis/ILLIndirectReductionFWS.py
@@ -0,0 +1,103 @@
+import stresstesting
+from mantid.simpleapi import *
+from mantid import config
+
+
+class ILLIndirectReductionFWSTest(stresstesting.MantidStressTest):
+
+    # cache default instrument and datadirs
+    facility = config['default.facility']
+    instrument = config['default.instrument']
+    datadirs = config['datasearch.directories']
+
+    def __init__(self):
+        super(ILLIndirectReductionFWSTest, self).__init__()
+        self.setUp()
+
+    def setUp(self):
+        # these must be set, so the required files
+        # without instrument name can be retrieved
+        config['default.facility'] = 'ILL'
+        config['default.instrument'] = 'IN16B'
+        config.appendDataSearchSubDir('ILL/IN16B/')
+
+        self.params = {'Tolerance':1e-3,
+                       'CheckInstrument':False}
+
+    def tearDown(self):
+        config['default.facility'] = self.facility
+        config['default.instrument'] = self.instrument
+        config['datasearch.directories'] = self.datadirs
+
+    def requiredFiles(self):
+
+        return ["165944.nxs", "165945.nxs", "165946.nxs", "165947.nxs", "165948.nxs",
+                "165949.nxs", "165950.nxs", "165951.nxs", "165952.nxs", "165953.nxs",
+                "143720.nxs", "143721.nxs", "143722.nxs", "143723.nxs", "143724.nxs",
+                "143725.nxs", "143726.nxs", "143727.nxs", "143728.nxs", "143729.nxs"]
+
+    def runTest(self):
+
+        self._run_ifws()
+
+        #self._run_efws()
+
+        self._run_sum_interpolate()
+
+        self.tearDown()
+
+    def _run_ifws(self):
+        # test EFWS+IFWS mixed
+        IndirectILLReductionFWS(Run="165944:165953", SortXAxis=True, OutputWorkspace="ifws")
+
+        LoadNexusProcessed(Filename="ILLIN16B_FWS.nxs",OutputWorkspace="ref")
+
+        result = CompareWorkspaces(Workspace1='ifws_red',Workspace2='ref',**self.params)
+
+        if result[0]:
+            self.assertTrue(result[0])
+        else:
+            self.assertTrue(result[0],"Mismatch in IFWS: " + result[1].row(0)['Message'])
+
+    def _run_efws(self):
+        # test EFWS with sum/interpolate options with background and calibration
+        IndirectILLReductionFWS(Run="143720:143728:2",
+                                BackgroundRun="143721,143723,143725",
+                                CalibrationRun="143727,143729",
+                                BackgroundOption="Interpolate",
+                                CalibrationOption="Sum",
+                                SortXAxis=True,
+                                OutputWorkspace="efws")
+
+        LoadNexusProcessed(Filename="ILLIN16B_EFWS.nxs",OutputWorkspace="ref")
+
+        result = CompareWorkspaces(Workspace1='efws_0.0_red',Workspace2='ref',**self.params)
+
+        if result[0]:
+            self.assertTrue(result[0])
+        else:
+            self.assertTrue(result[0], "Mismatch in EFWS: " + result[1].row(0)['Message'])
+
+    def _run_sum_interpolate(self):
+
+        # this cross-tests if only one background point is given,
+        # sum and interpolate options should give identical output
+        IndirectILLReductionFWS(Run="143720:143728:2",
+                                BackgroundRun="143721",
+                                BackgroundOption="Interpolate",
+                                SortXAxis=True,
+                                OutputWorkspace="efws_int")
+
+        IndirectILLReductionFWS(Run="143720:143728:2",
+                                BackgroundRun="143721",
+                                BackgroundOption="Sum",
+                                SortXAxis=True,
+                                OutputWorkspace="efws_sum")
+
+        result = CompareWorkspaces(Workspace1='efws_int_red', Workspace2='efws_sum_red', Tolerance=1e-9)
+
+        if result[0]:
+            self.assertTrue(result[0])
+        else:
+            self.assertTrue(result[0], "Sum/interpolate should be the same for one point: "
+                            + result[1].row(0)['Message'])
diff --git a/Testing/SystemTests/tests/analysis/ILLIndirectReductionQENS.py b/Testing/SystemTests/tests/analysis/ILLIndirectReductionQENS.py
new file mode 100644
index 0000000000000000000000000000000000000000..0e627e8ff8d7da94c9550f1c08e1f1d39d08e59a
--- /dev/null
+++ b/Testing/SystemTests/tests/analysis/ILLIndirectReductionQENS.py
@@ -0,0 +1,158 @@
+import stresstesting
+from mantid.simpleapi import *
+from mantid import config
+from testhelpers import run_algorithm
+
+
+class ILLIndirectReductionQENSTest(stresstesting.MantidStressTest):
+
+    # cache default instrument and datadirs
+    facility = config['default.facility']
+    instrument = config['default.instrument']
+    datadirs = config['datasearch.directories']
+
+    def __init__(self):
+        super(ILLIndirectReductionQENSTest, self).__init__()
+        self.setUp()
+
+    def setUp(self):
+        # these must be set, so the required files
+        # without instrument name can be retrieved
+        config['default.facility'] = 'ILL'
+        config['default.instrument'] = 'IN16B'
+        config.appendDataSearchSubDir('ILL/IN16B/')
+
+    def tearDown(self):
+        config['default.facility'] = self.facility
+        config['default.instrument'] = self.instrument
+        config['datasearch.directories'] = self.datadirs
+
+    def requiredFiles(self):
+
+        return ["136553.nxs","136554.nxs",  # calibration vanadium files
+                "136555.nxs","136556.nxs",  # alignment vanadium files
+                "136599.nxs","136600.nxs",  # background (empty can)
+                "136558.nxs","136559.nxs"]  # sample
+
+    def test_unmirror_0_1_2_3(self):
+
+        args = {'Run' : '136553.nxs',
+                'UnmirrorOption' : 0,
+                'OutputWorkspace' : 'zero'}
+
+        alg_test = run_algorithm('IndirectILLReductionQENS', **args)
+
+        self.assertTrue(alg_test.isExecuted(), "IndirectILLReductionQENS not executed for unmirror 0")
+
+        args['UnmirrorOption'] = 1
+
+        args['OutputWorkspace'] = 'both'
+
+        alg_test = run_algorithm('IndirectILLReductionQENS', **args)
+
+        self.assertTrue(alg_test.isExecuted(), "IndirectILLReductionQENS not executed for unmirror 1")
+
+        args['UnmirrorOption'] = 2
+
+        args['OutputWorkspace'] = 'left'
+
+        alg_test = run_algorithm('IndirectILLReductionQENS', **args)
+
+        self.assertTrue(alg_test.isExecuted(), "IndirectILLReductionQENS not executed for unmirror 2")
+
+        args['UnmirrorOption'] = 3
+
+        args['OutputWorkspace'] = 'right'
+
+        alg_test = run_algorithm('IndirectILLReductionQENS', **args)
+
+        self.assertTrue(alg_test.isExecuted(), "IndirectILLReductionQENS not executed for unmirror 3")
+
+        summed = Plus(mtd['left_red'].getItem(0),mtd['right_red'].getItem(0))
+
+        Scale(InputWorkspace=summed,Factor=0.5,OutputWorkspace=summed)
+
+        result = CompareWorkspaces(summed,mtd['both_red'].getItem(0))
+
+        self.assertTrue(result[0],"Unmirror 1 should be the sum of 2 and 3")
+
+        left_right = GroupWorkspaces([mtd['left_red'].getItem(0).getName(), mtd['right_red'].getItem(0).getName()])
+
+        result = CompareWorkspaces(left_right,'zero_red')
+
+        self.assertTrue(result[0],"Unmirror 0 should be the group of 2 and 3")
+
+    def test_unmirror_4_5(self):
+
+        args = {'Run': '136553.nxs',
+                'UnmirrorOption': 4,
+                'OutputWorkspace': 'vana4'}
+
+        alg_test = run_algorithm('IndirectILLReductionQENS', **args)
+
+        self.assertTrue(alg_test.isExecuted(), "IndirectILLReductionQENS not executed for unmirror 4")
+
+        args['AlignmentRun'] = '136553.nxs'
+
+        args['UnmirrorOption'] = 5
+
+        args['OutputWorkspace'] = 'vana5'
+
+        alg_test = run_algorithm('IndirectILLReductionQENS', **args)
+
+        self.assertTrue(alg_test.isExecuted(), "IndirectILLReductionQENS not executed for unmirror 5")
+
+        result = CompareWorkspaces('vana4_red', 'vana5_red')
+
+        self.assertTrue(result[0], "Unmirror 4 should be the same as 5 if "
+                                   "the same run is also defined as alignment run")
+
+    def test_unmirror_6_7(self):
+
+        args = {'Run': '136553.nxs',
+                'UnmirrorOption': 6,
+                'OutputWorkspace': 'vana6'}
+
+        alg_test = run_algorithm('IndirectILLReductionQENS', **args)
+
+        self.assertTrue(alg_test.isExecuted(), "IndirectILLReductionQENS not executed for unmirror 6")
+
+        args['AlignmentRun'] = '136553.nxs'
+
+        args['UnmirrorOption'] = 7
+
+        args['OutputWorkspace'] = 'vana7'
+
+        alg_test = run_algorithm('IndirectILLReductionQENS', **args)
+
+        self.assertTrue(alg_test.isExecuted(), "IndirectILLReductionQENS not executed for unmirror 7")
+
+        result = CompareWorkspaces('vana6_red','vana7_red')
+
+        self.assertTrue(result[0], "Unmirror 6 should be the same as 7 if "
+                                   "the same run is also defined as alignment run")
+
+    def runTest(self):
+
+        self.test_unmirror_0_1_2_3()
+
+        self.test_unmirror_4_5()
+
+        self.test_unmirror_6_7()
+
+        self.tolerance = 1e-3
+
+        self.disableChecking = ['Instrument']
+
+        IndirectILLReductionQENS(Run="136558-136559",
+                                 CalibrationRun="136553-136554",
+                                 BackgroundRun="136599-136600",
+                                 AlignmentRun="136555-136556",
+                                 BackgroundScalingFactor=0.1,
+                                 UnmirrorOption=7,
+                                 OutputWorkspace='out')
+
+        self.tearDown()
+
+    def validate(self):
+        return ['136558_multiple_out_red','ILLIN16B_QENS.nxs']
diff --git a/Testing/SystemTests/tests/analysis/ISISDirectInelastic.py b/Testing/SystemTests/tests/analysis/ISISDirectInelastic.py
index b0bfbfe301a605eac20a063e79e84256149a15bb..af33267c34c01e41e2f543409592579e2e712892 100644
--- a/Testing/SystemTests/tests/analysis/ISISDirectInelastic.py
+++ b/Testing/SystemTests/tests/analysis/ISISDirectInelastic.py
@@ -288,10 +288,11 @@ class MARIReductionMonSeparate(ISISDirectInelasticReduction):
         outWS=self.red.reduce()
         # temporary fix to account for different monovan integral
         #outWS*=0.997966051169129
+        self.ws_name = outWS.name()
 
     def get_result_workspace(self):
         """Returns the result workspace to be checked"""
-        return "outWS"
+        return self.ws_name
 
     def get_reference_file(self):
         # monitor separate for MARI needs new maps and masks so, it is easier to redefine
@@ -317,10 +318,11 @@ class MARIReductionSum(ISISDirectInelasticReduction):
         #pylint: disable=unused-variable
         outWS=self.red.reduce()
         #outWS*=1.00001556766686
+        self.ws_name = outWS.name()
 
     def get_result_workspace(self):
         """Returns the result workspace to be checked"""
-        return "outWS"
+        return self.ws_name
 
     def get_reference_file(self):
         return "MARIReductionSum.nxs"
@@ -372,6 +374,7 @@ class MARIReductionWaitAndSum(ISISDirectInelasticReduction):
         self.red.reducer.prop_man.sample_run=[11001,11002]
         #pylint: disable=unused-variable
         outWS = self.red.run_reduction()
+        self.ws_name = outWS.name()
 
         self.red.wait_for_file =0
         self.red._debug_wait_for_files_operation = None
@@ -379,7 +382,7 @@ class MARIReductionWaitAndSum(ISISDirectInelasticReduction):
 
     def get_result_workspace(self):
         """Returns the result workspace to be checked"""
-        return "outWS"
+        return self.ws_name
 
     def get_reference_file(self):
         return "MARIReductionSum.nxs"
@@ -412,7 +415,7 @@ class MAPSDgreduceReduction(ISISDirectInelasticReduction):
 
         # rename workspace to the name expected by unit test framework
         #RenameWorkspace(InputWorkspace=outWS,OutputWorkspace=wsName)
-        self.ws_name = 'outWS'
+        self.ws_name = outWS.name()
 
     def get_reference_file(self):
         return "MAPSDgreduceReduction.nxs"
@@ -444,13 +447,14 @@ class MERLINReduction(ISISDirectInelasticReduction):
     def runTest(self):
         #pylint: disable=unused-variable
         outWS = self.red.reduce()
+        self.ws_name = outWS.name()
 
     def get_reference_file(self):
         return "MERLINReduction.nxs"
 
     def get_result_workspace(self):
         """Returns the result workspace to be checked"""
-        return "outWS"
+        return self.ws_name
 
     def validate(self):
         self.tolerance = 1e-6
@@ -485,6 +489,7 @@ class LETReduction(stresstesting.MantidStressTest):
         red.def_advanced_properties()
         #pylint: disable=unused-variable
         outWS=red.reduce()
+        self.ws_name = outWS.name()
 
     def validate(self):
         self.tolerance = 1e-6
@@ -492,7 +497,7 @@ class LETReduction(stresstesting.MantidStressTest):
         self.disableChecking.append('SpectraMap')
         self.disableChecking.append('Instrument')
 
-        return "outWS", "LETReduction.nxs"
+        return self.ws_name, "LETReduction.nxs"
 
 
 class LETReductionEvent2015Multirep(stresstesting.MantidStressTest):
@@ -520,6 +525,7 @@ class LETReductionEvent2015Multirep(stresstesting.MantidStressTest):
 
         #pylint: disable=unused-variable
         out_ws_list=red.run_reduction()
+        self.ws_names=[ws.name() for ws in out_ws_list]
 
         #for ind,ws in enumerate(out_ws_list):
         #  ws *=mults[ind]
@@ -530,4 +536,4 @@ class LETReductionEvent2015Multirep(stresstesting.MantidStressTest):
         self.disableChecking.append('SpectraMap')
         self.disableChecking.append('Instrument')
 
-        return "LETreducedEi3.4","LET14305_3_4meV2015.nxs","LETreducedEi8.0", "LET14305_8_0meV2015.nxs"
+        return self.ws_names[0],"LET14305_3_4meV2015.nxs",self.ws_names[1], "LET14305_8_0meV2015.nxs"
diff --git a/Testing/SystemTests/tests/analysis/ISISIndirectInelastic.py b/Testing/SystemTests/tests/analysis/ISISIndirectInelastic.py
index 7523cfc37ac82a79add468e9658b29f6b0a570cc..52b5f31084c4690659e3daadd266cdc8f61a1296 100644
--- a/Testing/SystemTests/tests/analysis/ISISIndirectInelastic.py
+++ b/Testing/SystemTests/tests/analysis/ISISIndirectInelastic.py
@@ -591,7 +591,7 @@ class ISISIndirectInelasticMoments(ISISIndirectInelasticBase):
         LoadNexus(self.input_workspace,
                   OutputWorkspace=self.input_workspace)
 
-        SofQWMoments(Sample=self.input_workspace, EnergyMin=self.e_min,
+        SofQWMoments(InputWorkspace=self.input_workspace, EnergyMin=self.e_min,
                      EnergyMax=self.e_max, Scale=self.scale,
                      OutputWorkspace=self.input_workspace + '_Moments')
 
@@ -778,8 +778,8 @@ class ISISIndirectInelasticIqtAndIqtFit(ISISIndirectInelasticBase):
                                                            self.endx, 0,
                                                            self.spec_max)
 
-        self.result_names = [iqt_ws.getName(),
-                             iqtfitSeq_ws.getName()]
+        self.result_names = [iqt_ws.name(),
+                             iqtfitSeq_ws.name()]
 
         # Remove workspaces from Mantid
         for sample in self.samples:
@@ -898,7 +898,7 @@ class ISISIndirectInelasticIqtAndIqtFitMulti(ISISIndirectInelasticBase):
                                    DryRun=False)
 
         # Test IqtFitMultiple
-        iqtfitSeq_ws, params, fit_group = IqtFitMultiple(iqt_ws.getName(),
+        iqtfitSeq_ws, params, fit_group = IqtFitMultiple(iqt_ws.name(),
                                                          self.func,
                                                          self.ftype,
                                                          self.startx,
@@ -906,8 +906,8 @@ class ISISIndirectInelasticIqtAndIqtFitMulti(ISISIndirectInelasticBase):
                                                          self.spec_min,
                                                          self.spec_max)
 
-        self.result_names = [iqt_ws.getName(),
-                             iqtfitSeq_ws.getName()]
+        self.result_names = [iqt_ws.name(),
+                             iqtfitSeq_ws.name()]
 
         #remove workspaces from mantid
         for sample in self.samples:
@@ -1024,6 +1024,7 @@ class ISISIndirectInelasticConvFit(ISISIndirectInelasticBase):
             BackgroundType=self.bg,
             SpecMin=self.spectra_min,
             SpecMax=self.spectra_max,
+            PeakRadius=5,
             OutputWorkspace='result')
 
     def _validate_properties(self):
diff --git a/Testing/SystemTests/tests/analysis/ISISPowderDiffractionGemTest.py b/Testing/SystemTests/tests/analysis/ISISPowderDiffractionGemTest.py
index f0b40d6775cd304454dfaa87ee3bf3ac03a4d67b..871efe70632dd27ac517cc052089bf1fa354abd6 100644
--- a/Testing/SystemTests/tests/analysis/ISISPowderDiffractionGemTest.py
+++ b/Testing/SystemTests/tests/analysis/ISISPowderDiffractionGemTest.py
@@ -103,19 +103,19 @@ class LoadTests(unittest.TestCase):
             self.assertTrue(isinstance(data1[i], MatrixWorkspace))
         self.assertTrue(isinstance(data1[3], ITableWorkspace))
 
-        self.assertTrue("CalWorkspace1_group" in data1[0].getName())
-        self.assertTrue("CalWorkspace1_offsets" in data1[1].getName())
-        self.assertTrue("CalWorkspace1_mask" in data1[2].getName())
-        self.assertTrue("CalWorkspace1_cal" in data1[3].getName())
+        self.assertTrue("CalWorkspace1_group" in data1[0].name())
+        self.assertTrue("CalWorkspace1_offsets" in data1[1].name())
+        self.assertTrue("CalWorkspace1_mask" in data1[2].name())
+        self.assertTrue("CalWorkspace1_cal" in data1[3].name())
 
         for i in range(0, 3):
             self.assertTrue(isinstance(data2[i], MatrixWorkspace))
             self.assertTrue(isinstance(data1[3], ITableWorkspace))
 
-        self.assertTrue("CalWorkspace2_group" in data2[0].getName())
-        self.assertTrue("CalWorkspace2_offsets" in data2[1].getName())
-        self.assertTrue("CalWorkspace2_mask" in data2[2].getName())
-        self.assertTrue("CalWorkspace2_cal" in data2[3].getName())
+        self.assertTrue("CalWorkspace2_group" in data2[0].name())
+        self.assertTrue("CalWorkspace2_offsets" in data2[1].name())
+        self.assertTrue("CalWorkspace2_mask" in data2[2].name())
+        self.assertTrue("CalWorkspace2_cal" in data2[3].name())
 
     def test_nxsfile_with_workspace(self):
         self.wsname = "NexusWorkspace"
@@ -127,7 +127,7 @@ class LoadTests(unittest.TestCase):
 
         for i in range(1, 7):
             self.assertTrue(isinstance(data[i], MatrixWorkspace))
-            self.assertTrue("ResultTOF-" + str(i) in data[i].getName())
+            self.assertTrue("ResultTOF-" + str(i) in data[i].name())
 
         self.assertTrue('ResultTOFgrp', self.wsname[0])
 
@@ -155,7 +155,7 @@ class LoadTests(unittest.TestCase):
             self.assertTrue(isinstance(_file, MatrixWorkspace))
 
         for i in range(0, len(dat_data)):
-            self.assertTrue(("datWorkspace" + str(i + 1)) in dat_data[i].getName())
+            self.assertTrue(("datWorkspace" + str(i + 1)) in dat_data[i].name())
 
         for _file in dat_data:
             self.assertEquals(1, _file.getNumberHistograms())
@@ -277,19 +277,19 @@ class LoadTests2(unittest.TestCase):
             self.assertTrue(isinstance(data1[i], MatrixWorkspace))
         self.assertTrue(isinstance(data1[3], ITableWorkspace))
 
-        self.assertTrue("CalWorkspace1_group" in data1[0].getName())
-        self.assertTrue("CalWorkspace1_offsets" in data1[1].getName())
-        self.assertTrue("CalWorkspace1_mask" in data1[2].getName())
-        self.assertTrue("CalWorkspace1_cal" in data1[3].getName())
+        self.assertTrue("CalWorkspace1_group" in data1[0].name())
+        self.assertTrue("CalWorkspace1_offsets" in data1[1].name())
+        self.assertTrue("CalWorkspace1_mask" in data1[2].name())
+        self.assertTrue("CalWorkspace1_cal" in data1[3].name())
 
         for i in range(0, 3):
             self.assertTrue(isinstance(data2[i], MatrixWorkspace))
             self.assertTrue(isinstance(data1[3], ITableWorkspace))
 
-        self.assertTrue("CalWorkspace2_group" in data2[0].getName())
-        self.assertTrue("CalWorkspace2_offsets" in data2[1].getName())
-        self.assertTrue("CalWorkspace2_mask" in data2[2].getName())
-        self.assertTrue("CalWorkspace2_cal" in data2[3].getName())
+        self.assertTrue("CalWorkspace2_group" in data2[0].name())
+        self.assertTrue("CalWorkspace2_offsets" in data2[1].name())
+        self.assertTrue("CalWorkspace2_mask" in data2[2].name())
+        self.assertTrue("CalWorkspace2_cal" in data2[3].name())
 
     def test_nxsfile_with_workspace(self):
         self.wsname = "NexusWorkspace"
@@ -301,7 +301,7 @@ class LoadTests2(unittest.TestCase):
 
         for i in range(1, 7):
             self.assertTrue(isinstance(data[i], MatrixWorkspace))
-            self.assertTrue("ResultTOF-" + str(i) in data[i].getName())
+            self.assertTrue("ResultTOF-" + str(i) in data[i].name())
 
     def test_gssfile_with_workspace(self):
         gssfile = (DIRS[0] + "GEM/test/Cycle_09_5_No_ExtV/mantid_tester/GEM48436.gss")
@@ -327,7 +327,7 @@ class LoadTests2(unittest.TestCase):
             self.assertTrue(isinstance(_file, MatrixWorkspace))
 
         for i in range(0, len(dat_data)):
-            self.assertTrue(("datWorkspace" + str(i + 1)) in dat_data[i].getName())
+            self.assertTrue(("datWorkspace" + str(i + 1)) in dat_data[i].name())
 
         for _file in dat_data:
             self.assertEquals(1, _file.getNumberHistograms())
diff --git a/Testing/SystemTests/tests/analysis/ISISPowderDiffractionHrpdTest.py b/Testing/SystemTests/tests/analysis/ISISPowderDiffractionHrpdTest.py
index 8d5bc654b27f8452246cac12a18c72c8f9e394d8..bca8e6c8998bd0df22a840d6910bb4571d1d79e0 100644
--- a/Testing/SystemTests/tests/analysis/ISISPowderDiffractionHrpdTest.py
+++ b/Testing/SystemTests/tests/analysis/ISISPowderDiffractionHrpdTest.py
@@ -92,18 +92,18 @@ class LoadTests(unittest.TestCase):
         for i in range(0, 3):
             self.assertTrue(isinstance(data1[i], MatrixWorkspace))
 
-        self.assertTrue("CalWorkspace1_group" in data1[0].getName())
-        self.assertTrue("CalWorkspace1_offsets" in data1[1].getName())
-        self.assertTrue("CalWorkspace1_mask" in data1[2].getName())
-        self.assertTrue("CalWorkspace1_cal" in data1[3].getName())
+        self.assertTrue("CalWorkspace1_group" in data1[0].name())
+        self.assertTrue("CalWorkspace1_offsets" in data1[1].name())
+        self.assertTrue("CalWorkspace1_mask" in data1[2].name())
+        self.assertTrue("CalWorkspace1_cal" in data1[3].name())
 
         for i in range(0, 3):
             self.assertTrue(isinstance(data2[i], MatrixWorkspace))
 
-        self.assertTrue("CalWorkspace2_group" in data2[0].getName())
-        self.assertTrue("CalWorkspace2_offsets" in data2[1].getName())
-        self.assertTrue("CalWorkspace2_mask" in data2[2].getName())
-        self.assertTrue("CalWorkspace2_cal" in data2[3].getName())
+        self.assertTrue("CalWorkspace2_group" in data2[0].name())
+        self.assertTrue("CalWorkspace2_offsets" in data2[1].name())
+        self.assertTrue("CalWorkspace2_mask" in data2[2].name())
+        self.assertTrue("CalWorkspace2_cal" in data2[3].name())
 
     def test_nxsfile_with_workspace(self):
         self.wsname = "NexusWorkspace"
@@ -117,7 +117,7 @@ class LoadTests(unittest.TestCase):
             self.assertTrue(isinstance(data[i], MatrixWorkspace))
 
         for i in range(1, 3):
-            self.assertTrue(("ResultTOF-" + str(i)) in data[i].getName())
+            self.assertTrue(("ResultTOF-" + str(i)) in data[i].name())
 
         self.assertTrue('ResultTOFgrp', self.wsname[0])
 
@@ -141,7 +141,7 @@ class LoadTests(unittest.TestCase):
         for i in range(0, len(file_name)):
             data_list.append((LoadAscii(Filename=file_name[i], OutputWorkspace=("datWorkspace" + str(i + 1)))))
             self.assertTrue(isinstance(data_list[i], MatrixWorkspace))
-            self.assertTrue(("datWorkspace" + str(i + 1)) in data_list[i].getName())
+            self.assertTrue(("datWorkspace" + str(i + 1)) in data_list[i].name())
             self.assertEquals(1, data_list[i].getNumberHistograms())
 
         self.assertEquals(22981, data_list[0].blocksize())
diff --git a/Testing/SystemTests/tests/analysis/ISIS_PowderOldApiCalTest.py b/Testing/SystemTests/tests/analysis/ISIS_PowderOldApiCalTest.py
index 09318fe2e02d99fb9d91dbdc970448cf09ee933a..5dc1e86627d60c10c779b5ba1538f0aec8ab5494 100644
--- a/Testing/SystemTests/tests/analysis/ISIS_PowderOldApiCalTest.py
+++ b/Testing/SystemTests/tests/analysis/ISIS_PowderOldApiCalTest.py
@@ -13,7 +13,9 @@ DIFF_PLACES = 8
 DIRS = config['datasearch.directories'].split(';')
 
 
-class PearlPowderDiffractionScriptTestCalibration(stresstesting.MantidStressTest):
+class PowderDiffOldApiCalibrateTest(stresstesting.MantidStressTest):
+    _existing_config = None
+
     def requiredFiles(self):
         filenames = []
 
@@ -49,6 +51,7 @@ class PearlPowderDiffractionScriptTestCalibration(stresstesting.MantidStressTest
 
     def runTest(self):
         self._success = False
+        self._existing_config = config['datasearch.directories']
 
         pearl_routines.PEARL_startup("Calib", "15_3")
 
@@ -177,10 +180,9 @@ class LoadCalibTests(unittest.TestCase):
         vanadium_tt_35_dir = os.path.join(vanadium_base_dir, tt_35_file)
         van_tt35_data = LoadNexusProcessed(Filename=vanadium_tt_35_dir)
         self.matrix_workspaces_test(van_tt35_data, 'tt35')
-
-        self.assertAlmostEquals(-5.2637392907314393e-06, van_tt35_data[1].readY(0)[2], places=DIFF_PLACES)
-        self.assertAlmostEquals(1.46103398829e-05, van_tt35_data[5].readY(0)[4545], places=DIFF_PLACES)
-        self.assertAlmostEquals(5.20516790953e-06, van_tt35_data[8].readY(0)[7553], places=DIFF_PLACES)
+        self.assertAlmostEquals(-5.59125571e-06, van_tt35_data[1].readY(0)[2], places=DIFF_PLACES)
+        self.assertAlmostEquals(1.45223820e-05, van_tt35_data[5].readY(0)[4545], places=DIFF_PLACES)
+        self.assertAlmostEquals(5.16652141e-06, van_tt35_data[8].readY(0)[7553], places=DIFF_PLACES)
         self.assertAlmostEquals(2.30071459205e-08, van_tt35_data[4].readE(0)[17], places=DIFF_PLACES)
         self.assertAlmostEquals(177.218826007, van_tt35_data[13].readX(0)[278], places=DIFF_PLACES)
 
@@ -190,9 +192,9 @@ class LoadCalibTests(unittest.TestCase):
                                            OutputWorkspace=tt_70_file)
         self.matrix_workspaces_test(van_tt70_data, 'tt70')
 
-        self.assertAlmostEquals(-9.63683468044e-06, van_tt70_data[1].readY(0)[2], places=DIFF_PLACES)
-        self.assertAlmostEquals(3.05213907891e-05, van_tt70_data[5].readY(0)[4545], places=DIFF_PLACES)
-        self.assertAlmostEquals(1.05450348217e-05, van_tt70_data[8].readY(0)[7553], places=DIFF_PLACES)
+        self.assertAlmostEquals(-1.00937319e-05, van_tt70_data[1].readY(0)[2], places=DIFF_PLACES)
+        self.assertAlmostEquals(3.03206351e-05, van_tt70_data[5].readY(0)[4545], places=DIFF_PLACES)
+        self.assertAlmostEquals(1.04670371e-05, van_tt70_data[8].readY(0)[7553], places=DIFF_PLACES)
         self.assertAlmostEquals(3.2808780582e-08, van_tt70_data[4].readE(0)[17], places=DIFF_PLACES)
         self.assertAlmostEquals(177.218826007, van_tt70_data[13].readX(0)[278], places=DIFF_PLACES)
 
@@ -202,10 +204,10 @@ class LoadCalibTests(unittest.TestCase):
                                            OutputWorkspace=tt_88_file)
         self.matrix_workspaces_test(van_tt88_data, 'tt88')
 
-        self.assertAlmostEquals(-1.20275831674e-05, van_tt88_data[1].readY(0)[2], places=DIFF_PLACES)
-        self.assertAlmostEquals(3.64097322294e-05, van_tt88_data[5].readY(0)[4545], places=DIFF_PLACES)
-        self.assertAlmostEquals(1.28680957601e-05, van_tt88_data[8].readY(0)[7553], places=DIFF_PLACES)
-        self.assertAlmostEquals(2.6326912352e-08, van_tt88_data[4].readE(0)[17], places=DIFF_PLACES)
+        self.assertAlmostEquals(-1.15778020e-05, van_tt88_data[1].readY(0)[2], places=DIFF_PLACES)
+        self.assertAlmostEquals(3.61722568e-05, van_tt88_data[5].readY(0)[4545], places=DIFF_PLACES)
+        self.assertAlmostEquals(1.27747701e-05, van_tt88_data[8].readY(0)[7553], places=DIFF_PLACES)
+        self.assertAlmostEquals(3.21810924e-08, van_tt88_data[4].readE(0)[17], places=DIFF_PLACES)
         self.assertAlmostEquals(177.218826007, van_tt88_data[13].readX(0)[278], places=DIFF_PLACES)
 
     def matrix_workspaces_test(self, vanadium_tt_file, tt_mode='tt35'):
diff --git a/Testing/SystemTests/tests/analysis/ISIS_PowderOldApiTest.py b/Testing/SystemTests/tests/analysis/ISIS_PowderOldApiTest.py
index 36ee86f9f8b234fe01bb0830631877828b9d0657..c2cfd587088c79afd400820eb679a513c951395f 100644
--- a/Testing/SystemTests/tests/analysis/ISIS_PowderOldApiTest.py
+++ b/Testing/SystemTests/tests/analysis/ISIS_PowderOldApiTest.py
@@ -154,7 +154,7 @@ def _validate_wrapper(cls, focus_mode):
     cls.disableChecking.append('Sample')
     cls.disableChecking.append('SpectraMap')
     out_name = "PEARL_routines_fmode_" + focus_mode
-    mantid.LoadNexus(Filename=DIRS[0] + "PEARL/Focus_Test/DataOut/PEARL92476_92479.nxs",
+    mantid.LoadNexus(Filename=DIRS[0] + "PEARL/Focus_Test/DataOut/15_4/Mantid_Tester/PEARL92476_92479.nxs",
                      OutputWorkspace=out_name)
-    reference_file_name = "PEARL92476_92479_" + focus_mode + ".nxs"
+    reference_file_name = "ISIS_Powder-PEARL92476_92479_" + focus_mode + ".nxs"
     return out_name, reference_file_name
diff --git a/Testing/SystemTests/tests/analysis/ISIS_PowderPolarisTest.py b/Testing/SystemTests/tests/analysis/ISIS_PowderPolarisTest.py
new file mode 100644
index 0000000000000000000000000000000000000000..7aa1b1127813ea1f98167c4a6705bba9a43f931d
--- /dev/null
+++ b/Testing/SystemTests/tests/analysis/ISIS_PowderPolarisTest.py
@@ -0,0 +1,132 @@
+from __future__ import (absolute_import, division, print_function)
+
+import os
+import stresstesting
+
+import mantid.simpleapi as mantid
+from mantid import config
+
+from isis_powder import polaris
+
+DIRS = config['datasearch.directories'].split(';')
+
+
+class isis_powder_PolarisVanadiumCalTest(stresstesting.MantidStressTest):
+
+    calibration_results = None
+    existing_config = config['datasearch.directories']
+
+    def requiredFiles(self):
+        return _gen_required_files()
+
+    def runTest(self):
+        self.calibration_results = _run_vanadium_calibration()
+
+    def validate(self):
+        return _calibration_validation(self, self.calibration_results)  # First element is WS Group
+
+    def cleanup(self):
+        # TODO clean up reference files properly
+        config['datasearch.directories'] = self.existing_config
+        # _clean_up()
+
+
+class isis_powder_PolarisFocusTest(stresstesting.MantidStressTest):
+
+    focus_results = None
+    existing_config = config['datasearch.directories']
+
+    def requiredFiles(self):
+        return _gen_required_files()
+
+    def runTest(self):
+        # Gen vanadium calibration first
+        _run_vanadium_calibration()
+        self.focus_results = _run_focus()
+
+    def validation(self):
+        return _focus_validation(self, self.focus_results)
+
+    def cleanup(self):
+        config['datasearch.directories'] = self.existing_config
+        # TODO
+
+
+def _gen_required_files():
+    input_files = ["POLARIS/POL78338.raw",
+                   "POLARIS/POL78339.raw",
+                   "POLARIS/POL79514.raw"]
+    return input_files
+
+
+def _run_vanadium_calibration():
+    vanadium_run = 78338
+    gen_absorb = True
+
+    polaris_obj = setup_polaris_instrument()
+    # Try it without an output name
+
+    return polaris_obj.create_calibration_vanadium(run_in_range=vanadium_run,
+                                                   gen_absorb_correction=gen_absorb)
+
+
+def _run_focus():
+    run_number = 79514
+    polaris_obj = setup_polaris_instrument()
+    return polaris_obj.focus(run_number=run_number)
+
+
+def _calibration_validation(cls, results):
+    _validation_setup(cls)
+    results_name = results[0].name()
+    reference_file_name = "ISIS_Powder-PEARL78338_Van_Cal.nxs"
+    return results_name, reference_file_name
+
+
+def _focus_validation(cls, results):
+    _validation_setup(cls)
+
+    reference_file_name = "POLARIS_PowderFocus79514.nxs"
+    focus_output_name = "Focus_results"
+    mantid.GroupWorkspaces(InputWorkspaces=results, OutputWorkspace=focus_output_name)
+
+    return focus_output_name, reference_file_name
+
+
+def _validation_setup(cls):
+    cls.disableChecking.append('Instrument')
+    cls.disableChecking.append('Sample')
+    cls.disableChecking.append('SpectraMap')
+
+
+def _clean_up():
+    output_file_path = _get_calibration_dir() + _get_calibration_output_name()
+    try:
+        os.remove(output_file_path)
+    except OSError:
+        print ("Could not delete output file at: ", output_file_path)
+
+
+def setup_polaris_instrument():
+    user_name = "Test"
+
+    calibration_dir = _get_calibration_dir()
+    path_to_add = os.path.join(DIRS[0], "POLARIS")
+    config['datasearch.directories'] += ";" + path_to_add
+    output_dir = _get_output_dir()
+
+    polaris_obj = polaris.Polaris(user_name=user_name, chopper_on=True,
+                                  calibration_dir=calibration_dir, output_dir=output_dir)
+    return polaris_obj
+
+
+def _get_calibration_output_name():
+    return "system_test_polaris_van_cal.nxs"
+
+
+def _get_output_dir():
+    return os.path.join(DIRS[0], "POLARIS/DataOut")
+
+
+def _get_calibration_dir():
+    return os.path.join(DIRS[0], "POLARIS/Calibration")
diff --git a/Testing/SystemTests/tests/analysis/ISIS_WISHCalibration.py b/Testing/SystemTests/tests/analysis/ISIS_WISHCalibration.py
new file mode 100644
index 0000000000000000000000000000000000000000..71f0a01cec722e8722226635f52b8d6173f266f6
--- /dev/null
+++ b/Testing/SystemTests/tests/analysis/ISIS_WISHCalibration.py
@@ -0,0 +1,72 @@
+"""
+System test for WISH calibration
+
+This makes use of the tube calibration python package. This also includes
+additional processing to correct "bad" peaks fits in some tubes.
+
+Note that this is a test for the newer configuration of WISH. Previously this
+was fitted with 9 Gaussian peaks and this was done on a panel by panel basis.
+
+Modern method (tested below) uses a single run for all panels and uses only
+5 Gaussian peaks for calibration.
+
+"""
+from mantid.simpleapi import (Load, ApplyCalibration)
+from tube_calib_fit_params import TubeCalibFitParams
+from tube_spec import TubeSpec
+from ideal_tube import IdealTube
+import tube
+
+import stresstesting
+import numpy as np
+
+
+class WISHCalibrationTest(stresstesting.MantidStressTest):
+
+    def requiredFiles(self):
+        return ["WISH30541_integrated.nxs"]
+
+    def requiredMemoryMB(self):
+        return 4000
+
+    def cleanup(self):
+        pass
+
+    def runTest(self):
+        workspace = Load("WISH30541_integrated.nxs", OutputWorkspace="30541")
+
+        # define the positions of each of calibration bands on WISH
+        tube_positions = np.array([-274.81703361, -131.75052481, 0.,
+                                   131.75052481, 274.81703361])
+        func_form = len(tube_positions)*[1] # 5 gaussian peaks
+        margin = 15
+
+        # start position of each of the peaks to fit
+        fit_params = TubeCalibFitParams([59, 161, 258, 353, 448])
+        fit_params.setAutomatic(True)
+
+        instrument = workspace.getInstrument()
+        spec = TubeSpec(workspace)
+        spec.setTubeSpecByString(instrument.getFullName())
+
+        ideal_tube = IdealTube()
+        ideal_tube.setArray(tube_positions)
+
+        # First calibrate all of the detectors
+        calibration_table, peaks = \
+            tube.calibrate(workspace, spec, tube_positions, func_form,
+                           margin=margin, outputPeak=True,
+                           fitPar=fit_params)
+
+        ApplyCalibration(workspace, calibration_table)
+        # should have # detectors to update
+        self.assertEqual(calibration_table.rowCount(), 778240)
+
+        # now correct badly aligned tubes
+        corrected_calibration_table = \
+            tube.correctMisalignedTubes(workspace, calibration_table, peaks, spec,
+                                        ideal_tube, fit_params)
+
+        ApplyCalibration(workspace, corrected_calibration_table)
+        # should have 12288 detectors to correct after refitting
+        self.assertEqual(corrected_calibration_table.rowCount(), 12288)
diff --git a/Testing/SystemTests/tests/analysis/L2QScriptTest.py b/Testing/SystemTests/tests/analysis/L2QScriptTest.py
index bd2f6f6257d9efaed2bd2984f2f38342babaac0d..29ac1c6d73f5c2e886a4c3a2c07382a862eb5c80 100644
--- a/Testing/SystemTests/tests/analysis/L2QScriptTest.py
+++ b/Testing/SystemTests/tests/analysis/L2QScriptTest.py
@@ -10,9 +10,9 @@ class L2QScriptTest(stresstesting.MantidStressTest):
     def runTest(self):
         ws = Load(Filename="INTER00013469.nxs")
         ws = ConvertUnits(InputWorkspace=ws,Target="Wavelength",AlignBins=1)
-        Io=CropWorkspace(InputWorkspace=ws,XMin=0.8,XMax=14.5,StartWorkspaceIndex=2,EndWorkspaceIndex=2)
-        D=CropWorkspace(InputWorkspace=ws,XMin=0.8,XMax=14.5,StartWorkspaceIndex=3)
-        I= Divide(LHSWorkspace=D,RHSWorkspace=Io,AllowDifferentNumberSpectra=True)
+        #Io=CropWorkspace(InputWorkspace=ws,XMin=0.8,XMax=14.5,StartWorkspaceIndex=2,EndWorkspaceIndex=2)
+        #D=CropWorkspace(InputWorkspace=ws,XMin=0.8,XMax=14.5,StartWorkspaceIndex=3)
+        #I= Divide(LHSWorkspace=D,RHSWorkspace=Io,AllowDifferentNumberSpectra=True)
         detector_component_name =  'linear-detector'
         sample_component_name = 'some-surface-holder'
         theta = 0.7
diff --git a/Testing/SystemTests/tests/analysis/LoadLotsOfFiles.py b/Testing/SystemTests/tests/analysis/LoadLotsOfFiles.py
index c641621b916fd2474cdf0107356215023e5aae3e..c1556903f877f7fcaf8bd9aadf0a1b1b8b98fba5 100644
--- a/Testing/SystemTests/tests/analysis/LoadLotsOfFiles.py
+++ b/Testing/SystemTests/tests/analysis/LoadLotsOfFiles.py
@@ -240,7 +240,7 @@ class LoadLotsOfFiles(stresstesting.MantidStressTest):
             return False
 
         # generic checks
-        if wksp.getName() is None or len(wksp.getName()) <= 0:
+        if wksp.name() is None or len(wksp.name()) <= 0:
             print "Workspace does not have a name"
             del wksp
             return False
diff --git a/Testing/SystemTests/tests/analysis/PEARLSystemTest.py b/Testing/SystemTests/tests/analysis/PEARLSystemTest.py
index ff30722c6a8a0a6bd292fdec24dadfdf4077b8e5..37773c081bca3104c3d331318d30af413e35dca7 100644
--- a/Testing/SystemTests/tests/analysis/PEARLSystemTest.py
+++ b/Testing/SystemTests/tests/analysis/PEARLSystemTest.py
@@ -5,12 +5,14 @@ from mantid.simpleapi import *
 from mantid import *
 import os
 import numpy as n
+from abc import ABCMeta, abstractmethod
 
 #pylint: disable=too-many-instance-attributes
 
 
 class PEARL_Reduction(stresstesting.MantidStressTest):
     '''Test adapted from actual script used by the scientists'''
+    __metaclass__ = ABCMeta # Mark as an abstract class
     validate=None
 
     def __init__(self):
@@ -165,6 +167,15 @@ class PEARL_Reduction(stresstesting.MantidStressTest):
         mtd.remove(monitor)
         return
 
+    def PEARL_remove_workspaces(self):
+        for i in range(0,14):
+            output="mod"+str(i+1)
+            van="van"+str(i+1)
+            rdata="rdata"+str(i+1)
+            mtd.remove(rdata)
+            mtd.remove(van)
+            mtd.remove(output)
+
     def PEARL_focus(self, number,ext="raw",fmode="trans",ttmode="TT70",atten=True,van_norm=True):
 
         self.tt_mode=ttmode
@@ -173,14 +184,9 @@ class PEARL_Reduction(stresstesting.MantidStressTest):
         work="work"
         focus="focus"
 
-        if isinstance(number, int):
-            outfile="PRL"+str(number)+".nxs"
-            gssfile="PRL"+str(number)+".gss"
-            outwork="PRL"+str(number)
-        else:
-            outfile="PRL"+number+".nxs"
-            gssfile="PRL"+number+".gss"
-            outwork="PRL"+number
+        outfile="PRL"+str(number)+".nxs"
+        gssfile="PRL"+str(number)+".gss"
+        outwork="PRL"+str(number)
 
         self.PEARL_read(number,ext,work)
         Rebin(InputWorkspace=work,OutputWorkspace=work,Params=self.tofbinning)
@@ -225,13 +231,7 @@ class PEARL_Reduction(stresstesting.MantidStressTest):
                 ConvertUnits(InputWorkspace=tosave,OutputWorkspace=tosave,Target="dSpacing")
                 SaveNexus(Filename=outfile,InputWorkspace=tosave,Append=True)
 
-            for i in range(0,14):
-                output="mod"+str(i+1)
-                van="van"+str(i+1)
-                rdata="rdata"+str(i+1)
-                mtd.remove(rdata)
-                mtd.remove(van)
-                mtd.remove(output)
+            self.PEARL_remove_workspaces()
             mtd.remove("bank1")
 
         elif self.mode=="groups":
@@ -269,13 +269,7 @@ class PEARL_Reduction(stresstesting.MantidStressTest):
                 SaveGSS(InputWorkspace=tosave,Filename=gssfile,Append=True,Bank=i+5)
                 ConvertUnits(InputWorkspace=tosave,OutputWorkspace=tosave,Target="dSpacing")
                 SaveNexus(Filename=outfile,InputWorkspace=tosave,Append=True)
-            for i in range(0,14):
-                output="mod"+str(i+1)
-                van="van"+str(i+1)
-                rdata="rdata"+str(i+1)
-                mtd.remove(rdata)
-                mtd.remove(van)
-                mtd.remove(output)
+            self.PEARL_remove_workspaces()
             mtd.remove("group1")
             mtd.remove("group2")
             mtd.remove("group3")
@@ -301,13 +295,7 @@ class PEARL_Reduction(stresstesting.MantidStressTest):
                 ConvertUnits(InputWorkspace=tosave,OutputWorkspace=tosave,Target="dSpacing")
                 SaveNexus(Filename=outfile,InputWorkspace=tosave,Append=True)
 
-            for i in range(0,14):
-                output="mod"+str(i+1)
-                van="van"+str(i+1)
-                rdata="rdata"+str(i+1)
-                mtd.remove(rdata)
-                mtd.remove(van)
-                mtd.remove(output)
+            self.PEARL_remove_workspaces()
             mtd.remove("bank1")
 
         elif self.mode=="mods":
diff --git a/Testing/SystemTests/tests/analysis/POLDILoadRunsTest.py b/Testing/SystemTests/tests/analysis/POLDILoadRunsTest.py
index 2ef837b95142f93b620701fe998afbf30ecbc21f..8a70bb994f9f551b1e95d44827b2ed91b6fede64 100644
--- a/Testing/SystemTests/tests/analysis/POLDILoadRunsTest.py
+++ b/Testing/SystemTests/tests/analysis/POLDILoadRunsTest.py
@@ -139,8 +139,8 @@ class POLDILoadRunsTest(stresstesting.MantidStressTest):
                       OutputWorkspace='twoWorkspacesMerged')
 
         wsMerged = AnalysisDataService.retrieve("twoWorkspacesMerged_data_6904")
-        self.assertEquals(len([True for x in range(wsMerged.getNumberHistograms()) if wsMerged.getDetector(
-            x).isMasked()]), 36)
+        specInfoMerged = wsMerged.spectrumInfo()
+        self.assertEquals(len([True for x in range(wsMerged.getNumberHistograms()) if specInfoMerged.isMasked(x)]), 36)
 
         self.clearAnalysisDataService()
 
@@ -150,8 +150,8 @@ class POLDILoadRunsTest(stresstesting.MantidStressTest):
                       OutputWorkspace='twoWorkspacesMerged')
 
         wsMerged = AnalysisDataService.retrieve("twoWorkspacesMerged_data_6904")
-        self.assertEquals(len([True for x in range(wsMerged.getNumberHistograms()) if wsMerged.getDetector(
-            x).isMasked()]), 49)
+        specInfoMerged = wsMerged.spectrumInfo()
+        self.assertEquals(len([True for x in range(wsMerged.getNumberHistograms()) if specInfoMerged.isMasked(x)]), 49)
 
         self.clearAnalysisDataService()
 
@@ -160,8 +160,8 @@ class POLDILoadRunsTest(stresstesting.MantidStressTest):
                       OutputWorkspace='twoWorkspacesMerged')
 
         wsMerged = AnalysisDataService.retrieve("twoWorkspacesMerged_data_6904")
-        self.assertEquals(len([True for x in range(wsMerged.getNumberHistograms()) if wsMerged.getDetector(
-            x).isMasked()]), 12)
+        specInfoMerged = wsMerged.spectrumInfo()
+        self.assertEquals( len([True for x in range(wsMerged.getNumberHistograms()) if specInfoMerged.isMasked(x)]), 12)
 
         self.clearAnalysisDataService()
 
diff --git a/Testing/SystemTests/tests/analysis/ReduceOneSCD_Run.py b/Testing/SystemTests/tests/analysis/ReduceOneSCD_Run.py
index b72e11cd528c94d71e89443ada929b7bf218f8c9..4139086c4b1bbc2614e1ded77b64de0904aca989 100644
--- a/Testing/SystemTests/tests/analysis/ReduceOneSCD_Run.py
+++ b/Testing/SystemTests/tests/analysis/ReduceOneSCD_Run.py
@@ -121,7 +121,7 @@ class ReduceOneSCD_Run( stresstesting.MantidStressTest):
         peaks_ws = FindPeaksMD( MDEW, MaxPeaks=num_peaks_to_find,
                                 PeakDistanceThreshold=distance_threshold )
 
-        AnalysisDataService.remove( MDEW.getName() )
+        AnalysisDataService.remove( MDEW.name() )
 #      SaveIsawPeaks( InputWorkspace=peaks_ws, AppendFile=False,
 #               Filename='A'+run_niggli_integrate_file )
 #
diff --git a/Testing/SystemTests/tests/analysis/SANS2DSearchCentreGUI.py b/Testing/SystemTests/tests/analysis/SANS2DSearchCentreGUI.py
index c6619f5e092c1d1871cb9bed6f4c7636da53e394..de2beb771d143bab20cca7e0f4bcb92830bf6167 100644
--- a/Testing/SystemTests/tests/analysis/SANS2DSearchCentreGUI.py
+++ b/Testing/SystemTests/tests/analysis/SANS2DSearchCentreGUI.py
@@ -1,5 +1,5 @@
-#pylint: disable=invalid-name
-from mantid.simpleapi import *
+#pylint: disable=invalid-name
+import mantid
 import ISISCommandInterface as i
 import isis_reducer
 import isis_instrument
diff --git a/Testing/SystemTests/tests/analysis/SANSDarkRunSubtractionTest.py b/Testing/SystemTests/tests/analysis/SANSDarkRunSubtractionTest.py
index 81bb671ed5b9179c06399bfe492ce3dfd1f89918..0f824ccc8ac4a18b3f8881ce3948d3a11aaf7602 100644
--- a/Testing/SystemTests/tests/analysis/SANSDarkRunSubtractionTest.py
+++ b/Testing/SystemTests/tests/analysis/SANSDarkRunSubtractionTest.py
@@ -8,6 +8,7 @@ from mantid.simpleapi import *
 from isis_reduction_steps import DarkRunSubtraction
 from SANSUserFileParser import DarkRunSettings
 from SANSUtility import getFileAndName
+import numpy as np
 
 
 class DarkRunSubtractionTest(unittest.TestCase):
@@ -85,7 +86,8 @@ class DarkRunSubtractionTest(unittest.TestCase):
 
         # Since in this test we use the same file for the scatterer and the dark run, we expect
         # that the detectors are 0. This is because we subtract bin by bin when using UAMP
-        self.assertFalse(scatter_workspace.extractY().any(), "Detector entries should all be 0")
+        y = scatter_workspace.extractY()
+        self.assertFalse(np.greater(y, 1e-14).any(), "Detector entries should all be 0")
 
         # The monitors should not be affected, but we only have data in ws_index 0-3
         self.assertTrue(monitor_workspace.extractY()[:,0:3].any(), "Monitor entries should not all be 0")
@@ -121,13 +123,15 @@ class DarkRunSubtractionTest(unittest.TestCase):
         # Expect all entries to be 0 except for monitor 0. We selected monitor 1 and all detectors
         # for the subtraction. Hence only moniotr 0 would have been spared.
 
-        self.assertFalse(scatter_workspace.extractY().any(), "Detector entries should all be 0")
+        y = scatter_workspace.extractY()
+        self.assertFalse(np.greater(y, 1e-14).any(), "Detector entries should all be 0")
 
         for i in [0,2,3]:
             self.assertTrue(monitor_workspace.dataY(i).any(), "Monitor entries should not all be 0")
 
         for i in ws_index2:
-            self.assertFalse(monitor_workspace.dataY(i).any(), "Entries should all be 0")
+            y = monitor_workspace.dataY(i)
+            self.assertFalse(np.greater(y, 1e-14).any(), "Entries should all be 0")
 
     def test_that_subtracts_correct_added_file_type(self):
         # Arrange
@@ -154,9 +158,8 @@ class DarkRunSubtractionTest(unittest.TestCase):
 
         # Since in this test we use the same file for the scatterer and the dark run, we expect
         # that the detectors are 0. This is because we subtract bin by bin when using UAMP
-
-        self.assertFalse(scatter_workspace.extractY().any(), "Detector entries should all be 0")
-
+        y = scatter_workspace.extractY()
+        self.assertFalse(np.greater(y, 1e-14).any(), "Detector entries should all be 0")
         # The monitors should not be affected, but we only have data in ws_index 0-3
         for i in [0,3]:
             self.assertTrue(monitor_workspace.dataY(i).any(), "Monitor entries should not all be 0")
@@ -200,7 +203,8 @@ class DarkRunSubtractionTest(unittest.TestCase):
 
         # Monitor 2 (workspace index 1 should be 0
         for i in ws_index:
-            self.assertFalse(monitor_workspace.dataY(i).any(), "Monitor2 entries should  all be 0")
+            y = monitor_workspace.dataY(i)
+            self.assertFalse(np.greater(y, 1e-14).any(), "Monitor2 entries should  all be 0")
 
         os.remove(os.path.join(config['defaultsave.directory'],run_number))
 
@@ -236,7 +240,8 @@ class DarkRunSubtractionTest(unittest.TestCase):
 
         # Monitor 1 should be 0
         for i in ws_index:
-            self.assertFalse(monitor_workspace.dataY(i).any(), "Monitor2 entries should  all be 0")
+            y = monitor_workspace.dataY(i)
+            self.assertFalse(np.greater(y, 1e-14).any(), "Monitor2 entries should  all be 0")
 
     def test_that_subtracts_correct_for_transmission_workspace_with_only_monitors(self):
         # Arrange
@@ -268,7 +273,8 @@ class DarkRunSubtractionTest(unittest.TestCase):
 
         # Monitor2 should be 0
         for i in ws_index:
-            self.assertFalse(transmission_workspace.dataY(i).any(), "Monitor2 entries should  all be 0")
+            y = transmission_workspace.dataY(i)
+            self.assertFalse(np.greater(y, 1e-14).any(), "Monitor2 entries should  all be 0")
 
     def test_that_subtracts_nothing_when_selecting_detector_subtraction_for_transmission_workspace_with_only_monitors(self):
         # Arrange
@@ -340,12 +346,14 @@ class DarkRunSubtractionTest(unittest.TestCase):
 
         # Monitor 2 should be set to 0
         for i in ws_index2:
-            self.assertFalse(transmission_workspace.dataY(i).any(), "Monitor2 entries should be 0")
+            y = transmission_workspace.dataY(i)
+            self.assertFalse(np.greater(y, 1e-14).any(), "Monitor2 entries should be 0")
 
         # Detectors should be set to 0
         detector_indices = range(4,14)
         for i in detector_indices:
-            self.assertFalse(transmission_workspace.dataY(i).any(), "All detectors entries should be 0")
+            y = transmission_workspace.dataY(i)
+            self.assertFalse(np.greater(y, 1e-14).any(), "All detectors entries should be 0")
 
     def test_that_subtracts_monitors_only_for_transmission_workspace_with_monitors_and_detectors(self):
         # Arrange
@@ -380,7 +388,8 @@ class DarkRunSubtractionTest(unittest.TestCase):
 
         # Monitor 2 should be set to 0
         for i in ws_index:
-            self.assertFalse(transmission_workspace.dataY(i).any(), "Monitor2 entries should be 0")
+            y = transmission_workspace.dataY(i)
+            self.assertFalse(np.greater(y, 1e-14).any(), "Monitor2 entries should be 0")
 
         # Detectors should NOT all be set to 0
         self.assertTrue(transmission_workspace.extractY().any(), "There should be some detectors which are not zero")
diff --git a/Testing/SystemTests/tests/analysis/SEQUOIAreduction.py b/Testing/SystemTests/tests/analysis/SEQUOIAreduction.py
index 128ce91e6a2839d2f69807eefe3202cf22f9aff4..9938da56bcda3ddf1c565b48f7f18dccbcebf5d5 100644
--- a/Testing/SystemTests/tests/analysis/SEQUOIAreduction.py
+++ b/Testing/SystemTests/tests/analysis/SEQUOIAreduction.py
@@ -206,7 +206,7 @@ class DirectInelaticSNSTest(stresstesting.MantidStressTest):
                 MaskDetectors(Workspace="OWST",MaskedWorkspace="VAN")
             if do_powder:
                 if i==0:
-                    dummy_mapping=self.createanglelist("OWST",anglemin,anglemax,anglestep)
+                    self.createanglelist("OWST",anglemin,anglemax,anglestep)
                 GroupDetectors( InputWorkspace="OWST",OutputWorkspace="OWST",
                                 MapFile=os.path.join(self.customDataDir,"group.map"),Behaviour="Sum")
                 SolidAngle(InputWorkspace="OWST",OutputWorkspace="sa")
diff --git a/Testing/SystemTests/tests/analysis/SNAPRedux.py b/Testing/SystemTests/tests/analysis/SNAPRedux.py
new file mode 100644
index 0000000000000000000000000000000000000000..85a2dcbb3d11f4be3637247117799c68d2f2fa62
--- /dev/null
+++ b/Testing/SystemTests/tests/analysis/SNAPRedux.py
@@ -0,0 +1,63 @@
+#pylint: disable=no-init,invalid-name,attribute-defined-outside-init
+from __future__ import (absolute_import, division, print_function)
+import stresstesting
+from mantid.simpleapi import *
+import os
+
+
+def _skip_test():
+    """Helper function to determine if we run the test"""
+    import platform
+
+    # Only runs on RHEL6 at the moment
+    return "Linux" not in platform.platform()
+
+
+def getSaveDir():
+    """determine where to save - the current working directory"""
+    return os.path.abspath(os.path.curdir)
+
+
+def do_cleanup():
+    Files = [os.path.join('d_spacing', 'SNAP_34172_2_4_Grouping.dat'),
+             os.path.join('gsas', 'SNAP_34172_2_4_Grouping.gsa'),
+             os.path.join('fullprof', 'SNAP_34172_2_4_Grouping-0.dat'),
+             os.path.join('fullprof', 'SNAP_34172_2_4_Grouping-1.dat'),
+             os.path.join('nexus', 'SNAP_34172_2_4_Grouping.nxs')]
+    savedir = getSaveDir()
+    for filename in Files:
+        absfile = os.path.join(savedir, filename)
+        if os.path.exists(absfile):
+            os.remove(absfile)
+    for direc in ['d_spacing', 'gsas', 'fullprof', 'nexus']:
+        direc = os.path.join(savedir, direc)
+        if os.listdir(direc) == []:
+            os.rmdir(direc)
+
+    return True
+
+
+class SNAP_short(stresstesting.MantidStressTest):
+    def skipTests(self):
+        return _skip_test()
+
+    def cleanup(self):
+        do_cleanup()
+        return True
+
+    def requiredFiles(self):
+        files = []
+        files.append("SNAP_34172_event.nxs")
+        return files
+
+    def runTest(self):
+        # run the actual code
+        SNAPReduce(RunNumbers='34172', Masking='Horizontal', Binning='0.9,-0.004,6',
+                   Normalization='Extracted from Data', PeakClippingWindowSize=7,
+                   SmoothingRange=5, GroupDetectorsBy='2_4 Grouping',
+                   SaveData=True, OutputDirectory=getSaveDir())
+
+    def validate(self):
+        self.tolerance = 1.0e-2
+        # default validation of workspace to processed nexus is right
+        return ('SNAP_34172_2_4_Grouping_nor','SNAP_34172_2_4_Grouping_nor.nxs')
diff --git a/Testing/SystemTests/tests/analysis/TeixeiraWaterSQESystemTest.py b/Testing/SystemTests/tests/analysis/TeixeiraWaterSQESystemTest.py
new file mode 100644
index 0000000000000000000000000000000000000000..f02dbfa78569f0186d37381fe261df888ed4a1d8
--- /dev/null
+++ b/Testing/SystemTests/tests/analysis/TeixeiraWaterSQESystemTest.py
@@ -0,0 +1,90 @@
+#pylint: disable=no-init
+"""
+    Extract or compute the Q values from reduced QENS data
+"""
+from stresstesting import MantidStressTest
+import mantid
+import mantid.simpleapi as sm
+import re
+
+
+class GlobalFitTest(MantidStressTest):
+    """Global fit of QENS data to the jump-diffusion model by Teixeira
+       Fitting model. In this case:
+        Convolution( A*Resolution, x*Delta + (1-x)*TeixeiraWaterSQE ) + LinearBackground
+        with 0<x<1 is the fraction of the elastic intensity
+       Parameters DiffCoeff and Tau (residence time) of fit function TeixeiraWaterSQE are
+       the same for all spectra. All other fitting  parameters are different for each spectrum
+    """
+
+    #def requiredFiles(self):
+    #    return ["irs26173_graphite002_res.nxs", "irs26176_graphite002_red.nxs"]
+
+    def runTest(self):
+
+        data = sm.Load("irs26176_graphite002_red.nxs")
+        sm.Load("irs26173_graphite002_res.nxs", OutputWorkspace="resolution")
+
+        single_model = """(composite=Convolution,NumDeriv=true;
+        name=TabulatedFunction,Workspace=resolution,WorkspaceIndex=0,
+             Scaling=1,Shift=0,XScaling=1;
+        (name=DeltaFunction,Height=1.5,Centre=0;
+         name=TeixeiraWaterSQE,Height=1.0,Tau=1.0,DiffCoeff=1.0,Centre=0;
+         ties=(f1.Centre=f0.Centre)));
+        name=LinearBackground,A0=0,A1=0"""
+        single_model = re.sub('[\s+]', '', single_model)
+
+        # Include all spectra for the fit
+        selected_wi = range(data.getNumberHistograms())
+        nWi = len(selected_wi)  # number of selected spectra for fitting
+
+        # Energy range over which we do the fitting.
+        minE = -0.4  # Units are in meV
+        maxE = 0.4
+
+        # Create the string representation of the global model (for selected spectra):
+        global_model="composite=MultiDomainFunction,NumDeriv=true;"
+        for _ in selected_wi:
+            global_model += "(composite=CompositeFunction,NumDeriv=true,$domains=i;{0});\n".format(single_model)
+
+        # Tie DiffCoeff and Tau since they are global parameters
+        ties = ['='.join(["f{0}.f0.f1.f1.DiffCoeff".format(di) for di in reversed(range(nWi))]),
+                '='.join(["f{0}.f0.f1.f1.Tau".format(wi) for wi in reversed(range(nWi))])]
+        global_model += "ties=(" + ','.join(ties) + ')'  # tie Radius
+
+        # Now relate each domain(i.e. spectrum) to each single-spectrum model
+        domain_model = dict()
+        domain_index = 0
+        for wi in selected_wi:
+            if domain_index == 0:
+                domain_model.update({"InputWorkspace": data.name(), "WorkspaceIndex": str(wi),
+                                     "StartX": str(minE), "EndX": str(maxE)})
+            else:
+                di = str(domain_index)
+                domain_model.update({"InputWorkspace_" + di: data.name(), "WorkspaceIndex_" + di: str(wi),
+                                     "StartX_" + di: str(minE), "EndX_" + di: str(maxE)})
+            domain_index += 1
+
+        # Invoke the Fit algorithm using global_model and domain_model:
+        output_workspace = "glofit_" + data.name()
+        status,chi2,covar,params,curves = sm.Fit(Function=global_model, Output=output_workspace,
+                                                 CreateOutput=True, MaxIterations=500,
+                                                 **domain_model)
+
+        # Validate
+        self._success = True
+        try:
+            self.assertTrue(chi2 < 1)
+            self.assertTrue(abs(params.row(6)["Value"]-1.58)/1.58 < 0.1) # optimal DiffCoeff
+            self.assertTrue(abs(params.row(7)["Value"] - 1.16) / 1.16 < 0.1)  # optimal Tau
+        except:
+            self._success = False
+
+    def cleanup(self):
+        for workspace in ["data", "resolution", "glofit_data_Parameters",
+                          "glofit_data_Workspaces", "glofit_data_NormalisedCovarianceMatrix"]:
+            if mantid.AnalysisDataService.doesExist(workspace):
+                sm.DeleteWorkspace(workspace)
+
+    def validate(self):
+        return self._success
diff --git a/Testing/SystemTests/tests/analysis/WishMasking.py b/Testing/SystemTests/tests/analysis/WishMasking.py
index b34e9bd7fdb5366cf9627e31b79a0f9cc705ffa7..59bd853d66371bfc28cab183bcf9017fa35d2b0f 100644
--- a/Testing/SystemTests/tests/analysis/WishMasking.py
+++ b/Testing/SystemTests/tests/analysis/WishMasking.py
@@ -62,8 +62,8 @@ class WishMasking(stresstesting.MantidStressTest):
         masking_edge = 9
 
                 # Test the 'isMasked' property on the detectors of the original workspace
-        self.assertTrue( ws.getDetector(masking_edge).isMasked() )
-        self.assertTrue( not ws.getDetector(masking_edge + 1).isMasked() )
+        self.assertTrue( ws.spectrumInfo().isMasked(masking_edge) )
+        self.assertTrue( not ws.spectrumInfo().isMasked(masking_edge + 1) )
 
                 # Extract a masking workspace
         ExtractMask( InputWorkspace=ws, OutputWorkspace='masking_wish_workspace' )
@@ -74,8 +74,8 @@ class WishMasking(stresstesting.MantidStressTest):
                 # Test the 'isMasked' property on the detectors of the masked workspace
                 # The following tests have been added even though they are broken because extracted workspaces currently do not preserve the
                 # Masking flags (buty they SHOULD!). Hopefully the broken functionality will be fixed and I can enable them.
-                #self.assertTrue( mask_ws.getDetector(masking_edge).isMasked() )
-                #self.assertTrue( not mask_ws.getDetector(masking_edge + 1).isMasked() )
+                #self.assertTrue( mask_ws.spectrumInfo().isMasked(masking_edge) )
+                #self.assertTrue( not mask_ws.spectrumInfo().isMasked(masking_edge + 1) )
 
                 # Save masking
         mask_file = 'wish_masking_system_test_mask_file_temp.xml'
@@ -101,7 +101,7 @@ class WishMasking(stresstesting.MantidStressTest):
 
                 # Testing that the isMasking is the same on both sides of the masking boundary.
         # If things were working properly the following would not pass!
-        self.assertTrue( mask_ws.getDetector(masking_edge).isMasked() == mask_ws.getDetector(masking_edge + 1).isMasked() )
+        self.assertTrue( mask_ws.spectrumInfo().isMasked(masking_edge) == mask_ws.spectrumInfo().isMasked(masking_edge + 1) )
                 ## END CHARACTERISATION TESTS
 
                 #Test creation with normal masking
diff --git a/Testing/SystemTests/tests/analysis/reference/II.IRISMoments.nxs.md5 b/Testing/SystemTests/tests/analysis/reference/II.IRISMoments.nxs.md5
index 8c35b4dde95104160d1554129a83ca262a37e314..870024467e73790d3cf578ce13fa1e900a33ca4a 100644
--- a/Testing/SystemTests/tests/analysis/reference/II.IRISMoments.nxs.md5
+++ b/Testing/SystemTests/tests/analysis/reference/II.IRISMoments.nxs.md5
@@ -1 +1 @@
-7f10d5dcad3a94e17af3f8d21ded8adb
\ No newline at end of file
+d2185756bd31c3fce4bee9f4dc0bc441
diff --git a/Testing/SystemTests/tests/analysis/reference/II.OSIRISMoments.nxs.md5 b/Testing/SystemTests/tests/analysis/reference/II.OSIRISMoments.nxs.md5
index 8bd1379ea9b12de732e9fb128655ab5eb625febf..8bd1cff7ee995f771198fd4e5a5b861457a4292f 100644
--- a/Testing/SystemTests/tests/analysis/reference/II.OSIRISMoments.nxs.md5
+++ b/Testing/SystemTests/tests/analysis/reference/II.OSIRISMoments.nxs.md5
@@ -1 +1 @@
-0f1bfeffea3f3a8b861f0fd64d53eda4
\ No newline at end of file
+a1a495cd3351cd56ed06c7c7844817bb
diff --git a/Testing/SystemTests/tests/analysis/reference/ILLIN16B_EFWS.nxs.md5 b/Testing/SystemTests/tests/analysis/reference/ILLIN16B_EFWS.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..88845194842687ed04d4690dc20fe060ddd40885
--- /dev/null
+++ b/Testing/SystemTests/tests/analysis/reference/ILLIN16B_EFWS.nxs.md5
@@ -0,0 +1 @@
+d89017d00392f902df71ba4561724835
diff --git a/Testing/SystemTests/tests/analysis/reference/ILLIN16B_FWS.nxs.md5 b/Testing/SystemTests/tests/analysis/reference/ILLIN16B_FWS.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..6a595c73848e54d8ed116604c2f08dec90c47344
--- /dev/null
+++ b/Testing/SystemTests/tests/analysis/reference/ILLIN16B_FWS.nxs.md5
@@ -0,0 +1 @@
+d03db75972ed593fc3b86f35ec0074e7
diff --git a/Testing/SystemTests/tests/analysis/reference/ILLIN16B_QENS.nxs.md5 b/Testing/SystemTests/tests/analysis/reference/ILLIN16B_QENS.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..f496213636ef0622ac12d66c2d48840b2d9b2e82
--- /dev/null
+++ b/Testing/SystemTests/tests/analysis/reference/ILLIN16B_QENS.nxs.md5
@@ -0,0 +1 @@
+9b81e5ff6d430a4cb3f8b1ca28e3519d
diff --git a/Testing/SystemTests/tests/analysis/reference/ISIS_Powder-PEARL78338_Van_Cal.nxs.md5 b/Testing/SystemTests/tests/analysis/reference/ISIS_Powder-PEARL78338_Van_Cal.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..76e055cb075a06a960d13796e52829829e3fb141
--- /dev/null
+++ b/Testing/SystemTests/tests/analysis/reference/ISIS_Powder-PEARL78338_Van_Cal.nxs.md5
@@ -0,0 +1 @@
+7e80088fe9a61995c18fa1f9156321b9
diff --git a/Testing/SystemTests/tests/analysis/reference/ISIS_Powder-PEARL92476_92479_all.nxs.md5 b/Testing/SystemTests/tests/analysis/reference/ISIS_Powder-PEARL92476_92479_all.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..b44466a2bb8467410caa7ba90cd3e127b9934b96
--- /dev/null
+++ b/Testing/SystemTests/tests/analysis/reference/ISIS_Powder-PEARL92476_92479_all.nxs.md5
@@ -0,0 +1 @@
+5af4d59e931792809a6c71768815827f
diff --git a/Testing/SystemTests/tests/analysis/reference/ISIS_Powder-PEARL92476_92479_groups.nxs.md5 b/Testing/SystemTests/tests/analysis/reference/ISIS_Powder-PEARL92476_92479_groups.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..68ea3bd901954d16417d0676dba12d6f50b5e87f
--- /dev/null
+++ b/Testing/SystemTests/tests/analysis/reference/ISIS_Powder-PEARL92476_92479_groups.nxs.md5
@@ -0,0 +1 @@
+693f8b8d827cd832109d43380a366785
diff --git a/Testing/SystemTests/tests/analysis/reference/ISIS_Powder-PEARL92476_92479_mods.nxs.md5 b/Testing/SystemTests/tests/analysis/reference/ISIS_Powder-PEARL92476_92479_mods.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..5a11d8bad076945b9650d186912676ed7d160707
--- /dev/null
+++ b/Testing/SystemTests/tests/analysis/reference/ISIS_Powder-PEARL92476_92479_mods.nxs.md5
@@ -0,0 +1 @@
+f89ecea6de2d33cb886f6211ada2e4bf
diff --git a/Testing/SystemTests/tests/analysis/reference/ISIS_Powder-PEARL92476_92479_trans.nxs.md5 b/Testing/SystemTests/tests/analysis/reference/ISIS_Powder-PEARL92476_92479_trans.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..11956eddd8c8c5b8e0d45ee9ed17499a7bece5a2
--- /dev/null
+++ b/Testing/SystemTests/tests/analysis/reference/ISIS_Powder-PEARL92476_92479_trans.nxs.md5
@@ -0,0 +1 @@
+e51964efcfa8661b34a6e2578e2b5cd9
diff --git a/Testing/SystemTests/tests/analysis/reference/PEARL92476_92479_all.nxs.md5 b/Testing/SystemTests/tests/analysis/reference/PEARL92476_92479_all.nxs.md5
deleted file mode 100644
index 471b8bfd669b35fa533b4b35a7d509f17f37e6fc..0000000000000000000000000000000000000000
--- a/Testing/SystemTests/tests/analysis/reference/PEARL92476_92479_all.nxs.md5
+++ /dev/null
@@ -1 +0,0 @@
-64d518c20150e68b6c63f33f14e54560
diff --git a/Testing/SystemTests/tests/analysis/reference/PEARL92476_92479_groups.nxs.md5 b/Testing/SystemTests/tests/analysis/reference/PEARL92476_92479_groups.nxs.md5
deleted file mode 100644
index 02ec9279e68f0a5646166253a817edecdb6e2075..0000000000000000000000000000000000000000
--- a/Testing/SystemTests/tests/analysis/reference/PEARL92476_92479_groups.nxs.md5
+++ /dev/null
@@ -1 +0,0 @@
-976285458340a8dd36b70674bb0e9466
diff --git a/Testing/SystemTests/tests/analysis/reference/PEARL92476_92479_trans.nxs.md5 b/Testing/SystemTests/tests/analysis/reference/PEARL92476_92479_trans.nxs.md5
deleted file mode 100644
index fb76e9b5bdad77afa1f948b1ea015468e9e1f019..0000000000000000000000000000000000000000
--- a/Testing/SystemTests/tests/analysis/reference/PEARL92476_92479_trans.nxs.md5
+++ /dev/null
@@ -1 +0,0 @@
-ce1ff4b0fae10af2614acdf73a4fbfbf
diff --git a/Testing/SystemTests/tests/analysis/reference/POLARIS_PowderDiffVanCalibration.nxs.md5 b/Testing/SystemTests/tests/analysis/reference/POLARIS_PowderDiffVanCalibration.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..cbc2c31b267bd6f481413dff1a580dadeb9d5f86
--- /dev/null
+++ b/Testing/SystemTests/tests/analysis/reference/POLARIS_PowderDiffVanCalibration.nxs.md5
@@ -0,0 +1 @@
+0da8c306cff2df48fba9f09fcef00b92
diff --git a/Testing/SystemTests/tests/analysis/reference/POLARIS_PowderFocus79514.nxs.md5 b/Testing/SystemTests/tests/analysis/reference/POLARIS_PowderFocus79514.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..02d58c5e136f2887dc407a98a695860a0a094f76
--- /dev/null
+++ b/Testing/SystemTests/tests/analysis/reference/POLARIS_PowderFocus79514.nxs.md5
@@ -0,0 +1 @@
+a21f83421257de6da7fb7c2dd66d3eef
diff --git a/Testing/SystemTests/tests/analysis/reference/SNAP_34172_2_4_Grouping_nor.nxs.md5 b/Testing/SystemTests/tests/analysis/reference/SNAP_34172_2_4_Grouping_nor.nxs.md5
new file mode 100644
index 0000000000000000000000000000000000000000..218741c01fad2569fcb820d0d846fcf0ff580989
--- /dev/null
+++ b/Testing/SystemTests/tests/analysis/reference/SNAP_34172_2_4_Grouping_nor.nxs.md5
@@ -0,0 +1 @@
+648aeeed791af5dea783e6550a3fab97
diff --git a/Vates/ParaviewPlugins/ParaViewFilters/SplatterPlot/vtkSplatterPlot.cxx b/Vates/ParaviewPlugins/ParaViewFilters/SplatterPlot/vtkSplatterPlot.cxx
index a5c0d9010671d79dd82997b90ab62afe69a600c9..1eea242716f9c91443fd197a60ca0e5ca611bcfd 100644
--- a/Vates/ParaviewPlugins/ParaViewFilters/SplatterPlot/vtkSplatterPlot.cxx
+++ b/Vates/ParaviewPlugins/ParaViewFilters/SplatterPlot/vtkSplatterPlot.cxx
@@ -12,7 +12,6 @@
 #include "MantidVatesAPI/ADSWorkspaceProvider.h"
 #include "MantidVatesAPI/FieldDataToMetadata.h"
 #include "MantidVatesAPI/FilteringUpdateProgressAction.h"
-#include "MantidVatesAPI/NoThresholdRange.h"
 #include "MantidVatesAPI/VatesXMLDefinitions.h"
 #include "MantidVatesAPI/vtkDataSetToNonOrthogonalDataSet.h"
 #include "MantidVatesAPI/vtkDataSetToWsName.h"
@@ -142,8 +141,7 @@ int vtkSplatterPlot::RequestInformation(vtkInformation *,
     try {
       std::string scalarName = "signal";
       m_presenter = Mantid::Kernel::make_unique<vtkSplatterPlotFactory>(
-            boost::make_shared<NoThresholdRange>(), scalarName, m_numberPoints,
-            m_topPercentile);
+          scalarName, m_numberPoints, m_topPercentile);
 
       // Get the info objects
       vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
@@ -177,8 +175,8 @@ void vtkSplatterPlot::PrintSelf(ostream& os, vtkIndent indent)
  */
 void vtkSplatterPlot::updateAlgorithmProgress(double progress, const std::string& message)
 {
-  this->SetProgress(progress);
   this->SetProgressText(message.c_str());
+  this->UpdateProgress(progress);
 }
 
 /**
diff --git a/Vates/ParaviewPlugins/ParaViewReaders/MDEWNexusReader/vtkMDEWNexusReader.cxx b/Vates/ParaviewPlugins/ParaViewReaders/MDEWNexusReader/vtkMDEWNexusReader.cxx
index 9b89a559be79e5689be7c0ffedbe62fd4ef10df3..d2146f524f8806d3be8498174f3e0a0b9fb316ec 100644
--- a/Vates/ParaviewPlugins/ParaViewReaders/MDEWNexusReader/vtkMDEWNexusReader.cxx
+++ b/Vates/ParaviewPlugins/ParaViewReaders/MDEWNexusReader/vtkMDEWNexusReader.cxx
@@ -17,7 +17,6 @@
 #include "MantidVatesAPI/vtkMDHexFactory.h"
 #include "MantidVatesAPI/vtkMDQuadFactory.h"
 #include "MantidVatesAPI/vtkMDLineFactory.h"
-#include "MantidVatesAPI/IgnoreZerosThresholdRange.h"
 #include "MantidVatesAPI/FilteringUpdateProgressAction.h"
 #include "MantidVatesAPI/MDLoadingViewAdapter.h"
 
@@ -26,8 +25,6 @@
 vtkStandardNewMacro(vtkMDEWNexusReader)
 
     using namespace Mantid::VATES;
-using Mantid::Geometry::IMDDimension_sptr;
-using Mantid::Geometry::IMDDimension_sptr;
 
 vtkMDEWNexusReader::vtkMDEWNexusReader()
     : FileName{nullptr}, m_loadInMemory{false}, m_depth{1}, m_time{0},
@@ -106,15 +103,14 @@ int vtkMDEWNexusReader::RequestData(
   FilterUpdateProgressAction<vtkMDEWNexusReader> drawingProgressAction(
       this, "Drawing...");
 
-  ThresholdRange_scptr thresholdRange =
-      boost::make_shared<IgnoreZerosThresholdRange>();
-  auto hexahedronFactory = Mantid::Kernel::make_unique<vtkMDHexFactory>(
-      thresholdRange, m_normalization);
+  auto hexahedronFactory =
+      Mantid::Kernel::make_unique<vtkMDHexFactory>(m_normalization);
 
-  hexahedronFactory->setSuccessor(Mantid::Kernel::make_unique<vtkMDQuadFactory>(
-                                      thresholdRange, m_normalization))
-      .setSuccessor(Mantid::Kernel::make_unique<vtkMDLineFactory>(
-          thresholdRange, m_normalization));
+  hexahedronFactory
+      ->setSuccessor(
+          Mantid::Kernel::make_unique<vtkMDQuadFactory>(m_normalization))
+      .setSuccessor(
+          Mantid::Kernel::make_unique<vtkMDLineFactory>(m_normalization));
 
   hexahedronFactory->setTime(m_time);
   vtkDataSet *product = m_presenter->execute(
diff --git a/Vates/ParaviewPlugins/ParaViewReaders/MDEWNexusReader/vtkMDEWReader.h b/Vates/ParaviewPlugins/ParaViewReaders/MDEWNexusReader/vtkMDEWReader.h
index 333149bdb6a93b522c33903777768a7d3bd94f63..856e29e821ad0c483c91c7c85d57bbd173a3c15e 100644
--- a/Vates/ParaviewPlugins/ParaViewReaders/MDEWNexusReader/vtkMDEWReader.h
+++ b/Vates/ParaviewPlugins/ParaViewReaders/MDEWNexusReader/vtkMDEWReader.h
@@ -4,6 +4,7 @@
 #include "MantidVatesAPI/MultiDimensionalDbPresenter.h"
 #include "MantidMDAlgorithms/WidthParameter.h"
 #include "MantidVatesAPI/EscalatingRebinningActionManager.h"
+#include "MantidGeometry/MDGeometry/IMDDimension.h"
 #include "MantidGeometry/MDGeometry/MDGeometryXMLBuilder.h"
 #include "MantidVatesAPI/ThresholdRange.h"
 #include "MantidKernel/MultiThreaded.h"
diff --git a/Vates/ParaviewPlugins/ParaViewReaders/MDHWNexusReader/vtkMDHWNexusReader.cxx b/Vates/ParaviewPlugins/ParaViewReaders/MDHWNexusReader/vtkMDHWNexusReader.cxx
index 41a42db9540d41e5a8b1b033abb9393caf865b72..73433a07b5ba3746911699d106f17e463e4a805d 100644
--- a/Vates/ParaviewPlugins/ParaViewReaders/MDHWNexusReader/vtkMDHWNexusReader.cxx
+++ b/Vates/ParaviewPlugins/ParaViewReaders/MDHWNexusReader/vtkMDHWNexusReader.cxx
@@ -17,14 +17,12 @@
 #include "MantidVatesAPI/TimeToTimeStep.h"
 #include "MantidVatesAPI/vtkMDHistoHex4DFactory.h"
 #include "MantidVatesAPI/vtkMDHistoHexFactory.h"
-#include "MantidVatesAPI/IgnoreZerosThresholdRange.h"
 #include "MantidVatesAPI/FilteringUpdateProgressAction.h"
 #include "MantidVatesAPI/MDLoadingViewAdapter.h"
 
 vtkStandardNewMacro(vtkMDHWNexusReader)
 
     using namespace Mantid::VATES;
-using Mantid::Geometry::IMDDimension_sptr;
 
 vtkMDHWNexusReader::vtkMDHWNexusReader()
     : FileName{nullptr}, m_loadInMemory(false), m_depth(1), m_time(0),
@@ -106,16 +104,13 @@ int vtkMDHWNexusReader::RequestData(
   FilterUpdateProgressAction<vtkMDHWNexusReader> drawingProgressAction(
       this, "Drawing...");
 
-  ThresholdRange_scptr thresholdRange =
-      boost::make_shared<IgnoreZerosThresholdRange>();
-
   // Will attempt to handle drawing in 4D case and then in 3D case
   // if that fails.
   auto factory =
       Mantid::Kernel::make_unique<vtkMDHistoHex4DFactory<TimeToTimeStep>>(
-          thresholdRange, m_normalizationOption, m_time);
-  factory->setSuccessor(Mantid::Kernel::make_unique<vtkMDHistoHexFactory>(
-      thresholdRange, m_normalizationOption));
+          m_normalizationOption, m_time);
+  factory->setSuccessor(
+      Mantid::Kernel::make_unique<vtkMDHistoHexFactory>(m_normalizationOption));
 
   auto product = m_presenter->execute(factory.get(), loadingProgressAction,
                                       drawingProgressAction);
@@ -126,7 +121,8 @@ int vtkMDHWNexusReader::RequestData(
   try {
     auto workspaceProvider = Mantid::Kernel::make_unique<
         ADSWorkspaceProvider<Mantid::API::IMDWorkspace>>();
-    m_presenter->makeNonOrthogonal(output, std::move(workspaceProvider));
+    m_presenter->makeNonOrthogonal(output, std::move(workspaceProvider),
+                                   &drawingProgressAction);
   } catch (std::invalid_argument &e) {
     std::string error = e.what();
     vtkDebugMacro(<< "Workspace does not have correct information to "
diff --git a/Vates/ParaviewPlugins/ParaViewReaders/NexusPeaksReader/vtkNexusPeaksReader.cxx b/Vates/ParaviewPlugins/ParaViewReaders/NexusPeaksReader/vtkNexusPeaksReader.cxx
index fa274fb335ff9451192f58d46e6c8a418f026616..79612fb5ea998b6149f131a7ed844683387b9899 100644
--- a/Vates/ParaviewPlugins/ParaViewReaders/NexusPeaksReader/vtkNexusPeaksReader.cxx
+++ b/Vates/ParaviewPlugins/ParaViewReaders/NexusPeaksReader/vtkNexusPeaksReader.cxx
@@ -29,8 +29,6 @@
 vtkStandardNewMacro(vtkNexusPeaksReader)
 
 using namespace Mantid::VATES;
-using Mantid::Geometry::IMDDimension_sptr;
-using Mantid::Geometry::IMDDimension_sptr;
 using Mantid::API::Workspace_sptr;
 using Mantid::API::AnalysisDataService;
 
diff --git a/Vates/ParaviewPlugins/ParaViewReaders/PeaksReader/vtkPeaksReader.cxx b/Vates/ParaviewPlugins/ParaViewReaders/PeaksReader/vtkPeaksReader.cxx
index 9e62f3296499533a89de8f88905807cbdbb1f226..813c2cca0c462627466ceeddf33b4f881d44f026 100644
--- a/Vates/ParaviewPlugins/ParaViewReaders/PeaksReader/vtkPeaksReader.cxx
+++ b/Vates/ParaviewPlugins/ParaViewReaders/PeaksReader/vtkPeaksReader.cxx
@@ -28,13 +28,11 @@
 vtkStandardNewMacro(vtkPeaksReader)
 
 using namespace Mantid::VATES;
-using Mantid::Geometry::IMDDimension_sptr;
-using Mantid::Geometry::IMDDimension_sptr;
 using Mantid::API::Workspace_sptr;
 using Mantid::API::AnalysisDataService;
 
 vtkPeaksReader::vtkPeaksReader()
-    : FileName{NULL}, m_isSetup{false}, m_uintPeakMarkerSize{0.3},
+    : FileName{nullptr}, m_isSetup{false}, m_uintPeakMarkerSize{0.3},
       m_dimensions{1} {
   this->SetNumberOfInputPorts(0);
   this->SetNumberOfOutputPorts(1);
diff --git a/Vates/ParaviewPlugins/ParaViewSources/MDEWSource/vtkMDEWSource.cxx b/Vates/ParaviewPlugins/ParaViewSources/MDEWSource/vtkMDEWSource.cxx
index a26fdd2dee44661aeba0b560b8b5af5f3df40074..f1678b68418fa6a36b08b2255e62bdfc913c1a17 100644
--- a/Vates/ParaviewPlugins/ParaViewSources/MDEWSource/vtkMDEWSource.cxx
+++ b/Vates/ParaviewPlugins/ParaViewSources/MDEWSource/vtkMDEWSource.cxx
@@ -3,27 +3,26 @@
 #include "vtkBox.h"
 #include "vtkInformation.h"
 #include "vtkInformationVector.h"
+#include "vtkNew.h"
 #include "vtkObjectFactory.h"
 #include "vtkPVClipDataSet.h"
 #include "vtkPVInformationKeys.h"
-#include "vtkUnstructuredGridAlgorithm.h"
-#include "vtkUnstructuredGrid.h"
 #include "vtkStreamingDemandDrivenPipeline.h"
-#include "vtkNew.h"
+#include "vtkUnstructuredGrid.h"
+#include "vtkUnstructuredGridAlgorithm.h"
 
-#include "MantidVatesAPI/BoxInfo.h"
-#include "MantidAPI/IMDWorkspace.h"
 #include "MantidAPI/IMDEventWorkspace.h"
+#include "MantidAPI/IMDWorkspace.h"
+#include "MantidKernel/WarningSuppressions.h"
+#include "MantidVatesAPI/ADSWorkspaceProvider.h"
+#include "MantidVatesAPI/BoxInfo.h"
+#include "MantidVatesAPI/FilteringUpdateProgressAction.h"
 #include "MantidVatesAPI/MDEWInMemoryLoadingPresenter.h"
 #include "MantidVatesAPI/MDLoadingViewAdapter.h"
-#include "MantidVatesAPI/ADSWorkspaceProvider.h"
+#include "MantidVatesAPI/vtkMD0DFactory.h"
 #include "MantidVatesAPI/vtkMDHexFactory.h"
-#include "MantidVatesAPI/vtkMDQuadFactory.h"
 #include "MantidVatesAPI/vtkMDLineFactory.h"
-#include "MantidVatesAPI/vtkMD0DFactory.h"
-#include "MantidVatesAPI/FilteringUpdateProgressAction.h"
-#include "MantidVatesAPI/IgnoreZerosThresholdRange.h"
-#include "MantidKernel/WarningSuppressions.h"
+#include "MantidVatesAPI/vtkMDQuadFactory.h"
 
 #include <boost/optional.hpp>
 
@@ -45,13 +44,11 @@ vtkMDEWSource::~vtkMDEWSource() {}
  Setter for the recursion depth
  @param depth : recursion depth to use
 */
-void vtkMDEWSource::SetDepth(int depth)
-{
+void vtkMDEWSource::SetDepth(int depth) {
   size_t temp = depth;
-  if(m_depth != temp)
-  {
-   this->m_depth = temp;
-   this->Modified();
+  if (m_depth != temp) {
+    this->m_depth = temp;
+    this->Modified();
   }
 }
 
@@ -59,10 +56,8 @@ void vtkMDEWSource::SetDepth(int depth)
   Setter for the workspace name.
   @param name : workspace name to extract from ADS.
 */
-void vtkMDEWSource::SetWsName(std::string name)
-{
-  if(m_wsName != name && name != "")
-  {
+void vtkMDEWSource::SetWsName(const std::string &name) {
+  if (m_wsName != name && !name.empty()) {
     m_wsName = name;
     this->Modified();
   }
@@ -148,43 +143,41 @@ std::string vtkMDEWSource::GetInstrument() {
 }
 
 /**
-Set the normalization option. This is how the signal data will be normalized before viewing.
+Set the normalization option. This is how the signal data will be normalized
+before viewing.
 @param option : Normalization option
 */
-void vtkMDEWSource::SetNormalization(int option)
-{
+void vtkMDEWSource::SetNormalization(int option) {
   m_normalization = static_cast<Mantid::VATES::VisualNormalization>(option);
   this->Modified();
 }
 
-
-int vtkMDEWSource::RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *outputVector)
-{
-  if(m_presenter->canReadFile())
-  {
+int vtkMDEWSource::RequestData(vtkInformation *, vtkInformationVector **,
+                               vtkInformationVector *outputVector) {
+  if (m_presenter->canReadFile()) {
     using namespace Mantid::VATES;
-    //get the info objects
+    // get the info objects
     vtkInformation *outInfo = outputVector->GetInformationObject(0);
 
-    if (outInfo->Has(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP()))
-    {
+    if (outInfo->Has(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP())) {
       // usually only one actual step requested
-      m_time =outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP());
+      m_time =
+          outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP());
     }
 
-    FilterUpdateProgressAction<vtkMDEWSource> loadingProgressUpdate(this, "Loading...");
-    FilterUpdateProgressAction<vtkMDEWSource> drawingProgressUpdate(this, "Drawing...");
+    FilterUpdateProgressAction<vtkMDEWSource> loadingProgressUpdate(
+        this, "Loading...");
+    FilterUpdateProgressAction<vtkMDEWSource> drawingProgressUpdate(
+        this, "Drawing...");
 
-    ThresholdRange_scptr thresholdRange =
-        boost::make_shared<IgnoreZerosThresholdRange>();
-    auto hexahedronFactory = Mantid::Kernel::make_unique<vtkMDHexFactory>(
-        thresholdRange, m_normalization);
+    auto hexahedronFactory =
+        Mantid::Kernel::make_unique<vtkMDHexFactory>(m_normalization);
 
-    hexahedronFactory->setSuccessor(
-                         Mantid::Kernel::make_unique<vtkMDQuadFactory>(
-                             thresholdRange, m_normalization))
-        .setSuccessor(Mantid::Kernel::make_unique<vtkMDLineFactory>(
-            thresholdRange, m_normalization))
+    hexahedronFactory
+        ->setSuccessor(
+            Mantid::Kernel::make_unique<vtkMDQuadFactory>(m_normalization))
+        .setSuccessor(
+            Mantid::Kernel::make_unique<vtkMDLineFactory>(m_normalization))
         .setSuccessor(Mantid::Kernel::make_unique<vtkMD0DFactory>());
 
     hexahedronFactory->setTime(m_time);
@@ -192,7 +185,7 @@ int vtkMDEWSource::RequestData(vtkInformation *, vtkInformationVector **, vtkInf
     product = m_presenter->execute(
         hexahedronFactory.get(), loadingProgressUpdate, drawingProgressUpdate);
 
-    //-------------------------------------------------------- Corrects problem whereby boundaries not set propertly in PV.
+    // Corrects problem whereby boundaries not set propertly in PV.
     auto box = vtkSmartPointer<vtkBox>::New();
     box->SetBounds(product->GetBounds());
     auto clipper = vtkSmartPointer<vtkPVClipDataSet>::New();
@@ -204,17 +197,16 @@ int vtkMDEWSource::RequestData(vtkInformation *, vtkInformationVector **, vtkInf
     //--------------------------------------------------------
 
     vtkUnstructuredGrid *output = vtkUnstructuredGrid::SafeDownCast(
-      outInfo->Get(vtkDataObject::DATA_OBJECT()));
+        outInfo->Get(vtkDataObject::DATA_OBJECT()));
     output->ShallowCopy(clipperOutput);
 
-    try
-    {
-      auto workspaceProvider = Mantid::Kernel::make_unique<ADSWorkspaceProvider<Mantid::API::IMDWorkspace>>();
-      m_presenter->makeNonOrthogonal(output, std::move(workspaceProvider));
-    }
-    catch (std::invalid_argument &e)
-    {
-    std::string error = e.what();
+    try {
+      auto workspaceProvider = Mantid::Kernel::make_unique<
+          ADSWorkspaceProvider<Mantid::API::IMDWorkspace>>();
+      m_presenter->makeNonOrthogonal(output, std::move(workspaceProvider),
+                                     &drawingProgressUpdate);
+    } catch (std::invalid_argument &e) {
+      std::string error = e.what();
       vtkDebugMacro(<< "Workspace does not have correct information to "
                     << "plot non-orthogonal axes. " << error);
       // Add the standard change of basis matrix and set the boundaries
@@ -232,48 +224,46 @@ int vtkMDEWSource::RequestInformation(
     vtkInformation *vtkNotUsed(request),
     vtkInformationVector **vtkNotUsed(inputVector),
     vtkInformationVector *outputVector) {
-  if (m_presenter == NULL && !m_wsName.empty()) {
+  if (!m_presenter && !m_wsName.empty()) {
     std::unique_ptr<MDLoadingView> view =
         Mantid::Kernel::make_unique<MDLoadingViewAdapter<vtkMDEWSource>>(this);
     m_presenter = Mantid::Kernel::make_unique<MDEWInMemoryLoadingPresenter>(
         std::move(view),
         new ADSWorkspaceProvider<Mantid::API::IMDEventWorkspace>, m_wsName);
-    if (!m_presenter->canReadFile()) {
-      vtkErrorMacro(<< "Cannot fetch the specified workspace from Mantid ADS.");
-    } else {
+    if (m_presenter->canReadFile()) {
       // If the MDEvent workspace has had top level splitting applied to it,
       // then use the a deptgit stah of 1
-      auto workspaceProvider = Mantid::Kernel::make_unique<ADSWorkspaceProvider<Mantid::API::IMDEventWorkspace>>();
-      if (auto split =
-              Mantid::VATES::findRecursionDepthForTopLevelSplitting(m_wsName, std::move(workspaceProvider))) {
+      auto workspaceProvider = Mantid::Kernel::make_unique<
+          ADSWorkspaceProvider<Mantid::API::IMDEventWorkspace>>();
+      if (auto split = Mantid::VATES::findRecursionDepthForTopLevelSplitting(
+              m_wsName, *workspaceProvider)) {
         SetDepth(split.get());
       }
 
       m_presenter->executeLoadMetadata();
       setTimeRange(outputVector);
+    } else {
+      vtkErrorMacro(<< "Cannot fetch the specified workspace from Mantid ADS.");
     }
   }
   return 1;
 }
 
-void vtkMDEWSource::PrintSelf(ostream& os, vtkIndent indent)
-{
+void vtkMDEWSource::PrintSelf(ostream &os, vtkIndent indent) {
   this->Superclass::PrintSelf(os, indent);
 }
 
 /** Helper function to setup the time range.
 @param outputVector : vector onto which the time range will be set.
 */
-void vtkMDEWSource::setTimeRange(vtkInformationVector* outputVector)
-{
-  if(m_presenter->hasTDimensionAvailable())
-  {
+void vtkMDEWSource::setTimeRange(vtkInformationVector *outputVector) {
+  if (m_presenter->hasTDimensionAvailable()) {
     vtkInformation *outInfo = outputVector->GetInformationObject(0);
     outInfo->Set(vtkPVInformationKeys::TIME_LABEL_ANNOTATION(),
                  m_presenter->getTimeStepLabel().c_str());
     std::vector<double> timeStepValues = m_presenter->getTimeStepValues();
-    outInfo->Set(vtkStreamingDemandDrivenPipeline::TIME_STEPS(), &timeStepValues[0],
-      static_cast<int> (timeStepValues.size()));
+    outInfo->Set(vtkStreamingDemandDrivenPipeline::TIME_STEPS(),
+                 &timeStepValues[0], static_cast<int>(timeStepValues.size()));
     double timeRange[2];
     timeRange[0] = timeStepValues.front();
     timeRange[1] = timeStepValues.back();
@@ -286,37 +276,28 @@ void vtkMDEWSource::setTimeRange(vtkInformationVector* outputVector)
 Getter for the recursion depth.
 @return depth
 */
-size_t vtkMDEWSource::getRecursionDepth() const
-{
-  return this->m_depth;
-}
+size_t vtkMDEWSource::getRecursionDepth() const { return this->m_depth; }
 
 /*
 Getter for the load in memory status
 @return true.
 */
-bool vtkMDEWSource::getLoadInMemory() const
-{
-  return true;
-}
+bool vtkMDEWSource::getLoadInMemory() const { return true; }
 
 /*Getter for the time
 @return the time.
 */
-double vtkMDEWSource::getTime() const
-{
-  return m_time;
-}
+double vtkMDEWSource::getTime() const { return m_time; }
 
 /*
 Setter for the algorithm progress.
 @param progress : progress increment
 @param message : progress message
 */
-void vtkMDEWSource::updateAlgorithmProgress(double progress, const std::string& message)
-{
+void vtkMDEWSource::updateAlgorithmProgress(double progress,
+                                            const std::string &message) {
   this->SetProgressText(message.c_str());
-  this->SetProgress(progress);
+  this->UpdateProgress(progress);
 }
 
 /*
diff --git a/Vates/ParaviewPlugins/ParaViewSources/MDEWSource/vtkMDEWSource.h b/Vates/ParaviewPlugins/ParaViewSources/MDEWSource/vtkMDEWSource.h
index 2636d28f80e2ea5687cd7b5cdcc3b9bdee2baf50..58112cacf74914fd8e6df29674b9f1a663eded8c 100644
--- a/Vates/ParaviewPlugins/ParaViewSources/MDEWSource/vtkMDEWSource.h
+++ b/Vates/ParaviewPlugins/ParaViewSources/MDEWSource/vtkMDEWSource.h
@@ -50,7 +50,7 @@ public:
   vtkTypeMacro(vtkMDEWSource, vtkUnstructuredGridAlgorithm) void PrintSelf(
       ostream &os, vtkIndent indent) override;
 
-  void SetWsName(std::string wsName);
+  void SetWsName(const std::string &wsName);
   void SetDepth(int depth);
   void SetNormalization(int option);
 
diff --git a/Vates/ParaviewPlugins/ParaViewSources/MDHWSource/vtkMDHWSource.cxx b/Vates/ParaviewPlugins/ParaViewSources/MDHWSource/vtkMDHWSource.cxx
index fc1431a35c5be433c1475880b502c9b5120ef255..34025b8c8eb3de51d8c9b0b7d7396e375a85e355 100644
--- a/Vates/ParaviewPlugins/ParaViewSources/MDHWSource/vtkMDHWSource.cxx
+++ b/Vates/ParaviewPlugins/ParaViewSources/MDHWSource/vtkMDHWSource.cxx
@@ -20,7 +20,6 @@
 #include "MantidVatesAPI/vtkMDHistoLineFactory.h"
 #include "MantidVatesAPI/vtkMD0DFactory.h"
 #include "MantidVatesAPI/FilteringUpdateProgressAction.h"
-#include "MantidVatesAPI/IgnoreZerosThresholdRange.h"
 
 using namespace Mantid::VATES;
 
@@ -154,22 +153,20 @@ int vtkMDHWSource::RequestData(vtkInformation *, vtkInformationVector **, vtkInf
     FilterUpdateProgressAction<vtkMDHWSource> loadingProgressUpdate(this, "Loading...");
     FilterUpdateProgressAction<vtkMDHWSource> drawingProgressUpdate(this, "Drawing...");
 
-    ThresholdRange_scptr thresholdRange =
-        boost::make_shared<IgnoreZerosThresholdRange>();
-
     /*
     Will attempt to handle drawing in 4D case and then in 3D case if that fails, and so on down to 1D
     */
     auto factory =
         Mantid::Kernel::make_unique<vtkMDHistoHex4DFactory<TimeToTimeStep>>(
-            thresholdRange, m_normalizationOption, m_time);
+            m_normalizationOption, m_time);
 
-    factory->setSuccessor(Mantid::Kernel::make_unique<vtkMDHistoHexFactory>(
-                              thresholdRange, m_normalizationOption))
+    factory
+        ->setSuccessor(Mantid::Kernel::make_unique<vtkMDHistoHexFactory>(
+            m_normalizationOption))
         .setSuccessor(Mantid::Kernel::make_unique<vtkMDHistoQuadFactory>(
-            thresholdRange, m_normalizationOption))
+            m_normalizationOption))
         .setSuccessor(Mantid::Kernel::make_unique<vtkMDHistoLineFactory>(
-            thresholdRange, m_normalizationOption))
+            m_normalizationOption))
         .setSuccessor(Mantid::Kernel::make_unique<vtkMD0DFactory>());
 
     auto product = m_presenter->execute(factory.get(), loadingProgressUpdate,
@@ -181,7 +178,8 @@ int vtkMDHWSource::RequestData(vtkInformation *, vtkInformationVector **, vtkInf
     try
     {
       auto workspaceProvider = Mantid::Kernel::make_unique<ADSWorkspaceProvider<Mantid::API::IMDWorkspace>>();
-      m_presenter->makeNonOrthogonal(output, std::move(workspaceProvider));
+      m_presenter->makeNonOrthogonal(output, std::move(workspaceProvider),
+                                     &drawingProgressUpdate);
     }
     catch (std::invalid_argument &e)
     {
@@ -291,8 +289,8 @@ Setter for the algorithm progress.
 */
 void vtkMDHWSource::updateAlgorithmProgress(double progress, const std::string& message)
 {
-  this->SetProgress(progress);
   this->SetProgressText(message.c_str());
+  this->UpdateProgress(progress);
 }
 
 /*
diff --git a/Vates/ParaviewPlugins/ParaViewSources/PeaksSource/vtkPeaksSource.cxx b/Vates/ParaviewPlugins/ParaViewSources/PeaksSource/vtkPeaksSource.cxx
index 20cac969d71d002fcbf98f10b26f0c952da089ff..d223689aa168c990ec134bee8b154cab2872b02d 100644
--- a/Vates/ParaviewPlugins/ParaViewSources/PeaksSource/vtkPeaksSource.cxx
+++ b/Vates/ParaviewPlugins/ParaViewSources/PeaksSource/vtkPeaksSource.cxx
@@ -20,8 +20,6 @@
 vtkStandardNewMacro(vtkPeaksSource)
 
 using namespace Mantid::VATES;
-using Mantid::Geometry::IMDDimension_sptr;
-using Mantid::Geometry::IMDDimension_sptr;
 using Mantid::API::Workspace_sptr;
 using Mantid::API::AnalysisDataService;
 
@@ -42,8 +40,7 @@ vtkPeaksSource::~vtkPeaksSource()
   Setter for the workspace name.
   @param name : workspace name to extract from ADS.
 */
-void vtkPeaksSource::SetWsName(std::string name)
-{
+void vtkPeaksSource::SetWsName(const std::string &name) {
   if (!name.empty())
   {
     m_wsName = name;
diff --git a/Vates/ParaviewPlugins/ParaViewSources/PeaksSource/vtkPeaksSource.h b/Vates/ParaviewPlugins/ParaViewSources/PeaksSource/vtkPeaksSource.h
index 33a1e5e8b38575b678fbab684130ff4bc7e9356c..a0671b26f981994fd5bc00f3739a4feb6934cff1 100644
--- a/Vates/ParaviewPlugins/ParaViewSources/PeaksSource/vtkPeaksSource.h
+++ b/Vates/ParaviewPlugins/ParaViewSources/PeaksSource/vtkPeaksSource.h
@@ -45,7 +45,7 @@ public:
                vtkPolyDataAlgorithm) void PrintSelf(ostream &os,
                                                     vtkIndent indent) override;
 
-  void SetWsName(std::string wsName);
+  void SetWsName(const std::string &wsName);
   void SetPeakDimension(int dim);
   /// Setter for the unitegrated peak marker size
   void SetUnintPeakMarkerSize(double mSize);
diff --git a/Vates/ParaviewPlugins/ParaViewSources/SinglePeakMarkerSource/vtkSinglePeakMarkerSource.cxx b/Vates/ParaviewPlugins/ParaViewSources/SinglePeakMarkerSource/vtkSinglePeakMarkerSource.cxx
index d607310440f8b68c6fcdb0e63170f4530c0dddbc..97368a421c14118d1932e938c69e19e1ad5065e3 100644
--- a/Vates/ParaviewPlugins/ParaViewSources/SinglePeakMarkerSource/vtkSinglePeakMarkerSource.cxx
+++ b/Vates/ParaviewPlugins/ParaViewSources/SinglePeakMarkerSource/vtkSinglePeakMarkerSource.cxx
@@ -68,4 +68,4 @@ void vtkSinglePeakMarkerSource::SetPosition3(double position3)
 {
   m_position3 = position3;
   this->Modified();
-}
\ No newline at end of file
+}
diff --git a/Vates/ParaviewPlugins/ParaViewWidgets/QtWidgets/CMakeLists.txt b/Vates/ParaviewPlugins/ParaViewWidgets/QtWidgets/CMakeLists.txt
index 3ad9523a000aef68d45dba67c509f5e72d5759ef..d9c5a349a9d73b798f72e170ec4f50a62b610907 100644
--- a/Vates/ParaviewPlugins/ParaViewWidgets/QtWidgets/CMakeLists.txt
+++ b/Vates/ParaviewPlugins/ParaViewWidgets/QtWidgets/CMakeLists.txt
@@ -4,7 +4,6 @@ set( INC_FILES
  WidgetDllOption.h
  LowHighStepInputWidget.h
  SimpleBinInputWidget.h
- ThresholdRangeWidget.h
 )
 
 # header files that are mocced
@@ -12,14 +11,12 @@ set( HDR_FILES
   BinInputWidget.h
   LowHighStepInputWidget.h
   SimpleBinInputWidget.h
-  ThresholdRangeWidget.h
 )
 
 # source files
 set( SRC_FILES
   LowHighStepInputWidget.cpp
   SimpleBinInputWidget.cpp
-  ThresholdRangeWidget.cpp
 )
 
 # Handle QtWidget header files
@@ -40,8 +37,5 @@ endif ()
 
 add_definitions( -DIN_MANTIDPARAVIEWQT_MANTIDPARAVIEWWIDGETS )
 
-# Put library into subfolder.
-#SET_TARGET_OUTPUT_DIRECTORY(MantidParaViewQtWidgets PVPlugins)
-
 install( TARGETS MantidParaViewQtWidgets ${SYSTEM_PACKAGE_TARGET} DESTINATION ${LIB_DIR} )
 
diff --git a/Vates/ParaviewPlugins/ParaViewWidgets/QtWidgets/ThresholdRangeWidget.cpp b/Vates/ParaviewPlugins/ParaViewWidgets/QtWidgets/ThresholdRangeWidget.cpp
deleted file mode 100644
index a4716b05d07ff3df4fd5bcfacc704bd8ef408606..0000000000000000000000000000000000000000
--- a/Vates/ParaviewPlugins/ParaViewWidgets/QtWidgets/ThresholdRangeWidget.cpp
+++ /dev/null
@@ -1,106 +0,0 @@
-#include "ThresholdRangeWidget.h"
-#include <QLabel>
-#include <QLineEdit>
-#include <QGridLayout>
-#include <QComboBox>
-#include <QPalette>
-#include <QFont>
-#include <boost/algorithm/string.hpp>
-#include <boost/format.hpp>
-#include <QDoubleValidator>
-
-ThresholdRangeWidget::ThresholdRangeWidget(double min, double max) {
-  QVBoxLayout *layout = new QVBoxLayout;
-
-  QGridLayout *headerLayout = new QGridLayout();
-  headerLayout->addWidget(new QLabel("Thresholds"), 0, 0, 1, 2,
-                          Qt::AlignCenter);
-  layout->addLayout(headerLayout);
-
-  m_thresholdStrategyComboBox = new QComboBox;
-  m_thresholdStrategyComboBox->addItem("Ignore Zeros");
-  m_thresholdStrategyComboBox->addItem("No Threshold Range");
-  m_thresholdStrategyComboBox->addItem("Median and Below");
-  m_thresholdStrategyComboBox->addItem("User Defined");
-  connect(m_thresholdStrategyComboBox,
-          SIGNAL(currentIndexChanged(const QString &)), this,
-          SLOT(strategySelectedListener(const QString &)));
-  layout->addWidget(m_thresholdStrategyComboBox, Qt::AlignLeft);
-
-  QHBoxLayout *mmLayout = new QHBoxLayout();
-
-  mmLayout->addWidget(new QLabel("Min"));
-
-  m_minEditBox = new QLineEdit();
-  m_minEditBox->setValidator(new QDoubleValidator(this));
-  std::string minValueString = boost::str(boost::format("%0.2f") % min);
-  m_minEditBox->setText(minValueString.c_str());
-  m_minEditBox->setCursorPosition(0);
-  mmLayout->addWidget(m_minEditBox, Qt::AlignLeft);
-  m_minEditBox->setDisabled(true); // Disabled by default.
-  connect(m_minEditBox, SIGNAL(textEdited(const QString &)), this,
-          SLOT(minThresholdListener(const QString &)));
-
-  mmLayout->addWidget(new QLabel("Max"));
-
-  m_maxEditBox = new QLineEdit();
-  m_maxEditBox->setValidator(new QDoubleValidator(this));
-  std::string maxValueString = boost::str(boost::format("%0.2f") % max);
-  m_maxEditBox->setText(maxValueString.c_str());
-  m_maxEditBox->setCursorPosition(0);
-  m_maxEditBox->setDisabled(true); // Disabled by default
-  mmLayout->addWidget(m_maxEditBox, Qt::AlignLeft);
-  connect(m_maxEditBox, SIGNAL(textEdited(const QString &)), this,
-          SLOT(maxThresholdListener(const QString &)));
-
-  layout->addLayout(mmLayout);
-
-  this->setLayout(layout);
-}
-
-void ThresholdRangeWidget::strategySelectedListener(const QString &) {
-  bool disableUserControls = true;
-  if (m_thresholdStrategyComboBox->currentText() == "User Defined") {
-    disableUserControls = false;
-  }
-  m_maxEditBox->setDisabled(disableUserControls);
-  m_minEditBox->setDisabled(disableUserControls);
-
-  emit chosenStrategyChanged();
-}
-
-void ThresholdRangeWidget::maxThresholdListener(const QString &) {
-  emit maxChanged();
-}
-
-void ThresholdRangeWidget::minThresholdListener(const QString &) {
-  emit minChanged();
-}
-
-void ThresholdRangeWidget::setMaximum(double value) {
-  std::string maxValueString = boost::str(boost::format("%0.2f") % value);
-  m_maxEditBox->setText(maxValueString.c_str());
-  m_maxEditBox->setCursorPosition(0);
-}
-
-void ThresholdRangeWidget::setMinimum(double value) {
-  std::string minValueString = boost::str(boost::format("%0.2f") % value);
-  m_minEditBox->setText(minValueString.c_str());
-  m_minEditBox->setCursorPosition(0);
-}
-
-ThresholdRangeWidget::~ThresholdRangeWidget() {}
-
-QString ThresholdRangeWidget::getMaxSignal() const {
-  return m_maxEditBox->text();
-}
-
-QString ThresholdRangeWidget::getMinSignal() const {
-  return m_minEditBox->text();
-}
-
-QString ThresholdRangeWidget::getChosenStrategy() const {
-  std::string minValueString = boost::str(
-      boost::format("%i") % m_thresholdStrategyComboBox->currentIndex());
-  return QString(minValueString.c_str());
-}
diff --git a/Vates/ParaviewPlugins/ParaViewWidgets/QtWidgets/ThresholdRangeWidget.h b/Vates/ParaviewPlugins/ParaViewWidgets/QtWidgets/ThresholdRangeWidget.h
deleted file mode 100644
index 4a89b9fc8d82f0df5e95c7fcb522f74040e4f6b7..0000000000000000000000000000000000000000
--- a/Vates/ParaviewPlugins/ParaViewWidgets/QtWidgets/ThresholdRangeWidget.h
+++ /dev/null
@@ -1,99 +0,0 @@
-#ifndef THRESHOLD_RANGE_WIDGET_H
-#define THRESHOLD_RANGE_WIDGET_H
-
-#include "WidgetDllOption.h"
-#include <qwidget.h>
-#include <qstring.h>
-#include "MantidGeometry/MDGeometry/MDTypes.h"
-#include <qlineedit.h>
-/** This is the GUI implementation of the threshold range widgets. These are
-   used to set max and min threshold values.
-
-    @author Owen Arnold Tessella/ISIS
-    @date July 04/2011
-
-    Copyright &copy; 2008 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>
-*/
-
-// Foward decs
-class QLabel;
-class QLayout;
-class QLineEdit;
-class QComboBox;
-
-// cppcheck-suppress class_X_Y
-class EXPORT_OPT_MANTIDPARVIEW ThresholdRangeWidget : public QWidget {
-
-  Q_OBJECT
-public:
-  Q_PROPERTY(QString MinSignal READ getMinSignal WRITE setMinSignal NOTIFY
-                 minChanged)
-  Q_PROPERTY(QString MaxSignal READ getMaxSignal WRITE setMaxSignal NOTIFY
-                 maxChanged)
-  Q_PROPERTY(QString ChosenStrategy READ getChosenStrategy WRITE
-                 setChosenStrategy NOTIFY chosenStrategyChanged)
-
-  ThresholdRangeWidget(double min, double max);
-
-  ~ThresholdRangeWidget() override;
-
-  QString getMaxSignal() const;
-  QString getMinSignal() const;
-  QString getChosenStrategy() const;
-
-  void setMaximum(double value);
-  void setMinimum(double value);
-
-  void setMinSignal(QString value) {
-    // Do nothing.
-    UNUSED_ARG(value);
-  }
-
-  void setMaxSignal(QString value) {
-    // Do nothing.
-    UNUSED_ARG(value);
-  }
-
-  void setChosenStrategy(QString value) {
-    // Do nothing.
-    UNUSED_ARG(value);
-  }
-
-Q_SIGNALS:
-  void minChanged();
-  void maxChanged();
-  void chosenStrategyChanged();
-
-private:
-  QLineEdit *m_maxEditBox;
-  QLineEdit *m_minEditBox;
-  QComboBox *m_thresholdStrategyComboBox;
-
-private slots:
-  void maxThresholdListener(const QString &);
-
-  void minThresholdListener(const QString &);
-
-  void strategySelectedListener(const QString &);
-};
-
-#endif
diff --git a/Vates/VatesAPI/CMakeLists.txt b/Vates/VatesAPI/CMakeLists.txt
index 6dcadda7cc892f968050d4f4fe4074d8fd080d4e..3231a91ea741b74e4dbd8ec92421a32286c68156 100644
--- a/Vates/VatesAPI/CMakeLists.txt
+++ b/Vates/VatesAPI/CMakeLists.txt
@@ -11,7 +11,6 @@ src/CompositePeaksPresenterVsi.cpp
 src/ConcretePeaksPresenterVsi.cpp
 src/EventNexusLoadingPresenter.cpp
 src/FieldDataToMetadata.cpp
-src/IgnoreZerosThresholdRange.cpp
 src/IMDDimensionComparitor.cpp
 src/LoadVTK.cpp
 src/MDEWEventNexusLoadingPresenter.cpp
@@ -21,22 +20,20 @@ src/MDHWInMemoryLoadingPresenter.cpp
 src/MDHWLoadingPresenter.cpp
 src/MDHWNexusLoadingPresenter.cpp
 src/MDLoadingViewSimple.cpp
-src/MedianAndBelowThresholdRange.cpp
 src/MetadataToFieldData.cpp
 src/MetadataToFieldData.cpp
 src/MetaDataExtractorUtils.cpp
 src/MetadataJsonManager.cpp
 src/MDLoadingPresenter.cpp
 src/Normalization.cpp
-src/NoThresholdRange.cpp
 src/ProgressAction.cpp
+src/PresenterFactories.cpp
 src/PresenterUtilities.cpp
 src/SaveMDWorkspaceToVTK.cpp
 src/SaveMDWorkspaceToVTKImpl.cpp
 src/SingleWorkspaceProvider.cpp
 src/TimeStepToTimeStep.cpp
 src/TimeToTimeStep.cpp
-src/UserDefinedThresholdRange.cpp
 src/VatesXMLDefinitions.cpp
 src/VatesConfigurations.cpp
 src/ViewFrustum.cpp
@@ -89,14 +86,11 @@ inc/MantidVatesAPI/MDLoadingPresenter.h
 inc/MantidVatesAPI/MDLoadingView.h
 inc/MantidVatesAPI/MDLoadingViewSimple.h
 inc/MantidVatesAPI/MDLoadingViewAdapter.h
-inc/MantidVatesAPI/MedianAndBelowThresholdRange.h
 inc/MantidVatesAPI/MetaDataExtractorUtils.h
 inc/MantidVatesAPI/MetadataJsonManager.h
 inc/MantidVatesAPI/Normalization.h
-inc/MantidVatesAPI/IgnoreZerosThresholdRange.h
 inc/MantidVatesAPI/IMDDimensionComparitor.h
 inc/MantidVatesAPI/MetadataToFieldData.h
-inc/MantidVatesAPI/NoThresholdRange.h
 inc/MantidVatesAPI/NullPeaksPresenterVsi.h
 inc/MantidVatesAPI/PeaksPresenterVsi.h
 inc/MantidVatesAPI/PresenterFactories.h
@@ -105,10 +99,8 @@ inc/MantidVatesAPI/SaveMDWorkspaceToVTK.h
 inc/MantidVatesAPI/SaveMDWorkspaceToVTKImpl.h
 inc/MantidVatesAPI/SingleWorkspaceProvider.h
 inc/MantidVatesAPI/SQWLoadingPresenter.h
-inc/MantidVatesAPI/ThresholdRange.h
 inc/MantidVatesAPI/TimeStepToTimeStep.h
 inc/MantidVatesAPI/TimeToTimeStep.h
-inc/MantidVatesAPI/UserDefinedThresholdRange.h
 inc/MantidVatesAPI/VatesXMLDefinitions.h
 inc/MantidVatesAPI/VatesConfigurations.h
 inc/MantidVatesAPI/VatesKnowledgeSerializer.h
@@ -180,10 +172,6 @@ test/SingleWorkspaceProviderTest.h
 test/SQWLoadingPresenterTest.h
 test/TimeStepToTimeStepTest.h
 test/TimeToTimeStepTest.h
-test/UserDefinedThresholdRangeTest.h
-test/MedianAndBelowThresholdRangeTest.h
-test/NoThresholdRangeTest.h
-test/IgnoreZerosThresholdRangeTest.h
 test/VatesKnowledgeSerializerTest.h
 test/ViewFrustumTest.h
 test/vtkDataSetToScaledDataSetTest.h
diff --git a/Vates/VatesAPI/inc/MantidVatesAPI/BoxInfo.h b/Vates/VatesAPI/inc/MantidVatesAPI/BoxInfo.h
index 4ade66519b1767f59f52ca5c02f09bd9c7082124..ec6fd5774d21741399162742cfe6b2b63b2d9f9c 100644
--- a/Vates/VatesAPI/inc/MantidVatesAPI/BoxInfo.h
+++ b/Vates/VatesAPI/inc/MantidVatesAPI/BoxInfo.h
@@ -42,7 +42,7 @@ Code Documentation is available at: <http://doxygen.mantidproject.org>
  */
 boost::optional<int> DLLExport findRecursionDepthForTopLevelSplitting(
     const std::string &workspaceName,
-    std::unique_ptr<WorkspaceProvider> workspaceProvider);
+    const WorkspaceProvider &workspaceProvider);
 }
 }
 
diff --git a/Vates/VatesAPI/inc/MantidVatesAPI/ColorScaleGuard.h b/Vates/VatesAPI/inc/MantidVatesAPI/ColorScaleGuard.h
index 8db5918485086aa1b673a2a652838ed0a431609e..cb46e74a839fa6dc82ae886690c6b27a5f06f154 100644
--- a/Vates/VatesAPI/inc/MantidVatesAPI/ColorScaleGuard.h
+++ b/Vates/VatesAPI/inc/MantidVatesAPI/ColorScaleGuard.h
@@ -25,8 +25,8 @@ private:
 class DLLExport ColorScaleLockGuard {
 public:
   ColorScaleLockGuard(ColorScaleLock *lock) {
-    if (lock == NULL || lock->isLocked()) {
-      m_lock = NULL;
+    if (!lock || lock->isLocked()) {
+      m_lock = nullptr;
     } else {
       m_lock = lock;
       m_lock->lock();
@@ -34,7 +34,7 @@ public:
   }
 
   ~ColorScaleLockGuard() {
-    if (m_lock != NULL) {
+    if (m_lock) {
       m_lock->unlock();
     }
   }
diff --git a/Vates/VatesAPI/inc/MantidVatesAPI/CompositePeaksPresenterVsi.h b/Vates/VatesAPI/inc/MantidVatesAPI/CompositePeaksPresenterVsi.h
index a3a171b5661746d7bc08c3175027d7c53e975aca..659c18a21fff3c6ee95967ae4a55c6a4a22dd49d 100644
--- a/Vates/VatesAPI/inc/MantidVatesAPI/CompositePeaksPresenterVsi.h
+++ b/Vates/VatesAPI/inc/MantidVatesAPI/CompositePeaksPresenterVsi.h
@@ -37,9 +37,9 @@ public:
   void removePresenter(const std::string &peaksWorkspaceName);
   void updateWorkspaces(const std::vector<std::string> &peaksWorkspaceNames);
   void sortPeaksWorkspace(const std::string &, const bool) override {}
-  void sortPeaksWorkspace(
-      const std::string &columnToSortBy, const bool sortedAscending,
-      boost::shared_ptr<const Mantid::API::IPeaksWorkspace> peaksWS);
+  void sortPeaksWorkspace(const std::string &columnToSortBy,
+                          const bool sortedAscending,
+                          const Mantid::API::IPeaksWorkspace *peaksWS);
   bool hasPeaks();
 
 private:
@@ -48,4 +48,4 @@ private:
 };
 }
 }
-#endif
\ No newline at end of file
+#endif
diff --git a/Vates/VatesAPI/inc/MantidVatesAPI/ConcretePeaksPresenterVsi.h b/Vates/VatesAPI/inc/MantidVatesAPI/ConcretePeaksPresenterVsi.h
index 244373c7f3e63b8e1e06ed60d457bbb9e4673c0d..568db60d77224ff30edb690069332439d311eca9 100644
--- a/Vates/VatesAPI/inc/MantidVatesAPI/ConcretePeaksPresenterVsi.h
+++ b/Vates/VatesAPI/inc/MantidVatesAPI/ConcretePeaksPresenterVsi.h
@@ -32,7 +32,7 @@ public:
 
 private:
   /// Get the max radius.
-  double getMaxRadius(Mantid::Geometry::PeakShape_sptr shape) const;
+  double getMaxRadius(const Mantid::Geometry::PeakShape &shape) const;
   /// Viewable Peaks
   mutable std::vector<bool> m_viewablePeaks;
   /// The viewable region
@@ -44,4 +44,4 @@ private:
 };
 }
 }
-#endif
\ No newline at end of file
+#endif
diff --git a/Vates/VatesAPI/inc/MantidVatesAPI/EventNexusLoadingPresenter.h b/Vates/VatesAPI/inc/MantidVatesAPI/EventNexusLoadingPresenter.h
index ec25c11c51bd4a22f17520d925e1959991762dd2..c01ad069a8332aba4fa01d2d3ceaeb2704e9aa09 100644
--- a/Vates/VatesAPI/inc/MantidVatesAPI/EventNexusLoadingPresenter.h
+++ b/Vates/VatesAPI/inc/MantidVatesAPI/EventNexusLoadingPresenter.h
@@ -37,7 +37,7 @@ class MDLoadingView;
 class DLLExport EventNexusLoadingPresenter : public MDEWLoadingPresenter {
 public:
   EventNexusLoadingPresenter(std::unique_ptr<MDLoadingView> view,
-                             const std::string fileName);
+                             const std::string &fileName);
   vtkSmartPointer<vtkDataSet>
   execute(vtkDataSetFactory *factory, ProgressAction &loadingProgressUpdate,
           ProgressAction &drawingProgressUpdate) override;
diff --git a/Vates/VatesAPI/inc/MantidVatesAPI/FactoryChains.h b/Vates/VatesAPI/inc/MantidVatesAPI/FactoryChains.h
index ccf2463465425944fafae99fc17fec84ccbb6db3..ee7e4781a967b210974110bac64677d08dbb3493 100644
--- a/Vates/VatesAPI/inc/MantidVatesAPI/FactoryChains.h
+++ b/Vates/VatesAPI/inc/MantidVatesAPI/FactoryChains.h
@@ -19,14 +19,12 @@ class MDLoadingPresenter;
 
 /// Creates a facotry chain for MDHisto workspaces
 std::unique_ptr<vtkMDHistoHex4DFactory<TimeToTimeStep>> DLLExport
-createFactoryChainForHistoWorkspace(ThresholdRange_scptr threshold,
-                                    VisualNormalization normalization,
+createFactoryChainForHistoWorkspace(VisualNormalization normalization,
                                     double time);
 
 /// Creates a factory chain for MDEvent workspaces
 std::unique_ptr<vtkMDHexFactory> DLLExport
-createFactoryChainForEventWorkspace(ThresholdRange_scptr threshold,
-                                    VisualNormalization normalization,
+createFactoryChainForEventWorkspace(VisualNormalization normalization,
                                     double time);
 
 /// Function to apply the Change-of-Basis-Matrix
@@ -36,7 +34,7 @@ void DLLExport applyCOBMatrixSettingsToVtkDataSet(
 
 /// Function to get clipped data sets.
 vtkSmartPointer<vtkPVClipDataSet> DLLExport
-getClippedDataSet(vtkSmartPointer<vtkDataSet> dataSet);
+getClippedDataSet(const vtkSmartPointer<vtkDataSet> &dataSet);
 
 /// Create name with timestamp attached.
 std::string DLLExport createTimeStampedName(const std::string &name);
diff --git a/Vates/VatesAPI/inc/MantidVatesAPI/FieldDataToMetadata.h b/Vates/VatesAPI/inc/MantidVatesAPI/FieldDataToMetadata.h
index 694dce9654540ec293645568ef7d2815d815e3a2..24fff10ab06ab04b5da04d6fa0630a362a5ac278 100644
--- a/Vates/VatesAPI/inc/MantidVatesAPI/FieldDataToMetadata.h
+++ b/Vates/VatesAPI/inc/MantidVatesAPI/FieldDataToMetadata.h
@@ -41,7 +41,7 @@ class DLLExport FieldDataToMetadata
     : public std::binary_function<vtkFieldData *, std::string, std::string> {
 public:
   /// Act as Functor.
-  std::string operator()(vtkFieldData *fieldData, std::string id) const;
+  std::string operator()(vtkFieldData *fieldData, const std::string &id) const;
 
   /// Explicit call to Functor execution.
   std::string execute(vtkFieldData *fieldData, const std::string &id) const;
diff --git a/Vates/VatesAPI/inc/MantidVatesAPI/IMDDimensionComparitor.h b/Vates/VatesAPI/inc/MantidVatesAPI/IMDDimensionComparitor.h
index b93a6371aac036b7e42f43b8213a8fe3169856d9..b22ab7dd6c1d08a739dc3a5a0bba77e67ec83199 100644
--- a/Vates/VatesAPI/inc/MantidVatesAPI/IMDDimensionComparitor.h
+++ b/Vates/VatesAPI/inc/MantidVatesAPI/IMDDimensionComparitor.h
@@ -1,7 +1,9 @@
 #ifndef IMD_DIMENSION_COMPARITOR_H
 #define IMD_DIMENSION_COMPARITOR_H
 
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/IMDWorkspace.h"
+#include "MantidGeometry/MDGeometry/IMDDimension.h"
 
 namespace Mantid {
 namespace VATES {
@@ -43,13 +45,13 @@ public:
   /// Destructor
   ~IMDDimensionComparitor();
 
-  bool isXDimension(Mantid::Geometry::IMDDimension_const_sptr queryDimension);
+  bool isXDimension(const Mantid::Geometry::IMDDimension &queryDimension);
 
-  bool isYDimension(Mantid::Geometry::IMDDimension_const_sptr queryDimension);
+  bool isYDimension(const Mantid::Geometry::IMDDimension &queryDimension);
 
-  bool isZDimension(Mantid::Geometry::IMDDimension_const_sptr queryDimension);
+  bool isZDimension(const Mantid::Geometry::IMDDimension &queryDimension);
 
-  bool istDimension(Mantid::Geometry::IMDDimension_const_sptr queryDimension);
+  bool istDimension(const Mantid::Geometry::IMDDimension &queryDimension);
 
 private:
   /// imd workspace shared ptr.
diff --git a/Vates/VatesAPI/inc/MantidVatesAPI/IgnoreZerosThresholdRange.h b/Vates/VatesAPI/inc/MantidVatesAPI/IgnoreZerosThresholdRange.h
deleted file mode 100644
index 2b556e3b4d27e0380c97e5c0c471bb6755a8e7af..0000000000000000000000000000000000000000
--- a/Vates/VatesAPI/inc/MantidVatesAPI/IgnoreZerosThresholdRange.h
+++ /dev/null
@@ -1,64 +0,0 @@
-#ifndef MANTID_PARAVIEW_IGNORE_ZEROS_THRESHOLD_RANGE
-#define MANTID_PARAVIEW_IGNORE_ZEROS_THRESHOLD_RANGE
-
-#include "MantidKernel/System.h"
-#include "MantidVatesAPI/ThresholdRange.h"
-/** Set range selection to cut-out zeros.
-
- @author Owen Arnold, Tessella plc
- @date 07/07/2011
-
- Copyright &copy; 2010 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>
- */
-
-namespace Mantid {
-namespace VATES {
-class DLLExport IgnoreZerosThresholdRange : public ThresholdRange {
-
-public:
-  IgnoreZerosThresholdRange(signal_t min, signal_t max);
-
-  IgnoreZerosThresholdRange();
-
-  void calculate() override;
-
-  signal_t getMinimum() const override;
-
-  signal_t getMaximum() const override;
-
-  ~IgnoreZerosThresholdRange() override;
-
-  bool hasCalculated() const override;
-
-  IgnoreZerosThresholdRange *clone() const override;
-
-  bool inRange(const signal_t &signal) override;
-
-private:
-  signal_t m_min;
-
-  signal_t m_max;
-};
-}
-}
-
-#endif
\ No newline at end of file
diff --git a/Vates/VatesAPI/inc/MantidVatesAPI/MDEWEventNexusLoadingPresenter.h b/Vates/VatesAPI/inc/MantidVatesAPI/MDEWEventNexusLoadingPresenter.h
index dff9d3941cf6dbb98ec978bf5ac1a51c5a443119..66ea5eebd78561b3792d17c5dca9959469907837 100644
--- a/Vates/VatesAPI/inc/MantidVatesAPI/MDEWEventNexusLoadingPresenter.h
+++ b/Vates/VatesAPI/inc/MantidVatesAPI/MDEWEventNexusLoadingPresenter.h
@@ -37,7 +37,7 @@ class MDLoadingView;
 class DLLExport MDEWEventNexusLoadingPresenter : public MDEWLoadingPresenter {
 public:
   MDEWEventNexusLoadingPresenter(std::unique_ptr<MDLoadingView> view,
-                                 const std::string fileName);
+                                 const std::string &fileName);
   vtkSmartPointer<vtkDataSet>
   execute(vtkDataSetFactory *factory, ProgressAction &rebinningProgressUpdate,
           ProgressAction &drawingProgressUpdate) override;
diff --git a/Vates/VatesAPI/inc/MantidVatesAPI/MDHWNexusLoadingPresenter.h b/Vates/VatesAPI/inc/MantidVatesAPI/MDHWNexusLoadingPresenter.h
index 52f89d5de2268c5af542a62ef376d1392e3076f1..70749725770082db426f8553f6e3c104698d20ea 100644
--- a/Vates/VatesAPI/inc/MantidVatesAPI/MDHWNexusLoadingPresenter.h
+++ b/Vates/VatesAPI/inc/MantidVatesAPI/MDHWNexusLoadingPresenter.h
@@ -38,7 +38,7 @@ class MDLoadingView;
 class DLLExport MDHWNexusLoadingPresenter : public MDHWLoadingPresenter {
 public:
   MDHWNexusLoadingPresenter(std::unique_ptr<MDLoadingView> view,
-                            const std::string fileName);
+                            const std::string &fileName);
   vtkSmartPointer<vtkDataSet>
   execute(vtkDataSetFactory *factory, ProgressAction &rebinningProgressUpdate,
           ProgressAction &drawingProgressUpdate) override;
diff --git a/Vates/VatesAPI/inc/MantidVatesAPI/MDLoadingPresenter.h b/Vates/VatesAPI/inc/MantidVatesAPI/MDLoadingPresenter.h
index 5fafd8b5a6130a982af54b753a38faa953d352b3..4c783473bc73315c119886fdfede5389644d1985 100644
--- a/Vates/VatesAPI/inc/MantidVatesAPI/MDLoadingPresenter.h
+++ b/Vates/VatesAPI/inc/MantidVatesAPI/MDLoadingPresenter.h
@@ -57,7 +57,8 @@ public:
   virtual void setDefaultCOBandBoundaries(vtkDataSet *visualDataSet);
   virtual void makeNonOrthogonal(
       vtkDataSet *visualDataSet,
-      std::unique_ptr<Mantid::VATES::WorkspaceProvider> workspaceProvider);
+      std::unique_ptr<Mantid::VATES::WorkspaceProvider> workspaceProvider,
+      ProgressAction *progress);
   virtual bool canReadFile() const = 0;
   virtual const std::string &getGeometryXML() const = 0;
   virtual ~MDLoadingPresenter() {}
diff --git a/Vates/VatesAPI/inc/MantidVatesAPI/MedianAndBelowThresholdRange.h b/Vates/VatesAPI/inc/MantidVatesAPI/MedianAndBelowThresholdRange.h
deleted file mode 100644
index 4ce4577975aed87178deaedc7ffcaf1d480d3b62..0000000000000000000000000000000000000000
--- a/Vates/VatesAPI/inc/MantidVatesAPI/MedianAndBelowThresholdRange.h
+++ /dev/null
@@ -1,74 +0,0 @@
-#ifndef MANTID_PARAVIEW_MEDIAN_AND_BELOW_THRESHOLD_RANGE
-#define MANTID_PARAVIEW_MEDIAN_AND_BELOW_THRESHOLD_RANGE
-
-#include "MantidKernel/System.h"
-#include "MantidVatesAPI/ThresholdRange.h"
-#include "MantidAPI/IMDWorkspace.h"
-
-/** Set range selection to cut-out zeros and provide an upper limit equal to the
- median value in the workspace.
-
- @author Owen Arnold, Tessella plc
- @date 07/07/2011
-
- Copyright &copy; 2010 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>
- */
-
-namespace Mantid {
-namespace VATES {
-class DLLExport MedianAndBelowThresholdRange : public ThresholdRange {
-
-public:
-  MedianAndBelowThresholdRange();
-
-  void calculate() override;
-
-  signal_t getMinimum() const override;
-
-  signal_t getMaximum() const override;
-
-  ~MedianAndBelowThresholdRange() override;
-
-  bool hasCalculated() const override;
-
-  MedianAndBelowThresholdRange *clone() const override;
-
-  bool inRange(const signal_t &signal) override;
-
-  void setWorkspace(Mantid::API::Workspace_sptr workspace) override;
-
-private:
-  MedianAndBelowThresholdRange(signal_t min, signal_t max, bool isCalculated,
-                               Mantid::API::IMDWorkspace_sptr m_workspace);
-
-  signal_t m_min;
-
-  signal_t m_max;
-
-  bool m_isCalculated;
-
-  Mantid::API::IMDWorkspace_sptr m_workspace;
-};
-}
-}
-
-#endif
\ No newline at end of file
diff --git a/Vates/VatesAPI/inc/MantidVatesAPI/MetaDataExtractorUtils.h b/Vates/VatesAPI/inc/MantidVatesAPI/MetaDataExtractorUtils.h
index 124d6deb36531b46bf4f21950e0f5f5ae4e85fd1..fb99f28721a6dbce85d43427a7ff5ffa10aeff54 100644
--- a/Vates/VatesAPI/inc/MantidVatesAPI/MetaDataExtractorUtils.h
+++ b/Vates/VatesAPI/inc/MantidVatesAPI/MetaDataExtractorUtils.h
@@ -47,14 +47,14 @@ public:
     * @param workspace A pointer to the workspace
     * @returns A pair of minimum and maximum values.
     */
-  QwtDoubleInterval getMinAndMax(Mantid::API::IMDWorkspace_sptr workspace);
+  QwtDoubleInterval getMinAndMax(const Mantid::API::IMDWorkspace *workspace);
 
   /**
     * Extracts the instrument from the workspace.
     * @param workspace A pointer to a workspace.
     * @returns The instrument.
     */
-  std::string extractInstrument(Mantid::API::IMDWorkspace_sptr workspace);
+  std::string extractInstrument(const Mantid::API::IMDWorkspace *workspace);
 
 private:
   /**
@@ -69,4 +69,4 @@ private:
 };
 }
 }
-#endif
\ No newline at end of file
+#endif
diff --git a/Vates/VatesAPI/inc/MantidVatesAPI/MetadataJsonManager.h b/Vates/VatesAPI/inc/MantidVatesAPI/MetadataJsonManager.h
index baf689d60f8bc781ded8b7021afb8e0b60f4702c..40adb76d91758bd193f07c9c1eff44855cbc69d4 100644
--- a/Vates/VatesAPI/inc/MantidVatesAPI/MetadataJsonManager.h
+++ b/Vates/VatesAPI/inc/MantidVatesAPI/MetadataJsonManager.h
@@ -43,9 +43,9 @@ public:
 
   std::string getSerializedJson();
 
-  void readInSerializedJson(std::string serializedJson);
+  void readInSerializedJson(const std::string &serializedJson);
 
-  void setInstrument(std::string instrument);
+  void setInstrument(const std::string &instrument);
   std::string &getInstrument();
 
   void setMinValue(double minValue);
diff --git a/Vates/VatesAPI/inc/MantidVatesAPI/MetadataToFieldData.h b/Vates/VatesAPI/inc/MantidVatesAPI/MetadataToFieldData.h
index 000b95d025f7922fe12d8edaa64973fd750c6066..ee36241b6d52b81d3233731846105e97c3b5c2ca 100644
--- a/Vates/VatesAPI/inc/MantidVatesAPI/MetadataToFieldData.h
+++ b/Vates/VatesAPI/inc/MantidVatesAPI/MetadataToFieldData.h
@@ -39,12 +39,12 @@ namespace VATES {
 class DLLExport MetadataToFieldData {
 public:
   /// Act as Functor.
-  void operator()(vtkFieldData *fieldData, std::string metaData,
-                  std::string id) const;
+  void operator()(vtkFieldData *fieldData, const std::string &metaData,
+                  const std::string &id) const;
 
   /// Explicit call to Functor execution.
-  void execute(vtkFieldData *fieldData, std::string metaData,
-               std::string id) const;
+  void execute(vtkFieldData *fieldData, const std::string &metaData,
+               const std::string &id) const;
 };
 }
 }
diff --git a/Vates/VatesAPI/inc/MantidVatesAPI/NoThresholdRange.h b/Vates/VatesAPI/inc/MantidVatesAPI/NoThresholdRange.h
deleted file mode 100644
index cd308bfaec09625f1280b5fb8fd1fb23e2ef3e27..0000000000000000000000000000000000000000
--- a/Vates/VatesAPI/inc/MantidVatesAPI/NoThresholdRange.h
+++ /dev/null
@@ -1,64 +0,0 @@
-#ifndef MANTID_PARAVIEW_NO_THRESHOLD_RANGE
-#define MANTID_PARAVIEW_NO_THRESHOLD_RANGE
-
-#include "MantidKernel/System.h"
-#include "MantidVatesAPI/ThresholdRange.h"
-/** Does not constrain to any range.
-
- @author Owen Arnold, Tessella plc
- @date 07/07/2011
-
- Copyright &copy; 2010 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>
- */
-
-namespace Mantid {
-namespace VATES {
-class DLLExport NoThresholdRange : public ThresholdRange {
-
-public:
-  NoThresholdRange();
-
-  void calculate() override;
-
-  signal_t getMinimum() const override;
-
-  signal_t getMaximum() const override;
-
-  ~NoThresholdRange() override;
-
-  bool hasCalculated() const override;
-
-  NoThresholdRange *clone() const override;
-
-  bool inRange(const signal_t &signal) override;
-
-private:
-  NoThresholdRange(signal_t min, signal_t max);
-
-  signal_t m_min;
-
-  signal_t m_max;
-};
-}
-}
-
-#endif
\ No newline at end of file
diff --git a/Vates/VatesAPI/inc/MantidVatesAPI/PresenterFactories.h b/Vates/VatesAPI/inc/MantidVatesAPI/PresenterFactories.h
index bce7458c72757b22e6dbdf380fe6ec2ee2dae2be..9b26b0b4fb14b665db5f33298a10cabc96e7400c 100644
--- a/Vates/VatesAPI/inc/MantidVatesAPI/PresenterFactories.h
+++ b/Vates/VatesAPI/inc/MantidVatesAPI/PresenterFactories.h
@@ -13,15 +13,15 @@ class WorkspaceProvider;
 
 class DLLExport EmptyWorkspaceNamePolicy {
 protected:
-  std::string getWorkspaceName(Mantid::API::IMDWorkspace_sptr) {
-    return "__EmptyWorkspaceNamePolicy";
-  }
+  const std::string &
+  getWorkspaceName(const Mantid::API::IMDWorkspace & /*workspace*/);
 };
 
 class DLLExport NonEmptyWorkspaceNamePolicy {
 protected:
-  std::string getWorkspaceName(Mantid::API::IMDWorkspace_sptr workspace) {
-    return workspace->name();
+  const std::string &
+  getWorkspaceName(const Mantid::API::IMDWorkspace &workspace) {
+    return workspace.getName();
   }
 };
 
@@ -43,7 +43,7 @@ public:
          std::unique_ptr<WorkspaceProvider> workspaceProvider) {
     return Mantid::Kernel::make_unique<Presenter>(std::move(view),
                                                   workspaceProvider.release(),
-                                                  getWorkspaceName(workspace));
+                                                  getWorkspaceName(*workspace));
   }
 };
 }
diff --git a/Vates/VatesAPI/inc/MantidVatesAPI/SQWLoadingPresenter.h b/Vates/VatesAPI/inc/MantidVatesAPI/SQWLoadingPresenter.h
index ead0a17c1e0450cce3387764c1c369d1779869d5..1e189152ccd1fb2edd7b73fb850ac73337361575 100644
--- a/Vates/VatesAPI/inc/MantidVatesAPI/SQWLoadingPresenter.h
+++ b/Vates/VatesAPI/inc/MantidVatesAPI/SQWLoadingPresenter.h
@@ -36,7 +36,7 @@ class MDLoadingView;
 class DLLExport SQWLoadingPresenter : public MDEWLoadingPresenter {
 public:
   SQWLoadingPresenter(std::unique_ptr<MDLoadingView> view,
-                      const std::string fileName);
+                      const std::string &fileName);
   vtkSmartPointer<vtkDataSet>
   execute(vtkDataSetFactory *factory, ProgressAction &rebinningProgressUpdate,
           ProgressAction &drawingProgressUpdate) override;
diff --git a/Vates/VatesAPI/inc/MantidVatesAPI/SaveMDWorkspaceToVTKImpl.h b/Vates/VatesAPI/inc/MantidVatesAPI/SaveMDWorkspaceToVTKImpl.h
index 2a9210ac47a8c5c3e22adeb83159ec90315f2818..646a063cf035765ff7b25defe319584d5d32b055 100644
--- a/Vates/VatesAPI/inc/MantidVatesAPI/SaveMDWorkspaceToVTKImpl.h
+++ b/Vates/VatesAPI/inc/MantidVatesAPI/SaveMDWorkspaceToVTKImpl.h
@@ -2,9 +2,10 @@
 #define VATES_API_SAVE_MD_WORKSPACE_TO_VTK_IMPL_H_
 
 #include "MantidAPI/IMDWorkspace.h"
+#include "MantidAPI/Progress.h"
 #include "MantidKernel/System.h"
 #include "MantidVatesAPI/Normalization.h"
-#include "MantidVatesAPI/ThresholdRange.h"
+#include "MantidVatesAPI/SaveMDWorkspaceToVTK.h"
 
 #include <map>
 #include <vtkSmartPointer.h>
@@ -44,12 +45,11 @@ Code Documentation is available at: <http://doxygen.mantidproject.org>
 */
 class DLLExport SaveMDWorkspaceToVTKImpl {
 public:
-  SaveMDWorkspaceToVTKImpl();
+  SaveMDWorkspaceToVTKImpl(SaveMDWorkspaceToVTK *parent = nullptr);
   ~SaveMDWorkspaceToVTKImpl() {}
-  void saveMDWorkspace(Mantid::API::IMDWorkspace_sptr workspace,
+  void saveMDWorkspace(const Mantid::API::IMDWorkspace_sptr &workspace,
                        const std::string &filename,
-                       VisualNormalization normalization,
-                       ThresholdRange_scptr thresholdRange, int recursionDepth,
+                       VisualNormalization normalization, int recursionDepth,
                        const std::string &compressorType) const;
 
   const static std::string structuredGridExtension;
@@ -57,24 +57,19 @@ public:
 
   std::vector<std::string>
   getAllowedNormalizationsInStringRepresentation() const;
-  std::vector<std::string> getAllowedThresholdsInStringRepresentation() const;
   VisualNormalization
-  translateStringToVisualNormalization(const std::string normalization) const;
-  ThresholdRange_scptr
-  translateStringToThresholdRange(const std::string thresholdRange) const;
-
-  bool is3DWorkspace(Mantid::API::IMDWorkspace_sptr workspace) const;
+  translateStringToVisualNormalization(const std::string &normalization) const;
+  bool is3DWorkspace(const Mantid::API::IMDWorkspace &workspace) const;
 
 private:
+  mutable API::Progress m_progress;
   std::map<std::string, VisualNormalization> m_normalizations;
-  std::vector<std::string> m_thresholds;
-
   void setupMembers();
-  bool is4DWorkspace(Mantid::API::IMDWorkspace_sptr workspace) const;
+  bool is4DWorkspace(const Mantid::API::IMDWorkspace &workspace) const;
   int writeDataSetToVTKFile(vtkXMLWriter *writer, vtkDataSet *dataSet,
                             const std::string &filename,
                             vtkXMLWriter::CompressorType compressor) const;
-  double selectTimeSliceValue(Mantid::API::IMDWorkspace_sptr workspace) const;
+  double selectTimeSliceValue(const Mantid::API::IMDWorkspace &workspace) const;
   std::string getFullFilename(std::string filename,
                               bool isHistoWorkspace) const;
   vtkSmartPointer<vtkXMLWriter> getXMLWriter(bool isHistoWorkspace) const;
@@ -83,7 +78,6 @@ private:
       Mantid::API::IMDWorkspace_sptr workspace, bool isHistoWorkspace) const;
   std::unique_ptr<vtkDataSetFactory>
   getDataSetFactoryChain(bool isHistWorkspace,
-                         ThresholdRange_scptr thresholdRange,
                          VisualNormalization normalization, double time) const;
   std::unique_ptr<MDLoadingPresenter>
   getPresenter(bool isHistoWorkspace, Mantid::API::IMDWorkspace_sptr workspace,
diff --git a/Vates/VatesAPI/inc/MantidVatesAPI/ThresholdRange.h b/Vates/VatesAPI/inc/MantidVatesAPI/ThresholdRange.h
deleted file mode 100644
index 9729ca81df2d5e733aa7c9383d62de6e5bbd3e78..0000000000000000000000000000000000000000
--- a/Vates/VatesAPI/inc/MantidVatesAPI/ThresholdRange.h
+++ /dev/null
@@ -1,72 +0,0 @@
-#ifndef MANTID_PARAVIEW_THRESHOLD_RANGE
-#define MANTID_PARAVIEW_THRESHOLD_RANGE
-
-#include <boost/shared_ptr.hpp>
-#include "MantidKernel/System.h"
-#include "MantidGeometry/MDGeometry/MDTypes.h"
-#include "MantidAPI/Workspace_fwd.h"
-
-/** Abstract type promises to supply a minimum and maximum set of threshold
- range values.
-
- @author Owen Arnold, Tessella plc
- @date 30/06/2011
-
- Copyright &copy; 2010 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>
- */
-
-namespace Mantid {
-namespace VATES {
-class DLLExport ThresholdRange {
-
-public:
-  /// Calculate the threshold range.
-  virtual void calculate() = 0;
-
-  /// Getter for the has executed status.
-  virtual bool hasCalculated() const = 0;
-
-  /// Fetch the threshold range.
-  virtual signal_t getMinimum() const = 0;
-
-  /// Fetch the threshold range minimum.
-  virtual signal_t getMaximum() const = 0;
-
-  /// Virtual constructor method.
-  virtual ThresholdRange *clone() const = 0;
-
-  /// Determine wheter the given value is within the range.
-  virtual bool inRange(const signal_t &signal) = 0;
-
-  /// Destructor
-  virtual ~ThresholdRange() {}
-
-  /// Interface allows the threshold range to accept a workspace.
-  virtual void setWorkspace(Mantid::API::Workspace_sptr) {}
-};
-
-/// ThresholdRange as a scoped pointer.
-typedef boost::shared_ptr<ThresholdRange> ThresholdRange_scptr;
-}
-}
-
-#endif
diff --git a/Vates/VatesAPI/inc/MantidVatesAPI/UserDefinedThresholdRange.h b/Vates/VatesAPI/inc/MantidVatesAPI/UserDefinedThresholdRange.h
deleted file mode 100644
index 76a4b70cbf33fc4c8d956c4be1de763602baa113..0000000000000000000000000000000000000000
--- a/Vates/VatesAPI/inc/MantidVatesAPI/UserDefinedThresholdRange.h
+++ /dev/null
@@ -1,62 +0,0 @@
-#ifndef MANTID_PARAVIEW_USER_DEFINED_THRESHOLD_RANGE
-#define MANTID_PARAVIEW_USER_DEFINED_THRESHOLD_RANGE
-
-#include "MantidKernel/System.h"
-#include "MantidVatesAPI/ThresholdRange.h"
-/** Stores range values specified by the user.
-
- @author Owen Arnold, Tessella plc
- @date 30/06/2011
-
- Copyright &copy; 2010 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>
- */
-
-namespace Mantid {
-namespace VATES {
-class DLLExport UserDefinedThresholdRange : public ThresholdRange {
-
-public:
-  UserDefinedThresholdRange(signal_t min, signal_t max);
-
-  void calculate() override;
-
-  signal_t getMinimum() const override;
-
-  signal_t getMaximum() const override;
-
-  ~UserDefinedThresholdRange() override;
-
-  bool hasCalculated() const override;
-
-  UserDefinedThresholdRange *clone() const override;
-
-  bool inRange(const signal_t &signal) override;
-
-private:
-  const signal_t m_min;
-
-  const signal_t m_max;
-};
-}
-}
-
-#endif
diff --git a/Vates/VatesAPI/inc/MantidVatesAPI/VatesKnowledgeSerializer.h b/Vates/VatesAPI/inc/MantidVatesAPI/VatesKnowledgeSerializer.h
index c23f4c6d099679e6d4a361f829435e598bd65618..e9662039610b3e26fedd9e2b3e72b3c598b72284 100644
--- a/Vates/VatesAPI/inc/MantidVatesAPI/VatesKnowledgeSerializer.h
+++ b/Vates/VatesAPI/inc/MantidVatesAPI/VatesKnowledgeSerializer.h
@@ -1,6 +1,7 @@
 #ifndef VATES_KNOWLEDGE_SERIALIZER_H
 #define VATES_KNOWLEDGE_SERIALIZER_H
 
+#include "MantidKernel/System.h"
 #include <boost/shared_ptr.hpp>
 #include <string>
 
@@ -70,14 +71,13 @@ public:
       boost::shared_ptr<const Mantid::Geometry::MDImplicitFunction> spFunction);
 
   /// Set the workspace name to apply.
-  void
-  setWorkspace(boost::shared_ptr<const Mantid::API::IMDWorkspace> workspace);
+  void setWorkspace(const Mantid::API::IMDWorkspace &workspace);
 
   /// Set the workspace name to apply.
-  void setWorkspaceName(std::string wsName);
+  void setWorkspaceName(const std::string &wsName);
 
   /// Set the geometry xml to apply.
-  void setGeometryXML(std::string geomXML);
+  void setGeometryXML(const std::string &geomXML);
 
   /// Create the xml string correponding to the set values.
   std::string createXMLString() const;
diff --git a/Vates/VatesAPI/inc/MantidVatesAPI/ViewFrustum.h b/Vates/VatesAPI/inc/MantidVatesAPI/ViewFrustum.h
index 682fe0c221f6d7df446f0f76090b61aaa6c65175..7c1cbb085de4302297f98e0c331631a8b3bcadbd 100644
--- a/Vates/VatesAPI/inc/MantidVatesAPI/ViewFrustum.h
+++ b/Vates/VatesAPI/inc/MantidVatesAPI/ViewFrustum.h
@@ -56,9 +56,9 @@ typedef FrustumPlane<NEARPLANE, double> NearPlane;
 
 class DLLExport ViewFrustum {
 public:
-  ViewFrustum(const LeftPlane leftPlane, const RightPlane rightPlane,
-              const BottomPlane bottomPlane, const TopPlane topPlane,
-              const FarPlane farPlane, const NearPlane nearPlane);
+  ViewFrustum(const LeftPlane &leftPlane, const RightPlane &rightPlane,
+              const BottomPlane &bottomPlane, const TopPlane &topPlane,
+              const FarPlane &farPlane, const NearPlane &nearPlane);
   ViewFrustum(const ViewFrustum &other);
   ~ViewFrustum();
   ViewFrustum &operator=(const ViewFrustum &other);
diff --git a/Vates/VatesAPI/inc/MantidVatesAPI/vtkDataSetFactory.h b/Vates/VatesAPI/inc/MantidVatesAPI/vtkDataSetFactory.h
index ef0097126e0bf259430153981911ff6792764aab..de95431d72b3eae8c5afcd31e2789d4ce9261932 100644
--- a/Vates/VatesAPI/inc/MantidVatesAPI/vtkDataSetFactory.h
+++ b/Vates/VatesAPI/inc/MantidVatesAPI/vtkDataSetFactory.h
@@ -70,7 +70,7 @@ public:
   virtual vtkSmartPointer<vtkDataSet> create(ProgressAction &) const = 0;
 
   /// Initalize with a target workspace.
-  virtual void initialize(Mantid::API::Workspace_sptr) = 0;
+  virtual void initialize(const Mantid::API::Workspace_sptr &workspace) = 0;
 
   /// Create the product in one step.
   virtual vtkSmartPointer<vtkDataSet> oneStepCreate(Mantid::API::Workspace_sptr,
@@ -115,29 +115,19 @@ public:
 
 protected:
   /**
-  Try to cast it to the specified IMDType and then run checks based on the
-  non-integrated dimensionality.
-  The latter checks are only run if the factory is set to apply these checks.
-  @param  workspace : workspace to cast.
-  @param  bExactMatch : run an exact match on non-integarated dimensionality if
-  TRUE, otherwise is less than or equal to ExpectedDimensions.
-  @return  correctly cast shared pointer or an empty shared pointer if cast or
-  checks fail.
-  */
+   Run checks based on the non-integrated dimensionality, which are only run
+   if the factory is set to apply these checks.
+   @param  imdws : workspace to check.
+   @param  bExactMatch : run an exact match on non-integarated dimensionality if
+   TRUE, otherwise is less than or equal to ExpectedDimensions.
+   @return whether the checks pass or fail.
+   */
   template <typename IMDWorkspaceType, size_t ExpectedNDimensions>
-  boost::shared_ptr<IMDWorkspaceType>
-  castAndCheck(Mantid::API::Workspace_sptr workspace,
-               bool bExactMatch = true) const {
-    boost::shared_ptr<IMDWorkspaceType> temp;
-    boost::shared_ptr<IMDWorkspaceType> imdws =
-        boost::dynamic_pointer_cast<IMDWorkspaceType>(workspace);
-    if (!imdws) {
-      // Abort as imdws cannot be dynamically cast to the target type.
-      return temp;
-    }
+  bool checkWorkspace(const IMDWorkspaceType &imdws,
+                      bool bExactMatch = true) const {
     bool bPassesDimensionalityCheck = false;
     size_t actualNonIntegratedDimensionality =
-        imdws->getNonIntegratedDimensions().size();
+        imdws.getNonIntegratedDimensions().size();
     if (bExactMatch) {
       bPassesDimensionalityCheck =
           (ExpectedNDimensions == actualNonIntegratedDimensionality);
@@ -148,13 +138,40 @@ protected:
     if (this->doesCheckDimensionality() && !bPassesDimensionalityCheck) {
       // Abort as there are dimensionality checks to be applied and these checks
       // fail.
-      return temp;
+      return false;
+    }
+    return true;
+  }
+
+  /**
+   Try to cast it to the specified IMDType and then run checks based on the
+   non-integrated dimensionality.
+   The latter checks are only run if the factory is set to apply these checks.
+   @param  workspace : workspace to cast.
+   @param  bExactMatch : run an exact match on non-integarated dimensionality if
+   TRUE, otherwise is less than or equal to ExpectedDimensions.
+   @return  correctly cast shared pointer or an empty shared pointer if cast or
+   checks fail.
+   */
+  template <typename IMDWorkspaceType, size_t ExpectedNDimensions>
+  boost::shared_ptr<IMDWorkspaceType>
+  castAndCheck(Mantid::API::Workspace_sptr workspace,
+               bool bExactMatch = true) const {
+    boost::shared_ptr<IMDWorkspaceType> imdws =
+        boost::dynamic_pointer_cast<IMDWorkspaceType>(workspace);
+    if (imdws &&
+        this->checkWorkspace<IMDWorkspaceType, ExpectedNDimensions>(
+            *imdws, bExactMatch)) {
+      return imdws;
+    } else {
+      // Abort as imdws cannot be dynamically cast to the target type.
+      return nullptr;
     }
-    return imdws;
   }
 
   /**
-  Common initialization implementation. Most vtkDataSets will need this in order
+  Common initialization implementation. Most vtkDataSets will need this in
+  order
   to correctly delegate initialization onto successors.
   @param workspace : workspace to cast.
   @param bExactMatch : run an exact match on non-integarated dimensionality if
@@ -166,7 +183,7 @@ protected:
   boost::shared_ptr<IMDWorkspaceType>
   doInitialize(Mantid::API::Workspace_sptr workspace,
                bool bExactMatch = true) const {
-    if (workspace == NULL) {
+    if (!workspace) {
       std::string message = this->getFactoryTypeName() +
                             " initialize cannot operate on a null workspace";
       throw std::invalid_argument(message);
@@ -187,13 +204,15 @@ protected:
   }
 
   /**
-  Common creation implementation whereby delegation to successor is attempted if
+  Common creation implementation whereby delegation to successor is attempted
+  if
   appropriate.
   @param workspace : workspace to cast and create from.
   @param progressUpdate : object used to pass progress information back up the
   stack.
   @param bExactMatch : Check for an exact match if true.
-  @return TRUE if delegation to successors has occured. Otherwise returns false.
+  @return TRUE if delegation to successors has occured. Otherwise returns
+  false.
   */
   template <typename IMDWorkspaceType, size_t ExpectedNDimensions>
   vtkSmartPointer<vtkDataSet>
diff --git a/Vates/VatesAPI/inc/MantidVatesAPI/vtkDataSetToNonOrthogonalDataSet.h b/Vates/VatesAPI/inc/MantidVatesAPI/vtkDataSetToNonOrthogonalDataSet.h
index 908dfacf9d25fafc958933c1b83d4b881c1fe7b1..fc7a859d280f6e842aeaf6f8a43d45ec4be4b10b 100644
--- a/Vates/VatesAPI/inc/MantidVatesAPI/vtkDataSetToNonOrthogonalDataSet.h
+++ b/Vates/VatesAPI/inc/MantidVatesAPI/vtkDataSetToNonOrthogonalDataSet.h
@@ -1,13 +1,14 @@
 #ifndef MANTID_VATES_VTKDATASETTONONORTHOGONALDATASET_H_
 #define MANTID_VATES_VTKDATASETTONONORTHOGONALDATASET_H_
 
-#include "MantidVatesAPI/WorkspaceProvider.h"
+#include "MantidGeometry/MDGeometry/MDTypes.h"
+#include "MantidKernel/Matrix.h"
 #include "MantidKernel/SpecialCoordinateSystem.h"
 #include "MantidKernel/System.h"
-#include "MantidKernel/cow_ptr.h"
-#include "MantidKernel/Matrix.h"
 #include "MantidKernel/V3D.h"
-#include "MantidGeometry/MDGeometry/MDTypes.h"
+#include "MantidKernel/cow_ptr.h"
+#include "MantidVatesAPI/ProgressAction.h"
+#include "MantidVatesAPI/WorkspaceProvider.h"
 
 #include <string>
 #include <array>
@@ -58,7 +59,7 @@ public:
       vtkDataSet *dataset, std::string name,
       std::unique_ptr<Mantid::VATES::WorkspaceProvider> workspaceProvider);
   /// Class execution method
-  void execute();
+  void execute(ProgressAction *progress = nullptr);
   /// Destructor
   virtual ~vtkDataSetToNonOrthogonalDataSet();
 
diff --git a/Vates/VatesAPI/inc/MantidVatesAPI/vtkDataSetToScaledDataSet.h b/Vates/VatesAPI/inc/MantidVatesAPI/vtkDataSetToScaledDataSet.h
index d5fbef969f7abbd40fd4c7fbf31c107503887e13..5c0b38494cf2fe7279e9c29fb2f3d596b54530a4 100644
--- a/Vates/VatesAPI/inc/MantidVatesAPI/vtkDataSetToScaledDataSet.h
+++ b/Vates/VatesAPI/inc/MantidVatesAPI/vtkDataSetToScaledDataSet.h
@@ -46,7 +46,8 @@ public:
                        vtkPointSet *inputData, vtkInformation *info);
   /// Apply the scaling and add metadata
   vtkPointSet *execute(double xScale, double yScale, double zScale,
-                       vtkPointSet *inputData, vtkPointSet *outputData = NULL);
+                       vtkPointSet *inputData,
+                       vtkPointSet *outputData = nullptr);
 
 private:
   vtkDataSetToScaledDataSet &operator=(const vtkDataSetToScaledDataSet &other);
diff --git a/Vates/VatesAPI/inc/MantidVatesAPI/vtkMD0DFactory.h b/Vates/VatesAPI/inc/MantidVatesAPI/vtkMD0DFactory.h
index 038b5b324b7cf216069f93adbfbd7c1c83cd8c84..d8542d1899cf5daa771354ca182ec56c0d39cbd9 100644
--- a/Vates/VatesAPI/inc/MantidVatesAPI/vtkMD0DFactory.h
+++ b/Vates/VatesAPI/inc/MantidVatesAPI/vtkMD0DFactory.h
@@ -5,7 +5,6 @@
 #include "MantidVatesAPI/vtkDataSetFactory.h"
 #include "MantidAPI/IMDWorkspace.h"
 #include "vtkUnstructuredGrid.h"
-#include "MantidVatesAPI/ThresholdRange.h"
 
 namespace Mantid {
 namespace VATES {
@@ -45,7 +44,7 @@ public:
   vtkSmartPointer<vtkDataSet>
   create(ProgressAction &progressUpdating) const override;
 
-  void initialize(Mantid::API::Workspace_sptr) override;
+  void initialize(const Mantid::API::Workspace_sptr &workspace) override;
 
   std::string getFactoryTypeName() const override { return "vtkMD0DFactory"; }
 
diff --git a/Vates/VatesAPI/inc/MantidVatesAPI/vtkMDHWSignalArray.h b/Vates/VatesAPI/inc/MantidVatesAPI/vtkMDHWSignalArray.h
index 9892284002833579869ec109a0c08ecc73e54d08..7162a9d204561c3a02bd93e7bec1d6d9af033725 100644
--- a/Vates/VatesAPI/inc/MantidVatesAPI/vtkMDHWSignalArray.h
+++ b/Vates/VatesAPI/inc/MantidVatesAPI/vtkMDHWSignalArray.h
@@ -30,7 +30,8 @@
 #include "vtkVariant.h"
 #include "vtkVariantCast.h"
 
-#include "MantidDataObjects/MDHistoWorkspaceIterator.h"
+#include "MantidDataObjects/MDHistoWorkspace.h"
+#include "MantidVatesAPI/Normalization.h"
 
 namespace Mantid {
 namespace VATES {
@@ -46,9 +47,8 @@ public:
   // clang-format on
   void PrintSelf(ostream &os, vtkIndent indent) override;
 
-  void InitializeArray(
-      std::unique_ptr<Mantid::DataObjects::MDHistoWorkspaceIterator> iterator,
-      std::size_t offset, vtkIdType size);
+  void InitializeArray(Mantid::DataObjects::MDHistoWorkspace *ws,
+                       VisualNormalization normalization, std::size_t offset);
 
   // Reimplemented virtuals -- see superclasses for descriptions:
   void Initialize() override;
@@ -116,7 +116,8 @@ private:
   void operator=(const vtkMDHWSignalArray &);     // Not implemented.
 
   std::size_t m_offset;
-  std::unique_ptr<Mantid::DataObjects::MDHistoWorkspaceIterator> m_iterator;
+  API::MDNormalization m_normalization;
+  DataObjects::MDHistoWorkspace *m_ws;
   Scalar m_temporaryTuple[1];
 };
 
@@ -138,13 +139,25 @@ void vtkMDHWSignalArray<Scalar>::PrintSelf(ostream &os, vtkIndent indent) {
 //------------------------------------------------------------------------------
 template <class Scalar>
 void vtkMDHWSignalArray<Scalar>::InitializeArray(
-    std::unique_ptr<Mantid::DataObjects::MDHistoWorkspaceIterator> iterator,
-    std::size_t offset, vtkIdType size) {
-  this->MaxId = size - 1;
-  this->Size = size;
+    Mantid::DataObjects::MDHistoWorkspace *ws,
+    Mantid::VATES::VisualNormalization normalization, std::size_t offset) {
   this->NumberOfComponents = 1;
-  this->m_iterator = std::move(iterator);
+  this->m_ws = ws;
   this->m_offset = offset;
+
+  const auto nBinsX = m_ws->getXDimension()->getNBins();
+  const auto nBinsY = m_ws->getYDimension()->getNBins();
+  const auto nBinsZ = m_ws->getZDimension()->getNBins();
+  this->Size = nBinsX * nBinsY * nBinsZ;
+  this->MaxId = this->Size - 1;
+
+  if (normalization == AutoSelect) {
+    // enum to enum.
+    m_normalization =
+        static_cast<API::MDNormalization>(m_ws->displayNormalization());
+  } else {
+    m_normalization = static_cast<API::MDNormalization>(normalization);
+  }
 }
 
 //------------------------------------------------------------------------------
@@ -204,7 +217,7 @@ template <class Scalar> void vtkMDHWSignalArray<Scalar>::Squeeze() {
 template <class Scalar>
 vtkArrayIterator *vtkMDHWSignalArray<Scalar>::NewIterator() {
   vtkErrorMacro(<< "Not implemented.");
-  return NULL;
+  return nullptr;
 }
 
 //------------------------------------------------------------------------------
@@ -247,16 +260,14 @@ template <class Scalar> void vtkMDHWSignalArray<Scalar>::ClearLookup() {
 //------------------------------------------------------------------------------
 template <class Scalar>
 double *vtkMDHWSignalArray<Scalar>::GetTuple(vtkIdType i) {
-  m_iterator->jumpTo(m_offset + i);
-  m_temporaryTuple[0] = m_iterator->getNormalizedSignal();
+  m_temporaryTuple[0] = this->GetValue(i);
   return &m_temporaryTuple[0];
 }
 
 //------------------------------------------------------------------------------
 template <class Scalar>
 void vtkMDHWSignalArray<Scalar>::GetTuple(vtkIdType i, double *tuple) {
-  m_iterator->jumpTo(m_offset + i);
-  tuple[0] = m_iterator->getNormalizedSignal();
+  tuple[0] = this->GetValue(i);
 }
 
 //------------------------------------------------------------------------------
@@ -292,14 +303,22 @@ vtkIdType vtkMDHWSignalArray<Scalar>::Lookup(const Scalar &val,
 //------------------------------------------------------------------------------
 template <class Scalar>
 Scalar vtkMDHWSignalArray<Scalar>::GetValue(vtkIdType idx) const {
-  m_iterator->jumpTo(m_offset + idx);
-  return m_iterator->getNormalizedSignal();
+  auto pos = m_offset + idx;
+  switch (m_normalization) {
+  case API::NoNormalization:
+    return m_ws->getSignalAt(pos);
+  case API::VolumeNormalization:
+    return m_ws->getSignalAt(pos) * m_ws->getInverseVolume();
+  case API::NumEventsNormalization:
+    return m_ws->getSignalAt(pos) / m_ws->getNumEventsAt(pos);
+  }
+  // Should not reach here
+  return std::numeric_limits<signal_t>::quiet_NaN();
 }
 //------------------------------------------------------------------------------
 template <class Scalar>
 Scalar &vtkMDHWSignalArray<Scalar>::GetValueReference(vtkIdType idx) {
-  m_iterator->jumpTo(m_offset + idx);
-  m_temporaryTuple[0] = m_iterator->getNormalizedSignal();
+  m_temporaryTuple[0] = this->GetValue(idx);
   return m_temporaryTuple[0];
 }
 
@@ -307,8 +326,7 @@ Scalar &vtkMDHWSignalArray<Scalar>::GetValueReference(vtkIdType idx) {
 template <class Scalar>
 void vtkMDHWSignalArray<Scalar>::GetTypedTuple(vtkIdType tupleId,
                                                Scalar *tuple) const {
-  m_iterator->jumpTo(m_offset + tupleId);
-  tuple[0] = m_iterator->getNormalizedSignal();
+  tuple[0] = this->GetValue(tupleId);
 }
 
 //------------------------------------------------------------------------------
diff --git a/Vates/VatesAPI/inc/MantidVatesAPI/vtkMDHexFactory.h b/Vates/VatesAPI/inc/MantidVatesAPI/vtkMDHexFactory.h
index 6948a3f92013b513a5452685ffa56b10dd723291..6839b53ac8f56a9a65506af45a7327340e626e3a 100644
--- a/Vates/VatesAPI/inc/MantidVatesAPI/vtkMDHexFactory.h
+++ b/Vates/VatesAPI/inc/MantidVatesAPI/vtkMDHexFactory.h
@@ -5,7 +5,6 @@
 #include "MantidDataObjects/MDEventFactory.h"
 #include "MantidDataObjects/MDEventWorkspace.h"
 #include "MantidVatesAPI/Normalization.h"
-#include "MantidVatesAPI/ThresholdRange.h"
 #include "MantidVatesAPI/TimeToTimeStep.h"
 #include "MantidVatesAPI/vtkDataSetFactory.h"
 
@@ -58,8 +57,7 @@ class DLLExport vtkMDHexFactory : public vtkDataSetFactory {
 
 public:
   /// Constructor
-  vtkMDHexFactory(ThresholdRange_scptr thresholdRange,
-                  const VisualNormalization normalizationOption,
+  vtkMDHexFactory(const VisualNormalization normalizationOption,
                   const size_t maxDepth = 1000);
 
   /// Destructor
@@ -70,7 +68,7 @@ public:
   create(ProgressAction &progressUpdate) const override;
 
   /// Initalize with a target workspace.
-  void initialize(Mantid::API::Workspace_sptr) override;
+  void initialize(const Mantid::API::Workspace_sptr &workspace) override;
 
   /// Get the name of the type.
   std::string getFactoryTypeName() const override { return "vtkMDHexFactory"; }
@@ -81,10 +79,11 @@ public:
   void setTime(double timeStep);
 
 private:
-  coord_t getNextBinBoundary(Mantid::API::IMDEventWorkspace_sptr imdws) const;
-
   coord_t
-  getPreviousBinBoundary(Mantid::API::IMDEventWorkspace_sptr imdws) const;
+  getNextBinBoundary(const Mantid::API::IMDEventWorkspace_sptr &imdws) const;
+
+  coord_t getPreviousBinBoundary(
+      const Mantid::API::IMDEventWorkspace_sptr &imdws) const;
 
   template <typename MDE, size_t nd>
   void doCreate(typename MDEventWorkspace<MDE, nd>::sptr ws) const;
@@ -92,9 +91,6 @@ private:
   /// Template Method pattern to validate the factory before use.
   void validate() const override;
 
-  /// Threshold range strategy.
-  ThresholdRange_scptr m_thresholdRange;
-
   /// Normalization option and info.
   const VisualNormalization m_normalizationOption;
 
diff --git a/Vates/VatesAPI/inc/MantidVatesAPI/vtkMDHistoHex4DFactory.h b/Vates/VatesAPI/inc/MantidVatesAPI/vtkMDHistoHex4DFactory.h
index 894ce675cd763cab4d3a05840e7d77c0715a40e4..0ed83ee2ced646afdebda12cd3e9cd849a4d636e 100644
--- a/Vates/VatesAPI/inc/MantidVatesAPI/vtkMDHistoHex4DFactory.h
+++ b/Vates/VatesAPI/inc/MantidVatesAPI/vtkMDHistoHex4DFactory.h
@@ -32,7 +32,6 @@
 
 #include "MantidAPI/IMDWorkspace.h"
 #include "MantidVatesAPI/Normalization.h"
-#include "MantidVatesAPI/ThresholdRange.h"
 #include "MantidVatesAPI/vtkDataSetFactory.h"
 #include "MantidVatesAPI/vtkMDHistoHexFactory.h"
 #include <vtkCellData.h>
@@ -47,8 +46,7 @@ template <typename TimeMapper>
 class DLLExport vtkMDHistoHex4DFactory : public vtkMDHistoHexFactory {
 public:
   /// Constructor
-  vtkMDHistoHex4DFactory(ThresholdRange_scptr thresholdRange,
-                         const VisualNormalization normalizationOption,
+  vtkMDHistoHex4DFactory(const VisualNormalization normalizationOption,
                          const double timestep);
 
   /// Assignment operator
@@ -62,7 +60,7 @@ public:
   ~vtkMDHistoHex4DFactory() override;
 
   /// Initialize the object with a workspace.
-  void initialize(Mantid::API::Workspace_sptr workspace) override;
+  void initialize(const Mantid::API::Workspace_sptr &workspace) override;
 
   /// Factory method
   vtkSmartPointer<vtkDataSet>
diff --git a/Vates/VatesAPI/inc/MantidVatesAPI/vtkMDHistoHexFactory.h b/Vates/VatesAPI/inc/MantidVatesAPI/vtkMDHistoHexFactory.h
index f65dd27efee811866fb03f749ac539a2b1153722..e2e0f0ad0f84306cdb5b085a67aea3a5ee816a4b 100644
--- a/Vates/VatesAPI/inc/MantidVatesAPI/vtkMDHistoHexFactory.h
+++ b/Vates/VatesAPI/inc/MantidVatesAPI/vtkMDHistoHexFactory.h
@@ -33,7 +33,6 @@
 #include "MantidVatesAPI/vtkDataSetFactory.h"
 #include "MantidAPI/IMDWorkspace.h"
 #include "MantidVatesAPI/Normalization.h"
-#include "MantidVatesAPI/ThresholdRange.h"
 #include <vtkFloatArray.h>
 #include <vtkCellData.h>
 #include <vtkHexahedron.h>
@@ -45,8 +44,7 @@ namespace VATES {
 class DLLExport vtkMDHistoHexFactory : public vtkDataSetFactory {
 public:
   /// Constructor
-  vtkMDHistoHexFactory(ThresholdRange_scptr thresholdRange,
-                       const VisualNormalization normalizationOption);
+  vtkMDHistoHexFactory(const VisualNormalization normalizationOption);
 
   /// Assignment operator
   vtkMDHistoHexFactory &operator=(const vtkMDHistoHexFactory &other);
@@ -58,7 +56,7 @@ public:
   ~vtkMDHistoHexFactory() override;
 
   /// Initialize the object with a workspace.
-  void initialize(Mantid::API::Workspace_sptr workspace) override;
+  void initialize(const Mantid::API::Workspace_sptr &workspace) override;
 
   /// Factory method
   vtkSmartPointer<vtkDataSet>
@@ -83,9 +81,6 @@ protected:
 
   /// Normalization option
   VisualNormalization m_normalizationOption;
-
-  /// Threshold range.
-  mutable ThresholdRange_scptr m_thresholdRange;
 };
 }
 }
diff --git a/Vates/VatesAPI/inc/MantidVatesAPI/vtkMDHistoLineFactory.h b/Vates/VatesAPI/inc/MantidVatesAPI/vtkMDHistoLineFactory.h
index cd47ac315d7d459914cad39e59ef3c066888c4c1..3223b13f86e051e89576b04579b40b9ea4379a2d 100644
--- a/Vates/VatesAPI/inc/MantidVatesAPI/vtkMDHistoLineFactory.h
+++ b/Vates/VatesAPI/inc/MantidVatesAPI/vtkMDHistoLineFactory.h
@@ -6,7 +6,6 @@
 #include "MantidAPI/IMDWorkspace.h"
 #include "vtkUnstructuredGrid.h"
 #include "MantidVatesAPI/Normalization.h"
-#include "MantidVatesAPI/ThresholdRange.h"
 #include "MantidDataObjects/MDHistoWorkspace.h"
 #include <vtkNew.h>
 
@@ -43,8 +42,7 @@ namespace VATES {
 class DLLExport vtkMDHistoLineFactory : public vtkDataSetFactory {
 public:
   /// Constructor
-  vtkMDHistoLineFactory(ThresholdRange_scptr thresholdRange,
-                        const VisualNormalization normalizationOption);
+  vtkMDHistoLineFactory(const VisualNormalization normalizationOption);
 
   /// Assignment operator
   vtkMDHistoLineFactory &operator=(const vtkMDHistoLineFactory &other);
@@ -59,7 +57,7 @@ public:
   vtkSmartPointer<vtkDataSet>
   create(ProgressAction &progressUpdating) const override;
 
-  void initialize(Mantid::API::Workspace_sptr) override;
+  void initialize(const Mantid::API::Workspace_sptr &workspace) override;
 
   typedef std::vector<UnstructuredPoint> Column;
 
@@ -74,8 +72,6 @@ private:
   Mantid::DataObjects::MDHistoWorkspace_sptr m_workspace;
 
   VisualNormalization m_normalizationOption;
-
-  mutable ThresholdRange_scptr m_thresholdRange;
 };
 }
 }
diff --git a/Vates/VatesAPI/inc/MantidVatesAPI/vtkMDHistoQuadFactory.h b/Vates/VatesAPI/inc/MantidVatesAPI/vtkMDHistoQuadFactory.h
index 4ee573720028353b9c2e7d683241afcfe73d3ab9..8f8a643de51a9ff03c00addc9970d7fb9396ea40 100644
--- a/Vates/VatesAPI/inc/MantidVatesAPI/vtkMDHistoQuadFactory.h
+++ b/Vates/VatesAPI/inc/MantidVatesAPI/vtkMDHistoQuadFactory.h
@@ -3,7 +3,6 @@
 
 #include "MantidKernel/System.h"
 #include "MantidVatesAPI/Normalization.h"
-#include "MantidVatesAPI/ThresholdRange.h"
 #include "MantidVatesAPI/vtkDataSetFactory.h"
 
 #include "MantidAPI/IMDWorkspace.h"
@@ -46,8 +45,7 @@ National Laboratory & European Spallation Source
 class DLLExport vtkMDHistoQuadFactory : public vtkDataSetFactory {
 public:
   /// Constructor
-  vtkMDHistoQuadFactory(ThresholdRange_scptr thresholdRange,
-                        const VisualNormalization normalizationOption);
+  vtkMDHistoQuadFactory(const VisualNormalization normalizationOption);
 
   /// Assignment operator
   vtkMDHistoQuadFactory &operator=(const vtkMDHistoQuadFactory &other);
@@ -62,7 +60,7 @@ public:
   vtkSmartPointer<vtkDataSet>
   create(ProgressAction &progressUpdating) const override;
 
-  void initialize(Mantid::API::Workspace_sptr) override;
+  void initialize(const Mantid::API::Workspace_sptr &workspace) override;
 
   typedef std::vector<std::vector<UnstructuredPoint>> Plane;
 
@@ -79,8 +77,6 @@ private:
   Mantid::DataObjects::MDHistoWorkspace_sptr m_workspace;
 
   VisualNormalization m_normalizationOption;
-
-  mutable ThresholdRange_scptr m_thresholdRange;
 };
 }
 }
diff --git a/Vates/VatesAPI/inc/MantidVatesAPI/vtkMDLineFactory.h b/Vates/VatesAPI/inc/MantidVatesAPI/vtkMDLineFactory.h
index 192d40a49663583be0e835a113d1143069abb30a..a7f92d7dcce4e1864d1b90983cd8613b48c9a1fe 100644
--- a/Vates/VatesAPI/inc/MantidVatesAPI/vtkMDLineFactory.h
+++ b/Vates/VatesAPI/inc/MantidVatesAPI/vtkMDLineFactory.h
@@ -3,7 +3,6 @@
 
 #include "MantidVatesAPI/Normalization.h"
 #include "MantidVatesAPI/vtkDataSetFactory.h"
-#include "MantidVatesAPI/ThresholdRange.h"
 #include <boost/shared_ptr.hpp>
 
 namespace Mantid {
@@ -40,8 +39,7 @@ class DLLExport vtkMDLineFactory : public vtkDataSetFactory {
 
 public:
   /// Constructor
-  vtkMDLineFactory(ThresholdRange_scptr thresholdRange,
-                   const VisualNormalization normalizationOption);
+  vtkMDLineFactory(const VisualNormalization normalizationOption);
 
   /// Destructor
   ~vtkMDLineFactory() override;
@@ -51,7 +49,7 @@ public:
   create(ProgressAction &progressUpdating) const override;
 
   /// Initalize with a target workspace.
-  void initialize(Mantid::API::Workspace_sptr) override;
+  void initialize(const Mantid::API::Workspace_sptr &workspace) override;
 
   /// Get the name of the type.
   std::string getFactoryTypeName() const override;
@@ -61,9 +59,6 @@ protected:
   void validate() const override;
 
 private:
-  /// ThresholdRange functor.
-  ThresholdRange_scptr m_thresholdRange;
-
   /// Name of the scalar.
   const VisualNormalization m_normalizationOption;
 
@@ -73,4 +68,4 @@ private:
 }
 }
 
-#endif
\ No newline at end of file
+#endif
diff --git a/Vates/VatesAPI/inc/MantidVatesAPI/vtkMDQuadFactory.h b/Vates/VatesAPI/inc/MantidVatesAPI/vtkMDQuadFactory.h
index 5b5a7ebe7069b2c1580757f10ff8cc837643e883..bc259a002d9f63e87edfd1122da166d8cc181aee 100644
--- a/Vates/VatesAPI/inc/MantidVatesAPI/vtkMDQuadFactory.h
+++ b/Vates/VatesAPI/inc/MantidVatesAPI/vtkMDQuadFactory.h
@@ -2,7 +2,6 @@
 #define VATES_MD_QUAD_FACTORY
 
 #include "MantidVatesAPI/Normalization.h"
-#include "MantidVatesAPI/ThresholdRange.h"
 #include "MantidVatesAPI/vtkDataSetFactory.h"
 
 #include <boost/shared_ptr.hpp>
@@ -41,8 +40,7 @@ class DLLExport vtkMDQuadFactory : public vtkDataSetFactory {
 
 public:
   /// Constructor
-  vtkMDQuadFactory(ThresholdRange_scptr thresholdRange,
-                   const VisualNormalization normalizationOption);
+  vtkMDQuadFactory(const VisualNormalization normalizationOption);
 
   /// Destructor
   ~vtkMDQuadFactory() override;
@@ -52,7 +50,7 @@ public:
   create(ProgressAction &progressUpdating) const override;
 
   /// Initalize with a target workspace.
-  void initialize(Mantid::API::Workspace_sptr) override;
+  void initialize(const Mantid::API::Workspace_sptr &workspace) override;
 
   /// Get the name of the type.
   std::string getFactoryTypeName() const override;
@@ -62,9 +60,6 @@ protected:
   void validate() const override;
 
 private:
-  /// ThresholdRange functor.
-  ThresholdRange_scptr m_thresholdRange;
-
   /// Name of the scalar.
   const VisualNormalization m_normalizationOption;
 
@@ -74,4 +69,4 @@ private:
 }
 }
 
-#endif
\ No newline at end of file
+#endif
diff --git a/Vates/VatesAPI/inc/MantidVatesAPI/vtkSplatterPlotFactory.h b/Vates/VatesAPI/inc/MantidVatesAPI/vtkSplatterPlotFactory.h
index ef78869d3ea71352efbf352c69cfeb5e76e7a765..4657dfb5db77d4ce95934e8d0f37ab10b8bdc51c 100644
--- a/Vates/VatesAPI/inc/MantidVatesAPI/vtkSplatterPlotFactory.h
+++ b/Vates/VatesAPI/inc/MantidVatesAPI/vtkSplatterPlotFactory.h
@@ -7,7 +7,6 @@
 #include "MantidAPI/IMDHistoWorkspace_fwd.h"
 #include "MantidDataObjects/MDEventFactory.h"
 #include "MantidDataObjects/MDEventWorkspace.h"
-#include "MantidVatesAPI/ThresholdRange.h"
 #include "MantidVatesAPI/vtkDataSetFactory.h"
 #include "MantidVatesAPI/MetaDataExtractorUtils.h"
 #include "MantidVatesAPI/MetadataJsonManager.h"
@@ -55,8 +54,7 @@ typedef Mantid::signal_t (Mantid::API::IMDNode::*SigFuncIMDNodePtr)() const;
 class DLLExport vtkSplatterPlotFactory : public vtkDataSetFactory {
 public:
   /// Constructor
-  vtkSplatterPlotFactory(ThresholdRange_scptr thresholdRange,
-                         const std::string &scalarName,
+  vtkSplatterPlotFactory(const std::string &scalarName,
                          const size_t numPoints = 150000,
                          const double percentToUse = 5.0);
 
@@ -68,7 +66,7 @@ public:
   create(ProgressAction &progressUpdating) const override;
 
   /// Initalize with a target workspace.
-  void initialize(Mantid::API::Workspace_sptr) override;
+  void initialize(const Mantid::API::Workspace_sptr &workspace) override;
 
   /// Get the name of the type.
   std::string getFactoryTypeName() const override {
@@ -101,13 +99,13 @@ private:
   void doCreate(typename MDEventWorkspace<MDE, nd>::sptr ws) const;
 
   /// Check if the MDHisto workspace is 3D or 4D in nature
-  bool doMDHisto4D(Mantid::API::IMDHistoWorkspace_sptr workspace) const;
+  bool doMDHisto4D(const Mantid::API::IMDHistoWorkspace *workspace) const;
 
   /// Generate the vtkDataSet from the objects input MDHistoWorkspace
-  void doCreateMDHisto(Mantid::API::IMDHistoWorkspace_sptr workspace) const;
+  void doCreateMDHisto(const Mantid::API::IMDHistoWorkspace &workspace) const;
 
   /// Set the signals and the valid points which are to be displayed
-  signal_t extractScalarSignal(Mantid::API::IMDHistoWorkspace_sptr workspace,
+  signal_t extractScalarSignal(const Mantid::API::IMDHistoWorkspace &workspace,
                                bool do4D, const int x, const int y,
                                const int z) const;
 
@@ -117,9 +115,6 @@ private:
   /// Add metadata
   void addMetadata() const;
 
-  /// Threshold range strategy.
-  ThresholdRange_scptr m_thresholdRange;
-
   /// Scalar name to provide on dataset.
   const std::string m_scalarName;
 
diff --git a/Vates/VatesAPI/src/ADSWorkspaceProvider.cpp b/Vates/VatesAPI/src/ADSWorkspaceProvider.cpp
index 126ebd059d4afd354c245564dc3c4d45f86db305..476f9c28c2f9806aa123ed421d976bd5d5027821 100644
--- a/Vates/VatesAPI/src/ADSWorkspaceProvider.cpp
+++ b/Vates/VatesAPI/src/ADSWorkspaceProvider.cpp
@@ -21,7 +21,7 @@ bool ADSWorkspaceProvider<Workspace_Type>::canProvideWorkspace(
   bool bCanProvide = false;
   try {
     bCanProvide =
-        (NULL !=
+        (nullptr !=
          AnalysisDataService::Instance().retrieveWS<Workspace_Type>(wsName));
   } catch (Mantid::Kernel::Exception::NotFoundError &) {
     bCanProvide = false;
diff --git a/Vates/VatesAPI/src/BoxInfo.cpp b/Vates/VatesAPI/src/BoxInfo.cpp
index 753962929ea3fc1f885a319b046f5a208e7d2797..93857ce57aa46efc34565bd3ba5a27c4dc8012eb 100644
--- a/Vates/VatesAPI/src/BoxInfo.cpp
+++ b/Vates/VatesAPI/src/BoxInfo.cpp
@@ -9,13 +9,13 @@ namespace VATES {
 
 boost::optional<int> findRecursionDepthForTopLevelSplitting(
     const std::string &workspaceName,
-    std::unique_ptr<WorkspaceProvider> workspaceProvider) {
+    const WorkspaceProvider &workspaceProvider) {
   const int topLevelRecursionDepth = 1;
   boost::optional<int> recursionDepth;
-  if (workspaceProvider->canProvideWorkspace(workspaceName)) {
+  if (workspaceProvider.canProvideWorkspace(workspaceName)) {
     auto workspace =
         boost::dynamic_pointer_cast<Mantid::API::IMDEventWorkspace>(
-            workspaceProvider->fetchWorkspace(workspaceName));
+            workspaceProvider.fetchWorkspace(workspaceName));
     auto boxController = workspace->getBoxController();
     boost::optional<std::vector<size_t>> topLevelSplits =
         boxController->getSplitTopInto();
diff --git a/Vates/VatesAPI/src/CompositePeaksPresenterVsi.cpp b/Vates/VatesAPI/src/CompositePeaksPresenterVsi.cpp
index 016f820a6ba011091d3e5910ed36918b6691e3a7..38d495bb49b092cb614cee74ed1873af3ab26197 100644
--- a/Vates/VatesAPI/src/CompositePeaksPresenterVsi.cpp
+++ b/Vates/VatesAPI/src/CompositePeaksPresenterVsi.cpp
@@ -162,9 +162,9 @@ bool CompositePeaksPresenterVsi::hasPeaks() {
  */
 void CompositePeaksPresenterVsi::sortPeaksWorkspace(
     const std::string &columnToSortBy, const bool sortedAscending,
-    boost::shared_ptr<const Mantid::API::IPeaksWorkspace> peaksWS) {
+    const Mantid::API::IPeaksWorkspace *peaksWS) {
   for (const auto &presenter : m_peaksPresenters) {
-    if (presenter->getPeaksWorkspace() == peaksWS) {
+    if (presenter->getPeaksWorkspace().get() == peaksWS) {
       presenter->sortPeaksWorkspace(columnToSortBy, sortedAscending);
     }
   }
diff --git a/Vates/VatesAPI/src/ConcretePeaksPresenterVsi.cpp b/Vates/VatesAPI/src/ConcretePeaksPresenterVsi.cpp
index 444bd47d63b60aebb0a7aec1cb0e6321d22d5453..d42265700cc6166c819560c77b00bc292d5ada53 100644
--- a/Vates/VatesAPI/src/ConcretePeaksPresenterVsi.cpp
+++ b/Vates/VatesAPI/src/ConcretePeaksPresenterVsi.cpp
@@ -54,7 +54,8 @@ std::vector<bool> ConcretePeaksPresenterVsi::getViewablePeaks() const {
     alg->setRethrows(true);
     alg->initialize();
     alg->setProperty("InputWorkspace", peaksWS);
-    alg->setProperty("OutputWorkspace", peaksWS->name() + "_peaks_in_region");
+    alg->setProperty("OutputWorkspace",
+                     peaksWS->getName() + "_peaks_in_region");
     alg->setProperty("Extents", viewable);
     alg->setProperty("CheckPeakExtents", true);
     alg->setProperty("PeakRadius", effectiveRadius);
@@ -127,7 +128,7 @@ void ConcretePeaksPresenterVsi::getPeaksInfo(
   // Peak radius
   Mantid::Geometry::PeakShape_sptr shape(
       peaksWorkspace->getPeakPtr(row)->getPeakShape().clone());
-  radius = getMaxRadius(shape);
+  radius = getMaxRadius(*shape);
 }
 
 /**
@@ -136,11 +137,11 @@ void ConcretePeaksPresenterVsi::getPeaksInfo(
  * @returns The maximal radius of the peak.
  */
 double ConcretePeaksPresenterVsi::getMaxRadius(
-    Mantid::Geometry::PeakShape_sptr shape) const {
+    const Mantid::Geometry::PeakShape &shape) const {
   const double defaultRadius = 1.0;
 
   boost::optional<double> radius =
-      shape->radius(Mantid::Geometry::PeakShape::Radius);
+      shape.radius(Mantid::Geometry::PeakShape::Radius);
   if (radius) {
     return radius.get();
   } else {
diff --git a/Vates/VatesAPI/src/EventNexusLoadingPresenter.cpp b/Vates/VatesAPI/src/EventNexusLoadingPresenter.cpp
index b2fea4d15b185761d39f616efb196b96e9c56aad..72f9f932108be9198b967126a34b4757b1d3aa21 100644
--- a/Vates/VatesAPI/src/EventNexusLoadingPresenter.cpp
+++ b/Vates/VatesAPI/src/EventNexusLoadingPresenter.cpp
@@ -1,4 +1,5 @@
 #include "MantidVatesAPI/EventNexusLoadingPresenter.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/IEventWorkspace.h"
 #include "MantidAPI/IMDEventWorkspace.h"
 #include "MantidGeometry/MDGeometry/MDGeometryXMLBuilder.h"
@@ -25,7 +26,7 @@ namespace VATES {
  @throw logic_error if cannot use the reader-presenter for this filetype.
  */
 EventNexusLoadingPresenter::EventNexusLoadingPresenter(
-    std::unique_ptr<MDLoadingView> view, const std::string filename)
+    std::unique_ptr<MDLoadingView> view, const std::string &filename)
     : MDEWLoadingPresenter(std::move(view)), m_filename(filename),
       m_wsTypeName("") {
   if (this->m_filename.empty()) {
diff --git a/Vates/VatesAPI/src/FieldDataToMetadata.cpp b/Vates/VatesAPI/src/FieldDataToMetadata.cpp
index 95565ff10ab531771e78db50022c8c46f50a2d7e..0d2c4966f24cfd0b74aa7731e4bf4e9f18d1ba62 100644
--- a/Vates/VatesAPI/src/FieldDataToMetadata.cpp
+++ b/Vates/VatesAPI/src/FieldDataToMetadata.cpp
@@ -7,24 +7,24 @@ namespace Mantid {
 namespace VATES {
 
 std::string FieldDataToMetadata::operator()(vtkFieldData *fieldData,
-                                            std::string id) const {
+                                            const std::string &id) const {
   return execute(fieldData, id);
 }
 
 std::string FieldDataToMetadata::execute(vtkFieldData *fieldData,
                                          const std::string &id) const {
   std::string sXml;
-  if (fieldData == NULL) {
+  if (!fieldData) {
     throw std::runtime_error("vtkFieldData argument is null");
   }
-  vtkDataArray *arry = fieldData->GetArray(id.c_str());
-  if (arry == NULL) {
+  vtkDataArray *array = fieldData->GetArray(id.c_str());
+  if (!array) {
     throw std::runtime_error("The specified vtk array does not exist");
   }
-  if (vtkCharArray *carry = dynamic_cast<vtkCharArray *>(arry)) {
-    carry->Squeeze();
-    for (int i = 0; i < carry->GetSize(); i++) {
-      char c = carry->GetValue(i);
+  if (vtkCharArray *carray = vtkCharArray::FastDownCast(array)) {
+    carray->Squeeze();
+    for (int i = 0; i < carray->GetSize(); i++) {
+      char c = carray->GetValue(i);
       if (int(c) > 1) {
         sXml.push_back(c);
       }
diff --git a/Vates/VatesAPI/src/IMDDimensionComparitor.cpp b/Vates/VatesAPI/src/IMDDimensionComparitor.cpp
index f748933dd4ae06290d1f627057aee7da782f8503..bcaa67212de470612b7933a31e5ae0ba45c585c7 100644
--- a/Vates/VatesAPI/src/IMDDimensionComparitor.cpp
+++ b/Vates/VatesAPI/src/IMDDimensionComparitor.cpp
@@ -5,55 +5,55 @@ namespace VATES {
 
 IMDDimensionComparitor::IMDDimensionComparitor(
     Mantid::API::IMDWorkspace_sptr workspace)
-    : m_workspace(workspace) {}
+    : m_workspace(std::move(workspace)) {}
 
 IMDDimensionComparitor::~IMDDimensionComparitor() {}
 
 bool IMDDimensionComparitor::isXDimension(
-    Mantid::Geometry::IMDDimension_const_sptr queryDimension) {
+    const Mantid::Geometry::IMDDimension &queryDimension) {
   // Compare dimensions on the basis of their ids.
   Mantid::Geometry::IMDDimension_const_sptr actualXDimension =
       m_workspace->getXDimension();
-  return queryDimension->getDimensionId() == actualXDimension->getDimensionId();
+  return queryDimension.getDimensionId() == actualXDimension->getDimensionId();
 }
 
 bool IMDDimensionComparitor::isYDimension(
-    Mantid::Geometry::IMDDimension_const_sptr queryDimension) {
+    const Mantid::Geometry::IMDDimension &queryDimension) {
   Mantid::Geometry::IMDDimension_const_sptr actualYDimension =
       m_workspace->getYDimension();
-  if (NULL == actualYDimension.get()) {
-    return false; // MDImages may have 1 dimension or more.
-  } else {
+  if (actualYDimension) {
     // Compare dimensions on the basis of their ids.
-    return queryDimension->getDimensionId() ==
+    return queryDimension.getDimensionId() ==
            actualYDimension->getDimensionId();
+  } else {
+    return false; // MDImages may have 1 dimension or more.
   }
 }
 
 bool IMDDimensionComparitor::isZDimension(
-    Mantid::Geometry::IMDDimension_const_sptr queryDimension) {
+    const Mantid::Geometry::IMDDimension &queryDimension) {
   Mantid::Geometry::IMDDimension_const_sptr actualZDimension =
       m_workspace->getZDimension();
-  if (NULL == actualZDimension.get()) {
-    return false; // MDImages may have 1 dimension or more.
-  } else {
+  if (actualZDimension) {
     // Compare dimensions on the basis of their ids.
-    return queryDimension->getDimensionId() ==
+    return queryDimension.getDimensionId() ==
            actualZDimension->getDimensionId();
+  } else {
+    return false; // MDImages may have 1 dimension or more.
   }
 }
 
 bool IMDDimensionComparitor::istDimension(
-    Mantid::Geometry::IMDDimension_const_sptr queryDimension) {
+    const Mantid::Geometry::IMDDimension &queryDimension) {
   Mantid::Geometry::IMDDimension_const_sptr actualtDimension =
       m_workspace->getTDimension();
-  if (NULL == actualtDimension.get()) {
-    return false; // MDImages may have 1 dimension or more.
-  } else {
+  if (actualtDimension) {
     // Compare dimensions on the basis of their ids.
-    return queryDimension->getDimensionId() ==
+    return queryDimension.getDimensionId() ==
            actualtDimension->getDimensionId();
+  } else {
+    return false; // MDImages may have 1 dimension or more.
   }
 }
 }
-}
\ No newline at end of file
+}
diff --git a/Vates/VatesAPI/src/IgnoreZerosThresholdRange.cpp b/Vates/VatesAPI/src/IgnoreZerosThresholdRange.cpp
deleted file mode 100644
index 949ffb5f2e6be798db99977f2a912da2773aa1a2..0000000000000000000000000000000000000000
--- a/Vates/VatesAPI/src/IgnoreZerosThresholdRange.cpp
+++ /dev/null
@@ -1,67 +0,0 @@
-#include "MantidVatesAPI/IgnoreZerosThresholdRange.h"
-#include <stdexcept>
-
-namespace Mantid {
-namespace VATES {
-
-/**
-Constructor.
-*/
-IgnoreZerosThresholdRange::IgnoreZerosThresholdRange() : m_min(1), m_max(1) {}
-
-/**
-Constructor.
-*/
-IgnoreZerosThresholdRange::IgnoreZerosThresholdRange(signal_t min, signal_t max)
-    : m_min(min), m_max(max) {}
-
-/**
-Indicates wheter execution has occured or not.
-return : true always.
-*/
-bool IgnoreZerosThresholdRange::hasCalculated() const { return true; }
-
-/**
-Destructor.
-*/
-IgnoreZerosThresholdRange::~IgnoreZerosThresholdRange() {}
-
-/**
-Do nothing calculate method.
-*/
-void IgnoreZerosThresholdRange::calculate() {}
-
-/**
-Minimum value getter.
-@return The minimum value.
-*/
-double IgnoreZerosThresholdRange::getMinimum() const { return m_min; }
-
-/**
-Maximum value getter.
-@return The maximum value.
-*/
-double IgnoreZerosThresholdRange::getMaximum() const { return m_max; }
-
-/**
-Virtual constructor clone method.
-@return clone of original.
-*/
-IgnoreZerosThresholdRange *IgnoreZerosThresholdRange::clone() const {
-  return new IgnoreZerosThresholdRange(this->m_min, this->m_max);
-}
-
-/**
-Determine whether the signal is withing range.
-@param signal value
-@return true if the signal is in the range defined by this object.
-*/
-bool IgnoreZerosThresholdRange::inRange(const signal_t &signal) {
-  m_max = signal > m_max ? signal : m_max; // cache min and max values.
-  if (signal < m_min && 0 != signal) {
-    m_min = signal < m_min ? signal : m_min;
-  }
-  return signal != 0;
-}
-}
-}
diff --git a/Vates/VatesAPI/src/LoadVTK.cpp b/Vates/VatesAPI/src/LoadVTK.cpp
index 25e2570d3a38b6a727bfece221fbe10a557bd181..224521850ddc4a1e1231ca26f3f8c1213d007035 100644
--- a/Vates/VatesAPI/src/LoadVTK.cpp
+++ b/Vates/VatesAPI/src/LoadVTK.cpp
@@ -112,8 +112,7 @@ int LoadVTK::version() const { return 1; }
 const std::string LoadVTK::category() const { return "MDAlgorithms"; }
 
 void LoadVTK::init() {
-  std::vector<std::string> exts;
-  exts.push_back("vtk");
+  std::vector<std::string> exts{"vtk"};
   this->declareProperty(
       Kernel::make_unique<FileProperty>("Filename", "", FileProperty::Load,
                                         exts),
@@ -187,12 +186,13 @@ void LoadVTK::execMDHisto(vtkUnsignedShortArray *signals,
   double *destinationSignals = outputWS->getSignalArray();
   double *destinationErrorsSQ = outputWS->getErrorSquaredArray();
 
-  if (errorsSQ == NULL) {
+  if (errorsSQ) {
     PARALLEL_FOR_NO_WSP_CHECK()
     for (int64_t i = 0; i < nPoints; ++i) {
       PARALLEL_START_INTERUPT_REGION
       // cppcheck-suppress unreadVariable
       destinationSignals[i] = signals->GetValue(i);
+      destinationErrorsSQ[i] = errorsSQ->GetValue(i);
       if (i % frequency == 0)
         prog.report();
       PARALLEL_END_INTERUPT_REGION
@@ -204,14 +204,12 @@ void LoadVTK::execMDHisto(vtkUnsignedShortArray *signals,
       PARALLEL_START_INTERUPT_REGION
       // cppcheck-suppress unreadVariable
       destinationSignals[i] = signals->GetValue(i);
-      destinationErrorsSQ[i] = errorsSQ->GetValue(i);
       if (i % frequency == 0)
         prog.report();
       PARALLEL_END_INTERUPT_REGION
     }
     PARALLEL_CHECK_INTERUPT_REGION
   }
-
   prog.report("Complete");
   this->setProperty("OutputWorkspace", outputWS);
 }
@@ -252,21 +250,21 @@ void LoadVTK::execMDEvent(vtkDataSet *readDataset,
   bc->setSplitInto(2);
   bc->setSplitThreshold(10);
   bc->setMaxDepth(7);
-  ws->addDimension(dimX);
-  ws->addDimension(dimY);
-  ws->addDimension(dimZ);
+  ws->addDimension(std::move(dimX));
+  ws->addDimension(std::move(dimY));
+  ws->addDimension(std::move(dimZ));
   ws->initialize();
 
-  if (errorsSQ == NULL) {
+  if (errorsSQ) {
     PARALLEL_FOR_IF(Kernel::threadSafe(*ws))
     for (int64_t i = 0; i < nPoints; ++i) {
       PARALLEL_START_INTERUPT_REGION
       double coordinates[3];
       readDataset->GetPoint(i, coordinates);
       float signal = signals->GetValue(i);
-
+      float errorSQ = errorsSQ->GetValue(i);
       if (signal > lowerBounds) {
-        MDLeanEvent<3> event(signal, 0, coordinates);
+        MDLeanEvent<3> event(signal, errorSQ, coordinates);
         ws->addEvent(event);
       }
       if (i % frequency == 0)
@@ -281,9 +279,9 @@ void LoadVTK::execMDEvent(vtkDataSet *readDataset,
       double coordinates[3];
       readDataset->GetPoint(i, coordinates);
       float signal = signals->GetValue(i);
-      float errorSQ = errorsSQ->GetValue(i);
+
       if (signal > lowerBounds) {
-        MDLeanEvent<3> event(signal, errorSQ, coordinates);
+        MDLeanEvent<3> event(signal, 0, coordinates);
         ws->addEvent(event);
       }
       if (i % frequency == 0)
@@ -316,16 +314,16 @@ void LoadVTK::exec() {
   vtkSmartPointer<vtkStructuredPoints> readDataset;
   readDataset.TakeReference(reader->GetOutput());
 
-  vtkUnsignedShortArray *signals = vtkUnsignedShortArray::SafeDownCast(
+  vtkUnsignedShortArray *signals = vtkUnsignedShortArray::FastDownCast(
       readDataset->GetPointData()->GetArray(signalArrayName.c_str()));
-  if (signals == NULL) {
+  if (!signals) {
     throw std::invalid_argument("Signal array: " + signalArrayName +
                                 " does not exist");
   }
 
-  vtkUnsignedShortArray *errorsSQ = vtkUnsignedShortArray::SafeDownCast(
+  vtkUnsignedShortArray *errorsSQ = vtkUnsignedShortArray::FastDownCast(
       readDataset->GetPointData()->GetArray(errorSQArrayName.c_str()));
-  if (!errorSQArrayName.empty() && errorsSQ == NULL) {
+  if (!errorSQArrayName.empty() && !errorsSQ) {
     throw std::invalid_argument("Error squared array: " + errorSQArrayName +
                                 " does not exist");
   }
diff --git a/Vates/VatesAPI/src/MDEWEventNexusLoadingPresenter.cpp b/Vates/VatesAPI/src/MDEWEventNexusLoadingPresenter.cpp
index e6140965d176d2b46e4698576b925a0965c35a15..81cc8b7afd0a2764e51dec715f01108be679c5ea 100644
--- a/Vates/VatesAPI/src/MDEWEventNexusLoadingPresenter.cpp
+++ b/Vates/VatesAPI/src/MDEWEventNexusLoadingPresenter.cpp
@@ -1,4 +1,5 @@
 #include "MantidVatesAPI/MDEWEventNexusLoadingPresenter.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/IMDEventWorkspace.h"
 #include "MantidVatesAPI/MDLoadingView.h"
 #include "MantidVatesAPI/ProgressAction.h"
@@ -23,13 +24,13 @@ Constructor
 @throw logic_error if cannot use the reader-presenter for this filetype.
 */
 MDEWEventNexusLoadingPresenter::MDEWEventNexusLoadingPresenter(
-    std::unique_ptr<MDLoadingView> view, const std::string filename)
+    std::unique_ptr<MDLoadingView> view, const std::string &filename)
     : MDEWLoadingPresenter(std::move(view)), m_filename(filename),
-      m_wsTypeName("") {
+      m_wsTypeName() {
   if (this->m_filename.empty()) {
     throw std::invalid_argument("File name is an empty string.");
   }
-  if (nullptr == this->m_view) {
+  if (!this->m_view) {
     throw std::invalid_argument("View is NULL.");
   }
 }
@@ -45,17 +46,13 @@ bool MDEWEventNexusLoadingPresenter::canReadFile() const {
     return 0;
   }
 
-  ::NeXus::File *file = NULL;
-
-  file = new ::NeXus::File(this->m_filename);
+  auto file = Kernel::make_unique<::NeXus::File>(this->m_filename);
   // MDEventWorkspace file has a different name for the entry
   try {
     file->openGroup("MDEventWorkspace", "NXentry");
-    file->close();
     return 1;
   } catch (::NeXus::Exception &) {
     // If the entry name does not match, then it can't read the file.
-    file->close();
     return 0;
   }
   return 0;
diff --git a/Vates/VatesAPI/src/MDEWInMemoryLoadingPresenter.cpp b/Vates/VatesAPI/src/MDEWInMemoryLoadingPresenter.cpp
index ec930737942e52615b08a44469bcb613c2bc9944..1b1320b050e67602fdbfd37881ebe81150c252cc 100644
--- a/Vates/VatesAPI/src/MDEWInMemoryLoadingPresenter.cpp
+++ b/Vates/VatesAPI/src/MDEWInMemoryLoadingPresenter.cpp
@@ -113,13 +113,13 @@ void MDEWInMemoryLoadingPresenter::executeLoadMetadata() {
 
   // Set the minimum and maximum of the workspace data.
   QwtDoubleInterval minMaxContainer =
-      m_metaDataExtractor->getMinAndMax(eventWs);
+      m_metaDataExtractor->getMinAndMax(eventWs.get());
   m_metadataJsonManager->setMinValue(minMaxContainer.minValue());
   m_metadataJsonManager->setMaxValue(minMaxContainer.maxValue());
 
   // Set the instrument which is associated with the workspace.
   m_metadataJsonManager->setInstrument(
-      m_metaDataExtractor->extractInstrument(eventWs));
+      m_metaDataExtractor->extractInstrument(eventWs.get()));
 
   // Set the special coordinates
   m_metadataJsonManager->setSpecialCoordinates(m_specialCoords);
diff --git a/Vates/VatesAPI/src/MDEWLoadingPresenter.cpp b/Vates/VatesAPI/src/MDEWLoadingPresenter.cpp
index 33b1f390a9659dd4416b84f22628a1348fb44185..05fac0698d89118be5a473bfca25098af6289d91 100644
--- a/Vates/VatesAPI/src/MDEWLoadingPresenter.cpp
+++ b/Vates/VatesAPI/src/MDEWLoadingPresenter.cpp
@@ -2,6 +2,7 @@
 #include "MantidVatesAPI/MDLoadingView.h"
 #include "MantidAPI/FrameworkManager.h"
 #include "MantidAPI/IMDEventWorkspace.h"
+#include "MantidGeometry/MDGeometry/IMDDimension.h"
 
 #include "MantidGeometry/MDGeometry/NullImplicitFunction.h"
 #include "MantidVatesAPI/VatesKnowledgeSerializer.h"
diff --git a/Vates/VatesAPI/src/MDHWInMemoryLoadingPresenter.cpp b/Vates/VatesAPI/src/MDHWInMemoryLoadingPresenter.cpp
index 1387b7cff278409c7910e5cac56ebec10957d563..133941d87ab192f4feee97ed6d5e1dcccbb8f0ce 100644
--- a/Vates/VatesAPI/src/MDHWInMemoryLoadingPresenter.cpp
+++ b/Vates/VatesAPI/src/MDHWInMemoryLoadingPresenter.cpp
@@ -1,15 +1,19 @@
 #include "MantidVatesAPI/MDHWInMemoryLoadingPresenter.h"
 #include "MantidAPI/AlgorithmManager.h"
 #include "MantidAPI/IMDHistoWorkspace.h"
+#include "MantidGeometry/MDGeometry/MDGeometryXMLBuilder.h"
+#include "MantidVatesAPI/FactoryChains.h"
 #include "MantidVatesAPI/MDLoadingView.h"
 #include "MantidVatesAPI/MetaDataExtractorUtils.h"
-#include "MantidVatesAPI/FactoryChains.h"
 #include "MantidVatesAPI/ProgressAction.h"
-#include "MantidVatesAPI/vtkDataSetFactory.h"
 #include "MantidVatesAPI/WorkspaceProvider.h"
-#include "MantidGeometry/MDGeometry/MDGeometryXMLBuilder.h"
+#include "MantidVatesAPI/vtkDataSetFactory.h"
 #include <qwt_double_interval.h>
-#include <vtkUnstructuredGrid.h>
+
+#include "tbb/tbb.h"
+#include "vtkStructuredGrid.h"
+#include "vtkUnsignedCharArray.h"
+#include "vtkUnstructuredGrid.h"
 
 namespace Mantid {
 namespace VATES {
@@ -31,10 +35,10 @@ MDHWInMemoryLoadingPresenter::MDHWInMemoryLoadingPresenter(
   if (m_wsName.empty()) {
     throw std::invalid_argument("The workspace name is empty.");
   }
-  if (NULL == repository) {
+  if (!repository) {
     throw std::invalid_argument("The repository is NULL");
   }
-  if (nullptr == m_view) {
+  if (!m_view) {
     throw std::invalid_argument("View is NULL.");
   }
 }
@@ -49,18 +53,74 @@ bool MDHWInMemoryLoadingPresenter::canReadFile() const {
   if (!m_repository->canProvideWorkspace(m_wsName)) {
     // The workspace does not exist.
     bCanReadIt = false;
-  } else if (NULL ==
-             boost::dynamic_pointer_cast<Mantid::API::IMDHistoWorkspace>(
-                 m_repository->fetchWorkspace(m_wsName)).get()) {
+  } else if (boost::dynamic_pointer_cast<Mantid::API::IMDHistoWorkspace>(
+                 m_repository->fetchWorkspace(m_wsName))) {
     // The workspace can be found, but is not an IMDHistoWorkspace.
-    bCanReadIt = false;
+    bCanReadIt = true;
   } else {
     // The workspace is present, and is of the correct type.
-    bCanReadIt = true;
+    bCanReadIt = false;
   }
   return bCanReadIt;
 }
 
+namespace {
+class CellVisibility {
+public:
+  explicit CellVisibility(const unsigned char *array)
+      : MASKED_CELL_VALUE(vtkDataSetAttributes::HIDDENCELL |
+                          vtkDataSetAttributes::REFINEDCELL),
+        InputCellGhostArray(array) {}
+  bool operator()(vtkIdType id) const {
+    if (InputCellGhostArray)
+      return !(this->InputCellGhostArray[id] & this->MASKED_CELL_VALUE);
+    else
+      return true;
+  }
+
+private:
+  const unsigned char MASKED_CELL_VALUE;
+  const unsigned char *InputCellGhostArray;
+};
+
+struct MinAndMax {
+  double m_minimum = VTK_DOUBLE_MAX;
+  double m_maximum = VTK_DOUBLE_MIN;
+  vtkDataArray *m_cellScalars;
+  CellVisibility m_isCellVisible;
+  MinAndMax(vtkDataArray *cellScalars, const unsigned char *cellGhostArray)
+      : m_cellScalars(cellScalars), m_isCellVisible(cellGhostArray) {}
+  MinAndMax(MinAndMax &rhs, tbb::split)
+      : m_cellScalars(rhs.m_cellScalars), m_isCellVisible(rhs.m_isCellVisible) {
+  }
+  void operator()(const tbb::blocked_range<int> &r) {
+    for (int id = r.begin(); id != r.end(); ++id) {
+      if (m_isCellVisible(id)) {
+        double s = m_cellScalars->GetComponent(id, 0);
+        m_minimum = std::min(m_minimum, s);
+        m_maximum = std::max(m_maximum, s);
+      }
+    }
+  }
+  void join(MinAndMax &rhs) {
+    m_minimum = std::min(m_minimum, rhs.m_minimum);
+    m_maximum = std::max(m_maximum, rhs.m_maximum);
+  }
+};
+
+void ComputeScalarRange(vtkStructuredGrid *grid, double *cellRange) {
+  vtkDataArray *cellScalars = grid->GetCellData()->GetScalars();
+  auto cga = grid->GetCellGhostArray();
+  MinAndMax minandmax(cellScalars, cga ? cga->GetPointer(0) : nullptr);
+
+  int num = boost::numeric_cast<int>(grid->GetNumberOfCells());
+  tbb::parallel_reduce(tbb::blocked_range<int>(0, num), minandmax);
+
+  cellRange[0] = minandmax.m_minimum;
+  cellRange[1] = minandmax.m_maximum;
+}
+}
+
 /*
 Executes the underlying algorithm to create the MVP model.
 @param factory : visualisation factory to use.
@@ -87,20 +147,32 @@ MDHWInMemoryLoadingPresenter::execute(vtkDataSetFactory *factory,
       drawingProgressUpdate); // HACK: progressUpdate should be
                               // argument for drawing!
 
-  /*extractMetaData needs to be re-run here because the first execution of this
-    from ::executeLoadMetadata will not have ensured that all dimensions
-    have proper range extents set.
-  */
-
   // Update the meta data min and max values with the values of the visual data
   // set. This is necessary since we want the full data range of the visual
   // data set and not of the actual underlying data set.
-  double *range = visualDataSet->GetScalarRange();
-  if (range) {
-    this->m_metadataJsonManager->setMinValue(range[0]);
-    this->m_metadataJsonManager->setMaxValue(range[1]);
+
+  // vtkStructuredGrid::GetScalarRange(...) is slow and single-threaded.
+  // Until this is addressed in VTK, we are better of doing the calculation
+  // ourselves.
+  // 600x600x600 vtkStructuredGrid, every other cell blank
+  // structuredGrid->GetScalarRange(range) : 2.267s
+  // structuredGrid->GetCellData()->GetScalars()->GetRange(range) : 1.023s
+  // ComputeScalarRange(structuredGrid,range): 0.075s
+  double range[2];
+  if (auto structuredGrid = vtkStructuredGrid::SafeDownCast(visualDataSet)) {
+    ComputeScalarRange(structuredGrid, range);
+  } else {
+    // should never happen
+    visualDataSet->GetScalarRange(range);
   }
 
+  this->m_metadataJsonManager->setMinValue(range[0]);
+  this->m_metadataJsonManager->setMaxValue(range[1]);
+
+  /*extractMetaData needs to be re-run here because the first execution of this
+   from ::executeLoadMetadata will not have ensured that all dimensions
+   have proper range extents set.
+  */
   this->extractMetadata(*m_cachedVisualHistoWs);
 
   // Transposed workpace is temporary, outside the ADS, and does not have a
@@ -130,13 +202,13 @@ void MDHWInMemoryLoadingPresenter::executeLoadMetadata() {
 
   // Set the minimum and maximum of the workspace data.
   QwtDoubleInterval minMaxContainer =
-      m_metaDataExtractor->getMinAndMax(histoWs);
+      m_metaDataExtractor->getMinAndMax(histoWs.get());
   m_metadataJsonManager->setMinValue(minMaxContainer.minValue());
   m_metadataJsonManager->setMaxValue(minMaxContainer.maxValue());
 
   // Set the instrument which is associated with the workspace.
   m_metadataJsonManager->setInstrument(
-      m_metaDataExtractor->extractInstrument(m_cachedVisualHistoWs));
+      m_metaDataExtractor->extractInstrument(m_cachedVisualHistoWs.get()));
 
   // Set the special coordinates
   m_metadataJsonManager->setSpecialCoordinates(m_specialCoords);
diff --git a/Vates/VatesAPI/src/MDHWLoadingPresenter.cpp b/Vates/VatesAPI/src/MDHWLoadingPresenter.cpp
index 0439d1c6c0641478762ae3852f4d4c5d7ce0f437..2498623bdf4cce842f9149e6a6f171b1e437dde0 100644
--- a/Vates/VatesAPI/src/MDHWLoadingPresenter.cpp
+++ b/Vates/VatesAPI/src/MDHWLoadingPresenter.cpp
@@ -5,6 +5,7 @@
 #include "MantidAPI/IAlgorithm.h"
 #include "MantidAPI/IMDHistoWorkspace.h"
 
+#include "MantidGeometry/MDGeometry/IMDDimension.h"
 #include "MantidGeometry/MDGeometry/MDHistoDimension.h"
 #include "MantidGeometry/MDGeometry/NullImplicitFunction.h"
 #include "MantidVatesAPI/VatesKnowledgeSerializer.h"
@@ -18,6 +19,8 @@
 #include "MantidVatesAPI/Common.h"
 
 #include <boost/scoped_ptr.hpp>
+#include <boost/algorithm/string/case_conv.hpp>
+#include <boost/algorithm/string/trim.hpp>
 
 #include <vtkPVChangeOfBasisHelper.h>
 #include <vtkFieldData.h>
diff --git a/Vates/VatesAPI/src/MDHWNexusLoadingPresenter.cpp b/Vates/VatesAPI/src/MDHWNexusLoadingPresenter.cpp
index 9bb01b22c40a5c77a9bc1cc280ee6e57630d13a4..e8654c3c990a163327961a2d90c1ba6170b48bfa 100644
--- a/Vates/VatesAPI/src/MDHWNexusLoadingPresenter.cpp
+++ b/Vates/VatesAPI/src/MDHWNexusLoadingPresenter.cpp
@@ -1,4 +1,5 @@
 #include "MantidVatesAPI/MDHWNexusLoadingPresenter.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/IMDHistoWorkspace.h"
 #include "MantidVatesAPI/MDLoadingView.h"
 #include "MantidVatesAPI/ProgressAction.h"
@@ -23,7 +24,7 @@ namespace VATES {
  * @throw logic_error if cannot use the reader-presenter for this filetype.
  */
 MDHWNexusLoadingPresenter::MDHWNexusLoadingPresenter(
-    std::unique_ptr<MDLoadingView> view, const std::string filename)
+    std::unique_ptr<MDLoadingView> view, const std::string &filename)
     : MDHWLoadingPresenter(std::move(view)), m_filename(filename),
       m_wsTypeName("") {
   if (this->m_filename.empty()) {
@@ -44,17 +45,13 @@ bool MDHWNexusLoadingPresenter::canReadFile() const {
   if (!canLoadFileBasedOnExtension(m_filename, ".nxs")) {
     return 0;
   }
-  ::NeXus::File *file = NULL;
-
-  file = new ::NeXus::File(this->m_filename);
+  auto file = Kernel::make_unique<::NeXus::File>(this->m_filename);
   // MDHistoWorkspace file has a different name for the entry
   try {
     file->openGroup("MDHistoWorkspace", "NXentry");
-    file->close();
     return 1;
   } catch (::NeXus::Exception &) {
     // If the entry name does not match, then it can't read the file.
-    file->close();
     return 0;
   }
   return 0;
diff --git a/Vates/VatesAPI/src/MDLoadingPresenter.cpp b/Vates/VatesAPI/src/MDLoadingPresenter.cpp
index 90e45ff14b3a846e25eee66afa68eaae5b192171..00d0f0433256a5d47988b84b32ac64ab11312250 100644
--- a/Vates/VatesAPI/src/MDLoadingPresenter.cpp
+++ b/Vates/VatesAPI/src/MDLoadingPresenter.cpp
@@ -38,14 +38,16 @@ void MDLoadingPresenter::setDefaultCOBandBoundaries(vtkDataSet *visualDataSet) {
  * @param visualDataSet: the vtk visual data set to which the transformation
  * will be applied
  * @param workspaceProvider: the provider of the underlying workspace
+ * @param progress: optional progress reporting.
  */
 void MDLoadingPresenter::makeNonOrthogonal(
     vtkDataSet *visualDataSet,
-    std::unique_ptr<Mantid::VATES::WorkspaceProvider> workspaceProvider) {
+    std::unique_ptr<Mantid::VATES::WorkspaceProvider> workspaceProvider,
+    ProgressAction *progress) {
   std::string wsName = vtkDataSetToWsName::exec(visualDataSet);
   vtkDataSetToNonOrthogonalDataSet converter(visualDataSet, wsName,
                                              std::move(workspaceProvider));
-  converter.execute();
+  converter.execute(progress);
 }
 }
 }
diff --git a/Vates/VatesAPI/src/MedianAndBelowThresholdRange.cpp b/Vates/VatesAPI/src/MedianAndBelowThresholdRange.cpp
deleted file mode 100644
index acfb839a48c7cef41fee732db4a4326b75ac091a..0000000000000000000000000000000000000000
--- a/Vates/VatesAPI/src/MedianAndBelowThresholdRange.cpp
+++ /dev/null
@@ -1,111 +0,0 @@
-#include "MantidVatesAPI/MedianAndBelowThresholdRange.h"
-#include "MantidAPI/IMDIterator.h"
-#include <cmath>
-
-namespace Mantid {
-namespace VATES {
-
-/**
-Constructor
-*/
-MedianAndBelowThresholdRange::MedianAndBelowThresholdRange()
-    : m_min(0.00), m_max(0), m_isCalculated(false) {}
-
-/**
-Constructor
-*/
-MedianAndBelowThresholdRange::MedianAndBelowThresholdRange(
-    signal_t min, signal_t max, bool isCalculated,
-    Mantid::API::IMDWorkspace_sptr workspace)
-    : m_min(min), m_max(max), m_isCalculated(isCalculated),
-      m_workspace(workspace) {}
-
-/// Destructor
-MedianAndBelowThresholdRange::~MedianAndBelowThresholdRange() {}
-
-/**
-Overriden calculate method.
-*/
-void MedianAndBelowThresholdRange::calculate() {
-  if (NULL == m_workspace.get()) {
-    throw std::logic_error("The workspace has not been set.");
-  }
-
-  signal_t signal = 0;
-  signal_t accumulated_signal = 0;
-
-  Mantid::API::IMDIterator *it = m_workspace->createIterator();
-  do {
-    signal = it->getNormalizedSignal();
-    accumulated_signal += signal;
-    m_min = signal < m_min ? signal : m_min;
-  } while (it->next());
-
-  m_max = accumulated_signal / static_cast<signal_t>(it->getDataSize());
-  m_isCalculated = true;
-}
-
-/**
-Indicates wheter execution has occured or not.
-@return : true if calculate has been called previously, otherwise false.
-*/
-bool MedianAndBelowThresholdRange::hasCalculated() const {
-  return m_isCalculated;
-}
-
-/**
-Getter for the calculated minimum value.
-*/
-signal_t MedianAndBelowThresholdRange::getMinimum() const {
-  if (!m_isCalculated) {
-    throw std::runtime_error(
-        "Cannot call ::getMinimum() without first calling ::calculate()");
-  }
-  return m_min;
-}
-
-/**
-Getter for the calculated maximum value.
-*/
-signal_t MedianAndBelowThresholdRange::getMaximum() const {
-  if (!m_isCalculated) {
-    throw std::runtime_error(
-        "Cannot call ::getMaximum() without first calling ::calculate()");
-  }
-  return m_max;
-}
-
-/**
-Virtual constructor clone method.
-@return clone as MedianAndBelowThresholdRange*.
-*/
-MedianAndBelowThresholdRange *MedianAndBelowThresholdRange::clone() const {
-  return new MedianAndBelowThresholdRange(m_min, m_max, m_isCalculated,
-                                          this->m_workspace);
-}
-
-/**
-Setter for IMDWorkspace.
-@param workspace : The workspace to extract ranges from.
-*/
-void MedianAndBelowThresholdRange::setWorkspace(
-    Mantid::API::Workspace_sptr workspace) {
-  m_isCalculated = false;
-  m_workspace =
-      boost::dynamic_pointer_cast<Mantid::API::IMDWorkspace>(workspace);
-  if (!workspace) {
-    throw std::logic_error(
-        "MedianAndBelowThresholdRange only works for IMDWorkspaces");
-  }
-}
-
-/**
-Determine whether the signal is withing range.
-@param signal value
-@return true if the signal is in the range defined by this object.
-*/
-bool MedianAndBelowThresholdRange::inRange(const signal_t &signal) {
-  return signal != 0 && signal < m_max;
-}
-}
-}
diff --git a/Vates/VatesAPI/src/MetaDataExtractorUtils.cpp b/Vates/VatesAPI/src/MetaDataExtractorUtils.cpp
index 5d520a305637464ca464502c7f0ed4e533f00b64..746045cc2ad39987e59c94b2607bfa41ae0c5292 100644
--- a/Vates/VatesAPI/src/MetaDataExtractorUtils.cpp
+++ b/Vates/VatesAPI/src/MetaDataExtractorUtils.cpp
@@ -7,6 +7,7 @@
 #include "MantidAPI/IMDWorkspace.h"
 #include "MantidGeometry/Instrument.h"
 #include "MantidKernel/Logger.h"
+#include "MantidKernel/MultiThreaded.h"
 #include "boost/pointer_cast.hpp"
 #include <cfloat>
 
@@ -30,11 +31,11 @@ MetaDataExtractorUtils::~MetaDataExtractorUtils() {}
  * @returns The instrument name or an empty string.
  */
 std::string MetaDataExtractorUtils::extractInstrument(
-    Mantid::API::IMDWorkspace_sptr workspace) {
-  Mantid::API::IMDEventWorkspace_sptr eventWorkspace =
-      boost::dynamic_pointer_cast<Mantid::API::IMDEventWorkspace>(workspace);
-  Mantid::API::IMDHistoWorkspace_sptr histoWorkspace =
-      boost::dynamic_pointer_cast<Mantid::API::IMDHistoWorkspace>(workspace);
+    const Mantid::API::IMDWorkspace *workspace) {
+  auto eventWorkspace =
+      dynamic_cast<const Mantid::API::IMDEventWorkspace *>(workspace);
+  auto histoWorkspace =
+      dynamic_cast<const Mantid::API::IMDHistoWorkspace *>(workspace);
 
   std::string instrument = "";
 
@@ -73,12 +74,13 @@ std::string MetaDataExtractorUtils::extractInstrument(
  * @param workspace Rreference to an IMD workspace
  * @returns The minimum and maximum value of the workspace dataset.
  */
-QwtDoubleInterval
-MetaDataExtractorUtils::getMinAndMax(Mantid::API::IMDWorkspace_sptr workspace) {
+QwtDoubleInterval MetaDataExtractorUtils::getMinAndMax(
+    const Mantid::API::IMDWorkspace *workspace) {
   if (!workspace)
     throw std::invalid_argument("The workspace is empty.");
 
-  auto iterators = workspace->createIterators(PARALLEL_GET_MAX_THREADS, 0);
+  auto iterators =
+      workspace->createIterators(PARALLEL_GET_MAX_THREADS, nullptr);
 
   std::vector<QwtDoubleInterval> intervals(iterators.size());
   // cppcheck-suppress syntaxError
diff --git a/Vates/VatesAPI/src/MetadataJsonManager.cpp b/Vates/VatesAPI/src/MetadataJsonManager.cpp
index af3ac67541c50c116e88a62c8b4c033ad00aa6dd..27cecf7abdcf4349213b839ea1aaefc098c5a679 100644
--- a/Vates/VatesAPI/src/MetadataJsonManager.cpp
+++ b/Vates/VatesAPI/src/MetadataJsonManager.cpp
@@ -32,7 +32,8 @@ std::string MetadataJsonManager::getSerializedJson() {
  * Read in the serialized JSON data and opulate the JSON container
  * @param serializedJson The serialized JSON string.
  */
-void MetadataJsonManager::readInSerializedJson(std::string serializedJson) {
+void MetadataJsonManager::readInSerializedJson(
+    const std::string &serializedJson) {
   Json::Reader reader;
   metadataContainer.clear();
 
@@ -106,7 +107,7 @@ double MetadataJsonManager::getMinValue() { return minValue; }
  * Set the instrument.
  * @param instrument The instrument associated with the workspace.
  */
-void MetadataJsonManager::setInstrument(std::string instrument) {
+void MetadataJsonManager::setInstrument(const std::string &instrument) {
   this->instrument = instrument;
 }
 
@@ -130,4 +131,4 @@ void MetadataJsonManager::setSpecialCoordinates(int specialCoordinates) {
  */
 int MetadataJsonManager::getSpecialCoordinates() { return specialCoordinates; }
 }
-}
\ No newline at end of file
+}
diff --git a/Vates/VatesAPI/src/MetadataToFieldData.cpp b/Vates/VatesAPI/src/MetadataToFieldData.cpp
index 4cafe5c4ace83099a20782df52adad4530adc874..35544546b7b10307e43f0b7785a4ed11d429b29e 100644
--- a/Vates/VatesAPI/src/MetadataToFieldData.cpp
+++ b/Vates/VatesAPI/src/MetadataToFieldData.cpp
@@ -7,26 +7,26 @@ namespace Mantid {
 namespace VATES {
 
 void MetadataToFieldData::operator()(vtkFieldData *fieldData,
-                                     std::string metaData,
-                                     std::string id) const {
+                                     const std::string &metaData,
+                                     const std::string &id) const {
   execute(fieldData, metaData, id);
 }
 
-void MetadataToFieldData::execute(vtkFieldData *fieldData, std::string metaData,
-                                  std::string id) const {
+void MetadataToFieldData::execute(vtkFieldData *fieldData,
+                                  const std::string &metaData,
+                                  const std::string &id) const {
   // clean out existing.
-  vtkDataArray *arry = fieldData->GetArray(id.c_str());
-  if (NULL != arry) {
+  vtkDataArray *array = fieldData->GetArray(id.c_str());
+  if (array) {
     fieldData->RemoveArray(id.c_str());
   }
   // create new.
-  vtkNew<vtkCharArray> newArry;
-  newArry->Allocate(metaData.size());
-  newArry->SetName(id.c_str());
-  fieldData->AddArray(newArry.GetPointer());
-
-  for (unsigned int i = 0; i < metaData.size(); i++) {
-    newArry->InsertNextValue(metaData.at(i));
+  vtkNew<vtkCharArray> newArray;
+  newArray->SetNumberOfTuples(metaData.size());
+  newArray->SetName(id.c_str());
+  fieldData->AddArray(newArray.GetPointer());
+  for (size_t i = 0; i < metaData.size(); i++) {
+    newArray->SetValue(i, metaData[i]);
   }
 }
 }
diff --git a/Vates/VatesAPI/src/NoThresholdRange.cpp b/Vates/VatesAPI/src/NoThresholdRange.cpp
deleted file mode 100644
index 6f605e03f8ddfcefde7a97cef6a4c1f717d073a5..0000000000000000000000000000000000000000
--- a/Vates/VatesAPI/src/NoThresholdRange.cpp
+++ /dev/null
@@ -1,65 +0,0 @@
-#include "MantidVatesAPI/NoThresholdRange.h"
-#include <stdexcept>
-
-namespace Mantid {
-namespace VATES {
-
-/**
-Constructor.
-*/
-NoThresholdRange::NoThresholdRange() : m_min(0), m_max(0) {}
-
-/**
-Constructor.
-*/
-NoThresholdRange::NoThresholdRange(signal_t min, signal_t max)
-    : m_min(min), m_max(max) {}
-
-/**
-Indicates wheter execution has occured or not.
-return : true always.
-*/
-bool NoThresholdRange::hasCalculated() const { return true; }
-
-/**
-Destructor.
-*/
-NoThresholdRange::~NoThresholdRange() {}
-
-/**
-Do nothing calculate method.
-*/
-void NoThresholdRange::calculate() {}
-
-/**
-Minimum value getter.
-@return The minimum value.
-*/
-double NoThresholdRange::getMinimum() const { return m_min; }
-
-/**
-Maximum value getter.
-@return The maximum value.
-*/
-double NoThresholdRange::getMaximum() const { return m_max; }
-
-/**
-Virtual constructor clone method.
-@return clone of original.
-*/
-NoThresholdRange *NoThresholdRange::clone() const {
-  return new NoThresholdRange(this->m_min, this->m_max);
-}
-
-/**
-Determine whether the signal is withing range.
-@param signal value
-@return true if the signal is in the range defined by this object.
-*/
-bool NoThresholdRange::inRange(const signal_t &signal) {
-  m_max = signal > m_max ? signal : m_max; // cache min and max values.
-  m_min = signal < m_min ? signal : m_min;
-  return true;
-}
-}
-}
diff --git a/Vates/VatesAPI/src/PresenterFactories.cpp b/Vates/VatesAPI/src/PresenterFactories.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9911a8e8c5054d65f45565fa57f0dd8d5859aefe
--- /dev/null
+++ b/Vates/VatesAPI/src/PresenterFactories.cpp
@@ -0,0 +1,13 @@
+#include "MantidVatesAPI/PresenterFactories.h"
+
+namespace Mantid {
+namespace VATES {
+
+const std::string &EmptyWorkspaceNamePolicy::getWorkspaceName(
+    const Mantid::API::IMDWorkspace & /*workspace*/) {
+  static std::string name{"__EmptyWorkspaceNamePolicy"};
+  return name;
+}
+
+} // namespace VATES
+} // namespace Mantid
diff --git a/Vates/VatesAPI/src/PresenterUtilities.cpp b/Vates/VatesAPI/src/PresenterUtilities.cpp
index 4062c83c4047098bc51f02b3e0b7170d97e8fe3f..743672342c7ea8635aa003be4539b494fe7ca16a 100644
--- a/Vates/VatesAPI/src/PresenterUtilities.cpp
+++ b/Vates/VatesAPI/src/PresenterUtilities.cpp
@@ -2,7 +2,6 @@
 #include "MantidVatesAPI/FactoryChains.h"
 
 #include "MantidVatesAPI/MDLoadingPresenter.h"
-#include "MantidVatesAPI/ThresholdRange.h"
 #include "MantidVatesAPI/vtkMDHistoLineFactory.h"
 #include "MantidVatesAPI/vtkMDHistoQuadFactory.h"
 #include "MantidVatesAPI/vtkMDHistoHexFactory.h"
@@ -33,7 +32,7 @@ namespace VATES {
  * @returns a clipped object
  */
 vtkSmartPointer<vtkPVClipDataSet>
-getClippedDataSet(vtkSmartPointer<vtkDataSet> dataSet) {
+getClippedDataSet(const vtkSmartPointer<vtkDataSet> &dataSet) {
   auto box = vtkSmartPointer<vtkBox>::New();
   box->SetBounds(dataSet->GetBounds());
   auto clipper = vtkSmartPointer<vtkPVClipDataSet>::New();
@@ -56,7 +55,8 @@ void applyCOBMatrixSettingsToVtkDataSet(
     Mantid::VATES::MDLoadingPresenter *presenter, vtkDataSet *dataSet,
     std::unique_ptr<Mantid::VATES::WorkspaceProvider> workspaceProvider) {
   try {
-    presenter->makeNonOrthogonal(dataSet, std::move(workspaceProvider));
+    presenter->makeNonOrthogonal(dataSet, std::move(workspaceProvider),
+                                 nullptr);
   } catch (std::invalid_argument &e) {
     std::string error = e.what();
     g_log_presenter_utilities.warning()
@@ -76,21 +76,18 @@ void applyCOBMatrixSettingsToVtkDataSet(
 
 /**
  * Creates a factory chain for MDEvent workspaces
- * @param threshold: the threshold range
  * @param normalization: the normalization option
  * @param time: the time slice time
  * @returns a factory chain
  */
 std::unique_ptr<vtkMDHexFactory>
-createFactoryChainForEventWorkspace(ThresholdRange_scptr threshold,
-                                    VisualNormalization normalization,
+createFactoryChainForEventWorkspace(VisualNormalization normalization,
                                     double time) {
-  auto factory =
-      Mantid::Kernel::make_unique<vtkMDHexFactory>(threshold, normalization);
-  factory->setSuccessor(Mantid::Kernel::make_unique<vtkMDQuadFactory>(
-                            threshold, normalization))
-      .setSuccessor(Mantid::Kernel::make_unique<vtkMDLineFactory>(
-          threshold, normalization))
+  auto factory = Mantid::Kernel::make_unique<vtkMDHexFactory>(normalization);
+  factory->setSuccessor(
+               Mantid::Kernel::make_unique<vtkMDQuadFactory>(normalization))
+      .setSuccessor(
+           Mantid::Kernel::make_unique<vtkMDLineFactory>(normalization))
       .setSuccessor(Mantid::Kernel::make_unique<vtkMD0DFactory>());
   factory->setTime(time);
   return factory;
@@ -98,24 +95,22 @@ createFactoryChainForEventWorkspace(ThresholdRange_scptr threshold,
 
 /**
 * Creates a factory chain for MDHisto workspaces
-* @param threshold: the threshold range
 * @param normalization: the normalization option
 * @param time: the time slice time
 * @returns a factory chain
 */
 std::unique_ptr<vtkMDHistoHex4DFactory<TimeToTimeStep>>
-createFactoryChainForHistoWorkspace(ThresholdRange_scptr threshold,
-                                    VisualNormalization normalization,
+createFactoryChainForHistoWorkspace(VisualNormalization normalization,
                                     double time) {
   auto factory =
       Mantid::Kernel::make_unique<vtkMDHistoHex4DFactory<TimeToTimeStep>>(
-          threshold, normalization, time);
-  factory->setSuccessor(Mantid::Kernel::make_unique<vtkMDHistoHexFactory>(
-                            threshold, normalization))
-      .setSuccessor(Mantid::Kernel::make_unique<vtkMDHistoQuadFactory>(
-          threshold, normalization))
-      .setSuccessor(Mantid::Kernel::make_unique<vtkMDHistoLineFactory>(
-          threshold, normalization))
+          normalization, time);
+  factory->setSuccessor(
+               Mantid::Kernel::make_unique<vtkMDHistoHexFactory>(normalization))
+      .setSuccessor(
+           Mantid::Kernel::make_unique<vtkMDHistoQuadFactory>(normalization))
+      .setSuccessor(
+           Mantid::Kernel::make_unique<vtkMDHistoLineFactory>(normalization))
       .setSuccessor(Mantid::Kernel::make_unique<vtkMD0DFactory>());
   return factory;
 }
diff --git a/Vates/VatesAPI/src/SQWLoadingPresenter.cpp b/Vates/VatesAPI/src/SQWLoadingPresenter.cpp
index b7026167a68f2cc2094ceac4467c5ede9a5347fd..3a9d022aa09032232b23a180ddab026685eb89d0 100644
--- a/Vates/VatesAPI/src/SQWLoadingPresenter.cpp
+++ b/Vates/VatesAPI/src/SQWLoadingPresenter.cpp
@@ -1,4 +1,5 @@
 #include "MantidVatesAPI/SQWLoadingPresenter.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/IMDEventWorkspace.h"
 #include "MantidVatesAPI/Common.h"
 #include "MantidVatesAPI/MDLoadingView.h"
@@ -6,6 +7,7 @@
 #include "MantidVatesAPI/vtkDataSetFactory.h"
 
 #include "MantidAPI/AlgorithmManager.h"
+#include "MantidGeometry/MDGeometry/IMDDimension.h"
 #include <boost/regex.hpp>
 
 namespace Mantid {
@@ -20,7 +22,7 @@ namespace VATES {
     @throw logic_error if cannot use the reader-presenter for this filetype.
     */
 SQWLoadingPresenter::SQWLoadingPresenter(std::unique_ptr<MDLoadingView> view,
-                                         const std::string filename)
+                                         const std::string &filename)
     : MDEWLoadingPresenter(std::move(view)), m_filename(filename),
       m_wsTypeName("") {
   if (this->m_filename.empty()) {
@@ -72,7 +74,7 @@ SQWLoadingPresenter::execute(vtkDataSetFactory *factory,
     // Default is not to load into memory and when this is the case, generate a
     // nxs backend for output.
     if (!this->m_view->getLoadInMemory()) {
-      size_t pos = this->m_filename.find(".");
+      size_t pos = this->m_filename.find('.');
       std::string backEndFile = this->m_filename.substr(0, pos) + ".nxs";
       alg->setPropertyValue("OutputFilename", backEndFile);
     }
diff --git a/Vates/VatesAPI/src/SaveMDWorkspaceToVTK.cpp b/Vates/VatesAPI/src/SaveMDWorkspaceToVTK.cpp
index e7b77406bbe7a8aaf374806215c5010f57cbbee7..b10e7924bd8ddd6e234958a1aa721edf1128acc2 100644
--- a/Vates/VatesAPI/src/SaveMDWorkspaceToVTK.cpp
+++ b/Vates/VatesAPI/src/SaveMDWorkspaceToVTK.cpp
@@ -18,7 +18,7 @@ namespace VATES {
 DECLARE_ALGORITHM(SaveMDWorkspaceToVTK)
 
 SaveMDWorkspaceToVTK::SaveMDWorkspaceToVTK()
-    : saver(Mantid::Kernel::make_unique<SaveMDWorkspaceToVTKImpl>()) {}
+    : saver(Mantid::Kernel::make_unique<SaveMDWorkspaceToVTKImpl>(this)) {}
 
 SaveMDWorkspaceToVTK::~SaveMDWorkspaceToVTK() {}
 
@@ -60,13 +60,6 @@ void SaveMDWorkspaceToVTK::init() {
       "The visual normalization option. The automatic default will choose a "
       "normalization based on your data type and instrument.");
 
-  auto thresholds = saver->getAllowedThresholdsInStringRepresentation();
-  declareProperty(
-      "ThresholdRange", "IgnoreZerosThresholdRange",
-      boost::make_shared<Mantid::Kernel::StringListValidator>(thresholds),
-      "The threshold range. Currently either no threshold or an ignore-zeros "
-      "policy can be applied.");
-
   boost::shared_ptr<Mantid::Kernel::BoundedValidator<int>> mustBePositive(
       new Mantid::Kernel::BoundedValidator<int>());
   mustBePositive->setLower(1);
@@ -90,18 +83,13 @@ void SaveMDWorkspaceToVTK::exec() {
   auto normalization = saver->translateStringToVisualNormalization(
       normalizationInStringRepresentation);
 
-  std::string thresholdRangeInStringRepresentation =
-      this->getProperty("ThresholdRange");
-  auto thresholdRange = saver->translateStringToThresholdRange(
-      thresholdRangeInStringRepresentation);
-
   int recursionDepth = this->getProperty("RecursionDepth");
 
   std::string compressorType = this->getProperty("CompressorType");
 
   // Save workspace into file
-  saver->saveMDWorkspace(inputWS, filename, normalization, thresholdRange,
-                         recursionDepth, compressorType);
+  saver->saveMDWorkspace(inputWS, filename, normalization, recursionDepth,
+                         compressorType);
 }
 
 std::map<std::string, std::string> SaveMDWorkspaceToVTK::validateInputs() {
@@ -116,7 +104,7 @@ std::map<std::string, std::string> SaveMDWorkspaceToVTK::validateInputs() {
   }
 
   // Check for the dimensionality
-  if (!saver->is3DWorkspace(inputWS)) {
+  if (!saver->is3DWorkspace(*inputWS)) {
     errorMessage.emplace("InputWorkspace", "The MD workspace must be 3D.");
   }
 
diff --git a/Vates/VatesAPI/src/SaveMDWorkspaceToVTKImpl.cpp b/Vates/VatesAPI/src/SaveMDWorkspaceToVTKImpl.cpp
index 1d7440130c49f53cd459f63e419a020fca5c623e..8cb5293353739a291138f9a01d0648b1f3c77fb2 100644
--- a/Vates/VatesAPI/src/SaveMDWorkspaceToVTKImpl.cpp
+++ b/Vates/VatesAPI/src/SaveMDWorkspaceToVTKImpl.cpp
@@ -1,9 +1,6 @@
 #include "MantidVatesAPI/SaveMDWorkspaceToVTKImpl.h"
 #include "MantidVatesAPI/Normalization.h"
 
-#include "MantidVatesAPI/IgnoreZerosThresholdRange.h"
-#include "MantidVatesAPI/NoThresholdRange.h"
-
 #include "MantidVatesAPI/FactoryChains.h"
 #include "MantidVatesAPI/MDEWInMemoryLoadingPresenter.h"
 #include "MantidVatesAPI/MDHWInMemoryLoadingPresenter.h"
@@ -18,6 +15,7 @@
 #include "MantidKernel/Logger.h"
 #include "MantidKernel/make_unique.h"
 
+#include "vtkCallbackCommand.h"
 #include "vtkFloatArray.h"
 #include "vtkNew.h"
 #include "vtkSmartPointer.h"
@@ -26,7 +24,9 @@
 #include "vtkXMLUnstructuredGridWriter.h"
 
 #include <boost/make_shared.hpp>
+#include <boost/math/special_functions/round.hpp>
 #include <memory>
+#include <utility>
 
 namespace {
 // This progress object gets called by PV (and is used by the plugins),
@@ -46,10 +46,10 @@ bool has_suffix(const std::string &stringToCheck, const std::string &suffix) {
   return isSuffixInString;
 }
 
-bool isNDWorkspace(Mantid::API::IMDWorkspace_sptr workspace,
+bool isNDWorkspace(const Mantid::API::IMDWorkspace &workspace,
                    const size_t dimensionality) {
   auto actualNonIntegratedDimensionality =
-      workspace->getNonIntegratedDimensions().size();
+      workspace.getNonIntegratedDimensions().size();
   return actualNonIntegratedDimensionality == dimensionality;
 }
 }
@@ -60,21 +60,23 @@ namespace VATES {
 const std::string SaveMDWorkspaceToVTKImpl::structuredGridExtension = "vts";
 const std::string SaveMDWorkspaceToVTKImpl::unstructuredGridExtension = "vtu";
 
-SaveMDWorkspaceToVTKImpl::SaveMDWorkspaceToVTKImpl() { setupMembers(); }
+SaveMDWorkspaceToVTKImpl::SaveMDWorkspaceToVTKImpl(SaveMDWorkspaceToVTK *parent)
+    : m_progress(parent, 0.0, 1.0, 101) {
+  setupMembers();
+}
 
 /**
  * Save an MD workspace to a vts/vtu file.
  * @param workspace: the workspace which is to be saved.
  * @param filename: the name of the file to which the workspace is to be saved.
  * @param normalization: the visual normalization option
- * @param thresholdRange: a plolicy for the threshold range
  * @param recursionDepth: the recursion depth for MDEvent Workspaces determines
  * @param compressorType: the compression type used by VTK
  * from which level data should be displayed
  */
 void SaveMDWorkspaceToVTKImpl::saveMDWorkspace(
-    Mantid::API::IMDWorkspace_sptr workspace, const std::string &filename,
-    VisualNormalization normalization, ThresholdRange_scptr thresholdRange,
+    const Mantid::API::IMDWorkspace_sptr &workspace,
+    const std::string &filename, VisualNormalization normalization,
     int recursionDepth, const std::string &compressorType) const {
   auto isHistoWorkspace =
       boost::dynamic_pointer_cast<Mantid::API::IMDHistoWorkspace>(workspace) !=
@@ -95,11 +97,11 @@ void SaveMDWorkspaceToVTKImpl::saveMDWorkspace(
     }
   }();
   // Define a time slice.
-  auto time = selectTimeSliceValue(workspace);
+  auto time = selectTimeSliceValue(*workspace);
 
   // Get presenter and data set factory set up
-  auto factoryChain = getDataSetFactoryChain(isHistoWorkspace, thresholdRange,
-                                             normalization, time);
+  auto factoryChain =
+      getDataSetFactoryChain(isHistoWorkspace, normalization, time);
 
   auto presenter = getPresenter(isHistoWorkspace, workspace, recursionDepth);
 
@@ -145,22 +147,19 @@ void SaveMDWorkspaceToVTKImpl::saveMDWorkspace(
 /**
  * Creates the correct factory chain based
  * @param isHistoWorkspace: flag if workspace is MDHisto
- * @param thresholdRange: the threshold range
  * @param normalization: the normalization option
  * @param time: the time slice info
  * @returns a data set factory
  */
 std::unique_ptr<vtkDataSetFactory>
 SaveMDWorkspaceToVTKImpl::getDataSetFactoryChain(
-    bool isHistoWorkspace, ThresholdRange_scptr thresholdRange,
-    VisualNormalization normalization, double time) const {
+    bool isHistoWorkspace, VisualNormalization normalization,
+    double time) const {
   std::unique_ptr<vtkDataSetFactory> factory;
   if (isHistoWorkspace) {
-    factory = createFactoryChainForHistoWorkspace(thresholdRange, normalization,
-                                                  time);
+    factory = createFactoryChainForHistoWorkspace(normalization, time);
   } else {
-    factory = createFactoryChainForEventWorkspace(thresholdRange, normalization,
-                                                  time);
+    factory = createFactoryChainForEventWorkspace(normalization, time);
   }
   return factory;
 }
@@ -195,6 +194,22 @@ SaveMDWorkspaceToVTKImpl::getPresenter(bool isHistoWorkspace,
   return presenter;
 }
 
+void ProgressFunction(vtkObject *caller, long unsigned int vtkNotUsed(eventId),
+                      void *clientData, void *vtkNotUsed(callData)) {
+  vtkXMLWriter *testFilter = dynamic_cast<vtkXMLWriter *>(caller);
+  if (!testFilter)
+    return;
+  const char *progressText = testFilter->GetProgressText();
+  if (progressText) {
+    reinterpret_cast<Kernel::ProgressBase *>(clientData)
+        ->report(boost::math::iround(testFilter->GetProgress() * 100.0),
+                 progressText);
+  } else {
+    reinterpret_cast<Kernel::ProgressBase *>(clientData)
+        ->report(boost::math::iround(testFilter->GetProgress() * 100.0));
+  }
+}
+
 /**
  * Write an unstructured grid or structured grid to a vtk file.
  * @param writer: a vtk xml writer
@@ -206,6 +221,10 @@ SaveMDWorkspaceToVTKImpl::getPresenter(bool isHistoWorkspace,
 int SaveMDWorkspaceToVTKImpl::writeDataSetToVTKFile(
     vtkXMLWriter *writer, vtkDataSet *dataSet, const std::string &filename,
     vtkXMLWriter::CompressorType compressor) const {
+  vtkNew<vtkCallbackCommand> progressCallback;
+  progressCallback->SetCallback(ProgressFunction);
+  writer->AddObserver(vtkCommand::ProgressEvent, progressCallback.GetPointer());
+  progressCallback->SetClientData(&m_progress);
   writer->SetFileName(filename.c_str());
   writer->SetInputData(dataSet);
   writer->SetCompressorType(compressor);
@@ -231,7 +250,7 @@ SaveMDWorkspaceToVTKImpl::getAllowedNormalizationsInStringRepresentation()
 
 VisualNormalization
 SaveMDWorkspaceToVTKImpl::translateStringToVisualNormalization(
-    const std::string normalization) const {
+    const std::string &normalization) const {
   return m_normalizations.at(normalization);
 }
 
@@ -243,26 +262,6 @@ void SaveMDWorkspaceToVTKImpl::setupMembers() {
                            VisualNormalization::NumEventsNormalization);
   m_normalizations.emplace("VolumeNormalization",
                            VisualNormalization::VolumeNormalization);
-
-  m_thresholds.emplace_back("IgnoreZerosThresholdRange");
-  m_thresholds.emplace_back("NoThresholdRange");
-}
-
-std::vector<std::string>
-SaveMDWorkspaceToVTKImpl::getAllowedThresholdsInStringRepresentation() const {
-  return m_thresholds;
-}
-
-ThresholdRange_scptr SaveMDWorkspaceToVTKImpl::translateStringToThresholdRange(
-    const std::string thresholdRange) const {
-  if (thresholdRange == m_thresholds[0]) {
-    return boost::make_shared<IgnoreZerosThresholdRange>();
-  } else if (thresholdRange == m_thresholds[1]) {
-    return boost::make_shared<NoThresholdRange>();
-  } else {
-    throw std::runtime_error("SaveMDWorkspaceToVTK: The selected threshold "
-                             "range seems to be incorrect.");
-  }
 }
 
 /**
@@ -271,10 +270,10 @@ ThresholdRange_scptr SaveMDWorkspaceToVTKImpl::translateStringToThresholdRange(
  * @return either the first time entry in case of a 4D workspace or else 0.0
  */
 double SaveMDWorkspaceToVTKImpl::selectTimeSliceValue(
-    Mantid::API::IMDWorkspace_sptr workspace) const {
+    const Mantid::API::IMDWorkspace &workspace) const {
   double time = 0.0;
   if (is4DWorkspace(workspace)) {
-    auto timeLikeDimension = workspace->getDimension(3);
+    auto timeLikeDimension = workspace.getDimension(3);
     time = static_cast<double>(timeLikeDimension->getMinimum());
   }
   return time;
@@ -286,7 +285,7 @@ double SaveMDWorkspaceToVTKImpl::selectTimeSliceValue(
  * @return true if the workspace is 4D else false
  */
 bool SaveMDWorkspaceToVTKImpl::is4DWorkspace(
-    Mantid::API::IMDWorkspace_sptr workspace) const {
+    const Mantid::API::IMDWorkspace &workspace) const {
   const size_t dimensionality = 4;
   return isNDWorkspace(workspace, dimensionality);
 }
@@ -297,7 +296,7 @@ bool SaveMDWorkspaceToVTKImpl::is4DWorkspace(
  * @return true if the workspace is 3D else false
  */
 bool SaveMDWorkspaceToVTKImpl::is3DWorkspace(
-    Mantid::API::IMDWorkspace_sptr workspace) const {
+    const Mantid::API::IMDWorkspace &workspace) const {
   const size_t dimensionality = 3;
   return isNDWorkspace(workspace, dimensionality);
 }
diff --git a/Vates/VatesAPI/src/UserDefinedThresholdRange.cpp b/Vates/VatesAPI/src/UserDefinedThresholdRange.cpp
deleted file mode 100644
index a47a679ef1114cf69f03a2e3746ffd72f70623b9..0000000000000000000000000000000000000000
--- a/Vates/VatesAPI/src/UserDefinedThresholdRange.cpp
+++ /dev/null
@@ -1,65 +0,0 @@
-#include "MantidVatesAPI/UserDefinedThresholdRange.h"
-#include <stdexcept>
-
-namespace Mantid {
-namespace VATES {
-
-/**
-Constructor.
-@param min : range min.
-@param max : range max.
-*/
-UserDefinedThresholdRange::UserDefinedThresholdRange(signal_t min, signal_t max)
-    : m_min(min), m_max(max) {
-  if (max < min) {
-    throw std::invalid_argument(
-        "Cannot have max < min in a UserDefinedThresholdRange.");
-  }
-}
-
-/**
-Indicates wheter execution has occured or not.
-return : true always.
-*/
-bool UserDefinedThresholdRange::hasCalculated() const { return true; }
-
-/**
-Destructor.
-*/
-UserDefinedThresholdRange::~UserDefinedThresholdRange() {}
-
-/**
-Do nothing calculate method.
-*/
-void UserDefinedThresholdRange::calculate() {}
-
-/**
-Minimum value getter.
-@return The minimum value.
-*/
-double UserDefinedThresholdRange::getMinimum() const { return m_min; }
-
-/**
-Maximum value getter.
-@return The maximum value.
-*/
-double UserDefinedThresholdRange::getMaximum() const { return m_max; }
-
-/**
-Virtual constructor clone method.
-@return clone of original.
-*/
-UserDefinedThresholdRange *UserDefinedThresholdRange::clone() const {
-  return new UserDefinedThresholdRange(this->m_min, this->m_max);
-}
-
-/**
-Determine whether the signal is withing range.
-@param signal value
-@return true if the signal is in the range defined by this object.
-*/
-bool UserDefinedThresholdRange::inRange(const signal_t &signal) {
-  return signal >= m_min && signal <= m_max;
-}
-}
-}
diff --git a/Vates/VatesAPI/src/VatesKnowledgeSerializer.cpp b/Vates/VatesAPI/src/VatesKnowledgeSerializer.cpp
index 1a88636a27aa7e4b1118aa23c7cc57f3f5945e88..f59b6db5ccb0082cb0c2ee27d2141c4ab0b15074 100644
--- a/Vates/VatesAPI/src/VatesKnowledgeSerializer.cpp
+++ b/Vates/VatesAPI/src/VatesKnowledgeSerializer.cpp
@@ -1,11 +1,12 @@
-#include <MantidGeometry/MDGeometry/MDImplicitFunction.h>
-#include <boost/shared_ptr.hpp>
+#include "MantidVatesAPI/VatesKnowledgeSerializer.h"
+#include "MantidGeometry/MDGeometry/MDGeometryXMLDefinitions.h"
+#include "MantidVatesAPI/VatesXMLDefinitions.h"
 #include <MantidAPI/IMDWorkspace.h>
+#include <MantidGeometry/MDGeometry/MDImplicitFunction.h>
 #include <boost/algorithm/string.hpp>
 #include <boost/format.hpp>
-#include "MantidGeometry/MDGeometry/MDGeometryXMLDefinitions.h"
-#include "MantidVatesAPI/VatesKnowledgeSerializer.h"
-#include "MantidVatesAPI/VatesXMLDefinitions.h"
+#include <boost/shared_ptr.hpp>
+#include <utility>
 
 using Mantid::Geometry::MDGeometryXMLDefinitions;
 namespace Mantid {
@@ -16,30 +17,30 @@ VatesKnowledgeSerializer::VatesKnowledgeSerializer()
 
 void VatesKnowledgeSerializer::setImplicitFunction(
     boost::shared_ptr<const Mantid::Geometry::MDImplicitFunction> spFunction) {
-  this->m_spFunction = spFunction;
+  this->m_spFunction = std::move(spFunction);
 }
 
 /// Set the workspace name to apply.
 void VatesKnowledgeSerializer::setWorkspace(
-    boost::shared_ptr<const Mantid::API::IMDWorkspace> workspace) {
+    const Mantid::API::IMDWorkspace &workspace) {
 
   this->m_wsNameXML = MDGeometryXMLDefinitions::workspaceNameXMLTagStart() +
-                      workspace->getName() +
+                      workspace.getName() +
                       MDGeometryXMLDefinitions::workspaceNameXMLTagEnd();
   this->m_wsLocationXML =
       MDGeometryXMLDefinitions::workspaceLocationXMLTagStart() + "" +
       MDGeometryXMLDefinitions::workspaceLocationXMLTagEnd();
-  this->m_geomXML = workspace->getGeometryXML();
+  this->m_geomXML = workspace.getGeometryXML();
 }
 
-void VatesKnowledgeSerializer::setWorkspaceName(std::string wsName) {
+void VatesKnowledgeSerializer::setWorkspaceName(const std::string &wsName) {
   this->m_wsName = wsName;
   this->m_wsNameXML =
       std::string(MDGeometryXMLDefinitions::workspaceNameXMLTagStart() +
                   wsName + MDGeometryXMLDefinitions::workspaceNameXMLTagEnd());
 }
 
-void VatesKnowledgeSerializer::setGeometryXML(std::string geomXML) {
+void VatesKnowledgeSerializer::setGeometryXML(const std::string &geomXML) {
   this->m_geomXML = geomXML;
 }
 
@@ -56,7 +57,7 @@ std::string VatesKnowledgeSerializer::createXMLString() const {
     throw std::runtime_error("No workspace name provided on workspace.");
   }
   // Check to see if a function has been provided.
-  if (m_spFunction != NULL) {
+  if (m_spFunction) {
     return std::string(
         MDGeometryXMLDefinitions::workspaceInstructionXMLTagStart() +
         m_wsNameXML + m_wsLocationXML + m_geomXML +
@@ -81,7 +82,7 @@ const std::string &VatesKnowledgeSerializer::getWorkspaceGeometry() const {
 }
 
 bool VatesKnowledgeSerializer::hasFunctionInfo() const {
-  return NULL != m_spFunction.get();
+  return static_cast<bool>(m_spFunction);
 }
 
 bool VatesKnowledgeSerializer::hasGeometryInfo() const {
diff --git a/Vates/VatesAPI/src/ViewFrustum.cpp b/Vates/VatesAPI/src/ViewFrustum.cpp
index a7b895bd9904d51b8a9f98a714534306ad88a6ca..61d7d25b0cc8d6cb4f5fb3cacda98718c77f9db1 100644
--- a/Vates/VatesAPI/src/ViewFrustum.cpp
+++ b/Vates/VatesAPI/src/ViewFrustum.cpp
@@ -17,9 +17,11 @@ namespace VATES {
  * @param farPlane The far plane.
  * @param nearPlane The near plane.
  */
-ViewFrustum::ViewFrustum(const LeftPlane leftPlane, const RightPlane rightPlane,
-                         const BottomPlane bottomPlane, const TopPlane topPlane,
-                         const FarPlane farPlane, const NearPlane nearPlane)
+ViewFrustum::ViewFrustum(const LeftPlane &leftPlane,
+                         const RightPlane &rightPlane,
+                         const BottomPlane &bottomPlane,
+                         const TopPlane &topPlane, const FarPlane &farPlane,
+                         const NearPlane &nearPlane)
     : m_leftPlane(leftPlane), m_rightPlane(rightPlane), m_topPlane(topPlane),
       m_bottomPlane(bottomPlane), m_farPlane(farPlane), m_nearPlane(nearPlane) {
 }
diff --git a/Vates/VatesAPI/src/vtkDataSetFactory.cpp b/Vates/VatesAPI/src/vtkDataSetFactory.cpp
index 57fdf45b78bc3783e08e2bd06526517a6e84b6c4..56515c1b1bd2a1348b4eff24e4f42a1a90486222 100644
--- a/Vates/VatesAPI/src/vtkDataSetFactory.cpp
+++ b/Vates/VatesAPI/src/vtkDataSetFactory.cpp
@@ -1,6 +1,7 @@
 #include "MantidVatesAPI/vtkDataSetFactory.h"
 #include "MantidVatesAPI/ProgressAction.h"
 #include <stdexcept>
+#include <utility>
 
 namespace Mantid {
 namespace VATES {
@@ -51,7 +52,7 @@ Convenience function. Creates an output visualisation data set in one-shot.
 vtkSmartPointer<vtkDataSet>
 vtkDataSetFactory::oneStepCreate(Mantid::API::Workspace_sptr ws,
                                  ProgressAction &progressUpdater) {
-  this->initialize(ws);
+  this->initialize(std::move(ws));
   return this->create(progressUpdater);
 }
 
diff --git a/Vates/VatesAPI/src/vtkDataSetToImplicitFunction.cpp b/Vates/VatesAPI/src/vtkDataSetToImplicitFunction.cpp
index 829079bec7953d933752f5273f5d47554e510352..415eda9a6e4a4e8ab46b868084d0b3ddc1783e7e 100644
--- a/Vates/VatesAPI/src/vtkDataSetToImplicitFunction.cpp
+++ b/Vates/VatesAPI/src/vtkDataSetToImplicitFunction.cpp
@@ -26,7 +26,7 @@ Constructor
 */
 vtkDataSetToImplicitFunction::vtkDataSetToImplicitFunction(vtkDataSet *dataSet)
     : m_dataset(dataSet) {
-  if (m_dataset == NULL) {
+  if (!m_dataset) {
     throw std::runtime_error(
         "Tried to construct vtkDataSetToImplicitFunction with NULL vtkDataSet");
   }
@@ -51,7 +51,7 @@ Mantid::Geometry::MDImplicitFunction *vtkDataSetToImplicitFunction::execute() {
     Poco::XML::Element *pRootElem = pDoc->documentElement();
     Poco::XML::Element *functionElem = pRootElem->getChildElement(
         MDGeometryXMLDefinitions::functionElementName());
-    if (NULL != functionElem) {
+    if (functionElem) {
       auto existingFunction =
           std::unique_ptr<Mantid::Geometry::MDImplicitFunction>(
               Mantid::API::ImplicitFunctionFactory::Instance().createUnwrapped(
diff --git a/Vates/VatesAPI/src/vtkDataSetToNonOrthogonalDataSet.cpp b/Vates/VatesAPI/src/vtkDataSetToNonOrthogonalDataSet.cpp
index 14217faf1e2d9c2fd0a315dfe980d1f2ea1a58ab..03ce5038c7936d1ca7c51bfdc4100ae86caecda8 100644
--- a/Vates/VatesAPI/src/vtkDataSetToNonOrthogonalDataSet.cpp
+++ b/Vates/VatesAPI/src/vtkDataSetToNonOrthogonalDataSet.cpp
@@ -10,23 +10,25 @@
 #include "MantidVatesAPI/ADSWorkspaceProvider.h"
 #include "MantidVatesAPI/vtkDataSetToWsName.h"
 
-#include <vtkPointSet.h>
+#include "vtkSMPTools.h"
+#include "vtkVector.h"
+#include <vtkDataObject.h>
 #include <vtkDataSet.h>
+#include <vtkDoubleArray.h>
 #include <vtkFieldData.h>
 #include <vtkFloatArray.h>
-#include <vtkDoubleArray.h>
 #include <vtkMatrix3x3.h>
-#include "vtkVector.h"
+#include <vtkMatrix4x4.h>
 #include <vtkNew.h>
+#include <vtkPVChangeOfBasisHelper.h>
+#include <vtkPointSet.h>
 #include <vtkPoints.h>
-#include <vtkDataObject.h>
-#include <vtkMatrix4x4.h>
 #include <vtkSmartPointer.h>
-#include <vtkPVChangeOfBasisHelper.h>
 
 #include <vtkPointData.h>
 #include "vtkNew.h"
 
+#include <algorithm>
 #include <boost/algorithm/string/find.hpp>
 #include <stdexcept>
 
@@ -73,21 +75,6 @@ void addChangeOfBasisMatrixToFieldData(
 namespace Mantid {
 namespace VATES {
 
-/**
- * This function constructs and executes the helper class.
- * @param dataset : The VTK data to modify
- * @param name : The MDWorkspace containing the information to construct.
- * @param workspaceProvider: The provider of one or multiple workspaces.
-
- */
-void vtkDataSetToNonOrthogonalDataSet::exec(
-    vtkDataSet *dataset, std::string name,
-    std::unique_ptr<WorkspaceProvider> workspaceProvider) {
-  vtkDataSetToNonOrthogonalDataSet temp(dataset, name,
-                                        std::move(workspaceProvider));
-  temp.execute();
-}
-
 /**
  * This is the private class constructor.
  * @param dataset : The VTK data to modify
@@ -101,7 +88,7 @@ vtkDataSetToNonOrthogonalDataSet::vtkDataSetToNonOrthogonalDataSet(
       m_basisNorm(), m_basisX(1, 0, 0), m_basisY(0, 1, 0), m_basisZ(0, 0, 1),
       m_coordType(Kernel::HKL),
       m_workspaceProvider(std::move(workspaceProvider)) {
-  if (NULL == m_dataSet) {
+  if (!m_dataSet) {
     throw std::runtime_error("Cannot construct "
                              "vtkDataSetToNonOrthogonalDataSet with null VTK "
                              "dataset");
@@ -118,10 +105,29 @@ vtkDataSetToNonOrthogonalDataSet::vtkDataSetToNonOrthogonalDataSet(
  */
 vtkDataSetToNonOrthogonalDataSet::~vtkDataSetToNonOrthogonalDataSet() {}
 
-void vtkDataSetToNonOrthogonalDataSet::execute() {
+namespace {
+struct Worker {
+  Mantid::coord_t *m_skew;
+  vtkFloatArray *m_pts;
+  Worker(Mantid::coord_t *skew, vtkFloatArray *pts)
+      : m_skew(skew), m_pts(pts) {}
+  void operator()(vtkIdType begin, vtkIdType end) {
+    float in[3], out[3];
+    for (vtkIdType index = begin; index < end; ++index) {
+      m_pts->GetTypedTuple(index, in);
+      out[0] = in[0] * m_skew[0] + in[1] * m_skew[1] + in[2] * m_skew[2];
+      out[1] = in[0] * m_skew[3] + in[1] * m_skew[4] + in[2] * m_skew[5];
+      out[2] = in[0] * m_skew[6] + in[1] * m_skew[7] + in[2] * m_skew[8];
+      m_pts->SetTypedTuple(index, out);
+    }
+  }
+};
+} // end anon namespace
+
+void vtkDataSetToNonOrthogonalDataSet::execute(ProgressAction *progress) {
   // Downcast to a vtkPointSet
   vtkPointSet *data = vtkPointSet::SafeDownCast(m_dataSet);
-  if (NULL == data) {
+  if (!data) {
     throw std::runtime_error("VTK dataset does not inherit from vtkPointSet");
   }
 
@@ -228,22 +234,19 @@ void vtkDataSetToNonOrthogonalDataSet::execute() {
 
   // Get the original points
   vtkFloatArray *points =
-      vtkFloatArray::SafeDownCast(data->GetPoints()->GetData());
-  if (points == NULL) {
+      vtkFloatArray::FastDownCast(data->GetPoints()->GetData());
+  if (!points) {
     throw std::runtime_error("Failed to cast vtkDataArray to vtkFloatArray.");
   } else if (points->GetNumberOfComponents() != 3) {
     throw std::runtime_error("points array must have 3 components.");
   }
 
-  float *end = points->GetPointer(points->GetNumberOfTuples() * 3);
-  for (float *it = points->GetPointer(0); it < end; std::advance(it, 3)) {
-    float v1 = it[0];
-    float v2 = it[1];
-    float v3 = it[2];
-    it[0] = v1 * skew[0] + v2 * skew[1] + v3 * skew[2];
-    it[1] = v1 * skew[3] + v2 * skew[4] + v3 * skew[5];
-    it[2] = v1 * skew[6] + v2 * skew[7] + v3 * skew[8];
-  }
+  Worker func(skew, points);
+  if (progress)
+    progress->eventRaised(0.67);
+  vtkSMPTools::For(0, points->GetNumberOfTuples(), func);
+  if (progress)
+    progress->eventRaised(1.0);
   this->updateMetaData(data);
 }
 
diff --git a/Vates/VatesAPI/src/vtkDataSetToScaledDataSet.cpp b/Vates/VatesAPI/src/vtkDataSetToScaledDataSet.cpp
index bb5ec8cfc4db24af64147f84f23456b083edc7c0..b6631234d7f6fc2ffa2c49ee08d0e1afc35d5a3c 100644
--- a/Vates/VatesAPI/src/vtkDataSetToScaledDataSet.cpp
+++ b/Vates/VatesAPI/src/vtkDataSetToScaledDataSet.cpp
@@ -71,12 +71,12 @@ vtkPointSet *vtkDataSetToScaledDataSet::execute(double xScale, double yScale,
                                                 vtkPointSet *inputData,
                                                 vtkPointSet *outputData) {
 
-  if (NULL == inputData) {
+  if (!inputData) {
     throw std::runtime_error("Cannot construct vtkDataSetToScaledDataSet with "
                              "NULL input vtkPointSet");
   }
 
-  if (outputData == NULL) {
+  if (!outputData) {
     outputData = inputData->NewInstance();
   }
 
@@ -85,11 +85,11 @@ vtkPointSet *vtkDataSetToScaledDataSet::execute(double xScale, double yScale,
   vtkNew<vtkPoints> newPoints;
 
   vtkFloatArray *oldPointsArray =
-      vtkFloatArray::SafeDownCast(points->GetData());
+      vtkFloatArray::FastDownCast(points->GetData());
   vtkFloatArray *newPointsArray =
-      vtkFloatArray::SafeDownCast(newPoints->GetData());
+      vtkFloatArray::FastDownCast(newPoints->GetData());
 
-  if (oldPointsArray == NULL || newPointsArray == NULL) {
+  if (!oldPointsArray || !newPointsArray) {
     throw std::runtime_error("Failed to cast vtkDataArray to vtkFloatArray.");
   } else if (oldPointsArray->GetNumberOfComponents() != 3 ||
              newPointsArray->GetNumberOfComponents() != 3) {
diff --git a/Vates/VatesAPI/src/vtkDataSetToWsLocation.cpp b/Vates/VatesAPI/src/vtkDataSetToWsLocation.cpp
index 6a7d17d65c06372421b13fad48d0e8e754146c13..8d55fdd3157b76919e9eaff5d73eea1ce1859ede 100644
--- a/Vates/VatesAPI/src/vtkDataSetToWsLocation.cpp
+++ b/Vates/VatesAPI/src/vtkDataSetToWsLocation.cpp
@@ -26,7 +26,7 @@ Constructor
 */
 vtkDataSetToWsLocation::vtkDataSetToWsLocation(vtkDataSet *dataSet)
     : m_dataset(dataSet) {
-  if (m_dataset == NULL) {
+  if (!m_dataset) {
     throw std::runtime_error(
         "Tried to construct vtkDataSetToWsLocation with NULL vtkDataSet");
   }
@@ -47,7 +47,7 @@ std::string vtkDataSetToWsLocation::execute() {
   Poco::XML::Element *pRootElem = pDoc->documentElement();
   Poco::XML::Element *wsLocationElem = pRootElem->getChildElement(
       MDGeometryXMLDefinitions::workspaceLocationElementName());
-  if (wsLocationElem == NULL) {
+  if (!wsLocationElem) {
     throw std::runtime_error(
         "The element containing the workspace location must be present.");
   }
diff --git a/Vates/VatesAPI/src/vtkDataSetToWsName.cpp b/Vates/VatesAPI/src/vtkDataSetToWsName.cpp
index 2393a03db255807abb4251b17bff54568efdedd5..f4a88bc8efa387a9f01027a6f4516bec78bc2717 100644
--- a/Vates/VatesAPI/src/vtkDataSetToWsName.cpp
+++ b/Vates/VatesAPI/src/vtkDataSetToWsName.cpp
@@ -26,7 +26,7 @@ Constructor
 */
 vtkDataSetToWsName::vtkDataSetToWsName(vtkDataSet *dataSet)
     : m_dataset(dataSet) {
-  if (m_dataset == NULL) {
+  if (!m_dataset) {
     throw std::runtime_error(
         "Tried to construct vtkDataSetToWsName with NULL vtkDataSet");
   }
@@ -47,7 +47,7 @@ std::string vtkDataSetToWsName::execute() {
   Poco::XML::Element *pRootElem = pDoc->documentElement();
   Poco::XML::Element *wsNameElem = pRootElem->getChildElement(
       MDGeometryXMLDefinitions::workspaceNameElementName());
-  if (wsNameElem == NULL) {
+  if (!wsNameElem) {
     throw std::runtime_error(
         "The element containing the workspace name must be present.");
   }
diff --git a/Vates/VatesAPI/src/vtkMD0DFactory.cpp b/Vates/VatesAPI/src/vtkMD0DFactory.cpp
index 6434862d90305f29d57e7488fd8fb6ab23f137f4..6d66eefdf766e0c9df935973396e7c0dfe3d96b6 100644
--- a/Vates/VatesAPI/src/vtkMD0DFactory.cpp
+++ b/Vates/VatesAPI/src/vtkMD0DFactory.cpp
@@ -37,7 +37,8 @@ vtkSmartPointer<vtkDataSet> vtkMD0DFactory::create(ProgressAction &) const {
 }
 
 /// Initalize with a target workspace.
-void vtkMD0DFactory::initialize(Mantid::API::Workspace_sptr) {}
+void vtkMD0DFactory::initialize(
+    const Mantid::API::Workspace_sptr & /*workspace*/) {}
 
 /// Validate the workspace
 void vtkMD0DFactory::validate() const {}
diff --git a/Vates/VatesAPI/src/vtkMDHexFactory.cpp b/Vates/VatesAPI/src/vtkMDHexFactory.cpp
index 282e1c3d912c4c6427af3b2d15f80ab6befe105f..24039b1bd8485ee05c4b0dcf0697e131bfc81e39 100644
--- a/Vates/VatesAPI/src/vtkMDHexFactory.cpp
+++ b/Vates/VatesAPI/src/vtkMDHexFactory.cpp
@@ -31,16 +31,13 @@ namespace Mantid {
 namespace VATES {
 
 /*Constructor
-  @param thresholdRange : Threshold range strategy
   @param normalizationOption : Info object setting how normalization should be
   done.
   @param maxDepth : Maximum depth to search to
   */
-vtkMDHexFactory::vtkMDHexFactory(ThresholdRange_scptr thresholdRange,
-                                 const VisualNormalization normalizationOption,
+vtkMDHexFactory::vtkMDHexFactory(const VisualNormalization normalizationOption,
                                  const size_t maxDepth)
-    : m_thresholdRange(thresholdRange),
-      m_normalizationOption(normalizationOption), m_maxDepth(maxDepth),
+    : m_normalizationOption(normalizationOption), m_maxDepth(maxDepth),
       slice(false), m_time(0) {}
 
 /// Destructor
@@ -81,7 +78,7 @@ void vtkMDHexFactory::doCreate(
 
   // Create 8 points per box.
   vtkNew<vtkPoints> points;
-  vtkFloatArray *pointsArray = vtkFloatArray::SafeDownCast(points->GetData());
+  vtkFloatArray *pointsArray = vtkFloatArray::FastDownCast(points->GetData());
   float *pointsPtr = pointsArray->WritePointer(0, numBoxes * 8 * 3);
 
   // One scalar per box
@@ -120,8 +117,7 @@ void vtkMDHexFactory::doCreate(
       API::IMDNode *box = boxes[i];
       Mantid::signal_t signal_normalized = (box->*normFunction)();
 
-      if (std::isfinite(signal_normalized) &&
-          m_thresholdRange->inRange(signal_normalized)) {
+      if (std::isfinite(signal_normalized)) {
         // Cache the signal and using of it
         signalCache[i] = static_cast<float>(signal_normalized);
         useBox[i] = true;
@@ -205,7 +201,7 @@ vtkSmartPointer<vtkDataSet>
 vtkMDHexFactory::create(ProgressAction &progressUpdating) const {
   this->dataSet = tryDelegatingCreation<IMDEventWorkspace, 3>(
       m_workspace, progressUpdating, false);
-  if (this->dataSet != NULL) {
+  if (this->dataSet) {
     return this->dataSet;
   } else {
     IMDEventWorkspace_sptr imdws =
@@ -258,7 +254,7 @@ vtkMDHexFactory::create(ProgressAction &progressUpdating) const {
  * Get the next highest bin boundary
  */
 coord_t
-vtkMDHexFactory::getNextBinBoundary(IMDEventWorkspace_sptr imdws) const {
+vtkMDHexFactory::getNextBinBoundary(const IMDEventWorkspace_sptr &imdws) const {
   auto t_dim = imdws->getTDimension();
   coord_t bin_width = t_dim->getBinWidth();
   coord_t dim_min = t_dim->getMinimum();
@@ -268,8 +264,8 @@ vtkMDHexFactory::getNextBinBoundary(IMDEventWorkspace_sptr imdws) const {
 /*
  * Get the previous bin boundary, or the current one if m_time is on a boundary
  */
-coord_t
-vtkMDHexFactory::getPreviousBinBoundary(IMDEventWorkspace_sptr imdws) const {
+coord_t vtkMDHexFactory::getPreviousBinBoundary(
+    const IMDEventWorkspace_sptr &imdws) const {
   auto t_dim = imdws->getTDimension();
   coord_t bin_width = t_dim->getBinWidth();
   coord_t dim_min = t_dim->getMinimum();
@@ -299,13 +295,9 @@ dataobjects (workspaces) to run against at a later time. If workspace is not an
 IMDEventWorkspace, attempts to use any run-time successor set.
 @Param ws : Workspace to use.
 */
-void vtkMDHexFactory::initialize(Mantid::API::Workspace_sptr ws) {
+void vtkMDHexFactory::initialize(const Mantid::API::Workspace_sptr &ws) {
   IMDEventWorkspace_sptr imdws = doInitialize<IMDEventWorkspace, 3>(ws, false);
   m_workspace = imdws;
-
-  // Setup range values according to whatever strategy object has been injected.
-  m_thresholdRange->setWorkspace(ws);
-  m_thresholdRange->calculate();
 }
 
 /// Validate the current object.
diff --git a/Vates/VatesAPI/src/vtkMDHistoHex4DFactory.cpp b/Vates/VatesAPI/src/vtkMDHistoHex4DFactory.cpp
index 5851197f8bad4117365f35c50e1508c377f93eb8..908620f13c145e673ba7657b7316acf364577ff6 100644
--- a/Vates/VatesAPI/src/vtkMDHistoHex4DFactory.cpp
+++ b/Vates/VatesAPI/src/vtkMDHistoHex4DFactory.cpp
@@ -15,10 +15,8 @@ namespace VATES {
 
 template <typename TimeMapper>
 vtkMDHistoHex4DFactory<TimeMapper>::vtkMDHistoHex4DFactory(
-    ThresholdRange_scptr thresholdRange,
     const VisualNormalization normalization, const double timestep)
-    : vtkMDHistoHexFactory(thresholdRange, normalization),
-      m_timestep(timestep) {}
+    : vtkMDHistoHexFactory(normalization), m_timestep(timestep) {}
 
 /**
 Assigment operator
@@ -30,7 +28,6 @@ vtkMDHistoHex4DFactory<TimeMapper> &vtkMDHistoHex4DFactory<TimeMapper>::
 operator=(const vtkMDHistoHex4DFactory<TimeMapper> &other) {
   if (this != &other) {
     this->m_normalizationOption = other.m_normalizationOption;
-    this->m_thresholdRange = other.m_thresholdRange;
     this->m_workspace = other.m_workspace;
     this->m_timestep = other.m_timestep;
     this->m_timeMapper = other.m_timeMapper;
@@ -50,19 +47,14 @@ vtkMDHistoHex4DFactory<TimeMapper>::vtkMDHistoHex4DFactory(
 
 template <typename TimeMapper>
 void vtkMDHistoHex4DFactory<TimeMapper>::initialize(
-    Mantid::API::Workspace_sptr workspace) {
+    const Mantid::API::Workspace_sptr &workspace) {
   m_workspace = doInitialize<MDHistoWorkspace, 4>(workspace);
-  if (m_workspace != NULL) {
+  if (m_workspace) {
     double tMax = m_workspace->getTDimension()->getMaximum();
     double tMin = m_workspace->getTDimension()->getMinimum();
     size_t nbins = m_workspace->getTDimension()->getNBins();
 
     m_timeMapper = TimeMapper::construct(tMin, tMax, nbins);
-
-    // Setup range values according to whatever strategy object has been
-    // injected.
-    m_thresholdRange->setWorkspace(workspace);
-    m_thresholdRange->calculate();
   }
 }
 
diff --git a/Vates/VatesAPI/src/vtkMDHistoHexFactory.cpp b/Vates/VatesAPI/src/vtkMDHistoHexFactory.cpp
index 4793d06e3b40e222435904d1702acdfddf9a2b8d..ae523f6b33a090c95db3869e258535b3d6f1775b 100644
--- a/Vates/VatesAPI/src/vtkMDHistoHexFactory.cpp
+++ b/Vates/VatesAPI/src/vtkMDHistoHexFactory.cpp
@@ -1,8 +1,6 @@
 #include "MantidAPI/IMDWorkspace.h"
 #include "MantidKernel/CPUTimer.h"
 #include "MantidDataObjects/MDHistoWorkspace.h"
-#include "MantidDataObjects/MDHistoWorkspaceIterator.h"
-
 #include "MantidVatesAPI/vtkMDHWSignalArray.h"
 #include "MantidVatesAPI/Common.h"
 #include "MantidVatesAPI/Normalization.h"
@@ -12,10 +10,12 @@
 #include "MantidAPI/NullCoordTransform.h"
 #include "MantidKernel/ReadLock.h"
 
+#include "vtkDoubleArray.h"
+#include "vtkFloatArray.h"
 #include "vtkNew.h"
+#include "vtkSMPTools.h"
 #include "vtkStructuredGrid.h"
-#include "vtkFloatArray.h"
-#include "vtkDoubleArray.h"
+#include "vtkUnsignedCharArray.h"
 
 #include <cmath>
 
@@ -29,10 +29,8 @@ namespace Mantid {
 namespace VATES {
 
 vtkMDHistoHexFactory::vtkMDHistoHexFactory(
-    ThresholdRange_scptr thresholdRange,
     const VisualNormalization normalizationOption)
-    : m_normalizationOption(normalizationOption),
-      m_thresholdRange(thresholdRange) {}
+    : m_normalizationOption(normalizationOption) {}
 
 /**
 Assigment operator
@@ -43,7 +41,6 @@ vtkMDHistoHexFactory &vtkMDHistoHexFactory::
 operator=(const vtkMDHistoHexFactory &other) {
   if (this != &other) {
     this->m_normalizationOption = other.m_normalizationOption;
-    this->m_thresholdRange = other.m_thresholdRange;
     this->m_workspace = other.m_workspace;
   }
   return *this;
@@ -55,27 +52,82 @@ Copy Constructor
 */
 vtkMDHistoHexFactory::vtkMDHistoHexFactory(const vtkMDHistoHexFactory &other) {
   this->m_normalizationOption = other.m_normalizationOption;
-  this->m_thresholdRange = other.m_thresholdRange;
   this->m_workspace = other.m_workspace;
 }
 
-void vtkMDHistoHexFactory::initialize(Mantid::API::Workspace_sptr workspace) {
+void vtkMDHistoHexFactory::initialize(
+    const Mantid::API::Workspace_sptr &workspace) {
   m_workspace = doInitialize<MDHistoWorkspace, 3>(workspace);
-
-  // Setup range values according to whatever strategy object has been injected.
-  m_thresholdRange->setWorkspace(workspace);
-  m_thresholdRange->calculate();
 }
 
 void vtkMDHistoHexFactory::validateWsNotNull() const {
-
-  if (NULL == m_workspace.get()) {
+  if (!m_workspace) {
     throw std::runtime_error("IMDWorkspace is null");
   }
 }
 
 void vtkMDHistoHexFactory::validate() const { validateWsNotNull(); }
 
+namespace {
+struct CellGhostArrayWorker {
+  vtkMDHWSignalArray<double> *m_signal;
+  vtkUnsignedCharArray *m_cga;
+  CellGhostArrayWorker(vtkMDHWSignalArray<double> *signal,
+                       vtkUnsignedCharArray *cga)
+      : m_signal(signal), m_cga(cga) {}
+  void operator()(vtkIdType begin, vtkIdType end) {
+    for (vtkIdType index = begin; index < end; ++index) {
+      if (!std::isfinite(m_signal->GetValue(index))) {
+        m_cga->SetValue(index, m_cga->GetValue(index) |
+                                   vtkDataSetAttributes::HIDDENCELL);
+      }
+    }
+  }
+};
+
+struct PointsWorker {
+  vtkPoints *m_pts;
+  coord_t incrementX, incrementY, incrementZ;
+  coord_t minX, minY, minZ;
+  vtkIdType nPointsX, nPointsY;
+  PointsWorker(Mantid::DataObjects::MDHistoWorkspace &ws, vtkPoints *pts)
+      : m_pts(pts) {
+    int nBinsX = static_cast<int>(ws.getXDimension()->getNBins());
+    int nBinsY = static_cast<int>(ws.getYDimension()->getNBins());
+    int nBinsZ = static_cast<int>(ws.getZDimension()->getNBins());
+
+    minX = ws.getXDimension()->getMinimum();
+    minY = ws.getYDimension()->getMinimum();
+    minZ = ws.getZDimension()->getMinimum();
+    coord_t maxX = ws.getXDimension()->getMaximum();
+    coord_t maxY = ws.getYDimension()->getMaximum();
+    coord_t maxZ = ws.getZDimension()->getMaximum();
+
+    incrementX = (maxX - minX) / static_cast<coord_t>(nBinsX);
+    incrementY = (maxY - minY) / static_cast<coord_t>(nBinsY);
+    incrementZ = (maxZ - minZ) / static_cast<coord_t>(nBinsZ);
+
+    nPointsX = nBinsX + 1;
+    nPointsY = nBinsY + 1;
+  }
+  void operator()(vtkIdType begin, vtkIdType end) {
+    float in[3];
+    vtkIdType pos = begin * nPointsX * nPointsY;
+    for (int z = static_cast<int>(begin); z < static_cast<int>(end); ++z) {
+      in[2] = minZ + static_cast<coord_t>(z) * incrementZ;
+      for (int y = 0; y < nPointsY; ++y) {
+        in[1] = minY + static_cast<coord_t>(y) * incrementY;
+        for (int x = 0; x < nPointsX; ++x) {
+          in[0] = minX + static_cast<coord_t>(x) * incrementX;
+          m_pts->SetPoint(pos, in);
+          ++pos;
+        }
+      }
+    }
+  }
+};
+} // end anon namespace
+
 /** Method for creating a 3D or 4D data set
  *
  * @param timestep :: index of the time step (4th dimension) in the workspace.
@@ -86,7 +138,7 @@ void vtkMDHistoHexFactory::validate() const { validateWsNotNull(); }
  */
 vtkSmartPointer<vtkDataSet>
 vtkMDHistoHexFactory::create3Dor4D(size_t timestep,
-                                   ProgressAction &progressUpdate) const {
+                                   ProgressAction &progress) const {
   // Acquire a scoped read-only lock to the workspace (prevent segfault from
   // algos modifying ws)
   ReadLock lock(*m_workspace);
@@ -109,87 +161,40 @@ vtkMDHistoHexFactory::create3Dor4D(size_t timestep,
 
   const int imageSize = (nBinsX) * (nBinsY) * (nBinsZ);
 
-  vtkSmartPointer<vtkStructuredGrid> visualDataSet =
-      vtkSmartPointer<vtkStructuredGrid>::New();
+  auto visualDataSet = vtkSmartPointer<vtkStructuredGrid>::New();
   visualDataSet->SetDimensions(nBinsX + 1, nBinsY + 1, nBinsZ + 1);
 
   // Array with true where the voxel should be shown
-  double progressFactor = 0.5 / double(imageSize);
 
   std::size_t offset = 0;
   if (nDims == 4) {
     offset = timestep * indexMultiplier[2];
   }
 
-  std::unique_ptr<MDHistoWorkspaceIterator> iterator(
-      dynamic_cast<MDHistoWorkspaceIterator *>(createIteratorWithNormalization(
-          m_normalizationOption, m_workspace.get())));
-
   vtkNew<vtkMDHWSignalArray<double>> signal;
 
   signal->SetName(vtkDataSetFactory::ScalarName.c_str());
-  signal->InitializeArray(std::move(iterator), offset, imageSize);
+  signal->InitializeArray(m_workspace.get(), m_normalizationOption, offset);
   visualDataSet->GetCellData()->SetScalars(signal.GetPointer());
+  auto cga = visualDataSet->AllocateCellGhostArray();
 
-  for (vtkIdType index = 0; index < imageSize; ++index) {
-    progressUpdate.eventRaised(double(index) * progressFactor);
-    double signalScalar = signal->GetValue(index);
-    bool maskValue = (!std::isfinite(signalScalar) ||
-                      !m_thresholdRange->inRange(signalScalar));
-    if (maskValue) {
-      visualDataSet->BlankCell(index);
-    }
-  }
+  CellGhostArrayWorker cgafunc(signal.GetPointer(), cga);
+  progress.eventRaised(0.0);
+  vtkSMPTools::For(0, imageSize, cgafunc);
+  progress.eventRaised(0.33);
 
   vtkNew<vtkPoints> points;
-
-  Mantid::coord_t in[2];
-
-  const coord_t maxX = m_workspace->getXDimension()->getMaximum();
-  const coord_t minX = m_workspace->getXDimension()->getMinimum();
-  const coord_t maxY = m_workspace->getYDimension()->getMaximum();
-  const coord_t minY = m_workspace->getYDimension()->getMinimum();
-  const coord_t maxZ = m_workspace->getZDimension()->getMaximum();
-  const coord_t minZ = m_workspace->getZDimension()->getMinimum();
-
-  const coord_t incrementX = (maxX - minX) / static_cast<coord_t>(nBinsX);
-  const coord_t incrementY = (maxY - minY) / static_cast<coord_t>(nBinsY);
-  const coord_t incrementZ = (maxZ - minZ) / static_cast<coord_t>(nBinsZ);
-
   const vtkIdType nPointsX = nBinsX + 1;
   const vtkIdType nPointsY = nBinsY + 1;
   const vtkIdType nPointsZ = nBinsZ + 1;
+  points->SetNumberOfPoints(nPointsX * nPointsY * nPointsZ);
 
-  vtkFloatArray *pointsarray = vtkFloatArray::SafeDownCast(points->GetData());
-  if (pointsarray == NULL) {
-    throw std::runtime_error("Failed to cast vtkDataArray to vtkFloatArray.");
-  } else if (pointsarray->GetNumberOfComponents() != 3) {
-    throw std::runtime_error("points array must have 3 components.");
-  }
-  float *it = pointsarray->WritePointer(0, nPointsX * nPointsY * nPointsZ * 3);
-  // Array with the point IDs (only set where needed)
-  progressFactor = 0.5 / static_cast<double>(nPointsZ);
-  double progressOffset = 0.5;
-  for (int z = 0; z < nPointsZ; z++) {
-    // Report progress updates for the last 50%
-    progressUpdate.eventRaised(double(z) * progressFactor + progressOffset);
-    in[1] = (minZ + (static_cast<coord_t>(z) *
-                     incrementZ)); // Calculate increment in z;
-    for (int y = 0; y < nPointsY; y++) {
-      in[0] = (minY + (static_cast<coord_t>(y) *
-                       incrementY)); // Calculate increment in y;
-      for (int x = 0; x < nPointsX; x++) {
-        it[0] = (minX + (static_cast<coord_t>(x) *
-                         incrementX)); // Calculate increment in x;
-        it[1] = in[0];
-        it[2] = in[1];
-        std::advance(it, 3);
-      }
-    }
-  }
+  PointsWorker ptsfunc(*m_workspace, points.GetPointer());
+  vtkSMPTools::For(0, nPointsZ, ptsfunc);
+  progress.eventRaised(0.67);
 
   visualDataSet->SetPoints(points.GetPointer());
-  visualDataSet->Register(NULL);
+  visualDataSet->Register(nullptr);
   visualDataSet->Squeeze();
 
   // Hedge against empty data sets
@@ -212,7 +217,7 @@ vtkSmartPointer<vtkDataSet>
 vtkMDHistoHexFactory::create(ProgressAction &progressUpdating) const {
   auto product =
       tryDelegatingCreation<MDHistoWorkspace, 3>(m_workspace, progressUpdating);
-  if (product != NULL) {
+  if (product) {
     return product;
   } else {
     // Create in 3D mode
diff --git a/Vates/VatesAPI/src/vtkMDHistoLineFactory.cpp b/Vates/VatesAPI/src/vtkMDHistoLineFactory.cpp
index c8bf0e8aa14dd693613fb0b545de3156bb5d8b07..95e55256b9234c1b767ef86d13716fd26231d75a 100644
--- a/Vates/VatesAPI/src/vtkMDHistoLineFactory.cpp
+++ b/Vates/VatesAPI/src/vtkMDHistoLineFactory.cpp
@@ -26,10 +26,8 @@ namespace Mantid {
 namespace VATES {
 
 vtkMDHistoLineFactory::vtkMDHistoLineFactory(
-    ThresholdRange_scptr thresholdRange,
     const VisualNormalization normaliztionOption)
-    : m_normalizationOption(normaliztionOption),
-      m_thresholdRange(thresholdRange) {}
+    : m_normalizationOption(normaliztionOption) {}
 
 /**
 Assigment operator
@@ -40,7 +38,6 @@ vtkMDHistoLineFactory &vtkMDHistoLineFactory::
 operator=(const vtkMDHistoLineFactory &other) {
   if (this != &other) {
     this->m_normalizationOption = other.m_normalizationOption;
-    this->m_thresholdRange = other.m_thresholdRange;
     this->m_workspace = other.m_workspace;
   }
   return *this;
@@ -53,7 +50,6 @@ Copy Constructor
 vtkMDHistoLineFactory::vtkMDHistoLineFactory(
     const vtkMDHistoLineFactory &other) {
   this->m_normalizationOption = other.m_normalizationOption;
-  this->m_thresholdRange = other.m_thresholdRange;
   this->m_workspace = other.m_workspace;
 }
 
@@ -114,8 +110,7 @@ vtkMDHistoLineFactory::create(ProgressAction &progressUpdating) const {
       float signalScalar =
           static_cast<float>(m_workspace->getSignalNormalizedAt(i));
 
-      if (!std::isfinite(signalScalar) ||
-          !m_thresholdRange->inRange(signalScalar)) {
+      if (!std::isfinite(signalScalar)) {
         // Flagged so that topological and scalar data is not applied.
         unstructPoint.isSparse = true;
       } else {
@@ -165,16 +160,12 @@ vtkMDHistoLineFactory::create(ProgressAction &progressUpdating) const {
 }
 
 void vtkMDHistoLineFactory::initialize(
-    Mantid::API::Workspace_sptr wspace_sptr) {
+    const Mantid::API::Workspace_sptr &wspace_sptr) {
   m_workspace = this->doInitialize<MDHistoWorkspace, 1>(wspace_sptr);
-
-  // Setup range values according to whatever strategy object has been injected.
-  m_thresholdRange->setWorkspace(wspace_sptr);
-  m_thresholdRange->calculate();
 }
 
 void vtkMDHistoLineFactory::validate() const {
-  if (NULL == m_workspace.get()) {
+  if (!m_workspace) {
     throw std::runtime_error("IMDWorkspace is null");
   }
 }
diff --git a/Vates/VatesAPI/src/vtkMDHistoQuadFactory.cpp b/Vates/VatesAPI/src/vtkMDHistoQuadFactory.cpp
index b460e1183a3bbaa7c5699ad84bbbe65ec660e750..c4b624440b050688790eefd361cae50c5152758f 100644
--- a/Vates/VatesAPI/src/vtkMDHistoQuadFactory.cpp
+++ b/Vates/VatesAPI/src/vtkMDHistoQuadFactory.cpp
@@ -30,10 +30,8 @@ namespace Mantid {
 
 namespace VATES {
 vtkMDHistoQuadFactory::vtkMDHistoQuadFactory(
-    ThresholdRange_scptr thresholdRange,
     const VisualNormalization normalizationOption)
-    : m_normalizationOption(normalizationOption),
-      m_thresholdRange(thresholdRange) {}
+    : m_normalizationOption(normalizationOption) {}
 
 /**
 Assigment operator
@@ -44,7 +42,6 @@ vtkMDHistoQuadFactory &vtkMDHistoQuadFactory::
 operator=(const vtkMDHistoQuadFactory &other) {
   if (this != &other) {
     this->m_normalizationOption = other.m_normalizationOption;
-    this->m_thresholdRange = other.m_thresholdRange;
     this->m_workspace = other.m_workspace;
   }
   return *this;
@@ -57,7 +54,6 @@ Copy Constructor
 vtkMDHistoQuadFactory::vtkMDHistoQuadFactory(
     const vtkMDHistoQuadFactory &other) {
   this->m_normalizationOption = other.m_normalizationOption;
-  this->m_thresholdRange = other.m_thresholdRange;
   this->m_workspace = other.m_workspace;
 }
 
@@ -141,8 +137,7 @@ vtkMDHistoQuadFactory::create(ProgressAction &progressUpdating) const {
             iterator->getNormalizedSignal()); // Get signal normalized as per
                                               // m_normalizationOption
 
-        if (!std::isfinite(signalScalar) ||
-            !m_thresholdRange->inRange(signalScalar)) {
+        if (!std::isfinite(signalScalar)) {
           // out of range
           voxelShown[index] = false;
         } else {
@@ -166,7 +161,7 @@ vtkMDHistoQuadFactory::create(ProgressAction &progressUpdating) const {
 
     // Get the transformation that takes the points in the TRANSFORMED space
     // back into the ORIGINAL (not-rotated) space.
-    Mantid::API::CoordTransform const *transform = NULL;
+    Mantid::API::CoordTransform const *transform = nullptr;
     if (m_useTransform)
       transform = m_workspace->getTransformToOriginal();
 
@@ -239,16 +234,12 @@ vtkMDHistoQuadFactory::create(ProgressAction &progressUpdating) const {
 }
 
 void vtkMDHistoQuadFactory::initialize(
-    Mantid::API::Workspace_sptr wspace_sptr) {
+    const Mantid::API::Workspace_sptr &wspace_sptr) {
   m_workspace = doInitialize<MDHistoWorkspace, 2>(wspace_sptr);
-
-  // Setup range values according to whatever strategy object has been injected.
-  m_thresholdRange->setWorkspace(wspace_sptr);
-  m_thresholdRange->calculate();
 }
 
 void vtkMDHistoQuadFactory::validate() const {
-  if (NULL == m_workspace.get()) {
+  if (!m_workspace) {
     throw std::runtime_error("IMDWorkspace is null");
   }
 }
diff --git a/Vates/VatesAPI/src/vtkMDLineFactory.cpp b/Vates/VatesAPI/src/vtkMDLineFactory.cpp
index 33a028441dcf775e5e952e0808e9bbfd0ebd2ce5..3379a5bf4a51a0d2e2d2ed3cc3b3c96e7aba6c42 100644
--- a/Vates/VatesAPI/src/vtkMDLineFactory.cpp
+++ b/Vates/VatesAPI/src/vtkMDLineFactory.cpp
@@ -29,14 +29,11 @@ namespace Mantid {
 namespace VATES {
 /**
 Constructor
-@param thresholdRange : Thresholding range functor
 @param normalizationOption : Normalization option to use
 */
 vtkMDLineFactory::vtkMDLineFactory(
-    ThresholdRange_scptr thresholdRange,
     const VisualNormalization normalizationOption)
-    : m_thresholdRange(thresholdRange),
-      m_normalizationOption(normalizationOption) {}
+    : m_normalizationOption(normalizationOption) {}
 
 /// Destructor
 vtkMDLineFactory::~vtkMDLineFactory() {}
@@ -99,7 +96,7 @@ vtkMDLineFactory::create(ProgressAction &progressUpdating) const {
     vtkNew<vtkIdList> linePointList;
     linePointList->SetNumberOfIds(2);
 
-    Mantid::API::CoordTransform const *transform = NULL;
+    Mantid::API::CoordTransform const *transform = nullptr;
     if (m_useTransform) {
       transform = imdws->getTransformToOriginal();
     }
@@ -115,8 +112,7 @@ vtkMDLineFactory::create(ProgressAction &progressUpdating) const {
       progressUpdating.eventRaised(double(iBox) * progressFactor);
 
       Mantid::signal_t signal_normalized = it->getNormalizedSignal();
-      if (std::isfinite(signal_normalized) &&
-          m_thresholdRange->inRange(signal_normalized)) {
+      if (std::isfinite(signal_normalized)) {
         useBox[iBox] = true;
         signals->InsertNextValue(static_cast<float>(signal_normalized));
 
@@ -173,7 +169,7 @@ vtkMDLineFactory::create(ProgressAction &progressUpdating) const {
 }
 
 /// Initalize with a target workspace.
-void vtkMDLineFactory::initialize(Mantid::API::Workspace_sptr ws) {
+void vtkMDLineFactory::initialize(const Mantid::API::Workspace_sptr &ws) {
   m_workspace = doInitialize<IMDEventWorkspace, 1>(ws);
 }
 
@@ -184,7 +180,7 @@ std::string vtkMDLineFactory::getFactoryTypeName() const {
 
 /// Template Method pattern to validate the factory before use.
 void vtkMDLineFactory::validate() const {
-  if (NULL == m_workspace.get()) {
+  if (!m_workspace) {
     throw std::runtime_error(
         "vtkMDLineFactory has no workspace to run against");
   }
diff --git a/Vates/VatesAPI/src/vtkMDQuadFactory.cpp b/Vates/VatesAPI/src/vtkMDQuadFactory.cpp
index f8ed9f183d44e17bedd326a40526ffe5c3bf6c92..5fa55dc5f3f50d8d416945a71ad1d0064de4b72f 100644
--- a/Vates/VatesAPI/src/vtkMDQuadFactory.cpp
+++ b/Vates/VatesAPI/src/vtkMDQuadFactory.cpp
@@ -27,10 +27,8 @@ namespace Mantid {
 namespace VATES {
 /// Constructor
 vtkMDQuadFactory::vtkMDQuadFactory(
-    ThresholdRange_scptr thresholdRange,
     const VisualNormalization normalizationOption)
-    : m_thresholdRange(thresholdRange),
-      m_normalizationOption(normalizationOption) {}
+    : m_normalizationOption(normalizationOption) {}
 
 /// Destructor
 vtkMDQuadFactory::~vtkMDQuadFactory() {}
@@ -94,7 +92,7 @@ vtkMDQuadFactory::create(ProgressAction &progressUpdating) const {
     vtkNew<vtkIdList> quadPointList;
     quadPointList->SetNumberOfIds(4);
 
-    Mantid::API::CoordTransform const *transform = NULL;
+    Mantid::API::CoordTransform const *transform = nullptr;
     if (m_useTransform) {
       transform = imdws->getTransformToOriginal();
     }
@@ -110,7 +108,7 @@ vtkMDQuadFactory::create(ProgressAction &progressUpdating) const {
       progressUpdating.eventRaised(progressFactor * double(iBox));
 
       Mantid::signal_t signal = it->getNormalizedSignal();
-      if (std::isfinite(signal) && m_thresholdRange->inRange(signal)) {
+      if (std::isfinite(signal)) {
         useBox[iBox] = true;
         signals->InsertNextValue(static_cast<float>(signal));
 
@@ -169,7 +167,7 @@ vtkMDQuadFactory::create(ProgressAction &progressUpdating) const {
 }
 
 /// Initalize with a target workspace.
-void vtkMDQuadFactory::initialize(Mantid::API::Workspace_sptr ws) {
+void vtkMDQuadFactory::initialize(const Mantid::API::Workspace_sptr &ws) {
   m_workspace = doInitialize<IMDEventWorkspace, 2>(ws);
 }
 
@@ -180,7 +178,7 @@ std::string vtkMDQuadFactory::getFactoryTypeName() const {
 
 /// Template Method pattern to validate the factory before use.
 void vtkMDQuadFactory::validate() const {
-  if (NULL == m_workspace.get()) {
+  if (!m_workspace) {
     throw std::runtime_error(
         "vtkMDQuadFactory has no workspace to run against");
   }
diff --git a/Vates/VatesAPI/src/vtkSplatterPlotFactory.cpp b/Vates/VatesAPI/src/vtkSplatterPlotFactory.cpp
index 8a92822e55fdbafc5cf17b28dc38aa5c2902a19d..a65b23f0e0039334f001063c8bb50496d92ce144 100644
--- a/Vates/VatesAPI/src/vtkSplatterPlotFactory.cpp
+++ b/Vates/VatesAPI/src/vtkSplatterPlotFactory.cpp
@@ -19,6 +19,7 @@
 #include "MantidVatesAPI/Normalization.h"
 
 #include <vtkCellData.h>
+#include <vtkCellType.h>
 #include <vtkFloatArray.h>
 #include <vtkHexahedron.h>
 #include <vtkNew.h>
@@ -43,17 +44,15 @@ namespace Mantid {
 namespace VATES {
 /**
  * Constructor
- * @param thresholdRange : Threshold range strategy
  * @param scalarName : Name for scalar signal array.
  * @param numPoints : Total number of points to create.
  * @param percentToUse : Cutoff for the densest boxes.
  */
-vtkSplatterPlotFactory::vtkSplatterPlotFactory(
-    ThresholdRange_scptr thresholdRange, const std::string &scalarName,
-    const size_t numPoints, const double percentToUse)
-    : m_thresholdRange(thresholdRange), m_scalarName(scalarName),
-      m_numPoints(numPoints), m_buildSortedList(true), m_wsName(""),
-      slice(false), m_time(0.0), m_minValue(0.1), m_maxValue(0.1),
+vtkSplatterPlotFactory::vtkSplatterPlotFactory(const std::string &scalarName,
+                                               const size_t numPoints,
+                                               const double percentToUse)
+    : m_scalarName(scalarName), m_numPoints(numPoints), m_buildSortedList(true),
+      m_wsName(""), slice(false), m_time(0.0), m_minValue(0.1), m_maxValue(0.1),
       m_metaDataExtractor(new MetaDataExtractorUtils()),
       m_metadataJsonManager(new MetadataJsonManager()),
       m_vatesConfigurations(new VatesConfigurations()) {
@@ -158,7 +157,7 @@ void vtkSplatterPlotFactory::doCreate(
 
   // Create the point list, one position for each point actually used
   vtkNew<vtkPoints> points;
-  vtkFloatArray *pointsArray = vtkFloatArray::SafeDownCast(points->GetData());
+  vtkFloatArray *pointsArray = vtkFloatArray::FastDownCast(points->GetData());
   if (!pointsArray) {
     throw std::runtime_error("Failed to cast vtkDataArray to vtkFloatArray.");
   }
@@ -213,6 +212,12 @@ void vtkSplatterPlotFactory::doCreate(
   // Add points and scalars
   visualDataSet->SetPoints(points.GetPointer());
   visualDataSet->GetPointData()->SetScalars(signal.GetPointer());
+  visualDataSet->GetCellData()->SetScalars(signal.GetPointer());
+
+  visualDataSet->Allocate(points->GetNumberOfPoints());
+  for (vtkIdType ptId = 0; ptId < points->GetNumberOfPoints(); ++ptId) {
+    visualDataSet->InsertNextCell(VTK_VERTEX, 1, &ptId);
+  }
 }
 
 /**
@@ -245,22 +250,22 @@ void vtkSplatterPlotFactory::sortBoxesByDecreasingSignal(
  * scalar data.
  */
 void vtkSplatterPlotFactory::doCreateMDHisto(
-    IMDHistoWorkspace_sptr workspace) const {
+    const IMDHistoWorkspace &workspace) const {
   // Acquire a scoped read-only lock to the workspace (prevent segfault
   // from algos modifying wworkspace)
-  ReadLock lock(*workspace);
+  ReadLock lock(workspace);
 
   // Get the geometric information of the bins
-  const int nBinsX = static_cast<int>(workspace->getXDimension()->getNBins());
-  const int nBinsY = static_cast<int>(workspace->getYDimension()->getNBins());
-  const int nBinsZ = static_cast<int>(workspace->getZDimension()->getNBins());
+  const int nBinsX = static_cast<int>(workspace.getXDimension()->getNBins());
+  const int nBinsY = static_cast<int>(workspace.getYDimension()->getNBins());
+  const int nBinsZ = static_cast<int>(workspace.getZDimension()->getNBins());
 
-  const coord_t maxX = workspace->getXDimension()->getMaximum();
-  const coord_t minX = workspace->getXDimension()->getMinimum();
-  const coord_t maxY = workspace->getYDimension()->getMaximum();
-  const coord_t minY = workspace->getYDimension()->getMinimum();
-  const coord_t maxZ = workspace->getZDimension()->getMaximum();
-  const coord_t minZ = workspace->getZDimension()->getMinimum();
+  const coord_t maxX = workspace.getXDimension()->getMaximum();
+  const coord_t minX = workspace.getXDimension()->getMinimum();
+  const coord_t maxY = workspace.getYDimension()->getMaximum();
+  const coord_t minY = workspace.getYDimension()->getMinimum();
+  const coord_t maxZ = workspace.getZDimension()->getMaximum();
+  const coord_t minZ = workspace.getZDimension()->getMinimum();
 
   coord_t incrementX = (maxX - minX) / static_cast<coord_t>(nBinsX);
   coord_t incrementY = (maxY - minY) / static_cast<coord_t>(nBinsY);
@@ -287,34 +292,30 @@ void vtkSplatterPlotFactory::doCreateMDHisto(
   vtkNew<vtkVertex> vertex;
 
   // Check if the workspace requires 4D handling.
-  bool do4D = doMDHisto4D(workspace);
+  bool do4D = doMDHisto4D(&workspace);
 
   // Get the transformation that takes the points in the TRANSFORMED space back
   // into the ORIGINAL (not-rotated) space.
-  Mantid::API::CoordTransform const *transform = NULL;
+  Mantid::API::CoordTransform const *transform = nullptr;
   if (m_useTransform) {
-    transform = workspace->getTransformToOriginal();
+    transform = workspace.getTransformToOriginal();
   }
 
   Mantid::coord_t in[3];
   Mantid::coord_t out[3];
 
-  signal_t signalScalar;
-
-  size_t index = 0;
-
   for (int z = 0; z < nBinsZ; z++) {
     in[2] = (minZ + (static_cast<coord_t>(z) + 0.5f) * incrementZ);
     for (int y = 0; y < nBinsY; y++) {
       in[1] = (minY + (static_cast<coord_t>(y) + 0.5f) * incrementY);
       for (int x = 0; x < nBinsX; x++) {
         // Get the signalScalar
-        signalScalar = this->extractScalarSignal(workspace, do4D, x, y, z);
+        signal_t signalScalar =
+            this->extractScalarSignal(workspace, do4D, x, y, z);
 
         // Make sure that the signal is not bad and is in the range and larger
         // than 0
         if (std::isfinite(signalScalar) &&
-            m_thresholdRange->inRange(signalScalar) &&
             (signalScalar > static_cast<signal_t>(0.0))) {
           in[0] = (minX + (static_cast<coord_t>(x) + 0.5f) * incrementX);
           // Create the transformed value if required
@@ -333,7 +334,6 @@ void vtkSplatterPlotFactory::doCreateMDHisto(
 
           visualDataSet->InsertNextCell(VTK_VERTEX, vertex->GetPointIds());
         }
-        index++;
       }
     }
   }
@@ -353,17 +353,17 @@ void vtkSplatterPlotFactory::doCreateMDHisto(
  * @returns The scalar signal.
  */
 signal_t
-vtkSplatterPlotFactory::extractScalarSignal(IMDHistoWorkspace_sptr workspace,
+vtkSplatterPlotFactory::extractScalarSignal(const IMDHistoWorkspace &workspace,
                                             bool do4D, const int x, const int y,
                                             const int z) const {
   signal_t signalScalar;
 
   if (do4D) {
-    signalScalar = workspace->getSignalNormalizedAt(
+    signalScalar = workspace.getSignalNormalizedAt(
         static_cast<size_t>(x), static_cast<size_t>(y), static_cast<size_t>(z),
         static_cast<size_t>(m_time));
   } else {
-    signalScalar = workspace->getSignalNormalizedAt(
+    signalScalar = workspace.getSignalNormalizedAt(
         static_cast<size_t>(x), static_cast<size_t>(y), static_cast<size_t>(z));
   }
 
@@ -376,19 +376,13 @@ vtkSplatterPlotFactory::extractScalarSignal(IMDHistoWorkspace_sptr workspace,
  * @returns Is the workspace 4D?
  */
 bool vtkSplatterPlotFactory::doMDHisto4D(
-    IMDHistoWorkspace_sptr workspace) const {
-  bool do4D = false;
-
+    const IMDHistoWorkspace *workspace) const {
   bool bExactMatch = true;
-
-  IMDHistoWorkspace_sptr workspace4D =
-      castAndCheck<IMDHistoWorkspace, 4>(workspace, bExactMatch);
-
-  if (workspace4D) {
-    do4D = true;
+  if (workspace &&
+      checkWorkspace<IMDHistoWorkspace, 4>(*workspace, bExactMatch)) {
+    return true;
   }
-
-  return do4D;
+  return false;
 }
 
 /**
@@ -444,7 +438,7 @@ vtkSplatterPlotFactory::create(ProgressAction &progressUpdating) const {
   CALL_MDEVENT_FUNCTION(this->doCreate, m_workspace);
 
   // Set the instrument
-  m_instrument = m_metaDataExtractor->extractInstrument(m_workspace);
+  m_instrument = m_metaDataExtractor->extractInstrument(m_workspace.get());
   double *range = nullptr;
 
   if (dataSet) {
@@ -466,7 +460,7 @@ vtkSplatterPlotFactory::create(ProgressAction &progressUpdating) const {
     // Macro to call the right instance of the
     CALL_MDEVENT_FUNCTION(this->doCreate, eventWorkspace);
   } else {
-    this->doCreateMDHisto(histoWorkspace);
+    this->doCreateMDHisto(*histoWorkspace);
   }
 
   // Add metadata in json format
@@ -483,7 +477,7 @@ vtkSplatterPlotFactory::create(ProgressAction &progressUpdating) const {
  * not an IMDEventWorkspace, throws an invalid argument exception.
  * @param ws : Workspace to use.
  */
-void vtkSplatterPlotFactory::initialize(Mantid::API::Workspace_sptr ws) {
+void vtkSplatterPlotFactory::initialize(const Mantid::API::Workspace_sptr &ws) {
   this->m_workspace = boost::dynamic_pointer_cast<IMDWorkspace>(ws);
   this->validate();
 }
@@ -521,9 +515,7 @@ void vtkSplatterPlotFactory::addMetadata() const {
   const double defaultValue = 0.1;
 
   if (this->dataSet) {
-    double *range = nullptr;
-    range = dataSet->GetScalarRange();
-
+    double *range = dataSet->GetScalarRange();
     if (range) {
       m_minValue = range[0];
       m_maxValue = range[1];
@@ -535,7 +527,7 @@ void vtkSplatterPlotFactory::addMetadata() const {
     m_metadataJsonManager->setMinValue(m_minValue);
     m_metadataJsonManager->setMaxValue(m_maxValue);
     m_metadataJsonManager->setInstrument(
-        m_metaDataExtractor->extractInstrument(m_workspace));
+        m_metaDataExtractor->extractInstrument(m_workspace.get()));
     m_metadataJsonManager->setSpecialCoordinates(
         static_cast<int>(m_workspace->getSpecialCoordinateSystem()));
 
diff --git a/Vates/VatesAPI/test/BoxInfoTest.h b/Vates/VatesAPI/test/BoxInfoTest.h
index 385daf0ddd762700ddbacfbb6fe7b8f2e2d124bf..bf3d5175bae92ac45d22700850ee1e9e377d3a83 100644
--- a/Vates/VatesAPI/test/BoxInfoTest.h
+++ b/Vates/VatesAPI/test/BoxInfoTest.h
@@ -31,7 +31,7 @@ public:
     TSM_ASSERT("Should have no recursion depth for top level splitting.",
                boost::none ==
                    Mantid::VATES::findRecursionDepthForTopLevelSplitting(
-                       wsName, std::move(workspaceProvider)));
+                       wsName, *workspaceProvider));
 
     // Clean up
     AnalysisDataService::Instance().remove(wsName);
@@ -48,7 +48,7 @@ public:
     TSM_ASSERT("Should have no recursion depth for top level splitting.",
                boost::none ==
                    Mantid::VATES::findRecursionDepthForTopLevelSplitting(
-                       wsName, std::move(workspaceProvider)));
+                       wsName, *workspaceProvider));
 
     // Clean up
     AnalysisDataService::Instance().remove(wsName);
@@ -70,7 +70,7 @@ public:
 
     // Act
     auto result = Mantid::VATES::findRecursionDepthForTopLevelSplitting(
-        wsName, std::move(workspaceProvider));
+        wsName, *workspaceProvider);
     // Assert
 
     TSM_ASSERT("Should have recursion depth of 1 for top level splitting.",
diff --git a/Vates/VatesAPI/test/IgnoreZerosThresholdRangeTest.h b/Vates/VatesAPI/test/IgnoreZerosThresholdRangeTest.h
deleted file mode 100644
index 117b637b7d93311ce98722409c4fb8510e1d3795..0000000000000000000000000000000000000000
--- a/Vates/VatesAPI/test/IgnoreZerosThresholdRangeTest.h
+++ /dev/null
@@ -1,45 +0,0 @@
-#ifndef IGNORE_ZEROS_THRESHOLD_RANGE_TEST_H_
-#define IGNORE_ZEROS_THRESHOLD_RANGE_TEST_H_
-
-#include <cxxtest/TestSuite.h>
-#include "MantidVatesAPI/IgnoreZerosThresholdRange.h"
-
-using namespace Mantid;
-using namespace Mantid::VATES;
-
-//=====================================================================================
-// Functional tests
-//=====================================================================================
-class IgnoreZerosThresholdRangeTest : public CxxTest::TestSuite {
-
-public:
-  void testIgnoreEmptyCells() {
-    IgnoreZerosThresholdRange range;
-
-    TS_ASSERT_EQUALS(true, range.inRange(0.001));
-    TS_ASSERT_EQUALS(true, range.inRange(-0.001));
-    TS_ASSERT_EQUALS(false, range.inRange(0));
-  }
-
-  void testGetMinMax() {
-    IgnoreZerosThresholdRange range;
-
-    range.inRange(1);
-    range.inRange(3);
-    range.inRange(-2);
-    range.inRange(5);
-    TSM_ASSERT_EQUALS("Wrong max found", 5, range.getMaximum());
-    TSM_ASSERT_EQUALS("Wrong min found", -2, range.getMinimum());
-  }
-
-  void testMinIsNeverZero() {
-    IgnoreZerosThresholdRange range;
-
-    range.inRange(0);
-    range.inRange(0.5);
-    range.inRange(2);
-    TSM_ASSERT_EQUALS("Wrong min found", 0.5, range.getMinimum());
-  }
-};
-
-#endif
\ No newline at end of file
diff --git a/Vates/VatesAPI/test/LoadVTKTest.h b/Vates/VatesAPI/test/LoadVTKTest.h
index 68bd8de7275911aa4abcbccb7b78ab374662edfd..7d8897cbf98aaa01d12371b97534351c6f047eae 100644
--- a/Vates/VatesAPI/test/LoadVTKTest.h
+++ b/Vates/VatesAPI/test/LoadVTKTest.h
@@ -3,6 +3,7 @@
 
 #include <cxxtest/TestSuite.h>
 #include "MantidVatesAPI/LoadVTK.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/IMDHistoWorkspace.h"
 #include "MantidGeometry/MDGeometry/IMDDimension.h"
 #include "MantidGeometry/MDGeometry/UnknownFrame.h"
diff --git a/Vates/VatesAPI/test/MDHWNexusLoadingPresenterTest.h b/Vates/VatesAPI/test/MDHWNexusLoadingPresenterTest.h
index ab9ef3990b77d0b582fe26780e484592d029b60e..50cae98a708d14b36cfc8d2e210f9533b2c1acac 100644
--- a/Vates/VatesAPI/test/MDHWNexusLoadingPresenterTest.h
+++ b/Vates/VatesAPI/test/MDHWNexusLoadingPresenterTest.h
@@ -14,7 +14,6 @@
 #include "MantidVatesAPI/vtkMDHistoHexFactory.h"
 #include "MantidVatesAPI/vtkMDHistoHex4DFactory.h"
 #include "MantidVatesAPI/TimeToTimeStep.h"
-#include "MantidVatesAPI/IgnoreZerosThresholdRange.h"
 
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
@@ -155,22 +154,19 @@ public:
         .WillRepeatedly(testing::Return(true));
     EXPECT_CALL(*view, updateAlgorithmProgress(_, _)).Times(AnyNumber());
 
-    ThresholdRange_scptr thresholdRange =
-        boost::make_shared<IgnoreZerosThresholdRange>();
-
     // Create the presenter as in the vtkMDHWSource
     auto normalizationOption = Mantid::VATES::VisualNormalization::AutoSelect;
     MDHWNexusLoadingPresenter presenter(std::move(view), filename);
     const double time = 0.0;
     auto factory = boost::make_shared<vtkMDHistoHex4DFactory<TimeToTimeStep>>(
-        thresholdRange, normalizationOption, time);
+        normalizationOption, time);
 
     factory->setSuccessor(Mantid::Kernel::make_unique<vtkMDHistoHexFactory>(
-                              thresholdRange, normalizationOption))
+                              normalizationOption))
         .setSuccessor(Mantid::Kernel::make_unique<vtkMDHistoQuadFactory>(
-            thresholdRange, normalizationOption))
+            normalizationOption))
         .setSuccessor(Mantid::Kernel::make_unique<vtkMDHistoLineFactory>(
-            thresholdRange, normalizationOption))
+            normalizationOption))
         .setSuccessor(Mantid::Kernel::make_unique<vtkMD0DFactory>());
 
     presenter.executeLoadMetadata();
@@ -181,7 +177,8 @@ public:
     try {
       auto workspaceProvider = Mantid::Kernel::make_unique<
           ADSWorkspaceProvider<Mantid::API::IMDWorkspace>>();
-      presenter.makeNonOrthogonal(product, std::move(workspaceProvider));
+      presenter.makeNonOrthogonal(product, std::move(workspaceProvider),
+                                  &mockDrawingProgressAction);
     } catch (...) {
       // Add the standard change of basis matrix and set the boundaries
       presenter.setDefaultCOBandBoundaries(product);
diff --git a/Vates/VatesAPI/test/MDLoadingPresenterTest.h b/Vates/VatesAPI/test/MDLoadingPresenterTest.h
index 76cbef910491790f390453b01c1fa64132084d41..c0a11b8b2fbe75a4c523f03da465f547222527b6 100644
--- a/Vates/VatesAPI/test/MDLoadingPresenterTest.h
+++ b/Vates/VatesAPI/test/MDLoadingPresenterTest.h
@@ -3,7 +3,6 @@
 
 #include "MantidTestHelpers/MDEventsTestHelper.h"
 #include "MantidVatesAPI/MDLoadingPresenter.h"
-#include "MantidVatesAPI/NoThresholdRange.h"
 #include "MantidVatesAPI/ProgressAction.h"
 #include "MantidVatesAPI/vtkDataSetFactory.h"
 #include "MantidVatesAPI/vtkMDHexFactory.h"
@@ -55,8 +54,7 @@ private:
     FakeProgressAction progressUpdate;
     MDEventWorkspace3Lean::sptr ws =
         MDEventsTestHelper::makeMDEW<3>(8, -10.0, 10.0, 1);
-    Mantid::VATES::vtkMDHexFactory factory(
-        ThresholdRange_scptr(new NoThresholdRange), VolumeNormalization);
+    Mantid::VATES::vtkMDHexFactory factory(VolumeNormalization);
     factory.initialize(ws);
     auto dataset = factory.create(progressUpdate);
     auto grid = vtkUnstructuredGrid::SafeDownCast(dataset.Get());
diff --git a/Vates/VatesAPI/test/MedianAndBelowThresholdRangeTest.h b/Vates/VatesAPI/test/MedianAndBelowThresholdRangeTest.h
deleted file mode 100644
index c7e651c04cf77352d86c3a2a0210b64f354b2ff4..0000000000000000000000000000000000000000
--- a/Vates/VatesAPI/test/MedianAndBelowThresholdRangeTest.h
+++ /dev/null
@@ -1,64 +0,0 @@
-#ifndef MEDIAN_AND_BELOW_THRESHOLD_RANGE_TEST_H_
-#define MEDIAN_AND_BELOW_THRESHOLD_RANGE_TEST_H_
-
-#include <cxxtest/TestSuite.h>
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-#include "MantidVatesAPI/MedianAndBelowThresholdRange.h"
-#include "MantidAPI/IMDIterator.h"
-#include "MantidTestHelpers/MDEventsTestHelper.h"
-#include "MantidDataObjects/MDHistoWorkspace.h"
-
-using namespace Mantid;
-using namespace Mantid::DataObjects;
-using namespace testing;
-
-//=====================================================================================
-// Functional tests
-//=====================================================================================
-
-class MedianAndBelowThresholdRangeTest : public CxxTest::TestSuite {
-private:
-  // Fake workspace
-  MDHistoWorkspace_sptr sptrWs;
-
-public:
-  void setUp() override {
-    // Fake workspace with 8 cells
-    sptrWs = MDEventsTestHelper::makeFakeMDHistoWorkspace(1.0, 1, 8, 8.0);
-    // Set up a standard set of values for subsequent tests. Note that the
-    // following set gives a standard deviation of +/-2
-    sptrWs->setSignalAt(0, -1.0);
-    sptrWs->setSignalAt(1, 2);
-    sptrWs->setSignalAt(2, 2);
-    sptrWs->setSignalAt(3, 3);
-    sptrWs->setSignalAt(4, 4);
-    sptrWs->setSignalAt(5, 5);
-    sptrWs->setSignalAt(6, 6);
-    sptrWs->setSignalAt(7, 7);
-  }
-
-  void testMedianCalculation() {
-    Mantid::VATES::MedianAndBelowThresholdRange medianCalculator;
-    medianCalculator.setWorkspace(sptrWs);
-    medianCalculator.calculate();
-    //-1 + 2 + 2 + 3 + 4 + 5 + 6 + 7 / 8 = 3.5
-
-    TSM_ASSERT_EQUALS("Wrong maximum value.", 3.5,
-                      medianCalculator.getMaximum());
-    TSM_ASSERT_EQUALS("Wrong minimum value.", -1,
-                      medianCalculator.getMinimum());
-  }
-
-  void testInRange() {
-    Mantid::VATES::MedianAndBelowThresholdRange medianCalculator;
-    medianCalculator.setWorkspace(sptrWs);
-    medianCalculator.calculate();
-    //-1 + 2 + 2 + 3 + 4 + 5 + 6 + 7 / 8 = 3.5
-
-    TS_ASSERT_EQUALS(true, medianCalculator.inRange(3.499));
-    TS_ASSERT_EQUALS(false, medianCalculator.inRange(3.501));
-  }
-};
-
-#endif
diff --git a/Vates/VatesAPI/test/MetaDataExtractorUtilsTest.h b/Vates/VatesAPI/test/MetaDataExtractorUtilsTest.h
index 75873feba4d1cb9ad138e374097894db68866eb1..09868bf266c874604e5bf6f8b928fd08df2c1c91 100644
--- a/Vates/VatesAPI/test/MetaDataExtractorUtilsTest.h
+++ b/Vates/VatesAPI/test/MetaDataExtractorUtilsTest.h
@@ -16,6 +16,7 @@
 
 #include <qwt_double_interval.h>
 #include "MantidTestHelpers/MDEventsTestHelper.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/FileFinder.h"
 #include "MantidAPI/ITableWorkspace.h"
 #include "MantidAPI/WorkspaceFactory.h"
@@ -51,7 +52,7 @@ public:
 
     // Act
     MetaDataExtractorUtils extractor;
-    QwtDoubleInterval minMax = extractor.getMinAndMax(histoWorkspace);
+    QwtDoubleInterval minMax = extractor.getMinAndMax(histoWorkspace.get());
 
     // Assert
     TSM_ASSERT("Should find the a min which is smaller/equal to max ",
@@ -66,7 +67,7 @@ public:
     MetaDataExtractorUtils extractor;
 
     // Act
-    QwtDoubleInterval minMax = extractor.getMinAndMax(eventWorkspace);
+    QwtDoubleInterval minMax = extractor.getMinAndMax(eventWorkspace.get());
 
     // Assert
     TSM_ASSERT("Should find the a min which is smaller/equal to max ",
@@ -84,7 +85,7 @@ public:
     MetaDataExtractorUtils extractor;
 
     // Act
-    std::string instrument = extractor.extractInstrument(histoWorkspace);
+    std::string instrument = extractor.extractInstrument(histoWorkspace.get());
 
     // Assert
     TSM_ASSERT("Should find an empty instrment for invalid workspace",
diff --git a/Vates/VatesAPI/test/MockObjects.h b/Vates/VatesAPI/test/MockObjects.h
index 90355657d8328428e7b186c673f904a244128046..bdb8ccc55495eb8c0f8ec0ea9b2fa83bc8b84db0 100644
--- a/Vates/VatesAPI/test/MockObjects.h
+++ b/Vates/VatesAPI/test/MockObjects.h
@@ -54,7 +54,7 @@ public:
   const Mantid::Kernel::UnitLabel getUnits() const override {
     throw std::runtime_error("Not implemented");
   }
-  std::string getDimensionId() const override { return m_id; }
+  const std::string &getDimensionId() const override { return m_id; }
   coord_t getMaximum() const override { return 10; }
   coord_t getMinimum() const override { return 0; };
   size_t getNBins() const override { return m_nbins; };
@@ -141,7 +141,7 @@ public:
       create, vtkSmartPointer<vtkDataSet>(Mantid::VATES::ProgressAction &));
   MOCK_CONST_METHOD0(createMeshOnly, vtkDataSet *());
   MOCK_CONST_METHOD0(createScalarArray, vtkFloatArray *());
-  MOCK_METHOD1(initialize, void(Mantid::API::Workspace_sptr));
+  MOCK_METHOD1(initialize, void(const Mantid::API::Workspace_sptr &));
   MOCK_METHOD1(setSuccessorProxy, void(vtkDataSetFactory *));
   MOCK_CONST_METHOD0(hasSuccessor, bool());
   MOCK_CONST_METHOD0(validate, void());
diff --git a/Vates/VatesAPI/test/NoThresholdRangeTest.h b/Vates/VatesAPI/test/NoThresholdRangeTest.h
deleted file mode 100644
index 57b2a404b6b0303afd5d16879ab9bc88d35a2fbe..0000000000000000000000000000000000000000
--- a/Vates/VatesAPI/test/NoThresholdRangeTest.h
+++ /dev/null
@@ -1,36 +0,0 @@
-#ifndef NO_THRESHOLD_RANGE_TEST_H_
-#define NO_THRESHOLD_RANGE_TEST_H_
-
-#include <cxxtest/TestSuite.h>
-
-#include "MantidVatesAPI/NoThresholdRange.h"
-
-using namespace Mantid;
-using namespace Mantid::VATES;
-
-//=====================================================================================
-// Functional tests
-//=====================================================================================
-class NoThresholdRangeTest : public CxxTest::TestSuite {
-public:
-  void testEverythingWithinRange() {
-    NoThresholdRange range;
-
-    TS_ASSERT_EQUALS(true, range.inRange(-1e9));
-    TS_ASSERT_EQUALS(true, range.inRange(0));
-    TS_ASSERT_EQUALS(true, range.inRange(1e9));
-  }
-
-  void testGetMinMax() {
-    NoThresholdRange range;
-
-    range.inRange(1);
-    range.inRange(3);
-    range.inRange(-2);
-    range.inRange(5);
-    TSM_ASSERT_EQUALS("Wrong max found", 5, range.getMaximum());
-    TSM_ASSERT_EQUALS("Wrong min found", -2, range.getMinimum());
-  }
-};
-
-#endif
\ No newline at end of file
diff --git a/Vates/VatesAPI/test/SaveMDWorkspaceToVTKImplTest.h b/Vates/VatesAPI/test/SaveMDWorkspaceToVTKImplTest.h
index 3a06c37bdcac214ca4d278462587f52c2c419c55..a08c62d5b76917cacc7f2f124d9554421ee0c97d 100644
--- a/Vates/VatesAPI/test/SaveMDWorkspaceToVTKImplTest.h
+++ b/Vates/VatesAPI/test/SaveMDWorkspaceToVTKImplTest.h
@@ -4,7 +4,6 @@
 #include <cxxtest/TestSuite.h>
 #include "MantidVatesAPI/SaveMDWorkspaceToVTKImpl.h"
 #include "MantidVatesAPI/Normalization.h"
-#include "MantidVatesAPI/IgnoreZerosThresholdRange.h"
 #include "MantidTestHelpers/MDEventsTestHelper.h"
 #include "MantidKernel/ConfigService.h"
 
@@ -63,43 +62,6 @@ public:
                       volumeNormalization, Mantid::VATES::VolumeNormalization);
   }
 
-  void test_that_vector_of_threshold_strings_has_all_values() {
-    // Arrange
-    Mantid::VATES::SaveMDWorkspaceToVTKImpl saveMDToVTK;
-
-    // Act
-    const auto thresholds =
-        saveMDToVTK.getAllowedThresholdsInStringRepresentation();
-
-    // Assert
-    TSM_ASSERT_EQUALS("There should be 2 normalization options",
-                      thresholds.size(), 2);
-    TSM_ASSERT_EQUALS(
-        "First normalization should be IgnoreZerosThresholdRange.",
-        thresholds[0], "IgnoreZerosThresholdRange");
-    TSM_ASSERT_EQUALS("Second normalization should be NoThresholdRange.",
-                      thresholds[1], "NoThresholdRange");
-  }
-
-  void test_string_representation_converts_to_TresholdRange() {
-    // Arrange
-    Mantid::VATES::SaveMDWorkspaceToVTKImpl saveMDToVTK;
-    auto thresholds = saveMDToVTK.getAllowedThresholdsInStringRepresentation();
-    // Act
-    auto ignoreZerosThresholdRange =
-        saveMDToVTK.translateStringToThresholdRange(thresholds[0]);
-    auto noThresholdRange =
-        saveMDToVTK.translateStringToThresholdRange(thresholds[1]);
-    // Assert
-    TSM_ASSERT(
-        "Should be a IgnoreZerosTresholdRange",
-        boost::dynamic_pointer_cast<Mantid::VATES::IgnoreZerosThresholdRange>(
-            ignoreZerosThresholdRange));
-    TSM_ASSERT("Should be a NoTresholdRange",
-               boost::dynamic_pointer_cast<Mantid::VATES::ThresholdRange>(
-                   noThresholdRange));
-  }
-
   void test_detects_when_not_3D_workspace() {
     // Arrange
     Mantid::VATES::SaveMDWorkspaceToVTKImpl saveMDToVTK;
@@ -107,7 +69,7 @@ public:
     auto workspace = MDEventsTestHelper::makeFakeMDHistoWorkspace(1.0, numDims);
 
     // Act
-    const auto is3D = saveMDToVTK.is3DWorkspace(workspace);
+    const auto is3D = saveMDToVTK.is3DWorkspace(*workspace);
 
     // Assert
     TSM_ASSERT("Detects a non-3D MD workspace", !is3D);
@@ -120,7 +82,7 @@ public:
     auto workspace = MDEventsTestHelper::makeFakeMDHistoWorkspace(1.0, numDims);
 
     // Act
-    const auto is3D = saveMDToVTK.is3DWorkspace(workspace);
+    const auto is3D = saveMDToVTK.is3DWorkspace(*workspace);
 
     // Assert
     TSM_ASSERT("Detects that a 3D MD workspace", is3D);
@@ -208,13 +170,7 @@ private:
         saveMDToVTK.getAllowedNormalizationsInStringRepresentation();
     const auto normalization =
         saveMDToVTK.translateStringToVisualNormalization(normalizations[0]);
-
-    const auto thresholds =
-        saveMDToVTK.getAllowedThresholdsInStringRepresentation();
-    const auto threshold =
-        saveMDToVTK.translateStringToThresholdRange(thresholds[0]);
-
-    saveMDToVTK.saveMDWorkspace(workspace, filename, normalization, threshold,
+    saveMDToVTK.saveMDWorkspace(workspace, filename, normalization,
                                 recursionDepth, "NONE");
   }
 
diff --git a/Vates/VatesAPI/test/SaveMDWorkspaceToVTKTest.h b/Vates/VatesAPI/test/SaveMDWorkspaceToVTKTest.h
index 46027ce611af122974485747c97a51fd71abd045..c5264d10281945caca1740df1683a823d2818761 100644
--- a/Vates/VatesAPI/test/SaveMDWorkspaceToVTKTest.h
+++ b/Vates/VatesAPI/test/SaveMDWorkspaceToVTKTest.h
@@ -11,7 +11,7 @@ class SaveMDWorkspaceToVTKTest : public CxxTest::TestSuite {
 public:
   void test_that_wrong_workspace_type_throws() {
     // Arrange
-    auto workspace = WorkspaceCreationHelper::Create2DWorkspace(1, 10);
+    auto workspace = WorkspaceCreationHelper::create2DWorkspace(1, 10);
 
     Mantid::VATES::SaveMDWorkspaceToVTK alg;
     alg.setChild(true);
@@ -20,7 +20,6 @@ public:
     alg.setProperty("InputWorkspace", workspace);
     alg.setProperty("Filename", "test_file_name");
     alg.setProperty("Normalization", "AutoSelect");
-    alg.setProperty("ThresholdRange", "IgnoreZerosThresholdRange");
     alg.setProperty("RecursionDepth", 5);
     alg.setProperty("CompressorType", "NONE");
 
@@ -45,7 +44,6 @@ public:
     alg.setProperty("InputWorkspace", workspace);
     alg.setProperty("Filename", "test_file_name");
     alg.setProperty("Normalization", "AutoSelect");
-    alg.setProperty("ThresholdRange", "IgnoreZerosThresholdRange");
     alg.setProperty("RecursionDepth", 5);
     alg.setProperty("CompressorType", "NONE");
 
@@ -75,7 +73,6 @@ public:
     alg.setProperty("InputWorkspace", workspace);
     alg.setProperty("Filename", fullFilename);
     alg.setProperty("Normalization", "AutoSelect");
-    alg.setProperty("ThresholdRange", "IgnoreZerosThresholdRange");
     alg.setProperty("RecursionDepth", 5);
     alg.setProperty("CompressorType", "NONE");
 
diff --git a/Vates/VatesAPI/test/UserDefinedThresholdRangeTest.h b/Vates/VatesAPI/test/UserDefinedThresholdRangeTest.h
deleted file mode 100644
index b34062277c106157607c26668d74b6081e5d6c0b..0000000000000000000000000000000000000000
--- a/Vates/VatesAPI/test/UserDefinedThresholdRangeTest.h
+++ /dev/null
@@ -1,66 +0,0 @@
-#ifndef USER_DEFINED_THRESHOLD_RANGE_TEST_H_
-#define USER_DEFINED_THRESHOLD_RANGE_TEST_H_
-
-#include <cxxtest/TestSuite.h>
-#include "MantidVatesAPI/UserDefinedThresholdRange.h"
-
-using namespace Mantid::VATES;
-using namespace Mantid;
-
-class UserDefinedThresholdRangeTest : public CxxTest::TestSuite {
-public:
-  void testConstructMaxLessThanMinThrows() {
-    TSM_ASSERT_THROWS("Should not be able to construct with max less than min.",
-                      UserDefinedThresholdRange(2, 1), std::invalid_argument);
-  }
-
-  void testGetMaximum() {
-    Mantid::VATES::UserDefinedThresholdRange userRangeCalculator(1, 2);
-    TSM_ASSERT_EQUALS("::getMaximum not wired-up correctly.", 2,
-                      userRangeCalculator.getMaximum());
-  }
-
-  void testGetMinimum() {
-    Mantid::VATES::UserDefinedThresholdRange userRangeCalculator(1, 2);
-    TSM_ASSERT_EQUALS("::getMinimum not wired-up correctly.", 1,
-                      userRangeCalculator.getMinimum());
-  }
-
-  void testHasCalculated() {
-    Mantid::VATES::UserDefinedThresholdRange userRangeCalculator(1, 2);
-    TS_ASSERT(userRangeCalculator
-                  .hasCalculated()); // Should return true no matter what!
-  }
-
-  void testClone() {
-    Mantid::VATES::UserDefinedThresholdRange original(1, 2);
-    auto cloned = std::unique_ptr<Mantid::VATES::UserDefinedThresholdRange>(
-        original.clone());
-
-    TS_ASSERT_EQUALS(original.getMaximum(), cloned->getMaximum());
-    TS_ASSERT_EQUALS(original.getMinimum(), cloned->getMinimum());
-  }
-
-  void testInRange() {
-    Mantid::VATES::UserDefinedThresholdRange userRangeCalculator(1, 2);
-    // Boundary Value Analysis
-    signal_t just_above_upper_boundary = 2.001;
-    signal_t just_below_lower_boundary = 0.999;
-    signal_t on_lower_boundary = 1;
-    signal_t on_upper_boundary = 2;
-    signal_t just_below_upper_boundary = 1.999;
-    signal_t just_above_lower_boundary = 1.001;
-    TS_ASSERT_EQUALS(false,
-                     userRangeCalculator.inRange(just_above_upper_boundary));
-    TS_ASSERT_EQUALS(false,
-                     userRangeCalculator.inRange(just_below_lower_boundary));
-    TS_ASSERT_EQUALS(true, userRangeCalculator.inRange(on_lower_boundary));
-    TS_ASSERT_EQUALS(true, userRangeCalculator.inRange(on_upper_boundary));
-    TS_ASSERT_EQUALS(true,
-                     userRangeCalculator.inRange(just_below_upper_boundary));
-    TS_ASSERT_EQUALS(true,
-                     userRangeCalculator.inRange(just_above_lower_boundary));
-  }
-};
-
-#endif
\ No newline at end of file
diff --git a/Vates/VatesAPI/test/VatesKnowledgeSerializerTest.h b/Vates/VatesAPI/test/VatesKnowledgeSerializerTest.h
index c9e42504658477361cf67278c9976049c78e3196..db580dd97bbfba6baaaae7957c8b52ffa79a90da 100644
--- a/Vates/VatesAPI/test/VatesKnowledgeSerializerTest.h
+++ b/Vates/VatesAPI/test/VatesKnowledgeSerializerTest.h
@@ -56,7 +56,7 @@ public:
 
     VatesKnowledgeSerializer generator; // Location is not required.
     generator.setImplicitFunction(impFunction);
-    generator.setWorkspace(workspace);
+    generator.setWorkspace(*workspace);
 
     TSM_ASSERT_THROWS_NOTHING("The location is not mandatory, should not throw",
                               generator.createXMLString());
@@ -70,7 +70,7 @@ public:
     boost::shared_ptr<const Mantid::API::IMDWorkspace> workspace(pWorkspace);
     VatesKnowledgeSerializer generator;
     generator.setImplicitFunction(impFunction);
-    generator.setWorkspace(workspace);
+    generator.setWorkspace(*workspace);
 
     TSM_ASSERT_THROWS("Cannot create the xml without the workspace name",
                       generator.createXMLString(), std::runtime_error);
diff --git a/Vates/VatesAPI/test/vtkDataSetFactoryTest.h b/Vates/VatesAPI/test/vtkDataSetFactoryTest.h
index 2cb9cf290fa82211335a095a3446bc04920495e0..99cfedb581f3b2f5ac0805eba050affcce327f08 100644
--- a/Vates/VatesAPI/test/vtkDataSetFactoryTest.h
+++ b/Vates/VatesAPI/test/vtkDataSetFactoryTest.h
@@ -30,7 +30,8 @@ private:
     GCC_DIAG_OFF_SUGGEST_OVERRIDE
     MOCK_CONST_METHOD1(
         create, vtkSmartPointer<vtkDataSet>(Mantid::VATES::ProgressAction &));
-    MOCK_METHOD1(initialize, void(boost::shared_ptr<Mantid::API::Workspace>));
+    MOCK_METHOD1(initialize,
+                 void(const boost::shared_ptr<Mantid::API::Workspace> &));
     MOCK_CONST_METHOD0(validate, void());
     MOCK_CONST_METHOD0(getFactoryTypeName, std::string());
     GCC_DIAG_ON_SUGGEST_OVERRIDE
diff --git a/Vates/VatesAPI/test/vtkDataSetToNonOrthogonalDataSetTest.h b/Vates/VatesAPI/test/vtkDataSetToNonOrthogonalDataSetTest.h
index 53e882eefdd5d91f3893f027ced4a148921578b5..f5d6395db8e4d25433d934b584b90c79a9210bff 100644
--- a/Vates/VatesAPI/test/vtkDataSetToNonOrthogonalDataSetTest.h
+++ b/Vates/VatesAPI/test/vtkDataSetToNonOrthogonalDataSetTest.h
@@ -271,16 +271,6 @@ public:
     TS_ASSERT_THROWS_NOTHING(converter.execute());
   }
 
-  void testStaticUseForSimpleDataSet() {
-    std::string wsName = createMantidWorkspace(false);
-    vtkSmartPointer<vtkUnstructuredGrid> ds;
-    ds.TakeReference(createSingleVoxelPoints());
-    auto workspaceProvider = Mantid::Kernel::make_unique<
-        ADSWorkspaceProvider<Mantid::API::IMDWorkspace>>();
-    TS_ASSERT_THROWS_NOTHING(vtkDataSetToNonOrthogonalDataSet::exec(
-        ds, wsName, std::move(workspaceProvider)));
-  }
-
   void testNonUnitySimpleDataset() {
     std::string wsName = createMantidWorkspace(true);
     vtkSmartPointer<vtkUnstructuredGrid> ds;
diff --git a/Vates/VatesAPI/test/vtkDataSetToPeaksFilteredDataSetTest.h b/Vates/VatesAPI/test/vtkDataSetToPeaksFilteredDataSetTest.h
index c159e19f181fa1452c9475d7cf0e440b7aae5bed..142e573da02ae58cbd6c22345a830f5bf42d787c 100644
--- a/Vates/VatesAPI/test/vtkDataSetToPeaksFilteredDataSetTest.h
+++ b/Vates/VatesAPI/test/vtkDataSetToPeaksFilteredDataSetTest.h
@@ -13,8 +13,6 @@
 #include "MantidVatesAPI/FieldDataToMetadata.h"
 #include "MantidVatesAPI/MetadataJsonManager.h"
 #include "MantidVatesAPI/MetadataToFieldData.h"
-#include "MantidVatesAPI/NoThresholdRange.h"
-#include "MantidVatesAPI/UserDefinedThresholdRange.h"
 #include "MantidVatesAPI/VatesConfigurations.h"
 #include "MantidVatesAPI/vtkDataSetToPeaksFilteredDataSet.h"
 #include "MantidVatesAPI/vtkSplatterPlotFactory.h"
@@ -65,8 +63,7 @@ private:
     FakeProgressAction progressUpdate;
     MDEventWorkspace3Lean::sptr ws =
         MDEventsTestHelper::makeMDEW<3>(10, -10.0, 10.0, 1);
-    vtkSplatterPlotFactory factory(
-        boost::make_shared<UserDefinedThresholdRange>(0, 1), "signal");
+    vtkSplatterPlotFactory factory("signal");
     factory.initialize(ws);
     vtkSmartPointer<vtkDataSet> product;
     TS_ASSERT_THROWS_NOTHING(product = factory.create(progressUpdate));
diff --git a/Vates/VatesAPI/test/vtkDataSetToScaledDataSetTest.h b/Vates/VatesAPI/test/vtkDataSetToScaledDataSetTest.h
index 391434f9587672c5707e5080b7c7d1e201177d99..7325a44b26cd03d0ea92cef524708553b366d0ef 100644
--- a/Vates/VatesAPI/test/vtkDataSetToScaledDataSetTest.h
+++ b/Vates/VatesAPI/test/vtkDataSetToScaledDataSetTest.h
@@ -7,7 +7,6 @@
 #include "MantidVatesAPI/MetadataJsonManager.h"
 #include "MantidVatesAPI/MetadataToFieldData.h"
 #include "MantidVatesAPI/VatesConfigurations.h"
-#include "MantidVatesAPI/NoThresholdRange.h"
 #include "MantidVatesAPI/vtkDataSetToScaledDataSet.h"
 #include "MantidVatesAPI/vtkMDHexFactory.h"
 #include "MockObjects.h"
@@ -35,8 +34,7 @@ private:
     FakeProgressAction progressUpdate;
     MDEventWorkspace3Lean::sptr ws =
         MDEventsTestHelper::makeMDEW<3>(8, -10.0, 10.0, 1);
-    vtkMDHexFactory factory(ThresholdRange_scptr(new NoThresholdRange),
-                            VolumeNormalization);
+    vtkMDHexFactory factory(VolumeNormalization);
     factory.initialize(ws);
     auto product = factory.create(progressUpdate);
     auto data = vtkUnstructuredGrid::SafeDownCast(product.Get());
diff --git a/Vates/VatesAPI/test/vtkMDHWSignalArrayTest.h b/Vates/VatesAPI/test/vtkMDHWSignalArrayTest.h
index 014ec76ddf29ecd5903aca1ac28414da1fb455d0..ae6d338ddd9a60e3a0b7fa32a499cb392e9f46fb 100644
--- a/Vates/VatesAPI/test/vtkMDHWSignalArrayTest.h
+++ b/Vates/VatesAPI/test/vtkMDHWSignalArrayTest.h
@@ -34,12 +34,8 @@ public:
     const int nBinsY = static_cast<int>(ws_sptr->getYDimension()->getNBins());
     const int nBinsZ = static_cast<int>(ws_sptr->getZDimension()->getNBins());
     const int imageSize = (nBinsX) * (nBinsY) * (nBinsZ);
-
-    std::unique_ptr<MDHistoWorkspaceIterator> iterator(
-        dynamic_cast<MDHistoWorkspaceIterator *>(
-            createIteratorWithNormalization(Mantid::VATES::NoNormalization,
-                                            ws_sptr.get())));
-    signal->InitializeArray(std::move(iterator), offset, imageSize);
+    signal->InitializeArray(ws_sptr.get(), Mantid::VATES::NoNormalization,
+                            offset);
 
     for (auto index = 0; index < imageSize; ++index) {
       double output1[1];
@@ -82,7 +78,8 @@ public:
         dynamic_cast<MDHistoWorkspaceIterator *>(
             createIteratorWithNormalization(
                 Mantid::VATES::NumEventsNormalization, ws_sptr.get())));
-    signal->InitializeArray(std::move(iterator), offset, imageSize);
+    signal->InitializeArray(ws_sptr.get(),
+                            Mantid::VATES::NumEventsNormalization, offset);
 
     vtkNew<vtkIdList> ptIds;
 
@@ -108,20 +105,13 @@ public:
         MDEventsTestHelper::makeFakeMDHistoWorkspace(1.0, 3, 4);
     vtkNew<vtkMDHWSignalArray<double>> signal;
     std::size_t offset = 0;
-    const int nBinsX = static_cast<int>(ws_sptr->getXDimension()->getNBins());
-    const int nBinsY = static_cast<int>(ws_sptr->getYDimension()->getNBins());
-    const int nBinsZ = static_cast<int>(ws_sptr->getZDimension()->getNBins());
-    const int imageSize = (nBinsX) * (nBinsY) * (nBinsZ);
 
     ws_sptr->setMDMaskAt(0, true);
     ws_sptr->setMDMaskAt(7, true);
     ws_sptr->setMDMaskAt(42, true);
 
-    std::unique_ptr<MDHistoWorkspaceIterator> iterator(
-        dynamic_cast<MDHistoWorkspaceIterator *>(
-            createIteratorWithNormalization(Mantid::VATES::NoNormalization,
-                                            ws_sptr.get())));
-    signal->InitializeArray(std::move(iterator), offset, imageSize);
+    signal->InitializeArray(ws_sptr.get(), Mantid::VATES::NoNormalization,
+                            offset);
 
     vtkNew<vtkIdList> idList1, idList2;
 
@@ -135,16 +125,8 @@ public:
         MDEventsTestHelper::makeFakeMDHistoWorkspace(1.0, 3);
     vtkNew<vtkMDHWSignalArray<double>> signal;
     std::size_t offset = 0;
-    const int nBinsX = static_cast<int>(ws_sptr->getXDimension()->getNBins());
-    const int nBinsY = static_cast<int>(ws_sptr->getYDimension()->getNBins());
-    const int nBinsZ = static_cast<int>(ws_sptr->getZDimension()->getNBins());
-    const int imageSize = (nBinsX) * (nBinsY) * (nBinsZ);
-
-    std::unique_ptr<MDHistoWorkspaceIterator> iterator(
-        dynamic_cast<MDHistoWorkspaceIterator *>(
-            createIteratorWithNormalization(Mantid::VATES::VolumeNormalization,
-                                            ws_sptr.get())));
-    signal->InitializeArray(std::move(iterator), offset, imageSize);
+    signal->InitializeArray(ws_sptr.get(), Mantid::VATES::VolumeNormalization,
+                            offset);
 
     vtkNew<vtkDoubleArray> doubleArray;
     doubleArray->SetNumberOfComponents(1);
@@ -164,16 +146,9 @@ public:
         MDEventsTestHelper::makeFakeMDHistoWorkspace(8.0, 3, 10, 5.0);
     vtkNew<vtkMDHWSignalArray<double>> signal;
     std::size_t offset = 0;
-    const int nBinsX = static_cast<int>(ws_sptr->getXDimension()->getNBins());
-    const int nBinsY = static_cast<int>(ws_sptr->getYDimension()->getNBins());
-    const int nBinsZ = static_cast<int>(ws_sptr->getZDimension()->getNBins());
-    const int imageSize = (nBinsX) * (nBinsY) * (nBinsZ);
 
-    std::unique_ptr<MDHistoWorkspaceIterator> iterator(
-        dynamic_cast<MDHistoWorkspaceIterator *>(
-            createIteratorWithNormalization(Mantid::VATES::NoNormalization,
-                                            ws_sptr.get())));
-    signal->InitializeArray(std::move(iterator), offset, imageSize);
+    signal->InitializeArray(ws_sptr.get(), Mantid::VATES::NoNormalization,
+                            offset);
     TS_ASSERT(signal->LookupValue(1.0) == 0);
     TS_ASSERT(signal->LookupTypedValue(1.0) == 0);
   }
@@ -183,16 +158,8 @@ public:
         MDEventsTestHelper::makeFakeMDHistoWorkspace(1.0, 3);
     vtkNew<vtkMDHWSignalArray<double>> signal;
     std::size_t offset = 0;
-    const int nBinsX = static_cast<int>(ws_sptr->getXDimension()->getNBins());
-    const int nBinsY = static_cast<int>(ws_sptr->getYDimension()->getNBins());
-    const int nBinsZ = static_cast<int>(ws_sptr->getZDimension()->getNBins());
-    const int imageSize = (nBinsX) * (nBinsY) * (nBinsZ);
-
-    std::unique_ptr<MDHistoWorkspaceIterator> iterator(
-        dynamic_cast<MDHistoWorkspaceIterator *>(
-            createIteratorWithNormalization(Mantid::VATES::NoNormalization,
-                                            ws_sptr.get())));
-    signal->InitializeArray(std::move(iterator), offset, imageSize);
+    signal->InitializeArray(ws_sptr.get(), Mantid::VATES::NoNormalization,
+                            offset);
 
     vtkNew<vtkIdList> idList1, idList2;
     signal->LookupValue(0.0, idList1.GetPointer());
@@ -222,11 +189,8 @@ public:
     const int nBinsZ = static_cast<int>(ws_sptr->getZDimension()->getNBins());
     imageSize = (nBinsX) * (nBinsY) * (nBinsZ);
 
-    std::unique_ptr<MDHistoWorkspaceIterator> iterator(
-        dynamic_cast<MDHistoWorkspaceIterator *>(
-            createIteratorWithNormalization(
-                Mantid::VATES::NumEventsNormalization, ws_sptr.get())));
-    m_signal->InitializeArray(std::move(iterator), offset, imageSize);
+    m_signal->InitializeArray(ws_sptr.get(),
+                              Mantid::VATES::NumEventsNormalization, offset);
   }
 
   void tearDown() override {}
diff --git a/Vates/VatesAPI/test/vtkMDHexFactoryTest.h b/Vates/VatesAPI/test/vtkMDHexFactoryTest.h
index 9fdf7d8cc30500dd225583f58b7390238aa011e8..6c5509cc93259173ad761cba6166f5ea829f5715 100644
--- a/Vates/VatesAPI/test/vtkMDHexFactoryTest.h
+++ b/Vates/VatesAPI/test/vtkMDHexFactoryTest.h
@@ -1,6 +1,7 @@
 #ifndef VTK_MD_HEX_FACTORY_TEST
 #define VTK_MD_HEX_FACTORY_TEST
 
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/IMDEventWorkspace.h"
 #include "MantidKernel/make_unique.h"
 #include "MantidDataObjects/MDEventFactory.h"
@@ -8,9 +9,7 @@
 #include "MantidDataObjects/MDHistoWorkspace.h"
 #include "MantidDataObjects/TableWorkspace.h"
 #include "MantidTestHelpers/MDEventsTestHelper.h"
-#include "MantidVatesAPI/UserDefinedThresholdRange.h"
 #include "MantidVatesAPI/vtkMDHexFactory.h"
-#include "MantidVatesAPI/NoThresholdRange.h"
 #include "MockObjects.h"
 #include <cxxtest/TestSuite.h>
 #include <gmock/gmock.h>
@@ -50,8 +49,7 @@ private:
         AnalysisDataService::Instance().retrieve("binned");
     FakeProgressAction progressUpdater;
 
-    vtkMDHexFactory factory(boost::make_shared<UserDefinedThresholdRange>(0, 1),
-                            VATES::VolumeNormalization);
+    vtkMDHexFactory factory(VATES::VolumeNormalization);
     factory.setCheckDimensionality(doCheckDimensionality);
     if (doCheckDimensionality) {
       TS_ASSERT_THROWS(factory.initialize(binned_ws), std::runtime_error);
@@ -67,15 +65,13 @@ public:
 
   void testCreateWithoutInitalizeThrows() {
     FakeProgressAction progressUpdater;
-    vtkMDHexFactory factory(boost::make_shared<UserDefinedThresholdRange>(0, 1),
-                            VATES::VolumeNormalization);
+    vtkMDHexFactory factory(VATES::VolumeNormalization);
     TSM_ASSERT_THROWS("Have NOT initalized object. Should throw.",
                       factory.create(progressUpdater), std::runtime_error);
   }
 
   void testInitalizeWithNullWorkspaceThrows() {
-    vtkMDHexFactory factory(boost::make_shared<UserDefinedThresholdRange>(0, 1),
-                            VATES::VolumeNormalization);
+    vtkMDHexFactory factory(VATES::VolumeNormalization);
 
     IMDEventWorkspace *ws = NULL;
     TSM_ASSERT_THROWS("This is a NULL workspace. Should throw.",
@@ -84,8 +80,7 @@ public:
   }
 
   void testGetFactoryTypeName() {
-    vtkMDHexFactory factory(boost::make_shared<NoThresholdRange>(),
-                            VATES::VolumeNormalization);
+    vtkMDHexFactory factory(VATES::VolumeNormalization);
     TS_ASSERT_EQUALS("vtkMDHexFactory", factory.getFactoryTypeName());
   }
 
@@ -96,8 +91,7 @@ public:
     EXPECT_CALL(*mockSuccessor, initialize(_)).Times(1);
     EXPECT_CALL(*mockSuccessor, getFactoryTypeName()).Times(1);
 
-    vtkMDHexFactory factory(boost::make_shared<NoThresholdRange>(),
-                            VATES::VolumeNormalization);
+    vtkMDHexFactory factory(VATES::VolumeNormalization);
     factory.setSuccessor(std::move(uniqueSuccessor));
 
     auto ws = boost::make_shared<Mantid::DataObjects::TableWorkspace>();
@@ -120,8 +114,7 @@ public:
         .WillOnce(Return(vtkSmartPointer<vtkStructuredGrid>::New()));
     EXPECT_CALL(*mockSuccessor, getFactoryTypeName()).Times(1);
 
-    vtkMDHexFactory factory(boost::make_shared<NoThresholdRange>(),
-                            VATES::VolumeNormalization);
+    vtkMDHexFactory factory(VATES::VolumeNormalization);
     factory.setSuccessor(std::move(uniqueSuccessor));
 
     auto ws = boost::make_shared<Mantid::DataObjects::TableWorkspace>();
@@ -134,8 +127,7 @@ public:
 
   void testOnInitaliseCannotDelegateToSuccessor() {
     FakeProgressAction progressUpdater;
-    vtkMDHexFactory factory(boost::make_shared<NoThresholdRange>(),
-                            VATES::VolumeNormalization);
+    vtkMDHexFactory factory(VATES::VolumeNormalization);
     // factory.SetSuccessor(mockSuccessor); No Successor set.
 
     auto ws = boost::make_shared<Mantid::DataObjects::TableWorkspace>();
@@ -144,8 +136,7 @@ public:
 
   void testCreateWithoutInitializeThrows() {
     FakeProgressAction progressUpdater;
-    vtkMDHexFactory factory(boost::make_shared<NoThresholdRange>(),
-                            VATES::VolumeNormalization);
+    vtkMDHexFactory factory(VATES::VolumeNormalization);
     // initialize not called!
     TS_ASSERT_THROWS(factory.create(progressUpdater), std::runtime_error);
   }
@@ -186,8 +177,7 @@ public:
 
     Mantid::DataObjects::MDEventWorkspace3Lean::sptr ws =
         MDEventsTestHelper::makeMDEW<3>(10, 0.0, 10.0, 1);
-    vtkMDHexFactory factory(boost::make_shared<UserDefinedThresholdRange>(0, 1),
-                            VATES::VolumeNormalization);
+    vtkMDHexFactory factory(VATES::VolumeNormalization);
     factory.initialize(ws);
     vtkSmartPointer<vtkDataSet> product;
 
@@ -226,8 +216,7 @@ public:
 
     Mantid::DataObjects::MDEventWorkspace4Lean::sptr ws =
         MDEventsTestHelper::makeMDEW<4>(5, -10.0, 10.0, 1);
-    vtkMDHexFactory factory(boost::make_shared<UserDefinedThresholdRange>(0, 1),
-                            VATES::VolumeNormalization);
+    vtkMDHexFactory factory(VATES::VolumeNormalization);
     factory.initialize(ws);
     vtkSmartPointer<vtkDataSet> product;
 
@@ -274,8 +263,7 @@ public:
 
     Mantid::DataObjects::MDEventWorkspace4Lean::sptr ws =
         MDEventsTestHelper::makeMDEW<4>(4, -10.0, 10.0, 1);
-    vtkMDHexFactory factory(boost::make_shared<UserDefinedThresholdRange>(0, 1),
-                            VATES::VolumeNormalization);
+    vtkMDHexFactory factory(VATES::VolumeNormalization);
     factory.initialize(ws);
     vtkSmartPointer<vtkDataSet> product;
 
@@ -319,8 +307,7 @@ public:
   void test_CreateDataSet_from3D() {
     FakeProgressAction progressUpdate;
 
-    vtkMDHexFactory factory(boost::make_shared<UserDefinedThresholdRange>(0, 1),
-                            VATES::VolumeNormalization);
+    vtkMDHexFactory factory(VATES::VolumeNormalization);
     factory.initialize(m_ws3);
     vtkSmartPointer<vtkDataSet> product;
 
@@ -359,8 +346,7 @@ public:
   void test_CreateDataSet_from4D() {
     FakeProgressAction progressUpdate;
 
-    vtkMDHexFactory factory(boost::make_shared<UserDefinedThresholdRange>(0, 1),
-                            VATES::VolumeNormalization);
+    vtkMDHexFactory factory(VATES::VolumeNormalization);
     factory.initialize(m_ws4);
     vtkSmartPointer<vtkDataSet> product;
 
diff --git a/Vates/VatesAPI/test/vtkMDHistoHex4DFactoryTest.h b/Vates/VatesAPI/test/vtkMDHistoHex4DFactoryTest.h
index 08c6f50a62a8e488a2fdf2157e24da78a9e2c780..6d62735bbaf27ca38e39e427cd413a0807a2afca 100644
--- a/Vates/VatesAPI/test/vtkMDHistoHex4DFactoryTest.h
+++ b/Vates/VatesAPI/test/vtkMDHistoHex4DFactoryTest.h
@@ -5,9 +5,7 @@
 #include "MantidDataObjects/MDHistoWorkspace.h"
 #include "MantidTestHelpers/MDEventsTestHelper.h"
 #include "MantidVatesAPI/TimeStepToTimeStep.h"
-#include "MantidVatesAPI/UserDefinedThresholdRange.h"
 #include "MantidVatesAPI/vtkMDHistoHex4DFactory.h"
-#include "MantidVatesAPI/NoThresholdRange.h"
 #include "MockObjects.h"
 #include <cxxtest/TestSuite.h>
 #include "MantidVatesAPI/vtkStructuredGrid_Silent.h"
@@ -27,55 +25,6 @@ using namespace testing;
 class vtkMDHistoHex4DFactoryTest : public CxxTest::TestSuite {
 
 public:
-  void testThresholds() {
-    FakeProgressAction progressAction;
-
-    // Workspace with value 1.0 everywhere
-    MDHistoWorkspace_sptr ws_sptr =
-        MDEventsTestHelper::makeFakeMDHistoWorkspace(1.0, 4);
-    ws_sptr->setTransformFromOriginal(new NullCoordTransform);
-
-    // Set up so that only cells with signal values == 1 should not be filtered
-    // out by thresholding.
-
-    vtkMDHistoHex4DFactory<TimeStepToTimeStep> inside(
-        ThresholdRange_scptr(new UserDefinedThresholdRange(0, 2)),
-        Mantid::VATES::VolumeNormalization, 0);
-    inside.initialize(ws_sptr);
-    auto insideData = inside.create(progressAction);
-    auto insideProduct = vtkStructuredGrid::SafeDownCast(insideData.Get());
-
-    vtkMDHistoHex4DFactory<TimeStepToTimeStep> below(
-        ThresholdRange_scptr(new UserDefinedThresholdRange(0, 0.5)),
-        Mantid::VATES::VolumeNormalization, 0);
-    below.initialize(ws_sptr);
-    auto belowData = below.create(progressAction);
-    auto belowProduct = vtkStructuredGrid::SafeDownCast(belowData.Get());
-
-    vtkMDHistoHex4DFactory<TimeStepToTimeStep> above(
-        ThresholdRange_scptr(new UserDefinedThresholdRange(2, 3)),
-        Mantid::VATES::VolumeNormalization, 0);
-    above.initialize(ws_sptr);
-    auto aboveData = above.create(progressAction);
-    auto aboveProduct = vtkStructuredGrid::SafeDownCast(aboveData.Get());
-
-    TS_ASSERT_EQUALS((10 * 10 * 10), insideProduct->GetNumberOfCells());
-    for (auto i = 0; i < insideProduct->GetNumberOfCells(); ++i) {
-      TS_ASSERT(insideProduct->IsCellVisible(i) != 0);
-    }
-
-    // This has changed. Cells are still present but not visible.
-    TS_ASSERT_EQUALS((10 * 10 * 10), belowProduct->GetNumberOfCells());
-    for (auto i = 0; i < belowProduct->GetNumberOfCells(); ++i) {
-      TS_ASSERT(belowProduct->IsCellVisible(i) == 0);
-    }
-
-    TS_ASSERT_EQUALS((10 * 10 * 10), aboveProduct->GetNumberOfCells());
-    for (auto i = 0; i < aboveProduct->GetNumberOfCells(); ++i) {
-      TS_ASSERT(aboveProduct->IsCellVisible(i) == 0);
-    }
-  }
-
   void testProgressUpdating() {
     MockProgressAction mockProgressAction;
     // Expectation checks that progress should be >= 0 and <= 100 and called at
@@ -86,7 +35,6 @@ public:
     MDHistoWorkspace_sptr ws_sptr =
         MDEventsTestHelper::makeFakeMDHistoWorkspace(1.0, 4);
     vtkMDHistoHex4DFactory<TimeStepToTimeStep> factory(
-        ThresholdRange_scptr(new NoThresholdRange),
         Mantid::VATES::VolumeNormalization, 0);
 
     factory.initialize(ws_sptr);
@@ -103,21 +51,18 @@ public:
     MDHistoWorkspace_sptr ws_sptr =
         MDEventsTestHelper::makeFakeMDHistoWorkspace(1.0, 4);
     ws_sptr->setTransformFromOriginal(new NullCoordTransform);
-    auto pRange =
-        Mantid::Kernel::make_unique<UserDefinedThresholdRange>(0, 100);
 
     // Constructional method ensures that factory is only suitable for providing
     // mesh information.
     vtkMDHistoHex4DFactory<TimeStepToTimeStep> factory =
         vtkMDHistoHex4DFactory<TimeStepToTimeStep>(
-            ThresholdRange_scptr(pRange.release()),
             Mantid::VATES::VolumeNormalization, 0);
     factory.initialize(ws_sptr);
 
     auto product = factory.create(progressUpdate);
-    TSM_ASSERT_EQUALS(
-        "A single array should be present on the product dataset.", 1,
-        product->GetCellData()->GetNumberOfArrays());
+    TSM_ASSERT_EQUALS("Two arrays (signal and cell ghost array) should be "
+                      "present on the product dataset.",
+                      2, product->GetCellData()->GetNumberOfArrays());
     auto signalData = vtkSmartPointer<vtkDataArray>::Take(
         product->GetCellData()->GetArray(0));
     TSM_ASSERT_EQUALS("The obtained cell data has the wrong name.",
@@ -132,9 +77,8 @@ public:
 
     IMDWorkspace *nullWorkspace = NULL;
     Mantid::API::IMDWorkspace_sptr ws_sptr(nullWorkspace);
-    UserDefinedThresholdRange *pRange = new UserDefinedThresholdRange(0, 100);
     vtkMDHistoHex4DFactory<TimeStepToTimeStep> factory(
-        ThresholdRange_scptr(pRange), Mantid::VATES::VolumeNormalization, 1);
+        Mantid::VATES::VolumeNormalization, 1);
 
     TSM_ASSERT_THROWS(
         "No workspace, so should not be possible to complete initialization.",
@@ -144,10 +88,7 @@ public:
   void testCreateWithoutInitializeThrows() {
     FakeProgressAction progressAction;
 
-    auto pRange =
-        Mantid::Kernel::make_unique<UserDefinedThresholdRange>(0, 100);
     vtkMDHistoHex4DFactory<TimeStepToTimeStep> factory(
-        ThresholdRange_scptr(pRange.release()),
         Mantid::VATES::VolumeNormalization, 1);
     TS_ASSERT_THROWS(factory.create(progressAction), std::runtime_error);
   }
@@ -167,14 +108,10 @@ public:
     EXPECT_CALL(*pMockFactorySuccessor, getFactoryTypeName())
         .WillOnce(testing::Return("TypeA"));
 
-    auto pRange =
-        Mantid::Kernel::make_unique<UserDefinedThresholdRange>(0, 100);
-
     // Constructional method ensures that factory is only suitable for providing
     // mesh information.
     vtkMDHistoHex4DFactory<TimeStepToTimeStep> factory =
         vtkMDHistoHex4DFactory<TimeStepToTimeStep>(
-            ThresholdRange_scptr(pRange.release()),
             Mantid::VATES::VolumeNormalization, (double)0);
 
     // Successor is provided.
@@ -196,14 +133,10 @@ public:
     MDHistoWorkspace_sptr ws_sptr =
         MDEventsTestHelper::makeFakeMDHistoWorkspace(1.0, 2);
 
-    auto pRange =
-        Mantid::Kernel::make_unique<UserDefinedThresholdRange>(0, 100);
-
     // Constructional method ensures that factory is only suitable for providing
     // mesh information.
     vtkMDHistoHex4DFactory<TimeStepToTimeStep> factory =
         vtkMDHistoHex4DFactory<TimeStepToTimeStep>(
-            ThresholdRange_scptr(pRange.release()),
             Mantid::VATES::VolumeNormalization, (double)0);
 
     TSM_ASSERT_THROWS("Should have thrown an execption given that no successor "
@@ -235,14 +168,10 @@ public:
     EXPECT_CALL(*pMockFactorySuccessor, getFactoryTypeName())
         .WillOnce(testing::Return("TypeA"));
 
-    auto pRange =
-        Mantid::Kernel::make_unique<UserDefinedThresholdRange>(0, 100);
-
     // Constructional method ensures that factory is only suitable for providing
     // mesh information.
     vtkMDHistoHex4DFactory<TimeStepToTimeStep> factory =
         vtkMDHistoHex4DFactory<TimeStepToTimeStep>(
-            ThresholdRange_scptr(pRange.release()),
             Mantid::VATES::VolumeNormalization, (double)0);
 
     // Successor is provided.
@@ -260,12 +189,8 @@ public:
   void testTypeName() {
     using namespace Mantid::VATES;
 
-    auto pRange =
-        Mantid::Kernel::make_unique<UserDefinedThresholdRange>(0, 100);
-
     vtkMDHistoHex4DFactory<TimeStepToTimeStep> factory =
         vtkMDHistoHex4DFactory<TimeStepToTimeStep>(
-            ThresholdRange_scptr(pRange.release()),
             Mantid::VATES::VolumeNormalization, (double)0);
     TS_ASSERT_EQUALS("vtkMDHistoHex4DFactory", factory.getFactoryTypeName());
   }
@@ -288,10 +213,7 @@ public:
   void testGenerateVTKDataSet() {
     FakeProgressAction progressUpdate;
 
-    auto pRange =
-        Mantid::Kernel::make_unique<UserDefinedThresholdRange>(0, 100000);
     vtkMDHistoHex4DFactory<TimeStepToTimeStep> factory(
-        ThresholdRange_scptr(pRange.release()),
         Mantid::VATES::VolumeNormalization, 0);
     factory.initialize(m_ws_sptr);
     TS_ASSERT_THROWS_NOTHING(factory.create(progressUpdate));
diff --git a/Vates/VatesAPI/test/vtkMDHistoHexFactoryTest.h b/Vates/VatesAPI/test/vtkMDHistoHexFactoryTest.h
index 3cdb9c9515afec087463f1415b81ee773a60b967..3473ba460c7a2a50374ed1dfffbeb32a8b1b56d8 100644
--- a/Vates/VatesAPI/test/vtkMDHistoHexFactoryTest.h
+++ b/Vates/VatesAPI/test/vtkMDHistoHexFactoryTest.h
@@ -4,8 +4,6 @@
 #include "MantidKernel/make_unique.h"
 #include "MantidDataObjects/MDHistoWorkspace.h"
 #include "MantidTestHelpers/MDEventsTestHelper.h"
-#include "MantidVatesAPI/UserDefinedThresholdRange.h"
-#include "MantidVatesAPI/NoThresholdRange.h"
 #include "MantidVatesAPI/vtkMDHistoHexFactory.h"
 #include "MockObjects.h"
 #include <cxxtest/TestSuite.h>
@@ -29,52 +27,6 @@ using namespace testing;
 class vtkMDHistoHexFactoryTest : public CxxTest::TestSuite {
 
 public:
-  void testThresholds() {
-    FakeProgressAction progressUpdate;
-
-    // Workspace with value 1.0 everywhere
-    MDHistoWorkspace_sptr ws_sptr =
-        MDEventsTestHelper::makeFakeMDHistoWorkspace(1.0, 3);
-    ws_sptr->setTransformFromOriginal(new NullCoordTransform);
-
-    vtkMDHistoHexFactory inside(
-        boost::make_shared<UserDefinedThresholdRange>(0, 2),
-        Mantid::VATES::VolumeNormalization);
-    inside.initialize(ws_sptr);
-    auto insideData = inside.create(progressUpdate);
-    auto insideProduct = vtkStructuredGrid::SafeDownCast(insideData.Get());
-
-    vtkMDHistoHexFactory below(
-        boost::make_shared<UserDefinedThresholdRange>(0, 0.5),
-        Mantid::VATES::VolumeNormalization);
-    below.initialize(ws_sptr);
-    auto belowData = below.create(progressUpdate);
-    auto belowProduct = vtkStructuredGrid::SafeDownCast(belowData.Get());
-
-    vtkMDHistoHexFactory above(
-        boost::make_shared<UserDefinedThresholdRange>(2, 3),
-        Mantid::VATES::VolumeNormalization);
-    above.initialize(ws_sptr);
-    auto aboveData = above.create(progressUpdate);
-    auto aboveProduct = vtkStructuredGrid::SafeDownCast(aboveData.Get());
-
-    TS_ASSERT_EQUALS((10 * 10 * 10), insideProduct->GetNumberOfCells());
-    for (auto i = 0; i < insideProduct->GetNumberOfCells(); ++i) {
-      TS_ASSERT(insideProduct->IsCellVisible(i) != 0);
-    }
-
-    // This has changed. Cells are still present but not visible.
-    TS_ASSERT_EQUALS((10 * 10 * 10), belowProduct->GetNumberOfCells());
-    for (auto i = 0; i < belowProduct->GetNumberOfCells(); ++i) {
-      TS_ASSERT(belowProduct->IsCellVisible(i) == 0);
-    }
-
-    TS_ASSERT_EQUALS((10 * 10 * 10), aboveProduct->GetNumberOfCells());
-    for (auto i = 0; i < aboveProduct->GetNumberOfCells(); ++i) {
-      TS_ASSERT(aboveProduct->IsCellVisible(i) == 0);
-    }
-  }
-
   void testSignalAspects() {
     FakeProgressAction progressUpdate;
 
@@ -85,15 +37,13 @@ public:
 
     // Constructional method ensures that factory is only suitable for providing
     // mesh information.
-    vtkMDHistoHexFactory factory(
-        boost::make_shared<UserDefinedThresholdRange>(0, 10000),
-        Mantid::VATES::VolumeNormalization);
+    vtkMDHistoHexFactory factory(Mantid::VATES::VolumeNormalization);
     factory.initialize(ws_sptr);
 
     auto product = factory.create(progressUpdate);
-    TSM_ASSERT_EQUALS(
-        "A single array should be present on the product dataset.", 1,
-        product->GetCellData()->GetNumberOfArrays());
+    TSM_ASSERT_EQUALS("Two arrays (signal and cell ghost array) should be "
+                      "present on the product dataset.",
+                      2, product->GetCellData()->GetNumberOfArrays());
     vtkDataArray *signalData = product->GetCellData()->GetArray(0);
     TSM_ASSERT_EQUALS("The obtained cell data has the wrong name.",
                       std::string("signal"),
@@ -112,8 +62,7 @@ public:
 
     MDHistoWorkspace_sptr ws_sptr =
         MDEventsTestHelper::makeFakeMDHistoWorkspace(1.0, 3);
-    vtkMDHistoHexFactory factory(boost::make_shared<NoThresholdRange>(),
-                                 Mantid::VATES::VolumeNormalization);
+    vtkMDHistoHexFactory factory(Mantid::VATES::VolumeNormalization);
 
     factory.initialize(ws_sptr);
     auto product = factory.create(mockProgressAction);
@@ -126,9 +75,7 @@ public:
     IMDWorkspace *nullWorkspace = NULL;
     Mantid::API::IMDWorkspace_sptr ws_sptr(nullWorkspace);
 
-    vtkMDHistoHexFactory factory(
-        boost::make_shared<UserDefinedThresholdRange>(0, 10000),
-        Mantid::VATES::VolumeNormalization);
+    vtkMDHistoHexFactory factory(Mantid::VATES::VolumeNormalization);
 
     TSM_ASSERT_THROWS(
         "No workspace, so should not be possible to complete initialization.",
@@ -137,9 +84,7 @@ public:
 
   void testCreateWithoutInitializeThrows() {
     FakeProgressAction progressUpdate;
-    vtkMDHistoHexFactory factory(
-        boost::make_shared<UserDefinedThresholdRange>(0, 10000),
-        Mantid::VATES::VolumeNormalization);
+    vtkMDHistoHexFactory factory(Mantid::VATES::VolumeNormalization);
     TS_ASSERT_THROWS(factory.create(progressUpdate), std::runtime_error);
   }
 
@@ -159,9 +104,7 @@ public:
 
     // Constructional method ensures that factory is only suitable for providing
     // mesh information.
-    vtkMDHistoHexFactory factory(
-        boost::make_shared<UserDefinedThresholdRange>(0, 10000),
-        Mantid::VATES::VolumeNormalization);
+    vtkMDHistoHexFactory factory(Mantid::VATES::VolumeNormalization);
 
     // Successor is provided.
     factory.setSuccessor(std::move(uniqueSuccessor));
@@ -183,9 +126,7 @@ public:
 
     // Constructional method ensures that factory is only suitable for providing
     // mesh information.
-    vtkMDHistoHexFactory factory(
-        boost::make_shared<UserDefinedThresholdRange>(0, 10000),
-        Mantid::VATES::VolumeNormalization);
+    vtkMDHistoHexFactory factory(Mantid::VATES::VolumeNormalization);
 
     TSM_ASSERT_THROWS("Should have thrown an execption given that no successor "
                       "was available.",
@@ -217,9 +158,7 @@ public:
 
     // Constructional method ensures that factory is only suitable for providing
     // mesh information.
-    vtkMDHistoHexFactory factory(
-        boost::make_shared<UserDefinedThresholdRange>(0, 10000),
-        Mantid::VATES::VolumeNormalization);
+    vtkMDHistoHexFactory factory(Mantid::VATES::VolumeNormalization);
 
     // Successor is provided.
     factory.setSuccessor(std::move(uniqueSuccessor));
@@ -235,9 +174,7 @@ public:
 
   void testTypeName() {
     using namespace Mantid::VATES;
-    vtkMDHistoHexFactory factory(
-        boost::make_shared<UserDefinedThresholdRange>(0, 10000),
-        Mantid::VATES::VolumeNormalization);
+    vtkMDHistoHexFactory factory(Mantid::VATES::VolumeNormalization);
     TS_ASSERT_EQUALS("vtkMDHistoHexFactory", factory.getFactoryTypeName());
   }
 };
@@ -260,9 +197,7 @@ public:
     FakeProgressAction progressUpdate;
 
     // Create the factory.
-    vtkMDHistoHexFactory factory(
-        boost::make_shared<UserDefinedThresholdRange>(0, 10000),
-        Mantid::VATES::VolumeNormalization);
+    vtkMDHistoHexFactory factory(Mantid::VATES::VolumeNormalization);
     factory.initialize(m_ws_sptr);
 
     TS_ASSERT_THROWS_NOTHING(factory.create(progressUpdate));
diff --git a/Vates/VatesAPI/test/vtkMDHistoLineFactoryTest.h b/Vates/VatesAPI/test/vtkMDHistoLineFactoryTest.h
index af30d6e400a5b8260ff0fa8bffe31f94861ae9d2..15871c051c81ea2bcf4709ec919a51d9be5a5efb 100644
--- a/Vates/VatesAPI/test/vtkMDHistoLineFactoryTest.h
+++ b/Vates/VatesAPI/test/vtkMDHistoLineFactoryTest.h
@@ -3,8 +3,6 @@
 
 #include "MantidAPI/IMDIterator.h"
 #include "MantidTestHelpers/MDEventsTestHelper.h"
-#include "MantidVatesAPI/UserDefinedThresholdRange.h"
-#include "MantidVatesAPI/NoThresholdRange.h"
 #include "MantidVatesAPI/vtkMDHistoLineFactory.h"
 #include "MockObjects.h"
 #include <cxxtest/TestSuite.h>
@@ -31,9 +29,7 @@ public:
     IMDWorkspace *nullWorkspace = NULL;
     Mantid::API::IMDWorkspace_sptr ws_sptr(nullWorkspace);
 
-    vtkMDHistoLineFactory factory(
-        ThresholdRange_scptr(new UserDefinedThresholdRange(0, 10000)),
-        Mantid::VATES::VolumeNormalization);
+    vtkMDHistoLineFactory factory(Mantid::VATES::VolumeNormalization);
 
     TSM_ASSERT_THROWS(
         "No workspace, so should not be possible to complete initialization.",
@@ -42,72 +38,10 @@ public:
 
   void testCreateWithoutInitializeThrows() {
     FakeProgressAction progressUpdate;
-    vtkMDHistoLineFactory factory(
-        ThresholdRange_scptr(new UserDefinedThresholdRange(0, 10000)),
-        Mantid::VATES::VolumeNormalization);
+    vtkMDHistoLineFactory factory(Mantid::VATES::VolumeNormalization);
     TS_ASSERT_THROWS(factory.create(progressUpdate), std::runtime_error);
   }
 
-  void testInsideThresholds() {
-    FakeProgressAction progressUpdate;
-
-    Mantid::API::IMDWorkspace_sptr ws_sptr =
-        MDEventsTestHelper::makeFakeMDHistoWorkspace(1.0, 1);
-
-    // Thresholds have been set such that the signal values (hard-coded to 1,
-    // see above) will fall between the minimum 0 and maximum 2.
-    vtkMDHistoLineFactory inside(
-        ThresholdRange_scptr(new UserDefinedThresholdRange(0, 2)),
-        Mantid::VATES::VolumeNormalization);
-    inside.initialize(ws_sptr);
-    auto insideData = inside.create(progressUpdate);
-    auto insideProduct = vtkUnstructuredGrid::SafeDownCast(insideData.Get());
-
-    TS_ASSERT_EQUALS(9, insideProduct->GetNumberOfCells());
-    TS_ASSERT_EQUALS(10, insideProduct->GetNumberOfPoints());
-  }
-
-  void testAboveThreshold() {
-    using namespace Mantid::Geometry;
-    using namespace testing;
-
-    FakeProgressAction progressUpdate;
-
-    Mantid::API::IMDWorkspace_sptr ws_sptr =
-        MDEventsTestHelper::makeFakeMDHistoWorkspace(1.0, 1);
-
-    // Thresholds have been set such that the signal values (hard-coded to 1,
-    // see above) will fall above and outside the minimum 0 and maximum 0.5.
-    vtkMDHistoLineFactory above(
-        ThresholdRange_scptr(new UserDefinedThresholdRange(0, 0.5)),
-        Mantid::VATES::VolumeNormalization);
-    above.initialize(ws_sptr);
-    auto aboveData = above.create(progressUpdate);
-    auto aboveProduct = vtkUnstructuredGrid::SafeDownCast(aboveData.Get());
-
-    TS_ASSERT_EQUALS(0, aboveProduct->GetNumberOfCells());
-    TS_ASSERT_EQUALS(10, aboveProduct->GetNumberOfPoints());
-  }
-
-  void testBelowThreshold() {
-    FakeProgressAction progressUpdate;
-
-    Mantid::API::IMDWorkspace_sptr ws_sptr =
-        MDEventsTestHelper::makeFakeMDHistoWorkspace(1.0, 1);
-
-    // Thresholds have been set such that the signal values (hard-coded to 1,
-    // see above) will fall below and outside the minimum 1.5 and maximum 2.
-    vtkMDHistoLineFactory below(
-        ThresholdRange_scptr(new UserDefinedThresholdRange(1.5, 2)),
-        Mantid::VATES::VolumeNormalization);
-    below.initialize(ws_sptr);
-    auto belowData = below.create(progressUpdate);
-    auto belowProduct = vtkUnstructuredGrid::SafeDownCast(belowData.Get());
-
-    TS_ASSERT_EQUALS(0, belowProduct->GetNumberOfCells());
-    TS_ASSERT_EQUALS(10, belowProduct->GetNumberOfPoints());
-  }
-
   void testProgressUpdates() {
     MockProgressAction mockProgressAction;
     // Expectation checks that progress should be >= 0 and <= 100 and called at
@@ -117,8 +51,7 @@ public:
 
     MDHistoWorkspace_sptr ws_sptr =
         MDEventsTestHelper::makeFakeMDHistoWorkspace(1.0, 1);
-    vtkMDHistoLineFactory factory(ThresholdRange_scptr(new NoThresholdRange),
-                                  Mantid::VATES::VolumeNormalization);
+    vtkMDHistoLineFactory factory(Mantid::VATES::VolumeNormalization);
 
     factory.initialize(ws_sptr);
     auto product = factory.create(mockProgressAction);
@@ -144,9 +77,7 @@ public:
 
     // Constructional method ensures that factory is only suitable for providing
     // mesh information.
-    vtkMDHistoLineFactory factory(
-        ThresholdRange_scptr(new UserDefinedThresholdRange(0, 10000)),
-        Mantid::VATES::VolumeNormalization);
+    vtkMDHistoLineFactory factory(Mantid::VATES::VolumeNormalization);
 
     // Successor is provided.
     factory.setSuccessor(std::move(uniqueSuccessor));
@@ -168,9 +99,7 @@ public:
 
     // Constructional method ensures that factory is only suitable for providing
     // mesh information.
-    vtkMDHistoLineFactory factory(
-        ThresholdRange_scptr(new UserDefinedThresholdRange(0, 10000)),
-        Mantid::VATES::VolumeNormalization);
+    vtkMDHistoLineFactory factory(Mantid::VATES::VolumeNormalization);
 
     TSM_ASSERT_THROWS("Should have thrown an execption given that no successor "
                       "was available.",
@@ -202,9 +131,7 @@ public:
 
     // Constructional method ensures that factory is only suitable for providing
     // mesh information.
-    vtkMDHistoLineFactory factory(
-        boost::make_shared<UserDefinedThresholdRange>(0, 10000),
-        Mantid::VATES::VolumeNormalization);
+    vtkMDHistoLineFactory factory(Mantid::VATES::VolumeNormalization);
 
     // Successor is provided.
     factory.setSuccessor(std::move(uniqueSuccessor));
@@ -219,9 +146,7 @@ public:
   }
 
   void testTypeName() {
-    vtkMDHistoLineFactory factory(
-        boost::make_shared<UserDefinedThresholdRange>(0, 10000),
-        Mantid::VATES::VolumeNormalization);
+    vtkMDHistoLineFactory factory(Mantid::VATES::VolumeNormalization);
     TS_ASSERT_EQUALS("vtkMDHistoLineFactory", factory.getFactoryTypeName());
   }
 };
@@ -242,11 +167,7 @@ public:
 
   void testGenerateVTKDataSet() {
     FakeProgressAction progressUpdate;
-    // Thresholds have been set such that the signal values (hard-coded to 1,
-    // see above) will fall between the minimum 0 and maximum 2.
-    vtkMDHistoLineFactory factory(
-        boost::make_shared<UserDefinedThresholdRange>(0, 2),
-        Mantid::VATES::VolumeNormalization);
+    vtkMDHistoLineFactory factory(Mantid::VATES::VolumeNormalization);
     factory.initialize(m_ws_sptr);
     TS_ASSERT_THROWS_NOTHING(factory.create(progressUpdate));
   }
diff --git a/Vates/VatesAPI/test/vtkMDHistoQuadFactoryTest.h b/Vates/VatesAPI/test/vtkMDHistoQuadFactoryTest.h
index b03dba696237abf56a195cc898d6d5692b911f64..28424d037c3f2e92b9883090593cecaa93d9133d 100644
--- a/Vates/VatesAPI/test/vtkMDHistoQuadFactoryTest.h
+++ b/Vates/VatesAPI/test/vtkMDHistoQuadFactoryTest.h
@@ -4,8 +4,6 @@
 #include "MantidAPI/IMDIterator.h"
 #include "MantidKernel/make_unique.h"
 #include "MantidTestHelpers/MDEventsTestHelper.h"
-#include "MantidVatesAPI/UserDefinedThresholdRange.h"
-#include "MantidVatesAPI/NoThresholdRange.h"
 #include "MantidVatesAPI/vtkMDHistoQuadFactory.h"
 #include "MockObjects.h"
 #include <cxxtest/TestSuite.h>
@@ -35,8 +33,7 @@ public:
     IMDWorkspace *nullWorkspace = NULL;
     Mantid::API::IMDWorkspace_sptr ws_sptr(nullWorkspace);
 
-    auto pRange = boost::make_shared<UserDefinedThresholdRange>(0, 100);
-    vtkMDHistoQuadFactory factory(pRange, Mantid::VATES::VolumeNormalization);
+    vtkMDHistoQuadFactory factory(Mantid::VATES::VolumeNormalization);
 
     TSM_ASSERT_THROWS(
         "No workspace, so should not be possible to complete initialization.",
@@ -46,8 +43,7 @@ public:
   void testCreateWithoutInitializeThrows() {
     FakeProgressAction progressUpdate;
 
-    auto pRange = boost::make_shared<UserDefinedThresholdRange>(0, 100);
-    vtkMDHistoQuadFactory factory(pRange, Mantid::VATES::VolumeNormalization);
+    vtkMDHistoQuadFactory factory(Mantid::VATES::VolumeNormalization);
     TS_ASSERT_THROWS(factory.create(progressUpdate), std::runtime_error);
   }
 
@@ -58,10 +54,7 @@ public:
     Mantid::API::IMDWorkspace_sptr ws_sptr =
         MDEventsTestHelper::makeFakeMDHistoWorkspace(1.0, 2);
 
-    // Thresholds have been set such that the signal values (hard-coded to 1,
-    // see above) will fall between the minimum 0 and maximum 2.
-    auto pRange = boost::make_shared<UserDefinedThresholdRange>(0, 2);
-    vtkMDHistoQuadFactory inside(pRange, Mantid::VATES::VolumeNormalization);
+    vtkMDHistoQuadFactory inside(Mantid::VATES::VolumeNormalization);
     inside.initialize(ws_sptr);
     auto product = inside.create(progressUpdate);
     auto data = vtkDataSet::SafeDownCast(product.Get());
@@ -71,53 +64,6 @@ public:
     TS_ASSERT_EQUALS((11 * 11), insideProduct->GetNumberOfPoints());
   }
 
-  void testAboveThreshold() {
-    FakeProgressAction progressUpdate;
-    // WS with 2 dimensions
-    Mantid::API::IMDWorkspace_sptr ws_sptr =
-        MDEventsTestHelper::makeFakeMDHistoWorkspace(1.0, 2);
-
-    // Thresholds have been set such that the signal values (hard-coded to 1,
-    // see above) will fall above and outside the minimum 0 and maximum 0.5.
-    auto pRange = boost::make_shared<UserDefinedThresholdRange>(0, 0.5);
-    vtkMDHistoQuadFactory above(pRange, Mantid::VATES::VolumeNormalization);
-    above.initialize(ws_sptr);
-    auto product = above.create(progressUpdate);
-    auto data = vtkDataSet::SafeDownCast(product.Get());
-    vtkSmartPointer<vtkDataSet> aboveProduct(data);
-
-    // This changed from previously, in order to ensure that we do not pass on
-    // empty
-    // workspaces. A single point is created in the center by the
-    // vtkNullUnstructuredGrid
-    TS_ASSERT_EQUALS(1, aboveProduct->GetNumberOfCells());
-    TS_ASSERT_EQUALS(1, aboveProduct->GetNumberOfPoints());
-  }
-
-  void testBelowThreshold() {
-    FakeProgressAction progressUpdate;
-    // WS with 2 dimensions
-    Mantid::API::IMDWorkspace_sptr ws_sptr =
-        MDEventsTestHelper::makeFakeMDHistoWorkspace(1.0, 2);
-
-    // Thresholds have been set such that the signal values (hard-coded to 1,
-    // see above) will fall below and outside the minimum 1.5 and maximum 2.
-    auto pRange = boost::make_shared<UserDefinedThresholdRange>(1.5, 2);
-    vtkMDHistoQuadFactory below(pRange, Mantid::VATES::VolumeNormalization);
-
-    below.initialize(ws_sptr);
-    auto product = below.create(progressUpdate);
-    auto data = vtkUnstructuredGrid::SafeDownCast(product.Get());
-    vtkSmartPointer<vtkDataSet> belowProduct(data);
-
-    // This changed from previously, in order to ensure that we do not pass on
-    // empty
-    // workspaces. A single point is created in the center by the
-    // vtkNullUnstructuredGrid
-    TS_ASSERT_EQUALS(1, belowProduct->GetNumberOfCells());
-    TS_ASSERT_EQUALS(1, belowProduct->GetNumberOfPoints());
-  }
-
   void testInitializationDelegates() {
     // If the workspace provided is not a 4D imdworkspace, it should call the
     // successor's initalization
@@ -135,8 +81,7 @@ public:
 
     // Constructional method ensures that factory is only suitable for providing
     // mesh information.
-    auto pRange = boost::make_shared<UserDefinedThresholdRange>(0, 1);
-    vtkMDHistoQuadFactory factory(pRange, Mantid::VATES::VolumeNormalization);
+    vtkMDHistoQuadFactory factory(Mantid::VATES::VolumeNormalization);
 
     // Successor is provided.
     factory.setSuccessor(std::move(uniqueSuccessor));
@@ -159,9 +104,7 @@ public:
 
     // Constructional method ensures that factory is only suitable for providing
     // mesh information.
-    UserDefinedThresholdRange *pRange = new UserDefinedThresholdRange(0, 1);
-    vtkMDHistoQuadFactory factory(ThresholdRange_scptr(pRange),
-                                  Mantid::VATES::VolumeNormalization);
+    vtkMDHistoQuadFactory factory(Mantid::VATES::VolumeNormalization);
 
     TSM_ASSERT_THROWS("Should have thrown an execption given that no successor "
                       "was available.",
@@ -193,8 +136,7 @@ public:
 
     // Constructional method ensures that factory is only suitable for providing
     // mesh information.
-    auto pRange = boost::make_shared<UserDefinedThresholdRange>(0, 1);
-    vtkMDHistoQuadFactory factory(pRange, Mantid::VATES::VolumeNormalization);
+    vtkMDHistoQuadFactory factory(Mantid::VATES::VolumeNormalization);
 
     // Successor is provided.
     factory.setSuccessor(std::move(uniqueSuccessor));
@@ -209,8 +151,7 @@ public:
   }
 
   void testTypeName() {
-    auto pRange = boost::make_shared<UserDefinedThresholdRange>(0, 1);
-    vtkMDHistoQuadFactory factory(pRange, Mantid::VATES::VolumeNormalization);
+    vtkMDHistoQuadFactory factory(Mantid::VATES::VolumeNormalization);
     TS_ASSERT_EQUALS("vtkMDHistoQuadFactory", factory.getFactoryTypeName());
   }
 
@@ -223,8 +164,7 @@ public:
 
     MDHistoWorkspace_sptr ws_sptr =
         MDEventsTestHelper::makeFakeMDHistoWorkspace(1.0, 2);
-    vtkMDHistoQuadFactory factory(ThresholdRange_scptr(new NoThresholdRange),
-                                  Mantid::VATES::VolumeNormalization);
+    vtkMDHistoQuadFactory factory(Mantid::VATES::VolumeNormalization);
 
     factory.initialize(ws_sptr);
     auto product = factory.create(mockProgressAction);
@@ -250,10 +190,7 @@ public:
 
   void testGenerateVTKDataSet() {
     FakeProgressAction progressUpdate;
-    // Thresholds have been set such that the signal values (hard-coded to 1,
-    // see above) will fall between the minimum 0 and maximum 2.
-    auto pRange = boost::make_shared<UserDefinedThresholdRange>(0, 1);
-    vtkMDHistoQuadFactory factory(pRange, Mantid::VATES::VolumeNormalization);
+    vtkMDHistoQuadFactory factory(Mantid::VATES::VolumeNormalization);
     factory.initialize(m_ws_sptr);
     TS_ASSERT_THROWS_NOTHING(factory.create(progressUpdate));
   }
diff --git a/Vates/VatesAPI/test/vtkMDLineFactoryTest.h b/Vates/VatesAPI/test/vtkMDLineFactoryTest.h
index 2189e58b48b7097d45d8d3d9f4103c47b004c4e2..22707258d21bf5c360f3f7f8f69d53ec8599cacc 100644
--- a/Vates/VatesAPI/test/vtkMDLineFactoryTest.h
+++ b/Vates/VatesAPI/test/vtkMDLineFactoryTest.h
@@ -3,9 +3,9 @@
 
 #include <cxxtest/TestSuite.h>
 #include "MantidKernel/make_unique.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidDataObjects/TableWorkspace.h"
 #include "MantidVatesAPI/vtkMDLineFactory.h"
-#include "MantidVatesAPI/NoThresholdRange.h"
 #include "MockObjects.h"
 #include "MantidTestHelpers/MDEventsTestHelper.h"
 #include "vtkCellType.h"
@@ -24,8 +24,7 @@ using namespace testing;
 class vtkMDLineFactoryTest : public CxxTest::TestSuite {
 public:
   void testGetFactoryTypeName() {
-    vtkMDLineFactory factory(boost::make_shared<NoThresholdRange>(),
-                             Mantid::VATES::VolumeNormalization);
+    vtkMDLineFactory factory(Mantid::VATES::VolumeNormalization);
     TS_ASSERT_EQUALS("vtkMDLineFactory", factory.getFactoryTypeName());
   }
 
@@ -36,8 +35,7 @@ public:
     EXPECT_CALL(*mockSuccessor, initialize(_)).Times(1);
     EXPECT_CALL(*mockSuccessor, getFactoryTypeName()).Times(1);
 
-    vtkMDLineFactory factory(boost::make_shared<NoThresholdRange>(),
-                             Mantid::VATES::VolumeNormalization);
+    vtkMDLineFactory factory(Mantid::VATES::VolumeNormalization);
     factory.setSuccessor(std::move(uniqueSuccessor));
 
     ITableWorkspace_sptr ws =
@@ -60,8 +58,7 @@ public:
         .WillOnce(Return(vtkSmartPointer<vtkStructuredGrid>::New()));
     EXPECT_CALL(*mockSuccessor, getFactoryTypeName()).Times(1);
 
-    vtkMDLineFactory factory(boost::make_shared<NoThresholdRange>(),
-                             Mantid::VATES::VolumeNormalization);
+    vtkMDLineFactory factory(Mantid::VATES::VolumeNormalization);
     factory.setSuccessor(std::move(uniqueSuccessor));
 
     auto ws = boost::make_shared<Mantid::DataObjects::TableWorkspace>();
@@ -73,10 +70,7 @@ public:
   }
 
   void testOnInitaliseCannotDelegateToSuccessor() {
-    vtkMDLineFactory factory(boost::make_shared<NoThresholdRange>(),
-                             Mantid::VATES::VolumeNormalization);
-    // factory.SetSuccessor(mockSuccessor); No Successor set.
-
+    vtkMDLineFactory factory(Mantid::VATES::VolumeNormalization);
     ITableWorkspace_sptr ws =
         boost::make_shared<Mantid::DataObjects::TableWorkspace>();
     TS_ASSERT_THROWS(factory.initialize(ws), std::runtime_error);
@@ -85,8 +79,7 @@ public:
   void testCreateWithoutInitializeThrows() {
     FakeProgressAction progressUpdate;
 
-    vtkMDLineFactory factory(boost::make_shared<NoThresholdRange>(),
-                             Mantid::VATES::VolumeNormalization);
+    vtkMDLineFactory factory(Mantid::VATES::VolumeNormalization);
     // initialize not called!
     TS_ASSERT_THROWS(factory.create(progressUpdate), std::runtime_error);
   }
@@ -115,8 +108,7 @@ public:
     Workspace_sptr binned =
         Mantid::API::AnalysisDataService::Instance().retrieve("binned");
 
-    vtkMDLineFactory factory(boost::make_shared<NoThresholdRange>(),
-                             Mantid::VATES::VolumeNormalization);
+    vtkMDLineFactory factory(Mantid::VATES::VolumeNormalization);
     factory.initialize(binned);
 
     auto product = factory.create(mockProgressAction);
@@ -162,8 +154,7 @@ public:
     Workspace_sptr binned =
         Mantid::API::AnalysisDataService::Instance().retrieve("binned");
 
-    vtkMDLineFactory factory(boost::make_shared<NoThresholdRange>(),
-                             Mantid::VATES::VolumeNormalization);
+    vtkMDLineFactory factory(Mantid::VATES::VolumeNormalization);
     factory.initialize(binned);
 
     auto product = factory.create(progressAction);
diff --git a/Vates/VatesAPI/test/vtkMDQuadFactoryTest.h b/Vates/VatesAPI/test/vtkMDQuadFactoryTest.h
index cc4674639bf0a10e1e4ee82c919dc876f299e408..d29dfd93af33f454a6a302b4e3ac445f64f1a1a7 100644
--- a/Vates/VatesAPI/test/vtkMDQuadFactoryTest.h
+++ b/Vates/VatesAPI/test/vtkMDQuadFactoryTest.h
@@ -3,9 +3,9 @@
 
 #include <cxxtest/TestSuite.h>
 #include "MantidKernel/make_unique.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidDataObjects/TableWorkspace.h"
 #include "MantidVatesAPI/vtkMDQuadFactory.h"
-#include "MantidVatesAPI/NoThresholdRange.h"
 #include "MockObjects.h"
 #include "MantidTestHelpers/MDEventsTestHelper.h"
 #include "vtkCellType.h"
@@ -25,8 +25,7 @@ class vtkMDQuadFactoryTest : public CxxTest::TestSuite {
 
 public:
   void testGetFactoryTypeName() {
-    vtkMDQuadFactory factory(boost::make_shared<NoThresholdRange>(),
-                             Mantid::VATES::VolumeNormalization);
+    vtkMDQuadFactory factory(Mantid::VATES::VolumeNormalization);
     TS_ASSERT_EQUALS("vtkMDQuadFactory", factory.getFactoryTypeName());
   }
 
@@ -37,8 +36,7 @@ public:
     EXPECT_CALL(*mockSuccessor, initialize(_)).Times(1);
     EXPECT_CALL(*mockSuccessor, getFactoryTypeName()).Times(1);
 
-    vtkMDQuadFactory factory(boost::make_shared<NoThresholdRange>(),
-                             Mantid::VATES::VolumeNormalization);
+    vtkMDQuadFactory factory(Mantid::VATES::VolumeNormalization);
     factory.setSuccessor(std::move(uniqueSuccessor));
 
     ITableWorkspace_sptr ws =
@@ -61,8 +59,7 @@ public:
         .WillOnce(Return(vtkSmartPointer<vtkStructuredGrid>::New()));
     EXPECT_CALL(*mockSuccessor, getFactoryTypeName()).Times(1);
 
-    vtkMDQuadFactory factory(boost::make_shared<NoThresholdRange>(),
-                             Mantid::VATES::VolumeNormalization);
+    vtkMDQuadFactory factory(Mantid::VATES::VolumeNormalization);
     factory.setSuccessor(std::move(uniqueSuccessor));
 
     ITableWorkspace_sptr ws =
@@ -75,10 +72,7 @@ public:
   }
 
   void testOnInitaliseCannotDelegateToSuccessor() {
-    vtkMDQuadFactory factory(boost::make_shared<NoThresholdRange>(),
-                             Mantid::VATES::VolumeNormalization);
-    // factory.SetSuccessor(mockSuccessor); No Successor set.
-
+    vtkMDQuadFactory factory(Mantid::VATES::VolumeNormalization);
     ITableWorkspace_sptr ws =
         boost::make_shared<Mantid::DataObjects::TableWorkspace>();
     TS_ASSERT_THROWS(factory.initialize(ws), std::runtime_error);
@@ -87,8 +81,7 @@ public:
   void testCreateWithoutInitaliseThrows() {
     FakeProgressAction progressUpdate;
 
-    vtkMDQuadFactory factory(boost::make_shared<NoThresholdRange>(),
-                             Mantid::VATES::VolumeNormalization);
+    vtkMDQuadFactory factory(Mantid::VATES::VolumeNormalization);
     // initialize not called!
     TS_ASSERT_THROWS(factory.create(progressUpdate), std::runtime_error);
   }
@@ -118,8 +111,7 @@ public:
     Workspace_sptr binned =
         Mantid::API::AnalysisDataService::Instance().retrieve("binned");
 
-    vtkMDQuadFactory factory(boost::make_shared<NoThresholdRange>(),
-                             Mantid::VATES::VolumeNormalization);
+    vtkMDQuadFactory factory(Mantid::VATES::VolumeNormalization);
     factory.initialize(binned);
 
     auto product = factory.create(mockProgressAction);
@@ -165,8 +157,7 @@ public:
     Workspace_sptr binned =
         Mantid::API::AnalysisDataService::Instance().retrieve("binned");
 
-    vtkMDQuadFactory factory(boost::make_shared<NoThresholdRange>(),
-                             Mantid::VATES::VolumeNormalization);
+    vtkMDQuadFactory factory(Mantid::VATES::VolumeNormalization);
     factory.initialize(binned);
 
     auto product = factory.create(progressUpdate);
diff --git a/Vates/VatesAPI/test/vtkSplatterPlotFactoryTest.h b/Vates/VatesAPI/test/vtkSplatterPlotFactoryTest.h
index 39df83afdf9000121f1b8bcdba9ee29a61c5e971..b2c09d3bbb3fadd21d781e9242b1838a3ec5d2e1 100644
--- a/Vates/VatesAPI/test/vtkSplatterPlotFactoryTest.h
+++ b/Vates/VatesAPI/test/vtkSplatterPlotFactoryTest.h
@@ -9,7 +9,6 @@
 #include "MantidVatesAPI/FieldDataToMetadata.h"
 #include "MantidVatesAPI/MetadataJsonManager.h"
 #include "MantidVatesAPI/MetadataToFieldData.h"
-#include "MantidVatesAPI/UserDefinedThresholdRange.h"
 #include "MantidVatesAPI/VatesConfigurations.h"
 #include "MantidVatesAPI/vtkSplatterPlotFactory.h"
 #include "MockObjects.h"
@@ -37,15 +36,13 @@ public:
 
   void testCreateWithoutInitializeThrows() {
     FakeProgressAction progressUpdate;
-    vtkSplatterPlotFactory factory(
-        ThresholdRange_scptr(new UserDefinedThresholdRange(0, 1)), "signal");
+    vtkSplatterPlotFactory factory("signal");
     TSM_ASSERT_THROWS("Have NOT initalized object. Should throw.",
                       factory.create(progressUpdate), std::runtime_error);
   }
 
   void testInitializeWithNullWorkspaceThrows() {
-    vtkSplatterPlotFactory factory(
-        ThresholdRange_scptr(new UserDefinedThresholdRange(0, 1)), "signal");
+    vtkSplatterPlotFactory factory("signal");
     IMDEventWorkspace *ws = NULL;
     TSM_ASSERT_THROWS("This is a NULL workspace. Should throw.",
                       factory.initialize(Workspace_sptr(ws)),
@@ -60,8 +57,7 @@ public:
     size_t binning = 5;
     MDHistoWorkspace_sptr ws =
         MDEventsTestHelper::makeFakeMDHistoWorkspace(1.0, 3, binning);
-    vtkSplatterPlotFactory factory(
-        ThresholdRange_scptr(new UserDefinedThresholdRange(0, 1)), "signal");
+    vtkSplatterPlotFactory factory("signal");
     factory.initialize(ws);
     vtkSmartPointer<vtkDataSet> product;
 
@@ -98,8 +94,7 @@ public:
     size_t binning = 5;
     IMDHistoWorkspace_sptr ws =
         MDEventsTestHelper::makeFakeMDHistoWorkspace(1.0, 4, binning);
-    vtkSplatterPlotFactory factory(
-        ThresholdRange_scptr(new UserDefinedThresholdRange(0, 1)), "signal");
+    vtkSplatterPlotFactory factory("signal");
     factory.initialize(ws);
     vtkSmartPointer<vtkDataSet> product;
 
@@ -133,8 +128,7 @@ public:
 
     MDEventWorkspace3Lean::sptr ws =
         MDEventsTestHelper::makeMDEW<3>(10, 0.0, 10.0, 1);
-    vtkSplatterPlotFactory factory(
-        boost::make_shared<UserDefinedThresholdRange>(0, 1), "signal");
+    vtkSplatterPlotFactory factory("signal");
     factory.initialize(ws);
     vtkSmartPointer<vtkDataSet> product;
 
@@ -148,7 +142,7 @@ public:
     // New sizes for splatter plot test, after changing the way the points
     // are selected, 5/28/2013
     const size_t expected_n_points = 50;
-    const size_t expected_n_cells = 0;
+    const size_t expected_n_cells = 50;
 
     const size_t expected_n_signals = expected_n_points;
 
@@ -168,8 +162,7 @@ public:
 
     MDEventWorkspace4Lean::sptr ws =
         MDEventsTestHelper::makeMDEW<4>(5, -10.0, 10.0, 1);
-    vtkSplatterPlotFactory factory(
-        ThresholdRange_scptr(new UserDefinedThresholdRange(0, 1)), "signal");
+    vtkSplatterPlotFactory factory("signal");
     factory.initialize(ws);
     vtkSmartPointer<vtkDataSet> product;
 
@@ -202,8 +195,7 @@ public:
     FakeProgressAction progressUpdate;
     MDEventWorkspace3Lean::sptr ws =
         MDEventsTestHelper::makeMDEW<3>(10, 0.0, 10.0, 1);
-    vtkSplatterPlotFactory factory(
-        ThresholdRange_scptr(new UserDefinedThresholdRange(0, 1)), "signal");
+    vtkSplatterPlotFactory factory("signal");
     factory.initialize(ws);
     vtkDataSet *product = NULL;
 
diff --git a/Vates/VatesSimpleGui/QtWidgets/inc/MantidVatesSimpleGuiQtWidgets/AxisInformation.h b/Vates/VatesSimpleGui/QtWidgets/inc/MantidVatesSimpleGuiQtWidgets/AxisInformation.h
index 29b6143644ab50b00e690495af9c5134e9ce4341..4a654363343ad6a71716d1bd86113c8cd99a1093 100644
--- a/Vates/VatesSimpleGui/QtWidgets/inc/MantidVatesSimpleGuiQtWidgets/AxisInformation.h
+++ b/Vates/VatesSimpleGui/QtWidgets/inc/MantidVatesSimpleGuiQtWidgets/AxisInformation.h
@@ -57,7 +57,7 @@ public:
    * Get the title of the associated axis.
    * @return the axis title
    */
-  std::string getTitle() { return this->title; }
+  const std::string &getTitle() { return this->title; }
 
   /**
    * Set the maximum extent of the associated axis.
@@ -73,12 +73,12 @@ public:
    * Set the title of the associated axis.
    * @param title the axis title to apply
    */
-  void setTitle(std::string title) { this->title = title; }
+  void setTitle(const std::string &title) { this->title = title; }
 
 private:
-  std::string title; ///< The axis title (or label)
   double minimum;    ///< The minimum extent of the axis
   double maximum;    ///< The maximum extent of the axis
+  std::string title; ///< The axis title (or label)
 };
 }
 }
diff --git a/Vates/VatesSimpleGui/QtWidgets/inc/MantidVatesSimpleGuiQtWidgets/GeometryParser.h b/Vates/VatesSimpleGui/QtWidgets/inc/MantidVatesSimpleGuiQtWidgets/GeometryParser.h
index aeaef286f4fa37aed31696cd8d43a839f39a687a..2e980eda96aaeb0b8185bf73359e5afd43d63e22 100644
--- a/Vates/VatesSimpleGui/QtWidgets/inc/MantidVatesSimpleGuiQtWidgets/GeometryParser.h
+++ b/Vates/VatesSimpleGui/QtWidgets/inc/MantidVatesSimpleGuiQtWidgets/GeometryParser.h
@@ -62,7 +62,7 @@ public:
    * @param dimension the XML string containing the axis information
    * @return an axis information object containing the given information
    */
-  AxisInformation *getAxisInfo(const std::string dimension);
+  AxisInformation *getAxisInfo(const std::string &dimension);
 
 private:
   /**
@@ -70,7 +70,7 @@ private:
    * @param val the axis bound to convert
    * @return the double representation of the bound
    */
-  double convertBounds(Poco::XML::XMLString val);
+  double convertBounds(const Poco::XML::XMLString &val);
 
   Poco::AutoPtr<Poco::XML::Document> pDoc; ///< A XML document handle
 };
diff --git a/Vates/VatesSimpleGui/QtWidgets/inc/MantidVatesSimpleGuiQtWidgets/ModeControlWidget.h b/Vates/VatesSimpleGui/QtWidgets/inc/MantidVatesSimpleGuiQtWidgets/ModeControlWidget.h
index fe0e013cff60037c02f362feeacecd37a402229f..13ee793db56cc95d185a0bcb21091c8205ed34f3 100644
--- a/Vates/VatesSimpleGui/QtWidgets/inc/MantidVatesSimpleGuiQtWidgets/ModeControlWidget.h
+++ b/Vates/VatesSimpleGui/QtWidgets/inc/MantidVatesSimpleGuiQtWidgets/ModeControlWidget.h
@@ -48,7 +48,7 @@ public:
    * Default constructor.
    * @param parent the parent widget of the mode control widget
    */
-  ModeControlWidget(QWidget *parent = 0);
+  ModeControlWidget(QWidget *parent = nullptr);
   /// Default destructor.
   ~ModeControlWidget() override;
 
@@ -73,7 +73,7 @@ public slots:
   void setToSelectedView(ModeControlWidget::Views view);
 
   /// Convert a string into an enum
-  ModeControlWidget::Views getViewFromString(QString view);
+  ModeControlWidget::Views getViewFromString(const QString &view);
 
 signals:
   /**
diff --git a/Vates/VatesSimpleGui/QtWidgets/inc/MantidVatesSimpleGuiQtWidgets/RotationPointDialog.h b/Vates/VatesSimpleGui/QtWidgets/inc/MantidVatesSimpleGuiQtWidgets/RotationPointDialog.h
index 325caf4340f15b10fbe388802d342405196e2c52..fa6f120a4bcdddbe18c0c1b1628cec218657d7ed 100644
--- a/Vates/VatesSimpleGui/QtWidgets/inc/MantidVatesSimpleGuiQtWidgets/RotationPointDialog.h
+++ b/Vates/VatesSimpleGui/QtWidgets/inc/MantidVatesSimpleGuiQtWidgets/RotationPointDialog.h
@@ -42,7 +42,7 @@ class EXPORT_OPT_MANTIDVATES_SIMPLEGUI_QTWIDGETS RotationPointDialog
 
 public:
   /// Default constructor.
-  RotationPointDialog(QWidget *parent = 0);
+  RotationPointDialog(QWidget *parent = nullptr);
   /// Default destructor.
   ~RotationPointDialog() override;
 
diff --git a/Vates/VatesSimpleGui/QtWidgets/src/GeometryParser.cpp b/Vates/VatesSimpleGui/QtWidgets/src/GeometryParser.cpp
index 72b57b2ed795a7d41d021bd5af247bcf42d64378..67a8ed6cdd674c4a12d63944afa23bc5d912feaa 100644
--- a/Vates/VatesSimpleGui/QtWidgets/src/GeometryParser.cpp
+++ b/Vates/VatesSimpleGui/QtWidgets/src/GeometryParser.cpp
@@ -23,7 +23,7 @@ GeometryParser::GeometryParser(const char *xml) {
   this->pDoc = parser.parseString(Poco::XML::XMLString(xml));
 }
 
-AxisInformation *GeometryParser::getAxisInfo(const std::string dimension) {
+AxisInformation *GeometryParser::getAxisInfo(const std::string &dimension) {
   AxisInformation *axis = new AxisInformation();
 
   Poco::AutoPtr<Poco::XML::NodeList> pNodes =
@@ -49,7 +49,7 @@ AxisInformation *GeometryParser::getAxisInfo(const std::string dimension) {
   title = label;
   for (unsigned long int j = 0; j < cNodes->length(); ++j) {
     Poco::XML::Node *cNode = cNodes->item(j);
-    Poco::XML::XMLString elem = cNode->nodeName();
+    const Poco::XML::XMLString &elem = cNode->nodeName();
     // Keeping below around in case we go back to using axis name
     /*
         if (elem == Poco::XML::XMLString("Name"))
@@ -72,7 +72,7 @@ AxisInformation *GeometryParser::getAxisInfo(const std::string dimension) {
   return axis;
 }
 
-double GeometryParser::convertBounds(Poco::XML::XMLString val) {
+double GeometryParser::convertBounds(const Poco::XML::XMLString &val) {
   double temp;
   std::stringstream number(val);
   number >> temp;
diff --git a/Vates/VatesSimpleGui/QtWidgets/src/ModeControlWidget.cpp b/Vates/VatesSimpleGui/QtWidgets/src/ModeControlWidget.cpp
index 4b11798beab1e57b1b059571f54f4c3d109f13ba..4d718d61e9d718dea706bc04b799d3b3b4d3732e 100644
--- a/Vates/VatesSimpleGui/QtWidgets/src/ModeControlWidget.cpp
+++ b/Vates/VatesSimpleGui/QtWidgets/src/ModeControlWidget.cpp
@@ -165,7 +165,8 @@ void ModeControlWidget::enableViewButton(ModeControlWidget::Views mode,
  * @param view A selected view.
  * @returns The selected view as enum or the standard view.
  */
-ModeControlWidget::Views ModeControlWidget::getViewFromString(QString view) {
+ModeControlWidget::Views
+ModeControlWidget::getViewFromString(const QString &view) {
   if (!view.isEmpty() && mapFromStringToView.count(view) == 1) {
     return mapFromStringToView[view];
   } else {
diff --git a/Vates/VatesSimpleGui/StandAloneExec/inc/VsgMainWindow.h b/Vates/VatesSimpleGui/StandAloneExec/inc/VsgMainWindow.h
index 30bab5d7c073db4663e648705b21501ca57b220f..96bfd6c10a9851114e020b7f8e6d8fdf69e0a91e 100644
--- a/Vates/VatesSimpleGui/StandAloneExec/inc/VsgMainWindow.h
+++ b/Vates/VatesSimpleGui/StandAloneExec/inc/VsgMainWindow.h
@@ -49,7 +49,7 @@ public:
    * Default constructor.
    * @param parent the parent widget for the main window
    */
-  VsgMainWindow(QWidget *parent = 0);
+  VsgMainWindow(QWidget *parent = nullptr);
   /// Default destructor.
   ~VsgMainWindow() override;
 
diff --git a/Vates/VatesSimpleGui/StandAloneExec/src/main.cpp b/Vates/VatesSimpleGui/StandAloneExec/src/main.cpp
index bbd81c060ad56b8f141a278405e9e1008fb28872..52b4b76048795fc5d0258493687788585f24bf59 100644
--- a/Vates/VatesSimpleGui/StandAloneExec/src/main.cpp
+++ b/Vates/VatesSimpleGui/StandAloneExec/src/main.cpp
@@ -10,13 +10,13 @@ int main(int argc, char **argv) {
     window.show();
     return app.exec();
   } catch (std::exception &e) {
-    QMessageBox::critical(0, "VatesSimpleGui - Error",
+    QMessageBox::critical(nullptr, "VatesSimpleGui - Error",
                           QString("An unhandled exception has been caught. "
                                   "VatesSimpleGui will have to close. "
                                   "Details:\n\n") +
                               e.what());
   } catch (...) {
-    QMessageBox::critical(0, "VatesSimpleGui - Error",
+    QMessageBox::critical(nullptr, "VatesSimpleGui - Error",
                           "An unhandled exception has been caught. "
                           "VatesSimpleGui will have to close.");
   }
diff --git a/Vates/VatesSimpleGui/ViewWidgets/icons/ViewWidgetsIcons.qrc b/Vates/VatesSimpleGui/ViewWidgets/icons/ViewWidgetsIcons.qrc
index d6e22e59aefd6da2250d378879360e2659af31fc..42c9f3ff235499481befdd156a949bd49fc681d7 100644
--- a/Vates/VatesSimpleGui/ViewWidgets/icons/ViewWidgetsIcons.qrc
+++ b/Vates/VatesSimpleGui/ViewWidgets/icons/ViewWidgetsIcons.qrc
@@ -6,5 +6,7 @@
         <file>pvIcon.png</file>
         <file>pqEditColor24.png</file>
         <file>resetViewToAll24.png</file>
+        <file>pqSlice24.png</file>
+        <file>pqThreshold24.png</file>
     </qresource>
 </RCC>
diff --git a/Vates/VatesSimpleGui/ViewWidgets/icons/pqSlice24.png b/Vates/VatesSimpleGui/ViewWidgets/icons/pqSlice24.png
new file mode 100644
index 0000000000000000000000000000000000000000..070ce3bda466eb48ec29e873917fe3699d4262b9
Binary files /dev/null and b/Vates/VatesSimpleGui/ViewWidgets/icons/pqSlice24.png differ
diff --git a/Vates/VatesSimpleGui/ViewWidgets/icons/pqThreshold24.png b/Vates/VatesSimpleGui/ViewWidgets/icons/pqThreshold24.png
new file mode 100644
index 0000000000000000000000000000000000000000..407467f848105219bb51123b92952c3b7f4204de
Binary files /dev/null and b/Vates/VatesSimpleGui/ViewWidgets/icons/pqThreshold24.png differ
diff --git a/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/ColorMapEditorPanel.h b/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/ColorMapEditorPanel.h
index fde59adacd082163700af4b9be0411ff24bcf4bb..49c6818696aafdb0880e552d0f91ccdad9b976b9 100644
--- a/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/ColorMapEditorPanel.h
+++ b/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/ColorMapEditorPanel.h
@@ -41,7 +41,7 @@ class EXPORT_OPT_MANTIDVATES_SIMPLEGUI_VIEWWIDGETS ColorMapEditorPanel
   Q_OBJECT
 public:
   /// Default constructor.
-  ColorMapEditorPanel(QWidget *parent = 0);
+  ColorMapEditorPanel(QWidget *parent = nullptr);
   /// Default destructor.
   ~ColorMapEditorPanel() override;
   /// Connect the panel to ParaView
diff --git a/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/ColorSelectionWidget.h b/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/ColorSelectionWidget.h
index d30e3df512d84ea4c3061e111ad3f236ea8fe3fa..2dc23ce5bd3409e384bf09466a65cacd39b2283c 100644
--- a/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/ColorSelectionWidget.h
+++ b/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/ColorSelectionWidget.h
@@ -52,7 +52,7 @@ class EXPORT_OPT_MANTIDVATES_SIMPLEGUI_VIEWWIDGETS ColorSelectionWidget
 
 public:
   /// Default constructor.
-  ColorSelectionWidget(QWidget *parent = 0);
+  ColorSelectionWidget(QWidget *parent = nullptr);
   /// Default destructor.
   ~ColorSelectionWidget() override {}
 
diff --git a/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/MdViewerWidget.h b/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/MdViewerWidget.h
index 9deb82e95360f9dfe061775a8eb2a53b5c632b5d..5b8ef47568efcd0c2fec968bd398f622a72ee58e 100644
--- a/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/MdViewerWidget.h
+++ b/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/MdViewerWidget.h
@@ -90,11 +90,17 @@ public:
   void renderWorkspace(QString workspaceName, int workspaceType,
                        std::string instrumentName) override;
   /// See MantidQt::API::VatesViewerInterface
-  void setupPluginMode() override;
+  void setupPluginMode(int WsType, const std::string &instrumentName) override;
   /// Load the state of the window from a Mantid project file
   void loadFromProject(const std::string &lines) override;
   /// Save the state of the window to a Mantid project file
   std::string saveToProject(ApplicationWindow *app) override;
+  /// Returns a list of workspace names that are used by this window
+  std::vector<std::string> getWorkspaceNames() override;
+  /// Returns the user friendly name of the window
+  std::string getWindowName() override;
+  /// Returns the type of the window
+  std::string getWindowType() override;
 
 public slots:
   /// Seet MantidQt::API::VatesViewerInterface
@@ -118,7 +124,7 @@ protected slots:
   /// Triggered when panel is changed.
   void panelChanged();
   /// On rebin
-  void onRebin(std::string algorithmType);
+  void onRebin(const std::string &algorithmType);
   /// On  unbin
   void onUnbin();
   /// On switching an MDEvent source to a temporary source.
@@ -214,7 +220,7 @@ private:
   /// Set the signals/slots for the ParaView components based on the view.
   void setParaViewComponentsForView();
   /// Run the necessary setup for the main view.
-  void setupMainView();
+  void setupMainView(ModeControlWidget::Views viewType);
   /// Creates the UI and mode switch connection.
   void setupUiAndConnections();
   /// Create the requested view.
@@ -227,7 +233,7 @@ private:
   void updateAppState();
   /// Get the initial view for the current workspace and user setting
   ModeControlWidget::Views getInitialView(int workspaceType,
-                                          std::string instrumentName);
+                                          const std::string &instrumentName);
   /// Check that the view is valid for teh workspace type
   ModeControlWidget::Views
   checkViewAgainstWorkspace(ModeControlWidget::Views view, int workspaceType);
@@ -243,10 +249,10 @@ private:
   void resetCurrentView(int workspaceType, const std::string &instrumentName);
   /// Render rebinned workspace
   pqPipelineSource *
-  prepareRebinnedWorkspace(const std::string rebinnedWorkspaceName,
-                           std::string sourceType);
+  prepareRebinnedWorkspace(const std::string &rebinnedWorkspaceName,
+                           const std::string &sourceType);
   /// Handle drag and drop of peaks workspcaes
-  void handleDragAndDropPeaksWorkspaces(QEvent *e, QString text,
+  void handleDragAndDropPeaksWorkspaces(QEvent *e, const QString &text,
                                         QStringList &wsNames);
   /// Set up the default color for the background of the view.
   void setColorForBackground();
@@ -254,7 +260,7 @@ private:
   void setColorMap();
   /// Render the original workspace
   pqPipelineSource *
-  renderOriginalWorkspace(const std::string originalWorkspaceName);
+  renderOriginalWorkspace(const std::string &originalWorkspaceName);
 
   /// Remove the rebinning when switching views or otherwise.
   void
diff --git a/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/MultisliceView.h b/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/MultisliceView.h
index f8e622c278dd425062d81a4b43eda7c489dff8ea..c7bec4262ee5cfa77549adebd144ba555f4c89a2 100644
--- a/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/MultisliceView.h
+++ b/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/MultisliceView.h
@@ -55,8 +55,8 @@ public:
    * @param rebinnedSourcesManager Pointer to a RebinnedSourcesManager
    * @param createRenderProxy :: Whether to create a render proxy for this view
    */
-  MultiSliceView(QWidget *parent = 0,
-                 RebinnedSourcesManager *rebinnedSourcesManager = 0,
+  MultiSliceView(QWidget *parent = nullptr,
+                 RebinnedSourcesManager *rebinnedSourcesManager = nullptr,
                  bool createRenderProxy = true);
   /// Default constructor.
   ~MultiSliceView() override;
diff --git a/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/PeaksTabWidget.h b/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/PeaksTabWidget.h
index 301dc32e5c2098f2fbfb2a760c8093f09b5c0ff5..564b7743d25a0651226b7aedb8f7117ec49693d9 100644
--- a/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/PeaksTabWidget.h
+++ b/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/PeaksTabWidget.h
@@ -20,7 +20,7 @@ namespace SimpleGui {
 class EXPORT_OPT_MANTIDVATES_SIMPLEGUI_VIEWWIDGETS PeakCustomTabWidget
     : public QTabWidget {
 public:
-  PeakCustomTabWidget(QWidget *parent = 0) { setParent(parent); }
+  PeakCustomTabWidget(QWidget *parent = nullptr) { setParent(parent); }
 
   // Overridden method from QTabWidget
   QTabBar *tabBar() { return QTabWidget::tabBar(); }
@@ -31,13 +31,14 @@ class EXPORT_OPT_MANTIDVATES_SIMPLEGUI_VIEWWIDGETS PeaksTabWidget
   Q_OBJECT
 public:
   PeaksTabWidget(std::vector<Mantid::API::IPeaksWorkspace_sptr> ws,
-                 const std::string &coordinateSystem, QWidget *parent = 0);
+                 const std::string &coordinateSystem,
+                 QWidget *parent = nullptr);
   ~PeaksTabWidget() override;
   void setupMvc(std::map<std::string, std::vector<bool>> visiblePeaks);
   void addNewPeaksWorkspace(Mantid::API::IPeaksWorkspace_sptr peaksWorkspace,
                             std::vector<bool> visiblePeaks);
-  void updateTabs(std::map<std::string, std::vector<bool>> visiblePeaks,
-                  std::map<std::string, QColor> colors);
+  void updateTabs(std::map<std::string, std::vector<bool>> &visiblePeaks,
+                  std::map<std::string, QColor> &colors);
 signals:
   void zoomToPeak(Mantid::API::IPeaksWorkspace_sptr ws, int row);
   void sortPeaks(const std::string &columnToSortBy, const bool sortAscending,
@@ -47,10 +48,11 @@ public slots:
 
 private:
   /// Update a certain tab.
-  void updateTab(std::vector<bool> visiblePeaks, QColor color, int index);
+  void updateTab(const std::vector<bool> &visiblePeaks, const QColor &color,
+                 int index);
   /// Adds a new tab to the tab widget.
   void addNewTab(Mantid::API::IPeaksWorkspace_sptr peaksWorkspace,
-                 std::string tabName, std::vector<bool> visiblePeaks);
+                 const std::string &tabName, std::vector<bool> visiblePeaks);
   /// Auto-generated UI controls.
   Ui::PeaksTabWidget ui;
   /// Peaks workspace to view.
diff --git a/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/PeaksTableControllerVsi.h b/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/PeaksTableControllerVsi.h
index c0f9ef3bcd4df83b9bde339131b28d5bc59f035b..db1e15939ae974748b1839d32674514b7d4871f2 100644
--- a/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/PeaksTableControllerVsi.h
+++ b/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/PeaksTableControllerVsi.h
@@ -26,13 +26,13 @@ class EXPORT_OPT_MANTIDVATES_SIMPLEGUI_VIEWWIDGETS PeaksTableControllerVsi
   Q_OBJECT
 public:
   PeaksTableControllerVsi(boost::shared_ptr<CameraManager> cameraManager,
-                          QWidget *parent = 0);
+                          QWidget *parent = nullptr);
   ~PeaksTableControllerVsi() override;
   std::vector<bool> getViewablePeaks();
   bool hasPeaks();
   void showFullTable();
   void removeTable();
-  std::string getConcatenatedWorkspaceNames(std::string delimiter);
+  std::string getConcatenatedWorkspaceNames(const std::string &delimiter);
   void
   updatePeaksWorkspaces(const QList<QPointer<pqPipelineSource>> &peakSources,
                         pqPipelineSource *splatSource);
@@ -43,21 +43,20 @@ public slots:
   void onZoomToPeak(Mantid::API::IPeaksWorkspace_sptr peaksWorkspace, int row);
   void onPeaksSorted(const std::string &columnToSortBy,
                      const bool sortAscending,
-                     Mantid::API::IPeaksWorkspace_sptr ws);
+                     const Mantid::API::IPeaksWorkspace *ws);
   void destroySinglePeakSource();
   void onPeakMarkerDestroyed();
 
 private:
-  void addWorkspace(pqPipelineSource *source,
-                    QPointer<pqPipelineSource> splatSource);
+  void addWorkspace(pqPipelineSource *source, pqPipelineSource *splatSource);
   std::vector<std::string>
-  extractFrameFromSource(QPointer<pqPipelineSource> splatSource);
+  extractFrameFromSource(pqPipelineSource *splatSource);
   void generateSinglePeaksSource(double position1, double position2,
                                  double position3, double radius);
   void resetSinglePeaksSource(double position1, double position2,
                               double position3, double radius);
   bool checkMatchingSources(pqPipelineSource *source,
-                            QPointer<pqPipelineSource> splatSource);
+                            pqPipelineSource *splatSource);
   double getMaxRadius(Mantid::Geometry::PeakShape_sptr shape);
   void removeLayout(QWidget *widget);
   void createTable();
diff --git a/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/PeaksWidget.h b/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/PeaksWidget.h
index ae7aee329f254bf0c1bb27f2e7390d123b9779f3..0a324a8ed473a5dc7213c7341f9f6404e9a53829 100644
--- a/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/PeaksWidget.h
+++ b/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/PeaksWidget.h
@@ -18,7 +18,7 @@ class EXPORT_OPT_MANTIDVATES_SIMPLEGUI_VIEWWIDGETS PeaksWidget
   Q_OBJECT
 public:
   PeaksWidget(Mantid::API::IPeaksWorkspace_sptr ws,
-              const std::string &coordinateSystem, QWidget *parent = 0);
+              const std::string &coordinateSystem, QWidget *parent = nullptr);
   void setupMvc(std::vector<bool> visiblePeaks);
   void updateModel(std::vector<bool> visiblePeaks);
 signals:
@@ -26,7 +26,7 @@ signals:
   void sortPeaks(const std::string &columnToSortBy, const bool sortAscending,
                  Mantid::API::IPeaksWorkspace_sptr ws);
 public slots:
-  void onCurrentChanged(QModelIndex current, QModelIndex);
+  void onCurrentChanged(const QModelIndex &current, const QModelIndex &);
   void onPeaksSorted(const std::string &columnToSortBy,
                      const bool sortAscending);
 
diff --git a/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/RebinAlgorithmDialogProvider.h b/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/RebinAlgorithmDialogProvider.h
index 8255d596c1bf2484e4578803ca8b15016d9ec049..13a6d7c571ff6ff9c9477547c53b26ddac505bc8 100644
--- a/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/RebinAlgorithmDialogProvider.h
+++ b/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/RebinAlgorithmDialogProvider.h
@@ -48,19 +48,22 @@ public:
 
   ~RebinAlgorithmDialogProvider();
 
-  void showDialog(std::string inputWorkspace, std::string outputWorkspace,
-                  std::string algorithmType);
+  void showDialog(const std::string &inputWorkspace,
+                  const std::string &outputWorkspace,
+                  const std::string &algorithmType);
 
   static const size_t BinCutOffValue;
 
 private:
-  MantidQt::API::AlgorithmDialog *createDialog(
-      Mantid::API::IAlgorithm_sptr algorithm, const std::string &inputWorkspace,
-      const std::string &outputWorkspace, const std::string &algorithmType);
+  MantidQt::API::AlgorithmDialog *
+  createDialog(const Mantid::API::IAlgorithm &algorithm,
+               const std::string &inputWorkspace,
+               const std::string &outputWorkspace,
+               const std::string &algorithmType);
 
   void
   setAxisDimensions(MantidQt::MantidWidgets::SlicingAlgorithmDialog *dialog,
-                    std::string inputWorkspace);
+                    const std::string &inputWorkspace);
 
   Mantid::API::IMDEventWorkspace_sptr
   getWorkspace(const std::string &workspaceName);
diff --git a/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/RebinnedSourcesManager.h b/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/RebinnedSourcesManager.h
index 0f06707f15b0312985f6889b128831b0a578dbb6..41a31886482944b0859ed004fd6af98ae696dc2c 100644
--- a/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/RebinnedSourcesManager.h
+++ b/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/RebinnedSourcesManager.h
@@ -61,7 +61,7 @@ class EXPORT_OPT_MANTIDVATES_SIMPLEGUI_VIEWWIDGETS RebinnedSourcesManager
       MantidQt::API::WorkspaceObserver {
   Q_OBJECT
 public:
-  RebinnedSourcesManager(QWidget *parent = 0);
+  RebinnedSourcesManager(QWidget *parent = nullptr);
 
   ~RebinnedSourcesManager() override;
 
@@ -132,7 +132,7 @@ private:
   pqPipelineSource *m_rebinnedSource;
 
   std::vector<pqPipelineSource *>
-  findAllRebinnedSourcesForWorkspace(std::string workspaceName);
+  findAllRebinnedSourcesForWorkspace(const std::string &workspaceName);
 
   void swapSources(pqPipelineSource *source1, pqPipelineSource *source2);
 
@@ -142,9 +142,9 @@ private:
                              std::string &outputWorkspace,
                              pqPipelineSource *source,
                              std::string workspaceName,
-                             std::string algorithmType);
+                             const std::string &algorithmType);
 
-  void untrackWorkspaces(std::pair<std::string, std::string> key);
+  void untrackWorkspaces(const std::pair<std::string, std::string> &key);
 
   void copyProperties(pqPipelineFilter *filter1, pqPipelineFilter *filter2);
 
diff --git a/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/SplatterPlotView.h b/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/SplatterPlotView.h
index b967c71af60debd014981905a41fbbafcc233bad..9e381b4f43eb2f1764a71190cff1663ef435593b 100644
--- a/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/SplatterPlotView.h
+++ b/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/SplatterPlotView.h
@@ -65,9 +65,10 @@ public:
    * @param rebinnedSourcesManager Pointer to a RebinnedSourcesManager
    * @param createRenderProxy :: Whether to create a render proxy for this view
    */
-  explicit SplatterPlotView(QWidget *parent = 0,
-                            RebinnedSourcesManager *rebinnedSourcesManager = 0,
-                            bool createRenderProxy = true);
+  explicit SplatterPlotView(
+      QWidget *parent = nullptr,
+      RebinnedSourcesManager *rebinnedSourcesManager = nullptr,
+      bool createRenderProxy = true);
   /// Default destructor
   ~SplatterPlotView() override;
 
diff --git a/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/SplatterPlotView.ui b/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/SplatterPlotView.ui
index 49505fefb1c0d8addbb296cd4a0026556a0c41b1..e547784798173ef29f3efcc12bc8b32d29fe6ab0 100644
--- a/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/SplatterPlotView.ui
+++ b/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/SplatterPlotView.ui
@@ -38,13 +38,6 @@
        </property>
       </spacer>
      </item>
-     <item>
-      <widget class="QPushButton" name="thresholdButton">
-       <property name="text">
-        <string>Threshold</string>
-       </property>
-      </widget>
-     </item>
      <item>
       <widget class="QPushButton" name="overridePeakCoordsButton">
        <property name="toolTip">
@@ -90,6 +83,23 @@
        </property>
       </widget>
      </item>
+     <item>
+      <widget class="QPushButton" name="thresholdButton">
+       <property name="text">
+        <string/>
+       </property>
+       <property name="icon">
+        <iconset resource="../../icons/ViewWidgetsIcons.qrc">
+         <normaloff>:/VatesSimpleGuiViewWidgets/icons/pqThreshold24.png</normaloff>:/VatesSimpleGuiViewWidgets/icons/pqThreshold24.png</iconset>
+       </property>
+       <property name="iconSize">
+        <size>
+         <width>24</width>
+         <height>24</height>
+        </size>
+       </property>
+      </widget>
+     </item>
      <item>
       <spacer name="horizontalSpacer_2">
        <property name="orientation">
@@ -129,6 +139,8 @@
    </item>
   </layout>
  </widget>
- <resources/>
+ <resources>
+  <include location="../../icons/ViewWidgetsIcons.qrc"/>
+ </resources>
  <connections/>
 </ui>
diff --git a/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/StandardView.h b/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/StandardView.h
index 1c77e4caea592a150f856ce7e2013413fcb1fc01..14524c20090621f8b678067f505dcea21eed976c 100644
--- a/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/StandardView.h
+++ b/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/StandardView.h
@@ -53,8 +53,8 @@ class EXPORT_OPT_MANTIDVATES_SIMPLEGUI_VIEWWIDGETS StandardView
 
 public:
   /// Default constructor.
-  StandardView(QWidget *parent = 0,
-               RebinnedSourcesManager *rebinnedSourcesManager = 0,
+  StandardView(QWidget *parent = nullptr,
+               RebinnedSourcesManager *rebinnedSourcesManager = nullptr,
                bool createRenderProxy = true);
   /// Default destructor.
   ~StandardView() override;
@@ -89,6 +89,8 @@ public slots:
 protected slots:
   /// Add a slice to the current dataset.
   void onCutButtonClicked();
+  /// Apply the threshold filter to the current dataset.
+  void onThresholdButtonClicked();
   /// Perform operations when rendering is done.
   void onRenderDone();
   /// Invoke the ScaleWorkspace on the current dataset.
diff --git a/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/StandardView.ui b/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/StandardView.ui
index c3c83e587838de402e3a8a2bd38ff66bb296c040..508468c9a380b0f0810451760039e82dce3e7627 100644
--- a/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/StandardView.ui
+++ b/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/StandardView.ui
@@ -72,8 +72,41 @@
      </item>
      <item>
       <widget class="QPushButton" name="cutButton">
+       <property name="toolTip">
+        <string>apply cut filter</string>
+       </property>
        <property name="text">
-        <string>Cut</string>
+        <string/>
+       </property>
+       <property name="icon">
+        <iconset resource="../../icons/ViewWidgetsIcons.qrc">
+         <normaloff>:/VatesSimpleGuiViewWidgets/icons/pqSlice24.png</normaloff>:/VatesSimpleGuiViewWidgets/icons/pqSlice24.png</iconset>
+       </property>
+       <property name="iconSize">
+        <size>
+         <width>24</width>
+         <height>24</height>
+        </size>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="thresholdButton">
+       <property name="toolTip">
+        <string>apply threshold filter</string>
+       </property>
+       <property name="text">
+        <string/>
+       </property>
+       <property name="icon">
+        <iconset resource="../../icons/ViewWidgetsIcons.qrc">
+         <normaloff>:/VatesSimpleGuiViewWidgets/icons/pqThreshold24.png</normaloff>:/VatesSimpleGuiViewWidgets/icons/pqThreshold24.png</iconset>
+       </property>
+       <property name="iconSize">
+        <size>
+         <width>24</width>
+         <height>24</height>
+        </size>
        </property>
       </widget>
      </item>
@@ -111,6 +144,8 @@
   </layout>
  </widget>
  <layoutdefault spacing="6" margin="11"/>
- <resources/>
+ <resources>
+  <include location="../../icons/ViewWidgetsIcons.qrc"/>
+ </resources>
  <connections/>
 </ui>
diff --git a/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/ThreesliceView.h b/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/ThreesliceView.h
index cee050523252aaf149681316281c4f68825fa68e..d007c21ef144d4bcb7c0d2b397fc1d94e7ce4bef 100644
--- a/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/ThreesliceView.h
+++ b/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/ThreesliceView.h
@@ -56,8 +56,8 @@ public:
    * @param rebinnedSourcesManager Pointer to a RebinnedSourcesManager
    * @param createRenderProxy :: Whether to create a render proxy for this view
    */
-  ThreeSliceView(QWidget *parent = 0,
-                 RebinnedSourcesManager *rebinnedSourcesManager = 0,
+  ThreeSliceView(QWidget *parent = nullptr,
+                 RebinnedSourcesManager *rebinnedSourcesManager = nullptr,
                  bool createRenderProxy = true);
   /// Default destructor.
   ~ThreeSliceView() override;
diff --git a/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/TimeControlWidget.h b/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/TimeControlWidget.h
index 4651f8642129ad4e37403d3ff1282e02fae9d1a5..1c734d04a7d24dc1d97649b5185476888369c02e 100644
--- a/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/TimeControlWidget.h
+++ b/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/TimeControlWidget.h
@@ -42,7 +42,7 @@ class EXPORT_OPT_MANTIDVATES_SIMPLEGUI_VIEWWIDGETS TimeControlWidget
 
 public:
   /// Default constructor.
-  TimeControlWidget(QWidget *parent = 0);
+  TimeControlWidget(QWidget *parent = nullptr);
   /// Default destructor.
   ~TimeControlWidget() override;
 
diff --git a/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/ViewBase.h b/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/ViewBase.h
index 9b9b5d985a2d6c5ae0443a1ea2572a041144e179..1ea71dbb53bd7c226d36524c7778f15ab3953d3f 100644
--- a/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/ViewBase.h
+++ b/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/ViewBase.h
@@ -58,8 +58,8 @@ class EXPORT_OPT_MANTIDVATES_SIMPLEGUI_VIEWWIDGETS ViewBase : public QWidget {
   Q_OBJECT
 public:
   /// Default constructor.
-  ViewBase(QWidget *parent = 0,
-           RebinnedSourcesManager *rebinnedSourcesManager = 0);
+  ViewBase(QWidget *parent = nullptr,
+           RebinnedSourcesManager *rebinnedSourcesManager = nullptr);
 
   /// Default destructor.
   ~ViewBase() override {}
diff --git a/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/VsiApplyBehaviour.h b/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/VsiApplyBehaviour.h
index 7da0696c3d76e981e3fb103fbdc01c8df2593189..5fce015034299c06e410c8a205e206f6c887953e 100644
--- a/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/VsiApplyBehaviour.h
+++ b/Vates/VatesSimpleGui/ViewWidgets/inc/MantidVatesSimpleGuiViewWidgets/VsiApplyBehaviour.h
@@ -16,7 +16,8 @@ public:
   typedef QObject Superclass;
 
 public:
-  VsiApplyBehaviour(Mantid::VATES::ColorScaleLock *lock, QObject *parent = 0);
+  VsiApplyBehaviour(Mantid::VATES::ColorScaleLock *lock,
+                    QObject *parent = nullptr);
   ~VsiApplyBehaviour() override{};
 
   /// Register/unregister pqPropertiesPanel instances to monitor.
@@ -32,4 +33,4 @@ private:
 }
 }
 }
-#endif
\ No newline at end of file
+#endif
diff --git a/Vates/VatesSimpleGui/ViewWidgets/src/BackgroundRgbProvider.cpp b/Vates/VatesSimpleGui/ViewWidgets/src/BackgroundRgbProvider.cpp
index ead81038f0f1b800c936986831f59b4323e7d8ba..37a628bac26eb4d5e588f35d67482c6cda623fcf 100644
--- a/Vates/VatesSimpleGui/ViewWidgets/src/BackgroundRgbProvider.cpp
+++ b/Vates/VatesSimpleGui/ViewWidgets/src/BackgroundRgbProvider.cpp
@@ -145,4 +145,4 @@ void BackgroundRgbProvider::backgroundColorChangeCallbackFunction(
 }
 }
 }
-}
\ No newline at end of file
+}
diff --git a/Vates/VatesSimpleGui/ViewWidgets/src/CameraManager.cpp b/Vates/VatesSimpleGui/ViewWidgets/src/CameraManager.cpp
index f6efdf7366b967f6d96abda75cac15149a68e749..a215560a14d422c1ca0b738404daa7caa97d94ec 100644
--- a/Vates/VatesSimpleGui/ViewWidgets/src/CameraManager.cpp
+++ b/Vates/VatesSimpleGui/ViewWidgets/src/CameraManager.cpp
@@ -33,7 +33,7 @@ Mantid::VATES::ViewFrustum_const_sptr CameraManager::getCurrentViewFrustum() {
 
   pqView *view = pqActiveObjects::instance().activeView();
 
-  vtkSMRenderViewProxy *proxy = NULL;
+  vtkSMRenderViewProxy *proxy = nullptr;
 
   if (view) {
     proxy = vtkSMRenderViewProxy::SafeDownCast(view->getViewProxy());
@@ -98,7 +98,7 @@ Mantid::VATES::ViewFrustum_const_sptr CameraManager::getCurrentViewFrustum() {
 void CameraManager::setCameraToPeak(double xpos, double ypos, double zpos,
                                     double peakRadius) {
   pqView *view = pqActiveObjects::instance().activeView();
-  vtkSMRenderViewProxy *proxy = NULL;
+  vtkSMRenderViewProxy *proxy = nullptr;
 
   if (view) {
     proxy = vtkSMRenderViewProxy::SafeDownCast(view->getViewProxy());
diff --git a/Vates/VatesSimpleGui/ViewWidgets/src/ColorSelectionWidget.cpp b/Vates/VatesSimpleGui/ViewWidgets/src/ColorSelectionWidget.cpp
index 047138ef80e6422fabb84fa2eedb49ded15e073c..639726cd1c1efe29230b6cee954a5ea020e535b1 100644
--- a/Vates/VatesSimpleGui/ViewWidgets/src/ColorSelectionWidget.cpp
+++ b/Vates/VatesSimpleGui/ViewWidgets/src/ColorSelectionWidget.cpp
@@ -28,7 +28,7 @@ namespace SimpleGui {
 ColorSelectionWidget::ColorSelectionWidget(QWidget *parent)
     : QWidget(parent), m_minHistoric(0.01), m_maxHistoric(0.01),
       m_ignoreColorChangeCallbacks(false),
-      m_inProcessUserRequestedAutoScale(false), m_colorScaleLock(NULL) {
+      m_inProcessUserRequestedAutoScale(false), m_colorScaleLock(nullptr) {
   this->m_ui.setupUi(this);
   this->m_ui.autoColorScaleCheckBox->setChecked(true);
   this->setEditorStatus(false);
@@ -443,7 +443,7 @@ void ColorSelectionWidget::reset() {
  */
 void ColorSelectionWidget::setColorScaleLock(
     Mantid::VATES::ColorScaleLock *lock) {
-  if (m_colorScaleLock == NULL) {
+  if (!m_colorScaleLock) {
     m_colorScaleLock = lock;
   }
 }
diff --git a/Vates/VatesSimpleGui/ViewWidgets/src/ColorUpdater.cpp b/Vates/VatesSimpleGui/ViewWidgets/src/ColorUpdater.cpp
index 4923771f1ceab8783d9beaff37d1864bc8e5f60a..702ceaec9b29acf637fc9b1c5b4890cc9c906137 100644
--- a/Vates/VatesSimpleGui/ViewWidgets/src/ColorUpdater.cpp
+++ b/Vates/VatesSimpleGui/ViewWidgets/src/ColorUpdater.cpp
@@ -66,7 +66,7 @@ VsiColorScale ColorUpdater::autoScale() {
 void ColorUpdater::colorMapChange(pqPipelineRepresentation *repr,
                                   const Json::Value &model) {
   pqScalarsToColors *lut = repr->getLookupTable();
-  if (NULL == lut) {
+  if (!lut) {
     // Got a bad proxy, so just return
     return;
   }
@@ -120,7 +120,7 @@ void ColorUpdater::colorScaleChange(double min, double max) {
 void ColorUpdater::updateLookupTable(pqDataRepresentation *representation) {
   pqScalarsToColors *lookupTable = representation->getLookupTable();
 
-  if (NULL != lookupTable) {
+  if (lookupTable) {
     // Set the scalar range values
     lookupTable->setScalarRange(this->m_minScale, this->m_maxScale);
 
@@ -130,7 +130,7 @@ void ColorUpdater::updateLookupTable(pqDataRepresentation *representation) {
     vtkSMProxy *scalarOpacityFunctionProxy =
         lutProxy ? pqSMAdaptor::getProxyProperty(
                        lutProxy->GetProperty("ScalarOpacityFunction"))
-                 : NULL;
+                 : nullptr;
 
     if (scalarOpacityFunctionProxy) {
       vtkSMTransferFunctionProxy::RescaleTransferFunction(
diff --git a/Vates/VatesSimpleGui/ViewWidgets/src/MdViewerWidget.cpp b/Vates/VatesSimpleGui/ViewWidgets/src/MdViewerWidget.cpp
index 8174343d80934e226a70887cfbe33e5f02958735..66b82e0743e2d5bfa8fc4d5e53bd8fd3c825c843 100644
--- a/Vates/VatesSimpleGui/ViewWidgets/src/MdViewerWidget.cpp
+++ b/Vates/VatesSimpleGui/ViewWidgets/src/MdViewerWidget.cpp
@@ -3,8 +3,10 @@
 #include <boost/shared_ptr.hpp>
 #include <set>
 #include <string>
+#include <utility>
 #include <vector>
 
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/IMDEventWorkspace.h"
 #include "MantidAPI/IMDHistoWorkspace.h"
 #include "MantidAPI/IPeaksWorkspace.h"
@@ -156,13 +158,14 @@ MdViewerWidget::AllVSIViewsState::~AllVSIViewsState() {}
  * This constructor is used in the plugin mode operation of the VSI.
  */
 MdViewerWidget::MdViewerWidget()
-    : VatesViewerInterface(), currentView(NULL),
+    : VatesViewerInterface(), currentView(nullptr),
 
-      hiddenView(NULL), viewSwitched(false), dataLoader(NULL), lodAction(NULL),
-      screenShot(NULL), viewLayout(NULL), viewSettings(NULL),
-      useCurrentColorSettings(false), initialView(ModeControlWidget::STANDARD),
+      hiddenView(nullptr), viewSwitched(false), dataLoader(nullptr),
+      lodAction(nullptr), screenShot(nullptr), viewLayout(nullptr),
+      viewSettings(nullptr), useCurrentColorSettings(false),
+      initialView(ModeControlWidget::STANDARD),
       m_rebinAlgorithmDialogProvider(this),
-      m_rebinnedWorkspaceIdentifier("_tempvsi"), m_colorMapEditorPanel(NULL),
+      m_rebinnedWorkspaceIdentifier("_tempvsi"), m_colorMapEditorPanel(nullptr),
       m_gridAxesStartUpOn(true), m_allViews() {
   // this will initialize the ParaView application if needed.
   VatesParaViewApplication::instance();
@@ -194,7 +197,7 @@ MdViewerWidget::MdViewerWidget(QWidget *parent)
   // We're in the standalone application mode
   this->internalSetup(false);
   this->setupUiAndConnections();
-  this->setupMainView();
+  this->setupMainView(ModeControlWidget::STANDARD);
 }
 
 MdViewerWidget::~MdViewerWidget() {}
@@ -208,7 +211,7 @@ void MdViewerWidget::internalSetup(bool pMode) {
   static int widgetNumber = 0;
   this->m_widgetName = QString("MdViewerWidget%1").arg(widgetNumber++);
   this->pluginMode = pMode;
-  this->rotPointDialog = NULL;
+  this->rotPointDialog = nullptr;
   this->lodThreshold = 5.0;
   this->viewSwitched = false;
 }
@@ -241,14 +244,12 @@ void MdViewerWidget::setupUiAndConnections() {
     m_colorMapEditorPanel->setUpPanel();
   }
 
-  // this->connect(this->ui.proxiesPanel,SIGNAL(changeFinished(vtkSMProxy*)),SLOT(panelChanged()));
   QAction *temp = new QAction(this);
   pqDeleteReaction *deleteHandler = new pqDeleteReaction(temp);
   deleteHandler->connect(this->ui.propertiesPanel,
                          SIGNAL(deleteRequested(pqPipelineSource *)),
                          SLOT(deleteSource(pqPipelineSource *)));
 
-  // pqApplyBehavior* applyBehavior = new pqApplyBehavior(this);
   VsiApplyBehaviour *applyBehavior =
       new VsiApplyBehaviour(&m_colorScaleLock, this);
 
@@ -273,17 +274,17 @@ void MdViewerWidget::panelChanged() { this->currentView->renderAll(); }
  * event filter, tweaks the UI layout for the view and calls the routine that
  * sets up connections between ParaView and the main window widgets.
  */
-void MdViewerWidget::setupMainView() {
+void MdViewerWidget::setupMainView(ModeControlWidget::Views viewType) {
   // Commented this out to only use Mantid supplied readers
   // Initialize all readers available to ParaView. Now our application can load
   // all types of datasets supported by ParaView.
   // vtkSMProxyManager::GetProxyManager()->GetReaderFactory()->RegisterPrototypes("sources");
 
-  // Set the view at startup to STANDARD, the view will be changed, depending on
+  // Set the view at startup to view, the view will be changed, depending on
   // the workspace
-  this->currentView = this->createAndSetMainViewWidget(
-      this->ui.viewWidget, ModeControlWidget::STANDARD);
-  this->initialView = ModeControlWidget::STANDARD;
+  this->currentView =
+      this->createAndSetMainViewWidget(this->ui.viewWidget, viewType);
+  this->initialView = viewType;
   this->currentView->installEventFilter(this);
 
   // Create a layout to manage the view properly
@@ -440,7 +441,7 @@ void MdViewerWidget::setParaViewComponentsForView() {
  * Reaction for a rebin event
  * @param algorithmType The type of rebinning algorithm
  */
-void MdViewerWidget::onRebin(std::string algorithmType) {
+void MdViewerWidget::onRebin(const std::string &algorithmType) {
   pqPipelineSource *source = pqActiveObjects::instance().activeSource();
 
   std::string inputWorkspaceName;
@@ -459,8 +460,8 @@ void MdViewerWidget::onRebin(std::string algorithmType) {
 void MdViewerWidget::onSwitchSources(std::string rebinnedWorkspaceName,
                                      std::string sourceType) {
   // Create the rebinned workspace
-  pqPipelineSource *rebinnedSource =
-      prepareRebinnedWorkspace(rebinnedWorkspaceName, sourceType);
+  pqPipelineSource *rebinnedSource = prepareRebinnedWorkspace(
+      std::move(rebinnedWorkspaceName), std::move(sourceType));
 
   try {
     // Repipe the filters to the rebinned source
@@ -475,7 +476,7 @@ void MdViewerWidget::onSwitchSources(std::string rebinnedWorkspaceName,
     // Set the splatterplot button explicitly
     this->currentView->setSplatterplot(true);
 
-    pqActiveObjects::instance().setActiveSource(NULL);
+    pqActiveObjects::instance().setActiveSource(nullptr);
     pqActiveObjects::instance().setActiveSource(rebinnedSource);
   } catch (const std::runtime_error &error) {
     g_log.warning() << error.what();
@@ -515,7 +516,7 @@ void MdViewerWidget::onResetViewsStateToAllData() {
  * @param sourceType The name of the source plugin.
  */
 pqPipelineSource *MdViewerWidget::prepareRebinnedWorkspace(
-    const std::string rebinnedWorkspaceName, std::string sourceType) {
+    const std::string &rebinnedWorkspaceName, const std::string &sourceType) {
   // Load a new source plugin
   auto gridAxesOn = areGridAxesOn();
   pqPipelineSource *newRebinnedSource = this->currentView->setPluginSource(
@@ -524,7 +525,7 @@ pqPipelineSource *MdViewerWidget::prepareRebinnedWorkspace(
 
   // It seems that the new source gets set as active before it is fully
   // constructed. We therefore reset it.
-  pqActiveObjects::instance().setActiveSource(NULL);
+  pqActiveObjects::instance().setActiveSource(nullptr);
   pqActiveObjects::instance().setActiveSource(newRebinnedSource);
 
   this->renderAndFinalSetup();
@@ -542,7 +543,7 @@ pqPipelineSource *MdViewerWidget::prepareRebinnedWorkspace(
  * @param originalWorkspaceName The name of the original workspace
  */
 pqPipelineSource *MdViewerWidget::renderOriginalWorkspace(
-    const std::string originalWorkspaceName) {
+    const std::string &originalWorkspaceName) {
   // Load a new source plugin
   QString sourcePlugin = "MDEW Source";
   auto gridAxesOn = areGridAxesOn();
@@ -695,7 +696,10 @@ void MdViewerWidget::renderWorkspace(QString workspaceName, int workspaceType,
     this->setColorForBackground();
     this->setColorMap();
 
-    this->ui.modeControlWidget->setToStandardView();
+    if (VatesViewerInterface::PEAKS != workspaceType) {
+      resetCurrentView(workspaceType, instrumentName);
+    }
+
     this->currentView->hide();
     // Set the auto log scale state
     this->currentView->initializeColorScale();
@@ -724,20 +728,8 @@ void MdViewerWidget::renderWorkspace(QString workspaceName, int workspaceType,
   pqPipelineSource *source = this->currentView->setPluginSource(
       sourcePlugin, workspaceName, gridAxesOn);
   source->getProxy()->SetAnnotation(this->m_widgetName.toLatin1().data(), "1");
-
   this->renderAndFinalSetup();
-
-  // Reset the current view to the correct initial view
-  // Note that we can only reset if a source plugin exists.
-  // Also note that we can only reset the current view to the
-  // correct initial after calling renderAndFinalSetup. We first
-  // need to load in the current view and then switch to be inline
-  // with the current architecture.
-  if (VatesViewerInterface::PEAKS != workspaceType) {
-    resetCurrentView(workspaceType, instrumentName);
-  }
-
-  // save
+  this->currentView->show();
 }
 
 /**
@@ -772,7 +764,8 @@ void MdViewerWidget::resetCurrentView(int workspaceType,
  * @returns An initial view.
 */
 ModeControlWidget::Views
-MdViewerWidget::getInitialView(int workspaceType, std::string instrumentName) {
+MdViewerWidget::getInitialView(int workspaceType,
+                               const std::string &instrumentName) {
   // Get the possible initial views
   QString initialViewFromUserProperties =
       mdSettings.getUserSettingInitialView();
@@ -870,14 +863,12 @@ MdViewerWidget::checkViewAgainstWorkspace(ModeControlWidget::Views view,
   if (VatesViewerInterface::MDHW == workspaceType) {
     // Histo workspaces cannot have a splatter plot,
     if (view == ModeControlWidget::SPLATTERPLOT) {
-      g_log.notice()
-          << "The preferred initial view favours the splatterplot as initial "
-             "view, "
-          << "but an MDHisto workspace is being loaded. An MDHisto workspace "
-          << "cannot be loaded into a splatterplot view. Defaulted to standard "
-             "view. \n";
-
-      selectedView = ModeControlWidget::STANDARD;
+      g_log.notice("The preferred initial view favours the splatterplot "
+                   "as initial view, but an MDHisto workspace is being "
+                   "loaded. A MDHisto workspace cannot be loaded into a "
+                   "splatterplot view. Defaulted to MultiSlice view.");
+
+      selectedView = ModeControlWidget::MULTISLICE;
     } else {
       selectedView = view;
     }
@@ -892,12 +883,15 @@ MdViewerWidget::checkViewAgainstWorkspace(ModeControlWidget::Views view,
  * This function performs setup for the plugin mode of the Vates Simple
  * Interface. It calls a number of defined functions to complete the process.
  */
-void MdViewerWidget::setupPluginMode() {
+void MdViewerWidget::setupPluginMode(int WsType,
+                                     const std::string &instrumentName) {
   // Don't use the current color map at start up.
   this->useCurrentColorSettings = false;
   this->setupUiAndConnections();
   this->createMenus();
-  this->setupMainView();
+  ModeControlWidget::Views initialView =
+      this->getInitialView(WsType, instrumentName);
+  this->setupMainView(initialView);
 }
 
 /**
@@ -1113,6 +1107,31 @@ std::string MdViewerWidget::saveToProject(ApplicationWindow *app) {
   return tsv.outputLines();
 }
 
+std::vector<std::string> MdViewerWidget::getWorkspaceNames() {
+  auto server = pqActiveObjects::instance().activeServer();
+  auto model = pqApplicationCore::instance()->getServerManagerModel();
+  const auto sources = model->findItems<pqPipelineSource *>(server);
+
+  std::vector<std::string> workspaceNames;
+  for (auto source : sources) {
+    const auto proxy = source->getProxy();
+    const auto srcProxyName = proxy->GetXMLGroup();
+    if (srcProxyName == QString("sources")) {
+      std::string wsName(
+          vtkSMPropertyHelper(proxy, "WorkspaceName", true).GetAsString());
+      workspaceNames.push_back(wsName);
+    }
+  }
+
+  return workspaceNames;
+}
+
+std::string MdViewerWidget::getWindowName() {
+  return m_widgetName.toStdString();
+}
+
+std::string MdViewerWidget::getWindowType() { return "VSIWindow"; }
+
 /**
  * This function tells the current view to render the data, perform any
  * necessary checks on the view given the workspace type and update the
@@ -1146,7 +1165,7 @@ void MdViewerWidget::setColorForBackground() {
 void MdViewerWidget::checkForUpdates() {
   Mantid::VATES::ColorScaleLockGuard colorScaleLockGuard(&m_colorScaleLock);
   pqPipelineSource *src = pqActiveObjects::instance().activeSource();
-  if (NULL == src) {
+  if (!src) {
     return;
   }
   vtkSMProxy *proxy = src->getProxy();
@@ -1242,10 +1261,7 @@ void MdViewerWidget::swapViews() {
   if (!this->hiddenView)
     g_log.error(
         "Inconsistency found when swapping views, the next view is NULL");
-
-  ViewBase *temp = this->currentView;
-  this->currentView = this->hiddenView;
-  this->hiddenView = temp;
+  std::swap(this->currentView, this->hiddenView);
 }
 
 /**
@@ -1390,7 +1406,7 @@ void MdViewerWidget::onLodToggled(bool state) {
  * setting the communication between it and the current view.
  */
 void MdViewerWidget::onRotationPoint() {
-  if (NULL == this->rotPointDialog) {
+  if (!this->rotPointDialog) {
     this->rotPointDialog = new RotationPointDialog(this);
     this->connectRotationPointDialog();
   }
@@ -1414,9 +1430,10 @@ void MdViewerWidget::onWikiHelp() {
  * switch view since the connection to the current view is destroyed.
  */
 void MdViewerWidget::disconnectDialogs() {
-  if (NULL != this->rotPointDialog) {
+  if (this->rotPointDialog) {
     this->rotPointDialog->close();
-    QObject::disconnect(this->rotPointDialog, 0, this->currentView, 0);
+    QObject::disconnect(this->rotPointDialog, nullptr, this->currentView,
+                        nullptr);
   }
 }
 
@@ -1455,7 +1472,7 @@ void MdViewerWidget::connectColorSelectionWidget() {
  * the current view.
  */
 void MdViewerWidget::connectRotationPointDialog() {
-  if (NULL != this->rotPointDialog) {
+  if (this->rotPointDialog) {
     QObject::connect(
         this->rotPointDialog, SIGNAL(sendCoordinates(double, double, double)),
         this->currentView, SLOT(onResetCenterToPoint(double, double, double)));
@@ -1496,7 +1513,7 @@ void MdViewerWidget::afterReplaceHandle(
     const boost::shared_ptr<Mantid::API::Workspace> ws) {
   UNUSED_ARG(ws);
   pqPipelineSource *src = this->currentView->hasWorkspace(wsName.c_str());
-  if (NULL != src) {
+  if (src) {
     // Have to mark the filter as modified to get it to update. Do this by
     // changing the requested workspace name to a dummy name and then change
     // back. However, push the change all the way down for it to work.
@@ -1526,7 +1543,7 @@ void MdViewerWidget::preDeleteHandle(const std::string &wsName,
   UNUSED_ARG(ws);
 
   pqPipelineSource *src = this->currentView->hasWorkspace(wsName.c_str());
-  if (NULL != src) {
+  if (src) {
     long long numSources = this->currentView->getNumSources();
     if (numSources > 1) {
       pqObjectBuilder *builder =
@@ -1617,7 +1634,8 @@ bool otherWorkspacePresent() {
   * @param wsNames  Reference to a list of workspaces names, which are being
  * extracted.
   */
-void MdViewerWidget::handleDragAndDropPeaksWorkspaces(QEvent *e, QString text,
+void MdViewerWidget::handleDragAndDropPeaksWorkspaces(QEvent *e,
+                                                      const QString &text,
                                                       QStringList &wsNames) {
   int endIndex = 0;
   while (text.indexOf("[\"", endIndex) > -1) {
@@ -1680,22 +1698,22 @@ void MdViewerWidget::saveViewState(ViewBase *view) {
   switch (vtype) {
   case ModeControlWidget::Views::STANDARD: {
     m_allViews.stateStandard.TakeReference(
-        view->getView()->getRenderViewProxy()->SaveXMLState(NULL));
+        view->getView()->getRenderViewProxy()->SaveXMLState(nullptr));
   } break;
   case ModeControlWidget::Views::THREESLICE: {
     m_allViews.stateThreeSlice.TakeReference(
-        view->getView()->getRenderViewProxy()->SaveXMLState(NULL));
+        view->getView()->getRenderViewProxy()->SaveXMLState(nullptr));
   } break;
   case ModeControlWidget::Views::MULTISLICE: {
     m_allViews.stateMulti.TakeReference(
-        view->getView()->getRenderViewProxy()->SaveXMLState(NULL));
+        view->getView()->getRenderViewProxy()->SaveXMLState(nullptr));
   } break;
   case ModeControlWidget::Views::SPLATTERPLOT: {
     m_allViews.stateSplatter.TakeReference(
-        view->getView()->getRenderViewProxy()->SaveXMLState(NULL));
+        view->getView()->getRenderViewProxy()->SaveXMLState(nullptr));
   } break;
   default:
-    view = NULL;
+    view = nullptr;
     break;
   }
 }
@@ -1719,25 +1737,25 @@ void MdViewerWidget::restoreViewState(ViewBase *view,
   case ModeControlWidget::STANDARD: {
     if (m_allViews.stateStandard)
       loaded = view->getView()->getRenderViewProxy()->LoadXMLState(
-          m_allViews.stateStandard.GetPointer(), NULL);
+          m_allViews.stateStandard.GetPointer(), nullptr);
   } break;
   case ModeControlWidget::THREESLICE: {
     if (m_allViews.stateThreeSlice)
       loaded = view->getView()->getRenderViewProxy()->LoadXMLState(
-          m_allViews.stateThreeSlice.GetPointer(), NULL);
+          m_allViews.stateThreeSlice.GetPointer(), nullptr);
   } break;
   case ModeControlWidget::MULTISLICE: {
     if (m_allViews.stateMulti)
       loaded = view->getView()->getRenderViewProxy()->LoadXMLState(
-          m_allViews.stateMulti.GetPointer(), NULL);
+          m_allViews.stateMulti.GetPointer(), nullptr);
   } break;
   case ModeControlWidget::SPLATTERPLOT: {
     if (m_allViews.stateSplatter)
       loaded = view->getView()->getRenderViewProxy()->LoadXMLState(
-          m_allViews.stateSplatter.GetPointer(), NULL);
+          m_allViews.stateSplatter.GetPointer(), nullptr);
   } break;
   default:
-    view = NULL;
+    view = nullptr;
     break;
   }
 
diff --git a/Vates/VatesSimpleGui/ViewWidgets/src/MultisliceView.cpp b/Vates/VatesSimpleGui/ViewWidgets/src/MultisliceView.cpp
index 2fae62b53d082009d75e396bd2c6892e60dcef0d..01733d8a31924e820989cc5f08782eabf991919b 100644
--- a/Vates/VatesSimpleGui/ViewWidgets/src/MultisliceView.cpp
+++ b/Vates/VatesSimpleGui/ViewWidgets/src/MultisliceView.cpp
@@ -100,6 +100,9 @@ void MultiSliceView::setupData() {
 
 void MultiSliceView::render() {
   this->origSrc = pqActiveObjects::instance().activeSource();
+  if (this->origSrc == nullptr) {
+    return;
+  }
   this->checkSliceViewCompat();
   this->setupData();
   this->resetDisplay();
@@ -152,7 +155,7 @@ void MultiSliceView::checkSliceClicked(int axisIndex, double sliceOffsetOnAxis,
 void MultiSliceView::checkSliceViewCompat() {
   QString wsName = this->getWorkspaceName();
   if (wsName.isEmpty()) {
-    QObject::disconnect(this->m_mainView, 0, this, 0);
+    QObject::disconnect(this->m_mainView, nullptr, this, nullptr);
   }
 }
 
@@ -180,8 +183,8 @@ void MultiSliceView::showCutInSliceViewer(int axisIndex,
   pqServerManagerModel *smModel =
       pqApplicationCore::instance()->getServerManagerModel();
   QList<pqPipelineSource *> srcs = smModel->findItems<pqPipelineSource *>();
-  pqPipelineSource *src1 = NULL;
-  pqPipelineSource *src2 = NULL;
+  pqPipelineSource *src1 = nullptr;
+  pqPipelineSource *src2 = nullptr;
   foreach (pqPipelineSource *src, srcs) {
     const QString name(src->getProxy()->GetXMLName());
 
@@ -204,7 +207,7 @@ void MultiSliceView::showCutInSliceViewer(int axisIndex,
     geomXML = std::string(inGeomXML);
   }
 
-  if (NULL != src2) {
+  if (src2) {
     // Need to see if scaling is applied to axis
     QString scalingProperty("Scaling Factor");
     switch (axisIndex) {
diff --git a/Vates/VatesSimpleGui/ViewWidgets/src/PeaksTabWidget.cpp b/Vates/VatesSimpleGui/ViewWidgets/src/PeaksTabWidget.cpp
index 8c7bbfb057ecca28b780b15dde4b26de30c7c39e..2767f5d305c1cdef87090f8ea094e020f80bbf46 100644
--- a/Vates/VatesSimpleGui/ViewWidgets/src/PeaksTabWidget.cpp
+++ b/Vates/VatesSimpleGui/ViewWidgets/src/PeaksTabWidget.cpp
@@ -4,12 +4,13 @@
 #include "MantidQtSliceViewer/QPeaksTableModel.h"
 #include "MantidVatesSimpleGuiViewWidgets/PeaksWidget.h"
 
-#include <QWidget>
 #include <QItemSelectionModel>
 #include <QModelIndex>
-#include <vector>
-#include <string>
+#include <QWidget>
 #include <map>
+#include <string>
+#include <utility>
+#include <vector>
 
 namespace Mantid {
 namespace Vates {
@@ -53,11 +54,11 @@ void PeaksTabWidget::setupMvc(
 }
 
 void PeaksTabWidget::addNewTab(Mantid::API::IPeaksWorkspace_sptr peaksWorkspace,
-                               std::string tabName,
+                               const std::string &tabName,
                                std::vector<bool> visiblePeaks) {
   PeaksWidget *widget =
-      new PeaksWidget(peaksWorkspace, m_coordinateSystem, this);
-  widget->setupMvc(visiblePeaks);
+      new PeaksWidget(std::move(peaksWorkspace), m_coordinateSystem, this);
+  widget->setupMvc(std::move(visiblePeaks));
 
   // Connect to the output of the widget
   QObject::connect(
@@ -81,7 +82,7 @@ void PeaksTabWidget::addNewTab(Mantid::API::IPeaksWorkspace_sptr peaksWorkspace,
  */
 void PeaksTabWidget::onZoomToPeak(Mantid::API::IPeaksWorkspace_sptr ws,
                                   int row) {
-  emit zoomToPeak(ws, row);
+  emit zoomToPeak(std::move(ws), row);
 }
 
 /**
@@ -90,8 +91,8 @@ void PeaksTabWidget::onZoomToPeak(Mantid::API::IPeaksWorkspace_sptr ws,
  * @param colors The color of the tabs
  */
 void PeaksTabWidget::updateTabs(
-    std::map<std::string, std::vector<bool>> visiblePeaks,
-    std::map<std::string, QColor> colors) {
+    std::map<std::string, std::vector<bool>> &visiblePeaks,
+    std::map<std::string, QColor> &colors) {
   // Iterate over all tabs
   for (int i = 0; i < m_tabWidget->count(); i++) {
     QString label = m_tabWidget->tabText(i);
@@ -114,10 +115,10 @@ void PeaksTabWidget::updateTabs(
  * @param color
  * @param index The tab index.
  */
-void PeaksTabWidget::updateTab(std::vector<bool> visiblePeaks, QColor color,
-                               int index) {
+void PeaksTabWidget::updateTab(const std::vector<bool> &visiblePeaks,
+                               const QColor &color, int index) {
   PeaksWidget *widget = qobject_cast<PeaksWidget *>(m_tabWidget->widget(index));
-  widget->updateModel(visiblePeaks);
+  widget->updateModel(std::move(visiblePeaks));
   m_tabWidget->tabBar()->setTabTextColor(index, color);
 }
 
@@ -129,8 +130,8 @@ void PeaksTabWidget::updateTab(std::vector<bool> visiblePeaks, QColor color,
 void PeaksTabWidget::addNewPeaksWorkspace(
     Mantid::API::IPeaksWorkspace_sptr peaksWorkspace,
     std::vector<bool> visiblePeaks) {
-  m_ws.push_back(peaksWorkspace);
-  addNewTab(peaksWorkspace, peaksWorkspace->getName(), visiblePeaks);
+  m_ws.push_back(std::move(peaksWorkspace));
+  addNewTab(peaksWorkspace, peaksWorkspace->getName(), std::move(visiblePeaks));
 }
 }
 } // namespace
diff --git a/Vates/VatesSimpleGui/ViewWidgets/src/PeaksTableControllerVsi.cpp b/Vates/VatesSimpleGui/ViewWidgets/src/PeaksTableControllerVsi.cpp
index e6a938464d4a18ff5e24302bc3f405f6ed72f2d4..9b6c4965c245cfb86d6f9b374a5736f2d53072b9 100644
--- a/Vates/VatesSimpleGui/ViewWidgets/src/PeaksTableControllerVsi.cpp
+++ b/Vates/VatesSimpleGui/ViewWidgets/src/PeaksTableControllerVsi.cpp
@@ -49,12 +49,13 @@
 #include <QLayoutItem>
 #include <QColor>
 
+#include <algorithm>
 #include <boost/make_shared.hpp>
 #include <boost/shared_ptr.hpp>
-#include <stdexcept>
-#include <algorithm>
 #include <map>
 #include <sstream>
+#include <stdexcept>
+#include <utility>
 
 namespace Mantid {
 namespace Vates {
@@ -73,7 +74,7 @@ PeaksTableControllerVsi::PeaksTableControllerVsi(
     boost::shared_ptr<CameraManager> cameraManager, QWidget *parent)
     : QWidget(parent), m_cameraManager(cameraManager),
       m_presenter(new Mantid::VATES::CompositePeaksPresenterVsi()),
-      m_peaksTabWidget(NULL), m_peakMarker(NULL),
+      m_peaksTabWidget(nullptr), m_peakMarker(nullptr),
       m_coordinateSystem(Mantid::Kernel::SpecialCoordinateSystem::QLab) {
   m_peakTransformSelector.registerCandidate(
       boost::make_shared<Mantid::Geometry::PeakTransformHKLFactory>());
@@ -113,8 +114,8 @@ std::vector<bool> PeaksTableControllerVsi::getViewablePeaks() {
  * @param source A new peaks source
  * @param splatSource A pointer to the splatter source
  */
-void PeaksTableControllerVsi::addWorkspace(
-    pqPipelineSource *source, QPointer<pqPipelineSource> splatSource) {
+void PeaksTableControllerVsi::addWorkspace(pqPipelineSource *source,
+                                           pqPipelineSource *splatSource) {
   try {
     if (!source || !splatSource) {
       throw std::invalid_argument(
@@ -165,7 +166,8 @@ void PeaksTableControllerVsi::addWorkspace(
           m_presenter->getInitializedViewablePeaks();
       m_peaksTabWidget->addNewPeaksWorkspace(
           peaksWorkspace, viewablePeaks[peaksWorkspace->getName()]);
-      m_peaksTabWidget->updateTabs(viewablePeaks, getColors());
+      auto colors = this->getColors();
+      m_peaksTabWidget->updateTabs(viewablePeaks, colors);
       updatePeakWorkspaceColor();
     }
   } catch (Mantid::Kernel::Exception::NotFoundError &) {
@@ -268,8 +270,8 @@ void PeaksTableControllerVsi::updateViewableArea() {
  * Extract the frame from the source
  * @param splatSource A pointer to a splatter plot source.
  */
-std::vector<std::string> PeaksTableControllerVsi::extractFrameFromSource(
-    QPointer<pqPipelineSource> splatSource) {
+std::vector<std::string>
+PeaksTableControllerVsi::extractFrameFromSource(pqPipelineSource *splatSource) {
   pqPipelineFilter *filter = qobject_cast<pqPipelineFilter *>(splatSource);
 
   if (!filter) {
@@ -357,7 +359,8 @@ void PeaksTableControllerVsi::createTable() {
       layout()->addWidget(widget);
       m_peaksTabWidget = widget;
       // Set the color
-      m_peaksTabWidget->updateTabs(viewablePeaks, getColors());
+      auto colors = this->getColors();
+      m_peaksTabWidget->updateTabs(viewablePeaks, colors);
       updatePeakWorkspaceColor();
     } catch (std::runtime_error &ex) {
       g_log.warning()
@@ -376,9 +379,9 @@ void PeaksTableControllerVsi::createTable() {
 */
 void PeaksTableControllerVsi::removeLayout(QWidget *widget) {
   QLayout *layout = widget->layout();
-  if (layout != 0) {
+  if (layout) {
     QLayoutItem *item;
-    while ((item = layout->takeAt(0)) != 0) {
+    while ((item = layout->takeAt(0))) {
       layout->removeItem(item);
       delete item->widget();
     }
@@ -397,7 +400,7 @@ void PeaksTableControllerVsi::removeTable() {
   if (m_peaksTabWidget) {
     m_peaksTabWidget->deleteLater();
   }
-  m_peaksTabWidget = NULL;
+  m_peaksTabWidget = nullptr;
 }
 
 /**
@@ -411,7 +414,7 @@ void PeaksTableControllerVsi::onZoomToPeak(
     double radius;
     Mantid::Kernel::V3D position;
 
-    m_presenter->getPeaksInfo(peaksWorkspace, row, position, radius,
+    m_presenter->getPeaksInfo(std::move(peaksWorkspace), row, position, radius,
                               m_coordinateSystem);
 
     // Reset camera
@@ -486,14 +489,16 @@ void PeaksTableControllerVsi::destroySinglePeakSource() {
         pqApplicationCore::instance()->getObjectBuilder();
     builder->destroy(m_peakMarker);
 
-    m_peakMarker = NULL;
+    m_peakMarker = nullptr;
   }
 }
 
 /**
  * On Single Peak Marker destroyed
  */
-void PeaksTableControllerVsi::onPeakMarkerDestroyed() { m_peakMarker = NULL; }
+void PeaksTableControllerVsi::onPeakMarkerDestroyed() {
+  m_peakMarker = nullptr;
+}
 
 /**
  * Reset the single peak source
@@ -526,8 +531,8 @@ void PeaksTableControllerVsi::resetSinglePeaksSource(double position1,
  * @param delimiter The delimiter to concatenate workspace names.
  * @returns The concatenated workspace names.
  */
-std::string
-PeaksTableControllerVsi::getConcatenatedWorkspaceNames(std::string delimiter) {
+std::string PeaksTableControllerVsi::getConcatenatedWorkspaceNames(
+    const std::string &delimiter) {
   std::vector<std::string> peaksWorkspaceNames =
       m_presenter->getPeaksWorkspaceNames();
   std::stringstream stream;
@@ -579,8 +584,9 @@ void PeaksTableControllerVsi::updatePeaksWorkspaces(
   // Now update all the presenter
   m_presenter->updateWorkspaces(peaksWorkspaceNames);
   if (!peakSources.empty() && m_peaksTabWidget) {
-    m_peaksTabWidget->updateTabs(m_presenter->getInitializedViewablePeaks(),
-                                 getColors());
+    auto colors = this->getColors();
+    auto peaks = m_presenter->getInitializedViewablePeaks();
+    m_peaksTabWidget->updateTabs(peaks, colors);
     updatePeakWorkspaceColor();
   }
 
@@ -598,7 +604,7 @@ void PeaksTableControllerVsi::updatePeaksWorkspaces(
  */
 void PeaksTableControllerVsi::onPeaksSorted(
     const std::string &columnToSortBy, const bool sortAscending,
-    Mantid::API::IPeaksWorkspace_sptr ws) {
+    const Mantid::API::IPeaksWorkspace *ws) {
   // Invoke the ording command on the presenters
   m_presenter->sortPeaksWorkspace(columnToSortBy, sortAscending, ws);
   // Update the tabs
@@ -646,4 +652,4 @@ void PeaksTableControllerVsi::setPeakSourceColorToDefault() {
 }
 }
 }
-}
\ No newline at end of file
+}
diff --git a/Vates/VatesSimpleGui/ViewWidgets/src/PeaksWidget.cpp b/Vates/VatesSimpleGui/ViewWidgets/src/PeaksWidget.cpp
index a3059e7b04757a9dc64043450777a2dc5b528b1a..55c5a1502813431f977f746bbfe75d6501ed76a1 100644
--- a/Vates/VatesSimpleGui/ViewWidgets/src/PeaksWidget.cpp
+++ b/Vates/VatesSimpleGui/ViewWidgets/src/PeaksWidget.cpp
@@ -74,7 +74,8 @@ void PeaksWidget::setupMvc(std::vector<bool> visiblePeaks) {
  * Detects a newly selectedd peaks workspace.
  * @param current The currently selected index.
  */
-void PeaksWidget::onCurrentChanged(QModelIndex current, QModelIndex) {
+void PeaksWidget::onCurrentChanged(const QModelIndex &current,
+                                   const QModelIndex &) {
   if (current.isValid()) {
     emit zoomToPeak(m_ws, current.row());
   }
diff --git a/Vates/VatesSimpleGui/ViewWidgets/src/RebinAlgorithmDialogProvider.cpp b/Vates/VatesSimpleGui/ViewWidgets/src/RebinAlgorithmDialogProvider.cpp
index 2b9772410455b7693c23bdb0df491f38c09fe1da..91104fd02516a12e277fa8d2fff42517010e7d76 100644
--- a/Vates/VatesSimpleGui/ViewWidgets/src/RebinAlgorithmDialogProvider.cpp
+++ b/Vates/VatesSimpleGui/ViewWidgets/src/RebinAlgorithmDialogProvider.cpp
@@ -5,6 +5,7 @@
 #include "MantidQtMantidWidgets/SlicingAlgorithmDialog.h"
 #include "MantidAPI/IMDEventWorkspace.h"
 #include "MantidAPI/IMDWorkspace.h"
+#include "MantidGeometry/MDGeometry/IMDDimension.h"
 #include "MantidKernel/Logger.h"
 
 // Have to deal with ParaView warnings and Intel compiler the hard way.
@@ -49,9 +50,9 @@ RebinAlgorithmDialogProvider::~RebinAlgorithmDialogProvider() {}
  * @param outputWorkspace The name of the output workspace.
  * @param algorithmType The type of algorithm which is to be used for rebinning.
  */
-void RebinAlgorithmDialogProvider::showDialog(std::string inputWorkspace,
-                                              std::string outputWorkspace,
-                                              std::string algorithmType) {
+void RebinAlgorithmDialogProvider::showDialog(
+    const std::string &inputWorkspace, const std::string &outputWorkspace,
+    const std::string &algorithmType) {
   if (inputWorkspace.empty() || outputWorkspace.empty()) {
     return;
   }
@@ -64,7 +65,7 @@ void RebinAlgorithmDialogProvider::showDialog(std::string inputWorkspace,
   }
 
   MantidQt::API::AlgorithmDialog *rebinDialog =
-      createDialog(algorithm, inputWorkspace, outputWorkspace, algorithmType);
+      createDialog(*algorithm, inputWorkspace, outputWorkspace, algorithmType);
 
   rebinDialog->show();
   rebinDialog->raise();
@@ -123,21 +124,19 @@ RebinAlgorithmDialogProvider::createAlgorithm(const std::string &algorithmName,
  * @returns The algorithm dialog
  */
 MantidQt::API::AlgorithmDialog *RebinAlgorithmDialogProvider::createDialog(
-    Mantid::API::IAlgorithm_sptr algorithm, const std::string &inputWorkspace,
+    const Mantid::API::IAlgorithm &algorithm, const std::string &inputWorkspace,
     const std::string &outputWorkspace, const std::string &algorithmType) {
   QHash<QString, QString> presets;
   // Check if a workspace is selected in the dock and set this as a preference
   // for the input workspace
   // This is an optional message displayed at the top of the GUI.
-  QString optional_msg(algorithm->summary().c_str());
-
-  MantidQt::API::AlgorithmDialog *dialog = NULL;
+  QString optional_msg(algorithm.summary().c_str());
 
   MantidQt::API::InterfaceManager interfaceManager;
   presets.insert(m_lblInputWorkspace, QString::fromStdString(inputWorkspace));
   presets.insert(m_lblOutputWorkspace, QString::fromStdString(outputWorkspace));
 
-  dialog = interfaceManager.createDialogFromName(
+  auto dialog = interfaceManager.createDialogFromName(
       QString::fromStdString(algorithmType), -1, m_parent, false, presets);
 
   // The parent so that the dialog appears on top of it
@@ -145,7 +144,7 @@ MantidQt::API::AlgorithmDialog *RebinAlgorithmDialogProvider::createDialog(
   dialog->setAttribute(Qt::WA_DeleteOnClose, true);
 
   // Set the QDialog window flags to ensure the dialog ends up on top
-  Qt::WindowFlags flags = 0;
+  Qt::WindowFlags flags = nullptr;
   flags |= Qt::Dialog;
   flags |= Qt::WindowContextHelpButtonHint;
   dialog->setWindowFlags(flags);
@@ -169,7 +168,7 @@ MantidQt::API::AlgorithmDialog *RebinAlgorithmDialogProvider::createDialog(
  */
 void RebinAlgorithmDialogProvider::setAxisDimensions(
     MantidQt::MantidWidgets::SlicingAlgorithmDialog *dialog,
-    std::string inputWorkspace) {
+    const std::string &inputWorkspace) {
   Mantid::API::IMDEventWorkspace_sptr eventWorkspace =
       getWorkspace(inputWorkspace);
 
diff --git a/Vates/VatesSimpleGui/ViewWidgets/src/RebinnedSourcesManager.cpp b/Vates/VatesSimpleGui/ViewWidgets/src/RebinnedSourcesManager.cpp
index 087483d000e55f74c841a8e6eb8fede2aac7e534..f744f08b8b8aaaf3559f473f31eec93e0e9f0687 100644
--- a/Vates/VatesSimpleGui/ViewWidgets/src/RebinnedSourcesManager.cpp
+++ b/Vates/VatesSimpleGui/ViewWidgets/src/RebinnedSourcesManager.cpp
@@ -34,9 +34,10 @@
 #if defined(__INTEL_COMPILER)
 #pragma warning enable 1170
 #endif
-#include <QList>
 #include "boost/shared_ptr.hpp"
 #include <Poco/ActiveResult.h>
+#include <QList>
+#include <utility>
 
 namespace Mantid {
 namespace Vates {
@@ -48,7 +49,7 @@ Mantid::Kernel::Logger g_log("RebinnedSourcesManager");
 
 RebinnedSourcesManager::RebinnedSourcesManager(QWidget *parent)
     : QWidget(parent), m_tempPostfix("_rebinned_vsi"), m_tempPrefix(""),
-      m_inputSource(NULL), m_rebinnedSource(NULL) {
+      m_inputSource(nullptr), m_rebinnedSource(nullptr) {
   observeAdd();
   observeAfterReplace();
   observePreDelete();
@@ -152,7 +153,7 @@ void RebinnedSourcesManager::checkSource(pqPipelineSource *src,
   // anything
   if (isHistoWorkspace || isEventWorkspace) {
     processWorkspaceNames(inputWorkspace, outputWorkspace, source,
-                          workspaceName, algorithmType);
+                          workspaceName, std::move(algorithmType));
   }
 }
 
@@ -307,7 +308,7 @@ void RebinnedSourcesManager::getStoredWorkspaceNames(
  */
 std::vector<pqPipelineSource *>
 RebinnedSourcesManager::findAllRebinnedSourcesForWorkspace(
-    std::string workspaceName) {
+    const std::string &workspaceName) {
   std::vector<std::string> linkedSources;
   // We need to iterate over the map
   for (std::map<std::pair<std::string, std::string>,
@@ -371,17 +372,16 @@ bool RebinnedSourcesManager::doesSourceNeedToBeDeleted(
  * @param workspaceName The name of the workspace of the current source.
  * @param algorithmType The algorithm which creates the rebinned source.
  */
-void RebinnedSourcesManager::processWorkspaceNames(std::string &inputWorkspace,
-                                                   std::string &outputWorkspace,
-                                                   pqPipelineSource *source,
-                                                   std::string workspaceName,
-                                                   std::string algorithmType) {
+void RebinnedSourcesManager::processWorkspaceNames(
+    std::string &inputWorkspace, std::string &outputWorkspace,
+    pqPipelineSource *source, std::string workspaceName,
+    const std::string &algorithmType) {
   // Reset the temporary tracking elements, which are needed only for the
   // duration of the rebinning itself
   m_newWorkspacePairBuffer.clear();
   m_newRebinnedWorkspacePairBuffer.clear();
-  m_inputSource = NULL;
-  m_rebinnedSource = NULL;
+  m_inputSource = nullptr;
+  m_rebinnedSource = nullptr;
 
   // If the workspace is the original workspace or it is a freshly loaded, i.e.
   // it is not being tracked
@@ -424,7 +424,7 @@ void RebinnedSourcesManager::processWorkspaceNames(std::string &inputWorkspace,
  * @param key a key to the tracking map
  */
 void RebinnedSourcesManager::untrackWorkspaces(
-    std::pair<std::string, std::string> key) {
+    const std::pair<std::string, std::string> &key) {
   if (m_rebinnedWorkspaceAndSourceToOriginalWorkspace.count(key) > 0) {
     m_rebinnedWorkspaceAndSourceToOriginalWorkspace.erase(key);
   }
@@ -445,10 +445,9 @@ void RebinnedSourcesManager::rebuildPipeline(pqPipelineSource *source1,
   pqPipelineSource *endOfSource2Pipeline = source2;
 
   while (filter1) {
-    vtkSMProxy *proxy1 = NULL;
-    proxy1 = filter1->getProxy();
-    pqPipelineSource *newPipelineElement = NULL;
-    pqPipelineFilter *newFilter = NULL;
+    vtkSMProxy *proxy1 = filter1->getProxy();
+    pqPipelineSource *newPipelineElement = nullptr;
+    pqPipelineFilter *newFilter = nullptr;
     // Move source2 to its end.
     while (endOfSource2Pipeline->getNumberOfConsumers() > 0) {
       endOfSource2Pipeline = endOfSource2Pipeline->getConsumer(0);
@@ -471,7 +470,7 @@ void RebinnedSourcesManager::rebuildPipeline(pqPipelineSource *source1,
     if (filter1->getNumberOfConsumers() > 0) {
       filter1 = qobject_cast<pqPipelineFilter *>(filter1->getConsumer(0));
     } else {
-      filter1 = NULL;
+      filter1 = nullptr;
     }
   }
   emit triggerAcceptForNewFilters();
@@ -538,11 +537,11 @@ void RebinnedSourcesManager::copySafe(vtkSMProxy *dest, vtkSMProxy *source) {
       }
 
       vtkSMProxy *srcValue = srcPP->GetProxy(0);
-      vtkSMProxy *destValue = NULL;
+      vtkSMProxy *destValue = nullptr;
 
       // find srcValue type in destPLD and that's the proxy to use as destValue.
       for (unsigned int cc = 0;
-           srcValue != NULL && cc < destPLD->GetNumberOfProxyTypes(); cc++) {
+           srcValue != nullptr && cc < destPLD->GetNumberOfProxyTypes(); cc++) {
         if (srcValue->GetXMLName() && destPLD->GetProxyName(cc) &&
             strcmp(srcValue->GetXMLName(), destPLD->GetProxyName(cc)) == 0 &&
             srcValue->GetXMLGroup() && destPLD->GetProxyGroup(cc) &&
@@ -553,7 +552,7 @@ void RebinnedSourcesManager::copySafe(vtkSMProxy *dest, vtkSMProxy *source) {
       }
 
       if (destValue) {
-        Q_ASSERT(srcValue != NULL);
+        Q_ASSERT(srcValue != nullptr);
         copySafe(destValue, srcValue);
         destPP->SetProxy(0, destValue);
       }
@@ -756,7 +755,7 @@ RebinnedSourcesManager::createKeyPairForSource(pqPipelineSource *source) {
  * @param source A pointer to the source
  */
 void RebinnedSourcesManager::deleteSpecificSource(pqPipelineSource *source) {
-  if (NULL != source) {
+  if (source) {
     // Go to the end of the source and work your way back
     pqPipelineSource *tempSource = source;
 
diff --git a/Vates/VatesSimpleGui/ViewWidgets/src/SaveScreenshotReaction.cpp b/Vates/VatesSimpleGui/ViewWidgets/src/SaveScreenshotReaction.cpp
index b857e53c80fa8820a9a91ddc5516937d5a83fdee..070e48766ed71f9d84568e82dd36e18b19ece5c1 100644
--- a/Vates/VatesSimpleGui/ViewWidgets/src/SaveScreenshotReaction.cpp
+++ b/Vates/VatesSimpleGui/ViewWidgets/src/SaveScreenshotReaction.cpp
@@ -81,7 +81,7 @@ void SaveScreenshotReaction::saveScreenshot() {
   filters += ";;PPM image (*.ppm)";
   filters += ";;JPG image (*.jpg)";
   filters += ";;PDF file (*.pdf)";
-  pqFileDialog file_dialog(NULL, pqCoreUtilities::mainWidget(),
+  pqFileDialog file_dialog(nullptr, pqCoreUtilities::mainWidget(),
                            tr("Save Screenshot:"), QString(), filters);
   file_dialog.setRecentlyUsedExtension(lastUsedExt);
   file_dialog.setObjectName("FileSaveScreenshotDialog");
@@ -141,7 +141,7 @@ void SaveScreenshotReaction::saveScreenshot(const QString &filename,
     img.TakeReference(view->captureImage(size));
   }
 
-  if (img.GetPointer() == NULL) {
+  if (!img.GetPointer()) {
     qCritical() << "Save Image failed.";
   } else {
     pqImageUtil::saveImage(img, filename, quality);
diff --git a/Vates/VatesSimpleGui/ViewWidgets/src/SplatterPlotView.cpp b/Vates/VatesSimpleGui/ViewWidgets/src/SplatterPlotView.cpp
index 4367004587f984212afe44c9b7c5dadb33dab3f6..947d8e200b281bded1b6a2ede3f938b09e810230 100644
--- a/Vates/VatesSimpleGui/ViewWidgets/src/SplatterPlotView.cpp
+++ b/Vates/VatesSimpleGui/ViewWidgets/src/SplatterPlotView.cpp
@@ -52,6 +52,9 @@ namespace SimpleGui {
 
 namespace {
 Mantid::Kernel::Logger g_log("SplatterPlotView");
+const char *g_defaultRepresentation = "Point Gaussian";
+const double g_defaultOpacity = 0.5;
+const double g_defaultRadius = 0.005;
 }
 
 SplatterPlotView::SplatterPlotView(
@@ -59,7 +62,7 @@ SplatterPlotView::SplatterPlotView(
     bool createRenderProxy)
     : ViewBase(parent, rebinnedSourcesManager),
       m_cameraManager(boost::make_shared<CameraManager>()),
-      m_peaksTableController(NULL), m_peaksWorkspaceNameDelimiter(";") {
+      m_peaksTableController(nullptr), m_peaksWorkspaceNameDelimiter(";") {
   this->m_noOverlay = false;
   this->m_ui.setupUi(this);
 
@@ -131,14 +134,13 @@ void SplatterPlotView::destroyView() {
 pqRenderView *SplatterPlotView::getView() { return this->m_view.data(); }
 
 void SplatterPlotView::render() {
-  pqPipelineSource *src = NULL;
-  src = pqActiveObjects::instance().activeSource();
+  pqPipelineSource *src = pqActiveObjects::instance().activeSource();
   bool isPeaksWorkspace = this->isPeaksWorkspace(src);
   // Hedge for two things.
   // 1. If there is no active source
   // 2. If we are loading a peak workspace without haveing
   //    a splatterplot source in place
-  bool isBadInput = !src || (isPeaksWorkspace && this->m_splatSource == NULL);
+  bool isBadInput = !src || (isPeaksWorkspace && !this->m_splatSource);
   if (isBadInput) {
     g_log.warning() << "SplatterPlotView: Could not render source. You are "
                        "either loading an active source "
@@ -147,11 +149,11 @@ void SplatterPlotView::render() {
     return;
   }
 
-  const char *renderType = "Point Gaussian";
+  const char *renderType = g_defaultRepresentation;
   pqObjectBuilder *builder = pqApplicationCore::instance()->getObjectBuilder();
 
   // Do not allow overplotting of MDWorkspaces
-  if (!this->isPeaksWorkspace(src) && NULL != this->m_splatSource) {
+  if (!this->isPeaksWorkspace(src) && this->m_splatSource) {
     QMessageBox::warning(this, QApplication::tr("Overplotting Warning"),
                          QApplication::tr("SplatterPlot mode does not allow "
                                           "more that one MDEventWorkspace to "
@@ -197,8 +199,9 @@ void SplatterPlotView::render() {
       builder->createDataRepresentation(src->getOutputPort(0), this->m_view);
   vtkSMPropertyHelper(drep->getProxy(), "Representation").Set(renderType);
   if (!isPeaksWorkspace) {
-    vtkSMPropertyHelper(drep->getProxy(), "Opacity").Set(0.5);
-    vtkSMPropertyHelper(drep->getProxy(), "GaussianRadius").Set(0.005);
+    vtkSMPropertyHelper(drep->getProxy(), "Opacity").Set(g_defaultOpacity);
+    vtkSMPropertyHelper(drep->getProxy(), "GaussianRadius")
+        .Set(g_defaultRadius);
   } else {
     vtkSMPropertyHelper(drep->getProxy(), "LineWidth").Set(2);
   }
@@ -285,6 +288,13 @@ void SplatterPlotView::onThresholdButtonClicked() {
   pqObjectBuilder *builder = pqApplicationCore::instance()->getObjectBuilder();
   this->m_threshSource = builder->createFilter(
       "filters", MantidQt::API::MdConstants::Threshold, this->m_splatSource);
+  auto filterProxy =
+      builder->createDataRepresentation(this->m_threshSource->getOutputPort(0),
+                                        this->m_view)->getProxy();
+  vtkSMPropertyHelper(filterProxy, "Representation")
+      .Set(g_defaultRepresentation);
+  vtkSMPropertyHelper(filterProxy, "Opacity").Set(g_defaultOpacity);
+  vtkSMPropertyHelper(filterProxy, "GaussianRadius").Set(g_defaultRadius);
   emit this->lockColorControls();
 }
 
@@ -303,8 +313,8 @@ void SplatterPlotView::checkView(ModeControlWidget::Views initialView) {
 void SplatterPlotView::onPickModeToggled(bool state) {
   pqObjectBuilder *builder = pqApplicationCore::instance()->getObjectBuilder();
   if (state) {
-    pqPipelineSource *src = NULL;
-    if (NULL != this->m_threshSource) {
+    pqPipelineSource *src = nullptr;
+    if (this->m_threshSource) {
       src = this->m_threshSource;
     } else {
       src = this->m_splatSource;
@@ -351,7 +361,7 @@ void SplatterPlotView::readAndSendCoordinates() {
   vtkSMDoubleVectorProperty *coords =
       vtkSMDoubleVectorProperty::SafeDownCast(pList[0]->GetProperty("Center"));
 
-  if (NULL != coords) {
+  if (coords) {
     // Get coordinate type
     int peakViewCoords =
         vtkSMPropertyHelper(
@@ -460,10 +470,11 @@ void SplatterPlotView::createPeaksFilter() {
     pqDataRepresentation *dataRepresentation =
         m_peaksFilter->getRepresentation(this->m_view);
     vtkSMPropertyHelper(dataRepresentation->getProxy(), "Representation")
-        .Set("Point Gaussian");
+        .Set(g_defaultRepresentation);
     vtkSMPropertyHelper(dataRepresentation->getProxy(), "GaussianRadius")
-        .Set(0.005);
-    vtkSMPropertyHelper(dataRepresentation->getProxy(), "Opacity").Set(0.5);
+        .Set(g_defaultOpacity);
+    vtkSMPropertyHelper(dataRepresentation->getProxy(), "Opacity")
+        .Set(g_defaultRadius);
     dataRepresentation->getProxy()->UpdateVTKObjects();
 
     if (!this->isPeaksWorkspace(this->origSrc)) {
@@ -622,7 +633,7 @@ void SplatterPlotView::updatePeaksFilter(pqPipelineSource *filter) {
  * We need to do this, since PV can destroy the filter in a general
  * destorySources command.
  */
-void SplatterPlotView::onPeaksFilterDestroyed() { m_peaksFilter = NULL; }
+void SplatterPlotView::onPeaksFilterDestroyed() { m_peaksFilter = nullptr; }
 
 /**
  * Destroy all sources in the splatterplot view. We need to delete the filters
diff --git a/Vates/VatesSimpleGui/ViewWidgets/src/StandardView.cpp b/Vates/VatesSimpleGui/ViewWidgets/src/StandardView.cpp
index bac8b85d96ff7f75e3f1f5788dc50763598a474d..c3978bab05aab7a48695efab05a5870df0bbd79e 100644
--- a/Vates/VatesSimpleGui/ViewWidgets/src/StandardView.cpp
+++ b/Vates/VatesSimpleGui/ViewWidgets/src/StandardView.cpp
@@ -93,8 +93,8 @@ QMap<QString, QString> StandardView::g_actionToAlgName;
 StandardView::StandardView(QWidget *parent,
                            RebinnedSourcesManager *rebinnedSourcesManager,
                            bool createRenderProxy)
-    : ViewBase(parent, rebinnedSourcesManager), m_binMDAction(NULL),
-      m_sliceMDAction(NULL), m_cutMDAction(NULL), m_unbinAction(NULL) {
+    : ViewBase(parent, rebinnedSourcesManager), m_binMDAction(nullptr),
+      m_sliceMDAction(nullptr), m_cutMDAction(nullptr), m_unbinAction(nullptr) {
   this->m_ui.setupUi(this);
   this->m_cameraReset = false;
 
@@ -112,6 +112,10 @@ StandardView::StandardView(QWidget *parent,
   QObject::connect(this->m_ui.cutButton, SIGNAL(clicked()), this,
                    SLOT(onCutButtonClicked()));
 
+  // Set the cut button to create a slice on the data
+  QObject::connect(this->m_ui.thresholdButton, SIGNAL(clicked()), this,
+                   SLOT(onThresholdButtonClicked()));
+
   // Listen to a change in the active source, to adapt our rebin buttons
   QObject::connect(&pqActiveObjects::instance(),
                    SIGNAL(sourceChanged(pqPipelineSource *)), this,
@@ -175,6 +179,7 @@ void StandardView::setupViewButtons() {
 void StandardView::destroyView() {
   pqObjectBuilder *builder = pqApplicationCore::instance()->getObjectBuilder();
   this->destroyFilter(QString("Slice"));
+  this->destroyFilter(QString("Threshold"));
   builder->destroy(this->m_view);
 }
 
@@ -182,7 +187,7 @@ pqRenderView *StandardView::getView() { return this->m_view.data(); }
 
 void StandardView::render() {
   this->origSrc = pqActiveObjects::instance().activeSource();
-  if (NULL == this->origSrc) {
+  if (!this->origSrc) {
     return;
   }
   pqObjectBuilder *builder = pqApplicationCore::instance()->getObjectBuilder();
@@ -205,15 +210,11 @@ void StandardView::render() {
   if (!this->isPeaksWorkspace(this->origSrc)) {
     vtkSMPVRepresentationProxy::SetScalarColoring(
         drep->getProxy(), "signal", vtkDataObject::FIELD_ASSOCIATION_CELLS);
-    // drep->getProxy()->UpdateVTKObjects();
-    // vtkSMPVRepresentationProxy::RescaleTransferFunctionToDataRange(drep->getProxy(),
-    //                                                               "signal",
-    //                                                               vtkDataObject::FIELD_ASSOCIATION_CELLS);
     drep->getProxy()->UpdateVTKObjects();
   }
 
-  this->resetDisplay();
   emit this->triggerAccept();
+  this->resetDisplay();
 }
 
 void StandardView::onCutButtonClicked() {
@@ -231,6 +232,21 @@ void StandardView::onCutButtonClicked() {
   setVisibilityListener();
 }
 
+void StandardView::onThresholdButtonClicked() {
+  // check that has active source
+  if (!hasActiveSource()) {
+    return;
+  }
+
+  // Apply cut to currently viewed data
+  pqObjectBuilder *builder = pqApplicationCore::instance()->getObjectBuilder();
+  builder->createFilter("filters", "Threshold", this->getPvActiveSrc());
+
+  // We need to attach the visibility listener to the newly
+  // created filter, this is required for automatic updating the color scale
+  setVisibilityListener();
+}
+
 void StandardView::onScaleButtonClicked() {
   // check that has active source
   if (!hasActiveSource()) {
diff --git a/Vates/VatesSimpleGui/ViewWidgets/src/ThreesliceView.cpp b/Vates/VatesSimpleGui/ViewWidgets/src/ThreesliceView.cpp
index 15d062155e4fa13ed01a06ff27993d0794ab77c1..1dffe55dc37c844f46dac95510faa3679c126dcb 100644
--- a/Vates/VatesSimpleGui/ViewWidgets/src/ThreesliceView.cpp
+++ b/Vates/VatesSimpleGui/ViewWidgets/src/ThreesliceView.cpp
@@ -66,9 +66,7 @@ void ThreeSliceView::render() {
 }
 
 void ThreeSliceView::makeThreeSlice() {
-  pqPipelineSource *src = NULL;
-  src = pqActiveObjects::instance().activeSource();
-
+  pqPipelineSource *src = pqActiveObjects::instance().activeSource();
   pqObjectBuilder *builder = pqApplicationCore::instance()->getObjectBuilder();
 
   // Do not allow overplotting PeaksWorkspaces
@@ -85,6 +83,10 @@ void ThreeSliceView::makeThreeSlice() {
 
   this->origSrc = src;
 
+  if (this->origSrc == nullptr) {
+    return;
+  }
+
   pqDataRepresentation *drep = builder->createDataRepresentation(
       this->origSrc->getOutputPort(0), this->m_mainView);
   vtkSMPropertyHelper(drep->getProxy(), "Representation").Set("Slices");
diff --git a/Vates/VatesSimpleGui/ViewWidgets/src/VatesParaViewApplication.cpp b/Vates/VatesSimpleGui/ViewWidgets/src/VatesParaViewApplication.cpp
index 5eb8c041d5852451ed38f5cbfe39423319210984..ecaf926bd61dba5e02665add86324a26855e53c2 100644
--- a/Vates/VatesSimpleGui/ViewWidgets/src/VatesParaViewApplication.cpp
+++ b/Vates/VatesSimpleGui/ViewWidgets/src/VatesParaViewApplication.cpp
@@ -48,7 +48,7 @@ VatesParaViewApplication::VatesParaViewApplication()
         "set this variable.");
   }
 
-  Q_ASSERT(pqApplicationCore::instance() == NULL);
+  Q_ASSERT(pqApplicationCore::instance() == nullptr);
 
   // Provide ParaView's application core with a path to the running executable
   int argc = 1;
@@ -114,7 +114,7 @@ VatesParaViewApplication::~VatesParaViewApplication() {}
 
 VatesParaViewApplication *VatesParaViewApplication::instance() {
   static QPointer<VatesParaViewApplication> arg;
-  if (arg == NULL) {
+  if (!arg) {
     arg = new VatesParaViewApplication();
   }
   return arg;
diff --git a/Vates/VatesSimpleGui/ViewWidgets/src/ViewBase.cpp b/Vates/VatesSimpleGui/ViewWidgets/src/ViewBase.cpp
index 6e3d0b27f74f100d0bc73a86afcb8e21b2987657..e970106b37eb0bd1e67323a66d885ef945cad6b8 100644
--- a/Vates/VatesSimpleGui/ViewWidgets/src/ViewBase.cpp
+++ b/Vates/VatesSimpleGui/ViewWidgets/src/ViewBase.cpp
@@ -67,7 +67,7 @@ ViewBase::ViewBase(QWidget *parent,
                    RebinnedSourcesManager *rebinnedSourcesManager)
     : QWidget(parent), m_rebinnedSourcesManager(rebinnedSourcesManager),
       m_internallyRebinnedWorkspaceIdentifier("rebinned_vsi"),
-      m_colorScaleLock(NULL) {}
+      m_colorScaleLock(nullptr) {}
 
 /**
  * This function creates a single standard ParaView view instance.
@@ -155,7 +155,7 @@ void ViewBase::clearRenderLayout(QFrame *frame) {
   QLayout *layout = frame->layout();
   if (layout) {
     QLayoutItem *item;
-    while ((item = layout->takeAt(0)) != nullptr)
+    while ((item = layout->takeAt(0)))
       layout->removeItem(item);
     delete layout;
   }
@@ -167,7 +167,7 @@ void ViewBase::clearRenderLayout(QFrame *frame) {
  */
 void ViewBase::onColorMapChange(const Json::Value &model) {
   pqPipelineRepresentation *rep = this->getRep();
-  if (NULL == rep) {
+  if (!rep) {
     return;
   }
   // Work around a "bug" in pqScalarToColors::checkRange() where the lower
@@ -252,7 +252,7 @@ void ViewBase::setColorsForView(ColorSelectionWidget *colorScale) {
  * @return true if the pipeline source is derived from PeaksWorkspace
  */
 bool ViewBase::isPeaksWorkspace(pqPipelineSource *src) {
-  if (NULL == src) {
+  if (!src) {
     return false;
   }
   QString wsType(vtkSMPropertyHelper(src->getProxy(), "WorkspaceTypeName", true)
@@ -305,7 +305,7 @@ pqPipelineSource *ViewBase::setPluginSource(QString pluginName, QString wsName,
   auto workspaceProvider = Mantid::Kernel::make_unique<
       Mantid::VATES::ADSWorkspaceProvider<Mantid::API::IMDEventWorkspace>>();
   if (auto split = Mantid::VATES::findRecursionDepthForTopLevelSplitting(
-          wsName.toStdString(), std::move(workspaceProvider))) {
+          wsName.toStdString(), *workspaceProvider)) {
     vtkSMPropertyHelper(src->getProxy(), "Recursion Depth").Set(split.get());
   }
   // WORKAROUND END
@@ -433,7 +433,7 @@ long long ViewBase::getNumSources() {
  * @param dvp the vector property containing the "time" information
  */
 void ViewBase::handleTimeInfo(vtkSMDoubleVectorProperty *dvp) {
-  if (NULL == dvp) {
+  if (!dvp) {
     // This is a normal filter and therefore has no timesteps.
     // qDebug() << "No timestep vector, returning.";
     return;
@@ -584,7 +584,7 @@ void ViewBase::closeSubWindows() {}
  */
 pqPipelineRepresentation *ViewBase::getRep() {
   pqPipelineRepresentation *rep = this->getPvActiveRep();
-  if (NULL == rep) {
+  if (!rep) {
     rep = this->origRep;
   }
   return rep;
@@ -595,7 +595,7 @@ pqPipelineRepresentation *ViewBase::getRep() {
  * @return true if the source is a MDHistoWorkspace
  */
 bool ViewBase::isMDHistoWorkspace(pqPipelineSource *src) {
-  if (NULL == src) {
+  if (!src) {
     return false;
   }
   QString wsType(vtkSMPropertyHelper(src->getProxy(), "WorkspaceTypeName", true)
@@ -613,7 +613,7 @@ bool ViewBase::isMDHistoWorkspace(pqPipelineSource *src) {
  * @return true if the source is an internally rebinned workspace;
  */
 bool ViewBase::isInternallyRebinnedWorkspace(pqPipelineSource *src) {
-  if (NULL == src) {
+  if (!src) {
     return false;
   }
 
@@ -691,7 +691,7 @@ pqPipelineSource *ViewBase::hasWorkspace(const QString &name) {
       }
     }
   }
-  return NULL;
+  return nullptr;
 }
 
 /**
@@ -887,7 +887,7 @@ void ViewBase::setAxesGrid(bool on) {
  * Check if there is an active source available
  * @returns true if there is an active source else false
  */
-bool ViewBase::hasActiveSource() { return this->getPvActiveSrc() != nullptr; }
+bool ViewBase::hasActiveSource() { return this->getPvActiveSrc(); }
 
 } // namespace SimpleGui
 } // namespace Vates
diff --git a/Vates/VatesSimpleGui/ViewWidgets/src/VsiApplyBehaviour.cpp b/Vates/VatesSimpleGui/ViewWidgets/src/VsiApplyBehaviour.cpp
index 85a885c4f2cc26465a52a23edddd99ef6dbc9ffa..6425e47246fe38b1395245ec021b2fa5514d3d09 100644
--- a/Vates/VatesSimpleGui/ViewWidgets/src/VsiApplyBehaviour.cpp
+++ b/Vates/VatesSimpleGui/ViewWidgets/src/VsiApplyBehaviour.cpp
@@ -6,11 +6,7 @@ namespace SimpleGui {
 
 VsiApplyBehaviour::VsiApplyBehaviour(Mantid::VATES::ColorScaleLock *lock,
                                      QObject *parent)
-    : pqApplyBehavior(parent), m_colorScaleLock(NULL) {
-  if (lock != NULL) {
-    m_colorScaleLock = lock;
-  }
-}
+    : pqApplyBehavior(parent), m_colorScaleLock(lock) {}
 
 /**
  * Forward the register request
@@ -30,14 +26,14 @@ void VsiApplyBehaviour::unregisterPanel(pqPropertiesPanel *panel) {
 /// React to the apply button press. We forward the request, but we add a lock
 void VsiApplyBehaviour::applied(pqPropertiesPanel *, pqProxy *pqproxy) {
   Mantid::VATES::ColorScaleLockGuard colorScaleLockGuard(m_colorScaleLock);
-  this->pqApplyBehavior::applied(NULL, pqproxy);
+  this->pqApplyBehavior::applied(nullptr, pqproxy);
 }
 
 /// React to the apply button press. We forward the request, but we add a lock
 void VsiApplyBehaviour::applied(pqPropertiesPanel *) {
   Mantid::VATES::ColorScaleLockGuard colorScaleLockGuard(m_colorScaleLock);
-  this->pqApplyBehavior::applied(NULL);
+  this->pqApplyBehavior::applied(nullptr);
+}
 }
 }
 }
-}
\ No newline at end of file
diff --git a/buildconfig/CMake/Bootstrap.cmake b/buildconfig/CMake/Bootstrap.cmake
index 2b0b240acb971a22089f6882679733cb2562bb70..30ad09073e4a79162c1657bb435023d8ee357be9 100644
--- a/buildconfig/CMake/Bootstrap.cmake
+++ b/buildconfig/CMake/Bootstrap.cmake
@@ -10,7 +10,7 @@ if( MSVC )
   include ( ExternalProject )
   set( EXTERNAL_ROOT ${PROJECT_SOURCE_DIR}/external )
   set( THIRD_PARTY_GIT_URL "https://github.com/mantidproject/thirdparty-msvc2015.git" )
-  set ( THIRD_PARTY_GIT_SHA1 f73d59f82eaa2ea990c33b76447dcf9dcb670885 )
+  set ( THIRD_PARTY_GIT_SHA1 4691e740fa2050f4fd0b44628eac445906bb2978 )
   set ( THIRD_PARTY_DIR ${EXTERNAL_ROOT}/src/ThirdParty )
   # Generates a script to do the clone/update in tmp
   set ( _project_name ThirdParty )
diff --git a/buildconfig/CMake/CommonSetup.cmake b/buildconfig/CMake/CommonSetup.cmake
index 0b3c80c745c3200cf22c87d58e8be47396d32dea..3ee919cc85b00334bba69875b68cc8981179e8a9 100644
--- a/buildconfig/CMake/CommonSetup.cmake
+++ b/buildconfig/CMake/CommonSetup.cmake
@@ -95,22 +95,21 @@ find_package ( OpenSSL REQUIRED )
 
 set ( MtdVersion_WC_LAST_CHANGED_DATE Unknown )
 set ( MtdVersion_WC_LAST_CHANGED_DATETIME 0 )
+set ( MtdVersion_WC_LAST_CHANGED_SHA Unknown )
 set ( NOT_GIT_REPO "Not" )
 
 if ( GIT_FOUND )
   # Get the last revision
-  execute_process ( COMMAND ${GIT_EXECUTABLE} describe --long
-                    OUTPUT_VARIABLE GIT_DESCRIBE
+  execute_process ( COMMAND ${GIT_EXECUTABLE} rev-parse --short HEAD
+                    OUTPUT_VARIABLE GIT_SHA_HEAD
                     ERROR_VARIABLE NOT_GIT_REPO
                     WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
+                    OUTPUT_STRIP_TRAILING_WHITESPACE
   )
   if ( NOT NOT_GIT_REPO ) # i.e This is a git repository!
-    # Remove the tag name part
-    string ( REGEX MATCH "[-](.*)" MtdVersion_WC_LAST_CHANGED_REV ${GIT_DESCRIBE} )
-    # Extract the SHA1 part (with a 'g' prefix which stands for 'git')
-    # N.B. The variable comes back from 'git describe' with a line feed on the end, so we need to lose that
-    string ( REGEX MATCH "(g.*)[^\n]" MtdVersion_WC_LAST_CHANGED_SHA ${MtdVersion_WC_LAST_CHANGED_REV} )
-
+    # "git describe" was originally used to produce this variable and this prefixes the short
+    # SHA1 with a 'g'. We keep the same format here now that we use rev-parse
+    set ( MtdVersion_WC_LAST_CHANGED_SHA "g${GIT_SHA_HEAD}" )
     # Get the date of the last commit
     execute_process ( COMMAND ${GIT_EXECUTABLE} log -1 --format=format:%cD OUTPUT_VARIABLE MtdVersion_WC_LAST_CHANGED_DATE
                       WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
@@ -215,8 +214,8 @@ endif()
 
 ###########################################################################
 # Include the file that contains the version number
-# This must come after the git describe business above because it can be
-# used to override the patch version number (MtdVersion_WC_LAST_CHANGED_REV)
+# This must come after the git business above because it can be
+# used to override the patch version number
 ###########################################################################
 include ( VersionNumber )
 
diff --git a/buildconfig/CMake/DarwinSetup.cmake b/buildconfig/CMake/DarwinSetup.cmake
index 432f8e32762df35afb29c078f0a5930b8a653f21..3599de27c11070389f5fdf40fdaf3871c018baea 100644
--- a/buildconfig/CMake/DarwinSetup.cmake
+++ b/buildconfig/CMake/DarwinSetup.cmake
@@ -174,6 +174,8 @@ endif ()
 
 install ( DIRECTORY ${PYQT4_PYTHONPATH}/uic DESTINATION ${BIN_DIR}/PyQt4 )
 
+install ( FILES ${CMAKE_SOURCE_DIR}/images/MantidPlot.icns
+          DESTINATION MantidPlot.app/Contents/Resources/ )
 # Add launcher script for mantid python
 install ( PROGRAMS ${CMAKE_BINARY_DIR}/mantidpython_osx_install
           DESTINATION MantidPlot.app/Contents/MacOS/
@@ -198,7 +200,7 @@ install ( FILES ${CMAKE_SOURCE_DIR}/images/MantidNotebook.icns
           DESTINATION MantidNotebook\ \(optional\).app/Contents/Resources/ )
 
 set ( CPACK_DMG_BACKGROUND_IMAGE ${CMAKE_SOURCE_DIR}/images/osx-bundle-background.png )
-set ( CPACK_DMG_DS_STORE ${CMAKE_SOURCE_DIR}/installers/MacInstaller/osx_DS_Store)
+set ( CPACK_DMG_DS_STORE_SETUP_SCRIPT ${CMAKE_SOURCE_DIR}/installers/MacInstaller/CMakeDMGSetup.scpt )
 set ( MACOSX_BUNDLE_ICON_FILE MantidPlot.icns )
 
 string (REPLACE " " "" CPACK_SYSTEM_NAME ${OSX_CODENAME})
diff --git a/buildconfig/CMake/Packaging/osx/mantidpython_osx b/buildconfig/CMake/Packaging/osx/mantidpython_osx
index 3c208af1e5d2bee343815b1efab78dc3ef6de5b4..dbdbcff3c18c9e501ea5f46cbb037f2f5cca62d6 100755
--- a/buildconfig/CMake/Packaging/osx/mantidpython_osx
+++ b/buildconfig/CMake/Packaging/osx/mantidpython_osx
@@ -15,7 +15,7 @@ cd "`dirname "${SCRIPT_PATH}"`" > /dev/null
 SCRIPT_PATH="`pwd`";
 popd  > /dev/null
 
-PROG=${SCRIPT_PATH}/bin/ipython
+PROG=${SCRIPT_PATH}/bin/ipython@PYTHON_VERSION_MAJOR@
 
 # Define extra libraries for python
 LOCAL_PYTHONPATH=${SCRIPT_PATH}
@@ -26,7 +26,7 @@ fi
 
 if [ -n "$1" ] && [ "$1" = "--classic" ]; then
     shift
-    PROG=$(command -v python)
+    PROG=$(command -v python@PYTHON_VERSION_MAJOR@.@PYTHON_VERSION_MINOR@)
 fi
 
 # Define MANTIDPATH
diff --git a/buildconfig/Jenkins/buildscript b/buildconfig/Jenkins/buildscript
index 4fe31ab498a68bd7926bb918a1725c2a8358a14a..f10a1c0ce374fdd84ed7690b40cf8a9603ead659 100755
--- a/buildconfig/Jenkins/buildscript
+++ b/buildconfig/Jenkins/buildscript
@@ -136,6 +136,7 @@ fi
 if [[ ${JOB_NAME} == *python3* ]]; then
   PYTHON3_EXECUTABLE=`which python3`
   DIST_FLAGS="${DIST_FLAGS} -DPYTHON_EXECUTABLE=$PYTHON3_EXECUTABLE"
+  PARAVIEW_DIR="${PARAVIEW_DIR}-python3"
 fi
 
 ###############################################################################
diff --git a/buildconfig/dev-packages/deb/mantid-developer/README b/buildconfig/dev-packages/deb/mantid-developer/README
index 45484a4c965290f18bb3e5aa6fa3658f7ad1358f..0b684d4f9f4fe7d604251f4e6d03cc34322f986c 100644
--- a/buildconfig/dev-packages/deb/mantid-developer/README
+++ b/buildconfig/dev-packages/deb/mantid-developer/README
@@ -1,6 +1,12 @@
-This directory contains the structure required to build the simple mantid-developer debian file.
+This directory contains an ns-control file designed to be interpreted with the
+`equivs-build` command from the `equivs` debian package. This will need to be
+install via apt:
+
+```
+apt-get install equivs
+```
 
 To build the package:
    * Switch to the directory containing this file
-   * Run "dpkg --build mantid-developer/mantid-developer-1.2.7"
-   * A file called mantid-developer-1.2.7.deb will appear in the mantid-developer directory.
+   * Run `equivs-build ns-control`
+   * A file called mantid-developer_x.y.z.deb will appear in this directory.
diff --git a/buildconfig/dev-packages/deb/mantid-developer/mantid-developer-1.2.1/DEBIAN/control b/buildconfig/dev-packages/deb/mantid-developer/mantid-developer-1.2.1/DEBIAN/control
deleted file mode 100644
index 92c2c310e02fe35e7875dc1c55ec1eda16278a13..0000000000000000000000000000000000000000
--- a/buildconfig/dev-packages/deb/mantid-developer/mantid-developer-1.2.1/DEBIAN/control
+++ /dev/null
@@ -1,11 +0,0 @@
-Package: mantid-developer
-Version: 1.2.1
-Section: main
-Priority: optional
-Architecture: all
-Depends: git, cmake-qt-gui(>=2.8.12), qt4-qmake, qt4-dev-tools, libpoco-dev, libboost-all-dev, libnexus0-dev, libgoogle-perftools-dev, libqwt5-qt4-dev, libqwtplot3d-qt4-dev, python-qt4-dev, libgsl0-dev, liboce-visualization-dev, libmuparser-dev, python-numpy, libssl-dev, libqscintilla2-dev, texlive,texlive-latex-extra, dvipng, libhdf4-dev, doxygen, python-sphinx, python-scipy, ipython-qtconsole (>=1.2.0), libhdf5-dev, libhdf4-dev, libpococrypto9-dbg, libpocodata9-dbg, libpocofoundation9-dbg, libpocomysql9-dbg, libpoconet9-dbg, libpoconetssl9-dbg, libpocoodbc9-dbg, libpocosqlite9-dbg, libpocoutil9-dbg, libpocoxml9-dbg, libpocozip9-dbg, python-qt4-dbg, qt4-default, ninja-build
-Installed-Size: 0
-Maintainer: Mantid Project <mantid-help@mantidproject.org>
-Description: Installs all packages required for a Mantid developer
- A metapackage which requires all the dependencies and tools that are 
- required for Mantid development. It works for Ubuntu version 14.04
diff --git a/buildconfig/dev-packages/deb/mantid-developer/mantid-developer-1.2.2/DEBIAN/control b/buildconfig/dev-packages/deb/mantid-developer/mantid-developer-1.2.2/DEBIAN/control
deleted file mode 100644
index 1f541e4af9b7e5d6276d965254550efb2b8d2a25..0000000000000000000000000000000000000000
--- a/buildconfig/dev-packages/deb/mantid-developer/mantid-developer-1.2.2/DEBIAN/control
+++ /dev/null
@@ -1,13 +0,0 @@
-Package: mantid-developer
-Version: 1.2.2
-Section: main
-Priority: optional
-Architecture: all
-Depends: git, cmake-qt-gui(>=2.8.12), qt4-qmake, qt4-dev-tools, libqt4-dbg, libpoco-dev(>=1.4.2), libboost-all-dev, libboost-dbg, libnexus0-dev, libgoogle-perftools-dev, libqwt5-qt4-dev, libqwtplot3d-qt4-dev, python-qt4-dev, libgsl0-dev, liboce-visualization-dev, libmuparser-dev, python-numpy, libssl-dev, libqscintilla2-dev, texlive,texlive-latex-extra, dvipng, libhdf4-dev, doxygen, python-sphinx, python-scipy, ipython-qtconsole (>=1.2.0), libhdf5-dev, libhdf4-dev, libpococrypto11-dbg, libpocodata11-dbg, libpocofoundation11-dbg, libpocomysql11-dbg, libpoconet11-dbg, libpoconetssl11-dbg, libpocoodbc11-dbg, libpocosqlite11-dbg, libpocoutil11-dbg, libpocoxml11-dbg, libpocozip11-dbg, python-qt4-dbg, qt4-default, ninja-build, libjsoncpp-dev, python-dateutil
-Installed-Size: 0
-Maintainer: Mantid Project <mantid-help@mantidproject.org>
-Description: Installs all packages required for a Mantid developer
- A metapackage which requires all the dependencies and tools that are 
- required for Mantid development. It works for Ubuntu version 14.04, 14.10
- Some packages (poco) must be newer than thiose in the Ubuntu repository. Please 
- follow instructions at http://www.mantidproject.org/Mantid_Prerequisites#Repositories
diff --git a/buildconfig/dev-packages/deb/mantid-developer/mantid-developer-1.2.3/DEBIAN/control b/buildconfig/dev-packages/deb/mantid-developer/mantid-developer-1.2.3/DEBIAN/control
deleted file mode 100644
index 5d0abce474b78c18fa84bc3d1fd744ec2304d911..0000000000000000000000000000000000000000
--- a/buildconfig/dev-packages/deb/mantid-developer/mantid-developer-1.2.3/DEBIAN/control
+++ /dev/null
@@ -1,13 +0,0 @@
-Package: mantid-developer
-Version: 1.2.3
-Section: main
-Priority: optional
-Architecture: all
-Depends: git, clang, cmake-qt-gui(>=2.8.12), qt4-qmake, qt4-dev-tools, libqt4-dbg, libpoco-dev(>=1.4.2), libboost-all-dev, libboost-dbg, libnexus0-dev, libgoogle-perftools-dev, libqwt5-qt4-dev, libqwtplot3d-qt4-dev, python-qt4-dev, libgsl0-dev, liboce-visualization-dev, libmuparser-dev, python-numpy, libssl-dev, libqscintilla2-dev, texlive, texlive-latex-extra, dvipng, libhdf4-dev, doxygen, python-sphinx, python-scipy, ipython-qtconsole (>=1.2.0), libhdf5-dev, libhdf4-dev, libpococrypto11-dbg, libpocodata11-dbg, libpocofoundation11-dbg, libpocomysql11-dbg, libpoconet11-dbg, libpoconetssl11-dbg, libpocoodbc11-dbg, libpocosqlite11-dbg, libpocoutil11-dbg, libpocoxml11-dbg, libpocozip11-dbg, python-qt4-dbg, qt4-default, ninja-build, libjsoncpp-dev, python-dateutil, python-sphinx-bootstrap-theme
-Installed-Size: 0
-Maintainer: Mantid Project <mantid-help@mantidproject.org>
-Description: Installs all packages required for a Mantid developer
- A metapackage which requires all the dependencies and tools that are 
- required for Mantid development. It works for Ubuntu version 14.04, 14.10
- Some packages (poco) must be newer than thiose in the Ubuntu repository. Please 
- follow instructions at http://www.mantidproject.org/Mantid_Prerequisites#Repositories
diff --git a/buildconfig/dev-packages/deb/mantid-developer/mantid-developer-1.2.4/DEBIAN/control b/buildconfig/dev-packages/deb/mantid-developer/mantid-developer-1.2.4/DEBIAN/control
deleted file mode 100644
index 469c1f027e338df71632c5bb7c14508ac7ad38db..0000000000000000000000000000000000000000
--- a/buildconfig/dev-packages/deb/mantid-developer/mantid-developer-1.2.4/DEBIAN/control
+++ /dev/null
@@ -1,13 +0,0 @@
-Package: mantid-developer
-Version: 1.2.4
-Section: main
-Priority: optional
-Architecture: all
-Depends: g++, git, clang, cmake-qt-gui(>=2.8.12), qt4-qmake, qt4-dev-tools, libqt4-dbg, libpoco-dev(>=1.4.2), libboost-all-dev, libboost-dbg, libnexus0-dev, libgoogle-perftools-dev, libqwt5-qt4-dev, libqwtplot3d-qt4-dev, python-qt4-dev, libgsl0-dev, liboce-visualization-dev, libmuparser-dev, python-numpy, libssl-dev, libqscintilla2-dev, texlive,texlive-latex-extra, dvipng, libhdf4-dev, doxygen, python-sphinx, python-scipy, ipython-qtconsole (>=1.2.0), libhdf5-dev, libhdf4-dev, libpococrypto11-dbg, libpocodata11-dbg, libpocofoundation11-dbg, libpocomysql11-dbg, libpoconet11-dbg, libpoconetssl11-dbg, libpocoodbc11-dbg, libpocosqlite11-dbg, libpocoutil11-dbg, libpocoxml11-dbg, libpocozip11-dbg, python-qt4-dbg, qt4-default, ninja-build, libjsoncpp-dev, python-dateutil, python-sphinx-bootstrap-theme, graphviz
-Installed-Size: 0
-Maintainer: Mantid Project <mantid-help@mantidproject.org>
-Description: Installs all packages required for a Mantid developer
- A metapackage which requires all the dependencies and tools that are 
- required for Mantid development. It works for Ubuntu version 14.04, 14.10
- Some packages (poco) must be newer than those in the Ubuntu repository. Please 
- follow instructions at http://www.mantidproject.org/Mantid_Prerequisites#Repositories
diff --git a/buildconfig/dev-packages/deb/mantid-developer/mantid-developer-1.2.5/DEBIAN/control b/buildconfig/dev-packages/deb/mantid-developer/mantid-developer-1.2.5/DEBIAN/control
deleted file mode 100644
index 58b0055b7d4190626264169468d9cff5a00aad29..0000000000000000000000000000000000000000
--- a/buildconfig/dev-packages/deb/mantid-developer/mantid-developer-1.2.5/DEBIAN/control
+++ /dev/null
@@ -1,13 +0,0 @@
-Package: mantid-developer
-Version: 1.2.5
-Section: main
-Priority: optional
-Architecture: all
-Depends: g++, git, clang, cmake-qt-gui(>=2.8.12), qt4-qmake, qt4-dev-tools, libqt4-dbg, libpoco-dev(>=1.4.2), libboost-all-dev, libboost-dbg, libnexus0-dev, libgoogle-perftools-dev, libqwt5-qt4-dev, libqwtplot3d-qt4-dev, python-qt4-dev, libgsl0-dev, liboce-visualization-dev, libmuparser-dev, python-numpy, libssl-dev, libqscintilla2-dev, texlive,texlive-latex-extra, dvipng, libhdf4-dev, doxygen, python-sphinx, python-scipy, ipython-qtconsole (>=1.2.0), libhdf5-dev, libhdf4-dev, libpococrypto11-dbg, libpocodata11-dbg, libpocofoundation11-dbg, libpocomysql11-dbg, libpoconet11-dbg, libpoconetssl11-dbg, libpocoodbc11-dbg, libpocosqlite11-dbg, libpocoutil11-dbg, libpocoxml11-dbg, libpocozip11-dbg, python-qt4-dbg, qt4-default, ninja-build, libjsoncpp-dev, python-dateutil, python-sphinx-bootstrap-theme, graphviz, python-matplotlib
-Installed-Size: 0
-Maintainer: Mantid Project <mantid-help@mantidproject.org>
-Description: Installs all packages required for a Mantid developer
- A metapackage which requires all the dependencies and tools that are 
- required for Mantid development. It works for Ubuntu version 14.04, 14.10
- Some packages (poco) must be newer than those in the Ubuntu repository. Please 
- follow instructions at http://www.mantidproject.org/Mantid_Prerequisites#Repositories
diff --git a/buildconfig/dev-packages/deb/mantid-developer/mantid-developer-1.2.6/DEBIAN/control b/buildconfig/dev-packages/deb/mantid-developer/mantid-developer-1.2.6/DEBIAN/control
deleted file mode 100644
index 5366d7ae0ba161f0f8836bddf2708ec50eca9d83..0000000000000000000000000000000000000000
--- a/buildconfig/dev-packages/deb/mantid-developer/mantid-developer-1.2.6/DEBIAN/control
+++ /dev/null
@@ -1,13 +0,0 @@
-Package: mantid-developer
-Version: 1.2.6
-Section: main
-Priority: optional
-Architecture: all
-Depends: g++, git, clang, cmake-qt-gui(>=2.8.12), qt4-qmake, qt4-dev-tools, libqt4-dbg, libpoco-dev(>=1.4.2), libboost-all-dev, libboost-dbg, libnexus0-dev, libgoogle-perftools-dev, libqwt5-qt4-dev, libqwtplot3d-qt4-dev, python-qt4-dev, libgsl0-dev, liboce-visualization-dev, libmuparser-dev, python-numpy, libssl-dev, libqscintilla2-dev, texlive,texlive-latex-extra, dvipng, libhdf4-dev, doxygen, python-sphinx, python-scipy, ipython-qtconsole (>=1.2.0), libhdf5-dev, libhdf4-dev, libpococrypto11-dbg, libpocodata11-dbg, libpocofoundation11-dbg, libpocomysql11-dbg, libpoconet11-dbg, libpoconetssl11-dbg, libpocoodbc11-dbg, libpocosqlite11-dbg, libpocoutil11-dbg, libpocoxml11-dbg, libpocozip11-dbg, python-qt4-dbg, qt4-default, ninja-build, libjsoncpp-dev(>=0.7.0), python-dateutil, python-sphinx-bootstrap-theme, graphviz, python-matplotlib
-Installed-Size: 0
-Maintainer: Mantid Project <mantid-help@mantidproject.org>
-Description: Installs all packages required for a Mantid developer
- A metapackage which requires all the dependencies and tools that are 
- required for Mantid development. It works for Ubuntu version 14.04, 14.10
- Some packages (poco) must be newer than those in the Ubuntu repository. Please 
- follow instructions at http://www.mantidproject.org/Mantid_Prerequisites#Repositories
diff --git a/buildconfig/dev-packages/deb/mantid-developer/mantid-developer-1.2.7/DEBIAN/control b/buildconfig/dev-packages/deb/mantid-developer/mantid-developer-1.2.7/DEBIAN/control
deleted file mode 100644
index 1e53974118c58f8fd376201f1311bfe5278d3a24..0000000000000000000000000000000000000000
--- a/buildconfig/dev-packages/deb/mantid-developer/mantid-developer-1.2.7/DEBIAN/control
+++ /dev/null
@@ -1,13 +0,0 @@
-Package: mantid-developer
-Version: 1.2.7
-Section: main
-Priority: optional
-Architecture: all
-Depends: g++, git, clang, cmake-qt-gui(>=2.8.12), qt4-qmake, qt4-dev-tools, libqtwebkit-dev, libqt4-dbg, libpoco-dev(>=1.4.6), libboost-all-dev, libboost-dbg, libnexus0-dev, libgoogle-perftools-dev, libqwt5-qt4-dev, libqwtplot3d-qt4-dev, python-qt4-dev, libgsl0-dev, liboce-visualization-dev, libmuparser-dev, python-numpy, libssl-dev, libqscintilla2-dev, texlive,texlive-latex-extra, dvipng, libhdf4-dev, doxygen, python-sphinx, python-scipy, ipython-qtconsole (>=1.2.0), libhdf5-dev, libhdf4-dev, libpococrypto11-dbg, libpocodata11-dbg, libpocofoundation11-dbg, libpocomysql11-dbg, libpoconet11-dbg, libpoconetssl11-dbg, libpocoodbc11-dbg, libpocosqlite11-dbg, libpocoutil11-dbg, libpocoxml11-dbg, libpocozip11-dbg, python-qt4-dbg, qt4-default, ninja-build, libjsoncpp-dev(>=0.7.0), python-dateutil, python-sphinx-bootstrap-theme, graphviz, python-matplotlib, python-h5py
-Installed-Size: 0
-Maintainer: Mantid Project <mantid-help@mantidproject.org>
-Description: Installs all packages required for a Mantid developer
- A metapackage which requires all the dependencies and tools that are 
- required for Mantid development. It works for Ubuntu versions 14.04 and 16.04
- Some packages (poco) must be newer than those in the Ubuntu repository. Please 
- follow instructions at http://www.mantidproject.org/Mantid_Prerequisites#Repositories
diff --git a/buildconfig/dev-packages/deb/mantid-developer/mantid-developer-1.2/DEBIAN/control b/buildconfig/dev-packages/deb/mantid-developer/mantid-developer-1.2/DEBIAN/control
deleted file mode 100644
index dd5fd1fd043e3439fdc18befa2b845e998c2f6e2..0000000000000000000000000000000000000000
--- a/buildconfig/dev-packages/deb/mantid-developer/mantid-developer-1.2/DEBIAN/control
+++ /dev/null
@@ -1,11 +0,0 @@
-Package: mantid-developer
-Version: 1.2
-Section: main
-Priority: optional
-Architecture: all
-Depends: git, cmake-qt-gui(>=2.8.12), qt4-qmake, qt4-dev-tools, libpoco-dev, libboost-all-dev, libnexus0-dev, libgoogle-perftools-dev, libqwt5-qt4-dev, libqwtplot3d-qt4-dev, python-qt4-dev, libgsl0-dev, liboce-visualization-dev, libmuparser-dev, python-numpy, libssl-dev, libqscintilla2-dev, texlive-latex-extra, dvipng, libhdf4-dev, doxygen, python-sphinx, python-scipy, ipython-qtconsole (>=1.2.0), libhdf5-dev, libhdf4-dev, libpococrypto9-dbg, libpocodata9-dbg, libpocofoundation9-dbg, libpocomysql9-dbg, libpoconet9-dbg, libpoconetssl9-dbg, libpocoodbc9-dbg, libpocosqlite9-dbg, libpocoutil9-dbg, libpocoxml9-dbg, libpocozip9-dbg, python-qt4-dbg, qt4-default, ninja-build
-Installed-Size: 0
-Maintainer: Mantid Project <mantid-help@mantidproject.org>
-Description: Installs all packages required for a Mantid developer
- A metapackage which requires all the dependencies and tools that are 
- required for Mantid development. It works for Ubuntu version 14.04
diff --git a/buildconfig/dev-packages/deb/mantid-developer/ns-control b/buildconfig/dev-packages/deb/mantid-developer/ns-control
new file mode 100644
index 0000000000000000000000000000000000000000..9160584b4676f312ef35ff5a3d2d118c3b45dac3
--- /dev/null
+++ b/buildconfig/dev-packages/deb/mantid-developer/ns-control
@@ -0,0 +1,23 @@
+Section: main
+Priority: optional
+Standards-Version: 3.9.2
+
+Package: mantid-developer
+Version: 1.3.0
+Maintainer: Mantid Project <mantid-tech@mantidproject.org>
+Priority: optional
+Architecture: all
+Depends: git, g++, clang-format-3.6, cmake-qt-gui(>=3.5), ninja-build, libtbb-dev, libgoogle-perftools-dev, libboost-all-dev, libboost-dbg,
+  libpoco-dev(>=1.4.6), libpococrypto31-dbg, libpocodata31-dbg, libpocofoundation31-dbg, libpocomysql31-dbg, libpoconet31-dbg, libpoconetssl31-dbg,
+  libpocoodbc31-dbg, libpocosqlite31-dbg, libpocoutil31-dbg, libpocoxml31-dbg, libpocozip31-dbg, libnexus0-dev,
+  libhdf5-dev, libhdf4-dev, libgsl0-dev, liboce-visualization-dev, libmuparser-dev, libssl-dev, libjsoncpp-dev(>=0.7.0),
+  libpython-dev, python-numpy, python-scipy, python-qt4-dev, python-qt4-dbg, python-sphinx, python-dateutil,
+  python-sphinx-bootstrap-theme, python-matplotlib, python-h5py, python-yaml, python-mock, ipython-qtconsole (>=1.2.0),
+  qt4-default, qt4-qmake, qt4-dev-tools, libqtwebkit-dev, libqwt5-qt4-dev, libqwtplot3d-qt4-dev, libqscintilla2-dev,
+  texlive, texlive-latex-extra, dvipng, graphviz, doxygen
+Description: Installs all packages required for a Mantid developer
+ A metapackage which requires all the dependencies and tools that are
+ required for Mantid development. It works for Ubuntu versions 14.04 and 16.04
+ Some packages (poco) must be newer than those in the Ubuntu repository. Please
+ follow instructions at http://www.mantidproject.org/Mantid_Prerequisites#Repositories
+Installed-Size: 0
diff --git a/buildconfig/dev-packages/rpm/mantid-developer/mantid-developer.spec b/buildconfig/dev-packages/rpm/mantid-developer/mantid-developer.spec
index 1224556100e5e39069e98b6e675f30464951b4eb..97de3caa5857ed1f69583c9454956999def61294 100644
--- a/buildconfig/dev-packages/rpm/mantid-developer/mantid-developer.spec
+++ b/buildconfig/dev-packages/rpm/mantid-developer/mantid-developer.spec
@@ -1,5 +1,11 @@
+%if 0%{?fedora} || 0%{?rhel} >= 8
+  %global with_python3 1
+%else
+  %global with_python3 0
+%endif
+
 Name:           mantid-developer
-Version:        1.19
+Version:        1.21
 Release:        1%{?dist}
 Summary:        Meta Package to install dependencies for Mantid Development
 
@@ -49,6 +55,8 @@ Requires: python-matplotlib
 Requires: python-pip
 Requires: python-sphinx
 Requires: python-sphinx-theme-bootstrap
+Requires: PyYAML
+Requires: python2-mock
 Requires: qscintilla-devel
 Requires: qt-devel >= 4.6
 %if 0%{?el6}
@@ -83,7 +91,7 @@ Requires: qt-devel
 Requires: qtwebkit-devel
 %endif
 Requires: graphviz
-%if 0%{?fedora}
+%if %{with_python3}
 Requires: python3-sip-devel
 Requires: python3-PyQt4-devel
 Requires: python3-numpy
@@ -91,8 +99,11 @@ Requires: python3-scipy
 Requires: python3-sphinx
 Requires: python3-sphinx-theme-bootstrap
 Requires: python3-dateutil
-Requires: python3-matplotlib
+Requires: python3-h5py
 Requires: python3-ipython-gui
+Requires: python3-matplotlib
+Requires: python3-PyYAML
+Requires: python3-mock
 Requires: boost-python3-devel
 %endif
 
@@ -118,6 +129,12 @@ required for Mantid development.
 %files
 
 %changelog
+* Wed Dec 21 2016 Martyn Gigg <martyn.gigg@stfc.ac.uk>
+- Require python-mock & python3-mock on fedora
+
+* Fri Nov 18 2016 Martyn Gigg <martyn.gigg@stfc.ac.uk>
+- Require PyYAML
+
 * Fri Sep 23 2016 Stuart Campbell <campbellsi@ornl.gov>
 - Require poco >= 1.4.6
 
diff --git a/buildconfig/windows/visual-studio.bat b/buildconfig/windows/visual-studio.bat
index 1c641b98bbb2b269a088df500a9a9d754146e157..048959e782b78bef7ce810873328d5014beebaf5 100755
--- a/buildconfig/windows/visual-studio.bat
+++ b/buildconfig/windows/visual-studio.bat
@@ -7,4 +7,4 @@
 call %~dp0buildenv.bat
 
 :: Start IDE
-"%VS140COMNTOOLS%\..\IDE\devenv.exe" Mantid.sln
+start "" "%VS140COMNTOOLS%\..\IDE\devenv.exe" Mantid.sln
diff --git a/docs/runsphinx.py.in b/docs/runsphinx.py.in
index 63d713ed2d0769881889005b17b5243e5e515eb6..affe9cf411f97347f76610c4329364ddd7b18b82 100644
--- a/docs/runsphinx.py.in
+++ b/docs/runsphinx.py.in
@@ -19,6 +19,7 @@ SPHINX_BUILD_DIR = "@SPHINX_BUILD_DIR@"
 SCREENSHOTS_DIR = "@SCREENSHOTS_DIR@"
 DIAGRAMS_DIR = "@DIAGRAMS_DIR@"
 DOT_EXECUTABLE = "@DOT_EXECUTABLE@"
+BUILD_DIR = "@CMAKE_BINARY_DIR@"
 
 ###############################################################################
 # Main
@@ -39,7 +40,7 @@ def main(sysarg):
                            "Use -h for help" % ' '.join(args))
 
     # Update sys path if we need to
-    update_path(opts.mantidpath)
+    update_path()
 
     # Find test files
     testpaths = find_test_files(SRC_DIR, opts.testinclude)
@@ -101,8 +102,6 @@ def parseargs(arglist):
     """
     parser = OptionParser(usage="Usage: %prog [options]",
                           conflict_handler='error')
-    parser.add_option("-m", "--mantidpath", dest="mantidpath",
-                      help="Location of mantid package. Has no effect if run inside MantidPlot")
     parser.add_option("-R", "--tests-regex", dest="testinclude",
                       help="Regex specifying which tests to run. It is matched against the "
                       "filename when considering whether to run a test.")
@@ -110,13 +109,10 @@ def parseargs(arglist):
 
 #-----------------------------------------------------------------------------------------------
 
-def update_path(mantidpath):
+def update_path():
     """
     If not inside MantidPlot (current check is whether we can import _qti)
     then insert given path as first directory in sys.path
-
-    Args:
-      mantidpath (str): A string giving the location of the mantid module
     """
     try:
         import _qti
@@ -124,10 +120,21 @@ def update_path(mantidpath):
     except ImportError:
         gui = False
 
+
     # If it's MantidPlot then we already know what our paths should be so ignore it
     if gui:
         return
 
+    # the python wrapper sets this environment variable
+    mantidpath = os.environ.get('MANTIDPATH', None)
+
+    # otherwise try to expand based off of information in cmake
+    if mantidpath is None or len(mantidpath) == 0:
+        mantidpath = BUILD_DIR
+        if os.path.split(mantidpath)[-1] != 'bin' and \
+           os.path.isdir(os.path.join(mantidpath, 'bin')):
+            mantidpath = os.path.join(mantidpath, 'bin')
+
     # check for directory
     if not os.path.isdir(os.path.join(mantidpath, "mantid")):
         raise ValueError("Unable to find mantid package in '%s'" % mantidpath)
@@ -159,7 +166,7 @@ def find_test_files(src_dir, name_re):
     for dirpath, dirnames, filenames in os.walk(src_dir):
         testfiles = find_matching_tests(filenames, name_re_comp)
         # Join each filename with the current path and extend the list
-        testpaths.extend(map(lambda x: os.path.join(dirpath, x), testfiles))
+        testpaths.extend([os.path.join(dirpath, x) for x in testfiles])
 
     return testpaths
 
diff --git a/docs/source/algorithms/BinWidthAtX-v1.rst b/docs/source/algorithms/BinWidthAtX-v1.rst
new file mode 100644
index 0000000000000000000000000000000000000000..f7753cee2003a3fb03753be3e627c45a9abb420f
--- /dev/null
+++ b/docs/source/algorithms/BinWidthAtX-v1.rst
@@ -0,0 +1,68 @@
+.. algorithm::
+
+.. summary::
+
+.. alias::
+
+.. properties::
+  
+Description
+-----------
+  
+This algorithm takes the bin width at *X* of each histogram in *InputWorkspace* and calculates the average. This value is then placed in the *BinWidth* output property.
+
+Rounding
+########
+
+If the *Rounding* property is set to **10^n**, the bin width will be rounded down to the nearest power of 10. For example, 0.11 and 0.99 will be rounded to 0.1, while 0.011 and 0.099 will be rounded to 0.01.
+
+Restrictions on properties
+################################
+
+The *InputWorkspace* has to contain histogram data. For point data, :ref:`algm-ConvertToHistogram` can be used first, but care should be taken if the points are not equally spaced.
+
+Usage
+-----
+  
+**Example: rebin a workspace to equidistant bin boundaries.**
+
+.. testcode:: ExBinWidthAtX
+
+    import numpy
+    
+    # Create non-equidistant bin boundaries.
+    xs = [x * x for x in  numpy.arange(0.0, 10.0, 0.05)]
+    # Convert xs to numpy array.
+    xs = numpy.array(xs)
+    # There is one less bin than the number of boundaries.
+    ys = numpy.zeros(len(xs) - 1)
+    ws = CreateWorkspace(DataX=xs, DataY=ys)
+    
+    newWidth = BinWidthAtX(InputWorkspace=ws, X=1.0, Rounding='10^n')
+    print('New bin width: {0}'.format(newWidth))
+    
+    # Rebin to equidistant grid
+    rebinned = Rebin(InputWorkspace=ws, Params=[newWidth], FullBinsOnly=True)
+    
+    def firstAndLastBinWidths(workspace):
+        first = workspace.readX(0)[1] - workspace.readX(0)[0]
+        last = workspace.readX(0)[-1] - workspace.readX(0)[-2]
+        return (first, last)
+    
+    first, last = firstAndLastBinWidths(ws)
+    print('Bin widths before rebinning, first: {0}, last: {1}'.format(first, last))
+    first, last = firstAndLastBinWidths(rebinned)
+    print('Bin widths after rebinning, first: {0}, last: {1}'.format(first, last))
+
+
+Output:
+
+.. testoutput:: ExBinWidthAtX
+
+    New bin width: 0.01
+    Bin widths before rebinning, first: 0.0025, last: 0.9925
+    Bin widths after rebinning, first: 0.01, last: 0.01
+
+.. categories::
+
+.. sourcelink::
diff --git a/docs/source/algorithms/CalculateCostFunction-v1.rst b/docs/source/algorithms/CalculateCostFunction-v1.rst
new file mode 100644
index 0000000000000000000000000000000000000000..f39c80d5a0d0f21ba7015e31f565e4a8f9ffaef3
--- /dev/null
+++ b/docs/source/algorithms/CalculateCostFunction-v1.rst
@@ -0,0 +1,52 @@
+
+.. algorithm::
+
+.. summary::
+
+.. alias::
+
+.. properties::
+
+Description
+-----------
+
+Calculates a value of any available cost function. Returns the calculated value in the `Value` property. The input properties have the same meaning
+and behaviour as in :ref:`algm-Fit`.
+
+Usage
+-----
+**Example**
+
+.. testcode:: CalculateCostFunctionExample
+
+    import numpy as np
+
+    # Create a data set
+    x = np.linspace(0,1,10)
+    y = 1.0 + 2.0 * x
+    e = np.sqrt(y)
+    ws = CreateWorkspace(DataX=x, DataY=y, DataE=e)
+
+    # Define a function
+    func = 'name=LinearBackground,A0=1.1,A1=1.9'
+
+    # Calculate the chi squared by default
+    value = CalculateCostFunction(func, ws)
+    print 'Value of least squares is %s' % value
+
+    # Calculate the unweighted least squares
+    value = CalculateCostFunction(func, ws, CostFunction='Unweighted least squares')
+    print 'Value of unweighted least squares is %s' % value
+
+
+Output:
+
+.. testoutput:: CalculateCostFunctionExample
+
+    Value of least squares is 0.0133014391988
+    Value of unweighted least squares is 0.0175925925926
+
+
+.. categories::
+
+.. sourcelink::
diff --git a/docs/source/algorithms/CalculateFlatBackground-v1.rst b/docs/source/algorithms/CalculateFlatBackground-v1.rst
index e68b2af910c148bd20f624a543c066a50bb3b6ae..a947c75fa0e0f36a7a2cb0037fbe324920877fed 100644
--- a/docs/source/algorithms/CalculateFlatBackground-v1.rst
+++ b/docs/source/algorithms/CalculateFlatBackground-v1.rst
@@ -9,28 +9,19 @@
 Description
 -----------
 
-This algorithm takes a list of spectra and for each spectrum 
-calculates an average count rate in a region, usually a region when 
-there are only background neutrons. This count rate is then 
-subtracted from the counts in all the spectrum's bins. However, no 
-bin will take a negative value as bins with count rates less than 
-the background are set to zero (and their error is set to the 
-backgound value).
-
-The average background count rate is estimated in one of three ways. 
-When *Mode* is set to "Mean" it is the sum of the values in the bins 
-in the background region divided by the width of the X range. 
-Selecting "Linear Fit" sets the background value to the height in 
-the centre of the background region of a line of best fit through 
-that region. The "Averaging Window" *Mode* in turn calculates a 
-moving window average over each spectrum and takes the minimum as 
-the background. The values of the bins half-*AveragingWindowWidth* 
-from the beginning and end of a spectrum are taken as-is.
-
-The error on the background value is only calculated when "Mean" is
-used. It is the errors in all the bins in the background region summed
-in quadrature divided by the number of bins. This background error value
-is added in quadrature to the errors in each bin.
+This algorithm calculates the backgrounds for the histograms in a workspace. The backgrounds can be returned as-is, or directly subtracted from the input workspace depending on *OutputMode*.
+
+There are three modes of operation: **Linear Fit** fits a line to the range specified by *StartX* and *EndX* and uses the mid-point as the background. **Mean** calculates the mean in same range. Finally, **Moving Average** calculates a rolling average with cyclic boundary conditions over the histograms of the input workspace. Width of the averaging window can be specified by *AveragingWindowWidth*.
+
+The error of the background is only calculated when **Mean** or **Moving Average** is used. It is the errors in all the bins in the background region or averaging window, summed in quadrature and divided by the number of bins. This background error value is added in quadrature to the errors in each bin of the input workspace if **Subtract Background** is specified, otherwise returned in the background workspace.
+
+If *NullifyNegativeValues* is true, the background is set to the corresponding y value for the bins/points which would become negative when the background is subtracted. In these cases, the errors are set to either the background value or to the original error, whichever is greater.
+
+.. note::
+   Generally, using **Subtract Background** directly or subtracting the returned background manually later produces the same end result. This is not true, however, for the errors if *NullifyNegativeValues* is set. In this case **Subtract Background** will set the errors for the otherwise negative y values either to the background value or to the original error, whereas manual subtraction will add the background errors to the original ones in quadrature.
+
+.. note::
+   Care should be taken when subtracting the returned background from other workspaces than the input workspace if *NullifyNegativeValues* is set. For backgrounds corresponding to the y value which would be zeroed, this algorithm returns the original y values instead of the actual background.
 
 Usage
 -----
@@ -75,13 +66,20 @@ Output:
                                     Mode='Mean',
                                     OutputMode='Return Background')
 
+   # Note how some bins in the output workspace will be different from
+   # 3 (even negative!). By default, NullifyNegativeValues will be set
+   # to true, and subtracting the output from the input workspace will
+   # set these bins to zero.
    print 'Calculated Mean background:', np.around(output.readY(0))
+   subtracted = input - output
+   print 'Background subtracted:', np.around(subtracted.readY(0))
 
 Output:
 
 .. testoutput:: ExReturnMean
 
-   Calculated Mean background: [ 3.  3.  3.  3.  3.]
+   Calculated Mean background: [ 3.  3.  2.  3. -3.]
+   Background subtracted: [ 0.  1.  0.  0.  0.]
 
 **Example - Returning background using Moving Average (using a histogram):**
 
diff --git a/docs/source/algorithms/CollectHB3AExperimentInfo-v1.rst b/docs/source/algorithms/CollectHB3AExperimentInfo-v1.rst
index 8f3a05d7d27ee3d617f330b55f951ce88d0f9d74..eb89bb31aec3a30e2a014477692817967ed9a0d7 100644
--- a/docs/source/algorithms/CollectHB3AExperimentInfo-v1.rst
+++ b/docs/source/algorithms/CollectHB3AExperimentInfo-v1.rst
@@ -82,7 +82,7 @@ Output:
 
   Number of input files = 2
   Number of detectors in virtual instrument = 131072
-  Virtual detectors are from ID = 1 to ID = 131072
+  Virtual detectors are from ID = 0 to ID = 131070
 
 .. categories::
 
diff --git a/docs/source/algorithms/ComputeCalibrationCoefVan-v1.rst b/docs/source/algorithms/ComputeCalibrationCoefVan-v1.rst
index 799c1857fd20c4ceb21f6582fef5fe4d7012c57a..8af14998fd110f2a94e89ca63e207522f37ca235 100644
--- a/docs/source/algorithms/ComputeCalibrationCoefVan-v1.rst
+++ b/docs/source/algorithms/ComputeCalibrationCoefVan-v1.rst
@@ -21,11 +21,11 @@ Algorithm creates a workspace with  detector sensitivity correction coefficients
 
    :math:`J(y) = \int_0^1 x\cdot\mathrm{coth}\left(\frac{x}{2y}\right)\,\mathrm{d}x`
 
-   where :math:`y=T/T_m` is the ratio of the temperature during the experiment :math:`T` to the Debye temperature :math:`T_m = 389K`, :math:`m_V` is the Vanadium atomic mass (in kg) and :math:`\theta_i` is the polar angle of the i-th detector.
+   where :math:`y=T/T_m` is the ratio of the temperature during the experiment :math:`T` to the Debye temperature :math:`T_m = 389K`, :math:`m_V` is the Vanadium atomic mass (in kg) and :math:`\theta_i` is the polar angle of the i-th detector. By default, the temperature is read from the 'temperature' entry in the sample logs. If the entry is missing, or incorrect, the *Temperature* input property can be used instead.
 
 .. warning::
 
-    If sample log *temperature* is not present in the given Vanadium workspace or temperature is set to an invalid value, T=293K will be taken for the Debye-Waller factor calculation. Algorithm will produce warning in this case.
+    If the input *Temperature* is not specified or the sample log 'temperature' is not present in the given Vanadium workspace, or is set to an invalid value, T=293K will be taken for the Debye-Waller factor calculation. The algorithm will produce a warning in this case.
 
 2. Load the peak centre and sigma from the *EPPTable*. These values are used to calculate sum :math:`S_i` as
 
diff --git a/docs/source/algorithms/ConvertCWSDExpToMomentum-v1.rst b/docs/source/algorithms/ConvertCWSDExpToMomentum-v1.rst
index e3733cb4093c4169d19fd45d8bd4494479805a12..319715c4f232bc17fa8536e8c146b430311c2124 100644
--- a/docs/source/algorithms/ConvertCWSDExpToMomentum-v1.rst
+++ b/docs/source/algorithms/ConvertCWSDExpToMomentum-v1.rst
@@ -190,7 +190,7 @@ Output:
 
   Output MDEventWorkspace has 397 events.
   There are 1 peaks found in output MDWorkspace
-  In Q-sample frame, center of peak 0 is at (-6.93624, -0.08360, 8.16733) at detector with ID 35724
+  In Q-sample frame, center of peak 0 is at (-6.93624, -0.08360, 8.16733) at detector with ID 35723
 
 **Example - convert an HB3A experiment to MDEventWorkspace by copying instrument.:**
 
@@ -234,7 +234,7 @@ Output:
 
   Output MDEventWorkspace has 397 events.
   There are 1 peaks found in output MDWorkspace
-  In Q-sample frame, center of peak 0 is at (-3.58246, -4.40803, -3.06320) at detector with ID 29057
+  In Q-sample frame, center of peak 0 is at (-3.58246, -4.40802, -3.06320) at detector with ID 32881
 
 .. categories::
 
diff --git a/docs/source/algorithms/ConvertCWSDMDtoHKL-v1.rst b/docs/source/algorithms/ConvertCWSDMDtoHKL-v1.rst
index 219f648c8b5f9c388fa5ba5e4701471bcece86fc..68f44b314a3617cd0899c5a6a354270e5b45741d 100644
--- a/docs/source/algorithms/ConvertCWSDMDtoHKL-v1.rst
+++ b/docs/source/algorithms/ConvertCWSDMDtoHKL-v1.rst
@@ -9,7 +9,7 @@
 Description
 -----------
 
-This algorithms is to convert an MDEventWorkspace in Q-sample coordinate 
+This algorithms is to convert an MDEventWorkspace in Q-sample coordinate
 to HKL coordindate for a reactor-based four-circle single crystal diffractometer.
 Meanwhile, the algorithm is able to export the MDEvents to file.
 
@@ -26,20 +26,20 @@ Inputs
 
 **InputWorkspace** is an MDEventWorkspace ???.
 
-**PeakWorkspace** is an optional input as in many cases especially after calculating UB matrix, ... 
+**PeakWorkspace** is an optional input as in many cases especially after calculating UB matrix, ...
 
-**UBMatrix** is ???. 
+**UBMatrix** is ???.
 
 
 Outputs
 #######
 
-The output is an MDEventWorkspace that... .. 
+The output is an MDEventWorkspace that... ..
 
 MDEvent
 +++++++
 
-Each MDEvent in output MDEventWorkspace contain 
+Each MDEvent in output MDEventWorkspace contain
 * *H*
 * *K*
 * *L*
@@ -61,29 +61,31 @@ Usage
 .. testcode:: ExConvertHB3AToHKL
 
   # Create input table workspaces for experiment information and virtual instrument parameters
-  CollectHB3AExperimentInfo(ExperimentNumber='406', ScanList='298', PtLists='-1,22', 
+  CollectHB3AExperimentInfo(ExperimentNumber='406', ScanList='298', PtLists='-1,22',
       DataDirectory='',
       GenerateVirtualInstrument=False,
       OutputWorkspace='ExpInfoTable', DetectorTableWorkspace='VirtualInstrumentTable')
 
   # Convert to MDWorkspace
-  ConvertCWSDExpToMomentum(InputWorkspace='ExpInfoTable', CreateVirtualInstrument=False, 
+  ConvertCWSDExpToMomentum(InputWorkspace='ExpInfoTable', CreateVirtualInstrument=False,
       OutputWorkspace='QSampleMD',
       Directory='')
-      
-  ConvertCWSDMDtoHKL(InputWorkspace='QSampleMD', 
+
+  ConvertCWSDMDtoHKL(InputWorkspace='QSampleMD',
                 UBMatrix='0.13329061, 0.07152342, -0.04215966, 0.01084569, -0.1620849, 0.0007607, -0.14018499, -0.07841385, -0.04002737',
                 OutputWorkspace='HKLMD')
-              
-  
+
+
   # Examine
   mdws = mtd['QSampleMD']
-  print 'Output MDEventWorkspace has %d events.'%(mdws.getNEvents())
-  
   hklws = mtd['HKLMD']
-  print 'H: range from %.5f to %.5f.' % (hklws.getXDimension().getMinimum(), hklws.getXDimension().getMaximum())
-  print 'K: range from %.5f to %.5f.' % (hklws.getYDimension().getMinimum(), hklws.getYDimension().getMaximum())
-  print 'L: range from %.5f to %.5f.' % (hklws.getZDimension().getMinimum(), hklws.getZDimension().getMaximum())
+  print 'Output QSample and HKL workspaces have %d and %d events.'%(mdws.getNEvents(), hklws.getNEvents())
+
+  BinMD(InputWorkspace='HKLMD', AlignedDim0='H,-0.3,0.3,60', AlignedDim1='K,-0.4,0.5,90', AlignedDim2='L,4,8,10', OutputWorkspace='BinndHKL')
+  histws = mtd['BinndHKL']
+  events_array = histws.getNumEventsArray()
+  print 'events[22, 53, 5] = %.1f' % events_array[22, 53, 5]
+  print 'events[30, 40, 5] = %.1f' % events_array[30, 40, 5]
 
 .. testcleanup::  ExConvertHB3AToHKL
 
@@ -94,14 +96,14 @@ Usage
   DeleteWorkspace(Workspace='HB3A_exp0406_scan0298')
   DeleteWorkspace(Workspace='spicematrixws')
 
+
 Output:
 
 .. testoutput:: ExConvertHB3AToHKL
 
-  Output MDEventWorkspace has 1631 events.
-  H: range from -0.26128 to 0.24943.
-  K: range from -0.35012 to 0.44396.
-  L: range from 4.96512 to 7.18855.
+  Output QSample and HKL workspaces have 1631 and 1631 events.
+  events[22, 53, 5] = 19.0
+  events[30, 40, 5] = 38.0
 
 .. categories::
 
diff --git a/docs/source/algorithms/ConvertToReflectometryQ-v1.rst b/docs/source/algorithms/ConvertToReflectometryQ-v1.rst
index d48cd5ece32a4574c4ece4424e645f36729fe22a..27d2ea2fc633bc7c123a44598fa5df6dd8084381 100644
--- a/docs/source/algorithms/ConvertToReflectometryQ-v1.rst
+++ b/docs/source/algorithms/ConvertToReflectometryQ-v1.rst
@@ -117,9 +117,9 @@ Normalised Polygon Transformation
     
     pipf, vertexes_pipf = ConvertToReflectometryQ(InputWorkspace='SignedTheta_vs_Wavelength', OutputDimensions='P (lab frame)', Extents='0,0.1,-0.02,0.15', OutputAsMDWorkspace=False,Method='NormalisedPolygon')
 
-    print qxqy.getDimension(0).getName(), qxqy.getDimension(1).getName()
-    print kikf.getDimension(0).getName(), kikf.getDimension(1).getName()
-    print pipf.getDimension(0).getName(), pipf.getDimension(1).getName()
+    print qxqy.getDimension(0).name, qxqy.getDimension(1).name
+    print kikf.getDimension(0).name, kikf.getDimension(1).name
+    print pipf.getDimension(0).name, pipf.getDimension(1).name
 
 
 Output:
diff --git a/docs/source/algorithms/ConvolutionFitSequential-v1.rst b/docs/source/algorithms/ConvolutionFitSequential-v1.rst
index 615c0e177f848ee0e63ad5ee31ef4b5d55361c8a..651ccd5b2b70d4c9588fb09298d58ecdd8e45233 100644
--- a/docs/source/algorithms/ConvolutionFitSequential-v1.rst
+++ b/docs/source/algorithms/ConvolutionFitSequential-v1.rst
@@ -43,9 +43,9 @@ Usage
   maxIt = 500
   
   # Build resolution workspace (normally done by the Convfit tab when files load)
-  AppendSpectra(InputWorkspace1=resolution.getName(), InputWorkspace2=resolution.getName(), OutputWorkspace="__ConvFit_Resolution")
+  AppendSpectra(InputWorkspace1=resolution.name(), InputWorkspace2=resolution.name(), OutputWorkspace="__ConvFit_Resolution")
   for i in range(1, sample.getNumberHistograms()):
-    AppendSpectra(InputWorkspace1="__ConvFit_Resolution", InputWorkspace2=resolution.getName(), OutputWorkspace="__ConvFit_Resolution")  
+    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)
@@ -71,7 +71,7 @@ Output:
   
   Result has 2 Spectra
   
-  Amplitude 0: 4.293
+  Amplitude 0: 4.314
   Amplitude 1: 4.179
   Amplitude 2: 3.979
 
@@ -79,7 +79,7 @@ Output:
   X axis at 1: 0.72917
   X axis at 2: 0.92340
 
-  Amplitude Err 0: 0.00465
+  Amplitude Err 0: 0.00460
   Amplitude Err 1: 0.00464
   Amplitude Err 2: 0.00504
 
diff --git a/docs/source/algorithms/CorrectFlightPaths-v1.rst b/docs/source/algorithms/CorrectFlightPaths-v1.rst
deleted file mode 100644
index f323c8563489302591d355e4426ce24498a81ae7..0000000000000000000000000000000000000000
--- a/docs/source/algorithms/CorrectFlightPaths-v1.rst
+++ /dev/null
@@ -1,32 +0,0 @@
-.. algorithm::
-
-.. summary::
-
-.. alias::
-
-.. properties::
-
-Description
------------
-
-.. warning::
-
-   This algorithm will be deprecated in the next version of Mantid. Please, use :ref:`algm-ConvertToConstantL2` instead, which
-   is the new name for this algorithm.
-
-Moves the instrument and then corrects the flight paths such that a flat detector appears spherical with a constant l2 value.
-
-Both time-of-flight sample-detector time and sample to detector distance are corrected to constant values.
-
-The sample to detector distance must be specified as **l2** in the instrument parameters file.
-
-So far this has only be tested on the ILL IN5 instrument.
-
-Note
-###################################
-This algorithm is intended for visualisaion only. It is not recommended as part of any reduction process.
-
-
-.. categories::
-
-.. sourcelink::
diff --git a/docs/source/algorithms/CorrectTOFAxis-v1.rst b/docs/source/algorithms/CorrectTOFAxis-v1.rst
new file mode 100644
index 0000000000000000000000000000000000000000..1f67743382dd889950f736459d300b6768633359
--- /dev/null
+++ b/docs/source/algorithms/CorrectTOFAxis-v1.rst
@@ -0,0 +1,230 @@
+
+.. algorithm::
+
+.. summary::
+
+.. alias::
+
+.. properties::
+
+Description
+-----------
+
+This algorithm is meant to adjust the time-of-flight axis so that the elastic peak is at zero energy transfer after unit conversion from 'TOF' to 'DeltaE'. The algorithm has two modes: either it uses a given *ReferenceWorkspace*, or it calculates a constant time-of-flight shift using the L1 + L2 distances of the *InputWorkspace* and incident energy.
+
+Using a reference workspace
+###########################
+
+If *ReferenceWorkspace* is set, this algorithm copies the X axis as well as the 'Ei' and 'wavelength' sample logs, if present, to *OutputWorkspace*. The rest of the input properties are discarded.
+
+Calculating new TOF axis
+########################
+
+If no *ReferenceWorkspace* is given, the algorithm takes the L1 distance :math:`l_1` from the instrument attached to *InputWorkspace* and calculates the average L2 distance :math:`l_2` using the histograms specified by *ReferenceSpectra*. The algorithm also needs to know the TOF :math:`t_{elastic}` corresponding to the zero-energy transfer. This is either taken from the first spectrum in *InputWorkspace* as the bin centre of the bin specified by *ElasticBinIndex*, or calculated from the elastic peak positions given in *EPPTable*. *EPPTable* should be in the format returned by the :ref:`algm-FindEPP` algorithm. In this case the algorithm averages the `PeakCentre` column for histograms listed in *ReferenceSpectra*. Finally, the algorithm needs the incident energy :math:`E_i` which can be either specified by *EFixed* or is taken from the sample logs of *InputWorkspace*. In case *EFixed* is specified, the 'Ei' and 'wavelength' sample logs of *OutputWorkspace* are updated accordingly.
+
+The TOF shift :math:`\Delta t` is calculated by
+
+    :math:`\Delta t = t_{elastic} - (l_1 + l_2) / \sqrt{2 E_i / m_n}`,
+
+where :math:`m_n` is the neutron mass. The shift :math:`\Delta t` is then added to all X values of *OutputWorkspace*.
+
+The algorithm assumes micro seconds as units of time and meV as units of energy.
+
+Whether the *ReferenceSpectra* input property refers to workspace indices, spectrum numbers or detector IDs is specified by *IndexType*. 
+
+Usage
+-----
+
+**Example - CorrectTOFAxis by specifying the elatic bin**
+
+.. testcode:: ExElasticBin
+
+    import numpy
+    from scipy import constants
+    
+    L1 = 2.0 # in metres.
+    L2 = 2.0
+    Ei = 55.0 # in meV
+    v = numpy.sqrt(2 * Ei * 1e-3 * constants.e / constants.m_n)
+    elasticTOF = (L1 + L2) / v * 1e6 # in micro seconds.
+    
+    # Make a workspace with wrong TOF axis.
+    TOFMin = 0.0
+    TOFMax = 100.0
+    binWidth = 0.5
+    # Lets say the elastic bin is in the centre of the spectrum.
+    elasticBinIndex = int(((TOFMax - TOFMin) / binWidth) / 2.0)
+    # Build a Gaussian elastic peak in the workspace.
+    peakCentre = TOFMin + elasticBinIndex * binWidth
+    spectrumDescription = '''name=Gaussian, PeakCentre={0},
+    Height=100, Sigma={1}'''.format(peakCentre, 0.03 * peakCentre)
+    ws = CreateSampleWorkspace(WorkspaceType='Histogram',
+        NumBanks=1,
+        BankPixelWidth=1,
+        Function='User Defined',
+        UserDefinedFunction=spectrumDescription,
+        BankDistanceFromSample=L2,
+        SourceDistanceFromSample=L1,
+        XMin=TOFMin,
+        XMax=TOFMax,
+        BinWidth=binWidth)
+    
+    # Do the correction.
+    correctedWs = CorrectTOFAxis(ws,
+        IndexType='Workspace Index',
+        ReferenceSpectra='0',
+        ElasticBinIndex=elasticBinIndex,
+        EFixed=Ei)
+    
+    # Convert TOF to energy transfer.
+    convertedWs = ConvertUnits(correctedWs,
+        Target='DeltaE',
+        EMode='Direct')
+    
+    # Check results
+    # Zero energy transfer should be around elasticBinIndex.
+    for index in range(elasticBinIndex-1, elasticBinIndex+2):
+        binCentre = (convertedWs.readX(0)[index+1] + convertedWs.readX(0)[index]) / 2
+        print('DeltaE at bin centre {0}: {1:0.4f}'.format(index,binCentre))
+
+Output:
+
+.. testoutput:: ExElasticBin
+
+    DeltaE at bin centre 99: -0.0893
+    DeltaE at bin centre 100: -0.0000
+    DeltaE at bin centre 101: 0.0891
+
+**Example - CorrectTOFAxis using EPP table**
+
+.. testcode:: ExEPPTable
+
+    import numpy
+    from scipy import constants
+    
+    L1 = 2.0 # in metres
+    L2 = 2.0
+    Ei = 55.0 # in meV
+    velocity = numpy.sqrt(2 * Ei * 1e-3 * constants.e / constants.m_n)
+    elasticTOF = (L1 + L2) / velocity * 1e6 # in micro seconds.
+    
+    # Make a workspace with wrong TOF axis.
+    TOFMin = 0.0
+    TOFMax = 100.0
+    # Build a Gaussian elastic peak in the workspace.
+    peakCentre = TOFMin + 2.0 * (TOFMax - TOFMin) / 3.0
+    spectrumDescription = '''name=Gaussian, PeakCentre={0},
+    Height=100, Sigma={1}'''.format(peakCentre, 0.03 * peakCentre)
+    ws = CreateSampleWorkspace(WorkspaceType='Histogram',
+           NumBanks=1,
+           BankPixelWidth=1,
+           Function='User Defined',
+           UserDefinedFunction=spectrumDescription,
+           BankDistanceFromSample=L2,
+           SourceDistanceFromSample=L1,
+           XMin=TOFMin,
+           XMax=TOFMax,
+           BinWidth=0.5)
+    
+    # Prepare for the correction.
+    EPPTable = FindEPP(ws)
+    
+    # Do the correction.
+    correctedWs = CorrectTOFAxis(ws,
+        EPPTable=EPPTable,
+        IndexType='Workspace Index',
+        ReferenceSpectra='0',
+        EFixed=Ei)
+    
+    # Check results.
+    print('Original TOF for the elastic peak: {0:0.1f}'.format(
+        ws.readX(0)[numpy.argmax(ws.readY(0))]))
+    print('Corrected TOF for the elastic peak: {0:0.1f}'.format(
+        correctedWs.readX(0)[numpy.argmax(correctedWs.readY(0))]))
+    print('Actual elastic TOF: {0:0.1f}'.format(elasticTOF))
+
+Output:
+
+.. testoutput:: ExEPPTable
+
+    Original TOF for the elastic peak: 66.5
+    Corrected TOF for the elastic peak: 1232.7
+    Actual elastic TOF: 1233.1
+
+**Example - CorrectTOFAxis using a reference workspace**
+
+.. testcode:: ExReferenceWS
+
+    import numpy
+    from scipy import constants
+    
+    L1 = 2.0
+    L2 = 2.0
+    Ei = 55.0 # in meV
+    v = numpy.sqrt(2 * Ei * 1e-3 * constants.e / constants.m_n)
+    elasticTOF = (L1 + L2) / v * 1e6 # in micro seconds.
+    
+    # Make two workspaces with wrong TOF axis.
+    TOFMin = 0.0
+    TOFMax = 100.0
+    peakCentre = TOFMin + 2.0 * (TOFMax - TOFMin) / 3.0
+    # Build a Gaussian elastic peak in the first workspace.
+    spectrumDescription = '''name=Gaussian, PeakCentre={0},
+    Height=100, Sigma={1}'''.format(peakCentre, 0.03 * peakCentre)
+    ws1 = CreateSampleWorkspace(WorkspaceType='Histogram',
+        NumBanks=1,
+        BankPixelWidth=1,
+        Function='User Defined',
+        UserDefinedFunction=spectrumDescription,
+        BankDistanceFromSample=L2,
+        SourceDistanceFromSample=L1,
+        XMin=TOFMin,
+        XMax=TOFMax,
+        BinWidth=0.5)
+    # Build a second workspace with slightly different Gaussian.
+    spectrumDescription = '''name=Gaussian, PeakCentre={0},
+    Height=100, Sigma={1}'''.format(peakCentre, 0.06 * peakCentre)
+    ws2 = CreateSampleWorkspace(WorkspaceType='Histogram',
+    NumBanks=1,
+    BankPixelWidth=1,
+    Function='User Defined',
+    UserDefinedFunction=spectrumDescription,
+    BankDistanceFromSample=L2,
+    SourceDistanceFromSample=L1,
+    XMin=TOFMin,
+    XMax=TOFMax,
+    BinWidth=0.5)
+    
+    # Correct the first workspace using the EPP table method.
+    EPPTable = FindEPP(ws1)
+    
+    # Do the correction.
+    correctedWs1 = CorrectTOFAxis(ws1,
+        EPPTable=EPPTable,
+        IndexType='Workspace Index',
+        ReferenceSpectra='0',
+        EFixed=Ei)
+    
+    # Correct the second workspace by using the first as a reference.
+    correctedWs2 = CorrectTOFAxis(ws2,
+        ReferenceWorkspace=correctedWs1)
+    
+    # Check results
+    print('First workspace original TOF for the elastic peak: {0:0.1f}'.format(
+        ws1.readX(0)[numpy.argmax(ws1.readY(0))]))
+    print('EPP table corrected TOF for the elastic peak: {0:0.1f}'.format(
+        correctedWs1.readX(0)[numpy.argmax(correctedWs1.readY(0))]))
+    print('Elastic TOF for the corrected second workspace: {0:0.1f}'.format(
+        correctedWs2.readX(0)[numpy.argmax(correctedWs2.readY(0))]))
+
+Output:
+
+.. testoutput:: ExReferenceWS
+
+    First workspace original TOF for the elastic peak: 66.5
+    EPP table corrected TOF for the elastic peak: 1232.7
+    Elastic TOF for the corrected second workspace: 1232.7
+
+.. categories::
+
+.. sourcelink::
diff --git a/docs/source/algorithms/CreateEmptyTableWorkspace-v1.rst b/docs/source/algorithms/CreateEmptyTableWorkspace-v1.rst
index aaf525aff073392a766a70ce5bd21f23fcdbfc4f..6191c24c98fc72d21a3c32c54979e0ad3cdf3d82 100644
--- a/docs/source/algorithms/CreateEmptyTableWorkspace-v1.rst
+++ b/docs/source/algorithms/CreateEmptyTableWorkspace-v1.rst
@@ -38,7 +38,7 @@ Usage
    print "The run number for IRIS is " + str(my_table.cell("Run Number", 1)) + "."
    print "The number of rows is " + str(my_table.rowCount()) + "."
    print "The title of the table is " + my_table.getTitle() + "."
-   print "Remember, the table is a workspace.  It's name is \"" + my_table.getName() + "\"."
+   print "Remember, the table is a workspace.  It's name is \"" + my_table.name() + "\"."
 
 Output:
 
diff --git a/docs/source/algorithms/CreateGroupingWorkspace-v1.rst b/docs/source/algorithms/CreateGroupingWorkspace-v1.rst
index afdebe3f470942d0d01e5705a31979a994609740..96c7607422e589c2c6e5e8a358fd8c38dd43a6e9 100644
--- a/docs/source/algorithms/CreateGroupingWorkspace-v1.rst
+++ b/docs/source/algorithms/CreateGroupingWorkspace-v1.rst
@@ -29,6 +29,10 @@ the detectors for the given component will be grouped into the number
 of groups specified, detectors will be left ungrouped in the event that
 the number of detectors does not divide equally into the number of groups.
 
+GroupDetectorsBy has a new option, 2_4Grouping, to create one group of 4 
+columns of SNAP detectors and another with the remaining 2 columns. This 
+grouping is used frequently in their reduction.
+
 Usage
 -----
 
diff --git a/docs/source/algorithms/CreateMDWorkspace-v1.rst b/docs/source/algorithms/CreateMDWorkspace-v1.rst
index 0efbbe826eda7e1a6e667b2e0234fcd4ed382663..c7e342fa340506424e041296870dca2ca0fd6da6 100644
--- a/docs/source/algorithms/CreateMDWorkspace-v1.rst
+++ b/docs/source/algorithms/CreateMDWorkspace-v1.rst
@@ -38,7 +38,7 @@ Usage
     print "mdws is a " + mdws.id()
     print "with {0} dimensions:".format(mdws.getNumDims())
     for i in range (mdws.getNumDims()):
-        print mdws.getDimension(i).getName()
+        print mdws.getDimension(i).name
 
 Output:
 
diff --git a/docs/source/algorithms/CrystalFieldEnergies-v1.rst b/docs/source/algorithms/CrystalFieldEnergies-v1.rst
index 602b9d050019e279863e68f45908a67979ced10e..d72c6ca1fc3baf713bdc040a6348f6b851c5d442 100644
--- a/docs/source/algorithms/CrystalFieldEnergies-v1.rst
+++ b/docs/source/algorithms/CrystalFieldEnergies-v1.rst
@@ -46,18 +46,18 @@ The algorithm calculates the crystal field energies and wave functions. The exam
       [  3.38877312e-01+0.j  -2.36325596e-17+0.j   6.25169857e-01+0.j
          6.80756336e-01+0.j   1.95256823e-02+0.j   1.74683643e-01+0.j]]
      Hamiltonian:
-     [[  1.86648000-0.j   0.00000000-0.j   9.27182972-0.j   0.00000000-0.j
-        -3.36590841-0.j   0.00000000-0.j]
-      [  0.00000000+0.j   4.96692000-0.j   0.00000000-0.j  19.33604706-0.j
-         0.00000000-0.j  -3.36590841-0.j]
-      [  9.27182972+0.j   0.00000000+0.j  -6.83340000-0.j   0.00000000-0.j
-        19.33604706-0.j   0.00000000-0.j]
-      [  0.00000000+0.j  19.33604706+0.j   0.00000000+0.j  -6.83340000-0.j
-         0.00000000-0.j   9.27182972-0.j]
+     [[  1.86648000+0.j   0.00000000+0.j   9.27182972+0.j   0.00000000+0.j
+        -3.36590841+0.j   0.00000000+0.j]
+      [  0.00000000+0.j   4.96692000+0.j   0.00000000+0.j  19.33604706+0.j
+         0.00000000+0.j  -3.36590841+0.j]
+      [  9.27182972+0.j   0.00000000+0.j  -6.83340000+0.j   0.00000000+0.j
+        19.33604706+0.j   0.00000000+0.j]
+      [  0.00000000+0.j  19.33604706+0.j   0.00000000+0.j  -6.83340000+0.j
+         0.00000000+0.j   9.27182972+0.j]
       [ -3.36590841+0.j   0.00000000+0.j  19.33604706+0.j   0.00000000+0.j
-         4.96692000-0.j   0.00000000-0.j]
+         4.96692000+0.j   0.00000000+0.j]
       [  0.00000000+0.j  -3.36590841+0.j   0.00000000+0.j   9.27182972+0.j
-         0.00000000+0.j   1.86648000-0.j]]
+         0.00000000+0.j   1.86648000+0.j]]
       
 Please note that this area is under active development and any name can be changed in the future.
 
diff --git a/docs/source/algorithms/DiffractionFocussing-v2.rst b/docs/source/algorithms/DiffractionFocussing-v2.rst
index 99ef37d85d9885ba7e2201c8d19bb1524992d573..7b091cd19c81eb2339da24a6b2c8539bd6ef6490 100644
--- a/docs/source/algorithms/DiffractionFocussing-v2.rst
+++ b/docs/source/algorithms/DiffractionFocussing-v2.rst
@@ -15,10 +15,11 @@ following:
 
 #. The calibration file is read and a map of corresponding udet-group is
    created.
-#. The algorithm determine the X boundaries for each group as the upper
-   and lower limits of all contributing detectors to this group and
-   determine a logarithmic step that will ensure preserving the number
-   of bins in the initial workspace.
+#. The algorithm determines the X boundaries for each group as the upper
+   and lower limits of all contributing detectors. It then calculates
+   a logarithmic step that preserves the number of bins in the initial workspace. 
+   It assumes that the entire data set uses logarithmic binning in the process 
+   (i.e. it does not check for constant width binning).
 #. All histograms are read and rebinned to the new grid for their group.
 #. A new workspace with N histograms is created.
 
diff --git a/docs/source/algorithms/EnergyWindowScan-v1.rst b/docs/source/algorithms/EnergyWindowScan-v1.rst
new file mode 100644
index 0000000000000000000000000000000000000000..71f91e40b69d0c259fc8d92d59d314645c44edd2
--- /dev/null
+++ b/docs/source/algorithms/EnergyWindowScan-v1.rst
@@ -0,0 +1,35 @@
+.. algorithm::
+
+.. summary::
+
+.. alias::
+
+.. properties::
+
+Description
+-----------
+
+Performs a data reduction from :ref:`ISISIndirectEnergyTransfer <algm-ISISIndirectEnergyTransfer>`,
+before performing the :ref:`ElasticWindowMultiple <algm-ElasticWindowMultiple>` algorithm over the elastic
+and inelastic regions of the reduced data to calculate the elastic incoherent scattering factor. There
+is also an option to perform the :ref:`MSDFit <algm-MSDFit>` algorithm.
+
+
+Usage
+-----
+
+.. include:: ../usagedata-note.txt
+
+**Example - IRIS Energy Window Scan**
+
+.. code-block:: python
+
+    EnergyWindowScan(InputFiles="IRS21360.RAW", Instrument='IRIS', Analyser='graphite',
+                             Reflection='002', SpectraRange='3, 50', ElasticRange='-0.5, 0',
+                             InelasticRange='0, 0.5', GroupingMethod='Individual', MSDFit=True)
+
+.. categories::
+
+.. sourcelink::
+  :cpp: None
+  :h: None
diff --git a/docs/source/algorithms/EstimateFitParameters-v1.rst b/docs/source/algorithms/EstimateFitParameters-v1.rst
new file mode 100644
index 0000000000000000000000000000000000000000..0d5f6b186e1de93ece9831834810e6477c50ed2f
--- /dev/null
+++ b/docs/source/algorithms/EstimateFitParameters-v1.rst
@@ -0,0 +1,178 @@
+.. algorithm::
+
+.. summary::
+
+.. alias::
+
+.. properties::
+
+Description
+-----------
+
+This algorithm uses a Monte Carlo - type approach to estimate initial values of function parameters
+before passing the function to :ref:`algm-Fit` algorithm.
+The user needs to provide the search intervals for each parameters that requires estimation.
+These intervals are set by defining boundary constraints in the fitting function. For example::
+
+    name=UserFunction,Formula=a*x+b,a=0,b=0,constraints=(1<a<4, 0<b<4)
+  
+Here the algorithm will search intervals [1, 4] and [0, 4] for values of parameters `a` and `b` 
+respectively such that the cost function is the smallest.
+
+If a parameter will be fixed or tied in a fit don't include it in the `constraints`. For example::
+
+    name=UserFunction,Formula=a*x+b,a=0,ties=(b=1.9),constraints=(1<a<4)
+    name=UserFunction,Formula=a*x+b,a=0,ties=(b=a-1),constraints=(1<a<4)
+
+The algorithm uses one of the two strategies (set via `Type` property): "Monte Carlo" and "Cross Entropy".
+
+
+Monte Carlo
+###########
+
+In this strategy a number (defined by `NSamples` property) of paramter sets are generated and the one that
+gives the smallest cost function is considered the winner. These best parameters are set to `Function`
+property (it has the `InOut` direction).
+
+If `OutputWorkspace` property is set then more than 1 parameter set can be output. The output workspace is 
+a table workspace in which the first column contains the names of the parameters and the subsequent columns
+have the parameter sets with the smallest cost fnction values. Below is an example of such a workspace.
+
+.. figure:: /images/EstimateFitParameters_output.png
+
+
+Cross Entropy
+#############
+
+This strategy iteratively tries to narrow down the search space using statistics from a previous iteration.
+
+The steps of the algorithm:
+
+#. Generate a number (`NSamples`) of sets of function parameters normally distributed with given means and sigmas. Initially the distribution parameters are taken from the intervals passed in `constraints` of the fitting function: the means are the centres of the intervals and the sigmas are halves of their widths.
+#. Calculate the cost function for each set of parameters and select a number of the smallest values. This number is defined  by the `Selection` property.
+#. Find the sample means and sigmas of the parameters from the subset selected in step 2.
+#. Repeat steps 1 - 3 a few times (`NIterations`).
+#. Return parameters for the smallest cost function value found in the last iteration.
+
+
+Finding Bad Parameters
+######################
+
+It may happen that some of the parameters cannot be determined from the data set in the `InputWorkspace`. If this is the case :ref:`algm-Fit` may diverge
+or fail with an error. To try and find such parameters set `FixBadParameters` to `true`. 
+If the algorithm decides that some of the parameters may cause problems it will fix them.
+
+Usage
+-----
+
+**Example 1.**
+
+.. testcode:: ExMonteCarloBackToBackExponential
+
+    # Create a data set. It is a BackToBackExponential.
+    x = [-8.4, -7.4, -6.4, -5.4, -4.4, -3.4, -2.4, -1.4, -0.4, 0.6,  1.6,  2.6,  3.6,  4.6,  5.6,  6.6,  7.6,  8.5]
+    y = [5.899424685451e-06, 0.0007065291085075, 0.03312893859911,
+            0.6260554060356,    4.961949842664,     17.4766663495,
+            30.00494980772,     29.34773951093,     20.53693564978,
+            12.73990150587,     7.739398423952,     4.694362241084,
+            2.847186128946,     1.726807862958,     1.047276595461,
+            0.6351380161499,    0.3851804649058,    0.1957211887562]
+    ws = CreateWorkspace(x, y)
+    
+    # Define a function, constraints set the search intervals.
+    fun = 'name=BackToBackExponential,S=1.1,constraints=(50<I<200,0.1<A<300,0.01<B<10,-5<X0<0,0.001<S<4)'
+
+    # Set up the algorithm.
+    from mantid.api import AlgorithmManager
+    alg = AlgorithmManager.createUnmanaged('EstimateFitParameters')
+    alg.initialize()
+    alg.setProperty('Function', fun)
+    alg.setProperty('InputWorkspace', ws)
+    # Non-default cost function can be used.
+    alg.setProperty('CostFunction', 'Unweighted least squares')
+    # How many points to try.
+    alg.setProperty('NSamples', 1000)
+    # A seed for the random number generator. Only to make this test reproducible. 
+    alg.setProperty('Seed', 1234)
+    # Execute the algorithm.
+    alg.execute()
+    # Function now contains the estimated parameters.
+    function = alg.getProperty('Function').value
+    print(function)
+    # Evaluate the function with the returned parameters to see the quality of estimation.
+    EvaluateFunction(str(function),ws,OutputWorkspace='estimation')
+    # Run Fit starting with the new parameters.
+    Fit(str(function),ws,Output='fit')
+    
+.. figure:: /images/EstimateFitParameters_mcest.png
+.. figure:: /images/EstimateFitParameters_mcfit.png
+    
+Output:
+
+(You may see different numbers for the parameters when you run this example on your machine.)
+
+.. testoutput:: ExMonteCarloBackToBackExponential
+   :options: +ELLIPSIS, +NORMALIZE_WHITESPACE
+
+    name=BackToBackExponential,I=...,A=...,B=...,X0=...,S=...,constraints=(50<I<200,0.1<A<300,0.01<B<10,-5<X0<0,0.001<S<4)
+
+**Example 2.**
+
+.. testcode:: Ex2
+
+    # Create a data set. It is a Gaussian.
+    x = [-8.4, -7.4, -6.4, -5.4, -4.4, -3.4, -2.4, -1.4, -0.4, 0.6,  1.6,  2.6,  3.6,  4.6,  5.6,  6.6,  7.6,  8.5]
+    y = [2.18295779512548e-08, 1.13372713874796e-06, 3.57128496416351e-05,
+        0.000682328052756376, 0.00790705405159343, 0.0555762126114831,
+        0.236927758682122, 0.612626394184416, 0.960789439152323,
+        0.913931185271228, 0.527292424043049, 0.184519523992989,
+        0.0391638950989871, 0.00504176025969098, 0.000393669040655079,
+        1.86437423315169e-05, 5.35534780279311e-07, 1.43072419185677e-08]
+    ws = CreateWorkspace(x, y)
+    
+    # Define a function, constraints set the search intervals.
+    fun = 'name=BackToBackExponential,S=1.1,constraints=(0.01<I<200,0.001<A<300,0.001<B<300,-5<X0<5,0.001<S<4)'
+
+    # Set up the algorithm.
+    from mantid.api import AlgorithmManager
+    alg = AlgorithmManager.createUnmanaged('EstimateFitParameters')
+    alg.initialize()
+    alg.setProperty('Function', fun)
+    alg.setProperty('InputWorkspace', ws)
+    # Cross Entropy type.
+    alg.setProperty('Type', 'Cross Entropy')
+    # How many samples in each iteration.
+    alg.setProperty('NSamples', 100)
+    # How many samples to use to refine distributions.
+    alg.setProperty('Selection', 10)
+    # How many iterations to make.
+    alg.setProperty('NIterations', 10)
+    # Try to find bad parameters. A and B are expected to be bad.
+    alg.setProperty('FixBadParameters', True)
+    # A seed for the random number generator. Only to make this test reproducible.
+    alg.setProperty('Seed', 1234)
+    # Execute the algorithm.
+    alg.execute()
+    # Function now contains the estimated parameters.
+    function = alg.getProperty('Function').value
+    print(function)
+    # Evaluate the function with the returned parameters to see the quality of estimation.
+    EvaluateFunction(str(function),ws,OutputWorkspace='estimation')
+    # Run Fit starting with the new parameters.
+    Fit(str(function),ws,Output='fit')
+    
+.. figure:: /images/EstimateFitParameters_ceest.png
+.. figure:: /images/EstimateFitParameters_cefit.png
+
+Output:
+
+(You may see different numbers for the parameters when you run this example on your machine.)
+
+.. testoutput:: Ex2
+    :options: +ELLIPSIS, +NORMALIZE_WHITESPACE
+
+    name=BackToBackExponential,I=...,X0=...,S=...,constraints=(0.01<I<200,0.001<A<300,0.001<B<300,-5<X0<5,0.001<S<4),ties=(A=...,B=...)
+    
+.. categories::
+
+.. sourcelink::
diff --git a/docs/source/algorithms/EvaluateMDFunction-v1.rst b/docs/source/algorithms/EvaluateMDFunction-v1.rst
index 9461445e1f602fd8c1d107e06885324ee67b2da9..56b5bd917617d5a36fce6b15b12acd31af4db6a1 100644
--- a/docs/source/algorithms/EvaluateMDFunction-v1.rst
+++ b/docs/source/algorithms/EvaluateMDFunction-v1.rst
@@ -38,9 +38,9 @@ Usage
 
     # Check the result workspace
     print out.getNumDims()
-    print out.getXDimension().getName()
-    print out.getYDimension().getName()
-    print out.getZDimension().getName()
+    print out.getXDimension().name
+    print out.getYDimension().name
+    print out.getZDimension().name
     
     
 Output
diff --git a/docs/source/algorithms/Fit-v1.rst b/docs/source/algorithms/Fit-v1.rst
index 9267c4e1abbb5a76826f75f11081c9c2203eba52..5123ff717e4c9dd1720cd191fadae22886ea87d7 100644
--- a/docs/source/algorithms/Fit-v1.rst
+++ b/docs/source/algorithms/Fit-v1.rst
@@ -210,6 +210,33 @@ If any other functions need to be included in the list please leave a request at
 `Forum <http://forum.mantidproject.org/>`_.
 
 
+Excluding data from fit
+#######################
+
+Regions of a 1D data set can be excluded from fit with the `Exclude` property. It is a list of
+pairs of real numbers which define the regions to exclude. In the following example the regions
+under the peaks are excluded thus fitting only the background
+
+.. code-block:: python
+
+    x = np.linspace(-10, 10, 100)
+    y = np.exp(-4*(x+3)**2) + np.exp(-4*(x-3)**2) + 0.1 - 0.001*x**2
+    ws = CreateWorkspace(x, y)
+    Fit("name=Polynomial,n=2", ws, Exclude=[-5, -1, 1, 5], Output='out')
+
+.. figure:: /images/FitExcludeRange.png
+
+Peak Radius
+###########
+
+The effect of setting `PeakRadius` to a non-default value can be seen from next figure.
+
+.. figure:: /images/PeakRadius_Fit.png
+   :width: 700
+
+It can be used to speed up computations but there is a danger of introducing higher errors.
+
+
 Output
 ######
 
diff --git a/docs/source/algorithms/GetEiMonDet-v2.rst b/docs/source/algorithms/GetEiMonDet-v2.rst
index e9a9be030c990fb91522566f65f6d3ba91043bda..bb8169cd3504a97622cd41eb3159d07d034363cd 100644
--- a/docs/source/algorithms/GetEiMonDet-v2.rst
+++ b/docs/source/algorithms/GetEiMonDet-v2.rst
@@ -9,11 +9,11 @@
 Description
 -----------
 
-This algorithm calculates the incident energy from the time-of-flight between one monitor and some detectors. The time information is extracted from the PeakCentre columns of the EPP workspaces. The FitSuccess column in the EPP tables is used to single out detectors without good quality elastic peaks: only detectors with ``success`` in the column are accepted. Monitor-to-sample and sample-to-detector distances are loaded from the instrument definition. Both the time and the distance data is averaged over the specified detectors. 
+This algorithm calculates the incident energy from the time-of-flight between one monitor and some detectors. The time information is extracted from the 'PeakCentre' columns of the EPP workspaces. The 'FitSuccess' column in the EPP tables is used to single out detectors without good quality elastic peaks: only detectors with ``success`` in the column are accepted. Monitor-to-sample and sample-to-detector distances are loaded from the instrument definition. Both the time and the distance data is averaged over the specified detectors. 
 
 The EPP tables can be produced using the :ref:`algm-FindEPP` algorithm.
 
-If no MonitorWorkspace is specified, the monitor spectrum is expected to be in the detector workspace.
+If no *MonitorWorkspace* is specified, the monitor spectrum is expected to be in the detector workspace.
 
 Specifying the detectors and monitor
 ####################################
@@ -23,7 +23,7 @@ The drop-down menu is used to specify what the numbers in the *Detectors* and *M
 Neutrons detected in later frames
 #################################
 
-It is possible that a neutron pulse is detected at the detectors in a later frame than at the monitor. These cases can be identified if the time-of-flight from the monitor to the detectors is negative or if the calculated incident energy would end up being too large. In these cases, the value of  the *PulseInterval* field is added to the time-of-flight until the result is satisfactory.
+It is possible that a neutron pulse is detected at the detectors in a later frame than at the monitor. These cases can be identified if the time-of-flight from the monitor to the detectors is negative or if the calculated incident energy would end up being too large. In these cases, the value of  the *PulseInterval* field (in micro seconds) is added to the time-of-flight until the result is satisfactory. If *PulseInterval* is not given, the algorithm uses the 'pulse_interval' sample log (in seconds) instead.
 
 To identify when the incident energy is within acceptable bounds, the algorithm applies simple heuristics. Basically, the final energy has to be within 20% of the *NominalIncidentEnergy* or within the *PulseInterval* corrected time-of-flight :math:`\pm` *PulseInterval* / 2.
 
diff --git a/docs/source/algorithms/GroupDetectors-v2.rst b/docs/source/algorithms/GroupDetectors-v2.rst
index a1ccbda08e1d9b8b41007119cd09c563b7b1e0b9..5f160fc2e950010e61053e679072072d96925dc2 100644
--- a/docs/source/algorithms/GroupDetectors-v2.rst
+++ b/docs/source/algorithms/GroupDetectors-v2.rst
@@ -98,23 +98,23 @@ GroupingPattern
 Grouping can also be specified using the GroupingPattern property. Its syntax
 is as follows:
 
-The pattern consists of a list of numbers that refer to workspace indexes and
+The pattern consists of a list of numbers that refer to workspace indices and
 various operators: :literal:`,:+-`.
 
-To remove spectra, you list the workspace indexes that you want to keep. The
-:literal:`:` operator indicates a continuous range, sparing you the need to list
-every one. For example if you have 100 spectra (with workspace indexes from 0 to
-99) and want to remove the first and last 10 spectra along with the 12th, you
-would use the pattern :literal:`10,13:89`. This says keep workspace indices 10
-along with 13 to 89 inclusive.
+The spectra you wish to keep can be specified by selecting the appropriate
+workspace indices. This can be achieved with the following operators:
 
-To add spectra, use :literal:`+` to add two spectra or :literal:`-` to add a
-range. For example you may with to add 10 to 12 and ignore the rest, you would
-use :literal:`10+12`. If you were adding five groups of 20, you would use
-:literal:`0-19,20-39,40-59,60-79,80-99`.
+- :literal:`,` allows you to specify additional indices. :literal:`1,2,4` will
+  keep indices 1, 2 and 4 only.
+- :literal:`:` indicates a continuous range of indices. For example,
+  :literal:`1:5` is the same as :literal:`1,2,3,4,5`.
+- :literal:`+` sums two spectra together. :literal:'7+9' will produce a single
+  spectra listing the sum of 7 and 9, ignoring any others.
+- :literal:`-` sums a range of spectra together. For example, :literal:`3-8` is
+  the same as :literal:`3+4+5+6+7+8`.
 
-One could combine the two, for example :literal:`10+12,13:89` would list the sum
-of 10 and 12 followed by 13 to 89.
+One could combine these operations, for example :literal:`10+12,13:89` would
+list the sum of 10 and 12 followed by 13 to 89.
 
 Previous Versions
 -----------------
diff --git a/docs/source/algorithms/ILLIN16BCalibration-v1.rst b/docs/source/algorithms/ILLIN16BCalibration-v1.rst
index 223bf01cd4467846fa55417d8825249cd611a321..95be1ceead1d1baf5f63219cfe12fb3bfb64ef49 100644
--- a/docs/source/algorithms/ILLIN16BCalibration-v1.rst
+++ b/docs/source/algorithms/ILLIN16BCalibration-v1.rst
@@ -6,6 +6,10 @@
 
 .. properties::
 
+.. warning::
+
+   This algorithm is deprecated (20-Nov-2016). Please, use :ref:`IndirectILLReductionQENS <algm-IndirectILLReductionQENS>` instead.
+
 Description
 -----------
 
@@ -39,7 +43,7 @@ Output:
 
 .. testoutput:: ExILLIN16BCalibration
 
-    Calibration workspace has 24 spectra and 1 bin(s)
+    Calibration workspace has 18 spectra and 1 bin(s)
 
 .. categories::
 
diff --git a/docs/source/algorithms/ISISIndirectDiffractionReduction-v1.rst b/docs/source/algorithms/ISISIndirectDiffractionReduction-v1.rst
index 109410043515ddc50a052edc090775a6ed027a84..19ddfb1b96931c59f02b7999296df4229091bde3 100644
--- a/docs/source/algorithms/ISISIndirectDiffractionReduction-v1.rst
+++ b/docs/source/algorithms/ISISIndirectDiffractionReduction-v1.rst
@@ -32,7 +32,7 @@ Usage
 
     ws = mtd['DiffractionReductions'].getItem(0)
 
-    print 'Workspace name: %s' % ws.getName()
+    print 'Workspace name: %s' % ws.name()
     print 'Number of spectra: %d' % ws.getNumberHistograms()
     print 'Number of bins: %s' % ws.blocksize()
 
diff --git a/docs/source/algorithms/IndirectILLEnergyTransfer-v1.rst b/docs/source/algorithms/IndirectILLEnergyTransfer-v1.rst
new file mode 100644
index 0000000000000000000000000000000000000000..f50cd680b8aa6d6b5fb3b329c52789574b1bcec3
--- /dev/null
+++ b/docs/source/algorithms/IndirectILLEnergyTransfer-v1.rst
@@ -0,0 +1,89 @@
+.. algorithm::
+
+.. summary::
+
+.. alias::
+
+.. properties::
+
+Description
+-----------
+
+This is a part of multi-algorithm reduction workflow for **IN16B** indirect geometry instrument at **ILL**.
+It handles the first steps of the reduction chain, such as grouping of the detectors, normalizing to monitor dependent on the reduction type.
+It performs transformation of the axes; x-axis from channel number to energy transfer, y-axis to scattering angle.
+It handles **automatically** all three types of data (QENS, EFWS, IFWS) recorded with or without mirror sense.
+Note, that following the standard, the ``Unit`` for energy transfer (``DeltaE``) will be mili-elevtron-volts (``mev``).
+This algorithm is intended to handle only single file at a time, although if multiple files are given, they will be automatically summed at raw level, i.e. while loading.
+In this case ``MergeRuns`` algorithm will be invoked, which will forbid the merges across different types of data
+(e.g. different mirror senses, doppler energy or velocity profiles).
+Note, that this algorithm is compatible with the data recorded from 03.2014 onwards
+(i.e. where Doppler's ``mirror_sense``, ``maximum_delta_energy`` and ``velocity_profile`` entries are defined in ``.nxs`` files).
+It returns a :ref:`WorkspaceGroup <WorkspaceGroup>`, containing one (no mirror sense) or two workspaces (with mirror sense) for left and right wings respectively.
+This algorithm is **not** intended to be used directly by the end users. Instead it is used as a child algorithm by :ref:`IndirectILLReductionQENS <algm-IndirectILLReductionQENS>`
+and :ref:`IndirectILLReductionFWS <algm-IndirectILLReductionFWS>` for QENS and FWS type of reductions correspondingly.
+
+
+Workflow
+--------
+
+.. diagram:: IndirectILLEnergyTransfer-v1_wkflw.dot
+
+Usage
+-----
+
+**Example - IndirectILLEnergyTransfer : QENS data without mirror sense**
+
+.. testsetup:: ExIndirectILLEnergyTransfer
+
+   config['default.facility'] = 'ILL'
+   config['default.instrument'] = 'IN16B'
+
+.. testcode:: ExIndirectILLEnergyTransfer
+
+    ws = IndirectILLEnergyTransfer(Run='ILL/IN16B/090661.nxs')
+    print "Reduced workspace has %d wing" % ws.getNumberOfEntries()
+    print "which has %d spectra" % ws.getItem(0).getNumberHistograms()
+    print "and %d bins" % ws.getItem(0).blocksize()
+
+Output:
+
+.. testoutput:: ExIndirectILLEnergyTransfer
+
+    Reduced workspace has 1 wing
+    which has 18 spectra
+    and 1024 bins
+
+.. testcleanup:: ExIndirectILLEnergyTransfer
+
+   DeleteWorkspace('ws')
+
+**Example - IndirectILLEnergyTransfer : QENS data with mirror sense**
+
+.. testsetup:: ExIndirectILLEnergyTransferMirrorSense
+
+   config['default.facility'] = 'ILL'
+   config['default.instrument'] = 'IN16B'
+
+.. testcode:: ExIndirectILLEnergyTransferMirrorSense
+
+    ws = IndirectILLEnergyTransfer(Run='ILL/IN16B/136553:136555.nxs', CropDeadMonitorChannels=True)
+    print "Reduced workspace has %d wings" % ws.getNumberOfEntries()
+    print "which have %d spectra" % ws.getItem(0).getNumberHistograms()
+    print "and %d bins" % ws.getItem(0).blocksize()
+
+Output:
+
+.. testoutput:: ExIndirectILLEnergyTransferMirrorSense
+
+    Reduced workspace has 2 wings
+    which have 18 spectra
+    and 1017 bins
+
+.. testcleanup:: ExIndirectILLEnergyTransferMirrorSense
+
+   DeleteWorkspace('ws')
+
+.. categories::
+
+.. sourcelink::
diff --git a/docs/source/algorithms/IndirectILLReduction-v1.rst b/docs/source/algorithms/IndirectILLReduction-v1.rst
index 71b57071363779241fb137025b6656e542c48d64..6586665ebd05884b6a4025c68f8d1c6cb6c27d94 100644
--- a/docs/source/algorithms/IndirectILLReduction-v1.rst
+++ b/docs/source/algorithms/IndirectILLReduction-v1.rst
@@ -6,6 +6,10 @@
 
 .. properties::
 
+.. warning::
+
+   This algorithm is deprecated (20-Nov-2016). Please, use :ref:`IndirectILLReductionQENS <algm-IndirectILLReductionQENS>` instead.
+
 Description
 -----------
 
@@ -47,9 +51,11 @@ Output:
 
 .. testoutput:: ExIndirectILLReduction
 
-    Reduced workspace has 24 spectra
+    Reduced workspace has 18 spectra
     Raw workspace has 2057 spectra
 
+
+
 **Example - Running IndirectILLReduction in mirror mode**
 
 .. testcode:: ExIndirectILLReductionMirrorMode
@@ -71,9 +77,9 @@ Output:
 .. testoutput:: ExIndirectILLReductionMirrorMode
 
     Raw workspace has 2057 spectra
-    Reduced workspace has 24 spectra
-    Reduced left workspace has 24 spectra
-    Reduced right workspace has 24 spectra
+    Reduced workspace has 18 spectra
+    Reduced left workspace has 18 spectra
+    Reduced right workspace has 18 spectra
 
 .. categories::
 
diff --git a/docs/source/algorithms/IndirectILLReductionFWS-v1.rst b/docs/source/algorithms/IndirectILLReductionFWS-v1.rst
new file mode 100644
index 0000000000000000000000000000000000000000..1ca5430c619cb1d8025a5c6f643185ab2ca1551b
--- /dev/null
+++ b/docs/source/algorithms/IndirectILLReductionFWS-v1.rst
@@ -0,0 +1,70 @@
+.. algorithm::
+
+.. summary::
+
+.. alias::
+
+.. properties::
+
+Description
+-----------
+
+This algorithm performs Fixed Window Scan (FWS) data reduction (both Elastic and Inelastic) for IN16B indirect geometry instrument at ILL.
+It uses internally the :ref:`IndirectILLEnergyTransfer <algm-IndirectILLEnergyTransfer>` algorithm.
+
+Input
+-----
+Multiple files following the syntax given in `MultiFileLoading <http://www.mantidproject.org/MultiFileLoading>`_.
+
+Output
+------
+A :ref:`WorkspaceGroup <WorkspaceGroup>` that contains as many workspaces as many distinct Doppler's energy values were present in input files list (including E=0 for EFWS).
+Each Workspace in the group will have the given observable as the x-axis and as many bins, as many files were given corresponding to the same energy.
+Y-axis will be detector angle, and the values would be the intensities integrated over the whole spectra (for EFWS) or over the two peaks
+(symmetric around each peak) at the beginning and the end of the spectra (for IFWS).
+Scanning observable can be any numeric or time-stamp-like string parameter.
+See ``sample.*`` or e.g. ``start_time`` in Sample Logs.
+``BackgroundRun`` s and ``CalibrationRun`` s will be averaged or interpolated over all the ovservable points according to option.
+Interpolation is provided by :ref:`SplineInterpolation <algm-SplineInterpolation>`, which does cubic spline (or linear for 2 points only) interpolation inside the range and
+flat extrapolation beyond the range. For the moment it does not give errors on interpolated results.
+Interpolated subtraction or calibration is recommended only if there is a strong dependence on the observable and many measured points in the data to be interpolated.
+
+Workflow
+--------
+
+.. diagram:: IndirectILLReductionFWS-v1_wkflw.dot
+
+Usage
+-----
+
+**Example: EFWS+IFWS**
+
+.. testsetup:: ExFixedWindowScans
+
+   config['default.facility'] = 'ILL'
+   config['default.instrument'] = 'IN16B'
+
+.. testcode:: ExFixedWindowScans
+
+    ws = IndirectILLReductionFWS(Run='ILL/IN16B/083072:083077.nxs')
+    print "Result is now a WorkspaceGroup, which has %d workspaces, one per each energy value" % ws.getNumberOfEntries()
+    print "first item, called %s corresponds to energy value of %s" % \
+    (ws.getItem(0).getName(),ws.getItem(0).getName().split('_')[1])
+    print "it has %d histograms and %d bins, one per each temperature" % \
+    (ws.getItem(0).getNumberHistograms(),ws.getItem(0).blocksize())
+
+Output:
+
+.. testoutput:: ExFixedWindowScans
+
+    Result is now a WorkspaceGroup, which has 3 workspaces, one per each energy value
+    first item, called ws_0.0_red corresponds to energy value of 0.0
+    it has 18 histograms and 2 bins, one per each temperature
+
+.. testcleanup:: ExFixedWindowScans
+
+   DeleteWorkspace('ws_red')
+
+.. categories::
+
+.. sourcelink::
diff --git a/docs/source/algorithms/IndirectILLReductionQENS-v1.rst b/docs/source/algorithms/IndirectILLReductionQENS-v1.rst
new file mode 100644
index 0000000000000000000000000000000000000000..65d0fde51d52175a35d654db42e34fe44e6517e5
--- /dev/null
+++ b/docs/source/algorithms/IndirectILLReductionQENS-v1.rst
@@ -0,0 +1,110 @@
+.. algorithm::
+
+.. summary::
+
+.. alias::
+
+.. properties::
+
+Description
+-----------
+
+Performs a multiple-file QENS (Quasi-Elastic Neutron Scattering) data reduction for indirect geometry **ILL** instrument **IN16B**.
+It uses internally the :ref:`IndirectILLEnergyTransfer <algm-IndirectILLEnergyTransfer>` algorithm.
+
+Multiple File Reduction
+~~~~~~~~~~~~~~~~~~~~~~~
+The algorithm is capable of running over multiple files.
+Run property needs to be specified following the syntax in `MultiFileLoading <http://www.mantidproject.org/MultiFileLoading>`_.
+When ``SumRuns=True``, all the runs will be merged while loading.
+Note, for **Range** and **Stepped Range**, ``SumRuns`` will be ignored.
+Use **Added Range** and **Added Stepped Range** instead (see `MultiFileLoading <http://www.mantidproject.org/MultiFileLoading>`_).
+For ``BackgroundRun``, ``CalibrationRun`` and ``AlignmentRun`` all the runs will be automatically summed.
+
+Unmirror Options
+~~~~~~~~~~~~~~~~
+
+**IN16B** can record data with mirror sense, where the spectra for the acceleration and
+deceleration phase of the Doppler drive are recorded separately, or without.
+Technically this is defined in the ``Doppler.mirror_sense`` entry in the sample logs.
+For the data without mirror sense (i.e. mirror_sense = 16) only three unmirror options are valid:
+
+0: No x-axis shift. (Options 0-5 will fall back to 0).
+
+6: Centering the peaks at the zero energy transfer.
+
+7: Centering the peaks using the corresponding vanadium alignment run.
+
+For the data with mirror sense (i.e. mirror_sense = 14) there are 8 options available:
+
+0: Left and right wings are returned separately.
+
+1: Left and right wings will summed.
+
+2: Left wing will be returned.
+
+3: Right wing will be returned.
+
+4: Peaks in the right wing will be positioned at peak positions in the left wing, and then they will be summed.
+
+5: Right wing will be shifted according with the offsets of the peak positions in left and right wings in vanadium alignment run.
+
+6: Peaks in both, left and right wings will be centered at zero energy transfer and then they will be summed.
+
+7: Left and right wings will be shifted according to offsets of peak positions of left and right wings in corresponding vanadium alignment run.
+
+Options 5 and 7 require the ``AlignmentRun`` (vanadium) to determine the peak positions to align with.
+
+:ref:`MatchPeaks <algm-MatchPeaks>` algorithm is invoked for aligning the peaks with different options.
+
+Note, that both detector calibration and background subtraction are performed wing-by-wing, i.e. unmirroring is the very final step.
+
+Vanadium Calibration
+~~~~~~~~~~~~~~~~~~~~
+
+Integration range can be specified to integrate over spectra in ``CalibrationRun``. Note, that before integration, the spectra will be
+centered at 0-energy transfer (see Unmirror Option 6 above) for the calibration run.
+
+
+Output
+------
+
+A :ref:`WorkspaceGroup <WorkspaceGroup>` will be returned, containing workspaces for each individual (unsummed) run.
+
+Workflow
+--------
+
+.. diagram:: IndirectILLReductionQENS-v1_wkflw.dot
+
+Usage
+-----
+
+**Example - IndirectILLReduction : default options**
+
+.. testsetup:: ExIndirectILLReductionQENS
+
+   config['default.facility'] = 'ILL'
+   config['default.instrument'] = 'IN16B'
+
+.. testcode:: ExIndirectILLReductionQENS
+
+    ws = IndirectILLReductionQENS(Run='ILL/IN16B/136553:136555.nxs')
+    print "Result is a WorkspaceGroup, that contains %d workspaces" % ws.getNumberOfEntries()
+    print "the name of the first one is %s corresponding to run 136553" % ws.getItem(0).getName()
+    print "it has %d spectra and %d bins" % (ws.getItem(0).getNumberHistograms(),ws.getItem(0).blocksize())
+
+Output:
+
+.. testoutput:: ExIndirectILLReductionQENS
+
+    Result is a WorkspaceGroup, that contains 3 workspaces
+    the name of the first one is 136553_ws_red corresponding to run 136553
+    it has 18 spectra and 1024 bins
+
+.. testcleanup:: ExIndirectILLReductionQENS
+
+   DeleteWorkspace('ws_red')
+
+.. categories::
+
+.. sourcelink::
diff --git a/docs/source/algorithms/IndirectQuickRun-v1.rst b/docs/source/algorithms/IndirectQuickRun-v1.rst
new file mode 100644
index 0000000000000000000000000000000000000000..d8f19257054f719e61470117ac25c7cc9ce371d9
--- /dev/null
+++ b/docs/source/algorithms/IndirectQuickRun-v1.rst
@@ -0,0 +1,32 @@
+.. algorithm::
+
+.. summary::
+
+.. alias::
+
+.. properties::
+
+Description
+-----------
+
+Runs the :ref:`EnergyWindowScan <algm-EnergyWindowScan>` algorithm with slightly customised inputs and
+provides options for plotting and saving output.
+
+Usage
+-----
+
+.. include:: ../usagedata-note.txt
+
+**Example - IRIS Energy Window Scan**
+
+.. code-block:: python
+
+    IndirectQuickRun(RunNumbers="21360", Instrument='IRIS', Analyser='graphite',
+                     Reflection='002', SpectraRange='3, 50', ElasticRange='-0.5, 0',
+                     InelasticRange='0, 0.5', GroupingMethod='Individual', MSDFit=True)
+
+.. categories::
+
+.. sourcelink::
+  :cpp: None
+  :h: None
diff --git a/docs/source/algorithms/IntegrateEllipsoids-v1.rst b/docs/source/algorithms/IntegrateEllipsoids-v1.rst
index 3befdb87212c9a5c39a02be24d6d0eca022ccd6a..470207f4cc12aa6b6fc1ae6dac4ba1c2103b31eb 100644
--- a/docs/source/algorithms/IntegrateEllipsoids-v1.rst
+++ b/docs/source/algorithms/IntegrateEllipsoids-v1.rst
@@ -92,6 +92,14 @@ Explanation of Inputs
    :math:`0 < PeakSize \leq BackgroundInnerSize` and 
    :math:`BackgroundInnerSize < BackgroundOuterSize \leq RegionRadius`
 
+-  The top 1% of the background events are removed so that there are no intensity spikes near the edges.
+
+-  *AdaptiveQMultiplier* can be used with *SpecifySize* for the radius to vary as a function of the modulus of Q. If the *AdaptiveQBackground* option is set to True, the background radius also changes so each peak has a different integration radius.  Q includes the 2*pi factor.
+
+   -  PeakRadius + AdaptiveQMultiplier * **|Q|**
+   -  BackgroundOuterRadius + AdaptiveQMultiplier * **|Q|**
+   -  BackgroundInnerRadius + AdaptiveQMultiplier * **|Q|**
+
 -  If the *IntegrateInHKL* option is selected, then HKL space is used for
    the integration instead of reciprocal space.  This option may be useful
    for large unit cells where the radius of integration needs to be very different
diff --git a/docs/source/algorithms/IntegrateMDHistoWorkspace-v1.rst b/docs/source/algorithms/IntegrateMDHistoWorkspace-v1.rst
index 12a7081c2f2366dc768898b86315464f758f5a96..edf8a87057768aa354ce2774b1b02251437d9ee3 100644
--- a/docs/source/algorithms/IntegrateMDHistoWorkspace-v1.rst
+++ b/docs/source/algorithms/IntegrateMDHistoWorkspace-v1.rst
@@ -56,7 +56,7 @@ Usage
    non_integrated_dims = low_d_cut.getNonIntegratedDimensions()
    print 'Number of non integrated dimensions after integration are %i'  % len(non_integrated_dims)
    for dim in non_integrated_dims:
-       print 'Non integrated dimension is %s' % dim.getName()
+       print 'Non integrated dimension is %s' % dim.name
        print 'Limits are from %0.2f to %0.2f' % (dim.getMinimum(), dim.getMaximum())
 
 Output:
@@ -91,7 +91,7 @@ maximum and minimum limits may need to be adjusted to ensure no partial binning
    non_integrated_dims = low_d_cut.getNonIntegratedDimensions()
    print 'Number of non integrated dimensions after integration are %i'  % len(non_integrated_dims)
    for dim in non_integrated_dims:
-       print 'Non integrated dimension is %s' % dim.getName()
+       print 'Non integrated dimension is %s' % dim.name
        print 'Limits are from %0.2f to %0.2f' % (dim.getMinimum(), dim.getMaximum())
        print 'Output bin width is %0.2f' % float((dim.getMaximum() - dim.getMinimum() )/dim.getNBins())  
 
diff --git a/docs/source/algorithms/IntegratePeaksMD-v2.rst b/docs/source/algorithms/IntegratePeaksMD-v2.rst
index f65a28688c26bd635729977b99d96f232183bc64..339835760e7bd60c75faef5cc812f83a6e019cf6 100644
--- a/docs/source/algorithms/IntegratePeaksMD-v2.rst
+++ b/docs/source/algorithms/IntegratePeaksMD-v2.rst
@@ -60,6 +60,13 @@ the provided radii. Errors are also summed in quadrature.
    -  The volume of integration is :math:`V_{shell}`.
    -  **BackgroundInnerRadius** allows you to give some space between
       the peak and the background area.
+   -  The top 1% of the background events are removed so that there are no intensity spikes near the edges.
+
+-  **AdaptiveQMultiplier** can be used for the radius to vary as a function of the modulus of Q. If the AdaptiveQBackground option is set to True, the background radius also changes so each peak has a different integration radius.  Q includes the 2*pi factor.
+
+   -  PeakRadius + AdaptiveQMultiplier * **|Q|** 
+   -  BackgroundOuterRadius + AdaptiveQMultiplier * **|Q|** 
+   -  BackgroundInnerRadius + AdaptiveQMultiplier * **|Q|**
 
 Background Subtraction
 ######################
diff --git a/docs/source/algorithms/InvertMDDim-v1.rst b/docs/source/algorithms/InvertMDDim-v1.rst
index 954b2b1da7b16bc8ba722165d3392723c67c969f..ffeadd6f34720858d9b86f64069ad2d933e90d83 100644
--- a/docs/source/algorithms/InvertMDDim-v1.rst
+++ b/docs/source/algorithms/InvertMDDim-v1.rst
@@ -26,7 +26,7 @@ Usage
         print "Name   Bins   Min     Max"
         for dim_index in range(num_dims):
             dim = ws.getDimension(dim_index)
-            print "%s      %i      %.2f   %.2f" % (dim.getName(),
+            print "%s      %i      %.2f   %.2f" % (dim.name,
                  dim.getNBins(), dim.getMinimum(), dim.getMaximum())    
 
     #create a test MD event workspace
diff --git a/docs/source/algorithms/LoadAscii-v1.rst b/docs/source/algorithms/LoadAscii-v1.rst
index ccc54ae7f350e2f3adb3727307d5a03923debc67..9b7b2851204595b87be161be12e67181076caec1 100644
--- a/docs/source/algorithms/LoadAscii-v1.rst
+++ b/docs/source/algorithms/LoadAscii-v1.rst
@@ -39,4 +39,4 @@ if it has X errors written and several spectra.
 
 .. categories::
 
-.. sourcelink::
+.. sourcelink::
\ No newline at end of file
diff --git a/docs/source/algorithms/LoadEventPreNexus-v1.rst b/docs/source/algorithms/LoadEventPreNexus-v1.rst
deleted file mode 100644
index dce0a4de6679514a2008c7c886cf17d2a1195ae8..0000000000000000000000000000000000000000
--- a/docs/source/algorithms/LoadEventPreNexus-v1.rst
+++ /dev/null
@@ -1,28 +0,0 @@
-.. algorithm::
-
-.. summary::
-
-.. alias::
-
-.. properties::
-
-Description
------------
-
-The LoadEventPreNeXus algorithm stores data from the pre-nexus neutron
-event data file in an :ref:`EventWorkspace <EventWorkspace>`. The default
-histogram bin boundaries consist of a single bin able to hold all events
-(in all pixels), and will have their `units <http://www.mantidproject.org/units>`_ set to
-time-of-flight. Since it is an :ref:`EventWorkspace <EventWorkspace>`, it
-can be rebinned to finer bins with no loss of data.
-
-Optional properties
-###################
-
-Specific pulse ID and mapping files can be specified if needed; these
-are guessed at automatically from the neutron filename, if not
-specified.
-
-.. categories::
-
-.. sourcelink::
diff --git a/docs/source/algorithms/LoadFlexiNexus-v1.rst b/docs/source/algorithms/LoadFlexiNexus-v1.rst
index 501f490d4c9d989fb22430978ced5681689a4fa7..4685187a4cc8296c37a672125a976dbf95bf868f 100644
--- a/docs/source/algorithms/LoadFlexiNexus-v1.rst
+++ b/docs/source/algorithms/LoadFlexiNexus-v1.rst
@@ -73,7 +73,7 @@ Usage
     print "Name   Bins   Min     Max"
     for dim_index in range(num_dims):
         dim = wsOut.getDimension(dim_index)
-        print "%s      %i    %.2f  %.2f" % (dim.getName(),
+        print "%s      %i    %.2f  %.2f" % (dim.name,
              dim.getNBins(), dim.getMinimum(), dim.getMaximum())
 
 Output:
diff --git a/docs/source/algorithms/LoadILL-v1.rst b/docs/source/algorithms/LoadILL-v1.rst
deleted file mode 100644
index a94967826dc8d4a473a53603f38195265ad84fbd..0000000000000000000000000000000000000000
--- a/docs/source/algorithms/LoadILL-v1.rst
+++ /dev/null
@@ -1,99 +0,0 @@
-.. algorithm::
-
-.. summary::
-
-.. alias::
-
-.. properties::
-
-Description
------------
-
-.. warning::
-
-   This algorithm will be deprecated in the next version of Mantid. Please, use :ref:`algm-LoadILLTOF` instead, which
-   is the new name for this algorithm.
-
-Loads an ILL TOF NeXus file into a :ref:`Workspace2D <Workspace2D>` with
-the given name.
-
-This loader calculates the elastic peak position (EPP) on the fly. In
-cases where the dispersion peak might be higher than the EPP, it is good
-practice to load a Vanadium file.
-
-The property FilenameVanadium is optional. If it is present the EPP will
-be loaded from the Vanadium data.
-
-To date this algorithm only supports: IN4, IN5 and IN6
-
-Usage
------
-
-**Example - Load a regular histogram Nexus file:**
-(see :ref:`algm-LoadILL` for more options)
-
-.. code-block:: python
-
-   # Regular data file.
-   dataRegular = 'ILLIN6_151460.nxs'
-
-   # Load ILL dataset
-   ws = Load(dataRegular)
-
-   print "This workspace has", ws.getNumDims(), "dimensions and has", ws.getNumberHistograms(), "histograms."
-
-Output:
-
-   This workspace has 2 dimensions and has 340 histograms.
-
-
-
-**Example - Load a histogram Nexus file where the dispersion peak is higher than the elastic peak.
-An auxiliary vanadium file is needed to locate the elastic peak.:**
-(see :ref:`algm-LoadILL` for more options)
-
-.. code-block:: python
-
-   # Data file where the dispersion peak is higher than the elastic peak.
-   dataDispersionPeak = 'ILLIN5_Sample_096003.nxs'
-
-   # Vanadium file collected in the same conditions as the dispersion peak dataset.
-   vanaDispersionPeak = 'ILLIN5_Vana_095893.nxs'
-
-   # Load ILL dispersion peak dataset and a vanadium dataset
-   ws = Load(dataDispersionPeak, FilenameVanadium=vanaDispersionPeak)
-
-   print "This workspace has", ws.getNumDims(), "dimensions and has", ws.getNumberHistograms(), "histograms."
-
-Output:
-
-   This workspace has 2 dimensions and has 98305 histograms.
-
-**Example - Same example as above, but the vanadium file is loaded in advance. The dataset for the dispersion peak is loaded after, using the auxiliary vanadium workspace.:**
-(see :ref:`algm-LoadILL` for more options)
-
-.. code-block:: python
-
-   # Data file where the dispersion peak is higher than the elastic peak.
-   dataDispersionPeak = 'ILLIN5_Sample_096003.nxs'
-
-   # Vanadium file collected in the same conditions as the dispersion peak dataset.
-   vanaDispersionPeak = 'ILLIN5_Vana_095893.nxs'
-
-   # Load the Vanadium
-   wsVana = Load(dataDispersionPeak)
-
-   # Load ILL dispersion peak dataset and a vanadium dataset
-   wsData = Load(dataDispersionPeak, WorkspaceVanadium=wsVana)
-
-   print "The Vanadium workspace has", wsVana.getNumDims(), "dimensions and has", wsVana.getNumberHistograms(), "histograms."
-   print "The Data workspace has", wsData.getNumDims(), "dimensions and has", wsData.getNumberHistograms(), "histograms."
-
-Output:
-
-	The Vanadium workspace has 2 dimensions and has 98305 histograms.
-	The Data workspace has 2 dimensions and has 98305 histograms.
-
-.. categories::
-
-.. sourcelink::
diff --git a/docs/source/algorithms/LoadILLIndirect-v2.rst b/docs/source/algorithms/LoadILLIndirect-v2.rst
new file mode 100644
index 0000000000000000000000000000000000000000..f1e3bb0cf16654865fd855241e0b810ca37cf83b
--- /dev/null
+++ b/docs/source/algorithms/LoadILLIndirect-v2.rst
@@ -0,0 +1,37 @@
+.. algorithm::
+
+.. summary::
+
+.. alias::
+
+.. properties::
+
+Description
+-----------
+
+Loads an ILL Back Scattering NeXus file into a :ref:`Workspace2D <Workspace2D>` with
+the given name.
+
+The Units axis is defined with *empty* units. The main purpose of this loader is to be used with the **Indirect Load** interface.
+
+To date this algorithm only supports: IN16B
+
+Usage
+-----
+
+**Example - Load ILL IN16B NeXus file:**
+
+.. code-block:: python
+
+   # Load ILL IN16B data file into a workspace 2D.
+   ws = Load('ILLIN16B_034745.nxs')
+
+   print "This workspace has", ws.getNumDims(), "dimensions and has", ws.getNumberHistograms(), "histograms."
+
+Output:
+
+	This workspace has 2 dimensions and has 2057 histograms.
+
+.. categories::
+
+.. sourcelink::
diff --git a/docs/source/algorithms/LoadILLTOF-v2.rst b/docs/source/algorithms/LoadILLTOF-v2.rst
new file mode 100644
index 0000000000000000000000000000000000000000..6cac270c17417b2c09d1e5247e8d312a1c133171
--- /dev/null
+++ b/docs/source/algorithms/LoadILLTOF-v2.rst
@@ -0,0 +1,64 @@
+.. algorithm::
+
+.. summary::
+
+.. alias::
+
+.. properties::
+
+Description
+-----------
+
+Loads an ILL TOF NeXus file into a :ref:`Workspace2D <Workspace2D>` with
+the given name.
+
+To date this algorithm only supports: IN4, IN5 and IN6.
+
+.. note::
+    The initial time-of-flight axis is set up using the 'time_of_flight' field in the NeXus file. Therefore the conversion from 'TOF' to 'DeltaE' may not give the correct zero-energy transfer.
+
+Pulse Intervals
+---------------
+
+For IN4 and IN6 the algorithm also calculates the pulse interval.
+
+For the number of pulses:
+
+* **IN4:** :math:`n_{pulses} = \frac{v_{fc}}{4 v_{bc}}`
+    where :math:`n_{pulses}` is the number of pulses from the chopper per rotation, :math:`v_{fc}` the Fermi chopper speed and :math:`v_{bc}` the background chopper speed. Background chopper 1 and background chopper 2 must have the same speeds. All speeds are in units of rpm.
+
+* **IN6:** :math:`n_{pulses} = \frac{v_{fc}}{v_{sc}}`
+    where :math:`n_{pulses}` is the number of pulses from the chopper per rotation, :math:`v_{fc}` the Fermi chopper speed and :math:`v_{sc}` the suppressor chopper speed. All speeds are in units of rpm.
+
+The pulse interval, :math:`T_{pulse}` in seconds, is then given by,
+
+:math:`T_{pulse} = \frac{60 \textrm{s}}{2 v_{fc}} n_{pulses}`.
+
+Usage
+-----
+
+.. include:: ../usagedata-note.txt
+
+**Example - Load a regular histogram NeXus file:**
+
+.. testcode:: ExLoad
+
+    # Regular data file.
+    dataRegular = 'ILL/IN5/104007.nxs'
+
+    # Load ILL dataset
+    ws = Load(dataRegular)
+
+    numDimensions = ws.getNumDims()
+    numHistograms = ws.getNumberHistograms()
+    print('This workspace has {0} dimensions and {1} histograms.'.format(numDimensions, numHistograms))
+
+Output:
+
+.. testoutput:: ExLoad
+
+    This workspace has 2 dimensions and 98305 histograms.
+
+.. categories::
+
+.. sourcelink::
diff --git a/docs/source/algorithms/LoadLogsForSNSPulsedMagnet-v1.rst b/docs/source/algorithms/LoadLogsForSNSPulsedMagnet-v1.rst
deleted file mode 100644
index ebcd2d46148beaa2cee7a0d54caa2262a09372a0..0000000000000000000000000000000000000000
--- a/docs/source/algorithms/LoadLogsForSNSPulsedMagnet-v1.rst
+++ /dev/null
@@ -1,18 +0,0 @@
-.. algorithm::
-
-.. summary::
-
-.. alias::
-
-.. properties::
-
-Description
------------
-
-.. warning::
-
-    This algorithm is deprecated and should not be used.
-
-.. categories::
-
-.. sourcelink::
diff --git a/docs/source/algorithms/LoadMcStas-v1.rst b/docs/source/algorithms/LoadMcStas-v1.rst
index 96bb7991970e5e01c445b22d524cdcd4b08a5a94..a720bb626c26b540198195bfa76f613e3e51a4a1 100644
--- a/docs/source/algorithms/LoadMcStas-v1.rst
+++ b/docs/source/algorithms/LoadMcStas-v1.rst
@@ -11,24 +11,28 @@ Description
 
 Reads a McStas Nexus file into a Mantid WorkspaceGroup with a 
 user-supplied name. Data generated by McStas monitor components are 
-stored in workspaces of type Workspace2D or Event.
+stored in workspaces of type Workspace2D and/or EventWorkspace.
 
-For further information about Mcstas and Mantid see `here <https://github.com/McStasMcXtrace/McCode/wiki/McStas-and-Mantid>`_.
-This includes how to generate a McStas 2.1 event data file and the corresponding IDF.
-It also includes McStas event data conventions.
-The information in the link is *work in progress*.
+For information about how to create McStas outputs that can 
+readily be read by this loader, see `here <https://github.com/McStasMcXtrace/McCode/wiki/McStas-and-Mantid>`_.
+For more information about McStas, and combined McStas and Mantid analyses see references below.
+
+The ErrorBarsSetTo1 property applies to event data, but not to histogram data.
 
 LoadMcStas replaces LoadMcStasEventNexus. LoadMcStas can be used for 
 reading McStas 2.1 histogram and event data. 
 :ref:`algm-LoadMcStasNexus` can be used 
 for reading McStas 2.0 histogram data. 
 
-LoadMcStas will be called by Load, if the file has an 
+Information about the required structure of the input Nexus file
+################################################################
+
+The input file must have an 
 ``/entry1/simulation/name`` item whose value is ``"mccode"``.
 
 The output workspace will contain one workspace for each group of
-class ``NXdata`` and not of name ``"content_nxs"`` found in a  
-group of class ``NXDetector`` of name ``"Data"``.
+class ``NXdata`` in the input NeXus file, which is not of name ``"content_nxs"`` 
+found in a group of class ``NXDetector`` of name ``"Data"``.
 The name of the workspace is the same as the name of the group, 
 but with ``__mcstas_event_hist`` added to the end.
 
@@ -58,7 +62,7 @@ but with ``__mcstas_event_hist`` added to the end.
 |                                  | is needed for events to be loaded        | events are loaded                     | 
 +----------------------------------+------------------------------------------+---------------------------------------+
 
-The event data of the McStas file occurs in a table with six columns:
+The event data of the McStas file occurs in a NeXus table with six columns:
 
 1. Weight
 2. X coordinate
@@ -67,15 +71,52 @@ The event data of the McStas file occurs in a table with six columns:
 5. Detector ID
 6. Time
 
-The **ErrorBarsSetTo1** property applies to event data, but not to histogram data.
-
 
 References
 ##########
 
 For more information about McStas and its general usage for simulating neutron 
-scattering instruments and experiments visit the McStas homepage http://www.mcstas.org.
+scattering instruments and experiments visit the `McStas homepage <http://www.mcstas.org>`_ .
+
+For examples of how combined McStas and Mantid analyses can help 
+instrument simulation and data treatment/analysis tasks see Nielsen., T.R. et al., McStas
+and Mantid integration, Journal of Neutron Research, vol. 18, no. 2-3, pp. 61-77, 2015
+`DOI: 10.3233/JNR-160026 <http://dx.doi.org/10.3233/JNR-160026>`_ 
+[`arXiv <http://arxiv.org/abs/1607.02498>`_].
+
+Usage
+-----
+
+.. include:: ../usagedata-note.txt
+
+**Example - Load McStas data containing both event and histogram data:**
+
+.. testcode:: ExLoadMcStas
+
+   # Load the data into tuple
+   ws = LoadMcStas('mcstas_event_hist.h5')
+
+   # workspace group is first entry in tuple
+   group = ws[0]
+   print "Number of entries in group: " + str(group.getNumberOfEntries())
+
+   eventData = ws[1]
+   print "Number of histograms in event data: " + str(eventData.getNumberHistograms())
+   print "Name of event data: " + str(eventData.getName())
+
+   someHistogramData = ws[2]
+   print "Number of histograms in hist data: " + str(someHistogramData.getNumberHistograms())
+   print "Name of hist data: " + str(someHistogramData.getName())
+
+Output:
+
+.. testoutput:: ExLoadMcStas
 
+   Number of entries in group: 5
+   Number of histograms in event data: 8192
+   Name of event data: EventData_ws
+   Number of histograms in hist data: 1
+   Name of hist data: Edet.dat_ws
 
 .. categories::
 
diff --git a/docs/source/algorithms/LoadNexusLogs-v1.rst b/docs/source/algorithms/LoadNexusLogs-v1.rst
index 85b036c6cb200864cb7171e7babbf9adc152f5f6..a598f17748066e6344e366a9613b1ccfd1f9c45a 100644
--- a/docs/source/algorithms/LoadNexusLogs-v1.rst
+++ b/docs/source/algorithms/LoadNexusLogs-v1.rst
@@ -60,6 +60,8 @@ Items missing from the Nexus file are simply not loaded.
 |                                  |                                                    | *Existing values are always           |
 |                                  |                                                    | overwritten.*                         |
 +----------------------------------+----------------------------------------------------+---------------------------------------+
+| Run title                        | Entry ``"title"``                                  | Title in run object if it exists      |
++----------------------------------+----------------------------------------------------+---------------------------------------+
 
 If the nexus file has a ``"proton_log"`` group, then this algorithm will do some event filtering to allow SANS2D files to load.
 
diff --git a/docs/source/algorithms/LoadSpiceXML2DDet-v1.rst b/docs/source/algorithms/LoadSpiceXML2DDet-v1.rst
index 1544bd488267decbd9031e17bcbd210ef34e0586..68f8a43df094ee532d8290deee27eedd4a2b3e7a 100644
--- a/docs/source/algorithms/LoadSpiceXML2DDet-v1.rst
+++ b/docs/source/algorithms/LoadSpiceXML2DDet-v1.rst
@@ -41,6 +41,14 @@ Counts of an :math:`n\times m` 2D detectors  are recorded in XML file as below::
 And the (1,1) position is the bottom left corner of the Anger camera as seen from the sample position.
 
 
+HB3A instrument facts
+#####################
+
+HB3A has 1 detector with :math:`256 \times 256` pixels.
+
+ - Pixel: width = :math:`2 \times 9.921875e-05` m, height = :math:`2 \times 9.921875e-05` m, depth = 0.0001 m.
+ - Detector: 
+
 
 Output Worskpaces
 #################
diff --git a/docs/source/algorithms/Lorentzian1D-v1.rst b/docs/source/algorithms/Lorentzian1D-v1.rst
deleted file mode 100644
index 79a0048103b7c1e436034ddf951a997eed2e607c..0000000000000000000000000000000000000000
--- a/docs/source/algorithms/Lorentzian1D-v1.rst
+++ /dev/null
@@ -1,41 +0,0 @@
-.. algorithm::
-
-.. summary::
-
-.. alias::
-
-.. properties::
-
-Description
------------
-
-Takes a histogram in a 2D workspace and fit it to a Lorentzian function,
-i.e. to the function:
-
-.. math:: \mbox{BG0}+\mbox{BG1}*x+\mbox{Height}* \left( \frac{\mbox{HWHM}^2}{(x-\mbox{PeakCentre})^2+\mbox{HWHM}^2} \right)
-
-where
-
--  BG0 - constant background value
--  BG1 - constant background value
--  Height - height of peak (at maximum)
--  PeakCentre - centre of peak
--  HWHM - half-width at half-maximum
-
-Note that the FWHM (Full Width Half Maximum) equals two times HWHM, and
-the integral over the Lorentzian equals
-:math:`\mbox{Height} * \pi * \mbox{HWHM}` (ignoring the linear
-background). In the literature you may also often see the notation
-:math:`\gamma` = HWHM.
-
-The figure below illustrate this symmetric peakshape function fitted to
-a TOF peak:
-
-.. figure:: /images/LorentzianWithConstBackground.png
-   :alt: LorentzianWithConstBackground.png
-
-   LorentzianWithConstBackground.png
-
-.. categories::
-
-.. sourcelink::
diff --git a/docs/source/algorithms/MSDFit-v1.rst b/docs/source/algorithms/MSDFit-v1.rst
index 0b99d7a4ce9ab9c6fff4d3c7b47aace38f96ad42..c46e9536ffda7c0acd055e6bcf352411bfde1967 100644
--- a/docs/source/algorithms/MSDFit-v1.rst
+++ b/docs/source/algorithms/MSDFit-v1.rst
@@ -37,15 +37,13 @@ Usage
                              XStart=0.0, XEnd=5.0,
                              SpecMin=0, SpecMax=0)
 
-    print ', '.join(msd.getNames())
-    print 'A0: ' + str(msd.getItem(0).readY(0))
-    print 'A1: ' + str(msd.getItem(1).readY(0))
+    print 'A0: ' + str(msd.readY(0))
+    print 'A1: ' + str(msd.readY(1))
 
 Output:
 
 .. testoutput:: ExGeneratedDataFit
 
-    msd_A0, msd_A1
     A0: [ 0.95908058]
     A1: [ 0.11014908]
 
diff --git a/docs/source/algorithms/MaskDetectors-v1.rst b/docs/source/algorithms/MaskDetectors-v1.rst
index 7a38bc31e92e30ed5d16e461ba93201741c5efa4..33b63ac1ca8117bb79c92f4724c41578d51e2042 100644
--- a/docs/source/algorithms/MaskDetectors-v1.rst
+++ b/docs/source/algorithms/MaskDetectors-v1.rst
@@ -53,38 +53,39 @@ but any *ISIS MARI* workspace obtained from experiment will produce different se
 Description
 -----------
 
-The algorithm zeros the data in the spectra of the input workspace 
-defined as masked and flags as masked (can be verified by IDetector::isMasked() method)
-the detectors, corresponding to the masked spectra.
+The algorithm zeroes the data in the spectra of the input workspace 
+defined as masked. The detectors corresponding to the masked spectra are also
+flagged as masked (can be verified by the `IDetector::isMasked()` method).
 
-The first, the *Workspace* property specifies the workspace to mask and other algorithms properties
+The *Workspace* property specifies the workspace to mask while the other properties
 provide various ways to define the spectra and detectors to mask.
 
-If *Workspace* is PeaksWorkspaces, only the detectors listed are masked and 
-the mask must be specified by a DetectorList or MaskedWorkspace.
+If *Workspace* is PeaksWorkspace, only the detectors listed are masked and 
+the mask must be specified by a *DetectorList* or *MaskedWorkspace*.
 
 All but the *Workspace* property are optional and at least one of them must be
 set. If several are set, the combination of them is used.
 
 The set of spectra and detectors to be masked can be given as a list of either
-spectrum numbers, detector IDs, workspace indices or workspace indexes range.
+spectrum numbers, detector IDs, workspace indices, component names, or as a
+workspace index range.
 
-Workspace index range (properties *StartWorkspacIndex* and *EndWorkspaceIndex*)
-change its actions depending on other masking properties being provided, namely:
+The workspace index range (properties *StartWorkspacIndex* and *EndWorkspaceIndex*)
+changes its action depending on other masking properties being provided, namely:
 
-- If workspace indexes range is provided alone, the workspace is masked 
-  within this range.
-- If workspace indexes range is provided in combination with any other masking
+- If a workspace index range is provided alone, all spectra within this range are masked.
+- If a workspace index range is provided in combination with any other masking
   property, only the indexes in this range are masked.
 
 Mask Detectors According To Instrument & Masking Workspace
 ##########################################################
 
-If MaskedWorkspace is provided, both *MaskedWorkspace* and 
+If *MaskedWorkspace* is provided, both *MaskedWorkspace* and 
 *Workspace* mask have the same instrument. 
 
 The algorithm works differently depending on *MaskedWorkspace* property 
-being a *Mask Workspace* (SpecialWorkspace2D object) or  `Matrix Workspace <http://docs.mantidproject.org/nightly/concepts/MatrixWorkspace.html#matrixworkspace>`_. 
+being a *Mask Workspace* (SpecialWorkspace2D object) or 
+`Matrix Workspace <http://docs.mantidproject.org/nightly/concepts/MatrixWorkspace.html#matrixworkspace>`_. 
 
 If source *MaskedWorkspace* is a *Mask Workspace* and the number of spectra in the source 
 *MaskedWorkspace* is equal to number of spectra in the target *Workspace*, the 
@@ -93,20 +94,22 @@ of masking information for the target workspace.
 
 If the numbers of spectra in *Workspace* and *MaskedWorkspace* are different,
 the algorithm extracts list of masked detector IDS from source workspace and
-used them to mask the correspondent spectra of the target workspace. 
+uses them to mask the corresponding spectra of the target workspace. 
 
 Setting property *ForceInstrumentMasking* to true forces algorithm 
-to always use *MaskedWorkspace* detectors ID
+to always use *MaskedWorkspace* detector IDs
 as the source of the masking information. 
-If the detector is masked, then the corresponding detector
+If a detector is masked, then the corresponding detector
 will be masked in the input *Workspace*.
 
- 
 If the input *MaskedWorkspace* is a `Matrix Workspace <http://docs.mantidproject.org/nightly/concepts/MatrixWorkspace.html#matrixworkspace>`_ 
-the *MaskedWorkspace* can only have the same number of spectra as the target *Workspace* and the 
-information about masked spectra of the *MaskedWorkspace* 
-is copied to the target *Workspace*
+and the number of spectra in the source *MaskedWorkspace* is equal to the number 
+of spectra in the target *Workspace*, then workspace indicies of the source are
+used.
 
+If the numbers of spectra in *Workspace* and *MaskedWorkspace* are different,
+the algorithm extracts list of detector IDS from source workspace and uses them 
+to mask the corresponding spectra of the target workspace. 
 
 Definition of Mask
 ##################
@@ -131,14 +134,15 @@ About Input Parameters
 mask detectors, including
 
 -  Workspace indices
--  Spectra
--  Detectors
+-  Spectrum numbers
+-  Detector IDs
+-  Instrument components
 -  MaskWorkspace
 -  General :ref:`MatrixWorkspace <MatrixWorkspace>` other than
    MaskWorkspace (In this case, the mask will be
    extracted from this workspace)
--  Workspace indexes range specified by setting either *StartWorkspacIndex* or *EndWorkspaceIndex* to non-default value.
-   **Note:** Setting *EndWorkspaceIndex* to the value, exceeding the number of histogram in the target workspace would mask
+-  Workspace index range specified by setting either *StartWorkspacIndex* or *EndWorkspaceIndex* to non-default value.
+   **Note:** Setting *EndWorkspaceIndex* to a value exceeding the number of histograms in the target workspace would mask
    the entire workspace.
 
 Rules
@@ -150,7 +154,8 @@ Here are the rules for input information for masking
 2. Workspace indices and Spectra cannot be given at the same time.
 3. MaskWorkspace  and general :ref:`MatrixWorkspace <MatrixWorkspace>` cannot be given at the same time.
 4. When a general :ref:`MatrixWorkspace <MatrixWorkspace>` is specified, then all detectors in a spectrum are treated as masked if the effective detector of that spectrum is masked.
-5. The masks specified from
+5. The detectors found recursively in given instrument components are added to the list of detectors to mask. If multiple components with the same name exist, the first component found is masked.
+6. The masks specified from
 
    a) workspace indices/spectra
    b) detectors
@@ -162,14 +167,14 @@ Operations Involved in Masking
 There are 2 operations to mask a detector and thus spectrum related
 
 1. Set the detector in workspace's instrument's *parameter map* to *masked*.
-2. Clear the data associated with the spectrum with detectors that are masked.
+2. Zero the data and clear the events associated with the spectrum with detectors that are masked.
 
 
 Usage
 -----
 
 Example 1: specifying spectrum numbers
-##########################################
+######################################
 
 .. testcode:: ExMaskSpec
 
@@ -234,7 +239,7 @@ Output
 
 
 Example 2: specifying detector IDs
-######################################
+##################################
 
 .. testcode:: ExMaskIDs
 
@@ -274,7 +279,7 @@ Output
 
 
 Example 3: specifying workspace indices
-###########################################
+#######################################
 
 .. testcode:: ExMaskWI
 
@@ -318,8 +323,46 @@ Output
   Detector in spectrum with workspace index  4  is masked: False
 
 
-Example 4: specifying a masking workspace
-##################################################
+Example 4: specifying instrument components
+###########################################
+
+.. testcode:: ExMaskComp
+
+  # Create a workspace containing some data.
+  ws = CreateSampleWorkspace()
+  # Mask the column of detectors named 'bank1(x=3)' in bank1, and bank2 entirely.
+  # Unfortunately, individual detectors cannot be masked this way in the
+  # workspace created by CreateSampleWorkspace since their
+  # names contain a comma ',' which breaks the parsing of the component list.
+  MaskDetectors(ws, ComponentList='bank1/bank1(x=3), bank2')
+  
+  
+  # Define a helper function.
+  def checkMasked(detsBegin, detsEnd):
+      allMasked = True
+      for i in range(detsBegin, detsEnd):
+          det = ws.getInstrument().getDetector(i)
+          if not det.isMasked():
+              allMasked = False
+              break
+      if allMasked:
+          print('Detectors from {0} to {1} are masked.'.format(detsBegin, detsEnd))
+      else:
+          print('Some detectors were unmasked.')
+  
+  # Check the detector column in bank1
+  checkMasked(130, 140)
+  
+  # Check bank2
+  checkMasked(200,300)
+
+.. testoutput:: ExMaskComp
+
+  Detectors from 130 to 140 are masked.
+  Detectors from 200 to 300 are masked.
+
+Example 5: specifying a masking workspace
+#########################################
 
 .. testcode:: ExMaskMask
 
@@ -376,7 +419,7 @@ Output
   Detector 103 is masked: True
   Detector 104 is masked: False
   
-Example 5: Specifying a masking range
+Example 6: specifying a masking range
 #####################################
 
 .. testcode:: ExMaskInRange
@@ -404,8 +447,8 @@ Output
   Detector 104 is masked: True
   Detector 105 is masked: False
   
-Example 6: Constrain the masking range
-######################################
+Example 7: constraining the masking range
+#########################################
 
 .. testcode:: ExMaskConstrainInRange
 
diff --git a/docs/source/algorithms/MedianBinWidth-v1.rst b/docs/source/algorithms/MedianBinWidth-v1.rst
new file mode 100644
index 0000000000000000000000000000000000000000..9198e8ed0c9b507b8a6509ab0575949bc4d69cba
--- /dev/null
+++ b/docs/source/algorithms/MedianBinWidth-v1.rst
@@ -0,0 +1,66 @@
+.. algorithm::
+
+.. summary::
+
+.. alias::
+
+.. properties::
+  
+Description
+-----------
+  
+This algorithm calculates the median bin width of each histogram in *InputWorkspace*. The (optionally rounded) mean value of the medians is then placed in the *BinWidth* output property.
+
+Rounding
+########
+
+If the *Rounding* property is set to **10^n**, the bin width will be rounded down to the nearest power of 10. For example, 0.11 and 0.99 will be rounded to 0.1, while 0.011 and 0.099 will be rounded to 0.01.
+
+Restrictions on properties
+################################
+
+The *InputWorkspace* has to contain histogram data. For point data, :ref:`algm-ConvertToHistogram` can be used first, but care should be taken if the points are not equally spaced.
+
+Usage
+-----
+  
+**Example: rebinning a workspace.**
+
+.. testcode:: Example
+
+    import numpy
+    
+    # For normal python lists: 3 * [0.1] = [0.1, 0.1, 0.1]
+    binWidths = 3 * [0.1] + 4 * [1.7] + [10.0]
+    # Convert to numpy array.
+    # For numpy arrays: 3 * [0.1] = [0.3], thus the above magic would not work.
+    binWidhts = numpy.array(binWidths)
+    # Make bin boundaries out of the widths. The first boundary is at -3.0.
+    xs = numpy.cumsum(numpy.append(numpy.array([-3.0]), binWidths))
+    # There is one less bin than the number of boundaries.
+    ys = numpy.zeros(len(xs) - 1)
+    ws = CreateWorkspace(DataX=xs, DataY=ys)
+    
+    newWidth = MedianBinWidth(InputWorkspace=ws)
+    print('New bin width: {0}'.format(newWidth))
+    
+    rebinned = Rebin(InputWorkspace=ws, Params=[newWidth], FullBinsOnly=True)
+    
+    widths = ws.readX(0)[1:] - ws.readX(0)[:-1]
+    print('Bin widths before rebinning: {0}'.format(widths))
+    widths = rebinned.readX(0)[1:] - rebinned.readX(0)[:-1]
+    print('Bin widths after rebinning: {0}'.format(widths))
+
+Output:
+
+.. testoutput:: Example
+
+    New bin width: 1.7
+    Bin widths before rebinning: [  0.1   0.1   0.1   1.7   1.7   1.7   1.7  10. ]
+    Bin widths after rebinning: [ 1.7  1.7  1.7  1.7  1.7  1.7  1.7  1.7  1.7  1.7]
+
+.. categories::
+
+.. sourcelink::
+
+
diff --git a/docs/source/algorithms/MonteCarloAbsorption-v1.rst b/docs/source/algorithms/MonteCarloAbsorption-v1.rst
index b11610f35fcd3514edf809f3ff209ab70ecf7eb7..5dc65a73bab5b624380e1725de7cf5434ef10d4e 100644
--- a/docs/source/algorithms/MonteCarloAbsorption-v1.rst
+++ b/docs/source/algorithms/MonteCarloAbsorption-v1.rst
@@ -54,17 +54,16 @@ The algorithm proceeds as follows. For each spectrum:
      - generate a random point on the beam face defined by the input height & width. If the point is outside of the
        area defined by the face of the sample then it is pulled to the boundary of this area
 
-     - assume the neutron travels in the direction defined by the `samplePos - srcPos` and define a `Track`
+     - generate a random point within the sample or container objects as the scatter point and create a `Track`
+       from the selected position on the beam face to the scatter point
 
-     - test for intersections of the track & sample + container objects, giving the number of subsections
+     - test for intersections of the track & sample/container objects, giving the number of subsections
        and corresponding distances within the object for each section, call them :math:`l_{1i}`
 
-     - choose a random section and depth for the scatter point
-
      - form a second `Track` with the scatter position as the starting point and the direction defined by
        `detPos - scatterPos`
 
-     - test for intersections of the track & sample + container objects, giving the number of subsections
+     - test for intersections of the track & sample/container objects, giving the number of subsections
        and corresponding distances within the object for each section, call them :math:`l_{2i}`
 
      - compute the self-attenuation factor for all intersections as
@@ -77,7 +76,13 @@ The algorithm proceeds as follows. For each spectrum:
    * average the accumulated attentuation factors over `NEvents` and assign this as the correction factor for
      this :math:`\lambda_{step}`.
 
-#. finally, perform an interpolation through the unsimulated wavelength points
+#. finally, interpolate through the unsimulated wavelength points using the selected method
+
+Interpolation
+#############
+
+The default linear interpolation method will produce an absorption curve that is not smooth. CSpline interpolation
+will produce a smoother result by using a 3rd-order polynomial to approximate the original points. 
 
 Usage
 -----
@@ -96,6 +101,22 @@ Usage
    abscor = MonteCarloAbsorption(data, NumberOfWavelengthPoints=50)
    corrected = data/abscor
 
+**Example: A cylindrical sample with no container, interpolating with a CSpline**
+
+.. testcode:: ExCylinderSampleOnlyAndSpline
+
+   data = CreateSampleWorkspace(WorkspaceType='Histogram', NumBanks=1)
+   data = ConvertUnits(data, Target="Wavelength")
+   # Default up axis is Y
+   SetSample(data, Geometry={'Shape': 'Cylinder', 'Height': 5.0, 'Radius': 1.0,
+                     'Center': [0.0,0.0,0.0]},
+                   Material={'ChemicalFormula': '(Li7)2-C-H4-N-Cl6', 'SampleNumberDensity': 0.07})
+   # Simulating every data point can be slow. Use a smaller set and interpolate
+   abscor = MonteCarloAbsorption(data, NumberOfWavelengthPoints=50,
+                                 Interpolation='CSpline')
+   corrected = data/abscor
+
+
 **Example: A cylindrical sample setting a beam size**
 
 .. testcode:: ExCylinderSampleAndBeamSize
diff --git a/docs/source/algorithms/PDDetermineCharacterizations-v1.rst b/docs/source/algorithms/PDDetermineCharacterizations-v1.rst
index a6709c8885928b21a72457477eb8858c5196ef8e..d34d55bc56009072b62e9a89f0343b7cf8d12140 100644
--- a/docs/source/algorithms/PDDetermineCharacterizations-v1.rst
+++ b/docs/source/algorithms/PDDetermineCharacterizations-v1.rst
@@ -10,45 +10,62 @@ Description
 -----------
 
 This algorithm takes an ``InputWorkspace`` and ``Characterizations``
-`TableWorkspace <http://www.mantidproject.org/TableWorkspace>`__ and 
-creates a PropertyManager with the appropriate characterization runs. 
-This is done by determining the effective accelerator frequency and 
+`TableWorkspace <http://www.mantidproject.org/TableWorkspace>`__ and
+creates a PropertyManager with the appropriate characterization runs.
+This is done by determining the effective accelerator frequency and
 center wavelength and choosing the appropriate row from the table.
 
 This algorithm is one of the workflow algorithms that helps
-:ref:`algm-SNSPowderReduction`.
+:ref:`algm-SNSPowderReduction` and its child algorithm
+:ref:`algm-AlignAndFocusPowder`.
 
 Determing Frequency and Wavelength
 ##################################
 
-The freqency is found by inspecting the logs (in order) "SpeedRequest1",
-"Speed1", and "frequency". Whichever one has a nonzero value is used.
-Simlilarly, the wavelength is taken by inspecting "Lambda". If either the 
-frequency or wavelength cannot be determined, the algorithm will return a
+The freqency is found by inspecting the logs (in order)
+``SpeedRequest1``, ``Speed1``, and ``frequency``. Whichever one has a
+nonzero value is used.  Simlilarly, the wavelength is taken by
+inspecting ``LambdaRequest`` then ``Lambda``. If either the frequency
+or wavelength cannot be determined, the algorithm will return a
 default PropertyManager with mostly zeros.
 
 PropertyManager Contents
 ########################
 
 The PropertyManager will have the following keys and values. Listed in
-the table is also their default values.
-
-========== ======= =======
-Name         Type  Default
-========== ======= =======
-frequency  double  0
-wavelength double  0
-bank       integer 1
-vanadium   integer 0
-container  integer 0
-empty      integer 0
-d_min      string  ""
-d_max      string  ""
-tof_min    double  0
-tof_max    double  0
-========== ======= =======
-
-For a description of the  `TableWorkspace <TableWorkspace>`__ 
+the table is also their default values. The "Alg Property" column is
+what property of this algorithm is used to override what is in the
+table. For all of those properties, "0" is interpreted as use the
+information from the supplied table, "-1" is interpreted as set the
+value to zero in the resulting ``PropertyManager``.
+
+=================== ============ ======= ============
+Name                Type         Default Alg Property
+=================== ============ ======= ============
+frequency           double       0
+wavelength          double       0
+bank                integer      1
+vanadium            integerarray [0]     NormRun
+vanadium_background integerarray [0]     NormBackRun
+container           integerarray [0]     BackRun
+empty_environment   integerarray [0]     EmptyEnv
+empty_instrument    integerarray [0]     EmptyInstr
+d_min               string       ""
+d_max               string       ""
+tof_min             double       0
+tof_max             double       0
+wavelength_min      double       0
+wavelength_max      double       0
+=================== ============ ======= ============
+
+In the case of extra columns existing in the `TableWorkspace
+<TableWorkspace>`__ denoting ``SampleContainer`` information: if the
+``SampleContainer`` isn't a property on the workspace, or the value
+isn't one of the column labels, the value of the ``container`` column
+in the supplied `TableWorkspace <TableWorkspace>`__ will be used
+instead.
+
+For a description of the  `TableWorkspace <TableWorkspace>`__
 see :ref:`PDLoadCharacterizations <algm-PDLoadCharacterizations>`.
 
 .. categories::
diff --git a/docs/source/algorithms/PDLoadCharacterizations-v1.rst b/docs/source/algorithms/PDLoadCharacterizations-v1.rst
index 7d220b3c068ccbe23a85e52a28c72e753a5485ce..0f5737c7b391e8148459c4026e058684ff27565b 100644
--- a/docs/source/algorithms/PDLoadCharacterizations-v1.rst
+++ b/docs/source/algorithms/PDLoadCharacterizations-v1.rst
@@ -51,26 +51,99 @@ and is the same length as ``SpectrumIDs``, ``L2``, ``Polar``, and ``PrimaryFligh
 The second section of the characterizations file is read into the output
 `TableWorkspace <http://www.mantidproject.org/TableWorkspace>`__ as described below.
 
-The :literal:`exp.ini` file is specific to the NOMAD instrument at SNS and is optional.
+A second example from NOMAD demonstrates how to specify different ranges for each focused spectrum as well as the optional wavelength ranges::
+
+  Instrument parameter file: NOMAD_11_22_11.prm
+  1 2 15
+  2 2 31
+  3 2 67
+  4 2 122
+  5 2 154
+  6 2 7
+  L1 19.5
+  #S 1 characterization runs
+  #L frequency(Hz) center_wavelength(angstrom) bank_num vanadium_run empty_run vanadium_back d_min(angstrom) d_max(angstrom) wl_min wl_max
+  60 1.4  1 0 0 0 .31,.25,.13,.13,.13,.42 13.66,5.83,3.93,2.09,1.57,31.42 300.00 16666.67 .1 2.9
+
+The :literal:`exp.ini` file is specific to the NOMAD instrument at SNS
+and is optional. This file is generally discouraged. An example
+version of this file is::
+
+  required *******************
+  Dia 49262
+  DiaBg 49257
+  Vana 49258
+  VanaBg 49086
+  MTc 49257
+  optional ******************
+  recali yes
+  renorm yes
+  autotemp yes
+  scan1 49464
+  scanl 80000
+  Hz    60
+  # IPTS 14821
+
+After realizing that the much of the information in the
+characterizations file is independent of sample environment, a second
+characterization file was designed to add to the information of the
+first. The first line is to indicate the format of the file, and the
+rest is whitespace delimited. There are 6 required columns, everything
+past that is a :literal:`SampleContainer` identifier which will be
+used to override the value that is in the original characterization
+file. The :literal:`frequency` and :literal:`wavelength` columns are
+still used as keys to determine which row contains the run
+identifiers::
+
+  version=1
+  freq wl     van   van_back mt_env mt_instr PAC06 PAC08 PAC10
+  60 0.533   27056   27050     0      0      27044 27032 27038
+  60 1.066   27057   27051     0      0      27045 27033 27039
+  60 1.333   27058   27052     0      0      27046 27034 27040
+  60 2.665   27059   27053     0      0      27047 27035 27041
+  60 3.731   27060   27054     0      0      27048 27036 27042
+  60 4.797   27061   27055     0      0      27049 27037 27043
+  10 3.198   27062       0     0      0          0     0     0
 
 Characterization TableWorkspace
 ###############################
-The columns names and types are described in the following table.
-
-========== =======
-Name       Type
-========== =======
-frequency  double
-wavelength double
-bank       int
-vanadium   int
-container  int
-empty      int
-d_min      str
-d_max      str
-tof_min    double
-tof_max    double
-========== =======
+
+The columns names and types are described in the following table. Any
+missing values are replaced with a zero which will generally skip that
+bit of information.
+
+============== =======
+Name           Type
+============== =======
+frequency      double
+wavelength     double
+bank           int
+vanadium       str
+container      str
+empty          str
+d_min          str
+d_max          str
+tof_min        double
+tof_max        double
+wavelength_min double
+wavelength_max double
+============== =======
+
+There can be any number of additional columns with the
+:literal:`SampleContainer` (with spaces removed) for the column name,
+and type of string.
+
+Usage
+-----
+
+While there are many options for how to use this algorithm, the
+suggestion is to supply the classic and version 1 characterizations in
+a comma separated list as the :literal:`Filename` property.
+
+.. code-block:: python
+
+   filenames = ','.join(['PG3_char_2016_08_01-HR.txt','PG3_char_2016_02_15-PAC-single.txt'])
+   PDLoadCharacterizations(Filename=filenames, OutputWorkspace='char')
 
 .. categories::
 
diff --git a/docs/source/algorithms/ProcessDasNexusLog-v1.rst b/docs/source/algorithms/ProcessDasNexusLog-v1.rst
deleted file mode 100644
index ab7f79c958359be5332cd2c3a042c4daed239145..0000000000000000000000000000000000000000
--- a/docs/source/algorithms/ProcessDasNexusLog-v1.rst
+++ /dev/null
@@ -1,26 +0,0 @@
-.. algorithm::
-
-.. summary::
-
-.. alias::
-
-.. properties::
-
-Description
------------
-
-Some sample logs from DAS are written in the format such that the time
-stamps are the pulse times and the values are time-of-flight. They are
-usually used to record some mono-value sample log such as turning on or
-off of a sample environment device. This algorithm will convert sample
-logs of this time such that the new log will have the time stamp as the
-absolute time, i.e., sum of pulse time and time-of-flight.
-
-This type of DAS sample log won't be generated anymore in NeXus file.  
-Hence algorithm ProcessDasNexusLog is deprecated. 
-
-No usage example is needed for a deprecated algorithm. 
-
-.. categories::
-
-.. sourcelink::
diff --git a/docs/source/algorithms/ProjectMD-v1.rst b/docs/source/algorithms/ProjectMD-v1.rst
index 5e59279a023aff1826094e7af75614fbe677a07e..da7b8b26c33ca3e72a550a492ad41b2cfc4bae39 100644
--- a/docs/source/algorithms/ProjectMD-v1.rst
+++ b/docs/source/algorithms/ProjectMD-v1.rst
@@ -41,7 +41,7 @@ Usage
         print "Name   Bins   Min     Max"
         for dim_index in range(num_dims):
             dim = ws.getDimension(dim_index)
-            print "%s      %i      %.2f   %.2f" % (dim.getName(),
+            print "%s      %i      %.2f   %.2f" % (dim.name,
                  dim.getNBins(), dim.getMinimum(), dim.getMaximum())   
 
     #create a test MD event workspace
diff --git a/docs/source/algorithms/ReflectometryReductionOne-v1.rst b/docs/source/algorithms/ReflectometryReductionOne-v1.rst
index 3105ee03510f0d428a55cc6df07b840e76d65328..22c25541d8d7c4786e282f4f36db3596b1c1abdf 100644
--- a/docs/source/algorithms/ReflectometryReductionOne-v1.rst
+++ b/docs/source/algorithms/ReflectometryReductionOne-v1.rst
@@ -206,6 +206,13 @@ setup remains unchanged for other algorithms that may need to manipulate/use it.
     :height: 250px
     :align: center
 
+
+Processing Instructions
+#######################
+
+These enable a grouping pattern on workspace indices to yield only the detectors of interest. It allows usage of the operators :literal:`,:+-` to specify or exclude specific indices or to add
+spectra together. See :literal:`Grouping Pattern` from :Ref:`algm-GroupDetectors` for further details on their usage.
+
 Usage
 -----
 
diff --git a/docs/source/algorithms/ReplaceSpecialValues-v1.rst b/docs/source/algorithms/ReplaceSpecialValues-v1.rst
index 58b88c9812bb5ea7a8bb3416cf99bd65e18a33bc..e521c7077ad1839768837873d16860340d361067 100644
--- a/docs/source/algorithms/ReplaceSpecialValues-v1.rst
+++ b/docs/source/algorithms/ReplaceSpecialValues-v1.rst
@@ -10,15 +10,15 @@ Description
 -----------
 
 The algorithm searches over all of the values in a workspace and if it
-finds a value set to NaN (not a number), infinity or larger than the
-'big' threshold given then that value and the associated error is
+finds a value set to NaN (not a number), infinity, larger or smaller than the
+'big'/'small' threshold given then that value and the associated error is
 replaced by the user provided values.
 
-If no value is provided for either NaNValue, InfinityValue or
-BigValueThreshold then the algorithm will exit with an error, as in this
+If no value is provided for either NaNValue, InfinityValue, BigValueThreshold 
+or SmallValueThreshold then the algorithm will exit with an error, as in this
 case it would not be checking anything.
 
-Algorithm is now event aware.
+The algorithm can also handle event workspaces. 
 
 Usage
 -----
@@ -35,14 +35,16 @@ Usage
    yArray[1] = float("inf")
    yArray[2] = float("-inf")
    yArray[3] = float("NaN")
+   yArray[4] = 8e-7
    ws.setY(0,yArray)
   
    ws = ReplaceSpecialValues(ws,NaNValue=0,InfinityValue=1000,
-    BigNumberThreshold=1000, BigNumberValue=1000)
+    BigNumberThreshold=1000, BigNumberValue=1000, 
+    SmallNumberThreshold=1e-6, SmallNumberValue=200)
 
    print "i\tBefore\tAfter"   
    print "-\t------\t-----"
-   for i in range(4):
+   for i in range(5):
        print "%i\t%s\t%s" % (i, yArray[i],ws.readY(0)[i])     
  
 Output:
@@ -56,6 +58,32 @@ Output:
     1       inf     1000.0
     2       -inf    1000.0
     3       nan     0.0
+    4       8e-07   200.0
+    
+.. testcode:: replaceSVFloatingPointErrors
+
+    import numpy as np
+    ws = CreateSampleWorkspace(BankPixelWidth=1)
+
+    value1 = 1.00000004
+    value2 = 1.00000003
+    valueDiff = value1 - value2
+    
+    wsYArray = np.array(ws.readY(0))
+    wsYArray[0] = valueDiff
+    ws.setY(0, wsYArray)
+    ws = ReplaceSpecialValues(ws, SmallNumberThreshold=1e-6)
+    
+    print("Before\t\t After")
+    print("{0}\t{1}".format(wsYArray[0], ws.readY(0)[0]))
+    
+Output:
+
+.. testoutput:: replaceSVFloatingPointErrors
+    :options: +NORMALIZE_WHITESPACE
+
+    Before		  After
+    9.99999993923e-09	0.0
 
 
 .. categories::
diff --git a/docs/source/algorithms/SNAPReduce-v1.rst b/docs/source/algorithms/SNAPReduce-v1.rst
new file mode 100644
index 0000000000000000000000000000000000000000..7d79a441b31246feba4be7aa23ab6d68e65f3a07
--- /dev/null
+++ b/docs/source/algorithms/SNAPReduce-v1.rst
@@ -0,0 +1,23 @@
+.. algorithm::
+
+.. summary::
+
+.. alias::
+
+.. properties::
+
+Description
+-----------
+
+The purpose of this algorithm is to do a full reduction of SNAP
+data. This allows several runs, and with all the typical options that
+are usually used at the beamline, including calibrate from a cal file
+and from Convert Units, mask from file workspace and default masks,
+several groupings and save in GSAS or Fullprof format.
+
+Usage
+-----
+
+.. categories::
+
+.. sourcelink::
diff --git a/docs/source/algorithms/Scale-v1.rst b/docs/source/algorithms/Scale-v1.rst
index d32cdb66b0b85017e682e4fbd39163db3b123b6e..3506b2d6e8c8bb68feda54f03e0a797caf5bbb0e 100644
--- a/docs/source/algorithms/Scale-v1.rst
+++ b/docs/source/algorithms/Scale-v1.rst
@@ -23,17 +23,17 @@ Usage
 .. testcode:: ExOffsetScale
 
     ws = CreateSampleWorkspace(BankPixelWidth=1)
-    print "Every 10th bin value of " + ws.getName()
+    print "Every 10th bin value of " + ws.name()
     print ws.readY(0)[0:100:10]
 
     # Add 2 using scale
     wsOffset = Scale(ws,2,"Add")
-    print "Every 10th bin value of " + wsOffset.getName()
+    print "Every 10th bin value of " + wsOffset.name()
     print wsOffset.readY(0)[0:100:10]
 
     # Add 2 using the workspace operator overloads
     wsOffset2 = ws + 2
-    print "Every 10th bin value of " + wsOffset2.getName()
+    print "Every 10th bin value of " + wsOffset2.name()
     print wsOffset2.readY(0)[0:100:10]
 
 Output:
@@ -52,17 +52,17 @@ Output:
 .. testcode:: ExOffsetScale
 
     ws = CreateSampleWorkspace(BankPixelWidth=1)
-    print "Every 10th bin value of " + ws.getName()
+    print "Every 10th bin value of " + ws.name()
     print ws.readY(0)[0:100:10]
 
     # Multiply by 10 using scale
     wsScaled = Scale(ws,10,"Multiply")
-    print "Every 10th bin value of " + wsScaled.getName()
+    print "Every 10th bin value of " + wsScaled.name()
     print wsScaled.readY(0)[0:100:10]
 
     # Multiply by 10 using the workspace operator overloads
     wsScaled2 = ws * 10
-    print "Every 10th bin value of " + wsScaled2.getName()
+    print "Every 10th bin value of " + wsScaled2.name()
     print wsScaled2.readY(0)[0:100:10]
 
 Output:
diff --git a/docs/source/algorithms/SelectPowderDiffPeaks-v1.rst b/docs/source/algorithms/SelectPowderDiffPeaks-v1.rst
deleted file mode 100644
index 78b4409b3ec689e4797efc088f267ad81e619c0a..0000000000000000000000000000000000000000
--- a/docs/source/algorithms/SelectPowderDiffPeaks-v1.rst
+++ /dev/null
@@ -1,25 +0,0 @@
-.. algorithm::
-
-.. summary::
-
-.. alias::
-
-.. properties::
-
-Description
------------
-
-Select the powder diffraction peaks for `Le Bail Fit <Le Bail Fit>`__ 
-by the Z-score of the peak parameters. 
-The peak with parameters that are very different from the others will be removed
-from the list of peaks to do Le Bail Fit. 
-
-This algorithm was implemented as a prototype to calibate powder diffractomter's peak profile.
-It is deprecated because algorithm FitPowderDiffPeaks, which contains the similar functionality,
-has been implemented.  
-
-There won't be any usage example for SelectPowderDiffPeaks because it is deprecated. 
-
-.. categories::
-
-.. sourcelink::
diff --git a/docs/source/algorithms/SetDetScale-v1.rst b/docs/source/algorithms/SetDetScale-v1.rst
index 7da1aa9c9bde39d3a682c510f296cf32d5bd709c..34642442aa6d9c465349397c0e8aa29a77195585 100644
--- a/docs/source/algorithms/SetDetScale-v1.rst
+++ b/docs/source/algorithms/SetDetScale-v1.rst
@@ -13,7 +13,10 @@ Given a PeaksWorkspace or MatrixWorkspace with an instrument, this
 algorithm will set or change the detector bank scales that are used in
 SaveHKL and AnvredCorrection.  The input format is the same as
 used in anvred3.py, so DetScaleList input can be pasted from
-the definition of detScale there.  The default values can be 
+the definition of detScale there.  Alternately, there is an option, DetScaleFile, to
+read a text file with each line containing the detector number and scale factor for that detector.  
+If scales for a detector are given in both the DetScaleList text string and DetScaleFile,
+the values from the text string will be used.  The default values can be 
 set in the instrument parameter file.
 
 Usage
diff --git a/docs/source/algorithms/SetSample-v1.rst b/docs/source/algorithms/SetSample-v1.rst
index bb33da877dfd6a1b23466f36517d7045965cd8dd..10ff85bfa9fd1623a96357189ccfe2fc1ef3c58d 100644
--- a/docs/source/algorithms/SetSample-v1.rst
+++ b/docs/source/algorithms/SetSample-v1.rst
@@ -24,7 +24,7 @@ relate to the respective argument.
 Environment
 ###########
 
-Specifies the sample enviorment kit to be used. There are two required keywords:
+Specifies the sample environment kit to be used. There are two required keywords:
 
 - ``Name``: The name of the predefined kit
 - ``Container``: The id of the container within the predefined kit
@@ -71,14 +71,20 @@ For defining the full shape a key called ``Shape`` specifying the desired shape
 expected along with additional keys specifying the values (all values are assumed to
 be in centimeters):
 
-- ``FlatPlate``: Width, Height, Thick, Center
-- ``Cylinder``: Height, Radius, Center, Axis (X=0, Y=1, Z=2)
-- ``HollowCylinder``: Height, InnerRadius, OuterRadius, Center, Axis(X=0, Y=1, Z=2)
+- ``FlatPlate``: Width, Height, Thick, Center, Angle
+- ``Cylinder``: Height, Radius, Center
+- ``HollowCylinder``: Height, InnerRadius, OuterRadius, Center
 - ``CSG``: Value is a string containing any generic shape as detailed in
   :ref:`HowToDefineGeometricShape`
 
 The ``Center`` key is expected to be a list of three values indicating the :python:`[X,Y,Z]`
-position of the center.
+position of the center. The reference frame of the defined instrument is used to
+set the coordinate system for the shape.
+
+The ``Angle`` argument for a flat plate shape is expected to be in degrees and is defined as
+the angle between the positive beam axis and the normal to the face perpendicular to the
+beam axis when it is not rotated, increasing in an anti-clockwise sense. The rotation is
+performed about the vertical axis of the instrument's reference frame.
 
 Material
 ########
@@ -132,11 +138,11 @@ The following example uses a test file called ``CRYO-01.xml`` in the
 
    # A fake host workspace, replace this with your real one.
    ws = CreateSampleWorkspace()
-   # Use geometry from environment but set differnet height for sample
+   # Use geometry from environment but set different height for sample
    SetSample(ws, Environment={'Name': 'CRYO-01', 'Container': '8mm'},
              Geometry={'Shape': 'HollowCylinder', 'Height': 4.0,
                        'InnerRadius': 0.8, 'OuterRadius': 1.0,
-                       'Center': [0.,0.,0.], 'Axis':1},
+                       'Center': [0.,0.,0.]},
              Material={'ChemicalFormula': '(Li7)2-C-H4-N-Cl6'})
 
 .. categories::
diff --git a/docs/source/algorithms/SliceMDHisto-v1.rst b/docs/source/algorithms/SliceMDHisto-v1.rst
index 1c35317af649fcf70a6da75ea86fbc12b5a6c985..732bef4bd0c7d7842c58c38323e51c4d5cdd5aaa 100644
--- a/docs/source/algorithms/SliceMDHisto-v1.rst
+++ b/docs/source/algorithms/SliceMDHisto-v1.rst
@@ -33,7 +33,7 @@ Usage
         print "Name   Bins   Min     Max"
         for dim_index in range(num_dims):
             dim = ws.getDimension(dim_index)
-            print "%s      %i      %.2f   %.2f" % (dim.getName(),
+            print "%s      %i      %.2f   %.2f" % (dim.name,
                  dim.getNBins(), dim.getMinimum(), dim.getMaximum())   
 
     #create a test MD event workspace
diff --git a/docs/source/algorithms/SofQWMomentsScan-v1.rst b/docs/source/algorithms/SofQWMomentsScan-v1.rst
new file mode 100644
index 0000000000000000000000000000000000000000..643c8fc903a1549a82af5d002a4d144f8acc0ced
--- /dev/null
+++ b/docs/source/algorithms/SofQWMomentsScan-v1.rst
@@ -0,0 +1,30 @@
+.. algorithm::
+
+.. summary::
+
+.. alias::
+
+.. properties::
+
+Description
+-----------
+
+Performs a data reduction from :ref:`ISISIndirectEnergyTransfer <algm-ISISIndirectEnergyTransfer>`,
+before performing the :ref:`SofQW <algm-SofQW>` algorithm and :ref:`SofQWMoments <algm-SofQWMoments>`.
+Width and diffusion workspaces are then created.
+
+Usage
+-----
+
+.. include:: ../usagedata-note.txt
+
+**Example - Running SofQWMoments from with an SofQW workspace.**
+
+.. code-block:: python
+
+    reduced, sqw, moments = SofQWMomentsScan(InputFiles='OSIRIS100320', LoadLogFiles=False, Instrument='OSIRIS', Analyser='graphite', Reflection='002', SpectraRange='3,53',
+                                           QRange='0,0.1,2', EnergyRange='-0.4,0.01,0.4')
+
+.. categories::
+
+.. sourcelink::
diff --git a/docs/source/algorithms/Stitch1D-v3.rst b/docs/source/algorithms/Stitch1D-v3.rst
index af4b441e952d7313f0e80a42ded08229a3e645ef..010ebcdb32a900f7de9c9288609b80103db4dd53 100644
--- a/docs/source/algorithms/Stitch1D-v3.rst
+++ b/docs/source/algorithms/Stitch1D-v3.rst
@@ -10,27 +10,64 @@ Description
 -----------
 
 Stitches single histogram :ref:`Matrix Workspaces <MatrixWorkspace>`
-together outputting a stitched Matrix Workspace. Either the
-right-hand-side or left-hand-side workspace can be chosen to be scaled.
-Users must provide a Param step (single value), but the binning start
-and end are calculated from the input workspaces if not provided.
-Likewise, StartOverlap and EndOverlap are optional. If the StartOverlap
-or EndOverlap are not provided, then these are taken to be the region of
-x-axis intersection.
-
-The workspaces must be histogrammed. Use
-:ref:`algm-ConvertToHistogram` on workspaces prior to
-passing them to this algorithm.
-
-**Special Value Processing**
-
-Special values, meaning infinite and NaN double precision values, are treated in a different way by the algorithm. The processing is as follows:
-
-#. The workspaces are initially rebinned, as prescribed by the rebin Params (determined automatically if not provided)
-#. Each spectra is searched for signal values and error values that are special values. Positions and type of special value are recorded
-#. Special values found in the previous step are set to zero
-#. Stitching proceeds, integration will not be performed considering any special values
-#. Post processing the indexes of the special values are used to put the special values back where they came from
+together outputting a stitched Matrix Workspace. Note that workspaces must be histogrammed, you may
+want to use :ref:`algm-ConvertToHistogram` on workspaces prior to passing them to this algorithm.
+
+Either the right-hand-side or left-hand-side workspace can be chosen to be scaled.
+Users can optionally provide :ref:`algm-Rebin` :literal:`Params`, otherwise they are calculated from the input workspaces.
+Likewise, :literal:`StartOverlap` and :literal:`EndOverlap` are optional. If not provided, then these
+are taken to be the region of X-axis intersection.
+
+The algorithm workflow is as follows:
+
+#. The workspaces are initially rebinned, as prescribed by the rebin :literal:`Params`. Note that
+   rebin parameters are determined automatically if not provided. In this case, the step size is
+   taken from the step size of the LHS workspace (or from the RHS workspace if :literal:`ScaleRHSWorkspace`
+   was set to false) and rebin boundaries are taken from the minimum X value in the LHS workspace
+   and the maximum X value in the RHS workspace respectively.
+#. After rebinning, each spectrum is searched for special values. Special values refer to signal
+   (Y) and error (E) values that are either infinite or NaN. These special values are masked out
+   as zeroes and their positions are recorded for later reinsertion.
+#. Next, if :literal:`UseManualScaleFactor` was set to false, both workspaces will be integrated
+   according to the integration range defined by :literal:`StartOverlap` and :literal:`EndOverlap`.
+   Note that the integration is performed without special values, as those have been masked out
+   in the previous step. The scale factor is then calculated as the quotient of the integral of
+   the left-hand-side workspace by the integral of the right-hand-side workspace (or the quotient
+   of the right-hand-side workspace by the left-hand-side workspace if :literal:`ScaleRHSWorkspace`
+   was set to false), and the right-hand-side workspace (left-hand-side if :literal:`ScaleRHSWorkspace`
+   was set to false) is multiplied by the calculated factor.
+#. Alternatively, if :literal:`UseManualScaleFactor` was set to true, the scale factor is applied
+   to the right-hand-side workspace (left-hand-side workspace if :literal:`ScaleRHSWorkspace` was
+   set to false).
+#. The weighted mean of the two workspaces in range [:literal:`StartOverlap`, :literal:`EndOverlap`]
+   is calculated. Note that if both workspaces have zero errors, an un-weighted mean will be
+   performed instead.
+#. The output workspace will be created by summing the left-hand-side workspace (values in range
+   [:literal:`StartX`, :literal:`StartOverlap`], where :literal:`StartX` is the minimum X value
+   specified via :literal:`Params` or calculated from the left-hand-side workspace) + weighted
+   mean workspace + right-hand-side workspace (values in range [:literal:`EndOverlap`, :literal:`EndX`],
+   where :literal:`EndX` is the maximum X value specified via :literal:`Params` or calculated
+   from the right-hand-side workspace) multiplied by the scale factor.
+#. The special values are put back in the output workspace. Note that if both the left-hand-side
+   workspace and the right-hand-side workspace happen to have a different special value in the same bin, this
+   bin will be set to infinite in the output workspace.
+
+Below is a flowchart illustrating the steps in the algorithm (it assumes :literal:`ScaleRHSWorkspace`
+is true). Figure on the left corresponds
+to the workflow when no scale factor is provided, while figure on the right corresponds to
+workflow with a manual scale factor specified by the user.
+
+.. diagram:: Stitch1D-v3.dot
+
+Error propagation
+#################
+
+Errors are are handled and propagated in every step according to :ref:`Error Propagation`. This
+includes every child algorithm: :ref:`algm-Rebin`, :ref:`algm-Integration`, :ref:`algm-Divide`,
+:ref:`algm-Multiply` and :ref:`algm-WeightedMean`. In particular, when the scale factor is calculated
+as the quotient of the left-hand-side integral and the right-hand-side integral, the result is
+a number with an error associated, and therefore the multiplication of the right-hand-side
+workspace by this number takes into account its error.
 
 Usage
 -----
diff --git a/docs/source/algorithms/Stitch1DMany-v1.rst b/docs/source/algorithms/Stitch1DMany-v1.rst
index e83ee576ca2495a3ff69ee98465af7103530d944..b8abdf4079f74fd2442dcc9b50cd3384949e6ce9 100644
--- a/docs/source/algorithms/Stitch1DMany-v1.rst
+++ b/docs/source/algorithms/Stitch1DMany-v1.rst
@@ -23,9 +23,15 @@ The workspaces must be histogrammed. Use
 :ref:`algm-ConvertToHistogram` on workspaces prior to
 passing them to this algorithm.
 
+This algorithm is also capable of stitching together matrix workspaces
+from multiple workspace groups. In this case, each group must contain the
+same number of workspaces. The algorithm will stitch together the workspaces
+in the first group before stitching workspaces from the next group on top
+of the previous ones.
+
 Usage
 -----
-**Example - a basic example using Stitch1DMany to stitch two workspaces together.**
+**Example - a basic example using Stitch1DMany to stitch three workspaces together.**
 
 .. testcode:: ExStitch1DManySimple
 
@@ -35,15 +41,17 @@ Usage
       """Creates a gaussian peak centered on mu and with width sigma."""
       return (1/ sigma * np.sqrt(2 * np.pi)) * np.exp( - (x-mu)**2  / (2*sigma**2))
 
-    #create two histograms with a single peak in each one
+    # Create three histograms with a single peak in each one
     x1 = np.arange(-1, 1, 0.02)
     x2 = np.arange(0.4, 1.6, 0.02)
+    x3 = np.arange(1.3, 3, 0.02)
     ws1 = CreateWorkspace(UnitX="1/q", DataX=x1, DataY=gaussian(x1[:-1], 0, 0.1)+1)
     ws2 = CreateWorkspace(UnitX="1/q", DataX=x2, DataY=gaussian(x2[:-1], 1, 0.05)+1)
+    ws3 = CreateWorkspace(UnitX="1/q", DataX=x3, DataY=gaussian(x3[:-1], 2, 0.08)+1)
 
-    #stitch the histograms together
-    workspaces = ws1.name() + "," + ws2.name()
-    stitched, scale = Stitch1DMany(InputWorkspaces=workspaces, StartOverlaps=[0.4], EndOverlaps=[0.6], Params=[0.02])
+    # Stitch the histograms together
+    workspaces = ws1.name() + "," + ws2.name() + "," + ws3.name()
+    stitched, scale = Stitch1DMany(InputWorkspaces=workspaces, StartOverlaps=[0.4, 1.2], EndOverlaps=[0.6, 1.4], Params=[0.02])
 
 Output:
 
@@ -52,18 +60,41 @@ Output:
    :alt: Stitch1D output
    :align: center
 
-**Example - a practical example using reflectometry data and a scale factor.**
+**Example - another example using three group workspaces of two workspaces each.**
 
 .. testcode:: ExStitch1DPractical
 
-  trans1 = Load('INTER00013463')
-  trans2 = Load('INTER00013464')
+    import numpy as np
 
-  trans1_wav = CreateTransmissionWorkspaceAuto(trans1)
-  trans2_wav = CreateTransmissionWorkspaceAuto(trans2)
+    def gaussian(x, mu, sigma):
+      """Creates a gaussian peak centered on mu and with width sigma."""
+      return (1/ sigma * np.sqrt(2 * np.pi)) * np.exp( - (x-mu)**2  / (2*sigma**2))
 
-  workspaces = trans1_wav.name() + ',' + trans2_wav.name()
-  stitched_wav, y = Stitch1DMany(workspaces, params='1, 0.05, 17', UseManualScaleFactor=True, ManualScaleFactor=0.85)
+    # Create six histograms with a single peak in each one
+    x1 = np.arange(-1, 1, 0.02)
+    x3 = np.arange(0.3, 1.8, 0.02)
+    x5 = np.arange(1.4, 2.8, 0.02)
+    x2 = np.arange(2.4, 3.5, 0.02)
+    x4 = np.arange(3.2, 4.9, 0.02)
+    x6 = np.arange(4.5, 5.2, 0.02)
+    ws1 = CreateWorkspace(UnitX="1/q", DataX=x1, DataY=gaussian(x1[:-1], 0, 0.1)+1)
+    ws3 = CreateWorkspace(UnitX="1/q", DataX=x3, DataY=gaussian(x3[:-1], 1, 0.05)+1)
+    ws5 = CreateWorkspace(UnitX="1/q", DataX=x5, DataY=gaussian(x5[:-1], 2, 0.12)+1)
+    ws2 = CreateWorkspace(UnitX="1/q", DataX=x2, DataY=gaussian(x2[:-1], 3, 0.08)+1)
+    ws4 = CreateWorkspace(UnitX="1/q", DataX=x4, DataY=gaussian(x4[:-1], 4, 0.06)+1)
+    ws6 = CreateWorkspace(UnitX="1/q", DataX=x6, DataY=gaussian(x6[:-1], 5, 0.04)+1)
+
+    # Group first, second and third pairs of workspaces
+    groupWSNames1 = ws1.name() + "," + ws2.name()
+    gws1 = GroupWorkspaces(InputWorkspaces=groupWSNames1)
+    groupWSNames2 = ws3.name() + "," + ws4.name()
+    gws2 = GroupWorkspaces(InputWorkspaces=groupWSNames2)
+    groupWSNames3 = ws5.name() + "," + ws6.name()
+    gws3 = GroupWorkspaces(InputWorkspaces=groupWSNames3)
+
+    # Stitch together workspaces from each group
+    workspaceNames = gws1.name() + "," + gws2.name() + "," + gws3.name()
+    stitched, scale = Stitch1DMany(InputWorkspaces=workspaceNames, StartOverlaps=[0.3, 1.4], EndOverlaps=[3.3, 4.6], Params=[0.02])
 
 Output:
 
diff --git a/docs/source/algorithms/TOSCABankCorrection-v1.rst b/docs/source/algorithms/TOSCABankCorrection-v1.rst
index 22fee78069ae00a94287f9a423d0964dfdfe89dc..21a1da9a677f5faa15638beb7bb632d46cc22292 100644
--- a/docs/source/algorithms/TOSCABankCorrection-v1.rst
+++ b/docs/source/algorithms/TOSCABankCorrection-v1.rst
@@ -77,7 +77,7 @@ Output:
 
 .. testoutput:: ExTOSCABankCorrectionAutomatic
 
-    Target peak centre: 1077
+    Target peak centre: 1080
 
 **Example - Manual peak selection.**
 
@@ -95,6 +95,6 @@ Output:
 
 .. testoutput:: ExTOSCABankCorrectionManual
 
-    Target peak centre: 713
+    Target peak centre: 714
 
 .. categories::
diff --git a/docs/source/algorithms/TransposeMD-v1.rst b/docs/source/algorithms/TransposeMD-v1.rst
index 501eb76c91300c3eae70e527c57be523e94e64f6..479c69a0515e635cf711c48fa7d90a05578506b1 100644
--- a/docs/source/algorithms/TransposeMD-v1.rst
+++ b/docs/source/algorithms/TransposeMD-v1.rst
@@ -21,7 +21,7 @@ Usage
 
    def print_dims(ws):
        for i in range(ws.getNumDims()):
-           print 'Dimension %i is %s' % (i, ws.getDimension(i).getName())
+           print 'Dimension %i is %s' % (i, ws.getDimension(i).name)
 
    mdws = CreateMDWorkspace(Dimensions=3, Extents='-10,10,-10,10,-10,10', Names='A,B,C',          Units='U,U,U')
    FakeMDEventData(InputWorkspace=mdws, PeakParams='500000,0,0,0,3')
diff --git a/docs/source/algorithms/VesuvioDiffractionReduction-v1.rst b/docs/source/algorithms/VesuvioDiffractionReduction-v1.rst
index 25bd1dbfb2fed755360b224c9390d0d2546217b2..ac432b2b94c3e13022be0c036650d0aa69fbfac4 100644
--- a/docs/source/algorithms/VesuvioDiffractionReduction-v1.rst
+++ b/docs/source/algorithms/VesuvioDiffractionReduction-v1.rst
@@ -27,13 +27,13 @@ Usage
 
 .. testcode:: ExVesuvioDiffractionReductionSimple
 
-    VesuvioDiffractionReduction(InputFiles='EVS15289.raw',
+    VesuvioDiffractionReduction(InputFiles='15289',
                             OutputWorkspace='DiffractionReductions',
                             InstrumentParFile='IP0005.dat')
 
     ws = mtd['DiffractionReductions'].getItem(0)
 
-    print 'Workspace name: %s' % ws.getName()
+    print 'Workspace name: %s' % ws.name()
     print 'Number of spectra: %d' % ws.getNumberHistograms()
     print 'Number of bins: %s' % ws.blocksize()
 
diff --git a/docs/source/algorithms/VisionLoadDetectorTable-v1.rst b/docs/source/algorithms/VisionLoadDetectorTable-v1.rst
deleted file mode 100644
index fce9ae6bf565f7d4bca43c966ffcc6b754f11861..0000000000000000000000000000000000000000
--- a/docs/source/algorithms/VisionLoadDetectorTable-v1.rst
+++ /dev/null
@@ -1,23 +0,0 @@
-.. algorithm::
-
-.. summary::
-
-.. alias::
-
-.. properties::
-
-Description
------------
-
-This algorithm is used to load the detector parameters for VISION
-from a CSV file into a TableWorkspace.
-
-.. Note::
-
-        Do not use this algortithm, it is just for VISION commissioning
-
-
-.. categories::
-
-.. sourcelink::
-
diff --git a/docs/source/api/python/mantid/kernel/LiveListenerInfo.rst b/docs/source/api/python/mantid/kernel/LiveListenerInfo.rst
new file mode 100644
index 0000000000000000000000000000000000000000..51572389cc864bfdaec97070be20646d537b3255
--- /dev/null
+++ b/docs/source/api/python/mantid/kernel/LiveListenerInfo.rst
@@ -0,0 +1,14 @@
+==================
+ LiveListenerInfo
+==================
+
+This a python binding to the C++ class Mantid::Kernel::LiveListenerInfo.
+
+
+.. module:`mantid.kernel`
+
+.. autoclass:: mantid.kernel.LiveListenerInfo 
+    :members:
+    :undoc-members:
+    :inherited-members:
+
diff --git a/docs/source/concepts/ErrorPropagation.rst b/docs/source/concepts/ErrorPropagation.rst
index c45bfd1fa1b9f4cbabf28c69c6998835f9494766..6a5f084056344e9b4d3a9a7be6f806fdb88a8faa 100644
--- a/docs/source/concepts/ErrorPropagation.rst
+++ b/docs/source/concepts/ErrorPropagation.rst
@@ -3,62 +3,66 @@
 Error Propagation
 =================
 
-The purpose of this document is to explain how Mantid deals with Error
-Propogation and how it is used in its algorithms.
+The purpose of this document is to explain how Mantid deals with error
+propagation and how it is used in its algorithms.
 
 Theory
 ------
 
-In order to deal with error propagation, Mantid treats errors as guassian 
-probabilities (also known as a bell curve or normal probabilities) and each 
-observation as independent. Meaning that if X = 100 +- 1 then it is still 
-possible for a value of 102 to occur, but less likely than 101 or 99, and a 
-value of 105 is far less likely still than any of these values.
+In order to deal with error propagation, Mantid treats errors as Gaussian
+probabilities (also known as a bell curve or normal probabilities) and each
+observation as independent. Meaning that if :math:`X = 100 \pm 1` then it is still
+possible for a value of :math:`102` to occur, but less likely than :math:`101`
+or :math:`99`, and a value of :math:`105` is far less likely still than any of
+these values.
 
 Plus and Minus Algorithm
 ------------------------
 
-The plus algorithm adds a selection of datasets together, including their 
-margin of errors. Mantid has to therefore adapt the margin of error so it 
-continues to work with just one margin of error. The way it does this is by 
-simply adding together the certain values. Consider the example where: 
-X\ :sub:`1` = 101 ± 2 and X\ :sub:`2` = 99 ± 2. Then for the Plus algorithm
+The :ref:`algm-Plus` algorithm adds two datasets together, propagating the
+uncertainties. Mantid calculates the result of :math:`X_1 + X_2` as
 
-X = 200 = (101 + 99).
+:math:`X = X_1 + X_2`
 
-The propagated error is calculated by taking the root of the sum of the 
-squares of the two error margins:
+with uncertainty
 
-(√2:sup:`2` + 2\ :sup:`2`) = √8
+:math:`\sigma_X = \sqrt{ \left( \sigma_{X_1} \right)^2 + \left( \sigma_{X_2} \right)^2 }`.
 
-Hence the result of the Plus algorithm can be summarised as:
+Consider the example where :math:`X_1 = 101 \pm 2` and :math:`X_2 = 99 \pm 2`.
+Then for this algorithm:
 
-X = 200 ± √8
+:math:`X = X_1 + X_2 = 101 + 99 = 200`
 
-Mantid deals with the Minus algorithm similarly.
+:math:`\sigma_X = \sqrt{ 2^2 + 2^2} = \sqrt{8} = 2.8284`
 
-Multiply and Divide Algorithm
------------------------------
+Hence the result of :ref:`algm-Plus` can be summarised as :math:`X = 200 \pm \sqrt{8}`.
+
+Mantid deals with the :ref:`algm-Minus` algorithm similarly: the result of :math:`X_1 - X_2` is
 
-The Multiply and Divide Algorithm work slightly different from the Plus
-and Minus Algorithms, in the sense that they have to be more complex, 
-see also `here <http://en.wikipedia.org/wiki/Propagation_of_uncertainty>`_.
+:math:`X = X_1 - X_2`
 
-To calculate error propagation, of say X\ :sub:`1` and X\ :sub:`2`.
-X\ :sub:`1` = 101 ± 2 and X\ :sub:`2` = 99 ± 2 ,Mantid would
-undertake the following calculation for divide:
+with error
 
-Q = X\ :sub:`1`/X:sub:`2` = 101/99
+:math:`\sigma_X = \sqrt{ \left( \sigma_{X_1} \right)^2 + \left( \sigma_{X_2} \right)^2 }`.
+
+Multiply and Divide Algorithm
+-----------------------------
 
-Error Propogation = (√ ± 2/99 + ±2/101) All multiplied by Q = 0.22425
+The :ref:`algm-Multiply` and :ref:`algm-Divide` algorithms propagate the uncertainties according
+to (see also `here <http://en.wikipedia.org/wiki/Propagation_of_uncertainty>`_):
 
-For the multiply algorithm, the only difference is in how Q is created,
-which in turn affects the Error Propogation,
+:math:`\sigma_X = \left|X\right| \sqrt{ \left( \frac{\sigma_{X_1}}{X_1} \right)^2 + \left( \frac{\sigma_{X_2}}{X_2} \right)^2 }`,
 
-Q = X\ :sub:`1`\ \*X\ :sub:`2` = 101\*99
+where :math:`X` is the result of the multiplication, :math:`X = X_1 \cdot X_2`, or the division, :math:`X = X_1 / X_2`.
 
-Error Propogation = (√ ± 2/99 + ±2/101) All multiplied by Q = 0.22425
+Considering the example above where :math:`X_1 = 101 \pm 2` and
+:math:`X_2 = 99 \pm 2`. Mantid would calculate the result of :math:`X_1 / X_2` as
+:math:`X = 101 / 99 = 1.0202`, with uncertainty
+:math:`\sigma_X = 1.0202 \sqrt{ \left(2/101\right)^2 + \left(2/99\right)^2} = 0.0288`.
 
+For :ref:`algm-Multiply`, the result of :math:`X_1 \times X_2` is
+:math:`X = 101 \times 99 = 9999`, with uncertainty
+:math:`\sigma_X = 9999 \sqrt{ \left(2/101\right)^2 + \left(2/99\right)^2} = 282.8568`.
 
 
-.. categories:: Concepts
\ No newline at end of file
+.. categories:: Concepts
diff --git a/docs/source/concepts/EventWorkspace.rst b/docs/source/concepts/EventWorkspace.rst
index 0c24d64a32b6ef35e789f86294ed3c83b46dfc28..317f0656297f0a6b59132e9809c3cf1f1b95822e 100644
--- a/docs/source/concepts/EventWorkspace.rst
+++ b/docs/source/concepts/EventWorkspace.rst
@@ -59,7 +59,7 @@ If you want to check if a variable points to something that is an Event Workspac
     eventWS = CreateSampleWorkspace(WorkspaceType="Event")
 
     if isinstance(eventWS, IEventWorkspace):
-        print eventWS.getName() + " is an " + eventWS.id()
+        print eventWS.name() + " is an " + eventWS.id()
 
 Output:
 
diff --git a/docs/source/concepts/FittingMinimizers.rst b/docs/source/concepts/FittingMinimizers.rst
index f84d77dc47f481a14b97f3e955dbc3e2a50be734..b75e6177ef150809cecc71e9fba830c9f0354147 100644
--- a/docs/source/concepts/FittingMinimizers.rst
+++ b/docs/source/concepts/FittingMinimizers.rst
@@ -1,4 +1,26 @@
-.. _FittingMinimizers:
+.. _FittingMinimizers:
+
+Which minimizers to use with Mantid
+===================================
+
+Below are listed the current recommendations for which minimizers to use with Mantid:
+
+* By default Mantid uses Levenberg-Marquardt
+
+  We can also recommend Trust Region, in particular where stability is important
+* For Bayesian analysis, we currently support only one minimizer, which is FABADA
+
+The above recommendations are based on the results presented in the sections
+following this section.
+
+We hope to be able to provide recommendations for subsets of neutron
+fitting problems, such as for constrained problems in the future.
+However, to help us facilitate this, please let us know if you have
+any fitting problems that you would like to share.
+
+Further, if you think you have a bright idea for a new minimizer please
+do not hesitate to either let us know or test out your idea yourself
+using the fit benchmarking tests discussed below.
 
 Comparing Minimizers
 ====================
@@ -25,25 +47,16 @@ Several minimizers are included with Mantid and can be selected in the
 or when using the algorithm :ref:`Fit <algm-Fit>` The following
 options are available:
 
-- `Simplex <https://en.wikipedia.org/wiki/Nelder%E2%80%93Mead_method>`__
-- `SteepestDescent <https://en.wikipedia.org/wiki/Gradient_descent>`__
-- `Conjugate gradient (Fletcher-Reeves imp.) <https://en.wikipedia.org/wiki/Nonlinear_conjugate_gradient_method>`__
-- `Conjugate gradient (Polak-Ribiere imp.) <https://en.wikipedia.org/wiki/Nonlinear_conjugate_gradient_method>`__
-- `BFGS (Broyden-Fletcher-Goldfarb-Shanno) <https://en.wikipedia.org/wiki/Broyden–Fletcher–Goldfarb–Shanno_algorithm>`__
-- `Levenberg-Marquardt <https://en.wikipedia.org/wiki/Levenberg-Marquardt_algorithm>`__ (default)
-- Levenberg-MarquardtMD
-
-  A `Levenberg-Marquardt <https://en.wikipedia.org/wiki/Levenberg-Marquardt_algorithm>`__ implementation generalised to allow different cost functions, and supporting chunking techniques for large datasets.
-- Damping 
-
-  A `Gauss-Newton <https://en.wikipedia.org/wiki/Gauss–Newton_algorithm#Improved_versions>`__ algorithm with damping.
+- `Simplex <../fitminimizers/Simplex.html>`__
+- `SteepestDescent <../fitminimizers/GradientDescent.html>`__
+- `Conjugate gradient (Fletcher-Reeves imp.) <../fitminimizers/FletcherReeves.html>`__
+- `Conjugate gradient (Polak-Ribiere imp.) <../fitminimizers/PolakRibiere.html>`__
+- `BFGS (Broyden-Fletcher-Goldfarb-Shanno) <../fitminimizers/BFGS.html>`__
+- `Levenberg-Marquardt <../fitminimizers/LevenbergMarquardt.html>`__ (default)
+- `Levenberg-MarquardtMD <../fitminimizers/LevenbergMarquardtMD.html>`__
+- `Damped Gauss-Newton <../fitminimizers/DampedGaussNewton.html>`__
 - :ref:`FABADA <FABADA>`
-- `Trust region
-  <https://ccpforge.cse.rl.ac.uk/gf/project/ral_nlls>`__: a `trust
-  region algorithm <https://en.wikipedia.org/wiki/Trust_region>`__ that,
-  at each iteration, calculates and returns the step that reduces the
-  model by an acceptable amount by solving (or approximating a
-  solution to) the trust-region subproblem
+- `Trust region <../fitminimizers/TrustRegion.html>`__
 
 All these algorithms are `iterative
 <https://en.wikipedia.org/wiki/Iterative_method>`__.  The *Simplex*
@@ -63,7 +76,7 @@ information of the cost function (second-order partial derivatives of
 a Hessian matrix). Some algorithms like BFGS approximate the Hessian by the
 gradient values of successive iterations. The Levenberg-Marquard
 algorithm is a modified Gauss-Newton that introduces an adaptive term
-to prevent unstability when the approximated Hessian is not positive
+to prevent instability when the approximated Hessian is not positive
 defined. An in-depth description of the methods is beyond the scope of
 these pages. More information can be found from the links and general
 references on optimization methods such as [Kelley1999]_ and
@@ -138,7 +151,7 @@ following information:
 - Initial values (starting point) of the function parameters
 - Optional: reference best values for the parameters (some may refer to these as certified values), i.e. target parameter values for the minimizers   
 
-The current problems have been obtained from the following benchmarks and sources:
+The current problems have been obtained from the following sources:
 
 - `NIST nonlinear regression problems
   <http://itl.nist.gov/div898/strd/general/dataarchive.html>`__.
diff --git a/docs/source/concepts/InstrumentAccessLayers.rst b/docs/source/concepts/InstrumentAccessLayers.rst
new file mode 100644
index 0000000000000000000000000000000000000000..45aba7673070ed57e43e1664fcb84318122349ea
--- /dev/null
+++ b/docs/source/concepts/InstrumentAccessLayers.rst
@@ -0,0 +1,246 @@
+.. _InstrumentAccessLayers:
+
+===================================================
+Instrument Access via SpectrumInfo and DetectorInfo
+===================================================
+
+.. contents::
+  :local:
+
+Introduction
+------------
+
+There are two new layers to access instrument information, ``SpectrumInfo`` and ``DetectorInfo``, that are going to be introduced to Mantid as part of the work towards Instrument 2.0. Eventually these classes will store commonly accessed information about spectra or detectors, namely masking, monitor flags, L1, L2, 2-theta and position, leading to improved performance and cleaner code.
+
+A spectrum corresponds to (a group of) one or more detectors. Most algorithms work with spectra and thus ``SpectrumInfo`` would be used. Some algorithms work on a lower level (with individual detectors) and thus ``DetectorInfo`` would be used.
+
+In many cases direct access to ``Instrument`` can be removed by using these layers. This will also help in moving to using indexes for enumeration, and only working with IDs for user-facing input.
+
+Current Status
+##############
+
+``SpectrumInfo`` and ``DetectorInfo`` are currently implemented as wrapper classes in Mantid. Using the new interfaces everywhere now will help with the eventual rollout of Instrument 2.0. It also provides cleaner code and will help with the rollout of planned indexing changes. It is also necessary to provide the addition of time indexing, required to support scanning instruments.
+
+SpectrumInfo
+____________
+
+``SpectrumInfo`` can be obtained from a call to ``MatrixWorkspace::spectrumInfo()``. The wrapper class holds a reference to a ``DetectorInfo`` object and calls through to this for access to information on masking, monitor flags etc.
+
+DetectorInfo
+____________
+
+``DetectorInfo`` can be obtained from a call to ``ExperimentInfo::detectorInfo()`` (usually this method would be called on ``MatrixWorkspace``). The wrapper class holds a reference to the parametrised instrument for retrieving the relevant information.
+
+There is also a partial implementation of the "real" ``DetectorInfo`` class, in the ``Beamline`` namespace. The real class currently stores the masking information for a detector. The wrapper ``DetectorInfo`` class holds a reference to the real class. This does not affect the rollout, where the wrapper class should still be used in all cases.
+
+Changes for Rollout
+-------------------
+
+Performance Tests
+#################
+
+Before starting the refactoring work please take a look at the state of any performance tests that exist for the algorithms. If they exist they should be run to get the "before" timings. If they do not exist please add performance test for any algorithms that are widely used, or might be expected to have a performance increase. See `this performance test <https://github.com/mantidproject/mantid/pull/18189/files#diff-5695221d30495359738f90b83ceb0ba3>`_ added for the ``SpectrumInfo`` rollout for an example of adding such a test.
+
+Each PR should include the runtime metrics for the algorithms changed, so that improvements can be captured for the release notes.
+
+SpectrumInfo
+############
+
+Basics
+______
+
+All instances of ``MatrixWorkspace::getDetector()`` should be replaced using calls to the ``SpectrumInfo`` object obtained from ``MatrixWorkspace::spectrumInfo()``. The methods below can then be called on `SpectrumInfo` instead of on the detector.
+
+* ``isMonitor(wsIndex)``
+* ``isMasked(wsIndex)``
+* ``l2(wsIndex)``
+* ``twoTheta(wsIndex)``
+* ``signedTwoTheta(wsIndex)``
+* ``position(wsIndex)``
+
+The try/catch pattern for checking if a spectrum has a detector might look something like the following before/after example.
+
+**Before refactoring**
+
+.. code-block:: c++
+
+  try {
+    Geometry::IDetector_const_sptr det = ws.getDetector(wsIndex);
+    // do stuff
+  catch (Exception::NotFoundError &) {
+    // do exception
+    return false;
+  }
+
+**After - check it has some detectors**
+
+.. code-block:: c++
+
+  #include "MantidAPI/SpectrumInfo.h"
+
+  ...
+
+  const auto &spectrumInfo = ws->spectrumInfo();
+
+  if (spectrumInfo.hasDetectors(wsIndex)) {
+    // do stuff
+  } else {
+    // do exception
+    return false;
+  }
+
+In this case, which is generally more common, the check is for at least one detector. It is also possible to check for the existence of a unique detector, see the alternative after example below.
+
+**After - check for a unique detector**
+
+.. code-block:: c++
+
+  #include "MantidAPI/SpectrumInfo.h"
+
+  ...
+
+  const auto &spectrumInfo = ws->spectrumInfo();
+
+  if (!spectrumInfo.hasUniqueDetector(wsIndex)) {
+    // do exception
+    return false;
+  }
+
+  // do stuff
+
+
+Access to Detectors
+___________________
+
+The ``detector(wsIndex)`` method on ``SpectrumInfo`` returns the parameterised detector or detector group for the workspace. As ``SpectrumInfo`` does not provide access to things like ``Object::solidAngle()``, the ``detector()`` method on ``SpectrumInfo`` can be used to get access to these methods.
+
+Mutable SpectrumInfo
+____________________
+
+The method ``MatrixWorkspace::mutableSpectrumInfo()`` returns a non-const ``SpectrumInfo`` object. Currently the only method that this access is required for is ``SpectrumInfo::setMasked(const size_t index, bool masked)``.
+
+Useful Tips
+___________
+
+* Creation of ``SpectrumInfo`` objects is not cheap. Make sure ``ws.spectrumInfo()`` is called outside of loops that go over all spectra.
+* If a ``SpectrumInfo`` object is required for more than one workspace then include the workspace name in the name of the ``SpectrumInfo`` object, to avoid confusion.
+* Get the ``SpectrumInfo`` object as a const reference and use auto - ``const auto &spectrumInfo = ws->spectrumInfo();``.
+* Do not forget to add the import - ``#include "MantidAPI/SpectrumInfo.h"``.
+
+Complete Examples
+_________________
+
+* `FindCenterOfMassPosition2.cpp <https://github.com/mantidproject/mantid/pull/17394/files#diff-905c244467474fc320eaf3b8c7a9f0dd>`_
+
+* `CreatePSDBleedMask.cpp <https://github.com/mantidproject/mantid/pull/18218/files#diff-f490acf06e76f93898dc7d486c8dfa93>`_
+
+* `HRPDSlabCanAbsorption.cpp <https://github.com/mantidproject/mantid/pull/18464/files#diff-fc151838d9d7cc2e4ea469e98472c791>`_
+
+DetectorInfo
+############
+
+Basics
+______
+
+The conversion is similar to that for ``SpectrumInfo``. For ``DetectorInfo`` all instances of ``Instrument::getDetector()`` should be replaced using calls to the ``DetectorInfo`` object obtained from ``MatrixWorkspace::detectorInfo()``. The methods below can then be called on ``DetectorInfo`` instead of on the detector.
+
+* ``isMonitor(detIndex)``
+* ``isMasked(detIndex)``
+* ``l2(detIndex)``
+* ``twoTheta(detIndex)``
+* ``signedTwoTheta(detIndex)``
+* ``position(detIndex)``
+
+**Indexing**
+
+The ``DetectorInfo`` object is accessed by an index going from 0 to the number of detectors. A vector of detector IDs can be obtained from a call to ``detectorInfo.detectorIDs()``.
+
+It is also possible to use the method ``detectorInfo.indexOf(detID)`` to get the index for a particular detector ID. However, this is a call to a lookup in an unordered map, so is an expensive calculation which should be avoided where possible.
+
+Below is an example refactoring.
+
+**Before refactoring**
+
+.. code-block:: c++
+
+  auto instrument = ws->getInstrument();
+  if (!instrument)
+    throw runtime_error("There is no instrument in input workspace.")
+
+  size_t numdets = instrument->getNumberDetectors();
+  vector<detid_t> detIds = instrument->getDetectorIDs();
+
+  for (size_t i = 0; i < numdets; ++i) {
+    IDetector_const_sptr tmpdetector = instrument->getDetector(detIds[i]);
+    if (tmpdetector->isMasked()) {
+      maskeddetids.push_back(tmpdetid);
+    }
+  }
+
+**After - looping over index**
+
+.. code-block:: c++
+
+  #include "MantidAPI/Detector.h"
+
+  ...
+
+  const auto &detectorInfo = ws->detectorInfo();
+  if (detectorInfo.size() == 0)
+    throw runtime_error("There is no instrument in input workspace.")
+
+  vector<detid_t> detIds = detectorInfo.detectorIDs();
+
+  for (size_t i = 0; i < detectorInfo.size(); ++i) {
+    if (detectorInfo.isMasked(i)) {
+      maskedDetIds.push_back(detIds[i]);
+    }
+  }
+
+Access to Detectors
+___________________
+
+As for the ``SpectrumInfo`` object ``DetectorInfo`` can return a parameterised detector for the workspace.
+
+Mutable DetectorInfo
+____________________
+
+The method ``ExperimentInfo::mutableDetectorInfo()`` returns a non-const ``DetectorInfo`` object. This allows the methods below to be used.
+
+* ``setMasked(const size_t index, bool masked);``
+* ``clearMaskFlags();``
+* ``setPosition(const size_t index, const Kernel::V3D &position);``
+* ``setRotation(const size_t index, const Kernel::Quat &rotation);``
+* ``setPosition(const Geometry::IComponent &comp, const Kernel::V3D &pos);``
+* ``setRotation(const Geometry::IComponent &comp, const Kernel::Quat &rot);``
+
+For a complete example of setting the position of a detector see the changes to the algorithm `ApplyCalibration.cpp <https://github.com/mantidproject/mantid/commit/0c75f46e85c2dc39c2b76ea811f161fdfdef938e#diff-a4ccabae0099bfc22b3b87154cd6ee9e>`_.
+
+Useful Tips
+___________
+
+See tips for ``SpectrumInfo`` - the same advice applies to using ``DetectorInfo``.
+
+Complete Examples
+_________________
+
+* `FindDetectorsInShape.cpp <https://github.com/mantidproject/mantid/commit/177ad14b25db7c40ee10be513512be9ae7dd0da1#diff-7f367da22c1a837b315b4bca5b2b3e24>`_
+
+* `SmoothNeighbours.cpp <https://github.com/mantidproject/mantid/pull/18295/files#diff-26a49ef923e1bdd77677b962528d1e01>`_
+
+* `ClaerMaskFlag.cpp <https://github.com/mantidproject/mantid/pull/18198/files#diff-7f0f739ba6db714eb6ef64b6125e4620>`_
+
+* `ApplyCalibration.cpp <https://github.com/mantidproject/mantid/commit/0c75f46e85c2dc39c2b76ea811f161fdfdef938e#diff-a4ccabae0099bfc22b3b87154cd6ee9e>`_ - for mutable ``DetectorInfo``
+
+Rollout status
+--------------
+
+See ticket `17743 <https://github.com/mantidproject/mantid/issues/17743>`_ for an overview of the ``SpectrumInfo`` and ``DetectorInfo`` rollout, including completed and algorithms, and remaining algorithms. Please follow the instructions on the ticket for the rollout.
+
+Dealing with problems
+---------------------
+
+Join #instrument-2_0 on Slack if you need help or have questions. Please also feel free to get in touch with Ian Bush, Simon Heybrock or Owen Arnold directly for any questions about the ``SpectrumInfo``, ``DetectorInfo`` and the rollout.
+
+
+.. categories:: Concepts
diff --git a/docs/source/concepts/MDHistoWorkspace.rst b/docs/source/concepts/MDHistoWorkspace.rst
index 40d0e08c05c08e7122497e8434a13d0d36f0453e..7a03d4dfb78cb72aa767ce24e81f021a08718754 100644
--- a/docs/source/concepts/MDHistoWorkspace.rst
+++ b/docs/source/concepts/MDHistoWorkspace.rst
@@ -69,7 +69,7 @@ If you want to check if a variable points to something that is an MDHistoWorkspa
                            NumberOfBins='10,10',Names='Dim1,Dim2',Units='MomentumTransfer,EnergyTransfer')
 
    if isinstance(ws, IMDHistoWorkspace):
-    print ws.getName() + " is a " + ws.id()
+    print ws.name() + " is a " + ws.id()
 
 Output:
 
@@ -96,7 +96,7 @@ For a full list of the available properties and operation look at the :py:obj:`I
    for i in range(ws.getNumDims()):
       dimension = ws.getDimension(i)
       print "\tDimension {0} Name: {1}".format(i,
-         dimension.getName())
+         dimension.name)
 
 .. testoutput:: MDHistoWorkspaceProperties
    :hide:
@@ -124,15 +124,15 @@ As a generic multi dimensional container being able to access information about
      dimension = ws.getDimension(i)
      print "\tDimension {0} Name: {1} id: {2} Range: {3}-{4} {5}".format(i,
          dimension.getDimensionId(),
-         dimension.getName(),
+         dimension.name,
          dimension.getMinimum(),
          dimension.getMaximum(),
          dimension.getUnits())
 
-   print "The dimension assigned to X =", ws.getXDimension().getName()
-   print "The dimension assigned to Y =", ws.getYDimension().getName()
+   print "The dimension assigned to X =", ws.getXDimension().name
+   print "The dimension assigned to Y =", ws.getYDimension().name
    try:
-     print "The dimension assigned to Z =", ws.getZDimension().getName()
+     print "The dimension assigned to Z =", ws.getZDimension().name
    except RuntimeError:
       # if the dimension does not exist you will get a RuntimeError
      print "Workspace does not have a Z dimension"
diff --git a/docs/source/concepts/MDWorkspace.rst b/docs/source/concepts/MDWorkspace.rst
index 7741bf5839f5875f7da72a05d0f1f96f5b05a7f3..fa0b1e8f005a338346ede064819d71e0b43b817c 100644
--- a/docs/source/concepts/MDWorkspace.rst
+++ b/docs/source/concepts/MDWorkspace.rst
@@ -126,7 +126,7 @@ If you want to check if a variable points to something that is an MDWorkspace Wo
     mdws = CreateMDWorkspace(Dimensions=3, Extents='-10,10,-10,10,-10,10', Names='A,B,C', Units='U,U,U')
 
     if isinstance(mdws, IMDEventWorkspace):
-        print mdws.getName() + " is a " + mdws.id()
+        print mdws.name() + " is a " + mdws.id()
 
 Output:
 
@@ -153,7 +153,7 @@ For a full list of the available properties and operation look at the :py:obj:`I
    for i in range(ws.getNumDims()):
        dimension = ws.getDimension(i)
        print "\tDimension {0} Name: {1}".format(i,
-          dimension.getName())
+          dimension.name)
 
    bc =ws.getBoxController()
    print "Is the workspace using a file back end?", bc.isFileBacked()
@@ -186,15 +186,15 @@ As a generic multi dimensional container being able to access information about
       dimension = ws.getDimension(i)
       print "\tDimension {0} Name: {1} id: {2} Range: {3}-{4} {5}".format(i,
           dimension.getDimensionId(),
-          dimension.getName(),
+          dimension.name,
           dimension.getMinimum(),
           dimension.getMaximum(),
           dimension.getUnits())
 
-   print "The dimension assigned to X =", ws.getXDimension().getName()
-   print "The dimension assigned to Y =", ws.getYDimension().getName()
+   print "The dimension assigned to X =", ws.getXDimension().name
+   print "The dimension assigned to Y =", ws.getYDimension().name
    try:
-      print "The dimension assigned to Z =", ws.getZDimension().getName()
+      print "The dimension assigned to Z =", ws.getZDimension().name
    except RuntimeError:
        # if the dimension does not exist you will get a RuntimeError
       print "Workspace does not have a Z dimension"
@@ -244,4 +244,4 @@ To access the data of an MDWorkspace you need to convert it to a regular grid, o
    out_md = CutMD(mdWS, Projection=proj_ws, PBins=([0.1], [0.1], [0.1], [-5,5]), NoPix=True)
 
 
-.. categories:: Concepts
\ No newline at end of file
+.. categories:: Concepts
diff --git a/docs/source/concepts/MatrixWorkspace.rst b/docs/source/concepts/MatrixWorkspace.rst
index 6b74cafa7ae82cec03e06cfc76f45197c28a9ed3..bde1b38ebb9a7fce2ce8b0419d47c1bc87e51912 100644
--- a/docs/source/concepts/MatrixWorkspace.rst
+++ b/docs/source/concepts/MatrixWorkspace.rst
@@ -55,7 +55,7 @@ If you want to check if a variable points to something that is a Matrix Workspac
     histoWS = CreateSampleWorkspace(WorkspaceType="Histogram")
 
     if isinstance(histoWS, MatrixWorkspace):
-        print histoWS.getName() + " is a " + histoWS.id() + \
+        print histoWS.name() + " is a " + histoWS.id() + \
                  " and can be treated as a MatrixWorkspace"
 
     print "\nFor more workspace types"
diff --git a/docs/source/concepts/Workspace.rst b/docs/source/concepts/Workspace.rst
index f8a362df443147e2d3ffdc647d1c7b3685b941dc..6b2cba65c62bc988ff8b14f008f68ba1c813f583 100644
--- a/docs/source/concepts/Workspace.rst
+++ b/docs/source/concepts/Workspace.rst
@@ -104,7 +104,7 @@ You can look at the :ref:`Workspace API reference <mantid.api.Workspace>` for a
 .. testcode:: WorkspaceProperties
 
     myWS = CreateSampleWorkspace()
-    print "name = " + myWS.getName()
+    print "name = " + myWS.name()
 
     myWS.setTitle("This is my Title")
     print "getTitle = " + myWS.getTitle()
diff --git a/docs/source/concepts/Workspace2D.rst b/docs/source/concepts/Workspace2D.rst
index 84d9dbda158ccfbd24ef6c9f07ccee6c2f9677b6..9288209f1682699f7d05ee9304b2c05e60133c2e 100644
--- a/docs/source/concepts/Workspace2D.rst
+++ b/docs/source/concepts/Workspace2D.rst
@@ -39,7 +39,7 @@ If you want to check if a variable points to something that is a Workspace2D you
     histoWS = CreateSampleWorkspace()
 
     if histoWS.id() == "Workspace2D":
-        print histoWS.getName() + " is an " + histoWS.id()
+        print histoWS.name() + " is an " + histoWS.id()
 
 Output:
 
@@ -52,4 +52,4 @@ Output:
 
 
 
-.. categories:: Concepts
\ No newline at end of file
+.. categories:: Concepts
diff --git a/docs/source/concepts/WorkspaceGroup.rst b/docs/source/concepts/WorkspaceGroup.rst
index d6451f732c4ded3d5fc366f633c0d06cd0b91b24..d92c8ffd316e9675bfdfff13270088e1c3abd0da 100644
--- a/docs/source/concepts/WorkspaceGroup.rst
+++ b/docs/source/concepts/WorkspaceGroup.rst
@@ -76,7 +76,7 @@ If you want to check if a variable points to something that is a Workspace Group
     wsGroup = GroupWorkspaces("ws1,ws2")
 
     if isinstance(wsGroup, WorkspaceGroup):
-        print wsGroup.getName() + " is an " + wsGroup.id()
+        print wsGroup.name() + " is an " + wsGroup.id()
 
 Output:
 
@@ -138,4 +138,4 @@ You can pass workspace groups into any algorithm and Mantid will run that algori
 
 
 
-.. categories:: Concepts
\ No newline at end of file
+.. categories:: Concepts
diff --git a/docs/source/concepts/calibration/PowderDiffractionCalibration.rst b/docs/source/concepts/calibration/PowderDiffractionCalibration.rst
index 0a7eb45ae4711ce17ea823f3a8da6249392ddf5e..5eadf15a0c83fd2295649bda16b971ecb8f53aec 100644
--- a/docs/source/concepts/calibration/PowderDiffractionCalibration.rst
+++ b/docs/source/concepts/calibration/PowderDiffractionCalibration.rst
@@ -41,6 +41,9 @@ Steps for other instruments
 
      6. Run :ref:`GetDetOffsetsMultiPeaks <algm-GetDetOffsetsMultiPeaks>`, the Input workspace is the one from step 3 earlier.  For DReference you can enter a comma seperated list of the d-spacing values of the known peaks.
      7. The output is an OffsetsWorspace, and a workspace with the number of peaks found in each spectra,  The output offsets workspace that can be used directly in :ref:`DiffractionFocussing <algm-DiffractionFocussing>`, or saved using :ref:`SaveCalFile <algm-SaveCalFile>`.  You can also save it as a :ref:`CalFile` from :ref:`GetDetOffsetsMultiPeaks <algm-GetDetOffsetsMultiPeaks>`, by defining the GroupingFileName parameter.
+
+
+Additionally :ref:`PDCalibration <algm-PDCalibration>` can be used to fit peaks directly in TOF instead of converting to d-spacing. This algorithm produces a calibration table which can be passed to :ref:`AlignDetectors <algm-AlignDetectors>`. The algorithms :ref:`LoadDiffCal <algm-LoadDiffCal>` and :ref:`SaveDiffCal <algm-SaveDiffCal>` can be used to read and write the calibration table to file.
      
 .. figure:: /images/PG3_Calibrate.png
   :width: 400px
diff --git a/docs/source/diagrams/CreateTransmissionWorkspace_ConvertToWavelength-v1_wkflw.dot b/docs/source/diagrams/CreateTransmissionWorkspace_ConvertToWavelength-v1_wkflw.dot
index 07f01a354be311a5319fd719aff0146265bc09fc..b609d5f786754926e3517f2cad1eadcc941bfcea 100644
--- a/docs/source/diagrams/CreateTransmissionWorkspace_ConvertToWavelength-v1_wkflw.dot
+++ b/docs/source/diagrams/CreateTransmissionWorkspace_ConvertToWavelength-v1_wkflw.dot
@@ -12,6 +12,8 @@ subgraph params {
   wavMax              [label="WavelengthMax"]
   monIntWavMin        [label="MonitorIntegration-\nWavelengthMin"]
   monIntWavMax        [label="MonitorIntegration-\nWavelengthMax"]
+  monBgWavMax         [label="MonitorBackground-\nWavelengthMax"]
+  monBgWavMin         [label="MonitorBackground-\nWavelengthMin"]
   outputWS            [label="TransmissionRun\nin wavelength"]
 
   detWS               [label="DetectorWorkspace"]
@@ -20,7 +22,7 @@ subgraph params {
 
 subgraph decisions {
  $decision_style
-  checkMon        [label="Monitors?"]
+  checkMon        [label="I0MonitorIndex and\nMonitorBackground-\nWavelengthMin\Max\nprovided?"]
   checkBgMinMax   [label="MonitorBackground-\nWavelength\nMin/Max non-zero?"]
   checkMonInt	  [label="Normalize by\nIntegrated Monitors?"]
 }
@@ -63,10 +65,12 @@ wavMax               -> cropDet
 cropDet              -> detWS
 
 firstRun	     -> checkMon	[label="Monitors"]
+monBgWavMax         -> checkMon
+monBgWavMin         -> checkMon
+monitorIndex        -> checkMon
 checkMon             -> convertMon      [label="Yes"]
 convertMon	     -> valMon
 valMon		     -> cropMon
-monitorIndex	     -> cropMon
 cropMon		     -> checkBgMinMax
 checkBgMinMax	     -> calcFlatBg	[label="Yes"]
 calcFlatBg	     -> rebinToWS
@@ -88,7 +92,7 @@ monWS		     -> divideDetMon
 
 divideDetMon	     -> outputWS
 
-{rank = same; convertDet; convertMon}
+{rank = same; convertDet; monBgWavMax; monBgWavMin; monitorIndex;}
 {rank = same; valDet; valMon; valUnity}
 {rank = same; detWS; rebinToWS}
 }
diff --git a/docs/source/diagrams/IndirectILLEnergyTransfer-v1_wkflw.dot b/docs/source/diagrams/IndirectILLEnergyTransfer-v1_wkflw.dot
new file mode 100644
index 0000000000000000000000000000000000000000..19281073fecd5c100dcc094d6d089e6b146fd6bc
--- /dev/null
+++ b/docs/source/diagrams/IndirectILLEnergyTransfer-v1_wkflw.dot
@@ -0,0 +1,47 @@
+digraph IndirectILLEnergyTransfer {
+  label="IndirectILLEnergyTransfer Flowchart"
+  $global_style
+
+  subgraph values {
+    $value_style
+    OutputWorkspace
+  }
+
+  subgraph descision {
+    $decision_style
+    CropDeadMonitorChannels
+  }
+
+  subgraph params {
+  	$param_style
+  	Run
+  	MapFile
+  }
+
+  subgraph algorithms {
+  	$algorithm_style
+  	LoadILLIndirect
+  	MergeRuns
+  	GroupDetectors
+  	NormaliseToMonitor
+  	ConvertAxisByFormula
+  	ConvertSpectrumAxis
+  	CropWorkspace
+  	MaskBins
+  	GroupWorkspaces
+  }
+
+  Run -> LoadILLIndirect
+  LoadILLIndirect -> MergeRuns
+  MapFile -> GroupDetectors
+  MergeRuns -> GroupDetectors
+  GroupDetectors -> NormaliseToMonitor
+  NormaliseToMonitor -> CropDeadMonitorChannels
+  CropDeadMonitorChannels -> CropWorkspace [label="yes"]
+  CropDeadMonitorChannels -> MaskBins [label="no"]
+  CropWorkspace -> ConvertAxisByFormula
+  MaskBins -> ConvertAxisByFormula
+  ConvertAxisByFormula -> ConvertSpectrumAxis
+  ConvertSpectrumAxis -> GroupWorkspaces
+  GroupWorkspaces -> OutputWorkspace
+}
\ No newline at end of file
diff --git a/docs/source/diagrams/IndirectILLReductionFWS-v1_wkflw.dot b/docs/source/diagrams/IndirectILLReductionFWS-v1_wkflw.dot
new file mode 100644
index 0000000000000000000000000000000000000000..a1d5f82dd12dcd1b2739e8801c2143f13b8196a4
--- /dev/null
+++ b/docs/source/diagrams/IndirectILLReductionFWS-v1_wkflw.dot
@@ -0,0 +1,74 @@
+digraph IndirectILLReductionFWS {
+  label="IndirectILLReductionFWS Flowchart"
+  $global_style
+
+  subgraph values {
+    $value_style
+    OutputWorkspace
+  }
+
+  subgraph descision {
+    $decision_style
+  }
+
+  subgraph params {
+  	$param_style
+  	Run
+  	Observable
+  	CalibrationRun
+  	BackgroundRun
+  }
+
+  subgraph algorithms {
+  	$algorithm_style
+  	IndirectILLEnergyTransfer
+  	IndirectILLEnergyTransferB [label="IndirectILLEnergyTransfer"]
+  	IndirectILLEnergyTransferC [label="IndirectILLEnergyTransfer"]
+    SelectNexusFilesByMetadata
+    SelectNexusFilesByMetadataB [label="SelectNexusFilesByMetadata"]
+    SelectNexusFilesByMetadataC [label="SelectNexusFilesByMetadata"]
+    Integration
+    IntegrationB [label="Integration"]
+    IntegrationC [label="Integration"]
+    GroupWorkspaces
+    SplineInterpolationB [label="SplineInterpolation"]
+    SplineInterpolationC [label="SplineInterpolation"]
+    IntegrationBB [label="Integration"]
+    IntegrationCC [label="Integration"]
+    Minus
+    Divide
+  }
+
+  subgraph processes {
+  	$process_style
+  	Scan
+  	ScanB [label="Scan"]
+  	ScanC [label="Scan"]
+  }
+
+  Run -> SelectNexusFilesByMetadata
+  SelectNexusFilesByMetadata -> IndirectILLEnergyTransfer
+  IndirectILLEnergyTransfer -> Integration
+  Integration -> Scan
+  Observable -> Scan
+  BackgroundRun -> SelectNexusFilesByMetadataB
+  SelectNexusFilesByMetadataB -> IndirectILLEnergyTransferB
+  IndirectILLEnergyTransferB ->
+  IntegrationB -> ScanB
+  ScanB -> IntegrationBB [label="Sum"]
+  ScanB -> SplineInterpolationB [label="Interpolate"]
+  CalibrationRun -> SelectNexusFilesByMetadataC
+  SelectNexusFilesByMetadataC -> IndirectILLEnergyTransferC
+  IndirectILLEnergyTransferC -> IntegrationC
+  IntegrationC -> ScanC
+  ScanC -> IntegrationCC [label="Sum"]
+  ScanC -> SplineInterpolationC [label="Interpolate"]
+  Scan -> Minus
+  IntegrationBB -> Minus
+  SplineInterpolationB -> Minus
+  Minus -> Divide
+  IntegrationCC -> Divide
+  SplineInterpolationC -> Divide
+  Divide -> GroupWorkspaces
+  GroupWorkspaces -> OutputWorkspace
+}
\ No newline at end of file
diff --git a/docs/source/diagrams/IndirectILLReductionQENS-v1_wkflw.dot b/docs/source/diagrams/IndirectILLReductionQENS-v1_wkflw.dot
new file mode 100644
index 0000000000000000000000000000000000000000..47e0cdaae2806c05aa4429fb6ca9ff85c20b14ef
--- /dev/null
+++ b/docs/source/diagrams/IndirectILLReductionQENS-v1_wkflw.dot
@@ -0,0 +1,72 @@
+digraph IndirectILLReductionQENS {
+  label="IndirectILLReductionQENS Flowchart"
+  $global_style
+
+  subgraph values {
+    $value_style
+    OutputWorkspace
+  }
+
+  subgraph descision {
+    $decision_style
+  }
+
+  subgraph params {
+  	$param_style
+  	Run
+  	BackgroundRun
+  	CalibrationRun
+  	AlignmentRun
+  	BackgroundScalingFactor
+  	CalibrationPeakRange
+  	UnmirrorOption
+  	CropDeadMonitorChannels
+  }
+
+  subgraph algorithms {
+  	$algorithm_style
+  	SelectNexusFilesByMetadata
+  	SelectNexusFilesByMetadataA [label="SelectNexusFilesByMetadata"]
+  	SelectNexusFilesByMetadataB [label="SelectNexusFilesByMetadata"]
+    SelectNexusFilesByMetadataC [label="SelectNexusFilesByMetadata"]
+    IndirectILLEnergyTransfer
+    IndirectILLEnergyTransferA [label="IndirectILLEnergyTransfer"]
+    IndirectILLEnergyTransferB [label="IndirectILLEnergyTransfer"]
+  	IndirectILLEnergyTransferC [label="IndirectILLEnergyTransfer"]
+  	Integration
+  	Minus
+  	Divide
+    Plus
+    Scale
+    MatchPeaks
+    GroupWorkspaces
+  }
+
+  subgraph processes {
+  	$process_style
+  }
+
+  Run -> SelectNexusFilesByMetadata
+  SelectNexusFilesByMetadata -> IndirectILLEnergyTransfer
+  CropDeadMonitorChannels -> IndirectILLEnergyTransfer
+  IndirectILLEnergyTransfer -> Minus
+  BackgroundRun -> SelectNexusFilesByMetadataB
+  SelectNexusFilesByMetadataB -> IndirectILLEnergyTransferB
+  IndirectILLEnergyTransferB -> Scale
+  BackgroundScalingFactor -> Scale
+  Scale -> Minus
+  CalibrationRun -> SelectNexusFilesByMetadataC
+  SelectNexusFilesByMetadataC -> IndirectILLEnergyTransferC
+  IndirectILLEnergyTransferC -> Integration
+  CalibrationPeakRange -> Integration
+  Integration -> Divide
+  Minus -> Divide
+  Divide -> MatchPeaks
+  UnmirrorOption -> MatchPeaks
+  AlignmentRun -> SelectNexusFilesByMetadataA
+  SelectNexusFilesByMetadataA -> IndirectILLEnergyTransferA
+  IndirectILLEnergyTransferA -> MatchPeaks
+  MatchPeaks -> Plus
+  Plus -> GroupWorkspaces
+  GroupWorkspaces -> OutputWorkspace
+}
\ No newline at end of file
diff --git a/docs/source/diagrams/ReflectometryReductionOne_ConvertToWavelength-v1_wkflw.dot b/docs/source/diagrams/ReflectometryReductionOne_ConvertToWavelength-v1_wkflw.dot
index e1e345a820a5f44829fe834d3ca0a78fefab93af..af612c6d37ba9615d48f7b3928df0cc69f2b4aec 100644
--- a/docs/source/diagrams/ReflectometryReductionOne_ConvertToWavelength-v1_wkflw.dot
+++ b/docs/source/diagrams/ReflectometryReductionOne_ConvertToWavelength-v1_wkflw.dot
@@ -15,13 +15,15 @@ subgraph params {
   regionOfDirectBeam  [label="RegionOf-\nDirectBeam"]
   monIntWavMax        [label="MonitorIntegration-\nWavelengthMax"]
   monIntWavMin        [label="MonitorIntegration-\nWavelengthMin"]
+  monBgWavMax         [label="MonitorBackground-\nWavelengthMax"]
+  monBgWavMin         [label="MonitorBackground-\nWavelengthMin"]
   wavMaxRDB           [label="WavelengthMax"]
   wavMinRDB           [label="WavelengthMin"]
 }
 
 subgraph decisions {
  $decision_style
-  checkMonUnity   [label="Monitors?"]
+  checkMonUnity   [label="I0MonitorIndex and\nMonitorBackground-\nWavelengthMin\Max\nprovided?"]
   checkNormDetMon [label="Normalize by\nIntegrated Monitors?"]
   checkBgMinMax   [label="Monitor background\nwavelength\nmin/max non-zero?"]
   checkMultRDB    [label="MultidetectorAnalysis\nand\nRegionOfDirectBeam\ngiven?"]
@@ -59,6 +61,9 @@ subgraph values {
 
 inputWS             -> convertDet     [label="Detectors"]
 inputWS             -> checkMonUnity  [label="Monitors"]
+monBgWavMax         -> checkMonUnity
+monBgWavMin         -> checkMonUnity
+monitorIndex        -> checkMonUnity
 checkMonUnity       -> convertMon     [label="Yes"]
 checkMonUnity       -> valUnity       [label="No"]
 convertDet          -> valDet
@@ -75,7 +80,6 @@ wavMax              -> cropDetWS
 cropDetWS           -> detWS
 detWS               -> rebinToWS
 valMon              -> cropMonWS
-monitorIndex        -> cropMonWS
 cropMonWS           -> checkBgMinMax
 checkBgMinMax       -> calcFlatBg     [label="Yes"]
 checkBgMinMax       -> rebinToWS      [label="No"]
@@ -97,7 +101,7 @@ rebinToWSRDB        -> divideDetRDB
 divideDetRDB	    -> divideDetMon
 divideDetMon        -> outputWS
 
-{rank = same; convertDet; convertMon}
+{rank = same; convertDet; monBgWavMax; monBgWavMin; monitorIndex;}
 {rank = same; valUnity; valDet; valMon}
 {rank = same; cropDetWS; cropMonWS}
 {rank = same; detWS; calcFlatBg}
diff --git a/docs/source/diagrams/Stitch1D-v3.dot b/docs/source/diagrams/Stitch1D-v3.dot
new file mode 100644
index 0000000000000000000000000000000000000000..4ac10bbda6d53904595907352b3390e8a12cf7d2
--- /dev/null
+++ b/docs/source/diagrams/Stitch1D-v3.dot
@@ -0,0 +1,138 @@
+digraph Stitch1D {
+splines=false
+label = "\nStitch1D workflow - no manual scale factor                                                                                                                  Stitch1D workflow - manual scale factor given\n\n"
+ $global_style
+
+subgraph params {
+ $param_style
+  lhsworkspace          [label="LHSWorkspace", group=g1]
+  rhsworkspace          [label="RHSWorkspace", group=g2]
+  params				[label="Params", group=g3]
+  startOv				[label="StartOverlap"]
+  endOv					[label="EndOverlap"]
+  scaleFactor           [label="OutScaleFactor"]
+  lhsworkspace_o		[label="LHSWorkspace\n([StartX, StartOverlap])", group=g1]
+  rhsworkspace_o		[label="RHSWorkspace\n([EndOverlap, EndX])", group=g2]
+  outputworkspace		[label="OutputWorkspace", group=g3]
+  outputworkspace_2		[label="OutputWorkspace", group=g3]
+
+  lhsworkspace_1        [label="LHSWorkspace", group=g4]
+  rhsworkspace_1        [label="RHSWorkspace", group=g5]
+  params_1				[label="Params", group=g6]
+  scaleFactor_in		[label="ManualScaleFactor"]
+  lhsworkspace_1_1		[label="LHSWorkspace\n([StartX, StartOverlap])", group=g4]
+  rhsworkspace_1_1		[label="RHSWorkspace\n([EndOverlap, EndX])", group=g5]
+  outputworkspace_1		[label="OutputWorkspace", group=g6]
+  outputworkspace_2_1	[label="OutputWorkspace", group=g6]
+}
+
+subgraph decisions {
+ $decision_style
+}
+
+subgraph algorithms {
+ $algorithm_style
+  rebin_lhsw				[label="Rebin", group=g1]
+  rebin_rhsw				[label="Rebin", group=g2]
+  integrate_lhsw            [label="Integration", group=g1]
+  integrate_rhsw            [label="Integration", group=g2]
+  multiply					[label="Multiply", group=g2]
+  weightedMean				[label="WeightedMean\n([StartOverlap, EndOverlap])", group=g3]
+  divideScaleFactor		    [label="Divide"]
+  plus						[label="Plus"]
+
+  rebin_lhsw_1				[label="Rebin", group=g4]
+  rebin_rhsw_1				[label="Rebin", group=g5]
+  multiply_1				[label="Multiply", group=g5]
+  weightedMean_1			[label="WeightedMean\n([StartOverlap, EndOverlap])", group=g6]
+  plus_1					[label="Plus"]
+}
+
+subgraph processes {
+ $process_style
+  maskSpecialValues_1    [label="Mask special values", group=g1]
+  maskSpecialValues_2    [label="Mask special values", group=g2]
+  insertSpecialValues    [label="Reinsert special values"]
+
+  maskSpecialValues_1_1    [label="Mask special values", group=g4]
+  maskSpecialValues_2_1    [label="Mask special values", group=g5]
+  insertSpecialValues_1    [label="Reinsert special values"]
+}
+
+subgraph values {
+ $value_style
+}
+
+lhsworkspace -> rebin_lhsw
+rhsworkspace -> rebin_rhsw
+params       -> rebin_lhsw
+params       -> rebin_rhsw
+
+rebin_lhsw   -> maskSpecialValues_1
+rebin_rhsw   -> maskSpecialValues_2
+
+maskSpecialValues_1 -> integrate_lhsw
+maskSpecialValues_2 -> integrate_rhsw
+startOv				-> integrate_lhsw
+startOv				-> integrate_rhsw
+endOv				-> integrate_lhsw
+endOv				-> integrate_rhsw
+
+integrate_lhsw		-> lhsworkspace_o
+
+integrate_lhsw		-> divideScaleFactor
+integrate_rhsw		-> divideScaleFactor
+divideScaleFactor	-> scaleFactor
+
+scaleFactor			-> multiply
+maskSpecialValues_2 -> multiply
+
+lhsworkspace_o		-> plus
+
+multiply			-> weightedMean
+maskSpecialValues_1	-> weightedMean
+weightedMean		-> plus
+
+multiply			-> rhsworkspace_o
+rhsworkspace_o		-> plus
+plus				-> outputworkspace
+
+outputworkspace		-> insertSpecialValues
+insertSpecialValues	-> outputworkspace_2
+
+{rank=same; lhsworkspace_o; rhsworkspace_o}
+
+lhsworkspace_1 -> rebin_lhsw_1
+rhsworkspace_1 -> rebin_rhsw_1
+params_1       -> rebin_lhsw_1
+params_1       -> rebin_rhsw_1
+
+rebin_lhsw_1   -> maskSpecialValues_1_1
+rebin_rhsw_1   -> maskSpecialValues_2_1
+
+maskSpecialValues_1_1	-> lhsworkspace_1_1
+maskSpecialValues_2_1   -> multiply_1
+scaleFactor_in			-> multiply_1
+multiply_1			    -> weightedMean_1
+maskSpecialValues_1_1	-> weightedMean_1
+
+lhsworkspace_1_1	-> plus_1
+weightedMean_1		-> plus_1
+
+multiply_1			-> rhsworkspace_1_1
+rhsworkspace_1_1	-> plus_1
+plus_1				-> outputworkspace_1
+
+outputworkspace_1	-> insertSpecialValues_1
+insertSpecialValues_1 -> outputworkspace_2_1
+
+rhsworkspace_o	-> lhsworkspace_1_1 [style=invis; label="                "]
+
+{rank=same; lhsworkspace_1_1; rhsworkspace_1_1}
+
+{rank=same; lhsworkspace; rhsworkspace; lhsworkspace_1; rhsworkspace_1}
+{rank=same; rebin_lhsw; rebin_rhsw; rebin_lhsw_1; rebin_rhsw_1}
+{rank=same; maskSpecialValues_1; maskSpecialValues_2; maskSpecialValues_1_1; maskSpecialValues_2_1}
+{rank=same; lhsworkspace_o; rhsworkspace_o; lhsworkspace_1_1; rhsworkspace_1_1}
+{rank=same; scaleFactor; scaleFactor_in}
+}
diff --git a/docs/source/fitfunctions/CrystalFieldHeatCapacity.rst b/docs/source/fitfunctions/CrystalFieldHeatCapacity.rst
new file mode 100644
index 0000000000000000000000000000000000000000..a7085ddd70f33030cfee8c5d05b310b3f1a632f0
--- /dev/null
+++ b/docs/source/fitfunctions/CrystalFieldHeatCapacity.rst
@@ -0,0 +1,95 @@
+.. _func-CrystalFieldHeatCapacity:
+
+========================
+CrystalFieldHeatCapacity
+========================
+
+.. index:: CrystalFieldHeatCapacity
+
+Description
+-----------
+
+This function calculates the magnetic contribution to the heat capacity of a material from the splitting of its electronic energy
+levels by the crystal field. It is a part of crystal field computation in Mantid and under active development. 
+More documentation will follow as the development progresses.
+
+Theory
+------
+
+The heat capacity at constant volume is given by 
+
+.. math:: C_v = \left. \frac{\partial U}{\partial T} \right|_V = \frac{1}{k_B T^2} 
+   \frac{\partial}{\partial \beta} \left[ \frac{1}{Z}\frac{\partial Z}{\partial \beta} \right] 
+   \qquad \qquad \qquad \qquad \qquad \qquad \qquad \\
+   = \frac{1}{k_B T^2} \left( \frac{1}{Z}\sum_n E_n^2 \exp(-\beta E_n) 
+     - \left[ \frac{1}{Z}\sum_n E_n \exp(-\beta E_n) \right]^2 \right)
+
+where :math:`k_B` is Boltzmann's constant, :math:`Z` is the partition sum, and :math:`E_n` is the n-th energy level split by the 
+crystal field. This is obtained by diagonalising the crystal field Hamiltonian.
+
+Example
+-------
+
+Here is an example of how to fit function's parameters to a spectrum. All parameters disallowed by symmetry are fixed automatically.
+The "data" here is generated from the function itself. For real data, you should subtract the phonon contribution manually using either
+measurements from a phonon blank or a theoretical calculation (e.g. Debye model, or from lattice dynamical calculations) before
+using it with this function.
+
+The `x`-axis is given in Kelvin, and the heat capacity (`y`-axis) is in Joules per mole-Kelvin (Jmol\ :sup:`-1`\ K\ :sup:`-1`).
+
+.. testcode:: ExampleCrystalFieldHeatCapacity
+
+    import numpy as np
+
+    # Build a reference data set
+    fun = 'name=CrystalFieldHeatCapacity,Ion=Ce,B20=0.37737,B22=0.039770,B40=-0.031787,B42=-0.11611,B44=-0.12544'
+    
+    # This creates a (empty) workspace to use with EvaluateFunction
+    x = np.linspace(1, 300, 300)
+    y = x * 0
+    e = y + 1
+    ws = CreateWorkspace(x, y, e)
+    
+    # The calculated data will be in 'data', WorkspaceIndex=1
+    EvaluateFunction(fun, ws, OutputWorkspace='data')
+    
+     # Change parameters slightly and fit to the reference data
+    fun = 'name=CrystalFieldHeatCapacity,Ion=Ce,Symmetry=C2v,B20=0.4,B22=0.04,B40=-0.03,B42=-0.1,B44=-0.1,'
+    fun += 'ties=(B60=0,B62=0,B64=0,B66=0,BmolX=0,BmolY=0,BmolZ=0,BextX=0,BextY=0,BextZ=0)'
+    
+    # (set MaxIterations=0 to see the starting point)
+    Fit(fun, 'data', WorkspaceIndex=1, Output='fit',MaxIterations=100, CostFunction='Unweighted least squares')
+    # Using Unweighted least squares fit because the data has no errors.
+
+    # Extract fitted parameters
+    parws = mtd['fit_Parameters']
+    for i in range(parws.rowCount()):
+        row = parws.row(i)
+        if row['Value'] != 0:
+            print "%7s = % 7.5g" % (row['Name'], row['Value'])
+
+.. testcleanup:: ExampleCrystalFieldHeatCapacity
+
+Output:
+
+.. testoutput:: ExampleCrystalFieldHeatCapacity
+
+        B20 =  0.40709
+        B22 =  0.020272
+        B40 = -0.031454
+        B42 = -0.10724
+        B44 = -0.1314
+    Cost function value =  4.4642e-15
+
+.. attributes::
+
+   Ion;String;Mandatory;An element name for a rare earth ion. Possible values are: Ce, Pr, Nd, Pm, Sm, Eu, Gd, Tb, Dy, Ho, Er, Tm, Yb.
+   Symmetry;String;C1;A symbol for a symmetry group. Setting `Symmetry` automatically zeros and fixes all forbidden parameters. Possible values are: C1, Ci, C2, Cs, C2h, C2v, D2, D2h, C4, S4, C4h, D4, C4v, D2d, D4h, C3, S6, D3, C3v, D3d, C6, C3h, C6h, D6, C6v, D3h, D6h, T, Td, Th, O, Oh
+
+.. attributes::
+
+.. properties::
+
+.. categories::
+
+.. sourcelink::
diff --git a/docs/source/fitfunctions/CrystalFieldMagnetisation.rst b/docs/source/fitfunctions/CrystalFieldMagnetisation.rst
new file mode 100644
index 0000000000000000000000000000000000000000..e2c4883ecf1952b0b47130df806ce97622fb40ba
--- /dev/null
+++ b/docs/source/fitfunctions/CrystalFieldMagnetisation.rst
@@ -0,0 +1,107 @@
+.. _func-CrystalFieldMagnetisation:
+
+=========================
+CrystalFieldMagnetisation
+=========================
+
+.. index:: CrystalFieldMagnetisation
+
+Description
+-----------
+
+This function calculates the crystal field (molar) *magnetic moment* as a function of applied magnetic field in a specified 
+direction, in either atomic (:math:`\mu_B/`/ion), SI (Am\ :sup:`2`\ /mol) or cgs (erg/Gauss/mol == emu/mol) units. 
+If using cgs units, the magnetic field (:math:`x`-axis) is expected to be in Gauss. If using SI or atomic units, the field 
+should be given in Tesla.
+
+Strictly, to obtain the *magnetisation*, one should divide by the molar volume of the material.
+
+Theory
+------
+
+The function calculates the expectation value of the magnetic moment operator :math:`\mathbf{\mu} = g_J \mu_B \mathbf{J}`:
+
+.. math:: M(B) = \frac{1}{Z} \sum_n \langle V_n(H) | g_J \mu_B \mathbf{J} | V_n(H) \rangle \exp(-\beta E_n(H))
+
+where :math:`B` is the magnetic field in Tesla, :math:`g_J` is the Landé g-factor, :math:`\mu_B` is the Bohr magneton. 
+The moment operator is defined as :math:`\mathbf{J} = \hat{J}_x B_x + \hat{J}_y B_y + \hat{J}_z B_z` where 
+:math:`\hat{J}_x`, :math:`\hat{J}_y`, and :math:`\hat{J}_z` are the angular momentum operators in Cartesian coordinates, 
+with :math:`z` defined to be along the quantisation axis of the crystal field (which is usually defined to be the highest 
+symmetry rotation axis). :math:`B_x`, :math:`B_y`, and :math:`B_z` are the components of the unit vector pointing in the 
+direction of the applied magnetic field in this coordinate system. :math:`V_n(B)` and :math:`E_n(B)` are the n\ :sup:`th` 
+eigenvector and eigenvalue (wavefunction and energy) obtained by diagonalising the Hamiltonian:
+
+.. math:: \mathcal{H} = \mathcal{H}_{\mathrm{cf}} + \mathcal{H}_{\mathrm{Zeeman}} = \sum_{k,q} B_k^q \hat{O}_k^q 
+   - g_J \mu_B \mathbf{J}\cdot\mathbf{B}
+
+where in this case the magnetic field :math:`\mathbf{B}` is not normalised. Finally, :math:`\beta = 1/(k_B T)` 
+with :math:`k_B` the Boltzmann constant and :math:`T` the temperature, and :math:`Z` is the partition sum 
+:math:`Z = \sum_n \exp(-\beta E_n(H))`.
+
+Example
+-------
+
+Here is an example of how to fit crystal field parameters to a magnetisation measurement. All parameters disallowed by symmetry are fixed automatically.
+The "data" here is generated from the function itself.
+
+The `x`-axis is given in Tesla, and the magnetisation (`y`-axis) is in bohr magnetons per magnetic ion (:math:`\mu_B`/ion).
+
+.. code:: ExampleCrystalFieldMagnetisation
+
+    import numpy as np
+    
+    # Build a reference data set
+    fun = 'name=CrystalFieldMagnetisation,Ion=Ce,B20=0.37737,B22=0.039770,B40=-0.031787,B42=-0.11611,B44=-0.12544,'
+    fun += 'Temperature=10'
+    
+    # This creates a (empty) workspace to use with EvaluateFunction
+    x = np.linspace(0, 30, 300)
+    y = x * 0
+    e = y + 1
+    ws = CreateWorkspace(x, y, e)
+    
+    # The calculated data will be in 'data', WorkspaceIndex=1
+    EvaluateFunction(fun, ws, OutputWorkspace='data')
+    
+     # Change parameters slightly and fit to the reference data
+    fun = 'name=CrystalFieldMagnetisation,Ion=Ce,Symmetry=C2v,Temperature=10,B20=0.4,B22=0.04,B40=-0.03,B42=-0.1,B44=-0.1,'
+    fun += 'ties=(B60=0,B62=0,B64=0,B66=0,BmolX=0,BmolY=0,BmolZ=0,BextX=0,BextY=0,BextZ=0)'
+    
+    # (set MaxIterations=0 to see the starting point)
+    Fit(fun, 'data', WorkspaceIndex=1, Output='fit',MaxIterations=100, CostFunction='Unweighted least squares')
+    # Using Unweighted least squares fit because the data has no errors.
+
+    # Extract fitted parameters
+    parws = mtd['fit_Parameters']
+    for i in range(parws.rowCount()):
+        row = parws.row(i)
+        if row['Value'] != 0:
+            print "%7s = % 7.5g" % (row['Name'], row['Value'])
+
+.. testcleanup:: ExampleCrystalFieldMagnetisation
+
+Output:
+
+.. testoutput:: ExampleCrystalFieldMagnetisation
+
+        B20 =  0.39541
+        B22 =  0.030001
+        B40 = -0.029841
+        B42 = -0.11611
+        B44 = -0.1481
+    Cost function value =  1.2987e-14
+
+.. attributes::
+
+   Ion;String;Mandatory;An element name for a rare earth ion. Possible values are: Ce, Pr, Nd, Pm, Sm, Eu, Gd, Tb, Dy, Ho, Er, Tm, Yb.
+   Symmetry;String;C1;A symbol for a symmetry group. Setting `Symmetry` automatically zeros and fixes all forbidden parameters. Possible values are: C1, Ci, C2, Cs, C2h, C2v, D2, D2h, C4, S4, C4h, D4, C4v, D2d, D4h, C3, S6, D3, C3v, D3d, C6, C3h, C6h, D6, C6v, D3h, D6h, T, Td, Th, O, Oh
+   Temperature;Double;1.0; Temperature in Kelvin of the measurement.
+   powder;Boolean;false; Whether to calculate the powder averaged magnetisation or not.
+   Hdir;Vector;(0.,0.,1.); The direction of the applied field w.r.t. the crystal field parameters
+   Unit;String;'bohr'; The desired units of the output, either: 'bohr' (muB/ion), 'SI' (Am^2/mol) or 'cgs' (erg/G/mol).
+   
+.. properties::
+
+.. categories::
+
+.. sourcelink::
diff --git a/docs/source/fitfunctions/CrystalFieldMoment.rst b/docs/source/fitfunctions/CrystalFieldMoment.rst
new file mode 100644
index 0000000000000000000000000000000000000000..8dc299d6675f1d32f6180b9daf9e9d743ed0a00f
--- /dev/null
+++ b/docs/source/fitfunctions/CrystalFieldMoment.rst
@@ -0,0 +1,107 @@
+.. _func-CrystalFieldMoment:
+
+==================
+CrystalFieldMoment
+==================
+
+.. index:: CrystalFieldMoment
+
+Description
+-----------
+
+This function calculates the crystal field contribution to the magnetic moment as a function of temperature at a constant
+applied magnetic field in a specified direction, in either atomic (:math:`\mu_B/`/ion), SI (Am\ :sup:`2`\ /mol) or 
+cgs (erg/Gauss/mol == emu/mol) units. 
+
+Theory
+------
+
+The magnetic moment is calculated as the thermal expectation value of the magnetic moment operator 
+:math:`\mathbf{\mu} = g_J \mu_B \mathbf{J}`:
+
+.. math:: M(B) = \frac{1}{Z} \sum_n \langle V_n(H) | g_J \mathbf{J} | V_n(H) \rangle \exp(-\beta E_n(H))
+
+where :math:`B` is the magnetic field in Tesla, :math:`g_J` is the Landé g-factor, and :math:`\mu_B` is the Bohr magneton. 
+The moment operator is defined as :math:`\mathbf{J} = \hat{J}_x B_x + \hat{J}_y B_y + \hat{J}_z B_z` where 
+:math:`\hat{J}_x`, :math:`\hat{J}_y`, and :math:`\hat{J}_z` are the angular momentum operators in Cartesian coordinates, 
+with :math:`z` defined to be along the quantisation axis of the crystal field (which is usually defined to be the highest 
+symmetry rotation axis). :math:`B_x`, :math:`B_y`, and :math:`B_z` are the components of the unit vector pointing in the 
+direction of the applied magnetic field in this coordinate system. :math:`V_n(B)` and :math:`E_n(B)` are the n\ :sup:`th` 
+eigenvector and eigenvalue (wavefunction and energy) obtained by diagonalising the Hamiltonian:
+
+.. math:: \mathcal{H} = \mathcal{H}_{\mathrm{cf}} + \mathcal{H}_{\mathrm{Zeeman}} = \sum_{k,q} B_k^q \hat{O}_k^q 
+   - g_J \mu_B \mathbf{J}\cdot\mathbf{B}
+
+where in this case the magnetic field :math:`\mathbf{B}` is not normalised. Finally, :math:`\beta = 1/(k_B T)` with 
+:math:`k_B` the Boltzmann constant and :math:`T` the temperature, and :math:`Z` is the partition sum 
+:math:`Z = \sum_n \exp(-\beta E_n(H))`.
+
+Example
+-------
+
+Here is an example of how to fit M(T) to a measured dataset. All parameters disallowed by symmetry are fixed automatically.
+The "data" here is generated from the function itself.
+
+The `x`-axis is the temperature in Kelvin, and the magnetic moment (`y`-axis) is in Am\ :sup:`2`\ /mol (SI units), and the "measurement" was done with a field of 0.01 Tesla along the [110] direction of the crystal field (not necessarily the crystallographic [110] direction).
+
+.. code:: ExampleCrystalFieldMoment
+
+    import numpy as np
+    
+    # Build a reference data set
+    fun = 'name=CrystalFieldMoment,Ion=Ce,B20=0.37737,B22=0.039770,B40=-0.031787,B42=-0.11611,B44=-0.12544,'
+    fun += 'Hmag=0.01, Hdir=(1,1,0), Unit=SI,'
+    
+    # This creates a (empty) workspace to use with EvaluateFunction
+    x = np.linspace(1, 300, 300)
+    y = x * 0
+    e = y + 1
+    ws = CreateWorkspace(x, y, e)
+    
+    # The calculated data will be in 'data', WorkspaceIndex=1
+    EvaluateFunction(fun, ws, OutputWorkspace='data')
+    
+     # Change parameters slightly and fit to the reference data
+    fun = 'name=CrystalFieldMoment,Ion=Ce,Symmetry=C2v,B20=0.4,B22=0.04,B40=-0.03,B42=-0.1,B44=-0.1,'
+    fun += 'Hmag=0.01, Hdir=(1,1,0), Unit=SI,'
+    fun += 'ties=(B60=0,B62=0,B64=0,B66=0,BmolX=0,BmolY=0,BmolZ=0,BextX=0,BextY=0,BextZ=0)'
+    
+    # (set MaxIterations=0 to see the starting point)
+    Fit(fun, 'data', WorkspaceIndex=1, Output='fit',MaxIterations=100, CostFunction='Unweighted least squares')
+    # Using Unweighted least squares fit because the data has no errors.
+
+    # Extract fitted parameters
+    parws = mtd['fit_Parameters']
+    for i in range(parws.rowCount()):
+        row = parws.row(i)
+        if row['Value'] != 0:
+            print "%7s = % 7.5g" % (row['Name'], row['Value'])
+
+.. testcleanup:: ExampleCrystalFieldMoment
+
+Output:
+
+.. testoutput:: ExampleCrystalFieldMoment
+
+        B20 =  0.37745
+        B22 =  0.016732
+        B40 = -0.032093
+        B42 = -0.11298
+        B44 = -0.12685
+    Cost function value =  9.7067e-18
+
+.. attributes::
+
+   Ion;String;Mandatory;An element name for a rare earth ion. Possible values are: Ce, Pr, Nd, Pm, Sm, Eu, Gd, Tb, Dy, Ho, Er, Tm, Yb.
+   Symmetry;String;C1;A symbol for a symmetry group. Setting `Symmetry` automatically zeros and fixes all forbidden parameters. Possible values are: C1, Ci, C2, Cs, C2h, C2v, D2, D2h, C4, S4, C4h, D4, C4v, D2d, D4h, C3, S6, D3, C3v, D3d, C6, C3h, C6h, D6, C6v, D3h, D6h, T, Td, Th, O, Oh
+   powder;Boolean;false; Whether to calculate the powder averaged magnetisation or not.
+   Hmag;Double;1.0; The applied magnetic field magnitude in Tesla (for 'bohr' or 'SI' units) or Gauss (for 'cgs' units).
+   Hdir;Vector;(0.,0.,1.); The direction of the applied field w.r.t. the crystal field parameters
+   Unit;String;'bohr'; The desired units of the output, either: 'bohr' (muB/ion), 'SI' (Am^2/mol) or 'cgs' (erg/G/mol).
+   inverse;Boolean;false; Whether to output 1/M(T) instead of M(T).
+   
+.. properties::
+
+.. categories::
+
+.. sourcelink::
diff --git a/docs/source/fitfunctions/CrystalFieldMultiSpectrum.rst b/docs/source/fitfunctions/CrystalFieldMultiSpectrum.rst
index 07c515a7a165f32ecc9275961bedd8c3b30389cc..89b237389085bd36abb6b6b08cf4a7376eb7091d 100644
--- a/docs/source/fitfunctions/CrystalFieldMultiSpectrum.rst
+++ b/docs/source/fitfunctions/CrystalFieldMultiSpectrum.rst
@@ -13,7 +13,7 @@ This function calculates multiple spectra of a crystal electric field acting upo
 in Mantid and under active development. More documentation will follow as the development progresses.
 
 Here is an example of how to fit function's parameters to a spectrum. All parameters disallowed by symmetry are fixed automatically.
-Any other parameters that need fixing has to be tied explicitly. Peak centres (in meV) and intensitiaes (in mb/sr) are also fixed and computed 
+Any other parameters that need fixing has to be tied explicitly. Peak centres (in meV) and intensities (in mb/sr) are also fixed and computed 
 from the field parameters with the :ref:`CrystalFieldPeaks <func-CrystalFieldPeaks>` function. Any other peak parameter can be set using
 the "f-index-dot-name" syntax (see :ref:`CompositeFunction <func-CompositeFunction>` for more details).
 
diff --git a/docs/source/fitfunctions/CrystalFieldSusceptibility.rst b/docs/source/fitfunctions/CrystalFieldSusceptibility.rst
new file mode 100644
index 0000000000000000000000000000000000000000..87e6eb14cc3357f4bf66ef40a83858abfb0ba5b2
--- /dev/null
+++ b/docs/source/fitfunctions/CrystalFieldSusceptibility.rst
@@ -0,0 +1,110 @@
+.. _func-CrystalFieldSusceptibility:
+
+==========================
+CrystalFieldSusceptibility
+==========================
+
+.. index:: CrystalFieldSusceptibility
+
+Description
+-----------
+
+This function calculates the crystal field contribution to the *molar* magnetic susceptibility using the Van Vleck formula. 
+The function outputs the results by default in *cgs* units of cm\ :sup:`3`\ /mol == "emu/mol". 
+There are also options to output the result in SI (m\ :sup:`3`\ /mol) or "atomic" units (\ :math:`\mu_B`/Tesla/ion).
+
+Theory
+------
+
+The magnetic susceptibility can be calculated by treating the magnetic field (Zeeman interaction) as a perturbation on the crystal 
+field energy. To second order, the susceptibility per mole of magnetic ion is given by:
+
+.. math:: \chi(T) = \frac{N_A}{Z} \sum_n \left[ \frac{| \langle V_n | g_J \mu_B \mathbf{J} | V_n \rangle | ^2}{k_B T} 
+   - 2 \sum_{m \neq n} \frac{| \langle V_n | g_J \mu_B \mathbf{J} | V_m \rangle | ^2}{E_n - E_m} \right] \exp(-\beta E_n)
+
+where :math:`N_A` is Avogadro's constant, :math:`k_B` is Boltzmann's constant, :math:`Z` is the partition sum, and 
+:math:`V_n` and :math:`E_n` are the n-th wavefunction (eigenvector) and energy level (eigenvalue) of the unperturbed 
+crystal field Hamiltonian. :math:`g_J` is the Landé g-factor, :math:`\mu_B` is the Bohr magneton and the moment operator 
+is defined as :math:`\mathbf{J} = \hat{J}_x B_x + \hat{J}_y B_y + \hat{J}_z B_z` where :math:`\hat{J}_x`, :math:`\hat{J}_y`,
+and :math:`\hat{J}_z` are the angular momentum operators in Cartesian coordinates, with :math:`z` defined to 
+be along the quantisation axis of the crystal field (which is usually defined to be the highest symmetry rotation axis). 
+:math:`B_x`, :math:`B_y`, and :math:`B_z` are the components of the unit vector pointing in the direction of the applied 
+magnetic field in this coordinate system.
+
+Finally, in order to account for the effect of any exchange interactions in the system which will shift the susceptibility curve
+up or down (analogous to the Curie-Weiss temperature), the actual magnetic susceptibility calculated by this function is:
+
+.. math:: \chi^{\mathrm{eff}} = \frac{\chi(T)}{1 - \lambda \chi(T)}
+
+where :math:`\lambda` parameterises an effective exchange interaction and :math:`\chi` is the bare (paramagnetic Crystal Field)
+susceptibility. A negative :math:`\lambda` indicates overall antiferromagnetic interactions, whilst a positive :math:`\lambda`
+corresponds to overall ferromagnetic interactions.
+
+Example
+-------
+
+Here is an example of how to the crystal field parameters to a susceptibility dataset. All parameters disallowed by symmetry are fixed automatically.
+The "data" here is generated from the function itself, for a field along the [111] direction with respects to the crystal field parameters (not necessarily the [111] crystallographic direction).
+
+The `x`-axis is given in Kelvin, and the susceptibility (`y`-axis) is in cgs units of m\ :sup:`3`\ /mol (==emu/mol).
+
+.. code:: ExampleCrystalFieldSusceptibility
+
+    import numpy as np
+
+    # Build a reference data set
+    fun = 'name=CrystalFieldSusceptibility,Ion=Ce,B20=0.37737,B22=0.039770,B40=-0.031787,B42=-0.11611,B44=-0.12544,'
+    fun += 'Hdir=(1,1,1), Unit=cgs, inverse=1,'
+    
+    # This creates a (empty) workspace to use with EvaluateFunction
+    x = np.linspace(1, 300, 300)
+    y = x * 0
+    e = y + 1
+    ws = CreateWorkspace(x, y, e)
+    
+    # The calculated data will be in 'data', WorkspaceIndex=1
+    EvaluateFunction(fun, ws, OutputWorkspace='data')
+    
+     # Change parameters slightly and fit to the reference data
+    fun = 'name=CrystalFieldSusceptibility,Ion=Ce,Symmetry=C2v,B20=0.4,B22=0.04,B40=-0.03,B42=-0.1,B44=-0.1,'
+    fun += 'Hdir=(1,1,1), Unit=cgs, inverse=1,'
+    fun += 'ties=(B60=0,B62=0,B64=0,B66=0,BmolX=0,BmolY=0,BmolZ=0,BextX=0,BextY=0,BextZ=0)'
+    
+    # (set MaxIterations=0 to see the starting point)
+    Fit(fun, 'data', WorkspaceIndex=1, Output='fit',MaxIterations=100, CostFunction='Unweighted least squares')
+    # Using Unweighted least squares fit because the data has no errors.
+
+    # Extract fitted parameters
+    parws = mtd['fit_Parameters']
+    for i in range(parws.rowCount()):
+        row = parws.row(i)
+        if row['Value'] != 0:
+            print "%7s = % 7.5g" % (row['Name'], row['Value'])
+
+.. testcleanup:: ExampleCrystalFieldSusceptibility
+
+Output:
+
+.. testoutput:: ExampleCrystalFieldSusceptibility
+
+        B20 =  0.37737
+        B22 =  0.039788
+        B40 = -0.031787
+        B42 = -0.11611
+        B44 = -0.12544
+    Cost function value =  1.0921e-14
+
+.. attributes::
+
+   Ion;String;Mandatory;An element name for a rare earth ion. Possible values are: Ce, Pr, Nd, Pm, Sm, Eu, Gd, Tb, Dy, Ho, Er, Tm, Yb.
+   Symmetry;String;C1;A symbol for a symmetry group. Setting `Symmetry` automatically zeros and fixes all forbidden parameters. Possible values are: C1, Ci, C2, Cs, C2h, C2v, D2, D2h, C4, S4, C4h, D4, C4v, D2d, D4h, C3, S6, D3, C3v, D3d, C6, C3h, C6h, D6, C6v, D3h, D6h, T, Td, Th, O, Oh
+   powder;Boolean;false; Whether to calculate the powder averaged magnetisation or not.
+   Hdir;Vector;(0.,0.,1.); The direction of the applied field w.r.t. the crystal field parameters
+   Unit;String;'bohr'; The desired units of the output, either: 'bohr' (muB/T/ion), 'SI' (m^3/mol) or 'cgs' (cm^3/mol).
+   inverse;Boolean;false; Whether to output 1/chi(T) instead of chi(T).
+
+.. properties::
+
+.. categories::
+
+.. sourcelink::
diff --git a/docs/source/fitfunctions/FunctionQDepends.rst b/docs/source/fitfunctions/FunctionQDepends.rst
new file mode 100644
index 0000000000000000000000000000000000000000..c94cf75a8f9218c18acad057bdcbca8f32f14284
--- /dev/null
+++ b/docs/source/fitfunctions/FunctionQDepends.rst
@@ -0,0 +1,30 @@
+.. _func-FunctionQDepends:
+
+================
+FunctionQDepends
+================
+
+.. index:: FunctionQDepends
+
+Description
+-----------
+
+This fitting function is the base class for all fitting functions that have:
+
+- A range of energy transfers as their one-dimensional domain from which to take values
+- The magnitude of the momemtum transfer, :math:`Q`, as one of their attributes.
+
+Fitting functions for QENS data depending on :math:`Q` should derive from this class.
+
+There are two ways to update attribute :math:`Q` in the fit funtion:
+
+- The user inputs a particular value.
+- The spectrum contains :math:`Q` in addition to the range of energy transfers.
+
+Conflict may arise when both options are available. In that case, priority is given to the :math:`Q`-value contained
+in the spectrum. Here are some user cases:
+
+- User cannot override the value of attribute :math:`Q` if the spectrum contains a :math:`Q`-value.
+- User can set or update the value of of attribute :math:`Q` is the spectrum does not contain a :math:`Q`-value.
+- The value of attribute :math:`Q` will be updated everytime we pass a new spectrum containing a :math:`Q`-value.
+- The value of attribute :math:`Q` will be erased if we pass a new spectrum not containing a :math:`Q`-value. In this case it is the responsability of the user to set the appropriate value.
diff --git a/docs/source/fitfunctions/TeixeiraWaterSQE.rst b/docs/source/fitfunctions/TeixeiraWaterSQE.rst
index b7e2cd64041576d9ed15c02e60eb31f4fb8c09c6..218a1e97ff976b8090583a76b1e9fbe5cc7b8445 100644
--- a/docs/source/fitfunctions/TeixeiraWaterSQE.rst
+++ b/docs/source/fitfunctions/TeixeiraWaterSQE.rst
@@ -45,17 +45,48 @@ References
 Usage
 -----
 
-**Example - Global fit to a synthetic signal:**
+**Example - Single spectrum fit:**
 
 The signal is modeled by the convolution of a resolution function
-with an elastic signal plus this jump-diffusion model.
+with an elastic signal plus this jump-diffusion model. We include a linear background.
+The value of the momentum transfer :math:`Q` is contained in the loaded data
+
+:math:`S(Q,E) = I \cdot R(Q,E) \otimes [EISF\delta(E) + (1-EISF)\cdot TeixeiraWaterSQE(Q,E)] + (a+bE)`
+
+.. testcode:: SingleSpectrumTeixeiraWaterSQE
+
+    from __future__ import (absolute_import, division, print_function)
+    resolution=Load("irs26173_graphite002_res.nxs")
+    data=Load("irs26176_graphite002_red.nxs")
+    function="""
+    (composite=Convolution,FixResolution=false,NumDeriv=true;
+      name=TabulatedFunction,Workspace=resolution,WorkspaceIndex=0,Scaling=1,XScaling=1,ties=(Scaling=1,XScaling=1);
+      (  name=DeltaFunction,Centre=0,ties=(Centre=0);
+         name=TeixeiraWaterSQE,Centre=0,ties=(Centre=0),constraints=(DiffCoeff<3.0)
+      )
+    );
+    name=LinearBackground"""
+    # Let's fit spectrum with workspace index 5. Appropriate value of Q is picked up
+    # automatically from workspace 'data' and passed on to the fit function
+    out,chi2,covariance,params,curves=Fit(Function=function, InputWorkspace=data,
+        WorkspaceIndex=5, CreateOutput=True, Output="fit", MaxIterations=100)
+    # Check some results
+    drow=params.row(6)
+    DiffCoeff = params.row(6)["Value"]
+    Tau = params.row(7)["Value"]
+    if abs(DiffCoeff-2.1)/2.1 < 0.1 and abs(Tau-1.85)/1.85 < 0.1:
+        print("Optimal parameters within 10% of expected values")
+    else:
+        print(DiffCoeff, Tau, chi2)
+
+
+**Example - Global fit to a synthetic signal:**
+
+The signal is modeled by the model of the previous example.
 The resolution is modeled as a normal distribution.
-We insert a random noise in the jump-diffusion model.
+We insert a random noise in the jump-diffusion data.
 Finally, we choose a linear background noise.
 The goal is to find out the residence time and the jump length
-with a fit to the following model:
-
-:math:`S(Q,E) = I \cdot R(Q,E) \otimes [EISF\delta(E) + (1-EISF)\cdot TeixeiraWaterSQE(Q,E)] + (a+bE)`
 
 .. testcode:: ExampleTeixeiraWaterSQE
 
@@ -109,7 +140,7 @@ with a fit to the following model:
     single_model_template="""(composite=Convolution,FixResolution=true,NumDeriv=true;
     name=TabulatedFunction,Workspace=resolution,WorkspaceIndex=_WI_,Scaling=1,Shift=0,XScaling=1;
     (name=DeltaFunction,Height=0.5,Centre=0,constraints=(0<Height<1);
-    name=TeixeiraWaterSQE,Q=_Q_,Height=0.5,Tau=10,DiffCoeff=10,Centre=0;
+    name=TeixeiraWaterSQE,Q=_Q_,Height=0.5,Tau=10,DiffCoeff=5,Centre=0;
     ties=(f1.Height=1-f0.Height,f1.Centre=f0.Centre)));
     name=LinearBackground,A0=0,A1=0"""
     # Now create the string representation of the global model (all spectra, all Q-values):
@@ -135,7 +166,7 @@ with a fit to the following model:
                 "StartX_"+str(wi): "-0.09", "EndX_"+str(wi): "0.09"})
     # Invoke the Fit algorithm using global_model and domain_model:
     output_workspace = "glofit_"+data.name()
-    Fit(Function=global_model, Output=output_workspace, CreateOutput=True, MaxIterations=500, **domain_model)
+    Fit(Function=global_model, Output=output_workspace, CreateOutput=True, MaxIterations=200, **domain_model)
     # Extract DiffCoeff and Tau from workspace glofit_data_Parameters, the output of Fit:
     nparms=0
     parameter_ws = mtd[output_workspace+"_Parameters"]
@@ -162,6 +193,10 @@ with a fit to the following model:
 
 Output:
 
+.. testoutput:: SingleSpectrumTeixeiraWaterSQE
+
+    Optimal parameters within 10% of expected values
+
 .. testoutput:: ExampleTeixeiraWaterSQE
 
     Optimal Length within 10% of nominal value
diff --git a/docs/source/fitminimizers/BFGS.rst b/docs/source/fitminimizers/BFGS.rst
new file mode 100644
index 0000000000000000000000000000000000000000..18ac3f17de74498a559d396550ffff2312915734
--- /dev/null
+++ b/docs/source/fitminimizers/BFGS.rst
@@ -0,0 +1,18 @@
+.. _BFGS:
+
+BFGS (Broyden-Fletcher-Goldfarb-Shanno) minimizer
+=================================================
+
+This minimizer is
+explained at `Wikipedia <https://en.wikipedia.org/wiki/Broyden–Fletcher–Goldfarb–Shanno_algorithm>`__ 
+
+It is listed in `a comparison of fitting minimizers <../concepts/FittingMinimizers.html>`__.
+
+It makes use of the 
+`GSL (GNU Scientific Library) library
+<https://www.gnu.org/software/gsl/>`__, specifically the 
+`GSL routines for least-squares fitting
+<https://www.gnu.org/software/gsl/manual/html_node/Least_002dSquares-Fitting.html#Least_002dSquares-Fitting>`__.
+
+.. categories:: FitMinimizers
+
diff --git a/docs/source/fitminimizers/DampedGaussNewton.rst b/docs/source/fitminimizers/DampedGaussNewton.rst
new file mode 100644
index 0000000000000000000000000000000000000000..86cfb1f193b94f55d965896ad83df298147f296b
--- /dev/null
+++ b/docs/source/fitminimizers/DampedGaussNewton.rst
@@ -0,0 +1,19 @@
+.. _DampedGaussNewton:
+
+Damped Gauss-Newton minimizer
+=============================
+
+This minimizer is
+explained at `Wikipedia <https://en.wikipedia.org/wiki/Gauss–Newton_algorithm#Improved_versions>`__ 
+and has damping.
+
+It is listed in `a comparison of fitting minimizers <../concepts/FittingMinimizers.html>`__.
+
+It makes use of the 
+`GSL (GNU Scientific Library) library
+<https://www.gnu.org/software/gsl/>`__, specifically the 
+`GSL routines for least-squares fitting
+<https://www.gnu.org/software/gsl/manual/html_node/Least_002dSquares-Fitting.html#Least_002dSquares-Fitting>`__.
+
+.. categories:: FitMinimizers
+
diff --git a/docs/source/fitminimizers/FletcherReeves.rst b/docs/source/fitminimizers/FletcherReeves.rst
new file mode 100644
index 0000000000000000000000000000000000000000..42f581c9aec20f2dc68590e416f10793e03b7d9c
--- /dev/null
+++ b/docs/source/fitminimizers/FletcherReeves.rst
@@ -0,0 +1,18 @@
+.. _FletcherReeves:
+
+Conjugate Gradient Minimizer (Fletcher-Reeves imp.)
+===================================================
+
+This minimizer an implementation of the nonlinear conjugate gradient method 
+explained at `Wikipedia <https://en.wikipedia.org/wiki/Nonlinear_conjugate_gradient_method>`__ 
+
+It is listed in `a comparison of fitting minimizers <../concepts/FittingMinimizers.html>`__.
+
+It makes use of the 
+`GSL (GNU Scientific Library) library
+<https://www.gnu.org/software/gsl/>`__, specifically the 
+`GSL routines for least-squares fitting
+<https://www.gnu.org/software/gsl/manual/html_node/Least_002dSquares-Fitting.html#Least_002dSquares-Fitting>`__.
+
+.. categories:: FitMinimizers
+
diff --git a/docs/source/fitminimizers/GradientDescent.rst b/docs/source/fitminimizers/GradientDescent.rst
new file mode 100644
index 0000000000000000000000000000000000000000..30c7f77b753e0f96c133becddb971a76c1ef3d56
--- /dev/null
+++ b/docs/source/fitminimizers/GradientDescent.rst
@@ -0,0 +1,16 @@
+.. _GradientDescent:
+
+Steepest Descent Minimizer
+==========================
+
+This minimizer is explained at - `Wikipedia <https://en.wikipedia.org/wiki/Gradient_descent>`__  as the gradient descent method.
+It is listed in `a comparison of fitting minimizers <../concepts/FittingMinimizers.html>`__.
+
+It makes use of the 
+`GSL (GNU Scientific Library) library
+<https://www.gnu.org/software/gsl/>`__, specifically the 
+`GSL routines for least-squares fitting
+<https://www.gnu.org/software/gsl/manual/html_node/Least_002dSquares-Fitting.html#Least_002dSquares-Fitting>`__.
+
+.. categories:: FitMinimizers
+
diff --git a/docs/source/fitminimizers/LevenbergMarquardt.rst b/docs/source/fitminimizers/LevenbergMarquardt.rst
new file mode 100644
index 0000000000000000000000000000000000000000..2d4cf38415a375ba6510d6388a233189b780cc36
--- /dev/null
+++ b/docs/source/fitminimizers/LevenbergMarquardt.rst
@@ -0,0 +1,16 @@
+.. _LevenbergMarquardt:
+
+Levenberg-Marquardt Minimizer
+=============================
+
+This minimizer is explained at - `Wikipedia <https://en.wikipedia.org/wiki/Levenberg-Marquardt_algorithm>`__ 
+It is the default minimizer and is listed in `a comparison of fitting minimizers <../concepts/FittingMinimizers.html>`__.
+
+It makes use of the 
+`GSL (GNU Scientific Library) library
+<https://www.gnu.org/software/gsl/>`__, specifically the 
+`GSL routines for least-squares fitting
+<https://www.gnu.org/software/gsl/manual/html_node/Least_002dSquares-Fitting.html#Least_002dSquares-Fitting>`__.
+
+.. categories:: FitMinimizers
+
diff --git a/docs/source/fitminimizers/LevenbergMarquardtMD.rst b/docs/source/fitminimizers/LevenbergMarquardtMD.rst
new file mode 100644
index 0000000000000000000000000000000000000000..1e471e6daeb858c6eda4e131be760548fd3de5ed
--- /dev/null
+++ b/docs/source/fitminimizers/LevenbergMarquardtMD.rst
@@ -0,0 +1,22 @@
+.. _LevenbergMarquardtMD:
+
+Levenberg-Marquardt MD Minimizer
+================================
+
+This minimizer is the same as the `Levenberg-Marquardt minimizer <LevenbergMarquardt.html>`__ as explained 
+in - `Wikipedia <https://en.wikipedia.org/wiki/Levenberg-Marquardt_algorithm>`__ , but is intended for 
+`MD workspaces <../concepts/MDWorkspace.html>`__
+or for a large number of data points.
+It divides its work into chunks to achieve a greater efficiency for a large number of data points than
+can be obtained from the default Levenberg-Marquardt minimizer.
+
+It is listed in `a comparison of fitting minimizers <../concepts/FittingMinimizers.html>`__.
+
+It makes use of the 
+`GSL (GNU Scientific Library) library
+<https://www.gnu.org/software/gsl/>`__, specifically the 
+`GSL routines for least-squares fitting
+<https://www.gnu.org/software/gsl/manual/html_node/Least_002dSquares-Fitting.html#Least_002dSquares-Fitting>`__.
+
+.. categories:: FitMinimizers
+
diff --git a/docs/source/fitminimizers/PolakRibiere.rst b/docs/source/fitminimizers/PolakRibiere.rst
new file mode 100644
index 0000000000000000000000000000000000000000..d58deccf62d18e35cf40287c37014a6dcb25d5fc
--- /dev/null
+++ b/docs/source/fitminimizers/PolakRibiere.rst
@@ -0,0 +1,17 @@
+.. _PolakRiberiere:
+
+Conjugate Gradient Minimizer (Polak-Ribiere imp.)
+=================================================
+
+This minimizer an implementation of the nonlinear conjugate gradient method 
+explained at `Wikipedia <https://en.wikipedia.org/wiki/Nonlinear_conjugate_gradient_method>`__ .
+
+It is listed in `a comparison of fitting minimizers <../concepts/FittingMinimizers.html>`__.
+
+It makes use of the 
+`GSL (GNU Scientific Library) library
+<https://www.gnu.org/software/gsl/>`__, specifically the 
+`GSL routines for least-squares fitting
+<https://www.gnu.org/software/gsl/manual/html_node/Least_002dSquares-Fitting.html#Least_002dSquares-Fitting>`__.
+
+.. categories:: FitMinimizers
diff --git a/docs/source/fitminimizers/Simplex.rst b/docs/source/fitminimizers/Simplex.rst
new file mode 100644
index 0000000000000000000000000000000000000000..7364b6a7c1c7c8757f3d6ae2e755c541484ba53b
--- /dev/null
+++ b/docs/source/fitminimizers/Simplex.rst
@@ -0,0 +1,16 @@
+.. _Simplex:
+
+Simplex Minimizer
+=================
+
+This minimizer is explained at - `Wikipedia <https://en.wikipedia.org/wiki/Nelder%E2%80%93Mead_method>`__  as the Nelder-Mead method.
+It is listed in `a comparison of fitting minimizers <../concepts/FittingMinimizers.html>`__.
+
+It makes use of the 
+`GSL (GNU Scientific Library) library
+<https://www.gnu.org/software/gsl/>`__, specifically the 
+`GSL routines for least-squares fitting
+<https://www.gnu.org/software/gsl/manual/html_node/Least_002dSquares-Fitting.html#Least_002dSquares-Fitting>`__.
+
+.. categories:: FitMinimizers
+
diff --git a/docs/source/fitminimizers/TrustRegion.rst b/docs/source/fitminimizers/TrustRegion.rst
new file mode 100644
index 0000000000000000000000000000000000000000..5e6d87879f7214b5160684813175ad04a7a2a327
--- /dev/null
+++ b/docs/source/fitminimizers/TrustRegion.rst
@@ -0,0 +1,15 @@
+.. _TrustRegion:
+
+Trust Region Minimizer
+======================
+
+This minimizer is a hybrid 
+`Gauss-Newton <https://en.wikipedia.org/wiki/Gauss%E2%80%93Newton_algorithm>`__/`Quasi-Newton <https://en.wikipedia.org/wiki/Quasi-Newton_method>`__ 
+method, that makes use of a `trust region <https://en.wikipedia.org/wiki/Trust_region>`__.
+
+It is a reimplementation of part of `RALFit_nonlinear least squares solver <https://github.com/ralna/RALFit>`__. 
+
+It is listed in `a comparison of fitting minimizers <../concepts/FittingMinimizers.html>`__.
+
+.. categories:: FitMinimizers
+
diff --git a/docs/source/fitminimizers/index.rst b/docs/source/fitminimizers/index.rst
new file mode 100644
index 0000000000000000000000000000000000000000..8f47df4615b2500589e4bca562ab85fcc657c298
--- /dev/null
+++ b/docs/source/fitminimizers/index.rst
@@ -0,0 +1,19 @@
+.. Fitting Minimizers master file
+   It contains a hidden root toctree directive so that Sphinx
+   has an internal index of all of the pages and doesn't
+   produce a plethora of warnings about most documents not being in
+   a toctree.
+   See http://sphinx-doc.org/tutorial.html#defining-document-structure
+
+.. _fitminimizers contents:
+
+==================
+Fitting Minimizers
+==================
+
+.. toctree::
+   :glob:
+   :maxdepth: 1
+
+   *
+
diff --git a/docs/source/images/EstimateFitParameters_ceest.png b/docs/source/images/EstimateFitParameters_ceest.png
new file mode 100644
index 0000000000000000000000000000000000000000..12a9af3e0f8cc8ddcbd65ba579dfe096b6aeb3d9
Binary files /dev/null and b/docs/source/images/EstimateFitParameters_ceest.png differ
diff --git a/docs/source/images/EstimateFitParameters_cefit.png b/docs/source/images/EstimateFitParameters_cefit.png
new file mode 100644
index 0000000000000000000000000000000000000000..17b3561eacc26a61d3500a0d3d3d4335f4e02035
Binary files /dev/null and b/docs/source/images/EstimateFitParameters_cefit.png differ
diff --git a/docs/source/images/EstimateFitParameters_mcest.png b/docs/source/images/EstimateFitParameters_mcest.png
new file mode 100644
index 0000000000000000000000000000000000000000..13a21da8003b8972f4be87460c86edc58ad6cf05
Binary files /dev/null and b/docs/source/images/EstimateFitParameters_mcest.png differ
diff --git a/docs/source/images/EstimateFitParameters_mcfit.png b/docs/source/images/EstimateFitParameters_mcfit.png
new file mode 100644
index 0000000000000000000000000000000000000000..3fdb0e2a406fa385b762f5ca9ede6444aec24c3a
Binary files /dev/null and b/docs/source/images/EstimateFitParameters_mcfit.png differ
diff --git a/docs/source/images/EstimateFitParameters_output.png b/docs/source/images/EstimateFitParameters_output.png
new file mode 100644
index 0000000000000000000000000000000000000000..6427f0a5549f00f87fc95899973e8f77403a8f21
Binary files /dev/null and b/docs/source/images/EstimateFitParameters_output.png differ
diff --git a/docs/source/images/FitExcludeRange.png b/docs/source/images/FitExcludeRange.png
new file mode 100644
index 0000000000000000000000000000000000000000..6cf663445d22fab1ca413f1a7f19936a5c24f7ad
Binary files /dev/null and b/docs/source/images/FitExcludeRange.png differ
diff --git a/docs/source/images/ISISReflectometryPolref_INTER_table.JPG b/docs/source/images/ISISReflectometryPolref_INTER_table.JPG
deleted file mode 100644
index b72b29bdd4b72bd45eb7310c07942ea340dda9f4..0000000000000000000000000000000000000000
Binary files a/docs/source/images/ISISReflectometryPolref_INTER_table.JPG and /dev/null differ
diff --git a/docs/source/images/ISISReflectometryPolref_INTER_table.png b/docs/source/images/ISISReflectometryPolref_INTER_table.png
new file mode 100644
index 0000000000000000000000000000000000000000..c7e89adc207073bf060dfacd75bba83b2e2d183d
Binary files /dev/null and b/docs/source/images/ISISReflectometryPolref_INTER_table.png differ
diff --git a/docs/source/images/ISISReflectometryPolref_failed_transfer_run.JPG b/docs/source/images/ISISReflectometryPolref_failed_transfer_run.JPG
deleted file mode 100644
index da956e216b4526827ccb0e401cb218a7ca019212..0000000000000000000000000000000000000000
Binary files a/docs/source/images/ISISReflectometryPolref_failed_transfer_run.JPG and /dev/null differ
diff --git a/docs/source/images/ISISReflectometryPolref_failed_transfer_run.png b/docs/source/images/ISISReflectometryPolref_failed_transfer_run.png
new file mode 100644
index 0000000000000000000000000000000000000000..bd4bd47385233947371f1a7b8bd26ad5a83d32cf
Binary files /dev/null and b/docs/source/images/ISISReflectometryPolref_failed_transfer_run.png differ
diff --git a/docs/source/images/ISISReflectometryPolref_save_tab.png b/docs/source/images/ISISReflectometryPolref_save_tab.png
new file mode 100644
index 0000000000000000000000000000000000000000..dbb71a0f04966c9415ee06a6c7f3a121f53c83e9
Binary files /dev/null and b/docs/source/images/ISISReflectometryPolref_save_tab.png differ
diff --git a/docs/source/images/ISISReflectometryPolref_settings_tab.png b/docs/source/images/ISISReflectometryPolref_settings_tab.png
new file mode 100644
index 0000000000000000000000000000000000000000..fc1732aae929e1a767f03ee81332b0603450c854
Binary files /dev/null and b/docs/source/images/ISISReflectometryPolref_settings_tab.png differ
diff --git a/docs/source/images/MuonAnalysisDataAnalysis3.8.png b/docs/source/images/MuonAnalysisDataAnalysis3.8.png
index 4753b90faf5188a852b23f7bbbebd65d979d12a5..d58a73d27c1e6115b6d1254f1557a00ef70593ed 100644
Binary files a/docs/source/images/MuonAnalysisDataAnalysis3.8.png and b/docs/source/images/MuonAnalysisDataAnalysis3.8.png differ
diff --git a/docs/source/images/MuonAnalysisTests/fitting_test1.png b/docs/source/images/MuonAnalysisTests/fitting_test1.png
index 64d6eae09e03710d7ab5aed1ccd84c01570e10a8..609e5d62fd1d503a3fb30cda96947f4faa1d1893 100644
Binary files a/docs/source/images/MuonAnalysisTests/fitting_test1.png and b/docs/source/images/MuonAnalysisTests/fitting_test1.png differ
diff --git a/docs/source/images/MuonAnalysisTests/multiperiod-before.png b/docs/source/images/MuonAnalysisTests/multiperiod-before.png
index 6443e0ecc7d28b40262f8d260bc30ba267d90ebd..ecfb8451d0a9c1eadd74d115cc00a8dbf70c2f3b 100644
Binary files a/docs/source/images/MuonAnalysisTests/multiperiod-before.png and b/docs/source/images/MuonAnalysisTests/multiperiod-before.png differ
diff --git a/docs/source/images/MuonAnalysisTests/multiperiod.png b/docs/source/images/MuonAnalysisTests/multiperiod.png
index 5616eba57b6b6e36911e8f950f1a094e655873bc..e34808685e0d1132097573210e00efcd97e9b79a 100644
Binary files a/docs/source/images/MuonAnalysisTests/multiperiod.png and b/docs/source/images/MuonAnalysisTests/multiperiod.png differ
diff --git a/docs/source/images/NoPeakRadius_3.9.png b/docs/source/images/NoPeakRadius_3.9.png
new file mode 100644
index 0000000000000000000000000000000000000000..f8e515f062e9f77c7a28cb0e79d13cc80a28ffd4
Binary files /dev/null and b/docs/source/images/NoPeakRadius_3.9.png differ
diff --git a/docs/source/images/PeakRadius_Fit.png b/docs/source/images/PeakRadius_Fit.png
new file mode 100644
index 0000000000000000000000000000000000000000..b9cfc71c6a220ee13382a097ae911aa6bca61841
Binary files /dev/null and b/docs/source/images/PeakRadius_Fit.png differ
diff --git a/docs/source/images/SliceViewerNonOrthogonal.png b/docs/source/images/SliceViewerNonOrthogonal.png
new file mode 100644
index 0000000000000000000000000000000000000000..49bd105e416696ef4adf625f67612a6dc154b490
Binary files /dev/null and b/docs/source/images/SliceViewerNonOrthogonal.png differ
diff --git a/docs/source/images/Stitch1D1.png b/docs/source/images/Stitch1D1.png
index 90e8839046917b174104ce571dd053175ec91a43..280e1cea80d0f1daedfbcc2d7b16280626b88bcd 100644
Binary files a/docs/source/images/Stitch1D1.png and b/docs/source/images/Stitch1D1.png differ
diff --git a/docs/source/images/Stitch1D2.png b/docs/source/images/Stitch1D2.png
index a9d9b115dd2b95b7ef88bec1b8d9cf7be7a3fcb0..1e5b0ab84ca999f0847296dbf45d33a8cd93d1df 100644
Binary files a/docs/source/images/Stitch1D2.png and b/docs/source/images/Stitch1D2.png differ
diff --git a/docs/source/images/release38.png b/docs/source/images/release38.png
new file mode 100644
index 0000000000000000000000000000000000000000..433124b8bd2a1a2a6b0aa0588da0fb3cad0c85fd
Binary files /dev/null and b/docs/source/images/release38.png differ
diff --git a/docs/source/images/release39.PNG b/docs/source/images/release39.PNG
new file mode 100644
index 0000000000000000000000000000000000000000..b2e07b8750bde9414d2436fac2f08200e76877c6
Binary files /dev/null and b/docs/source/images/release39.PNG differ
diff --git a/docs/source/index.rst b/docs/source/index.rst
index 811ae0a59a632041c461816234487915175e1753..c717b16cdfefc488505425a5db5e10168285e341 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -25,6 +25,7 @@ Mantid Documentation
    concepts/index
    interfaces/index
    fitfunctions/*
+   fitminimizers/index
    api/index
    release/index
 
@@ -42,6 +43,7 @@ This is the documentation for Mantid |release|.
 * `Concepts <concepts/index.html>`_
 * `Interfaces <interfaces/index.html>`_
 * `Fit Functions <fitfunctions/index.html>`_
+* `Fit Minimizers <fitminimizers/index.html>`_
 * `API <api/index.html>`_
     - `Python <api/python/index.html>`_
     - `C++ <http://doxygen.mantidproject.org/>`_ (Doxygen)
diff --git a/docs/source/interfaces/CrystalFieldPythonInterface.rst b/docs/source/interfaces/CrystalFieldPythonInterface.rst
index 02f50afdba02e4c6cab47d710ec0e9c38203e38c..ac48f0dc4bb8b932e6ad0fbf83140f8c58dee00a 100644
--- a/docs/source/interfaces/CrystalFieldPythonInterface.rst
+++ b/docs/source/interfaces/CrystalFieldPythonInterface.rst
@@ -6,7 +6,7 @@ Crystal Field Python Interface
 .. contents::
   :local:
 
-The python facilities for Crystal Field calculations are avalable in Mantid from module `CrystalField`.
+The python facilities for Crystal Field calculations are available in Mantid from module `CrystalField`.
 There are two main classes the module provides: `CrystalFiled` that defines various properties of a crystal
 field and `CrystalFieldFit` that manages the fitting process.
 
@@ -14,7 +14,7 @@ field and `CrystalFieldFit` that manages the fitting process.
 Setting up crystal field parameters
 -----------------------------------
 
-A crystal field computation starts with cretaing an instance of the `CrystalField` class. The constructor
+A crystal field computation starts with creating an instance of the `CrystalField` class. The constructor
 has two mandatory arguments: `Ion` - a symbolic name of the ion, and `Symmetry` - a name of the symmetry group
 of the field. The rest of the parameters are optional.
 
@@ -33,7 +33,7 @@ The minimum code to create a crystal field object is::
   cf = CrystalField('Ce', 'C2v')
   
 Names of the crystal field parameters have the form `Bnn` and `IBnn` where `nn` are two digits between 0 and 6.
-The `Bnn` is a real and the `IBnn` is an imaginary part of a complex parameter. If a parameter isn't set explicitely
+The `Bnn` is a real and the `IBnn` is an imaginary part of a complex parameter. If a parameter isn't set explicitly
 its default value is 0. To set a parameter pass it to the `CrystalField` constructor as a keyword argument, e.g.::
 
   cf = CrystalField('Ce', 'C2v', B20=0.37737, B22=3.9770)
@@ -42,7 +42,7 @@ An alternative way to set a parameter is to use the square brackets with a `Crys
 
   cf['B40'] = -0.031
   
-Wich can also be used to query the value of a parameter::
+Which can also be used to query the value of a parameter::
 
   b = cf['B40']
 
@@ -104,7 +104,7 @@ The new output::
  [[   0.           24.40061976   42.49771237]
   [ 216.71156467   88.30985303    5.04430056]]
   
-To calcualte a spectrum we need to define a shape of each peak (peak profile function) and its default width (`FWHM`).
+To calculate a spectrum we need to define a shape of each peak (peak profile function) and its default width (`FWHM`).
 The width can be set either via a keyword argument or a property with name `FWHM`. If the peak shape isn't set the default
 of Lorentzian is assumed. To set a different shape use the `setPeaks` method::
 
@@ -176,7 +176,7 @@ A background has two components: a peak and a general background function. Set a
     cf.background = Background(peak=Function('Gaussian', Height=10, Sigma=1),
                                background=Function('LinearBackground', A0=1.0, A1=0.01))
     
-Here is an example of how to access the prameters of the background::
+Here is an example of how to access the parameters of the background::
     
     h = cf.background.peak.param['Height']
     a1 = cf.background.background.param['A1']
@@ -185,7 +185,7 @@ Here is an example of how to access the prameters of the background::
 Setting Ties and Constraints
 ----------------------------
 
-Seting ties and constraints are done by calling the `ties` and `constraints` methods of the `CrystalField` class or its components.
+Setting ties and constraints are done by calling the `ties` and `constraints` methods of the `CrystalField` class or its components.
 To `Bnn` parameters are tied by the `CrystalField` class directly specifying the tied parameter as a keyword argument::
 
   cf.ties(B20=1.0, B40='B20/2')
@@ -203,7 +203,7 @@ For the parameters of the background the syntax is the same but the methods are
     
 The names of the peak parameters both in ties and constraints must include the index of the peak to which they belong. Here we follow
 the naming convention of the :ref:`func-CompositeFunction`: f<n>.<name>, where <n> stands for an integer index staring at 0 and <name>
-is the name of the parameter. For example, `f1.Sigma`, `f3.FWHM`. Because names now contain the period symmbol '.' keyword arguments
+is the name of the parameter. For example, `f1.Sigma`, `f3.FWHM`. Because names now contain the period symbol '.' keyword arguments
 cannot be used. Instead we must pass strings containing ties::
 
     cf.peaks.ties('f2.FWHM=2*f1.FWHM', 'f3.FWHM=2*f2.FWHM')
@@ -256,7 +256,7 @@ Example of setting a resolution model::
     rm = ResolutionModel(my_func, xstart=0.0, xend=120.0, accuracy=0.01)
     cf = CrystalField('Ce', 'C2v', B20=0.37737, B22=3.9770, ..., Temperature=44.0, ResolutionModel=rm)
 
-When a resolution model is set the peak width will be constrained to have a value close to the model. The degree of deviation is controled by the
+When a resolution model is set the peak width will be constrained to have a value close to the model. The degree of deviation is controlled by the
 `FWHMVariation` parameter. It has the default of 0.1 and is an absolute maximum difference a width can have. If set to 0 the widths will be fixed
 to their calculated values (depending on the instant values of their peak centres). For example::
 
@@ -280,7 +280,7 @@ become lists. Here is an example of defining a `CrystalField` object with two sp
     cf.background[1].peak.param['Sigma'] = 0.8
     cf.background[1].background.param['A0'] = 1.1
 
-Note how `Temperature`, `FWHM`, `peaks` and `background` become lists. They must have the same size. Ties and constraints similarily
+Note how `Temperature`, `FWHM`, `peaks` and `background` become lists. They must have the same size. Ties and constraints similarly
 change::
 
     # The B parameters are common for all spectra - syntax doesn't change
@@ -305,7 +305,7 @@ The resolution model also needs to be initialised from a list::
     rm = ResolutionModel([func0, func1], 0, 100, accuracy = 0.01)
 
 
-To calcualte a spectrum call the same method `getSpectrum` but pass the pectrum index as its first parameter::
+To calculate a spectrum call the same method `getSpectrum` but pass the spectrum index as its first parameter::
 
   # Calculate second spectrum, use the generated x-values
   sp = cf.getSpectrum(1)
@@ -332,6 +332,12 @@ If there are multiple ions define `CrystalField` objects for each ion separately
     cf2 = CrystalField('Pr', 'C2v', **params)
     cf = cf1 + cf2
 
+The expression that combines the `CrystalField` objects also defines the contributions of each site into the overall intensity.
+The higher the coefficient of the object in the expression the higher its relative contribution. For example::
+
+    cf = 2*cf1 + cf2
+
+means that the intensity of `cf1` should be twice that of `cf2`.
 
 Fitting
 -------
@@ -351,5 +357,212 @@ Then call `fit()` method::
     fit.fit()
     
 After fitting finishes the `CrystalField` object updates automatically and contains new fitted parameter values.
-  
+
+Finding Initial Parameters
+--------------------------
+
+If the initial values of the fitting parameters are not known they can be estimated using `estimate_parameters()` method.
+It randomly searches the parameter space in a given region such that the calculated spectra are as close to the
+fit data as possible. The method uses :ref:`EstimateFitParameters <algm-EstimateFitParameters>` internally. See
+algorithm's description for the available properties.
+Here is an example of a fit with initial estimation::
+
+    from CrystalField.fitting import makeWorkspace
+    from CrystalField import CrystalField, CrystalFieldFit, Background, Function
+
+    # Create some crystal field data
+    origin = CrystalField('Ce', 'C2v', B20=0.37737, B22=3.9770, B40=-0.031787, B42=-0.11611, B44=-0.12544,
+                          Temperature=44.0, FWHM=1.1)
+    x, y = origin.getSpectrum()
+    ws = makeWorkspace(x, y)
+
+    # Define a CrystalField object with parameters slightly shifted.
+    cf = CrystalField('Ce', 'C2v', B20=0, B22=0, B40=0, B42=0, B44=0,
+                      Temperature=44.0, FWHM=1.0, ResolutionModel=([0, 100], [1, 1]), FWHMVariation=0)
+
+    # Set any ties on the field parameters.
+    cf.ties(B20=0.37737)
+    # Create a fit object
+    fit = CrystalFieldFit(cf, InputWorkspace=ws)
+    # Find initial values for the field parameters.
+    # You need to define the energy splitting and names of parameters to estimate.
+    # Optionally additional constraints can be set on tied parameters (eg, peak centres).
+    fit.estimate_parameters(EnergySplitting=50,
+                            Parameters=['B22', 'B40', 'B42', 'B44'],
+                            Constraints='20<f1.PeakCentre<45,20<f2.PeakCentre<45',
+                            NSamples=1000)
+    print 'Returned', fit.get_number_estimates(), 'sets of parameters.'
+    # The first set (the smallest chi squared) is selected by default.
+    # Select a different parameter set if required
+    fit.select_estimated_parameters(3)
+    print cf['B22'], cf['B40'], cf['B42'], cf['B44']
+    # Run fit
+    fit.fit()
+
+Calculating Physical Properties
+-------------------------------
+
+In addition to the inelastic neutron spectrum, various physical properties arising from the crystal field interaction
+can be calculated. These include the crystal field contribution to the magnetic heat capacity, the magnetic 
+susceptibility, and magnetisation. The calculated values can be invoked using the `getHeatCapacity()`, 
+`getSusceptibility()` and `getMagneticMoment()` methods. 
+
+To calculate the heat capacity use::
+
+    Cv = cf.getHeatCapacity()       # Calculates Cv(T) for 1<T<300K in 1K steps  (default)
+    pyplot.plot(*Cv)                # Returns a tuple of (x, y) values
+
+    T = np.arange(1,900,5)
+    Cv = cf.getHeatCapacity(T)      # Calculates Cv(T) for specified values of T (1 to 900K in 5K steps here)
+    pyplot.plot(T, Cv[1])
+
+    # Temperatures from a single spectrum workspace
+    ws = CreateWorkspace(T, T, T)
+    Cv = cf.getHeatCapacity(ws)     # Use the x-values of a workspace as the temperatures
+    ws_calc = CreateWorkspace(*Cv)
+    plot(ws_calc, 0)                # Creates workspace from data and plots it (plots the first spectrum, index 0)
+
+    # Temperatures from a multi-spectrum workspace
+    ws = CreateWorkspace(T, T, T, NSpec=2)
+    Cv = cf.getHeatCapacity(ws, 1)  # Uses the second spectrum's x-values for T (e.g. 450<T<900)
+    plot(*Cv)
+
+All the physical properties methods returns a tuple of `(x, y)` values. The heat capacity is calculated in 
+Jmol\ :sup:`-1`\ K\ :sup:`-1`\ .
+The theory is described in :ref:`CrystalFieldHeatCapacity <func-CrystalFieldHeatCapacity>`.
+
+The molar susceptibility is calculated using Van Vleck's formula, and requires in addition knowledge of the applied 
+field direction (default is `[0, 0, 1]` where the field is along the crystal field quantisation direction)::
+
+    chi_v = cf.getSusceptibility(T, Hdir=[1, 1, 1])
+
+The field direction is a Cartesian vector with coordinates defined with the `z`-axis parallel to the quantisation
+direction of the crystal field parameters (usually taken to be the highest symmetry rotation axis). To calculate
+for a powder averaged field direction use::
+
+    chi_v_powder = cf.getSusceptibility(T, Hdir='powder')
+
+The powder averaging is done by taking the mean of the susceptibility (or magnetisation) along the :math:`x`,
+:math:`y` and :math:`z` directions (e.g. :math:`\chi^{\mathrm{pow}} = (\chi^x + \chi^y + \chi^z)/3`).
+
+Note that the function calculates the *molar* magnetic susceptibility, and by default outputs it in *cgs* units
+(cm\ :sup:`3`/mol or emu/mol). To obtain the result in SI units (m\ :sup:`3`/mol)
+use::
+
+    chi_v_cgs = cf.getSusceptibility(T, Hdir=[1, 1, 0], Unit='SI')
+
+In addition, "atomic" units (:math:`\mu_B/\mathrm{T}/\mathrm{ion}`) can also be obtained using::
+
+    chi_v_bohr = cf.getSusceptibility(T, Unit='bohr')
+
+The theory is described in the :ref:`CrystalFieldSusceptibility <func-CrystalFieldSusceptibility>` function page.
+
+The magnetic moment is calculated by adding a Zeeman interaction to the crystal field Hamiltonian and diagonalising 
+the combined matrix, from which the expectation of the magnetic moment operator is calculated. The moment can
+be calculated as a function of temperature or applied field magnitude::
+
+    moment_t = cf.getMagneticMoment(Temperature=T, Hdir=[1, 1, 1], Hmag=0.1) # Calcs M(T) with at 0.1T field||[111]
+    H = np.linspace(0, 30, 121)
+    moment_h = cf.getMagneticMoment(Hmag=H, Hdir='powder', Temperature=10)   # Calcs M(H) at 10K for powder sample
+
+By default, the magnetisation is calculated in atomic units of bohr magnetons per magnetic ion. Alternatively, the 
+SI or cgs molar magnetic moments can be calculated::
+
+    moment_SI = cf.getMagneticMoment(H, [1, 1, 1], Unit='SI')         # M(H) in Am^2/mol at 1K for H||[111]
+    moment_cgs = cf.getMagneticMoment(100, Temperature=T, Unit='cgs') # M(T) in emu/mol in a field of 100G || [001]
+
+Please note that if cgs units are used, then the magnetic field must be specified in *Gauss* rather than *Tesla*
+(1T == 10000G). Note also that the cgs unit "emu/mol" in this case is "erg/Gauss/mol" quantifying a molar magnetic
+moment. 
+
+Finally, please note that the calculation result is the molar magnetic moment. Thus to get the magnetisation, you
+should divide this by the molar volume of the material. 
+By default, the calculation temperature is 1K, and the applied magnetic field is 1T along [001]. For further details 
+and a description of the theory, see the :ref:`CrystalFieldMagnetisation <func-CrystalFieldMagnetisation>` and 
+:ref:`CrystalFieldMoment <func-CrystalFieldMoment>` pages.
+
+Fitting Physical Properties
+---------------------------
+
+Instead of fitting the inelastic neutron spectrum, the physical properties can be fitted using a similar interface
+to that described above. The main difference is that some experimental setup information has to be given - especially
+for the susceptibility and magnetisation. This is done by specifying an instance of the `PhysicalProperties` helper
+class as the `PhysicalProperty` attribute of `CrystalField`, either as a keyword argument in the constructor::
+
+    from CrystalField import CrystalField, CrystalFieldFit, PhysicalProperties
+    # Fits a heat capacity dataset - you must have subtracted the phonon contribution by some method already
+    # and the data must be in J/mol/K.
+    cf = CrystalField('Ce', 'C2v', B20=0.37737, B22=3.9770, B40=-0.031787, B42=-0.11611, B44=-0.12544,
+                      PhysicalProperty=PhysicalProperties('Cv'))
+    fitcv = CrystalFieldFit(Model=cf, InputWorkspace=ws)
+    fitcv.fit()
+
+or separately after construction::
+
+    cf = CrystalField('Ce', 'C2v', B20=0.37737, B22=3.9770, B40=-0.031787, B42=-0.11611, B44=-0.12544)
+    cf.PhysicalProperty = PhysicalProperties('Cv')
+    fitcv = CrystalFieldFit(Model=cf, InputWorkspace=ws)
+    fitcv.fit()
+
+    # Fits a susceptibility dataset. Data is the volume susceptibility in SI units
+    cf.PhysicalProperty = PhysicalProperties('susc', Hdir='powder', Unit='SI')
+    fit_chi = CrystalFieldFit(Model=cf, InputWorkspace=ws)
+    fit_chi.fit()
+
+    # Fits a magnetisation dataset. Data is in emu/mol, and was measured at 5K with the field || [111].
+    cf.PhysicalProperty = PhysicalProperties('M(H)', Temperature=5, Hdir=[1, 1, 1], Unit='cgs')
+    fit_mag = CrystalFieldFit(Model=cf, InputWorkspace=ws)
+    fit_mag.fit()
+
+    # Fits a magnetisation vs temperature dataset. Data is in Am^2/mol, measured with a 0.1T field || [110]
+    cf.PhysicalProperty = PhysicalProperties('M(T)', Hmag=0.1, Hdir=[1, 1, 0], Unit='SI')
+    fit_moment = CrystalFieldFit(Model=cf, InputWorkspace=ws)
+    fit_moment.fit()
+
+Unfortunately only 1D datasets can be fitted (e.g. M(H, T) cannot be fitted as a simultaneous function of field and
+temperature).
+
+Simultaneous Fitting of Physical Properties and Inelastic Neutron Spectra
+-------------------------------------------------------------------------
+
+Finally, physical properties data and neutron spectra may be fitted simultaneously. In this case, all the inelastic
+neutron spectra must be specified first in the list of input workspaces, with the physical properties dataset(s)
+following in the same order as specified in the `PhysicalProperty` attribute, which for multiple physical
+properties should be a list. E.g.::
+
+    # Fits an INS spectrum (at 10K) and the heat capacity simultaneously
+    cf = CrystalField('Ce', 'C2v', B20=0.37737, B22=3.9770, B40=-0.031787, B42=-0.11611, B44=-0.12544)
+    cf.Temperature = 10
+    cf.FWHM = 1.5
+    cf.PhysicalProperty = PhysicalProperties('Cv')
+    fit = CrystalFieldFit(Model=cf, InputWorkspace=[ws_ins_10K, ws_cp])
+    fit.fit()
+
+    # Fits two INS spectra (at 44K and 50K) and the heat capacity, susceptibility and magnetisation simultaneously.
+    PPCv = PhysicalProperty('Cv')
+    PPchi = PhysicalProperty('susc', 'powder', Unit='cgs')
+    PPMag = PhysicalProperty('M(H)', 5, [1, 1, 1], 'bohr')
+    cf = CrystalField('Ce', 'C2v', B20=0.37737, B22=3.9770, B40=-0.031787, B42=-0.11611, B44=-0.12544,
+                      Temperature=[44.0, 50], FWHM=[1.1, 0.9], PhysicalProperty=[PPCv, PPchi, PPMag] )
+    fit = CrystalFieldFit(Model=cf, InputWorkspace=[ws_ins_44K, ws_ins_50K, ws_cp, ws_chi, ws_mag])
+    fit.fit()
+
+Note that `PhysicalProperty` requires the type of physical property (either `'Cv'` or `'Cp'` or `'heatcap'` for
+heat capacity; `'susc'` or `'chi'` for susceptibility; `'mag'` or `'M(H)'` for magnetic moment vs applied field;
+or `'mom'` or `'M(T)'` for moment vs temperature) as the first argument. subsequent arguments are optional, and
+are in the following order::
+
+    PhysicalProperties('Cp')  # No further parameters required for heat capacity
+    PhysicalProperties('chi', hdir, inverse, unit)
+    PhysicalProperties('chi', unit)
+    PhysicalProperties('mag', hdir, temp, unit)
+    PhysicalProperties('mag', unit)
+    PhysicalProperties('M(T)', hmag, hdir, inverse, unit)
+    PhysicalProperties('M(T)', unit)
+
+Or these parameters may be specified using keyword arguments, with the keywords: `'Hdir'`, `'Hmag'`, `'Inverse'`, 
+`'Unit'`, and `'Temperature'` (note these are case sensitive, and not all parameters apply to all types of 
+physical properties). The default values (`Hdir=[0,0,1]`, `Hmag=1`, `Inverse=False`, `Unit='cgs'` and 
+`Temperature=1` are used if nothing is specified for a particular attribute.
+
 .. categories:: Interfaces Indirect
diff --git a/docs/source/interfaces/ISIS_Reflectometry.rst b/docs/source/interfaces/ISIS_Reflectometry.rst
index efbab3739b51a188dfaee84fd1702ce8496af297..2f11e40546da785df6a51d38e236a5e737677f34 100644
--- a/docs/source/interfaces/ISIS_Reflectometry.rst
+++ b/docs/source/interfaces/ISIS_Reflectometry.rst
@@ -21,7 +21,7 @@ data is being processed, and easy to adjust any of the options used.
 Integration with data archives is also provided, allowing for data to
 be located and prepared for reduction automatically.
 
-IPython notebooks which document the processing steps and output 
+IPython notebooks which document the processing steps and output
 relevant plots can also be produced from the interface.
 
 Information on how to resolve common problems can be found in the
@@ -53,17 +53,15 @@ dialog will open. Select ``INTER_NR_test2.tbl`` as the file, and enter ``MyTable
 as the output workspace.
 
 A table workspace called ``MyTable`` should now exist in the ADS (:ref:`Analysis Data Service <Analysis Data Service>`).
-To open the table workspace go to **Reflectometry -> Open Table -> MyTable**.
-The processing table (shown below) should now contain four rows (13460, 13462, 13469, 13470).
+In addition the table workspace should be opened as well and the processing table
+(shown below) should now contain four rows (13460, 13462, 13469, 13470).
 
-.. figure:: /images/ISISReflectometryPolref_INTER_table.JPG
+.. figure:: /images/ISISReflectometryPolref_INTER_table.png
   :align: center
 
 Let's process the first group, which consists of the first two rows of the
 table (13460 and 13462). The simplest way to do this is simply to select the
-two rows we want to process, and then click on **Process**. Note that for the reduction
-to be successful, at least the bin size must be specified to :ref:`Stitch1DMany <algm-Stitch1DMany>`,
-as shown above.
+two rows we want to process, and then click on **Process**.
 
 .. tip::
   If you receive an error, consult the `Troubleshooting`_ section of this document for guidance on fixing it.
@@ -167,10 +165,10 @@ processing that is in progress. And at the bottom, near the **Process**
 button is the processing instrument selector. The processing instrument is
 used to help identify the correct data to load when processing runs.
 
-Next to the **Process** button there is a checkbox which allows enabling and 
-disabling output to an ipython notebook. If the checkbox is enabled, a dialog 
-window will ask for a save location for the notebook after processing is 
-complete. A generated notebook contains python code to repeat the processing 
+Next to the **Process** button there is a checkbox which allows enabling and
+disabling output to an ipython notebook. If the checkbox is enabled, a dialog
+window will ask for a save location for the notebook after processing is
+complete. A generated notebook contains python code to repeat the processing
 steps and output relevant plots.
 
 Tool Bar
@@ -310,9 +308,8 @@ Columns
 |                     |           | Options are specified in ``key=value`` pairs,                                   |
 |                     |           | separated by commas. Values containing commas                                   |
 |                     |           | must be quoted. Options specified via this                                      |
-|                     |           | column will prevail over global options                                         |
-|                     |           | specified in the                                                                |
-|                     |           | **ReflectometryReductionOneAuto** text box.                                     |
+|                     |           | column will prevail over options specified                                      |
+|                     |           | in the **Settings** tab.                                                        |
 |                     |           |                                                                                 |
 |                     |           | Example: ``StrictSpectrumChecking=0,``                                          |
 |                     |           | ``RegionOfDirectBeam="0,2", Params="1,2,3"``                                    |
@@ -361,9 +358,9 @@ Measure Based Search Transfer
 
 Measure based search transfer uses the log-values within nexus files from the experiment to assemble the batch. Since the files themselves are required, not just the overview metadata, the files must be accessible by mantid. One way of doing this is to mount the archive and set the user property ``icatDownload.mountPoint`` to your mount point. It may end up looking something like this ``icatDownload.mountPoint=/Volumes/inst$``. Alternately, you can download the files to your local disk and simply add that directory to the managed search directories in ``Manage User Directories``.
 
-- Any runs with the measurement_id log, will be
+- Any runs with the ``measurement_id`` log, will be
   placed into the same group.
-- Any runs with the ``same measurement_id`` and the same ``measurement_subid`` logs, will be merged into a single row, with all the runs listed in the **Run(s)** column in the format, ``123+124+125``. 
+- Any runs with the same ``measurement_id`` and the same ``measurement_subid`` logs, will be merged into a single row, with all the runs listed in the **Run(s)** column in the format, ``123+124+125``.
 
 Failed transfers
 ================
@@ -376,9 +373,9 @@ In the image below we select two runs from the Search table that we wish to tran
 Attempting to transfer an invalid run will result in that run not being transferred to the processing table. If the transfer was not successful then that specific
 run will be highlighted in the Search table.
 
-.. figure:: /images/ISISReflectometryPolref_failed_transfer_run.JPG
+.. figure:: /images/ISISReflectometryPolref_failed_transfer_run.png
    :alt: Failed transfer will be highlighted in orange, successful transfer is put into processing table
-   
+
 Hovering over the highlighted run with your cursor will allow you to see why the run was invalid.
 
 .. figure:: /images/ISISReflectometryPolref_tooltip_failed_run.jpg
@@ -388,22 +385,89 @@ Hovering over the highlighted run with your cursor will allow you to see why the
 Settings tab
 ~~~~~~~~~~~~
 
-The *Settings* tab can be used to specify global options for the reduction and post-processing. It shows the algorithms used
-by the interface to reduce the data, together with a text box allowing the specification of pre-processing,
-processing and post-processing options. Pre-processing options refer to the algorithms :ref:`Plus <algm-Plus>` (applied
-to the **Run(s)** column when multiple runs are specified) and :ref:`CreateTransmissionWorkspaceAuto <algm-CreateTransmissionWorkspaceAuto>`
-(applied to **Transmission Run(s)**). Options to the main reduction algorithm,
-:ref:`ReflectometryReductionOne <algm-ReflectometryReductionOne>`, can also be
-supplied using the corresponding text box. Note that when conflicting options are specified
-for the reduction, i.e. different values for the same property are specified via this
-text box and the **Options** column in the *Runs* tab, the latter will prevail. Therefore,
-the **ReflectometryReductionOneAuto** text box should be used to specify global options that will be
-applied to all the rows in the table, whereas the **Options** column will only be applicable
-to the specific row for which those options are defined. Finally, post-processing instructions,
-i.e. instructions to :ref:`Stitch1DMany <algm-Stitch1DMany>`, can also be supplied similarly (note
-that at least a bin width must be specified for this algorithm to run successfully, for instance *Params="-0.03"*). Pre-processing,
-processing and post-processing options are specified in ``key=value`` pairs separated by commas.
-Values containing commas must be quoted.
+.. figure:: /images/ISISReflectometryPolref_settings_tab.png
+   :alt: Showing view of the settings tab.
+
+The *Settings* tab can be used to specify options for the reduction and post-processing.
+These options are used by the interface to provide argument values for the pre-processing,
+processing and post-processing algorithms. Each of these respectively refer to the
+following algorithms:
+
+- :ref:`CreateTransmissionWorkspaceAuto <algm-CreateTransmissionWorkspaceAuto>`
+  (applied to **Transmission Run(s)**).
+- :ref:`ReflectometryReductionOne <algm-ReflectometryReductionOne>`, main reduction algorithm.
+- :ref:`Stitch1DMany <algm-Stitch1DMany>` (note that at least a bin width must be
+  specified for this algorithm to run successfully, for instance *Params="-0.03"*).
+
+Note that when conflicting options are specified for the reduction, i.e. different
+values for the same property are specified via the *Settings* tab and the **Options**
+column in the *Runs* tab, the latter will prevail. Therefore, the **ReflectometryReductionOneAuto**
+settings should be used to specify global options that will be applied to all the
+rows in the table, whereas the **Options** column will only be applicable to the
+specific row for which those options are defined.
+
+The *Settings* tab is split into two sections, **Experiment settings** and **Instrument
+settings**. The former refers to variables set mostly by the user, while the latter
+refers to variables set by the instrument used to perform the reduction. Both have
+a **Get Defaults** button that fills some of the variables with default values.
+For experiment settings, these are pulled from the **ReflectometryReductionOneAuto**
+algorithm whereas for instrument settings, they are pulled from the current instrument
+being used in the run.
+
+Save ASCII tab
+~~~~~~~~~~~~~~
+
+.. figure:: /images/ISISReflectometryPolref_save_tab.png
+   :alt: Showing view of the save ASCII tab.
+
+The *Save ASCII* tab allows for processed workspaces to be saved in specific
+ASCII formats. The filenames are saved in the form [Prefix][Workspace Name].[ext].
+
++-------------------------------+------------------------------------------------------+
+| Name                          | Description                                          |
++===============================+======================================================+
+| Save path                     | At present this dialog doesn't have a standard       |
+|                               | file dialog so that path must be filled in manually. |
+|                               | The path must already exist as this dialog doesn't   |
+|                               | have the ability to create directories. As the       |
+|                               | naming of files is automatic, the path must also     |
+|                               | point to a directory rather than a file.             |
++-------------------------------+------------------------------------------------------+
+| Prefix                        | The prefix is what is added to the beginning of      |
+|                               | the workspace name to create the file name. No       |
+|                               | underscore or space is added between them so they    |
+|                               | must be manually added.                              |
++-------------------------------+------------------------------------------------------+
+| Filter                        | This can be specified to filter out workspaces       |
+|                               | in the workspace list whose name does not match      |
+|                               | that of the filter text.                             |
++-------------------------------+------------------------------------------------------+
+| Regex                         | Checking this option allows a regular expression     |
+|                               | to be used for filtering workspace names.            |
++-------------------------------+------------------------------------------------------+
+| List Of Workspaces            | The left listbox will contain any workspaces loaded  |
+|                               | into mantid. Double clicking on one will fill        |
+|                               | the right list box with the parameters it contains.  |
+|                               | This listbox supports multi-select in order to       |
+|                               | allow for multiple workspaces to be saved out        |
+|                               | at the same time with the same settings.             |
++-------------------------------+------------------------------------------------------+
+| List Of Logged Parameters     | The right listbox starts out empty, but will fill    |
+|                               | with parameter names when a workspace in the left    |
+|                               | listbox is double clicked. This listbox supports     |
+|                               | multi-select in order to allow for the save output   |
+|                               | to contain multiple parameter notes.                 |
++-------------------------------+------------------------------------------------------+
+| File format                   | This dialog can save to ANSTO, ILL cosmos, 3-column, |
+|                               | and a customisable format. It doesn't save from      |
+|                               | the main interface's table, but from workspaces      |
+|                               | loaded into mantid. All algorithms are also          |
+|                               | available as save algorithms from mantid itself.     |
++-------------------------------+------------------------------------------------------+
+| Custom Format Options         | When saving in 'Custom' this section allows you      |
+|                               | to specify if you want a Title and/or Q Resolution   |
+|                               | column as well as specifying the delimiter.          |
++-------------------------------+------------------------------------------------------+
 
 .. _ISIS_Reflectomety-Options:
 
@@ -462,10 +526,12 @@ When I try to process I get an error: "Error encountered while stitching group .
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 This occurs when Mantid is unable to stitch a group. Please check that at you have
-specified at least the bin width in the *Stitch1DMany* text box. To specify the bin width please
-use the *Params* input property like this: ``Params="-0.03"``  (you may want to replace
-``0.03`` with a bin size suitable for your reduction). Note that the "-" sign will produce
-a logarithmic binning in the stitched workspace. For linear binning, use ``Params="0.03"``.
+specified at least the bin width. This can be done either by setting a value in column
+**dQ/Q** before processing the data, or by using the *Stitch1DMany* text
+box in the **Settings** tab to provide the *Params* input property like this:
+``Params="-0.03"`` (you may want to replace ``0.03`` with a bin size suitable for
+your reduction). Note that the "-" sign in this case will produce a logarithmic binning in the
+stitched workspace. For linear binning, use ``Params="0.03"``.
 
 When I try to process I get an error: "Invalid key value pair, '...'"
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/docs/source/interfaces/Indirect_DataReduction.rst b/docs/source/interfaces/Indirect_DataReduction.rst
index 68e7fce063e6b63ed5768f88663165e62eadeb84..651510cfbfcaae9817259805a31aa3870e660013 100644
--- a/docs/source/interfaces/Indirect_DataReduction.rst
+++ b/docs/source/interfaces/Indirect_DataReduction.rst
@@ -184,40 +184,80 @@ ILL Energy Transfer
 
 This tab handles the reduction of data from the IN16B instrument at the ILL.
 
-This will output the raw (*_raw*) data read from the file and reduced (*_red*)
-workspace by default, with mirror mode enabled you will also get the left
-(*_left*) and right (*_right*) hand components of the data as separate
-workspaces.
-
-Note that when using a calibration workspace the grouping of the calibration
-workspace must match that being used in the energy transfer reduction, i.e. both
-processes use the same grouping file (or both use the default grouping).
+Reduction Type
+~~~~~~~~~~~~~~
 
-Options
-~~~~~~~
+There are two reduction types of IN16B data: Quasi-Elastic Neutron Scattering (QENS) or Fixed Window Scans (FWS),
+and the latter can be either Elastic (EFWS) or Inelastic (IFWS).
+If one or another reduction type is checked, the corresponding algorithm will be invoked
+(see :ref:`IndirectILLReductionQENS <algm-IndirectILLReductionQENS>` and :ref:`IndirectILLReductionFWS <algm-IndirectILLReductionFWS>`).
+There are several properties in common between the two, and several others that are specific to one or the other.
+The specific ones will show up or disappear corresponding to the choice of the reduction type.
 
-Input
-  Used to select the raw data in *.nxs* format
+Common Options
+~~~~~~~~~~~~~~
 
-Calibration
-  Gives the option of applying a calibration workspace or NeXus file created
-  with the ILL Calibration tab or :ref:`ILLIN16BCalibration
-  <algm-ILLIN16BCalibration>` algorithm.
+Input File
+  Used to select the raw data in ``.nxs`` format. Note that multiple files can be specified following
+  `MultiFileLoading <http://www.mantidproject.org/MultiFileLoading>`_ instructions.
 
-Grouping
+Detector Grouping
   Used to switch between grouping as per the IDF (*Default*) or grouping using a
-  mapping file (*Map File*).
+  mapping file (*Map File*). This defines e.g. the summing of the vertical pixels per PSDs.
+
+Background Subtraction
+  Used to specify the background (i.e. empty can) runs to subtract. A scale factor can be applied to background subtraction.
 
-Use Mirror Mode
-  Enable to reduce data that has been captured with mirror mode enabled.
+Detector Calibration
+  Used to specify the calibration (i.e. vanadium) runs to divide by.
+
+Output Name
+  This will be the name of the resulting reduced workspace group.
 
 Plot
-  If enabled will plot the result as a spectra plot.
+  If enabled, will plot the result (of the first run) as a contour plot.
 
 Save
-  If enabled the result will be saved as a NeXus file in the default save
+  If enabled the reduced workspace group will be saved as a ``.nxs`` file in the default save
   directory.
 
+QENS-only Options
+~~~~~~~~~~~~~~~~~
+
+Sum All Runs
+  If checked, all the input runs will be summed while loading.
+
+Crop Dead Monitor Channels
+  If checked, the few channels in the beginning and at the end of the spectra, that contain zero monitor counts will be cropped out.
+  As a result, the doppler maximum energy will be mapped to the first and last non-zero monitor channels, resulting in narrower peaks.
+  Care must be taken with this option; since this alters the total number of bins,
+  problems might occur while subtracting the background or performing unmirroring, if the number of dead monitor channels are different.
+
+Calibration Peak Range
+  This defines the integration range over the peak in calibration run in ``mev``.
+
+Unmirror Options
+  This is used to choose the option of summing of the left and right wings of the data, when recorded in mirror sense.
+  See :ref:`IndirectILLReductionQENS <algm-IndirectILLReductionQENS>` for full details.
+  Unmirror option 5 and 7 require vanadium alignment run.
+
+
+FWS-only Options
+~~~~~~~~~~~~~~~~
+
+Observable
+  This is the scanning ovservable, that will become the x-axis of the final result.
+  It can be any numeric sample parameter defined in Sample Logs (e.g. sample.*) or a time-stamp string (e.g. start_time).
+  It can also be the run number. It can not be an instrument parameter.
+
+Sort X Axis
+  If checked, the x-axis of the final results will be sorted.
+
+Sum/Interpolate
+  Both background and calibration have options to use the summed (averaged) or interpolated values over different observable points.
+  Default behaviour is Sum. Interpolation is done using cubic (or linear for 2 measured values only) splines.
+  If interpolation is requested, x-axis will be sorted automatically.
+
 ISIS Calibration & Resolution
 -----------------------------
 
@@ -291,25 +331,23 @@ ILL Calibration
 .. interface:: Data Reduction
   :widget: tabILLCalibration
 
-This tab is used to create calibration workspaces for the IN16B spectrometer at
-the ILL using the :ref:`ILLIN16BCalibration <algm-ILLIN16BCalibration>`
-algorithm.
+**This tab is deprecated.** Use CalibrationRun in EnergyTransfer tab.
 
 Options
 ~~~~~~~
 
+Input Files
+  File for the calibration (e.g. vanadium) run. If multiple specified, they will be automatically summed.
+
 Grouping
   Used to switch between grouping as per the IDF (*Default*) or grouping using a
   mapping file (*Map File*).
 
 Peak Range
-  Sets the integreation range over the peak in :math:`meV`
+  Sets the integration range over the peak in :math:`meV`
 
 Scale Factor
-  Override the calculated scale factor
-
-Mirror Mode
-  Enable of the data uses mirror mode
+  Factor to scale the intensities with
 
 ISIS Diagnostics
 ----------------
diff --git a/docs/source/interfaces/MuonAnalysis_test_guides/index.rst b/docs/source/interfaces/MuonAnalysis_test_guides/index.rst
new file mode 100644
index 0000000000000000000000000000000000000000..9214e1c0bdad26f5aa34ab23d99409d569bfa6a5
--- /dev/null
+++ b/docs/source/interfaces/MuonAnalysis_test_guides/index.rst
@@ -0,0 +1,19 @@
+.. Muon Analysis Test Guides master file
+   It contains a hidden root toctree directive so that Sphinx
+   has an internal index of all of the pages and doesn't
+   produce a plethora of warnings about most documents not being in
+   a toctree.
+   See http://sphinx-doc.org/tutorial.html#defining-document-structure
+
+.. _MuonAnalysis_test_guides contents:
+
+=========================
+Muon Analysis Test Guides
+=========================
+
+.. toctree::
+   :glob:
+   :maxdepth: 1
+
+   *
+
diff --git a/docs/source/interfaces/Muon_Analysis.rst b/docs/source/interfaces/Muon_Analysis.rst
index e660c47c6d0edb0a1e427aa912e6c557d775aeaa..cd0202371307d6ff776f2a25095fac4993f9eba9 100644
--- a/docs/source/interfaces/Muon_Analysis.rst
+++ b/docs/source/interfaces/Muon_Analysis.rst
@@ -605,6 +605,12 @@ General
 |       |                             | - **Create new window**. When plotting a new run, it is             |
 |       |                             |   plotted in a new window each time.                                |
 |       |                             |                                                                     |
+|       |                             |   NOTE: This can can cause speed and stability problems once the    |
+|       |                             |   number of graphs managed by Mantidplot passes a few hundred       |
+|       |                             |   which can hapen if you run Mantid for a few days on an            |
+|       |                             |   experiment. For long term stability we suggest you select         |
+|       |                             |   **Use previous window**.                                          |
+|       |                             |                                                                     |
 +-------+-----------------------------+---------------------------------------------------------------------+
 | **3** | **Hide Toolbars**           | If enabled, opening the interface up hides the MantidPlot           |
 |       |                             | toolbars. This is useful on smaller screens.                        |
@@ -615,7 +621,7 @@ General
 |       |                             |                                                                     |
 |       |                             | Enabling the option will change the UI of the DataAnalysis_ tab to  |
 |       |                             | the new one described above, enabling fits of multiple datasets to  |
-|       |                             | be made.
+|       |                             | be made.                                                            |
 +-------+-----------------------------+---------------------------------------------------------------------+
 
 Feedback & Comments
diff --git a/docs/source/interfaces/Tomographic_Reconstruction.rst b/docs/source/interfaces/Tomographic_Reconstruction.rst
index 409838f2e0a1088262f6004193f2638df5c14ba2..3fa4756f6d241dcd9c52bb00c06ed2e5048f4753 100644
--- a/docs/source/interfaces/Tomographic_Reconstruction.rst
+++ b/docs/source/interfaces/Tomographic_Reconstruction.rst
@@ -342,9 +342,18 @@ same location:
 Running jobs locally
 --------------------
 
-This capability is being developed at the moment, and it requires
-additional setup steps on the local analysis machine. Basic
-functionality is supported only on the IMAT data analysis machine.
+You can run local reconstructions as well, however that requires properly setting up the:
+
+* External python interpretor path, for example:
+
+  - `C:/Anaconda/python.exe for Windows`
+  - `~/Anaconda2/bin/python for Linux`
+
+* PYTHONPATH environment variable should contain the Python directories 
+  that have the installed plugins for the supported tools
+
+* (Optional) Scripts directory
+  - By default this will be properly setup from the Mantid installation
 
 Visualization
 -------------
diff --git a/docs/source/interfaces/index.rst b/docs/source/interfaces/index.rst
index 8996c5b5eefab0c688904d3433884702bacb32dd..a5aad9e94446971187d1549c05e2f85bc8b387f0 100644
--- a/docs/source/interfaces/index.rst
+++ b/docs/source/interfaces/index.rst
@@ -17,4 +17,5 @@
    :maxdepth: 1
 
    *
+   MuonAnalysis_test_guides/index
 
diff --git a/docs/source/release/v3.8.0/direct_inelastic.rst b/docs/source/release/v3.8.0/direct_inelastic.rst
index 30446de0fc6719240766cfb2f341e81ca956de7a..1ccfefac1fb39833f2a7b630cb431a7346a72db1 100644
--- a/docs/source/release/v3.8.0/direct_inelastic.rst
+++ b/docs/source/release/v3.8.0/direct_inelastic.rst
@@ -10,18 +10,17 @@ Improvements
 
 - :ref:`MDNormDirectSC <algm-MDNormDirectSC>` has an option to skip safety checks. This improves the speed when acting on workspace groups.
 
-- A qtiGenie method *export_masks* was brought to Mantid as :ref:`ExportSpectraMask <algm-ExportSpectraMask>` Python algorithm and got documentation, unit tests and Python GUI.
-  The algorithm allows to export list of masked workspace spectra and save these spectra as ISIS *.msk* file. 
+- The :ref:`ExportSpectraMask <algm-ExportSpectraMask>` algorithm was added to Mantid, along with documentation, unit tests and a Python GUI.
+  The algorithm exports a list of masked spectra and the list can be saved as a single ISIS *.msk* file. 
   The export mask procedure is often used by instrument scientists in ISIS, and they had to initialize qtiGenie to do this operation before these changes. 
 
-- :ref:`GetEiMonDet <algm-GetEiMonDet>` has had a complete rewrite. The new version 2 utilizes elastic peak position data generated by :ref:`FindEPP <algm-FindEPP>`, the detectors of interest are specified by their indices instead of distances from sample, and the revised algorithm is able to deal with cases where neutrons arrive at the detectors in a later time frame.
-- :ref:`MaskDetectors <algm-MaskDetectors>` has been modified to work on with grouped spectra. If a detector of the mask workspace is masked, the spectrum of the target workspace, with the detector group containing the masked detector become masked. This allows to use *.xml* masks, produced by :ref:`SaveMask <algm-SaveMask>` algorithm on the workspaces containing mapped spectra obtained from ISIS instruments.  
+- :ref:`GetEiMonDet <algm-GetEiMonDet>` has had a complete rewrite. Version 2 utilises the elastic peak position data generated by :ref:`FindEPP <algm-FindEPP>`. The detectors of interest are specified by their indices instead of their distance from the sample. The revised algorithm is able to deal with cases where neutrons arrive at the detectors in a later time frame.
+- :ref:`MaskDetectors <algm-MaskDetectors>` has been modified to work on grouped spectra. If a detector of the workspace is masked then the relevant spectra of the target workspace become masked(zero). Masks defined by *.xml* files, produced by :ref:`SaveMask <algm-SaveMask>` algorithm,  can be applied to workspaces containing mapped spectra that has been obtained from ISIS instruments.  
  
-- :ref:`LoadMask <algm-LoadMask>` was modified to accept a workspace of spectra-detector map when spectra mask is provided.
-  This allow users to use old legacy *.msk* files as source of mask workspaces usable with modified :ref:`MaskDetectors <algm-MaskDetectors>` algorithm
-  and to use old spectra masks on a workspaces with different grouping and spectra-detector maps.
+- :ref:`LoadMask <algm-LoadMask>` was modified to accept a spectra mask and a spectra-detector map.
+  This allows the use of old legacy *.msk* files to generate a masked workspace, use old spectra masks on workspaces with different groupings and spectra-detector maps.
 
-- There is a new algorithm :ref:`MagFormFactorCorrection <algm-MagFormFactorCorrection>` which will scale an input workspace by 1/:math:`|F(Q)|^2` where :math:`F(Q)` is the magnetic form factor for a specified magnetic ion. 
+- The algorithm :ref:`MagFormFactorCorrection <algm-MagFormFactorCorrection>` will scale an input workspace by 1/:math:`|F(Q)|^2`, where :math:`F(Q)` is the magnetic form factor for a specified magnetic ion. 
 
 
 
diff --git a/docs/source/release/v3.8.0/framework.rst b/docs/source/release/v3.8.0/framework.rst
index 8f64701ac39c5556089600f156d84bfd62c48b74..b212b27d972649ac033ac21cdc5ba8d1e1d35992 100644
--- a/docs/source/release/v3.8.0/framework.rst
+++ b/docs/source/release/v3.8.0/framework.rst
@@ -51,7 +51,7 @@ New
 
 - :ref:`UnwrapMonitorsInTOF <algm-UnwrapMonitorsInTOF>` handles the data which was collected beyond the end of a frame.
 
-- :ref:`ExtractMonitors <algm-ExtractMonitors>` an algorithm to extract the monitor spectra into a new workspace. Can also be 
+- :ref:`ExtractMonitors <algm-ExtractMonitors>` an algorithm to extract the monitor spectra into a new workspace. Can also be
   used to create a workspace with just the detectors, or two workspaces, one with the monitors and one with the detectors.
 
 Improved
@@ -75,7 +75,7 @@ Improved
   had a bug where the table columns were in a reversed order in the dialogue's combo boxes.
   This is now fixed and the order is correct.
 
-- :ref:`ConvertUnits <algm-ConvertUnits>` and `ConvertUnitsUsingDetectorTable <algm-ConvertUnitsUsingDetectorTable>` will no longer corrupt a workspace used as input and output if the algorithm fails.
+- :ref:`ConvertUnits <algm-ConvertUnits>` and :ref:`ConvertUnitsUsingDetectorTable <algm-ConvertUnitsUsingDetectorTable>` will no longer corrupt a workspace used as input and output if the algorithm fails.
 
 - :ref:`SetSample <algm-SetSample>`: Fixed a bug with interpreting the `Center` attribute for cylinders/annuli
 
@@ -91,7 +91,7 @@ Improved
 
 - :ref:`FindSXPeaks <algm-FindSXPeaks>`: Fixed a bug where peaks with an incorrect TOF would stored for some intrument geometries.
 
-- :ref:`LoadILL <algm-LoadILL>` was renamed to `LoadILLTOF <algm-LoadILLTOF>` to better reflect what it does. The new algorithm can also handle cases where the monitor IDs are greater than the detector IDs.
+- :ref:`LoadILL <algm-LoadILLTOF>` was renamed to :ref:`LoadILLTOF <algm-LoadILLTOF>` to better reflect what it does. The new algorithm can also handle cases where the monitor IDs are greater than the detector IDs.
 
 - :ref:`FFT <algm-FFT>` deals correctly with histogram input data. Internally, it converts to point data, and the output is always a point data workspace. (It can be converted to histogram data using :ref:`ConvertToHistogram <algm-ConvertToHistogram>` if required).
 
@@ -125,7 +125,7 @@ Performance
   - :ref:`ConvertSpectrumAxis <algm-ConvertSpectrumAxis>`: 25% speedup
   - :ref:`ConvertToHistogram <algm-ConvertToHistogram>`: 3x to 4x speedup
   - :ref:`ConvertToPointData <algm-ConvertToPointData>`: 3x to 4x speedup
-  - :ref:`CorrectFlightPaths <algm-CorrectFlightPaths>`: 10% speedup
+  - :ref:`CorrectFlightPaths <algm-ConvertToConstantL2>`: 10% speedup
   - :ref:`ExtractSpectra <algm-ExtractSpectra>`: no change when X-range changes, otherwise 50x to 100x speedup for Workspace2D and up to 3x speedup for EventWorkspace
   - :ref:`GetAllEi <algm-GetAllEi>`: 5-10% speedup
   - :ref:`GetDetOffsetsMultiPeaks <algm-GetDetOffsetsMultiPeaks>`: 5-10% speedup
@@ -158,7 +158,7 @@ CurveFitting
 - Added a new minimizer belonging to the trust region family of algorithms developped for Mantid by the SCD
   Numerical Analysis Group at RAL. It has better performance characteristics compared to the existing
   minimizers especially when applied to the most difficult fitting problems.
-- Added new property `EvaluationType` to Fit algorithm. If set to "Histogram" and the input dataset 
+- Added new property `EvaluationType` to Fit algorithm. If set to "Histogram" and the input dataset
   is a histogram with large bins it can improve accuracy of the fit.
 - The concept page for :ref:`Comparing fit minimizers <FittingMinimizers>` has been updated to include the new
   minimizer and a comparison against neutron data examples.
@@ -173,7 +173,7 @@ Others
 - The case search in ``DataService`` has been replaced with a case-insensitive comparison function. Behavior
   is almost identical, but a small number of cases (such as adding the workspaces ``Z`` and ``z``) will work
   in a more predictable manner.
-  
+
 
 Python
 ------
@@ -203,4 +203,4 @@ Full list of
 `Framework <http://github.com/mantidproject/mantid/pulls?q=is%3Apr+milestone%3A%22Release+3.8%22+is%3Amerged+label%3A%22Component%3A+Framework%22>`__
 and
 `Python <http://github.com/mantidproject/mantid/pulls?q=is%3Apr+milestone%3A%22Release+3.8%22+is%3Amerged+label%3A%22Component%3A+Python%22>`__
-changes on GitHub
+changes on GitHub
\ No newline at end of file
diff --git a/docs/source/release/v3.8.0/index.rst b/docs/source/release/v3.8.0/index.rst
index 90227bd6100faca1a044333cdc8d808f0215b9fc..9b45cec8db0eb2449b1f4e6b8dee741f67ca89a7 100644
--- a/docs/source/release/v3.8.0/index.rst
+++ b/docs/source/release/v3.8.0/index.rst
@@ -2,7 +2,7 @@
 Mantid 3.8.0 Release Notes
 ==========================
 
-.. figure:: ../../images/release38.png
+.. figure:: /images/release38.png
    :class: screenshot
    :width: 500px
    :align: right
diff --git a/docs/source/release/v3.8.0/indirect_inelastic.rst b/docs/source/release/v3.8.0/indirect_inelastic.rst
index b12dedc82647cb3ea4973f2c01cf9307aa36be56..ceefc179f77d01ebdb9414070d0617c20a35045d 100644
--- a/docs/source/release/v3.8.0/indirect_inelastic.rst
+++ b/docs/source/release/v3.8.0/indirect_inelastic.rst
@@ -76,9 +76,9 @@ VESUVIO
 
 - Add the functionality for ties between internal parameters within each mass profile. This allows for the creation of a BivariateGaussian profile from the MultivariateGaussian profile.
   Ties can be added within the defintion of the mass profile with the following:
-  
+
   *flags['masses'] = [{'value':1.0079, 'function': 'MultivariateGaussian', 'SigmaX': 5, 'SigmaY': 5, 'SigmaZ': 5, 'ties': 'SigmaX=SigmaY'}]*
-  
+
   The above will tie SigmaX to SigmaY for this MultivariateGaussian in the driver script
 
 Improvements
@@ -106,4 +106,4 @@ Bugfixes
 * Fix end of line issue when loading ascii files in *LoadILL* interface
 * *BayesQuasi* now displays correct spectrum number in progress bar
 
-`Full list of changes on GitHub <http://github.com/mantidproject/mantid/pulls?q=is%3Apr+milestone%3A%22Release+3.8%22+is%3Amerged+label%3A%22Component%3A+Indirect+Inelastic%22>`_
+`Full list of changes on GitHub <http://github.com/mantidproject/mantid/pulls?q=is%3Apr+milestone%3A%22Release+3.8%22+is%3Amerged+label%3A%22Component%3A+Indirect+Inelastic%22>`_
\ No newline at end of file
diff --git a/docs/source/release/v3.8.0/sans.rst b/docs/source/release/v3.8.0/sans.rst
index 147cc4f94aa9b1806fa77a5f04c63532af2bbccd..1112352317b67f929d693030a6cb1fa9b34feb28 100644
--- a/docs/source/release/v3.8.0/sans.rst
+++ b/docs/source/release/v3.8.0/sans.rst
@@ -9,25 +9,25 @@ Features
 ----------
 
 - :ref:`CropToComponent <algm-CropToComponent>` allows for cropping a workspace to a list of component names.
-- Detect missing Bench_Rot for LARMOR and provide meaningful error message
+- Detect missing Bench_Rot for LARMOR and provide meaningful error message.
 - Enable the CanSAS1D algorithms to handle geometry inforamtion.
-- Add sort option to :ref:`CropToComponent <algm-CropToComponent>`
+- Add sort option to :ref:`CropToComponent <algm-CropToComponent>`.
 - Provide warning when users try to use a 2D reduction together with a merged reduction selection.
-- Processing of LOQ M4 in the SANS reduction was added
-- :ref:`UnwrapMonitorsInTOF <algm-UnwrapMonitorsInTOF>` handles the data which was collected beyond the end of a frame.
+- Processing of LOQ M4 in the SANS reduction was added.
+- :ref:`UnwrapMonitorsInTOF <algm-UnwrapMonitorsInTOF>` handles the data, which was collected beyond the end of a frame.
 
 
 Bug Fixes
 ---------
 
-- Fix for beam center finder
-- Fix loading of multiperiod event files
-- Fix period selection when loading multiperiod files.
-- Fix process note for SaveCanSAS1D
-- Fix output names for batch processing
-- Fix the loading of RKH files
-- Fix wrong initial position of LARMOR data in the beam centre finder
-- Allow loading of CanSAS data without error data
-- Fix saving CanSAS with transmission data from the ISIS SANS GUI
+- Fix for beam center finder.
+- Fixed loading of multiperiod event files.
+- Fixed period selection when loading multiperiod files.
+- Fixed process note for SaveCanSAS1D.
+- Fixed output names for batch processing.
+- Fixed the loading of RKH files.
+- Fixed wrong initial position of LARMOR data in the beam centre finder.
+- Allow loading of CanSAS data without error data.
+- Fixed saving CanSAS with transmission data from the ISIS SANS GUI.
 
 `Full list of changes on github <http://github.com/mantidproject/mantid/pulls?q=is%3Apr+milestone%3A%22Release+3.8%22+is%3Amerged+label%3A%22Component%3A+SANS%22>`__
diff --git a/docs/source/release/v3.9.0/diffraction.rst b/docs/source/release/v3.9.0/diffraction.rst
index f5fe77bec6ed9973372f31cb3a5a0ab01698ac89..2bc825da8c47404f606c872e601dd288f100349b 100644
--- a/docs/source/release/v3.9.0/diffraction.rst
+++ b/docs/source/release/v3.9.0/diffraction.rst
@@ -7,6 +7,22 @@ Diffraction Changes
 
 Crystal Improvements
 --------------------
+:ref:`algm-FindUBUsingLatticeParameters` will now return an oriented lattice even when the number of peaks used is very low.
+
+:ref:`algm-FindUBUsingLatticeParameters` has a new option to fix lattice parameters. This will find an orientation, but without optimisation between indexed HKLs and q vectors.
+
+:ref:`algm-CreateGroupingWorkspace` has a new option to create one group of 4 columns of SNAP detectors and another with the remaining 2 columns. This grouping is used frequently in their reduction.
+
+:ref:`algm-IntegratePeaksMD` now removes the top 1% of the background events so that intensity spikes near the edges are removed.
+
+:ref:`algm-IntegrateEllipsoids` has a new option, AdaptiveQMultiplier, for the radius to vary as a function of the modulus of Q. If the AdaptiveQBackground option is set to True, the background radius also changes.  These are the same as the adaptive options in :ref:`algm-IntegratePeaksMD`.
+
+Single Crystal Diffraction
+--------------------------
+HB3A's IDF is modified to allow its detector center shifted from default position.
+:ref:`algm-LoadSpiceXML2DDet` has new options for users to input amount of detector's shift in X and Y direction.
+:ref:`algm-ConvertCWSDExpToMomentum` has new options for users to input amount of detector's shift in X and Y direction.
+User interface *HFIR 4Circle Reduction* has been modified to allow user to specify wave length, detector center and distance between detector and sample.
 
 Engineering Diffraction
 -----------------------
@@ -16,6 +32,24 @@ Powder Diffraction
 
 :ref:`algm-SNSPowderReduction` had an error in logic of subtracting the vanadium background. It was not being subtracted when ``PreserveEvents=True``.
 
+:ref:`algm-PDLoadCharacterizations` and
+:ref:`algm-PDDetermineCharacterizations` have been upgraded to support
+sample container specific information, as well as additional
+information about the empty sample environment and instrument.
+
+:ref:`algm-SetDetScale` has a new option, DetScaleFile, to input a text file with each line containing the detector number and scale factor for that detector.  These scales will be used in SaveHKL and AnvredCorrection.  If scales for a detector are given in both the DetScaleList text string and the DetScaleFile file, the values from the text string will be used.
+
+High Pressure
+-------------
+
+:ref:`algm-CreateGroupingWorkspace` has a new option to create one group of 4 columns of SNAP detectors and another with the remaining 2 columns. This grouping is used frequently in their reduction.
+
+:ref:`algm-SNAPReduce` is new to mantid, but not for SNAP
+users. Adding the algorithm to mantid installations will reduce the
+amount of issues that SNAP users will encounter trying to reduce their
+data.
+
+New scripts for correcting diamond anvil cell attenuation. These are found in `scripts/DiamondAttenuationCorrection <https://github.com/peterfpeterson/mantid/tree/diamond_atten/scripts/DiamondAttenuationCorrection>`_.
 
 Full list of `diffraction <http://github.com/mantidproject/mantid/pulls?q=is%3Apr+milestone%3A%22Release+3.9%22+is%3Amerged+label%3A%22Component%3A+Diffraction%22>`_
 and
diff --git a/docs/source/release/v3.9.0/direct_inelastic.rst b/docs/source/release/v3.9.0/direct_inelastic.rst
index b35b441d1309aa57b1413e602c6aa5c943fa00c1..607166ca4ade431ff0d57ece5fb51797caea25d3 100644
--- a/docs/source/release/v3.9.0/direct_inelastic.rst
+++ b/docs/source/release/v3.9.0/direct_inelastic.rst
@@ -14,7 +14,11 @@ Improvements
 
 - The previously inaccurate instrument definition for IN4 at ILL has been updated. The instrument geometry should now be more correct.
 
-`Full list of changes on GitHub <http://github.com/mantidproject/mantid/pulls?q=is%3Apr+milestone%3A%22Release+3.9%22+is%3Amerged+label%3A%22Component%3A+Direct+Inelastic%22>`_
+- :ref:`LoadILLTOF <algm-LoadILLTOF>` has been upgraded to version 2. The new version loads the TOF axis as defined by the 'time_of_flight' field in the NeXus file. Consequently, the *FilenameVanadium* and *WorkspaceVanadium* input properties were removed and no 'EPP' entry is added to the sample logs anymore.
+
+- Overly pessimistic error calculation in :ref:`ComputeCalibrationCoefVan <algm-ComputeCalibrationCoefVan>` have been fixed.
+
+- A new input property *Temperature* has been added to :ref:`ComputeCalibrationCoefVan <algm-ComputeCalibrationCoefVan>`.
 
 New features
 ------------
@@ -23,8 +27,16 @@ Algorithms
 ##########
 
 - A utility algorithm :ref:`WorkflowAlgorithmRunner <algm-WorkflowAlgorithmRunner>` has been added to manage the running of certain data reduction workflows at ILL.
+- New algorithm :ref:`CorrectTOFAxis <algm-CorrectTOFAxis>` enables the adjustment of the time-of-flight axis according to incident energy or reference workspace.
 
 Crystal Field
 -------------
 
 - The peak widths can be fixed to or varied around values obtained from experimental or calculated instrument resolution function.
+- The initial field parameters can be estimated using a Monte Carlo search algorithm (:ref:`EstimateFitParameters <algm-EstimateFitParameters>`)
+- The crystal field heat capacity, magnetisation and susceptibility can now be calculated or fitted, using new functions
+  :ref:`CrystalFieldHeatCapacity <func-CrystalFieldHeatCapacity>`, :ref:`CrystalFieldSusceptibility <func-CrystalFieldSusceptibility>`,
+  :ref:`CrystalFieldMagnetisation <func-CrystalFieldMagnetisation>`, and :ref:`CrystalFieldMoment <func-CrystalFieldMoment>`.
+  The Python interface :ref:`Crystal Field Python Interface` has also been updated to handle calculating and fitting these quantities.
+
+`Full list of changes on GitHub <http://github.com/mantidproject/mantid/pulls?q=is%3Apr+milestone%3A%22Release+3.9%22+is%3Amerged+label%3A%22Component%3A+Direct+Inelastic%22>`_
diff --git a/docs/source/release/v3.9.0/framework.rst b/docs/source/release/v3.9.0/framework.rst
index ce414e3e898940a97ac57f1f2461c9eae632f775..3941119e13787c445334a5e12e9253cac4884288 100644
--- a/docs/source/release/v3.9.0/framework.rst
+++ b/docs/source/release/v3.9.0/framework.rst
@@ -5,6 +5,14 @@ Framework Changes
 .. contents:: Table of Contents
    :local:
 
+Changes
+-------
+
+- Mantid now supports automatic updates to the facilities.xml file in the same way that it does the instrument definitions.  This allows extensions and changes to the list of supported instruments without needing to install a new release of Mantid.
+  - This has been initially put into place to support a data file naming change for Vesuvio, but will help for future changes as well.
+
+- Mantid is aware of the change to file naming for Vesuvio, you can continue to use EVS or VESUVIO as a prefix when trying to load files from this instrument, and Mantid will map that to the correct filenames.
+
 Algorithms
 ----------
 
@@ -12,55 +20,103 @@ New
 ###
 
 - :ref:`ConvertToConstantL2 <algm-ConvertToConstantL2>` is the new name for CorrectFlightPaths.
+- :ref:`BinWidthAtX <algm-BinWidthAtX>` calculates the bin width at X, averaged over all histograms. 
+- :ref:`MedianBinWidth <algm-MedianBinWidth>` provides the median bin widths of histograms.
+
 
 Improved
 ########
 
-- :ref:`CalculateFlatBackground <algm-CalculateFlatBackground>` has now a new mode 'Moving Average' which takes the minimum of a moving window average as the flat background.
+- :ref:`CalculateFlatBackground <algm-CalculateFlatBackground>` has a new mode 'Moving Average', which takes the minimum of a moving window average as the flat background.
 - :ref:`StartLiveData <algm-StartLiveData>` and its dialog now support dynamic listener properties, based on the specific LiveListener being used.
+- All algorithms using AsciiPointBase now have a new property 'Separator' which allows the delimiter to be set to either comma, space or tab. This affects :ref:`SaveReflCustomAscii <algm-SaveReflCustomAscii>`, :ref:`SaveReflThreeColumnAscii <algm-SaveReflThreeColumnAscii>`, :ref:`SaveANSTOAscii <algm-SaveANSTOAscii>` and :ref:`SaveILLCosmosAscii <algm-SaveILLCosmosAscii>`.
+- :ref:`ReplaceSpecialValues <algm-ReplaceSpecialValues>` allows for 'small' values, which are below a user specified threshold, to be replaced.
+- :ref:`Stitch1DMany <algm-Stitch1DMany>` has a new property 'ScaleFactorFromPeriod', which enables it to apply scale factors from a particular period when stitching group workspaces. The documentation for this algorithm has also been improved.
+- :ref:`SaveMDWorkspaceToVTK <algm-SaveMDWorkspaceToVTK>` has a working progress bar.
+- :ref:`SumSpectra <algm-SumSpectra>` has an option to ignore special floating point values called 'RemoveSpecialValues'. This is off by default. When enabled it will ignore values such as NaN or Infinity during the summation of the spectra.  It was also updated to fix special values being used in some cases when the option was selected.
+- :ref:`MonteCarloAbsorption <algm-MonteCarloAbsorption>`:
+   - An `Interpolation` option has been added. The availabile options are: `Linear` & `CSpline`.
+   - The method of selecting the scattering point has ben updated to give better agreement with numerical algorithms (e.g. :ref:`CylinderAbsorption <algm-CylinderAbsorption>`).
+- :ref:`SetSample <algm-SetSample>` now accepts an Angle argument for defining a rotated flat plate sample.
+- :ref:`MaskDetectors <algm-MaskDetectors>` has a new option to mask detectors by the instrument's component name. It can accept a masked workspace with a differing number of spectra to the input workspace, providing that the number of detectors match. This can be useful in the case of hardware grouped detectors.
+
+- :ref:`SavePlot1D <algm-SavePlot1D>` now supports optional ``SpectraList`` for plotting
+- :ref:`MayersSampleCorrection <algm-MayersSampleCorrection>`: The calculation of the azimuth angle has been fixed. Previously it was set equal to the Mantid definition of phi but the old code defined it as the angle away from the scattering plane.
+- :ref:`MatchPeaks <algm-MatchPeaks>` performs circular shift operation (numpy roll) along the x-axis to align the peaks in the spectra.
+- :ref:`FindEPP <algm-FindEPP>` is improved to better determine the initial parameters and range for the fitting.
+- :ref:`StartLiveData <algm-StartLiveData>` can now accept LiveListener properties as parameters, based on the value of the "Instrument" parameter.
+Renamed
+#######
 
-Deprecated
-##########
+- :ref:`CorrectFlightPaths <algm-ConvertToConstantL2>` has been renamed to :ref:`ConvertToConstantL2 <algm-ConvertToConstantL2>`.
+
+Bug Fixes
+#########
 
-- :ref:`CorrectFlightPaths <algm-CorrectFlightPaths>` has been renamed to ConvertToConstantL2.
+- Bin masking information was incorrectly saved when converting workspaces into nexus files, which is now fixed.
+- :ref:`LoadEventNexus <algm-LoadEventNexus>` should no longer leak memory when the execution is cancelled.
+- :ref:`LoadNexusProcessed <algm-LoadNexusProcessed>` will now load the stored workspace names from a processed Nexus file in the case of multiperiod data.
+- If a run is aborted and restarted, the ``running`` log in the workspace will correctly reflect this. (``running`` will be false at all times before the abort.)
+- Fixed several issues with masked detectors and neighbour counts in the nearest-neighbour code used by a few algorithms.
+- Issues with :ref:`CalculateFlatBackground <algm-CalculateFlatBackground>` with  **Return Background** option returning fake values has been fixed.
 
-MD Algorithms (VATES CLI)
-#########################
+Deprecated
+##########
 
-Performance
------------
+- :ref:`AbortRemoteJob	 <algm-AbortRemoteJob>` is deprecated in favour of v2.
+- :ref:`Authenticate	 <algm-Authenticate>`  is deprecated in favour of v2.
+- :ref:`CentroidPeaksMD	 <algm-CentroidPeaksMD>`  is deprecated in favour of v2.
+- :ref:`ConvertEmptyToTof	 <algm-ConvertEmptyToTof>`.
+- :ref:`ConvertUnitsUsingDetectorTable	 <algm-ConvertUnitsUsingDetectorTable>`.
+- :ref:`DownloadRemoteFile	 <algm-DownloadRemoteFile>` is deprecated in favour of v2.
+- :ref:`FFTSmooth	 <algm-FFTSmooth>` is deprecated in favour of v2.
+- :ref:`OneStepMDEW	 <algm-OneStepMDEW>`.
+- :ref:`QueryAllRemoteJobs	 <algm-QueryAllRemoteJobs>` is deprecated in favour of v2.
+- :ref:`RefinePowderInstrumentParameters	 <algm-RefinePowderInstrumentParameters>` is deprecated in favour of v2.
+- :ref:`SetupILLD33Reduction	 <algm-SetupILLD33Reduction>`.
+- :ref:`StartRemoteTransaction	 <algm-StartRemoteTransaction>` is deprecated in favour of v2.
+- :ref:`LoadILLAscii	 <algm-LoadILLAscii>`.
+- :ref:`StopRemoteTransaction	 <algm-StopRemoteTransaction>` is deprecated in favour of v2.
+- :ref:`SubmitRemoteJob	 <algm-SubmitRemoteJob>` is deprecated in favour of v2.
+- :ref:`Transpose3D	 <algm-Transpose3D>` is deprecated in favour :ref:'TransposeMD <algm_TransposeMD>'.
+- The Python function `IMDDimension.getName()` has been deprecated in favour of `IMDDimension.name'.
+- The duplicate Python function `Workspace.getName()` has been deprecated in favour of `Workspace.name()'.
+Removed
+#######
+
+The following (previously deprecated) algorithms versions have now been removed:
+
+- LoadEventPreNexus v1
+- LoadLogsForSNSPulsedMagnet v1
+- Lorentzian1D v1
+- ProcessDasNexusLog v1
+- LoadILL v1
+- SANSDirectBeamScaling v1
 
 CurveFitting
 ------------
 
+- Systemtest and FittingBenchmarks have been added for testing the minimizer, the scripts generate the tables displayed on :ref:`FittingMinimzers page <FittingMinimizers>`. This Systemtest also demo how these tables can be created as a standard Mantid script.
+- Recommendations for which fitting method to use for a given data set has been added to :ref:`FittingMinimzers page <FittingMinimizers>`.
+- Algorithm :ref:`CalculateCostFunction <algm-CalculateCostFunction>` calculates a value of any available cost function.
+- Algorithm :ref:`EstimateFitParameters <algm-EstimateFitParameters>` estimates the initial values of a fiting function in given intervals.
+- `Exclude` is new property of :ref:`Fit <algm-Fit>`, which allows for a user defined range to be excluded from a fit. 
+- Fit Function :ref:`FunctionQDepends <func-FunctionQDepends>` as the base class for QENS models depending on Q.
+
 Improved
 ########
 
-Python
-------
+- The `Peak Radius` global setting for 1D peaks is replaced with `PeakRadius` property of the :ref:`Fit <algm-Fit>` algorithm (see algorithm's description for the details).
 
-Python Algorithms
-#################
+.. figure:: ../../images/NoPeakRadius_3.9.png
+   :class: screenshot
+   :width: 550px
 
-- :ref:`MatchPeaks <algm-MatchPeaks>` performs circular shift operation (numpy roll) along the x-axis to align the peaks in the spectra.
-- :ref:`FindEPP <algm-FindEPP>` is improved to better determine the initial parameters and range for the fitting.
-- :ref:`StartLiveData <algm-StartLiveData>` can now accept LiveListener properties as parameters, based on the value of the "Instrument" parameter.
+- The output and normalization MDHistoWorkspaces from :ref:`MDNormSCD <algm-MDNormSCD>` and :ref:`MDNormDirectSC <algm-MDNormDirectSC>` have the 'displayNormalization' set to 'NoNormalization'. For older outputs, the `setDisplayNormalization` function is now exposed to python.
 
-Bug Fixes
----------
-
-- Bin masking information was wrongly saved when saving workspaces into nexus files, which is now fixed.
-- :ref:`LoadEventNexus <algm-LoadEventNexus>` should no longer leak memory when the execution is cancelled.
-- :ref:`LoadNexusProcessed <algm-LoadNexusProcessed>` will now load the stored workspace names from a processed Nexus file in the case of multiperiod data.
-- If a run is aborted and restarted, the ``running`` log in the workspace will correctly reflect this. (``running`` will be false at all times before the abort.)
 
 Full list of
 `Framework <http://github.com/mantidproject/mantid/pulls?q=is%3Apr+milestone%3A%22Release+3.9%22+is%3Amerged+label%3A%22Component%3A+Framework%22>`__
 and
 `Python <http://github.com/mantidproject/mantid/pulls?q=is%3Apr+milestone%3A%22Release+3.9%22+is%3Amerged+label%3A%22Component%3A+Python%22>`__
 changes on GitHub
-
-Bug Fixes
----------
-
-- Fixed several issues with masked detectors and neighbour counts in the nearest-neighbour code used by a few algorithms.
diff --git a/docs/source/release/v3.9.0/imaging.rst b/docs/source/release/v3.9.0/imaging.rst
new file mode 100644
index 0000000000000000000000000000000000000000..364280c89aa7f309611382922d23b0d76d3c7b61
--- /dev/null
+++ b/docs/source/release/v3.9.0/imaging.rst
@@ -0,0 +1,24 @@
+=====================
+Imaging Changes
+=====================
+
+.. contents:: Table of Contents
+   :local:
+
+Tomographic reconstruction graphical user interface
+###################################################
+
+- Running local reconstructions is now possible, only a single reconstruction process can be run at any one time
+
+Bug Fixes
+---------
+- The external interpreter and scripts paths are no longer ignored and are now correctly appended when running a local reconstruction
+- Local reconstruction processes are now also updated in the reconstruction jobs list
+- The reconstruction jobs list command line is now Read Only
+- Clicking Cancel now cancels the running reconstruction process
+- The reconstruction scripts will now work with TomoPy v1.x.x, however the results have yet to be tested
+- Selecting the Center of Rotation, Area for Normalsation and Region of Interest will now always follow the exact position of the mouse
+- Multiple success/warning/error messages will no longer be shown after an operation. 
+
+
+`Full list of changes on github <http://github.com/mantidproject/mantid/pulls?q=is%3Apr+milestone%3A%22Release+3.9%22+is%3Amerged+label%3A%22Component%3A+Imaging%22>`__
diff --git a/docs/source/release/v3.9.0/index.rst b/docs/source/release/v3.9.0/index.rst
index 7ecf71a22447a8084c4c5115895e04b4b265e719..1b2dd8fd0abdb8014d04ac12ee8cb25eeaf2d2c6 100644
--- a/docs/source/release/v3.9.0/index.rst
+++ b/docs/source/release/v3.9.0/index.rst
@@ -2,12 +2,12 @@
 Mantid 3.9.0 Release Notes
 ==========================
 
-.. figure:: ../../images/ReleaseUnderConstruction.jpg
+.. figure:: ../../images/release39.png
    :class: screenshot
    :width: 550px
    :align: right
 
-   Release image
+   The Slice Viewer now is able to display data with non orthogonal axes
 
 .. contents:: Table of Contents
    :local:
@@ -37,7 +37,12 @@ Citation
 
 Please cite any usage of Mantid as follows:
 
+- *O. Arnold, et al., Mantid—Data analysis and visualization package for neutron scattering and μSR experiments, Nuclear Instruments and Methods in Physics Research Section A, Volume 764, 11 November 2014, Pages 156-166*, doi: `10.1016/j.nima.2014.07.029 <http://dx.doi.org/10.1016/j.nima.2014.07.029>`_
+
+If you want to cite this specific release please use:
+
 - *Mantid 3.9: Manipulation and Analysis Toolkit for Instrument Data.; Mantid Project*. doi: http://dx.doi.org/10.5286/SOFTWARE/MANTID3.9
+  `Full author list <http://data.datacite.org/10.5286/SOFTWARE/MANTID3.9>`_
 
 Changes
 -------
@@ -51,6 +56,7 @@ Changes
    Indirect Inelastic <indirect_inelastic>
    SANS <sans>
    Diffraction <diffraction>
+   Imaging <imaging>
    Muon Analysis <muon>
    Reflectometry <reflectometry>
 
diff --git a/docs/source/release/v3.9.0/indirect_inelastic.rst b/docs/source/release/v3.9.0/indirect_inelastic.rst
index b85b26e9333b06a7772c2ab65e9c1fb896feadb9..178c68bb445d8c10e503fb32a9a4f1f4b20dbad0 100644
--- a/docs/source/release/v3.9.0/indirect_inelastic.rst
+++ b/docs/source/release/v3.9.0/indirect_inelastic.rst
@@ -11,19 +11,28 @@ New features
 Algorithms
 ##########
 
+- :ref:`EnergyWindowScan <algm-EnergyWindowScan>` and :ref:`IndirectQuickRun <algm-IndirectQuickRun>` have been added
+  to perform a quick run of *EnergyTransfer*, *Elwin* and optional *MSDFit*
 - A new algorithm :ref:`NMoldyn4Interpolation <algm-NMoldyn4Interpolation>` which interpolates simulated data onto reference OSIRIS data
+- A 'QuickRun' algorithm :ref:`SofQWMomentsScan <algm-SofQWMomentsScan>` that reduces data and runs through :ref:`SofQW <algm-SofQW>` and :ref:`SofQWMoments <algm-SofQWMoments>`.
 
 Data Reduction
 ##############
 
 - Q-values in :ref:`BASISReduction <algm-BASISReduction>` output are now point data so that their values display correctly when plotted
-
+- :ref:`LoadILLIndirect-v2 <algm-LoadILLIndirect-v2>` now checks in the ``.nxs`` files which single detectors (SD) are enabled, and loads only those instead of all, while moving them to the correct anlge read from the file.
+- New :ref:`IndirectILLEnergyTransfer <algm-IndirectILLEnergyTransfer>` algorithm performs initial data reduction steps for IN16B instrument data at ILL.
+- New :ref:`IndirectILLReductionQENS <algm-IndirectILLReductionQENS>` algorithm performs complete multiple file reduction for Quasi-Elastic Neutron Scattering (QENS) data from IN16B instrument at ILL.
+- New :ref:`IndirectILLReductionFWS <algm-IndirectILLReductionFWS>` algorithm performs complete multiple file reduction for the elastic and inelastic fixed-window scan data from IN16B instrument at ILL.
+- Deprecated :ref:`IndirectILLReduction <algm-IndirectILLReduction>` and :ref:`ILLIN16BCalibration <algm-ILLIN16BCalibration>` algorithms.
+- When plotting *ConvFit* results "Two Lorentzians" will produce plots for both lorentzians
 
 Data Analysis
 #############
 
 - :ref:`TeixeiraWaterSQE <func-TeixeiraWaterSQE>` models translation of water-like molecules (jump diffusion).
 - :ref:`GetQsInQENSData <algm-GetQsInQENSData>` Extracts or computes Q values from a MatrixWorkspace.
+- *Elwin* now uses sample environment units found in sample logs
 
 
 Improvements
@@ -40,7 +49,7 @@ CalculatePaalmanPings
 - Option to calculate number density from mass density
 
 Absorption
-~~~~~~~~~~~
+~~~~~~~~~~
 
 - Option to calculate number density from mass density
 
@@ -54,17 +63,23 @@ Transmission
 - :ref:`IsoRotDiff <func-IsoRotDiff>` models isotropic rotational diffusion of a particle
   tethered to the origin at a constant distance.
 
+Vesuvio
+#######
+
+- Run numbers can now be input as a range in :ref:`LoadVesuvio <algm-LoadVesuvio>` and :ref:`VesuvioDiffractionReduction <algm-VesuvioDiffractionReduction>`
 
 Improvements
 ------------
 
- - Data saved in an ASCII format using the *EnergyTransfer* interface can be re-loaded into Mantid
-
+- Data saved in an ASCII format using the *EnergyTransfer* interface can be re-loaded into Mantid
+- TOSCA instrument definition file has been updated
+- When plotting from interfaces the plots now display error bars as standard
 
 Bugfixes
 --------
 
 - Clicking 'Save' without creating a res file in *ISISCalibration* no longer causes an error
+- Fixed issue when trying to plot multiple spectra
 
 
 `Full list of changes on GitHub <http://github.com/mantidproject/mantid/pulls?q=is%3Apr+milestone%3A%22Release+3.9%22+is%3Amerged+label%3A%22Component%3A+Indirect+Inelastic%22>`_
diff --git a/docs/source/release/v3.9.0/muon.rst b/docs/source/release/v3.9.0/muon.rst
index 830203ca229762cf8975fdd6c008aff6a85172c9..68b317d62430515a1a9f722d2e11acf2b3f9854b 100644
--- a/docs/source/release/v3.9.0/muon.rst
+++ b/docs/source/release/v3.9.0/muon.rst
@@ -18,7 +18,11 @@ Muon Analysis
 - Fixed a bug where the "load next/previous" buttons appended runs in certain cases where this was not the intended behaviour.
 - The *Grouping Options* and *Data Analysis* tabs now only become enabled once data has been loaded on the *Home* tab. Data should first be loaded on the *Home* tab, then it can be grouped/fitted. After the first dataset has been loaded, additional datasets can of course be added (for a multi-dataset fit) using the *Data Analysis* tab.
 - The "compatibility mode" option has been renamed "Enable multiple fitting", and defaults to off. The interface will therefore look the same as it did in Mantid 3.7 by default. To enable the new multi-fitting functionality, just tick the box on the settings tab.
-
+- The layout of the new fitting tab UI has been improved to give more space for the fitting function, and enable the relative space given to each section to be adjusted by the user.
+- Fixed a bug where stale plot guesses would be left on the graph in some situations.
+- Fixed a bug with load current run that meant it would be actually loading old data due to caching. Data from current run files is no longer cached behind the scenes.
+- The default Plot Policy has been changed to **Use Previous Window**.  This avoids the speed and stability issues that could occur with **Create New Window** once hundreds of graph windows had accumulated over several days of an experiement.
+- Fixed a bug for the time averaging within the muon analysis. Now uses the time average function. 
 Algorithms
 ----------
 
diff --git a/docs/source/release/v3.9.0/reflectometry.rst b/docs/source/release/v3.9.0/reflectometry.rst
index 3567b7e6395991cce10cbb6eb71e0f07e03d3112..cee752e7da48d35703a60a385ca183bf43279e15 100644
--- a/docs/source/release/v3.9.0/reflectometry.rst
+++ b/docs/source/release/v3.9.0/reflectometry.rst
@@ -5,9 +5,11 @@ Reflectometry Changes
 .. contents:: Table of Contents
    :local:
 
-ConvertToReflectometryQ
------------------------
+Algorithms
+----------
 
+- :ref:`algm-Stitch1D` documentation has been improved, it now includes a workflow diagram illustrating the different steps in the calculation and a note about how errors are propagated.
+- :ref:`Stitch1DMany <algm-Stitch1DMany>` has a new property 'ScaleFactorFromPeriod' which enables it to apply scale factors from a particular period when stitching group workspaces.
 
 Reflectometry Reduction Interface
 ---------------------------------
@@ -16,6 +18,13 @@ ISIS Reflectometry (Polref)
 ###########################
 
 - Settings tab now displays individual global options for experiment and instrument settings.
+- New 'Save ASCII' tab added, similar in function and purpose to the 'Save Workspaces' window accessible from Interfaces->ISIS Reflectometry->File->Save Workspaces.
+- When runs are transferred to the processing table groups are now labeled according to run title.
+- Column :literal:`dQ/Q` is used as the rebin parameter to stitch workspaces.
+- Fixed a bug where if the user answered 'no' to a popup asking if they wanted to process all runs, the progress bar would show activity as though a data reduction was occurring.
+- The interface is now arranged in two different groups. Groups apply to tabs 'Run' and 'Settings'.
+- Documentation regarding the interface has been updated accordingly.
+- Error messages are displayed if the user either attempts to transfer zero runs or transfer runs with a different strategy to the one they used to search for runs with. 
 
 ISIS Reflectometry
 ##################
diff --git a/docs/source/release/v3.9.0/sans.rst b/docs/source/release/v3.9.0/sans.rst
index 681c914cb3f403295d7744d0531cc013816c7794..687a695a66f64b53457b7fb1e2908c3eaa34ba03 100644
--- a/docs/source/release/v3.9.0/sans.rst
+++ b/docs/source/release/v3.9.0/sans.rst
@@ -20,6 +20,11 @@ Bug Fixes
 - Fix for LARMOR multi-period loading. The initial rotation was not correctly applied to all child workspaces.
 - IDF bug when using Larmor in batch mode was resolved.
 - Issue where Gui changes were not picked up for batch reductions was resolved.
+- Remove SaveNexusProcessed and SaveCSV as an option. Reorder options by dimensionality.
+- Fix for merged reduction with phi masking.
+- Fix SAScollimation issue in SaveCanSAS1D and LoadCanSAS1D.
+- Improved CropToComponent and removed detector ordering.
+
 
 X uncertainties (delta-Q)
 -------------------------
diff --git a/docs/source/release/v3.9.0/ui.rst b/docs/source/release/v3.9.0/ui.rst
index 7473dda26b6d0c16df99fc7fcd0576dd425239a1..a209ea6a2b7f64f73a29001cc2143fd2098a159e 100644
--- a/docs/source/release/v3.9.0/ui.rst
+++ b/docs/source/release/v3.9.0/ui.rst
@@ -5,27 +5,20 @@ UI & Usability Changes
 .. contents:: Table of Contents
    :local:
 
-Installation
-------------
-
-Windows
-#######
-
-OS X
-####
 
 User Interface
 --------------
 
-- ParaView's python scripting interface is available from within MantidPlot and mantidpython. Type `from paraview.simple import *` to get started.
-  `Additional documentation <http://www.paraview.org/ParaView3/Doc/Nightly/www/py-doc/>`_
-
 Instrument View
 ###############
- - New peak comparison tool on the pick tab. The user can select two peaks and information relating to their properties and the angles between them.
+
+- New peak comparison tool on the pick tab. The user can select two peaks and information relating to their properties and the angles between them.
+- Added the ability to drag and drop mask workspaces onto the instrument view. This will apply the store workspace to the view.
+- Added the ability to store masking/ROI/grouping shapes to a table workspace, which can be dragged & dropped back onto different instrument views. 
 
 Plotting Improvements
 #####################
+
 - Fixed a bug where left and right Y axes went out of sync when a fit was run.
 - Exposed the ``plotSubplots`` command to Python. This creates a tiled (multilayer) plot with one workspace per tile.
 
@@ -39,39 +32,66 @@ Plotting Improvements
 Algorithm Toolbox
 #################
 
-- Add compressorType option to SaveMDWorkspaceToVTK.
+- Added compressorType option to :ref:`SaveMDWorkspaceToVTK <algm-SaveMDWorkspaceToVTK>`.
+
+Python
+######
+
+- ParaView's python scripting interface is available from within MantidPlot and mantidpython. Type `from paraview.simple import *` to get started. Additional documentation is available `here <http://www.paraview.org/ParaView3/Doc/Nightly/www/py-doc/>`_
 
-Scripting Window
-################
+Custom Interfaces
+-----------------
 
-Documentation
-#############
+- Indirect Data Reduction (facility ILL, instrument IN16B) is face-lifted to incorporate the new reduction algorithms options.
+
+
+SliceViewer Improvements
+------------------------
+
+- Added the ability to view data using non orthogonal axes. View can be toggled on or off. When non orthogonal view is toggled the peak viewer and line viewer tools are disabled.
+
+.. figure:: ../../images/SliceViewerNonOrthogonal.png
+   :class: screenshot
+   :width: 450px
+   :align: right
+
+   SliceViewer with nonorthogonal view 
 
 Bugs Resolved
 -------------
 
 - Fixed a bug where checking or unchecking "show invisible workspaces" in View->Preferences->Mantid->Options would have no effect on workspaces loaded in the dock.
 - The Spectrum Viewer now reports two theta and azimuthal angle correctly.
-- Fixed crash when clicking "Help->Ask for Help" on Linux-based systems with Firefox set as the default browser.  
-- Fixed crash when loading data and the algorithm widget is hidden
-- Fixed exception being thrown when saving project with custom interfaces open
+- Fixed crash when clicking "Help->Ask for Help" on Linux-based systems with Firefox set as the default browser.
+- The "Filter log values by" option in the Sample Logs dialog now works out the log statistics with the correct filter applied, and deals correctly with aborted runs.
+- Fixed crash when loading data and the algorithm widget is hidden.
+- Fixed exception being thrown when saving a project with custom interfaces open.
 - The "Plot Surface from Group" and "Plot Contour from Group" options have been fixed and now work for both histogram and point data. Note that all workspaces in the group must have the same X data.
 - Fixed a bug where enabling auto rebinning in the slice viewer and zooming would not rebin the workspace if it was a histogram workspace.
 - Fixed importing string logs and string series logs into MantidPlot
+- Legend placement has been fixed in the "tiled plot"/``plotSubplots`` option, and these graphs now use Mantid's default plot style options.
+- Fixed a bug where saving a plot created from columns of a table window are loaded back as a blank plot from a Mantid project.
+- Fixed a bug where saving a tiled plot to a project file, would be reloaded with different size plots when opened.
+- Fixed a bug where minimised windows would not stay minimised after being serialised to a Mantid project
+- Fixed a bug where changing the integration range of the instrument view would clear the applied zooming.
+- Fixed a bug where the threshold filter in the VSI SplatterPlot view only returned an empty dataset.
+- Fixed a bug where plotting a column of TableWorkspace in the GUI did not work if decimal separator was not a dot.
 
-SliceViewer Improvements
-------------------------
 
-|
+VSI Improvements
+----------------
+
+- ParaView updated to v5.2.0
+- The sources and views more reliably show progress in the VSI status bar. 
+- Added a button to the standard view which applies the threshold filter.
+- Update the cut button to match the equivalent ParaView icon.
+- Changed the fallback for when MDHistoworkspace was opened in the (incompatible) SplatterPlot view to the MultiSlice view.
+- Faster initial loading of a MDHistoworkspace in the MultiSlice and ThreeSlice view.
+- Drawing of a MDHistoWorkspace is now carried out in parallel using vtkSMPTools.
+
 
 Full list of
 `GUI <http://github.com/mantidproject/mantid/pulls?q=is%3Apr+milestone%3A%22Release+3.9%22+is%3Amerged+label%3A%22Component%3A+GUI%22>`_
 and
 `Documentation <http://github.com/mantidproject/mantid/pulls?q=is%3Apr+milestone%3A%22Release+3.9%22+is%3Amerged+label%3A%22Component%3A+Documentation%22>`_
 changes on GitHub
-
-
-VSI Improvements
-----------------
-
-ParaView updated to v5.2.0
diff --git a/images/osx-bundle-background.png b/images/osx-bundle-background.png
index fa945f2dadba6aa69b1eafea2315551fe9d658d6..1b1d160a214be3dacea7b12cd273e7d5ba43b060 100644
Binary files a/images/osx-bundle-background.png and b/images/osx-bundle-background.png differ
diff --git a/installers/MacInstaller/CMakeDMGSetup.scpt b/installers/MacInstaller/CMakeDMGSetup.scpt
new file mode 100644
index 0000000000000000000000000000000000000000..37a2e9dde79f2a68c31733b110eaf0267bf9fb00
--- /dev/null
+++ b/installers/MacInstaller/CMakeDMGSetup.scpt
@@ -0,0 +1,59 @@
+on run argv
+  set image_name to item 1 of argv
+
+  tell application "Finder"
+  tell disk image_name
+
+    -- wait for the image to finish mounting
+    set open_attempts to 0
+    repeat while open_attempts < 4
+      try
+        open
+          delay 1
+          set open_attempts to 5
+        close
+      on error errStr number errorNumber
+        set open_attempts to open_attempts + 1
+        delay 10
+      end try
+    end repeat
+    delay 5
+
+    -- open the image the first time and save a DS_Store with just
+    -- background and icon setup
+    open
+      set current view of container window to icon view
+      set theViewOptions to the icon view options of container window
+      set background picture of theViewOptions to file ".background:background.png"
+      set arrangement of theViewOptions to not arranged
+      set icon size of theViewOptions to 128
+      delay 5
+    close
+
+    -- next setup the position of the app and Applications symlink
+    -- plus hide all the window decoration
+    open
+      update without registering applications
+      tell container window
+        set sidebar width to 0
+        set statusbar visible to false
+        set toolbar visible to false
+        set the bounds to { 400, 000, 900, 517 }
+        set position of item "MantidPlot.app" to { 110, 220 }
+        set position of item "Applications" to { 380, 220 }
+        set position of item "MantidPython (optional)" to { 380, 400 }
+        set position of item "MantidNotebook (optional)" to { 110, 400 }
+      end tell
+      update without registering applications
+      delay 5
+    close
+
+    -- one last open and close so you can see everything looks correct
+    open
+      delay 5
+    close
+
+  end tell
+  delay 1
+end tell
+end run
diff --git a/installers/MacInstaller/Info.plist.in b/installers/MacInstaller/Info.plist.in
index dff679f8c0bc109786ce56a5ef75f035249f69f1..542bf5487b35e797918a0d9bc610801c59810d65 100644
--- a/installers/MacInstaller/Info.plist.in
+++ b/installers/MacInstaller/Info.plist.in
@@ -7,7 +7,7 @@
 	<key>CFBundleExecutable</key>
 	<string>MantidPlot</string>
 	<key>CFBundleGetInfoString</key>
-	<string>@VERSION_MAJOR@.@VERSION_MINOR@.@MtdVersion_WC_LAST_CHANGED_REV@</string>
+	<string>@VERSION_MAJOR@.@VERSION_MINOR@.@VERSION_PATCH@</string>
 	<key>CFBundleIconFile</key>
 	<string>MantidPlot.icns</string>
 	<key>CFBundleIdentifier</key>
@@ -15,17 +15,17 @@
 	<key>CFBundleInfoDictionaryVersion</key>
 	<string>6.0</string>
 	<key>CFBundleLongVersionString</key>
-	<string>@VERSION_MAJOR@.@VERSION_MINOR@.@MtdVersion_WC_LAST_CHANGED_REV@</string>
+	<string>@VERSION_MAJOR@.@VERSION_MINOR@.@VERSION_PATCH@</string>
 	<key>CFBundleName</key>
 	<string>MantidPlot</string>
 	<key>CFBundlePackageType</key>
 	<string>APPL</string>
 	<key>CFBundleShortVersionString</key>
-	<string>@VERSION_MAJOR@.@VERSION_MINOR@.@MtdVersion_WC_LAST_CHANGED_REV@</string>
+	<string>@VERSION_MAJOR@.@VERSION_MINOR@.@VERSION_PATCH@</string>
 	<key>CFBundleSignature</key>
 	<string>????</string>
 	<key>CFBundleVersion</key>
-	<string>@VERSION_MAJOR@.@VERSION_MINOR@.@MtdVersion_WC_LAST_CHANGED_REV@</string>
+	<string>@VERSION_MAJOR@.@VERSION_MINOR@.@VERSION_PATCH@</string>
 	<key>CSResourcesFileMapped</key>
 	<true/>
 	<key>LSRequiresCarbon</key>
diff --git a/installers/MacInstaller/osx_DS_Store b/installers/MacInstaller/osx_DS_Store
deleted file mode 100644
index 0dc150247065eb3111939da1d68369963e5db36e..0000000000000000000000000000000000000000
Binary files a/installers/MacInstaller/osx_DS_Store and /dev/null differ
diff --git a/instrument/Facilities.xml b/instrument/Facilities.xml
index 2b6399ddd6f8b7e78b2de02f37cc287407e97100..ccdb1a5a5fc2dcbb5e5313ebce3226f4ab90bdb3 100644
--- a/instrument/Facilities.xml
+++ b/instrument/Facilities.xml
@@ -2,6 +2,7 @@
 <facilities>
 
 <facility name="ISIS" zeropadding="5" FileExtensions=".nxs,.raw,.sav,.n*,.s*,.add,.nxspe">
+
   <archive>
     <archiveSearch plugin="ISISDataSearch" />
   </archive>
@@ -23,100 +24,134 @@
 
   <instrument name="ALF">
     <technique>Single Crystal Diffraction</technique>
-    <livedata address="NDXALF:6789" />
+    <livedata>
+      <connection name="histo" address="NDXALF:6789" listener="ISISHistoDataListener" />
+    </livedata>
   </instrument>
 
   <instrument name="CRISP" shortname="CSP">
-    <zeropadding size="8" startRunNumber="99778" prefix="CRISP"/> 	
+    <zeropadding size="8" startRunNumber="99778" prefix="CRISP" />
     <technique>Reflectometry</technique>
-    <livedata address="NDXCRISP:6789" />
+    <livedata>
+      <connection name="histo" address="NDXCRISP:6789" listener="ISISHistoDataListener" />
+    </livedata>
   </instrument>
 
   <instrument name="ENGIN-X" shortname="ENGINX" >
-    <zeropadding size="8"/>
+    <zeropadding size="8" />
     <technique>Neutron Diffraction</technique>
-    <livedata address="NDXENGINX:6789" />
+    <livedata default="histo">
+      <connection name="histo" address="NDXENGINX:6789" listener="ISISHistoDataListener" />
+    </livedata>
   </instrument>
 
   <instrument name="ENGIN-X_EVENT" shortname="ENGINX" >
-    <zeropadding size="8"/>
+    <zeropadding size="8" />
     <technique>Neutron Diffraction</technique>
-    <livedata address="NDXENGINX:10000" listener="ISISLiveEventDataListener" />
+    <livedata default="event">
+      <connection name="event" address="NDXENGINX:10000" listener="ISISLiveEventDataListener" />
+    </livedata>
   </instrument>
 
   <instrument name="GEM">
     <technique>Neutron Diffraction</technique>
-    <livedata address="NDXGEM:6789" />
+    <livedata>
+      <connection name="histo" address="NDXGEM:6789" listener="ISISHistoDataListener" />
+    </livedata>
   </instrument>
 
   <instrument name="HET">
     <technique>Neutron Spectroscopy</technique>
     <technique>TOF Direct Geometry Spectroscopy</technique>
-    <livedata address="NDXHET:6789" />
+    <livedata>
+      <connection name="histo" address="NDXHET:6789" listener="ISISHistoDataListener" />
+    </livedata>
   </instrument>
 
   <instrument name="HRPD" shortname="HRP">
     <technique>Powder Diffraction</technique>
     <technique>Neutron Diffraction</technique>
-    <livedata address="NDXHRPD:6789" />
+    <livedata>
+      <connection name="histo" address="NDXHRPD:6789" listener="ISISHistoDataListener" />
+    </livedata>
   </instrument>
 
   <instrument name="IMAT">
     <technique>Neutron Imaging</technique>
-    <livedata address="NDXIMAT:6789" />
+    <livedata>
+      <connection name="histo" address="NDXIMAT:6789" listener="ISISHistoDataListener" />
+    </livedata>
   </instrument>
 
   <instrument name="INES" shortname="INS" beamline="N8">
     <technique>Neutron Diffraction</technique>
-    <livedata address="NDXINES:6789" />
+    <livedata>
+      <connection name="histo" address="NDXINES:6789" listener="ISISHistoDataListener" />
+    </livedata>
   </instrument>
 
   <instrument name="INTER">
     <technique>Reflectometry</technique>
     <zeropadding size="8"/>
-    <livedata address="NDXINTER:6789" />
+    <livedata>
+      <connection name="histo" address="NDXINTER:6789" listener="ISISHistoDataListener" />
+    </livedata>
   </instrument>
 
   <instrument name="IRIS" shortname="IRS" beamline="N6">
     <zeropadding size="8" startRunNumber="54938" prefix="IRIS"/>
     <technique>Neutron Spectroscopy</technique>
     <technique>TOF Indirect Geometry Spectroscopy</technique>
-    <livedata address="NDXIRIS:6789" />
+    <livedata>
+      <connection name="histo" address="NDXIRIS:6789" listener="ISISHistoDataListener" />
+    </livedata>
   </instrument>
 
   <instrument name="LARMOR">
     <technique>Small Angle Scattering</technique>
     <zeropadding size="8"/>
-    <livedata address="NDXLARMOR:6789" />
+    <livedata>
+      <connection name="histo" address="NDXLARMOR:6789" listener="ISISHistoDataListener" />
+    </livedata>
   </instrument>
 
   <instrument name="LOQ">
     <technique>Small Angle Scattering</technique>
-    <livedata address="NDXLOQ:6789" />
+    <livedata>
+      <connection name="histo" address="NDXLOQ:6789" listener="ISISHistoDataListener" />
+    </livedata>
   </instrument>
 
   <instrument name="MAPS" shortname="MAP">
     <technique>Neutron Spectroscopy</technique>
     <technique>TOF Direct Geometry Spectroscopy</technique>
-    <livedata address="NDXMAPS:6789" />
+    <livedata>
+      <connection name="histo" address="NDXMAPS:6789" listener="ISISHistoDataListener" />
+    </livedata>
   </instrument>
 
   <instrument name="MARI" shortname="MAR">
     <technique>Neutron Spectroscopy</technique>
     <technique>TOF Direct Geometry Spectroscopy</technique>
-    <livedata address="NDXMARI:6789" />
+    <livedata>
+      <connection name="histo" address="NDXMARI:6789" listener="ISISHistoDataListener" />
+    </livedata>
   </instrument>
 
   <instrument name="MERLIN" shortname="MER">
     <technique>Neutron Spectroscopy</technique>
     <technique>TOF Direct Geometry Spectroscopy</technique>
-    <livedata address="NDXMERLIN:6789" />
+    <livedata>
+      <connection name="histo" address="NDXMERLIN:6789" listener="ISISHistoDataListener" />
+    </livedata>
   </instrument>
 
   <instrument name="MERLIN_EVENT" shortname="MER">
     <technique>Neutron Spectroscopy</technique>
     <technique>TOF Direct Geometry Spectroscopy</technique>
-    <livedata address="NDXMERLIN:10000" listener="ISISLiveEventDataListener" />
+    <livedata>
+      <connection name="event" address="NDXMERLIN:10000" listener="ISISLiveEventDataListener" />
+    </livedata>
   </instrument>
 
   <instrument name="OSIRIS" shortname="OSI" beamline="N6">
@@ -124,25 +159,33 @@
     <technique>Neutron Diffraction</technique>
     <technique>Neutron Spectroscopy</technique>
     <technique>TOF Indirect Geometry Spectroscopy</technique>
-    <livedata address="NDXOSIRIS:6789" />
+    <livedata>
+      <connection name="histo" address="NDXOSIRIS:6789" listener="ISISHistoDataListener" />
+    </livedata>
   </instrument>
 
   <instrument name="PEARL" shortname="PRL">
     <zeropadding size="5" startRunNumber="1" prefix="PRL"/>
     <zeropadding size="8" startRunNumber="71010" prefix="PEARL"/>
     <technique>Neutron Diffraction</technique>
-    <livedata address="NDXPEARL:6789" />
+    <livedata>
+      <connection name="histo" address="NDXPEARL:6789" listener="ISISHistoDataListener" />
+    </livedata>
   </instrument>
 
   <instrument name="POLARIS" shortname="POL">
     <technique>Neutron Diffraction</technique>
-    <livedata address="NDXPOLARIS:6789" />
+    <livedata>
+      <connection name="histo" address="NDXPOLARIS:6789" listener="ISISHistoDataListener" />
+    </livedata>
   </instrument>
 
   <instrument name="SANDALS" shortname="SLS">
     <technique>Neutron Diffraction</technique>
     <technique>Neutron Diffraction with isotopic substitution</technique>
-    <livedata address="NDXSANDALS:6789" />
+    <livedata>
+      <connection name="histo" address="NDXSANDALS:6789" listener="ISISHistoDataListener" />
+    </livedata>
   </instrument>
 
   <instrument name="SURF" shortname="SRF">
@@ -150,13 +193,17 @@
     <zeropadding size="6" startRunNumber="100000" prefix="SRF"/>
     <zeropadding size="8" startRunNumber="104604" prefix="SURF"/>
     <technique>Reflectometry</technique>
-    <livedata address="NDXSURF:6789" />
+    <livedata>
+      <connection name="histo" address="NDXSURF:6789" listener="ISISHistoDataListener" />
+    </livedata>
   </instrument>
 
   <instrument name="SXD">
     <technique>Neutron Diffraction</technique>
     <technique>Single Crystal Diffraction</technique>
-    <livedata address="NDXSXD:6789" />
+    <livedata>
+      <connection name="histo" address="NDXSXD:6789" listener="ISISHistoDataListener" />
+    </livedata>
   </instrument>
 
   <instrument name="TFXA" shortname="TFX">
@@ -167,64 +214,86 @@
   <instrument name="TOSCA" shortname="TSC">
     <technique>Neutron Spectroscopy</technique>
     <technique>TOF Indirect Geometry Spectroscopy</technique>
-    <livedata address="NDXTOSCA:6789" />
+    <livedata>
+      <connection name="histo" address="NDXTOSCA:6789" listener="ISISHistoDataListener" />
+    </livedata>
   </instrument>
 
   <instrument name="VESUVIO" shortname="EVS">
+    <zeropadding size="5" startRunNumber="1" prefix="EVS"/>
+    <zeropadding size="8" startRunNumber="25989" prefix="VESUVIO"/>
     <technique>Neutron Compton Scattering</technique>
     <technique>TOF Indirect Geometry Diffraction</technique>
-    <livedata address="NDXVESUVIO:6789" />
+    <livedata>
+      <connection name="histo" address="NDXVESUVIO:6789" listener="ISISHistoDataListener" />
+    </livedata>
   </instrument>
 
   <instrument name="LET">
     <zeropadding size="8"/>
     <technique>Neutron Spectroscopy</technique>
     <technique>TOF Direct Geometry Spectroscopy</technique>
-    <livedata address="NDXLET:6789" />
+    <livedata>
+      <connection name="histo" address="NDXLET:6789" listener="ISISHistoDataListener" />
+    </livedata>
   </instrument>
 
   <instrument name="LET_EVENT" shortname="LET">
     <zeropadding size="8"/>
     <technique>Neutron Spectroscopy</technique>
     <technique>TOF Direct Geometry Spectroscopy</technique>
-    <livedata address="NDXLET:10000" listener="ISISLiveEventDataListener" />
+    <livedata>
+      <connection name="event" address="NDXLET:10000" listener="ISISLiveEventDataListener" />
+    </livedata>
   </instrument>
 
   <instrument name="NIMROD">
     <zeropadding size="8"/>
     <technique>Neutron Diffraction</technique>
     <technique>Neutron Diffraction with isotopic substitution</technique>
-    <livedata address="NDXNIMROD:6789" />
+    <livedata>
+      <connection name="histo" address="NDXNIMROD:6789" listener="ISISHistoDataListener" />
+    </livedata>
   </instrument>
 
   <instrument name="OFFSPEC">
     <zeropadding size="8"/>
     <technique>Reflectometry</technique>
-    <livedata address="NDXOFFSPEC:6789" />
+    <livedata>
+      <connection name="histo" address="NDXOFFSPEC:6789" listener="ISISHistoDataListener" />
+    </livedata>
   </instrument>
 
   <instrument name="OFFSPEC_EVENT" shortname="OFFSPEC">
     <zeropadding size="8"/>
     <technique>Reflectometry</technique>
-    <livedata address="NDXOFFSPEC:10000" listener="ISISLiveEventDataListener" />
+    <livedata>
+      <connection name="event" address="NDXOFFSPEC:10000" listener="ISISLiveEventDataListener" />
+    </livedata>
   </instrument>
 
   <instrument name="POLREF">
     <zeropadding size="8"/>
     <technique>Reflectometry</technique>
-    <livedata address="NDXPOLREF:6789" />
+    <livedata>
+      <connection name="histo" address="NDXPOLREF:6789" listener="ISISHistoDataListener" />
+    </livedata>
   </instrument>
 
   <instrument name="SANS2D">
     <zeropadding size="8"/>
     <technique>Small Angle Scattering</technique>
-    <livedata address="NDXSANS2D:6789" />
+    <livedata>
+      <connection name="histo" address="NDXSANS2D:6789" listener="ISISHistoDataListener" />
+    </livedata>
   </instrument>
 
   <instrument name="SANS2D_EVENT" shortname="SANS2D">
     <zeropadding size="8"/>
     <technique>Small Angle Scattering</technique>
-    <livedata address="NDXSANS2D:10000" listener="ISISLiveEventDataListener" />
+    <livedata>
+      <connection name="event" address="NDXSANS2D:10000" listener="ISISLiveEventDataListener" />
+    </livedata>
   </instrument>
 
   <instrument name="WISH">
@@ -232,7 +301,9 @@
     <technique>Neutron Diffraction</technique>
     <technique>Powder Diffraction</technique>
     <technique>Single Crystal Diffraction</technique>
-    <livedata address="NDXWISH:6789" />
+    <livedata>
+      <connection name="histo" address="NDXWISH:6789" listener="ISISHistoDataListener" />
+    </livedata>
   </instrument>
 
   <instrument name="HIFI">
@@ -240,14 +311,18 @@
     <technique>Muon level crossing resonance</technique>
     <technique>Muon spectroscopy</technique>
     <technique>Radio frequency muSR</technique>
-    <livedata address="NDXHIFI:6789" />
+    <livedata>
+      <connection name="histo" address="NDXHIFI:6789" listener="ISISHistoDataListener" />
+    </livedata>
   </instrument>
 
   <instrument name="MUSR">
     <zeropadding size="8"/>
     <technique>Muon spectroscopy</technique>
     <technique>Radio frequency muSR</technique>
-    <livedata address="NDXMUSR:6789" />
+    <livedata>
+      <connection name="histo" address="NDXMUSR:6789" listener="ISISHistoDataListener" />
+    </livedata>
   </instrument>
 
   <instrument name="MUT">
@@ -260,7 +335,9 @@
     <zeropadding size="8"/>
     <technique>Muon spectroscopy</technique>
     <technique>Radio frequency muSR</technique>
-    <livedata address="NDXEMU:6789" />
+    <livedata>
+      <connection name="histo" address="NDXEMU:6789" listener="ISISHistoDataListener" />
+    </livedata>
   </instrument>
 
   <instrument name="ARGUS">
@@ -268,20 +345,23 @@
     <zeropadding size="8" startRunNumber="57942"/>
     <technique>Muon spectroscopy</technique>
     <technique>Radio frequency muSR</technique>
-    <livedata address="NDXARGUS:6789" />
+    <livedata>
+      <connection name="histo" address="NDXARGUS:6789" listener="ISISHistoDataListener" />
+    </livedata>
   </instrument>
 
   <instrument name="CHRONUS">
     <zeropadding size="8"/>
     <technique>Muon spectroscopy</technique>
     <technique>Radio frequency muSR</technique>
-    <livedata address="NDXCHRONUS:6789" />
+    <livedata>
+      <connection name="histo" address="NDXCHRONUS:6789" listener="ISISHistoDataListener" />
+    </livedata>
   </instrument>
 
-  <livedata listener="ISISHistoDataListener"/>
-
 </facility>
 
+
 <facility name="HFIR" FileExtensions=".nxs,.dat,.xml">
 
    <instrument name="HB1">
@@ -316,7 +396,6 @@
       <technique>technique</technique>
    </instrument>
 
-
    <instrument name="GPSANS">
       <technique>Small Angle Scattering</technique>
    </instrument>
@@ -335,6 +414,7 @@
 
 </facility>
 
+
 <facility name="SNS" delimiter="_" FileExtensions=".nxs.h5,_event.nxs,.nxs,.dat,_runinfo.xml,_histo.nxs">
 
    <archive>
@@ -362,13 +442,17 @@
 
    <instrument name="USANS" shortname="USANS" beamline="1A">
       <technique>Small Angle Scattering</technique>
-      <livedata address="bl1a-daq1.sns.gov:31415" />
+      <livedata>
+      <connection name="event" address="bl1a-daq1.sns.gov:31415" listener="SNSLiveEventDataListener" />
+    </livedata>
    </instrument>
 
    <instrument name="NOMAD" shortname="NOM" beamline="1B">
    	<technique>Neutron Diffraction</technique>
    	<technique>Neutron Amorphous</technique>
-        <livedata address="bl1b-daq1.sns.gov:31415" />
+        <livedata>
+      <connection name="event" address="bl1b-daq1.sns.gov:31415" listener="SNSLiveEventDataListener" />
+    </livedata>
    </instrument>
 
    <instrument name="BASIS" shortname="BSS" beamline="2">
@@ -387,7 +471,9 @@
 
    <instrument name="REF_L" beamline="4B">
       <technique>Reflectometry</technique>
-      <livedata address="bl4b-daq1.sns.gov:31415" />
+      <livedata>
+      <connection name="event" address="bl4b-daq1.sns.gov:31415" listener="SNSLiveEventDataListener" />
+    </livedata>
    </instrument>
 
    <instrument name="CNCS" beamline="5">
@@ -407,12 +493,16 @@
    <instrument name="CORELLI" beamline="9">
 	<technique>Neutron Diffraction</technique>
 	<technique>Diffuse Scattering</technique>
-	<livedata address="bl9-daq1.sns.gov:31415" />
+	<livedata>
+      <connection name="event" address="bl9-daq1.sns.gov:31415" listener="SNSLiveEventDataListener" />
+    </livedata>
    </instrument>
 
    <instrument name="POWGEN" shortname="PG3" beamline="11A">
 	<technique>Neutron Diffraction</technique>
-        <livedata address="bl11a-daq1.sns.gov:31415" />
+        <livedata>
+      <connection name="event" address="bl11a-daq1.sns.gov:31415" listener="SNSLiveEventDataListener" />
+    </livedata>
    </instrument>
 
    <instrument name="MANDI" beamline="11B">
@@ -424,28 +514,36 @@
    <instrument name="TOPAZ" beamline="12">
 	<technique>Neutron Diffraction</technique>
     <technique>Single Crystal Diffraction</technique>
-    <livedata listener="TOPAZLiveEventDataListener" address="128.219.164.132:9000" />
+    <livedata>
+      <connection name="event" address="128.219.164.132:9000" listener="TOPAZLiveEventDataListener" />
+    </livedata>
     <!-- Act like we're ISawEV talking to event_catcher -->
    </instrument>
 
   <instrument name="HYSPEC" shortname="HYS" beamline="14B">
     <technique>Neutron Spectroscopy</technique>
     <technique>TOF Direct Geometry Spectroscopy</technique>
-    <livedata address="bl14b-daq1.sns.gov:31415" />
+    <livedata>
+      <connection name="event" address="bl14b-daq1.sns.gov:31415" listener="SNSLiveEventDataListener" />
+    </livedata>
   </instrument>
 
   <instrument name="VISION" shortname="VIS" beamline="16B">
     <technique>Neutron Spectroscopy</technique>
     <technique>TOF Indirect Geometry Spectroscopy</technique>
     <technique>Neutron Diffraction</technique>
-    <livedata address="bl16b-daq1.sns.gov:31415" />
+    <livedata>
+      <connection name="event" address="bl16b-daq1.sns.gov:31415" listener="SNSLiveEventDataListener" />
+    </livedata>
   </instrument>
 
    <instrument name="SEQUOIA" shortname="SEQ" beamline="17">
     <technique>Neutron Spectroscopy</technique>
     <technique>TOF Direct Geometry Spectroscopy</technique>
     <technique>Neutron Diffraction</technique>
-    <livedata address="bl17-daq1.sns.gov:31415" />
+    <livedata>
+      <connection name="event" address="bl17-daq1.sns.gov:31415" listener="SNSLiveEventDataListener" />
+    </livedata>
    </instrument>
 
    <instrument name="ARCS" beamline="18">
@@ -463,8 +561,6 @@
       <technique>Small Wide Angle Scattering</technique>
    </instrument>
 
-   <livedata listener="SNSLiveEventDataListener"/>
-
 </facility>
 
 <facility name="NCNR" FileExtensions=".dat,.xml">
@@ -659,22 +755,30 @@
 <facility name="TEST_LIVE" FileExtensions=".nxs,.raw">
   <instrument name="ISIS_Histogram">
     <technique>Test Listener</technique>
-    <livedata address="localhost:56789" listener="ISISHistoDataListener"/>
+    <livedata>
+      <connection name="histo" address="localhost:56789" listener="ISISHistoDataListener" />
+    </livedata>
   </instrument>
 
   <instrument name="ISIS_Event">
     <technique>Test Listener</technique>
-    <livedata address="localhost:59876" listener="ISISLiveEventDataListener" />
+    <livedata>
+      <connection name="event" address="localhost:59876" listener="ISISLiveEventDataListener" />
+    </livedata>
   </instrument>
 
   <instrument name="ADARA_FileReader">
     <technique>Test Listener</technique>
-    <livedata listener="FileEventDataListener" address="127.0.0.1:0" />
+    <livedata>
+      <connection name="file" address="127.0.0.1:0" listener="FileEventDataListener" />
+    </livedata>
   </instrument>
 
   <instrument name="ADARA_FakeEvent">
     <technique>Test Listener</technique>
-    <livedata listener="FakeEventDataListener" address="127.0.0.1:0" />
+    <livedata>
+      <connection name="fake" address="127.0.0.1:0" listener="FakeEventDataListener" />
+    </livedata>
   </instrument>
 
 </facility>
diff --git a/instrument/Grouping/IN16B_Grouping.xml b/instrument/Grouping/IN16B_Grouping.xml
index 728a27a4e27f9d6c2ec2e1e41b5a8034c52c7bc3..eb25f55c184cd10d2220cf9bd6f9252a3ee50789 100644
--- a/instrument/Grouping/IN16B_Grouping.xml
+++ b/instrument/Grouping/IN16B_Grouping.xml
@@ -16,13 +16,16 @@
   <group name="psd14"> <ids val="1666-1793"/> </group> 
   <group name="psd15"> <ids val="1794-1921"/> </group> 
   <group name="psd16"> <ids val="1922-2049"/> </group> 
- 
-  <group name="tube1"><detids val="2049"/></group> 
-  <group name="tube2"><detids val="2050"/> </group> 
-  <group name="tube3"><detids val="2051"/></group> 
-  <group name="tube4"><detids val="2052"/> </group> 
-  <group name="tube5"><detids val="2053"/></group> 
-  <group name="tube6"><detids val="2054"/> </group> 
-  <group name="tube7"><detids val="2055"/></group> 
-  <group name="tube8"><detids val="2056"/> </group> 
+
+  <group name="tube1"> <ids val="2050"/> </group>
+  <group name="tube2"> <ids val="2051"/> </group>
+
+  <!-- There are 2 SD active, though 8 slots available
+  <group name="tube3"><ids val="2052"/></group>
+  <group name="tube4"><ids val="2053"/> </group>
+  <group name="tube5"><ids val="2054"/></group>
+  <group name="tube6"><ids val="2055"/> </group>
+  <group name="tube7"><ids val="2056"/></group>
+  <group name="tube8"><ids val="2057"/> </group>
+  -->
 </detector-grouping>
diff --git a/instrument/HB3A_Definition.xml b/instrument/HB3A_Definition.xml
index 35f73f3af74250df6bcd1b1a910b9a176887a5a7..3cd97a7ca82d4e53e2d4015b721a63efdc94c562 100644
--- a/instrument/HB3A_Definition.xml
+++ b/instrument/HB3A_Definition.xml
@@ -12,7 +12,7 @@
   </component>
   <type is="SamplePos" name="sample-position"/>
   <!--PANEL-->
-  <component idfillbyfirst="x" idstart="1" idstepbyrow="256" type="panel">
+  <component idfillbyfirst="x" idstart="1" idstepbyrow="256" type="arm">
     <location name="bank1">
       <parameter name="r-position">
 	      <logfile eq="1.0*value+0.3750" id="diffr"/>
@@ -28,13 +28,19 @@
       </parameter>
     </location>
   </component>
+  <type name="arm">
+	  <component type="panel">
+		  <location>
+			  <parameter name="x">
+				  <logfile eq='value' id='deltax'/>
+			  </parameter>
+			  <parameter name="y">
+				  <logfile eq='value' id='deltay'/>
+			  </parameter>
+		  </location>
+	  </component>
+  </type>
   <type is="rectangular_detector" name="panel" type="pixel" xpixels="256" xstart="0.0252015625" xstep="-0.0001984375" ypixels="256" ystart="-0.022621875" ystep="0.0001984375">
-	  <parameter name="xstart">
-		  <value val="0.02530078125"/>
-	  </parameter>
-	  <parameter name="ystart">
-		  <value val="-0.02530078125"/>
-	  </parameter>
  </type>
   <type is="detector" name="pixel">
     <cuboid id="pixel-shape">
diff --git a/instrument/IDFs_for_UNIT_TESTING/UnitTestFacilities.xml b/instrument/IDFs_for_UNIT_TESTING/UnitTestFacilities.xml
index b87e614b3dbfb46f128ac9deecf2ff83c457f97c..06f3978d8137a40de44419a05e53018cc6d43386 100644
--- a/instrument/IDFs_for_UNIT_TESTING/UnitTestFacilities.xml
+++ b/instrument/IDFs_for_UNIT_TESTING/UnitTestFacilities.xml
@@ -3,28 +3,34 @@
 
 <facility name="TEST" FileExtensions=".nxs,.dat,.xml">
 
-   <livedata listener="MockILiveListener"/>
-
-   <instrument name="MINITOPAZ"> 
-      <technique>Test Neutron Diffraction</technique>
-      <livedata address="127.0.0.1:0" />
-   </instrument>
+  <instrument name="MINITOPAZ">
+    <technique>Test Neutron Diffraction</technique>
+    <livedata>
+      <connection name="default" address="127.0.0.1:0" listener="MockILiveListener" />
+    </livedata>
+  </instrument>
 
   <instrument name="TESTHISTOLISTENER"> 
     <zeropadding size="8"/>
     <zeropadding size="11" startRunNumber="300" prefix="TST"/>
     <technique>Test ISISHistoDataListener</technique>
-    <livedata listener="ISISHistoDataListener" address="127.0.0.1:56789" />
+    <livedata>
+      <connection name="default" listener="ISISHistoDataListener" address="127.0.0.1:56789" />
+    </livedata>
   </instrument>
 
   <instrument name="TestDataListener">
     <technique>Test Listener</technique>
-    <livedata listener="TestDataListener" address="127.0.0.1:0" />
+    <livedata>
+      <connection name="default" listener="TestDataListener" address="127.0.0.1:0" />
+    </livedata>
   </instrument>
 
   <instrument name="FakeEventDataListener">
     <technique>Test Listener</technique>
-    <livedata listener="FakeEventDataListener" address="127.0.0.1:0" />
+    <livedata>
+      <connection name="default" listener="FakeEventDataListener" address="127.0.0.1:0" />
+    </livedata>
   </instrument>
 
 </facility>
diff --git a/instrument/IN16B_Definition.xml b/instrument/IN16B_Definition.xml
index 63125cc9da8fd3784c0623c96e23e754226b86fe..f61501c624e382edcadca4ac5bf527b647ec9e80 100644
--- a/instrument/IN16B_Definition.xml
+++ b/instrument/IN16B_Definition.xml
@@ -243,6 +243,7 @@
 
   <type name="bank_single_detectors">
     <component type="single_tube">
+      <!-- Note, that thetas of single detectors will be read from nexus files and moved correspondingly -->
       <location r="4.100000" t="10.000000" p="0.0" rot="100.000000" axis-x="0.0" axis-y="1.0" axis-z="0.0" name="single_tube_1" />
       <location r="4.100000" t="25.714286" p="0.0" rot="115.714286" axis-x="0.0" axis-y="1.0" axis-z="0.0" name="single_tube_2" />
       <location r="4.100000" t="41.428571" p="0.0" rot="131.428571" axis-x="0.0" axis-y="1.0" axis-z="0.0" name="single_tube_3" />
@@ -251,12 +252,13 @@
       <location r="4.100000" t="88.571429" p="0.0" rot="178.571429" axis-x="0.0" axis-y="1.0" axis-z="0.0" name="single_tube_6" />
       <location r="4.100000" t="104.285714" p="0.0" rot="194.285714" axis-x="0.0" axis-y="1.0" axis-z="0.0" name="single_tube_7" />
       <location r="4.100000" t="120.000000" p="0.0" rot="210.000000" axis-x="0.0" axis-y="1.0" axis-z="0.0" name="single_tube_8" />
+
     </component>
   </type>
 
   <!-- Definition of single_tube -->
 
-  <type name="single_tube" outline="yes">
+  <type name="single_tube">
     <component type="single_pixel">
       <location />
     </component>
diff --git a/instrument/IN16B_Parameters.xml b/instrument/IN16B_Parameters.xml
index 1631449e9e1f68e1c55258e7cac12e773c1a01ba..83f7b6390cfc4fb01cdcd0c5fb635d2b837ad40a 100644
--- a/instrument/IN16B_Parameters.xml
+++ b/instrument/IN16B_Parameters.xml
@@ -15,6 +15,23 @@
   <value val="111,311" />
 </parameter>
 
+<!-- Sample log merging behaviour -->
+<parameter name="sample_logs_time_series" type="string">
+    <value val="sample.temperature, sample.pressure" />
+</parameter>
+<parameter name="sample_logs_list" type="string">
+    <value val="run_number" />
+</parameter>
+<parameter name="sample_logs_warn" type="string">
+</parameter>
+<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" />
+</parameter>
+<parameter name="sample_logs_fail_tolerances" type="string">
+    <value val="0, 0, 0, 0.001" />
+</parameter>
 
 <!-- Reduction workflow parameters under this line -->
 <parameter name="Workflow.beam-width" type="string">
@@ -25,6 +42,7 @@
 </parameter>
 <parameter name="Workflow.GroupingFile" type="string">
   <value val="IN16B_Grouping.xml" />
+  <!-- Note that equivalent IN16B_map.map file also exists. -->
 </parameter>
 </component-link>
 
diff --git a/instrument/IN16B_silicon_111_Parameters.xml b/instrument/IN16B_silicon_111_Parameters.xml
index 37b46e0a80caccd3e41785f20fa23a2313fd4786..0ac480ce03084dd64d0526023d325ea22946fdc8 100644
--- a/instrument/IN16B_silicon_111_Parameters.xml
+++ b/instrument/IN16B_silicon_111_Parameters.xml
@@ -20,7 +20,7 @@
     </parameter>
 
     <parameter name="resolution">
-      <value val="0.0003" />
+      <value val="0.00075" />
     </parameter>
 
   </component-link>
diff --git a/instrument/IN16B_silicon_311_Parameters.xml b/instrument/IN16B_silicon_311_Parameters.xml
new file mode 100644
index 0000000000000000000000000000000000000000..a743671c44ba460a25eaca026dee047be84fa065
--- /dev/null
+++ b/instrument/IN16B_silicon_311_Parameters.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<parameter-file instrument = "IN16B" valid-from = "2014-05-06T00:00:00">
+
+  <component-link name = "IN16B">
+
+    <parameter name="analysis-type" type="string">
+      <value val="spectroscopy" />
+    </parameter>
+
+    <parameter name="analyser" type="string">
+      <value val="silicon" />
+    </parameter>
+
+    <parameter name="reflection" type="string">
+      <value val="111" />
+    </parameter>
+
+    <parameter name="Efixed">
+      <value val="7.63" />
+    </parameter>
+
+    <parameter name="resolution">
+      <value val="0.002" />
+    </parameter>
+
+  </component-link>
+
+</parameter-file>
diff --git a/instrument/Schema/Facilities/1.0/FacilitiesSchema.xsd b/instrument/Schema/Facilities/1.0/FacilitiesSchema.xsd
index 2035427f3e05888d6e1eab8b74e581d2926973d6..c6cbde1cdeb9e8a6077b976d396d1d6d013ebd9c 100644
--- a/instrument/Schema/Facilities/1.0/FacilitiesSchema.xsd
+++ b/instrument/Schema/Facilities/1.0/FacilitiesSchema.xsd
@@ -82,8 +82,14 @@
                     <xs:element name="technique" maxOccurs="unbounded" type="xs:string"/>
                     <xs:element name="livedata">
                       <xs:complexType>
-                        <xs:attribute name ="address" type="xs:string" use="required"/>
-                        <xs:attribute name="listener" type="xs:string" use="optional"/>
+                        <xs:attribute name="default" type="xs:string" use="optional"/>
+                        <xs:element name="connection" minOccurs="1" maxOccurs="unbounded">
+                          <xs:complexType>
+                            <xs:attribute name="name" type="xs:string" use="required"/>
+                            <xs:attribute name="address" type="xs:string" use="required"/>
+                            <xs:attribute name="listener" type="xs:string" use="required"/>
+                          </xs:complexType>
+                        </xs:element>
                       </xs:complexType>
                     </xs:element>
                   </xs:choice>
@@ -92,11 +98,6 @@
                   <xs:attribute name="beamline" type="xs:string" use="optional"/>
                 </xs:complexType>
               </xs:element>
-              <xs:element name="livedata" minOccurs="0">
-                <xs:complexType>
-                  <xs:attribute name="listener" type="xs:string" use="required"/>
-                </xs:complexType>
-              </xs:element>
             </xs:choice>
             <xs:attribute name="name"/>
             <xs:attribute name="zeropadding"/>
diff --git a/instrument/TOSCA_Definition.xml b/instrument/TOSCA_Definition.xml
index a964103d6273f4964d7c1ee01d7d66def6a29c94..8806b3c20fd554231fc443c773470bfee4a65149 100644
--- a/instrument/TOSCA_Definition.xml
+++ b/instrument/TOSCA_Definition.xml
@@ -6,7 +6,7 @@
             xsi:schemaLocation="http://www.mantidproject.org/IDF/1.0 http://schema.mantidproject.org/IDF/1.0/IDFSchema.xsd"
             name="TOSCA"
             valid-from="2006-08-10 23:59:59"
-            valid-to="2100-01-31 23:59:59"
+            valid-to="2016-11-25 23:59:59"
             last-modified="2011-03-21 00:00:00" >
 
   <defaults>
diff --git a/instrument/TOSCA_Definition_2016.xml b/instrument/TOSCA_Definition_2016.xml
new file mode 100644
index 0000000000000000000000000000000000000000..3a884a3522ca215ad2c0c5a772a7c07533a42e6c
--- /dev/null
+++ b/instrument/TOSCA_Definition_2016.xml
@@ -0,0 +1,715 @@
+<?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="TOSCA"
+            valid-from="2016-11-25 23:59:59"
+            valid-to="2100-01-31 23:59:59"
+            last-modified="2011-03-21 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>
+  </defaults>
+
+  <!--  SOURCE AND SAMPLE POSITION -->
+
+  <component type="moderator">
+    <location z="-17.01" />
+  </component>
+
+  <type name="moderator" is="Source">
+  </type>
+
+  <component type="sample-position">
+    <location />
+  </component>
+
+  <type name="sample-position" 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.02"  />
+      <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>
+
+  <!-- MONITORS -->
+  <component type="monitor1" idlist="monitor1">
+    <location z="-1.1385" />
+  </component>
+
+  <type name="monitor1" is="monitor">
+    <cuboid id="shape">
+      <left-front-bottom-point x="0.0025" y="-0.1" z="0.0"  />
+      <left-front-top-point  x="0.0025" y="-0.1" z="0.02"  />
+      <left-back-bottom-point  x="-0.0025" y="-0.1" z="0.0"  />
+      <right-front-bottom-point  x="0.0025" y="0.1" z="0.0"  />
+    </cuboid>
+  </type>
+
+  <!-- DETECTORS -->
+
+  <component type="back" idlist="back">  
+    <location />
+  </component>
+
+  <component type="front" idlist="front">  
+    <location />
+  </component>
+
+  <component type="diffraction" idlist="diffraction">
+    <location />
+  </component>
+
+  <type name="back">
+    <component type="tube" > 
+      <location r="0.56370" t="140.8250595" p="150.0" rot="60.0" name="Detector #1" /> 
+      <parameter name="Efixed"> <value val="2.690280" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.57275" t="139.7268737" p="150.0" rot="60.0" name="Detector #2" /> 
+      <parameter name="Efixed"> <value val="2.771000" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.58139" t="138.7320442" p="150.0" rot="60.0" name="Detector #3" /> 
+      <parameter name="Efixed"> <value val="2.855410" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.58909" t="137.8857039" p="150.0" rot="60.0" name="Detector #4" /> 
+      <parameter name="Efixed"> <value val="2.943700"/> </parameter> 
+    </component> 
+    <component type="tube" > 
+      <location r="0.59795" t="136.9549250" p="150.0" rot="60.0" name="Detector #5" /> 
+      <parameter name="Efixed"> <value val="3.036910" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.60815" t="135.9356820" p="150.0" rot="60.0" name="Detector #6" /> 
+      <parameter name="Efixed"> <value val="3.134920" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.61800" t="135.0000000" p="150.0" rot="60.0" name="Detector #7" /> 
+      <parameter name="Efixed"> <value val="3.238630" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.62553" t="134.3143712" p="150.0" rot="60.0" name="Detector #8" /> 
+      <parameter name="Efixed"> <value val="3.345900" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.63820" t="133.2140449" p="150.0" rot="60.0" name="Detector #9" /> 
+      <parameter name="Efixed"> <value val="3.461600" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.64925" t="132.3046077" p="150.0" rot="60.0" name="Detector #10" /> 
+      <parameter name="Efixed"> <value val="3.582930" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.66204" t="131.3051250" p="150.0" rot="60.0" name="Detector #11" /> 
+      <parameter name="Efixed"> <value val="3.711220" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.67394" t="130.4221151" p="150.0" rot="60.0" name="Detector #12" /> 
+      <parameter name="Efixed"> <value val="3.846910" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.68674" t="129.5185603" p="150.0" rot="60.0" name="Detector #13" /> 
+      <parameter name="Efixed"> <value val="3.990450" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.70000" t="128.6289408" p="150.0" rot="60.0" name="Detector #14" /> 
+      <parameter name="Efixed"> <value val="4.000000" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.56697" t="140.4212644" p="210.0" rot="120.0" name="Detector #15" /> 
+      <parameter name="Efixed"> <value val="2.711400" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.57273" t="139.7292352" p="210.0" rot="120.0" name="Detector #16" /> 
+      <parameter name="Efixed"> <value val="2.791200" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.58159" t="138.7095962" p="210.0" rot="120.0" name="Detector #17" /> 
+      <parameter name="Efixed"> <value val="2.876300" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.59101" t="137.6802142" p="210.0" rot="120.0" name="Detector #18" /> 
+      <parameter name="Efixed"> <value val="2.967800" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.60202" t="136.5417863" p="210.0" rot="120.0" name="Detector #19" /> 
+      <parameter name="Efixed"> <value val="3.065600" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.61305" t="135.4645161" p="210.0" rot="120.0" name="Detector #20" /> 
+      <parameter name="Efixed"> <value val="3.169800" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.62244" t="134.5927407" p="210.0" rot="120.0" name="Detector #21" /> 
+      <parameter name="Efixed"> <value val="3.280600" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.63452" t="133.5270497" p="210.0" rot="120.0" name="Detector #22" /> 
+      <parameter name="Efixed"> <value val="3.400100" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.64940" t="132.2925646" p="210.0" rot="120.0" name="Detector #23" /> 
+      <parameter name="Efixed"> <value val="3.528800" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.66191" t="131.3150135" p="210.0" rot="120.0" name="Detector #24" /> 
+      <parameter name="Efixed"> <value val="3.666600" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.67482" t="130.3585065" p="210.0" rot="120.0" name="Detector #25" /> 
+      <parameter name="Efixed"> <value val="3.813200" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.68980" t="129.3092171" p="210.0" rot="120.0" name="Detector #26" /> 
+      <parameter name="Efixed"> <value val="3.973100" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.70642" t="128.2140307" p="210.0" rot="120.0" name="Detector #27" /> 
+      <parameter name="Efixed"> <value val="4.146300" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.70000" t="128.6289408" p="210.0" rot="120.0" name="Detector #28" /> 
+      <parameter name="Efixed"> <value val="4.000000" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.56940" t="140.1263856" p="270.0" rot="180.0" name="Detector #29" /> 
+      <parameter name="Efixed"> <value val="2.709560" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.57486" t="139.4792890" p="270.0" rot="180.0" name="Detector #30" /> 
+      <parameter name="Efixed"> <value val="2.789910" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.58484" t="138.3483445" p="270.0" rot="180.0" name="Detector #31" /> 
+      <parameter name="Efixed"> <value val="2.878350" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.59564" t="137.1933654" p="270.0" rot="180.0" name="Detector #32" /> 
+      <parameter name="Efixed"> <value val="2.973660" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.60434" t="136.3101592" p="270.0" rot="180.0" name="Detector #33" /> 
+      <parameter name="Efixed"> <value val="3.075680" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.61560" t="135.2238131" p="270.0" rot="180.0" name="Detector #34" /> 
+      <parameter name="Efixed"> <value val="3.187090" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.62627" t="134.2483089" p="270.0" rot="180.0" name="Detector #35" /> 
+      <parameter name="Efixed"> <value val="3.307450" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.64092" t="132.9860183" p="270.0" rot="180.0" name="Detector #36" /> 
+      <parameter name="Efixed"> <value val="3.438560" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.65612" t="131.7609698" p="270.0" rot="180.0" name="Detector #37" /> 
+      <parameter name="Efixed"> <value val="3.581780" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.67119" t="130.6223597" p="270.0" rot="180.0" name="Detector #38" /> 
+      <parameter name="Efixed"> <value val="3.737090" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.68877" t="129.3794046" p="270.0" rot="180.0" name="Detector #39" /> 
+      <parameter name="Efixed"> <value val="3.906990" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.70746" t="128.1477470" p="270.0" rot="180.0" name="Detector #40" /> 
+      <parameter name="Efixed"> <value val="4.093350" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.72661" t="126.9710935" p="270.0" rot="180.0" name="Detector #41" /> 
+      <parameter name="Efixed"> <value val="4.297320" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.70000" t="128.6289408" p="270.0" rot="180.0" name="Detector #42" /> 
+      <parameter name="Efixed"> <value val="4.000000" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.56746" t="140.3614522" p="330.0" rot="240.0" name="Detector #43" /> 
+      <parameter name="Efixed"> <value val="2.695290" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.57458" t="139.5119672" p="330.0" rot="240.0" name="Detector #44" /> 
+      <parameter name="Efixed"> <value val="2.773110" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.58325" t="138.5242550" p="330.0" rot="240.0" name="Detector #45" /> 
+      <parameter name="Efixed"> <value val="2.857010" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.58955" t="137.8362758" p="330.0" rot="240.0" name="Detector #46" /> 
+      <parameter name="Efixed"> <value val="2.946360" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.60136" t="136.6081885" p="330.0" rot="240.0" name="Detector #47" /> 
+      <parameter name="Efixed"> <value val="3.044560" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.61266" t="135.5015972" p="330.0" rot="240.0" name="Detector #48" /> 
+      <parameter name="Efixed"> <value val="3.149860" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.62338" t="134.5076258" p="330.0" rot="240.0" name="Detector #49" /> 
+      <parameter name="Efixed"> <value val="3.263620" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.63521" t="133.4679613" p="330.0" rot="240.0" name="Detector #50" /> 
+      <parameter name="Efixed"> <value val="3.386460" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.65000" t="132.2444707" p="330.0" rot="240.0" name="Detector #51" /> 
+      <parameter name="Efixed"> <value val="3.520580" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.66507" t="131.0761606" p="330.0" rot="240.0" name="Detector #52" /> 
+      <parameter name="Efixed"> <value val="3.665070" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.67977" t="130.0048698" p="330.0" rot="240.0" name="Detector #53" /> 
+      <parameter name="Efixed"> <value val="3.823790" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.69574" t="128.9098389" p="330.0" rot="240.0" name="Detector #54" /> 
+      <parameter name="Efixed"> <value val="3.995720" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.71370" t="127.7553324" p="330.0" rot="240.0" name="Detector #55" /> 
+      <parameter name="Efixed"> <value val="4.183510" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.70000" t="128.6289408" p="330.0" rot="240.0" name="Detector #56" /> 
+      <parameter name="Efixed"> <value val="4.000000" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.56356" t="140.8425303" p="390.0" rot="300.0" name="Detector #57" /> 
+      <parameter name="Efixed"> <value val="2.691220" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.57218" t="139.7942880" p="390.0" rot="300.0" name="Detector #58" /> 
+      <parameter name="Efixed"> <value val="2.770220" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.58014" t="138.8729233" p="390.0" rot="300.0" name="Detector #59" /> 
+      <parameter name="Efixed"> <value val="2.853400" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.58958" t="137.8330566" p="390.0" rot="300.0" name="Detector #60" /> 
+      <parameter name="Efixed"> <value val="2.942070" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.60177" t="136.5669120" p="390.0" rot="300.0" name="Detector #61" /> 
+      <parameter name="Efixed"> <value val="3.036440" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.60821" t="135.9298424" p="390.0" rot="300.0" name="Detector #62" /> 
+      <parameter name="Efixed"> <value val="3.135540" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.61705" t="135.0882797" p="390.0" rot="300.0" name="Detector #63" /> 
+      <parameter name="Efixed"> <value val="3.240510" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.62989" t="133.9284248" p="390.0" rot="300.0" name="Detector #64" /> 
+      <parameter name="Efixed"> <value val="3.354510" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.64195" t="132.9003934" p="390.0" rot="300.0" name="Detector #65" /> 
+      <parameter name="Efixed"> <value val="3.474760" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.65498" t="131.8500731" p="390.0" rot="300.0" name="Detector #66" /> 
+      <parameter name="Efixed"> <value val="3.603410" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.66910" t="130.7760529" p="390.0" rot="300.0" name="Detector #67" /> 
+      <parameter name="Efixed"> <value val="3.740930" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.68430" t="129.6872876" p="390.0" rot="300.0" name="Detector #68" /> 
+      <parameter name="Efixed"> <value val="3.888930" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.69355" t="129.0560258" p="390.0" rot="300.0" name="Detector #69" /> 
+      <parameter name="Efixed"> <value val="4.043890" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.70000" t="128.6289408" p="390.0" rot="300.0" name="Detector #70" /> 
+      <parameter name="Efixed"> <value val="4.000000" /> </parameter>
+    </component> 
+  </type>
+
+  <type name="front">
+    <component type="tube" > 
+      <location r="0.56287" t="39.0711405" p="150.0" rot="60.0" name="Detector #71" /> 
+      <parameter name="Efixed"> <value val="2.690050" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.57191" t="40.1736992" p="150.0" rot="60.0" name="Detector #72" /> 
+      <parameter name="Efixed"> <value val="2.766250" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.57991" t="41.1010455" p="150.0" rot="60.0" name="Detector #73" /> 
+      <parameter name="Efixed"> <value val="2.860390" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.58735" t="41.9261975" p="150.0" rot="60.0" name="Detector #74" /> 
+      <parameter name="Efixed"> <value val="2.952490" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.60016" t="43.2704960" p="150.0" rot="60.0" name="Detector #75" /> 
+      <parameter name="Efixed"> <value val="3.052270" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.60978" t="44.2223360" p="150.0" rot="60.0" name="Detector #76" /> 
+      <parameter name="Efixed"> <value val="3.156690" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.62000" t="45.1845283" p="150.0" rot="60.0" name="Detector #77" /> 
+      <parameter name="Efixed"> <value val="3.267580" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.63028" t="46.1057165" p="150.0" rot="60.0" name="Detector #78" /> 
+      <parameter name="Efixed"> <value val="3.385450" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.64397" t="47.2663943" p="150.0" rot="60.0" name="Detector #79" /> 
+      <parameter name="Efixed"> <value val="3.512280" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.65787" t="48.3749721" p="150.0" rot="60.0" name="Detector #80" /> 
+      <parameter name="Efixed"> <value val="3.648180" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.67388" t="49.5735398" p="150.0" rot="60.0" name="Detector #81" /> 
+      <parameter name="Efixed"> <value val="3.792910" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.68722" t="50.5144429" p="150.0" rot="60.0" name="Detector #82" /> 
+      <parameter name="Efixed"> <value val="3.947030" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.70304" t="51.5687694" p="150.0" rot="60.0" name="Detector #83" /> 
+      <parameter name="Efixed"> <value val="4.112830" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.70000" t="51.3710592" p="150.0" rot="60.0" name="Detector #84" /> 
+      <parameter name="Efixed"> <value val="4.000000" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.56463" t="39.2906118" p="210.0" rot="120.0" name="Detector #85" /> 
+      <parameter name="Efixed"> <value val="2.711270" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.57336" t="40.3450198" p="210.0" rot="120.0" name="Detector #86" /> 
+      <parameter name="Efixed"> <value val="2.790290" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.58214" t="41.3520046" p="210.0" rot="120.0" name="Detector #87" /> 
+      <parameter name="Efixed"> <value val="2.875850" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.59107" t="42.3261729" p="210.0" rot="120.0" name="Detector #88" /> 
+      <parameter name="Efixed"> <value val="2.968390" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.60258" t="43.5143774" p="210.0" rot="120.0" name="Detector #89" /> 
+      <parameter name="Efixed"> <value val="3.069580" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.61444" t="44.6670652" p="210.0" rot="120.0" name="Detector #90" /> 
+      <parameter name="Efixed"> <value val="3.179160" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.62424" t="45.5699125" p="210.0" rot="120.0" name="Detector #91" /> 
+      <parameter name="Efixed"> <value val="3.297780" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.63950" t="46.8952864" p="210.0" rot="120.0" name="Detector #92" /> 
+      <parameter name="Efixed"> <value val="3.428740" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.65562" t="48.2000032" p="210.0" rot="120.0" name="Detector #93" /> 
+      <parameter name="Efixed"> <value val="3.571460" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.66889" t="49.2084315" p="210.0" rot="120.0" name="Detector #94" /> 
+      <parameter name="Efixed"> <value val="3.725890" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.68722" t="50.5144429" p="210.0" rot="120.0" name="Detector #95" /> 
+      <parameter name="Efixed"> <value val="3.897650" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.70749" t="51.8541613" p="210.0" rot="120.0" name="Detector #96" /> 
+      <parameter name="Efixed"> <value val="4.086060" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.72794" t="53.1076678" p="210.0" rot="120.0" name="Detector #97" /> 
+      <parameter name="Efixed"> <value val="4.293330" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.70000" t="51.3710592" p="210.0" rot="120.0" name="Detector #98" /> 
+      <parameter name="Efixed"> <value val="4.000000" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.56172" t="38.9264282" p="270.0" rot="180.0" name="Detector #99" /> 
+      <parameter name="Efixed"> <value val="2.710510" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.56879" t="39.7999991" p="270.0" rot="180.0" name="Detector #100" /> 
+      <parameter name="Efixed"> <value val="2.788980" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.57828" t="40.9155771" p="270.0" rot="180.0" name="Detector #101" /> 
+      <parameter name="Efixed"> <value val="2.874580" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.58386" t="41.5434180" p="270.0" rot="180.0" name="Detector #102" /> 
+      <parameter name="Efixed"> <value val="3.068150" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.59803" t="43.0532807" p="270.0" rot="180.0" name="Detector #103" /> 
+      <parameter name="Efixed"> <value val="3.068150" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.60932" t="44.1778730" p="270.0" rot="180.0" name="Detector #104" /> 
+      <parameter name="Efixed"> <value val="3.177850" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.62343" t="45.4968910" p="270.0" rot="180.0" name="Detector #105" /> 
+      <parameter name="Efixed"> <value val="3.297760" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.63560" t="46.5653543" p="270.0" rot="180.0" name="Detector #106" /> 
+      <parameter name="Efixed"> <value val="3.427800" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.65215" t="47.9268411" p="270.0" rot="180.0" name="Detector #107" /> 
+      <parameter name="Efixed"> <value val="3.571110" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.66709" t="49.0748892" p="270.0" rot="180.0" name="Detector #108" /> 
+      <parameter name="Efixed"> <value val="3.726370" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.68570" t="50.4097202" p="270.0" rot="180.0" name="Detector #109" /> 
+      <parameter name="Efixed"> <value val="3.897560" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.70653" t="51.7929921" p="270.0" rot="180.0" name="Detector #110" /> 
+      <parameter name="Efixed"> <value val="4.087070" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.72616" t="53.0021741" p="270.0" rot="180.0" name="Detector #111" /> 
+      <parameter name="Efixed"> <value val="4.294290" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.70000" t="51.3710592" p="270.0" rot="180.0" name="Detector #112" /> 
+      <parameter name="Efixed"> <value val="4.000000" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.56350" t="39.1499775" p="330.0" rot="240.0" name="Detector #113" /> 
+      <parameter name="Efixed"> <value val="2.713690" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.57377" t="40.3931962" p="330.0" rot="240.0" name="Detector #114" /> 
+      <parameter name="Efixed"> <value val="2.802390" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.58080" t="41.2015857" p="330.0" rot="240.0" name="Detector #115" /> 
+      <parameter name="Efixed"> <value val="2.893380" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.59264" t="42.4925653" p="330.0" rot="240.0" name="Detector #116" /> 
+      <parameter name="Efixed"> <value val="2.989900" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.60046" t="43.3008959" p="330.0" rot="240.0" name="Detector #117" /> 
+      <parameter name="Efixed"> <value val="3.088330" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.61251" t="44.4841217" p="330.0" rot="240.0" name="Detector #118" /> 
+      <parameter name="Efixed"> <value val="3.192660" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.62265" t="45.4263074" p="330.0" rot="240.0" name="Detector #119" /> 
+      <parameter name="Efixed"> <value val="3.299820" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.63144" t="46.2069009" p="330.0" rot="240.0" name="Detector #120" /> 
+      <parameter name="Efixed"> <value val="3.410560" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.64536" t="47.3802994" p="330.0" rot="240.0" name="Detector #121" /> 
+      <parameter name="Efixed"> <value val="3.528660" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.65448" t="48.1107094" p="330.0" rot="240.0" name="Detector #122" /> 
+      <parameter name="Efixed"> <value val="3.648260" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.66854" t="49.1825423" p="330.0" rot="240.0" name="Detector #123" /> 
+      <parameter name="Efixed"> <value val="3.775230" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.67979" t="49.9965449" p="330.0" rot="240.0" name="Detector #124" /> 
+      <parameter name="Efixed"> <value val="3.906190" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.69304" t="50.9097545" p="330.0" rot="240.0" name="Detector #125" /> 
+      <parameter name="Efixed"> <value val="4.042820" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.70000" t="51.3710592" p="330.0" rot="240.0" name="Detector #126" /> 
+      <parameter name="Efixed"> <value val="4.000000" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.56139" t="38.8847087" p="390.0" rot="300.0" name="Detector #127" /> 
+      <parameter name="Efixed"> <value val="2.688160" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.57304" t="40.3073375" p="390.0" rot="300.0" name="Detector #128" /> 
+      <parameter name="Efixed"> <value val="2.787040" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.58139" t="41.2679558" p="390.0" rot="300.0" name="Detector #129" /> 
+      <parameter name="Efixed"> <value val="2.864760" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.58820" t="42.0183094" p="390.0" rot="300.0" name="Detector #130" /> 
+      <parameter name="Efixed"> <value val="2.952710" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.60028" t="43.2826617" p="390.0" rot="300.0" name="Detector #131" /> 
+      <parameter name="Efixed"> <value val="3.048190" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.60831" t="44.0798864" p="390.0" rot="300.0" name="Detector #132" /> 
+      <parameter name="Efixed"> <value val="3.157880" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.62104" t="45.2797817" p="390.0" rot="300.0" name="Detector #133" /> 
+      <parameter name="Efixed"> <value val="3.268740" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.63551" t="46.5576713" p="390.0" rot="300.0" name="Detector #134" /> 
+      <parameter name="Efixed"> <value val="3.394370" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.64570" t="47.4080548" p="390.0" rot="300.0" name="Detector #135" /> 
+      <parameter name="Efixed"> <value val="3.524460" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.66097" t="48.6133244" p="390.0" rot="300.0" name="Detector #136" /> 
+      <parameter name="Efixed"> <value val="3.664730" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.67463" t="49.6277789" p="390.0" rot="300.0" name="Detector #137" /> 
+      <parameter name="Efixed"> <value val="3.811590" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.69126" t="50.7897939" p="390.0" rot="300.0" name="Detector #138" /> 
+      <parameter name="Efixed"> <value val="3.968720" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.70513" t="51.7033958" p="390.0" rot="300.0" name="Detector #139" /> 
+      <parameter name="Efixed"> <value val="4.134120" /> </parameter>
+    </component> 
+    <component type="tube" > 
+      <location r="0.70000" t="51.3710592" p="390.0" rot="300.0" name="Detector #140" /> 
+      <parameter name="Efixed"> <value val="4.000000" /> </parameter>
+    </component>
+  </type>
+
+  <type name="diffraction">
+    <!-- Detector ID 170 -->
+    <component type="tube" > 
+      <location r="0.1" t="49.6277789" p="30" rot="300.0" name="Diff #1" /> 
+    </component>
+    <!-- Detector ID 171 -->
+    <component type="tube" > 
+      <location r="0.12" t="50.7897939" p="30" rot="300.0" name="Diff #2" /> 
+    </component> 
+    <!-- Detector ID 172 -->
+    <component type="tube" > 
+      <location r="0.14" t="51.7033958" p="30" rot="300.0" name="Diff #3" /> 
+    </component> 
+    <!-- For some reason Detector ID 15 (FIFTEEN) is next (?) -->
+    <component type="tube" > 
+      <location r="0.16" t="51.3710592" p="30" rot="300.0" name="Diff #4" /> 
+    </component>
+    <!-- ... 177 --> <!-- (Spectra 146) -->
+    <component type="tube" > 
+      <location r="1.21" t="179" p="0" rot="0" name="Diff #5" /> 
+    </component> 
+    <!-- ... 178 -->
+    <component type="tube" > 
+      <location r="1.21" t="179" p="0" rot="0" name="Diff #6" /> 
+    </component>
+    <!-- ... 179 -->    
+    <component type="tube" > 
+      <location r="1.21" t="179" p="0" rot="0" name="Diff #7" /> 
+    </component>
+    <!-- ... 180 -->
+    <component type="tube" > 
+      <location r="1.21" t="179" p="0" rot="0" name="Diff #8" /> 
+    </component>
+  </type>
+
+  <type name="tube" is="detector">
+    <cylinder id="shape">
+      <centre-of-bottom-base x="-0.03" y="0.0" z="0.0" />
+      <axis x="1.0" y="0.0" z="0" />
+      <radius val="0.005" />
+      <height val="0.06" />
+    </cylinder>
+    <algebra val="shape" />
+  </type>  
+
+  <!-- DETECTOR ID LISTS -->
+
+  <idlist idname="back">
+    <id start="1" end="14" />
+    <id start="17" end="30" />
+    <id start="33" end="46" />
+    <id start="49" end="62" />
+    <id start="65" end="78" />
+  </idlist>
+
+  <idlist idname="front">
+    <id start="81" end="94" />
+    <id start="97" end="110" />
+    <id start="113" end="126" />
+    <id start="129" end="142" />	
+    <id start="145" end="158" />
+  </idlist>
+
+  <idlist idname="monitor1">
+    <id val="194" />
+  </idlist>
+
+  <idlist idname="diffraction">
+    <id start="170" end="173" />
+    <!-- Having this value as 15 causes problems in the ConvertToEnergy scripts
+    <id val="15" /> -->
+    <id start="177" end="180" />
+  </idlist>  
+
+</instrument>
diff --git a/instrument/TOSCA_Parameters.xml b/instrument/TOSCA_Parameters.xml
index ee9239c9b9b42b99dc68410150643bea1f69b72b..363ccd05c05bd3aef477dae983ac4ff87d97ce87 100644
--- a/instrument/TOSCA_Parameters.xml
+++ b/instrument/TOSCA_Parameters.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8" ?>
 <parameter-file instrument="TOSCA"
   valid-from="2000-03-31 15:20:00"
-  valid-to="2100-01-31 23:59:59" >
+  valid-to="2016-11-25 23:59:59" >
 
   <component-link name = "TOSCA">
 
diff --git a/instrument/TOSCA_Parameters_2016.xml b/instrument/TOSCA_Parameters_2016.xml
new file mode 100644
index 0000000000000000000000000000000000000000..a005d1d1b6fae53e4bc7b5672df2ca7abaf64701
--- /dev/null
+++ b/instrument/TOSCA_Parameters_2016.xml
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<parameter-file instrument="TOSCA"
+  valid-from="2016-11-25 23:59:59"
+  valid-to="2100-01-31 23:59:59" >
+
+  <component-link name = "TOSCA">
+
+    <parameter name="deltaE-mode" type="string">
+      <value val="indirect"/>
+    </parameter>
+
+    <!-- These properties are neceessary for use in the Indirect CTE interface. -->
+    <parameter name="analysers" type="string">
+      <value val="graphite,diffraction" />
+    </parameter>
+    <parameter name="refl-graphite" type="string">
+      <value val="002" />
+    </parameter>
+    <parameter name="refl-diffraction" type="string">
+      <value val="diffspec" />
+    </parameter>
+
+    <!-- Available options are "true" or "false". -->
+    <parameter name="cm-1-convert-choice" type="string">
+      <value val="true" />
+    </parameter>
+    <parameter name="save-nexus-choice" type="string">
+      <value val="false" />
+    </parameter>
+    <parameter name="save-ascii-choice" type="string">
+      <value val="true" />
+    </parameter>
+    <parameter name="fold-frames-choice" type="string">
+      <value val="true" />
+    </parameter>
+
+    <!-- This parameter will be taken as a default value for the rebinning of
+            the data in DeltaE. The existence of the parameter will make rebinning
+            the default, as opposed to not rebinning.
+            This is necessary so that the spectra can be grouped.
+    -->
+    <parameter name="rebin-default" type="string">
+      <value val="-2.5,0.015,3,-0.005,1000" />
+    </parameter>
+
+    <!-- Reduction workflow parameters under this line -->
+    <parameter name="Workflow.InfoTable" type="string">
+      <value val="inst_abrv, run_number, user_name, run_title, hd_dur" />
+    </parameter>
+
+    <!-- This is actually spectrum index, NOT spectrum number -->
+    <parameter name="Workflow.Monitor1-SpectrumNumber" >
+      <value val="141" />
+    </parameter>
+    <parameter name="Workflow.Monitor1-Area" >
+      <value val="5.391011e-5" />
+    </parameter>
+    <parameter name="Workflow.Monitor1-Thickness" >
+      <value val="0.013" />
+    </parameter>
+    <parameter name="Workflow.Monitor1-ScalingFactor">
+      <value val="1e9" />
+    </parameter>
+    <parameter name="Workflow.Monitor1-Attenuation" >
+      <value val="8.3" />
+    </parameter>
+
+    <parameter name="Workflow.UnwrapMonitor" type="string">
+      <value val="Never" />
+    </parameter>
+    <parameter name="Workflow.ChopDataIfGreaterThan">
+      <value val="40000" />
+    </parameter>
+    <parameter name="Workflow.GroupingMethod" type="string">
+      <value val="File" />
+    </parameter>
+    <parameter name="Workflow.GroupingFile" type="string">
+      <value val="TOSCA_Grouping.xml" />
+    </parameter>
+    <parameter name="Workflow.Masking" type="string">
+      <value val="IdentifyNoisyDetectors" />
+    </parameter>
+
+  </component-link>
+
+</parameter-file>
diff --git a/instrument/maps/IN16B_map.map b/instrument/maps/IN16B_map.map
new file mode 100644
index 0000000000000000000000000000000000000000..f9c1dc1e68d6edf0a94ddcaf50d4628e2abb705f
--- /dev/null
+++ b/instrument/maps/IN16B_map.map
@@ -0,0 +1,55 @@
+18
+0
+128
+2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 
+1
+128
+130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 
+2
+128
+258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 
+3
+128
+386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 
+4
+128
+514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 
+5
+128
+642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 
+6
+128
+770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 
+7
+128
+898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 
+8
+128
+1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 
+9
+128
+1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 
+10
+128
+1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 
+11
+128
+1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 
+12
+128
+1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 
+13
+128
+1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 
+14
+128
+1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 
+15
+128
+1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 
+16
+1
+2050
+17
+1
+2051
diff --git a/scripts/CMakeLists.txt b/scripts/CMakeLists.txt
index bd69f64d171f3a5574ea2477b53aa41870d9ff61..08739451aa9db276091c7e5864d2fdb85e7384b8 100644
--- a/scripts/CMakeLists.txt
+++ b/scripts/CMakeLists.txt
@@ -57,7 +57,9 @@ set ( TEST_PY_FILES
       test/ReductionSettingsTest.py
       )
 
-
+# Addition tests for SANS components
+add_subdirectory(test/SANS)
+	  
 # python unit tests
 if (PYUNITTEST_FOUND)
   pyunittest_add_test ( ${CMAKE_CURRENT_SOURCE_DIR}/test PythonScriptsTest ${TEST_PY_FILES} )
diff --git a/scripts/Calibration/tube.py b/scripts/Calibration/tube.py
index 8f69124c42bcc31c1fdf8f9f8d358fafbeeb0cb8..e915596e4259773337591418d2090358ffff6a8a 100644
--- a/scripts/Calibration/tube.py
+++ b/scripts/Calibration/tube.py
@@ -1,10 +1,27 @@
 # pylint: disable=invalid-name
-"""
+import numpy
+import os
+import re
+
+from mantid.kernel import V3D
+from mantid.api import (MatrixWorkspace, ITableWorkspace)
+from mantid.simpleapi import (mtd, CreateEmptyTableWorkspace, DeleteWorkspace,
+                              FindPeaks, config)
+from tube_spec import TubeSpec
+from ideal_tube import IdealTube
+from tube_calib_fit_params import TubeCalibFitParams
+from tube_calib import getCalibration, getCalibratedPixelPositions, getPoints
+
+# Need to avoid flake8 warning but we can't do that with this
+# buried directly in the string
+CALIBRATE_SIGNATURE = "ws, tubeSet, knownPositions, funcForm, [fitPar, margin, rangeList, calibTable, plotTube, excludeShorTubes, overridePeaks, fitPolyn, outputPeak]" # noqa
+
+__doc__ = _MODULE_DOC="""
 =========================
 Definition of Calibration
 =========================
 
-.. autofunction:: tube.calibrate(ws, tubeSet, knownPositions, funcForm, [fitPar, margin, rangeList, calibTable, plotTube, excludeShorTubes, overridePeaks, fitPolyn, outputPeak])
+.. autofunction:: calibrate({0})
 
 =========
 Use Cases
@@ -48,19 +65,7 @@ Other Useful Methods
 
 .. autofunction:: tube.readCalibrationFile
 
-"""
-
-import numpy
-import os
-import re
-
-from mantid.kernel import V3D
-from mantid.api import (MatrixWorkspace, ITableWorkspace)
-from mantid.simpleapi import (mtd, CreateEmptyTableWorkspace, DeleteWorkspace, config)
-from tube_spec import TubeSpec
-from ideal_tube import IdealTube
-from tube_calib_fit_params import TubeCalibFitParams
-from tube_calib import getCalibration
+""".format(CALIBRATE_SIGNATURE)
 
 
 def calibrate(ws, tubeSet, knownPositions, funcForm, **kwargs):
@@ -749,3 +754,104 @@ def readCalibrationFile(table_name, in_path):
             }
 
             calibTable.addRow(nextRow)
+
+
+def findBadPeakFits(peaksTable, threshold=10):
+    """ Find peaks whose fit values fall outside of a given tolerance
+    of the mean peak centers across all tubes.
+
+    Tubes are defined as have a bad fit if the absolute difference
+    between the fitted peak centers for a specific tube and the
+    mean of the fitted peak centers for all tubes differ more than
+    the threshold parameter.
+
+    @param peakTable: the table containing fitted peak centers
+    @param threshold: the tolerance on the difference from the mean value
+    @return A list of expected peak positions and a list of indicies of tubes
+    to correct
+    """
+    n = len(peaksTable)
+    num_peaks = peaksTable.columnCount()-1
+    column_names = ['Peak%d'%(i) for i in range(1, num_peaks+1)]
+    data = numpy.zeros((n, num_peaks))
+    for i, row in enumerate(peaksTable):
+        data_row = [row[name] for name in column_names]
+        data[i,:] = data_row
+
+    # data now has all the peaks positions for each tube
+    # the mean value is the expected value for the peak position for each tube
+    expected_peak_pos = numpy.mean(data,axis=0)
+
+    #calculate how far from the expected position each peak position is
+    distance_from_expected =  numpy.abs(data - expected_peak_pos)
+    check = numpy.where(distance_from_expected > threshold)[0]
+    problematic_tubes = list(set(check))
+    return expected_peak_pos, problematic_tubes
+
+
+def cleanUpFit():
+    """Clean up workspaces created by calibration fitting """
+    for ws_name in ('TubePlot', 'RefittedPeaks', 'PolyFittingWorkspace',
+                    'QF_NormalisedCovarianceMatrix', 'QF_Parameters',
+                    'QF_Workspace'):
+        try:
+            DeleteWorkspace(ws_name)
+        except:
+            pass
+
+
+def correctMisalignedTubes(ws, calibrationTable, peaksTable, spec, idealTube,
+                           fitPar, threshold=10):
+    """ Correct misaligned tubes due to poor fitting results
+    during the first round of calibration.
+
+    Misaligned tubes are first identified according to a tolerance
+    applied to the absolute difference between the fitted tube
+    positions and the mean across all tubes.
+
+    The FindPeaks algorithm is then used to find a better fit
+    with the ideal tube positions as starting parameters
+    for the peak centers.
+
+    From the refitted peaks the positions of the detectors in the
+    tube are recalculated.
+
+    @param ws: the workspace to get the tube geometry from
+    @param calibrationTable: the calibration table ouput from running
+    calibration
+    @param peaksTable: the table containing the fitted peak centers from
+    calibration
+    @param spec: the tube spec for the instrument
+    @param idealTube: the ideal tube for the instrument
+    @param fitPar: the fitting parameters for calibration
+    @param threshold: tolerance defining is a peak is outside of the acceptable
+    range
+    @return table of corrected detector positions
+    """
+    table_name = calibrationTable.name() + 'Corrected'
+    corrections_table = CreateEmptyTableWorkspace(OutputWorkspace=table_name)
+    corrections_table.addColumn('int', "Detector ID")
+    corrections_table.addColumn('V3D', "Detector Position")
+
+    mean_peaks, bad_tubes = findBadPeakFits(peaksTable, threshold)
+
+    for index in bad_tubes:
+        print "Refitting tube %s" % spec.getTubeName(index)
+        tube_dets, _ = spec.getTube(index)
+        getPoints(ws, idealTube.getFunctionalForms(), fitPar, tube_dets)
+        tube_ws = mtd['TubePlot']
+        fit_ws = FindPeaks(InputWorkspace=tube_ws, WorkspaceIndex=0,
+                           PeakPositions=fitPar.getPeaks(),
+                           PeaksList='RefittedPeaks')
+        centers = [row['centre'] for row in fit_ws]
+        detIDList, detPosList = \
+            getCalibratedPixelPositions(ws, centers, idealTube.getArray(),
+                                        tube_dets)
+
+        for id, pos in zip(detIDList, detPosList):
+            corrections_table.addRow({'Detector ID': id,
+                                      'Detector Position': V3D(*pos)})
+
+        cleanUpFit()
+
+    return corrections_table
diff --git a/scripts/CompareFitMinimizers/fitting_benchmarking.py b/scripts/CompareFitMinimizers/fitting_benchmarking.py
new file mode 100644
index 0000000000000000000000000000000000000000..fb4e9890e83eddd5464f60a0a391634728a87f20
--- /dev/null
+++ b/scripts/CompareFitMinimizers/fitting_benchmarking.py
@@ -0,0 +1,404 @@
+"""
+Classes and utility functions to support benchmarking of fitting minimizers in
+Mantid or other packages useable from Python.  These benchmarks are
+focused on comparing different minimizers in terms of accuracy and
+computation time.
+"""
+# Copyright &copy; 2016 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>
+
+from __future__ import (absolute_import, division, print_function)
+
+import os
+import time
+
+import numpy as np
+
+import mantid.simpleapi as msapi
+
+import input_parsing as iparsing
+import results_output as fitout
+import test_result
+
+
+def run_all_with_or_without_errors(base_problem_files_dir, use_errors, minimizers,
+                                   group_names, group_suffix_names, color_scale, save_to_file=False):
+    """
+    Run all benchmark problems available, with/without using weights in the cost
+    function. This is just a convenience function meant to be used by system/unit tests, or other scripts
+
+    ALL means: NIST + CUTEST + any fitting problems against observed Neutron data (+ any other
+    which may be added in the future)
+
+    At this point in time it is assumed that the problem files are in store relative to
+    a base_problem_files_dir as follows:
+
+        CUTEst/
+        NIST_nonlinear_regression/
+        Neutron_data/
+
+    Be warned this function can be verbose.
+
+    @param base_problem_files_dir :: base directory path of all the benchmark problems
+    @param use_errors :: whether to use observational errors as weights in the cost function
+    @param minimizers :: list of minimizers to test
+    @param group_names :: names for display purposes
+    @param group_suffix_names :: group names to use as suffixes, for example in file names
+    @param color_scale :: list with pairs of threshold value - color, to produce color
+    @param save_to_file :: whether to save the table outputs to files following specific naming conventions
+    """
+
+    # Assume the benchmark problems are stores as follows
+    nist_group_dir = os.path.join(base_problem_files_dir, 'NIST_nonlinear_regression')
+    cutest_group_dir = os.path.join(base_problem_files_dir, 'CUTEst')
+    neutron_data_group_dirs = [os.path.join(base_problem_files_dir, 'Neutron_data')]
+
+    problems, results_per_group = do_fitting_benchmark(nist_group_dir=nist_group_dir,
+                                                       cutest_group_dir=cutest_group_dir,
+                                                       neutron_data_group_dirs=neutron_data_group_dirs,
+                                                       minimizers=minimizers, use_errors=use_errors)
+
+    # Results for every test problem in each group
+    for idx, group_results in enumerate(results_per_group):
+        print("\n\n")
+        print("********************************************************")
+        print("**************** RESULTS FOR GROUP {0}, {1} ************".format(idx+1,
+                                                                                group_names[idx]))
+        print("********************************************************")
+        fitout.print_group_results_tables(minimizers, group_results, problems[idx],
+                                          group_name=group_suffix_names[idx],
+                                          use_errors=use_errors,
+                                          simple_text=True, rst=True, save_to_file=save_to_file,
+                                          color_scale=color_scale)
+
+    # Results aggregated (median) by group (NIST, Neutron data, CUTEst, etc.)
+    header = '\n\n**************** OVERALL SUMMARY - ALL GROUPS ******** \n\n'
+    print(header)
+    fitout.print_overall_results_table(minimizers, results_per_group, problems, group_names,
+                                       use_errors=use_errors, save_to_file=save_to_file)
+
+    # Flush to reduce mix-up with system tests/runner output
+    import sys
+    sys.stdout.flush()
+
+
+def do_fitting_benchmark(nist_group_dir=None, cutest_group_dir=None, neutron_data_group_dirs=None,
+                         minimizers=None, use_errors=True):
+    """
+    Run a fit minimizer benchmark against groups of fitting problems.
+
+    Unless group directories of fitting problems are specified no fitting benchmarking is done.
+
+    NIST and CUTEst refer to the NIST and CUTEst fitting test problem sets, where
+    for example CUTEst is used for fit tests in the mathematical numerical literature.
+
+    The Neutron_data group contain fit tests against real noisy experimental neutron data.
+    This latter group may grow to contain fitting example from multiple directories.
+
+    @param nist_group_dir :: whether to try to load NIST problems
+    @param cutest_group_dir :: whether to try to load CUTEst problems
+    @param neutron_data_group_dirs :: base directory where fitting problems are located including NIST+CUTEst
+    @param minimizers :: list of minimizers to test
+    @param use_errors :: whether to use observational errors as weights in the cost function
+    """
+
+    # Several blocks of problems. Results for each block will be calculated sequentially, and
+    # will go into a separate table
+    problem_blocks = []
+
+    if nist_group_dir:
+        # get NIST problems grouped into blocks of problems, in blocks of increasing difficulty
+        problem_blocks.extend(get_nist_problem_files(nist_group_dir))
+
+    if cutest_group_dir:
+        # get CUTEet problems - just treated as one block of problems
+        problem_blocks.extend([get_cutest_problem_files(cutest_group_dir)])
+
+    if neutron_data_group_dirs:
+        problem_blocks.extend(get_data_groups(neutron_data_group_dirs))
+
+    prob_results = [do_fitting_benchmark_group(block, minimizers, use_errors=use_errors) for
+                    block in problem_blocks]
+
+    probs, results = zip(*prob_results)
+
+    if len(probs) != len(results):
+        raise RuntimeError('probs : {0}, prob_results: {1}'.format(len(probs), len(results)))
+
+    return probs, results
+
+
+def do_fitting_benchmark_group(problem_files, minimizers, use_errors=True):
+    """
+    Applies minimizers to a group (collection) of test problems. For example the
+    collection of all NIST problems
+
+    @param problem_files :: a list of list of files that define a group of
+    test problems. For example all the NIST files sub-groupped according to level
+    of fitting difficulty, where the lowest list level list the file names
+
+    @param minimizers :: list of minimizers to test
+    @param use_errors :: whether to use observational errors as weights in the cost function
+
+    @returns :: problem definitions loaded from the files, and results of running them with
+    the minimizers requested
+    """
+
+    problems = []
+    results_per_problem = []
+    for prob_file in problem_files:
+        try:
+            # Note the CUTEst problem are assumed to be expressed in NIST format
+            prob = iparsing.load_nist_fitting_problem_file(prob_file)
+        except (AttributeError, RuntimeError):
+            prob = iparsing.load_neutron_data_fitting_problem_file(prob_file)
+
+        print("* Testing fitting for problem definition file {0}".format(prob_file))
+        print("* Testing fitting of problem {0}".format(prob.name))
+
+        results_prob = do_fitting_benchmark_one_problem(prob, minimizers, use_errors)
+        results_per_problem.extend(results_prob)
+
+    return problems, results_per_problem
+
+
+def do_fitting_benchmark_one_problem(prob, minimizers, use_errors=True):
+    """
+    One problem with potentially several starting points, returns a list (start points) of
+    lists (minimizers).
+
+    @param prob :: fitting problem
+    @param minimizers :: list of minimizers to evaluate/compare
+    @param use_errors :: whether to use observational errors when evaluating accuracy (in the
+                         cost function)
+    """
+
+    wks, cost_function = prepare_wks_cost_function(prob, use_errors)
+
+    # Each NIST problem generate two results per file - from two different starting points
+    results_fit_problem = []
+
+    # Get function definitions for the problem - one for each starting point
+    function_defs = get_function_definitions(prob)
+
+    # Loop over the different starting points
+    for user_func in function_defs:
+        results_problem_start = []
+        for minimizer_name in minimizers:
+            t_start = time.clock()
+
+            status, chi2, fit_wks, params, errors = run_fit(wks, prob, function=user_func,
+                                                            minimizer=minimizer_name,
+                                                            cost_function=cost_function)
+            t_end = time.clock()
+            print("*** with minimizer {0}, Status: {1}, chi2: {2}".format(minimizer_name, status, chi2))
+            print("   params: {0}, errors: {1}".format(params, errors))
+
+            def sum_of_squares(values):
+                return np.sum(np.square(values))
+
+            if fit_wks:
+                sum_err_sq = sum_of_squares(fit_wks.readY(2))
+                # print " output simulated values: {0}".format(fit_wks.readY(1))
+            else:
+                sum_err_sq = float("inf")
+                print(" WARNING: no output fit workspace")
+
+            print("   sum sq: {0}".format(sum_err_sq))
+
+            result = test_result.FittingTestResult()
+            result.problem = prob
+            result.fit_status = status
+            result.fit_chi2 = chi2
+            result.params = params
+            result.errors = errors
+            result.sum_err_sq = sum_err_sq
+            result.runtime = t_end - t_start
+            print("Result object: {0}".format(result))
+            results_problem_start.append(result)
+
+        results_fit_problem.append(results_problem_start)
+
+    return results_fit_problem
+
+
+def run_fit(wks, prob, function, minimizer='Levenberg-Marquardt', cost_function='Least squares'):
+    """
+    Fits the data in a workspace with a function, using the algorithm Fit.
+    Importantly, the option IgnoreInvalidData is enabled. Check the documentation of Fit for the
+    implications of this.
+
+    @param wks :: MatrixWorkspace with data to fit, in the format expected by the algorithm Fit
+    @param prob :: Problem definition
+    @param function :: function definition as used in the algorithm Fit
+    @param minimizer :: minimizer to use in Fit
+    @param cost_function :: cost function to use in Fit
+
+    @returns the fitted parameter values and error estimates for these
+    """
+    status = None
+    chi2 = None
+    param_tbl = None
+    fit_wks = None
+    try:
+        # When using 'Least squares' (weighted by errors), ignore nans and zero errors, but don't
+        # ignore them when using 'Unweighted least squares' as that would ignore all values!
+        ignore_invalid = cost_function == 'Least squares'
+
+        # Note the ugly adhoc exception. We need to reconsider these WISH problems:
+        if 'WISH17701' in prob.name:
+            ignore_invalid = False
+
+        status, chi2, covar_tbl, param_tbl, fit_wks = msapi.Fit(function, wks, Output='ws_fitting_test',
+                                                                Minimizer=minimizer,
+                                                                CostFunction=cost_function,
+                                                                IgnoreInvalidData=ignore_invalid,
+                                                                StartX=prob.start_x, EndX=prob.end_x)
+
+        calc_chi2 = msapi.CalculateChiSquared(Function=function,
+                                              InputWorkspace=wks, IgnoreInvalidData=ignore_invalid)
+        print("*** with minimizer {0}, calculated: chi2: {1}".format(minimizer, calc_chi2))
+
+    except RuntimeError as rerr:
+        print("Warning, Fit probably failed. Going on. Error: {0}".format(str(rerr)))
+
+    if param_tbl:
+        params = param_tbl.column(1)[:-1]
+        errors = param_tbl.column(2)[:-1]
+    else:
+        params = None
+        errors = None
+
+    return status, chi2, fit_wks, params, errors
+
+
+def prepare_wks_cost_function(prob, use_errors):
+    """
+    Build a workspace ready for Fit() and a cost function string according to the problem
+    definition.
+    """
+    if use_errors:
+        data_e = None
+        if not isinstance(prob.data_pattern_obs_errors, np.ndarray):
+            # Fake observational errors
+            data_e = np.sqrt(prob.data_pattern_in)
+        else:
+            data_e = prob.data_pattern_obs_errors
+
+        wks = msapi.CreateWorkspace(DataX=prob.data_pattern_in, DataY=prob.data_pattern_out,
+                                    DataE=data_e)
+        cost_function = 'Least squares'
+    else:
+        wks = msapi.CreateWorkspace(DataX=prob.data_pattern_in, DataY=prob.data_pattern_out)
+        cost_function = 'Unweighted least squares'
+
+    return wks, cost_function
+
+
+def get_function_definitions(prob):
+    """
+    Produces function definition strings (as a full definition in
+    muparser format, including the function and the initial values for
+    the parameters), one for every different starting point defined in
+    the test problem.
+
+    @param prob :: fitting test problem object
+
+    @returns :: list of function strings ready for Fit()
+    """
+    function_defs = []
+    if prob.starting_values:
+        num_starts = len(prob.starting_values[0][1])
+        for start_idx in range(0, num_starts):
+
+            print("=================== starting values,: {0}, with idx: {1} ================".
+                  format(prob.starting_values, start_idx))
+            start_string = ''  # like: 'b1=250, b2=0.0005'
+            for param in prob.starting_values:
+                start_string += ('{0}={1},'.format(param[0], param[1][start_idx]))
+
+            if 'name' in prob.equation:
+                function_defs.append(prob.equation)
+            else:
+                function_defs.append("name=UserFunction, Formula={0}, {1}".format(prob.equation, start_string))
+    else:
+        # Equation from a neutron data spec file. Ready to be used
+        function_defs.append(prob.equation)
+
+    return function_defs
+
+
+def get_nist_problem_files(search_dir):
+    """
+    Group the NIST problem files into separeate blocks according
+    to assumed fitting different levels: lower, average,
+    higher.
+
+    @returns :: list of list of problem files
+    """
+    # Grouped by "level of difficulty"
+    nist_lower = ['Misra1a.dat', 'Chwirut2.dat', 'Chwirut1.dat', 'Lanczos3.dat',
+                  'Gauss1.dat', 'Gauss2.dat', 'DanWood.dat', 'Misra1b.dat']
+
+    nist_average = ['Kirby2.dat', 'Hahn1.dat',
+                    # 'Nelson.dat' needs log[y] parsing / DONE, needs x1, x2
+                    'MGH17.dat', 'Lanczos1.dat', 'Lanczos2.dat', 'Gauss3.dat',
+                    'Misra1c.dat', 'Misra1d.dat',
+                    # 'Roszman1.dat' <=== needs handling the  'pi = 3.1415...' / DOME
+                    # And the 'arctan()'/ DONE, but generated lots of NaNs
+                    'ENSO.dat']
+    nist_higher = ['MGH09.dat', 'Thurber.dat', 'BoxBOD.dat', 'Rat42.dat',
+                   'MGH10.dat', 'Eckerle4.dat', 'Rat43.dat', 'Bennett5.dat']
+
+    nist_lower_files = [os.path.join(search_dir, fname) for fname in nist_lower]
+    nist_average_files = [os.path.join(search_dir, fname) for fname in nist_average]
+    nist_higher_files = [os.path.join(search_dir, fname) for fname in nist_higher]
+    problem_files = [nist_lower_files, nist_average_files, nist_higher_files]
+
+    return problem_files
+
+
+def get_cutest_problem_files(search_dir):
+
+    cutest_all = ['PALMER6C.dat', 'PALMER7C.dat', 'PALMER8C.dat', 'YFITU.dat', 'VESUVIOLS.dat', 'DMN15102LS.dat']
+
+    cutest_files = [os.path.join(search_dir, fname) for fname in cutest_all]
+
+    return cutest_files
+
+
+def get_data_groups(data_groups_dirs):
+
+    problem_groups = []
+    for grp_dir in data_groups_dirs:
+        problem_groups.append(get_data_group_problem_files(grp_dir))
+
+    return problem_groups
+
+
+def get_data_group_problem_files(grp_dir):
+    import glob
+
+    search_str = os.path.join(grp_dir, "*.txt")
+    probs = glob.glob(search_str)
+
+    probs.sort()
+    print ("Found test problem files: ", probs)
+    return probs
diff --git a/scripts/CompareFitMinimizers/input_parsing.py b/scripts/CompareFitMinimizers/input_parsing.py
new file mode 100644
index 0000000000000000000000000000000000000000..641c3ba41b855f47d9c6e22a96e80367e9defa4a
--- /dev/null
+++ b/scripts/CompareFitMinimizers/input_parsing.py
@@ -0,0 +1,271 @@
+"""
+Parse input files describing fitting test examples and load the
+information into problem objects
+
+"""
+# Copyright &copy; 2016 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>
+
+from __future__ import (absolute_import, division, print_function)
+
+import os
+import re
+
+import numpy as np
+
+import test_problem
+
+
+def load_nist_fitting_problem_file(problem_filename):
+    with open(problem_filename) as spec_file:
+        return parse_nist_file(spec_file)
+
+
+def parse_data_pattern(data_text):
+    """
+    Parses the data part of a NIST test problem file (the columns of
+    values) and produces a numpy array with the data.
+
+    """
+    if not data_text:
+        return None
+
+    first = data_text[0].strip()
+    dim = len(first.split())
+    data_points = np.zeros((len(data_text), dim))
+
+    for idx, line in enumerate(data_text):
+        line = line.strip()
+        point_text = line.split()
+        point = [float(val) for val in point_text]
+        data_points[idx, :] = point
+
+    return data_points
+
+
+def parse_equation(eq_text):
+    """
+    Parses the equation text (possibly multi-line) and does a rough
+    conversion from NIST equation format to muparser format
+
+    @param eq_text :: equation formula as given in a NIST problem description
+    @return formula ready to be used in the 'Formula=' of functions 'UserFunction' of
+            the Fit algorithm
+    """
+    start_normal = r'\s*y\s*=(.+)'
+    start_log = r'\s*log\[y\]\s*=(.+)'
+    # try first the usual syntax
+    if re.match(start_normal, eq_text):
+        match = re.search(r'y\s*=(.+)\s*\+\s*e', eq_text)
+        equation = match.group(1).strip()
+    # log-syntax used in NIST/Nelson
+    elif re.match(start_log, eq_text):
+        match = re.search(r'log\[y\]\s*=(.+)\s*\+\s*e', eq_text)
+        equation = "exp(" + match.group(1).strip() + ")"
+    else:
+        raise RuntimeError("Unrecognized equation syntax when trying to parse a NIST "
+                           "equation: " + eq_text)
+
+    # 'NIST equation syntax' => muparser syntax
+    # brackets for muparser
+    equation = equation.replace('[', '(')
+    equation = equation.replace(']', ')')
+    equation = equation.replace('arctan', 'atan')
+    equation = equation.replace('**', '^')
+    return equation
+
+
+def parse_starting_values(lines):
+    starting_vals = []
+    for line in lines:
+        if not line.strip() or line.startswith('Residual'):
+            break
+
+        comps = line.split()
+        if 6 != len(comps) and 5 != len(comps):
+            raise RuntimeError("Failed to parse this line as starting "
+                               "values information: {0}".format(line))
+
+        # A bit weak/lax parsing, if there is one less column, assume only one start point
+        if 6 == len(comps):
+            alt_values = [float(comps[2]), float(comps[3])]
+        elif 5 == len(comps):
+            alt_values = [float(comps[2])]
+
+        starting_vals.append([comps[0], alt_values])
+
+    return starting_vals
+
+
+def parse_nist_file(spec_file):
+    """
+    Produce a fitting test problem definition object from a NIST text file.
+
+    @param spec_file :: input file, as a standard NIST text (.dat) file
+    """
+
+    lines = spec_file.readlines()
+    equation_text, data_pattern_text, starting_values, residual_sum_sq = parse_nist_file_line_by_line(lines)
+
+    if not equation_text or not data_pattern_text:
+        raise RuntimeError('Could not find the equation and data after parsing the lines of this file: {0}'.
+                           format(spec_file.name))
+
+    data_pattern = parse_data_pattern(data_pattern_text)
+    parsed_eq = parse_equation(equation_text)
+
+    prob = test_problem.FittingTestProblem()
+    prob.name = os.path.basename(spec_file.name)
+    prob.linked_name = ("`{0} <http://www.itl.nist.gov/div898/strd/nls/data/{1}.shtml>`__".
+                        format(prob.name, prob.name.lower()))
+    prob.equation = parsed_eq
+    prob.starting_values = starting_values
+    prob.data_pattern_in = data_pattern[:, 1:]
+    prob.data_pattern_out = data_pattern[:, 0]
+    prob.ref_residual_sum_sq = residual_sum_sq
+
+    return prob
+
+
+def parse_nist_file_line_by_line(lines):
+    """
+    Get several relevant pieces of information from the lines of a NIST problem file
+    This parser is far from great but it does the job.
+
+    @param lines :: lines as directly loaded from a file
+
+    @returns :: the equation string, the data string, the starting values, and the
+    certified chi^2, as found in the text lines
+    """
+
+    idx, data_idx = 0, 0
+    data_pattern_text = None
+    residual_sum_sq = 0
+    equation_text = None
+    starting_values = None
+    # The first line should be:
+    # NIST/ITL StRD
+    while idx < len(lines):
+        line = lines[idx].strip()
+        idx += 1
+
+        if not line:
+            continue
+
+        if line.startswith('Model:'):
+            # Would skip number of parameters, and empty line, but not
+            # adequate for all test problems
+            # idx += 3
+
+            # Before 'y = ...' there can be lines like 'pi = 3.14159...'
+            while (not re.match(r'\s*y\s*=(.+)', lines[idx])
+                   and not re.match(r'\s*log\[y\]\s*=(.+)', lines[idx]))\
+                   and idx < len(lines):  # [\s*\+\s*e]
+                idx += 1
+            # Next non-empty lines are assumed to continue the equation
+            equation_text = ''
+            while lines[idx].strip():
+                equation_text += lines[idx].strip()
+                idx += 1
+
+        elif 'Starting values' in line or 'Starting Values' in line:
+            # 1 empty line, and one heading line before values
+            idx += 2
+            starting_values = parse_starting_values(lines[idx:])
+            idx += len(starting_values)
+
+        elif line.startswith('Residual Sum of Squares'):
+            residual_sum_sq = float(line.split()[4])
+
+        elif line.startswith('Data:'):
+            if 0 == data_idx:
+                data_idx += 1
+            elif 1 == data_idx:
+                data_pattern_text = lines[idx:]
+                idx = len(lines)
+            else:
+                raise RuntimeError('Error parsing data line: {}'.format(line))
+        else:
+            print("unknown line in supposedly NIST test file, ignoring: {0}".format(line))
+
+    return equation_text, data_pattern_text, starting_values, residual_sum_sq
+
+
+def load_neutron_data_fitting_problem_file(fname):
+    """
+    Builds a FittingTestProblem object from a text file. The file is expected to
+    have a list of variables (input filename, name, equation, etc.)
+
+    Other alternatives could be ConfigParser (ini format, parser not extermely
+    good), or JSON.
+
+    @param fname :: name of the file to load
+    """
+    with open(fname) as probf:
+        entries = get_neutron_data_problem_entries(probf)
+
+        prob = test_problem.FittingTestProblem()
+        get_fitting_neutron_data(entries['input_file'], prob)
+        prob.name = entries['name']
+        prob.equation = entries['function']
+        prob.starting_values = None
+        if 'fit_parameters' in entries:
+            prob.start_x = entries['fit_parameters']['StartX']
+            prob.end_x = entries['fit_parameters']['EndX']
+
+    return prob
+
+
+def get_neutron_data_problem_entries(problem_file):
+    """
+    Get values from the lines of a "neutron fitting problem definition file",
+    They are returned as a dictionary of key (lhs) - value (rhs).
+    """
+    entries = {}
+    for line in problem_file:
+        # discard comments
+        line = line.partition('#')[0]
+        line = line.rstrip()
+        if not line:
+            continue
+
+        # take values (lhs = rhs)
+        lhs, rhs = line.split("=", 1)
+        # assumes it is safe to evaluate the rhs (it's a string for example)
+        entries[lhs.strip()] = eval(rhs.strip())
+
+    return entries
+
+
+def get_fitting_neutron_data(fname, prob):
+    """
+    Load the X-Y-E data from a file and put the values into a fitting problem
+    definition object.
+
+    @param fname :: file name to load (using mantid loaders)
+    @param prob :: problem definition to populate with X-Y-E data.
+    """
+    import mantid.simpleapi as msapi
+
+    wks = msapi.Load(fname)
+    prob.data_pattern_in = wks.readX(0)
+    prob.data_pattern_out = wks.readY(0)
+    prob.data_pattern_obs_errors = wks.readE(0)
+    prob.ref_residual_sum_sq = 0
diff --git a/scripts/CompareFitMinimizers/post_processing.py b/scripts/CompareFitMinimizers/post_processing.py
new file mode 100644
index 0000000000000000000000000000000000000000..2a947ace4b06391f913fb735f7908c4bbf5a56e9
--- /dev/null
+++ b/scripts/CompareFitMinimizers/post_processing.py
@@ -0,0 +1,115 @@
+# Copyright &copy; 2016 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>
+
+import numpy as np
+from scipy import stats  # older version of numpy does not support nanmean and nanmedian
+
+
+def calc_summary_table(minimizers, group_results):
+    """
+    Calculates a summary from problem-individual results. At the moment the only summary
+    statistic calculated is the median. The output is produced as numpy matrices.
+
+    @param minimizers :: list of minimizers used (their names)
+
+    @param group_results :: results from running fitting tests on different problems (list
+    of lists, where the first level is the group, and the second level is the individual test).
+
+
+    @returns two numpy matrices (where columns are the groups, and rows are the minimizers)
+    with summary statistic (median) from the problem-individual results.
+    """
+
+    num_groups = len(group_results)
+    num_minimizers = len(minimizers)
+
+    groups_norm_acc = np.zeros((num_groups, num_minimizers))
+    groups_norm_runtime = np.zeros((num_groups, num_minimizers))
+    for group_idx, results_per_test in enumerate(group_results):
+        num_tests = len(results_per_test)
+        accuracy_tbl = np.zeros((num_tests, num_minimizers))
+        time_tbl = np.zeros((num_tests, num_minimizers))
+
+        for test_idx in range(0, num_tests):
+            for minimiz_idx in range(0, num_minimizers):
+                accuracy_tbl[test_idx, minimiz_idx] = results_per_test[test_idx][minimiz_idx].sum_err_sq
+                time_tbl[test_idx, minimiz_idx] = results_per_test[test_idx][minimiz_idx].runtime
+
+        # Min across all alternative runs/minimizers
+        min_sum_err_sq = np.nanmin(accuracy_tbl, 1)
+        min_runtime = np.nanmin(time_tbl, 1)
+
+        norm_acc_rankings = accuracy_tbl / min_sum_err_sq[:, None]
+        norm_runtime_rankings = time_tbl / min_runtime[:, None]
+
+        groups_norm_acc[group_idx, :] = stats.nanmedian(norm_acc_rankings, 0)
+        groups_norm_runtime[group_idx, :] = stats.nanmedian(norm_runtime_rankings, 0)
+
+    return groups_norm_acc, groups_norm_runtime
+
+
+def calc_accuracy_runtime_tbls(results_per_test, minimizers):
+    """
+    This produces a numpy matrix for convenience, with
+    1 row per problem+start, 1 column per minimizer
+    """
+    num_tests = len(results_per_test)
+    num_minimizers = len(minimizers)
+    accuracy_tbl = np.zeros((num_tests, num_minimizers))
+    time_tbl = np.zeros((num_tests, num_minimizers))
+    for test_idx in range(0, num_tests):
+        for minimiz_idx in range(0, num_minimizers):
+            accuracy_tbl[test_idx, minimiz_idx] = results_per_test[test_idx][minimiz_idx].sum_err_sq
+            time_tbl[test_idx, minimiz_idx] = results_per_test[test_idx][minimiz_idx].runtime
+
+    return accuracy_tbl, time_tbl
+
+
+def calc_norm_summary_tables(accuracy_tbl, time_tbl):
+    """
+    Calculate normalized performance/ranking summary, as numpy
+    matrices as usual for convenience, and matrices of additional
+    statistics (min, max, percentiles, etc.)
+
+    Here normalized means relative to the best which gets a 1, all
+    others get the ratio resulting from dividing by the performance of
+    the best.
+    """
+    # Min across all minimizers, i.e. for each fit problem what is the lowest chi-squared and the lowest time
+    min_sum_err_sq = np.nanmin(accuracy_tbl, 1)
+    min_runtime = np.nanmin(time_tbl, 1)
+
+    # create normalised tables
+    norm_acc_rankings = accuracy_tbl / min_sum_err_sq[:, None]
+    norm_runtimes = time_tbl / min_runtime[:, None]
+
+    summary_cells_acc = np.array([np.nanmin(norm_acc_rankings, 0),
+                                  np.nanmax(norm_acc_rankings, 0),
+                                  stats.nanmean(norm_acc_rankings, 0),
+                                  stats.nanmedian(norm_acc_rankings, 0)
+                                  ])
+
+    summary_cells_runtime = np.array([np.nanmin(norm_runtimes, 0),
+                                      np.nanmax(norm_runtimes, 0),
+                                      stats.nanmean(norm_runtimes, 0),
+                                      stats.nanmedian(norm_runtimes, 0)
+                                      ])
+
+    return norm_acc_rankings, norm_runtimes, summary_cells_acc, summary_cells_runtime
diff --git a/scripts/CompareFitMinimizers/results_output.py b/scripts/CompareFitMinimizers/results_output.py
new file mode 100644
index 0000000000000000000000000000000000000000..57d28e5c23af2b95e2ca6723f5c3b07b132b5130
--- /dev/null
+++ b/scripts/CompareFitMinimizers/results_output.py
@@ -0,0 +1,474 @@
+"""
+Produce output tables from fitting benchmarking results, in different
+formats such as RST and plain text.
+"""
+# Copyright &copy; 2016 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>
+
+from __future__ import (absolute_import, division, print_function)
+
+import numpy as np
+from scipy import stats  # older version of numpy does not support nanmean and nanmedian
+import post_processing as postproc
+
+# Some naming conventions for the output files
+BENCHMARK_VERSION_STR = 'v3.8'
+FILENAME_SUFFIX_ACCURACY = 'acc'
+FILENAME_SUFFIX_RUNTIME = 'runtime'
+
+
+def print_group_results_tables(minimizers, results_per_test, problems_obj, group_name, use_errors,
+                               simple_text=True, rst=False, save_to_file=False, color_scale=None):
+    """
+    Prints out results for a group of fit problems in accuracy and runtime tables, in a summary
+    format and both as simple text, rst format and/or to file depending on input arguments
+
+    @param minimizers :: list of minimizer names
+    @param results_per_test :: result objects
+    @param problems_obj :: definitions of the test problems
+    @param group_name :: name of this group of problems (example 'NIST "lower difficulty"', or
+                         'Neutron data')
+    @param use_errors :: whether to use observational errors
+    @param simple_text :: whether to print the tables in a simple text format
+    @param rst :: whether to print the tables in rst format. They are printed to the standard outputs
+                  and to files following specific naming conventions
+    @param save_to_file :: If rst=True, whether to save the tables to files following specific naming conventions
+    @param color_scale :: threshold-color pairs. This is used for RST tables. The number of levels
+                          must be consistent with the style sheet used in the documentation pages (5
+                          at the moment).
+    """
+    linked_problems = build_indiv_linked_problems(results_per_test, group_name)
+
+    # Calculate summary tables
+    accuracy_tbl, runtime_tbl = postproc.calc_accuracy_runtime_tbls(results_per_test, minimizers)
+    norm_acc_rankings, norm_runtimes, summary_cells_acc, summary_cells_runtime = \
+        postproc.calc_norm_summary_tables(accuracy_tbl, runtime_tbl)
+
+    if simple_text:
+        print_tables_simple_text(minimizers, results_per_test, accuracy_tbl, runtime_tbl, norm_acc_rankings)
+
+    if rst:
+        # print out accuracy table for this group of fit problems
+        tbl_acc_indiv = build_rst_table(minimizers, linked_problems, norm_acc_rankings,
+                                        comparison_type='accuracy', comparison_dim='',
+                                        using_errors=use_errors, color_scale=color_scale)
+        header = " ************* Comparison of sum of square errors (RST): *********\n"
+        header += " *****************************************************************\n"
+        header += "\n\n"
+        print(header)
+        print (tbl_acc_indiv)
+
+        # optionally save the above table to file
+        if save_to_file:
+            fname = ('comparison_{weighted}_{version}_{metric_type}_{group_name}.txt'.
+                     format(weighted=weighted_suffix_string(use_errors),
+                            version=BENCHMARK_VERSION_STR, metric_type=FILENAME_SUFFIX_ACCURACY, group_name=group_name))
+            with open(fname, 'w') as tbl_file:
+                print(tbl_acc_indiv, file=tbl_file)
+
+        # print out accuracy summary table for this group of fit problems
+        ext_summary_cols = minimizers
+        ext_summary_rows = ['Best ranking', 'Worst ranking', 'Average', 'Median']
+        tbl_acc_summary = build_rst_table(ext_summary_cols, ext_summary_rows, summary_cells_acc,
+                                          comparison_type='accuracy', comparison_dim='',
+                                          using_errors=use_errors, color_scale=color_scale)
+        header = '**************** Statistics/Summary (accuracy): ******** \n\n'
+        print(header)
+        print(tbl_acc_summary)
+
+        # print out runtime table for this group of fit problems
+        tbl_runtime_indiv = build_rst_table(minimizers, linked_problems, norm_runtimes,
+                                            comparison_type='runtime', comparison_dim='',
+                                            using_errors=use_errors, color_scale=color_scale)
+        header = " ************* Comparison of runtimes (RST): ****************\n"
+        header += " *****************************************************************\n"
+        header += "\n\n"
+        print(header)
+        print (tbl_runtime_indiv)
+
+        # optionally save the above table to file
+        if save_to_file:
+            fname = ('comparison_{weighted}_{version}_{metric_type}_{group_name}.txt'.
+                     format(weighted=weighted_suffix_string(use_errors),
+                            version=BENCHMARK_VERSION_STR, metric_type=FILENAME_SUFFIX_RUNTIME, group_name=group_name))
+            with open(fname, 'w') as tbl_file:
+                print(tbl_runtime_indiv, file=tbl_file)
+
+        # print out runtime summary table for this group of fit problems
+        tbl_runtime_summary = build_rst_table(ext_summary_cols, ext_summary_rows, summary_cells_runtime,
+                                              comparison_type='runtime', comparison_dim='',
+                                              using_errors=use_errors, color_scale=color_scale)
+        header = '**************** Statistics/Summary (runtime): ******** \n\n'
+        print(header)
+        print(tbl_runtime_summary)
+
+
+def build_indiv_linked_problems(results_per_test, group_name):
+    """
+    Makes a list of linked problem names which would be used for the
+    rows of the first column of the tables of individual results.
+
+    @param results_per_test :: results as produces by the fitting tests
+    @param group_name :: name of the group (NIST, Neutron data, etc.) this problem is part of
+
+    @returns :: list of problems with their description link tags
+    """
+    num_tests = len(results_per_test)
+    prev_name = ''
+    prob_count = 1
+    linked_problems = []
+    for test_idx in range(0, num_tests):
+        raw_name = results_per_test[test_idx][0].problem.name
+        name = raw_name.split('.')[0]
+        if name == prev_name:
+            prob_count += 1
+        else:
+            prob_count = 1
+
+        prev_name = name
+        name_index = name + ' ' + str(prob_count)
+
+        # TO-DO: move this to the nist loader, not here!
+        if 'nist_' in group_name:
+            linked_problems.append("`{0} <http://www.itl.nist.gov/div898/strd/nls/data/{1}.shtml>`__".
+                                   format(name_index, name.lower()))
+        else:
+            linked_problems.append(name)
+
+    return linked_problems
+
+
+def build_group_linked_names(group_names):
+    """
+    Add a link for RST tables if there is a website or similar describing the group.
+
+    @param group_names :: names as plain text
+
+    @returns :: names with RST links if available
+    """
+    linked_names = []
+    for name in group_names:
+        # This should be tidied up. We currently don't have links for groups other than NIST
+        if 'NIST' in name:
+            linked = "`{0} <http://www.itl.nist.gov/div898/strd/nls/nls_main.shtml>`__".format(name)
+        else:
+            linked = name
+
+        linked_names.append(linked)
+
+    return linked_names
+
+
+def print_overall_results_table(minimizers, group_results, problems, group_names, use_errors,
+                                simple_text=True, save_to_file=False):
+
+    groups_norm_acc, groups_norm_runtime = postproc.calc_summary_table(minimizers, group_results)
+
+    grp_linked_names = build_group_linked_names(group_names)
+
+    header = '**************** Accuracy ******** \n\n'
+    print(header)
+    tbl_all_summary_acc = build_rst_table(minimizers, grp_linked_names, groups_norm_acc,
+                                          comparison_type='summary', comparison_dim='accuracy',
+                                          using_errors=use_errors)
+    print(tbl_all_summary_acc)
+
+    if save_to_file:
+        fname = ('comparison_{weighted}_{version}_{metric_type}_{group_name}.txt'.
+                 format(weighted=weighted_suffix_string(use_errors),
+                        version=BENCHMARK_VERSION_STR, metric_type=FILENAME_SUFFIX_ACCURACY, group_name='summary'))
+        with open(fname, 'w') as tbl_file:
+            print(tbl_all_summary_acc, file=tbl_file)
+
+    header = '**************** Runtime ******** \n\n'
+    print(header)
+    tbl_all_summary_runtime = build_rst_table(minimizers, grp_linked_names, groups_norm_runtime,
+                                              comparison_type='summary', comparison_dim='runtime',
+                                              using_errors=use_errors)
+    print(tbl_all_summary_runtime)
+
+    if save_to_file:
+        fname = ('comparison_{weighted}_{version}_{metric_type}_{group_name}.txt'.
+                 format(weighted=weighted_suffix_string(use_errors),
+                        version=BENCHMARK_VERSION_STR, metric_type=FILENAME_SUFFIX_RUNTIME, group_name='summary'))
+        with open(fname, 'w') as tbl_file:
+            print(tbl_all_summary_runtime, file=tbl_file)
+
+
+def weighted_suffix_string(use_errors):
+    """
+    Produces a suffix weighted/unweighted. Used to generate names of
+    output files.
+    """
+    values = {True: 'weighted', False: 'unweighted'}
+    return values[use_errors]
+
+
+def display_name_for_minimizers(names):
+    """
+    Converts minimizer names into their "display names". For example
+    to rename DTRS to "Trust region" or similar
+
+    """
+    display_names = names
+    # Quick fix for DTRS name in version 3.8 - REMOVE
+    for idx, minimizer in enumerate(names):
+        if 'DTRS' == minimizer:
+            display_names[idx] = 'Trust Region'
+
+    return display_names
+
+
+def calc_cell_len_rst_table(columns_txt, items_link):
+    """
+    Calculate what width in ascii characters we need for an RST table.
+
+    @param columns_txt :: list of the contents of the column headers
+    """
+    # One length for all cells
+    cell_len = 50
+    cell_len = 0
+    for col in columns_txt:
+        new_len = len(col) + 2
+        if new_len > cell_len:
+            cell_len = new_len
+
+    # Beware of the long links
+    links_len = 0
+    if items_link and isinstance(items_link, list):
+        links_len = max([len(item) for item in items_link])
+    elif items_link:
+        links_len = len(items_link)
+
+    additional_len = 0
+    if items_link:
+        additional_len = links_len
+    cell_len += int(additional_len/1.2)
+
+    return cell_len
+
+
+def build_rst_table(columns_txt, rows_txt, cells, comparison_type, comparison_dim,
+                    using_errors, color_scale=None):
+    """"
+    Builds an RST table as a string, given the list of column and row headers,
+    and a 2D numpy array with values for the cells.
+    This can be tricky/counterintuitive, see:
+    http://docutils.sourceforge.net/docs/dev/rst/problems.html
+
+    @param columns_txt :: the text for the columns, one item per column
+    @param rows_txt :: the text for the rows (will go in the leftmost column)
+    @param cells :: a 2D numpy array with as many rows as items have been given
+    in rows_txt, and as many columns as items have been given in columns_txt
+
+    @param comparison_type :: whether this is a 'summary', or a full 'accuracy', or 'runtime'
+                              table.
+    @param comparison_dim :: dimension (accuracy / runtime)
+    @param using_errors :: whether this comparison uses errors in the cost function
+    (weighted or unweighted), required to link the table properly
+
+    @param color_scale :: list with pairs of threshold value - color, to produce color
+    tags for the cells
+    """
+    columns_txt = display_name_for_minimizers(columns_txt)
+
+    items_link = build_items_links(comparison_type, comparison_dim, using_errors)
+
+    cell_len = calc_cell_len_rst_table(columns_txt, items_link)
+
+    # The first column tends to be disproportionately long if it has a link
+    first_col_len = calc_first_col_len(cell_len, rows_txt)
+
+    tbl_header_top, tbl_header_text, tbl_header_bottom = build_rst_table_header_chunks(first_col_len, cell_len,
+                                                                                       columns_txt)
+
+    tbl_header = tbl_header_top + '\n' + tbl_header_text + '\n' + tbl_header_bottom + '\n'
+    # the footer is in general the delimiter between rows, including the last one
+    tbl_footer = tbl_header_top + '\n'
+
+    tbl_body = ''
+    for row in range(0, cells.shape[0]):
+        # Pick either individual or group link
+        if isinstance(items_link, list):
+            link = items_link[row]
+        else:
+            link = items_link
+
+        tbl_body += '|' + rows_txt[row].ljust(first_col_len, ' ') + '|'
+        for col in range(0, cells.shape[1]):
+            tbl_body += format_cell_value_rst(cells[row, col], cell_len, color_scale, link) + '|'
+
+        tbl_body += '\n'
+        tbl_body += tbl_footer
+
+    return tbl_header + tbl_body
+
+
+def build_rst_table_header_chunks(first_col_len, cell_len, columns_txt):
+    """
+    Prepare the horizontal and vertical lines in the RST headers.
+
+    @param first_col_len :: length (in characters) of the first column
+    @param cell_len :: length of all other cells
+    """
+    tbl_header_top = '+'
+    tbl_header_text = '|'
+    tbl_header_bottom = '+'
+
+    # First column in the header for the name of the test or statistics
+    tbl_header_top += '-'.ljust(first_col_len, '-') + '+'
+    tbl_header_text += ' '.ljust(first_col_len, ' ') + '|'
+    tbl_header_bottom += '='.ljust(first_col_len, '=') + '+'
+    for col_name in columns_txt:
+        tbl_header_top += '-'.ljust(cell_len, '-') + '+'
+        tbl_header_text += col_name.ljust(cell_len, ' ') + '|'
+        tbl_header_bottom += '='.ljust(cell_len, '=') + '+'
+
+    return tbl_header_top, tbl_header_text, tbl_header_bottom
+
+
+def calc_first_col_len(cell_len, rows_txt):
+    first_col_len = cell_len
+    for row_name in rows_txt:
+        name_len = len(row_name)
+        if name_len > first_col_len:
+            first_col_len = name_len
+
+    return first_col_len
+
+
+def build_items_links(comparison_type, comparison_dim, using_errors):
+    """
+    Figure out the links from rst table cells to other pages/sections of pages.
+
+    @param comparison_type :: whether this is a 'summary', or a full 'accuracy', or 'runtime' table.
+    @param comparison_dim :: dimension (accuracy / runtime)
+    @param using_errors :: whether using observational errors in cost functions
+
+    @returns :: link or links to use from table cells.
+    """
+    if 'summary' == comparison_type:
+        items_link = ['Minimizers_{0}_comparison_in_terms_of_{1}_nist_lower'.
+                      format(weighted_suffix_string(using_errors), comparison_dim),
+                      'Minimizers_{0}_comparison_in_terms_of_{1}_nist_average'.
+                      format(weighted_suffix_string(using_errors), comparison_dim),
+                      'Minimizers_{0}_comparison_in_terms_of_{1}_nist_higher'.
+                      format(weighted_suffix_string(using_errors), comparison_dim),
+                      'Minimizers_{0}_comparison_in_terms_of_{1}_cutest'.
+                      format(weighted_suffix_string(using_errors), comparison_dim),
+                      'Minimizers_{0}_comparison_in_terms_of_{1}_neutron_data'.
+                      format(weighted_suffix_string(using_errors), comparison_dim),
+                      ]
+    elif 'accuracy' == comparison_type or 'runtime' == comparison_type:
+        if using_errors:
+            items_link = 'FittingMinimizersComparisonDetailedWithWeights'
+        else:
+            items_link = 'FittingMinimizersComparisonDetailed'
+    else:
+        items_link = ''
+
+    return items_link
+
+
+def format_cell_value_rst(value, width, color_scale=None, items_link=None):
+    """
+    Build the content string for a table cell, adding style/color tags
+    if required.
+
+    """
+    if not color_scale:
+        if not items_link:
+            value_text = ' {0:.4g}'.format(value).ljust(width, ' ')
+        else:
+            value_text = ' :ref:`{0:.4g} <{1}>`'.format(value, items_link).ljust(width, ' ')
+    else:
+        color = ''
+        for color_descr in color_scale:
+            if value <= color_descr[0]:
+                color = color_descr[1]
+                break
+        if not color:
+            color = color_scale[-1][1]
+        value_text = " :{0}:`{1:.4g}`".format(color, value).ljust(width, ' ')
+
+    return value_text
+
+
+def print_tables_simple_text(minimizers, results_per_test, accuracy_tbl, time_tbl, norm_acc_rankings):
+    """
+    Produces tables in plain ascii, without any markup.  This is much
+    easier to read than RST and useful when developing or just
+    checking the output of the runs from the system test logs.
+
+    """
+
+    header = " ============= Comparison of sum of square errors: ===============\n"
+    header += " =================================================================\n"
+    header += "\n\n"
+
+    for minimiz in minimizers:
+        header += " {0} |".format(minimiz)
+    header += "\n"
+    print(header)
+
+    min_sum_err_sq = np.amin(accuracy_tbl, 1)
+    num_tests = len(results_per_test)
+    results_text = ''
+    for test_idx in range(0, num_tests):
+        results_text += "{0}\t".format(results_per_test[test_idx][0].problem.name)
+        for minimiz_idx, minimiz in enumerate(minimizers):
+            # 'e' format is easier to read in raw text output than 'g'
+            results_text += (" {0:.10g}".
+                             format(results_per_test[test_idx][minimiz_idx].sum_err_sq /
+                                    min_sum_err_sq[test_idx]))
+        results_text += "\n"
+
+    # If some of the fits fail badly, they'll produce 'nan' values =>
+    # 'nan' errors. Requires np.nanmedian() and the like nan-safe
+    # functions.
+
+    # summary lines
+    results_text += '---------------- Summary (accuracy): -------- \n'
+    results_text += 'Best ranking: {0}\n'.format(np.nanmin(norm_acc_rankings, 0))
+    results_text += 'Worst ranking: {0}\n'.format(np.nanmax(norm_acc_rankings, 0))
+    results_text += 'Mean: {0}\n'.format(stats.nanmean(norm_acc_rankings, 0))
+    results_text += 'Median: {0}\n'.format(stats.nanmedian(norm_acc_rankings, 0))
+    results_text += '\n'
+
+    print(results_text)
+
+    print(" ======== Time: =======")
+    time_text = ''
+    for test_idx in range(0, num_tests):
+        time_text += "{0}\t".format(results_per_test[test_idx][0].problem.name)
+        for minimiz_idx, minimiz in enumerate(minimizers):
+            time_text += " {0}".format(results_per_test[test_idx][minimiz_idx].runtime)
+        time_text += "\n"
+
+    min_runtime = np.amin(time_tbl, 1)
+    norm_runtimes = time_tbl / min_runtime[:, None]
+    time_text += '---------------- Summary (run time): -------- \n'
+    time_text += 'Best ranking: {0}\n'.format(np.nanmin(norm_runtimes, 0))
+    time_text += 'Worst ranking: {0}\n'.format(np.nanmax(norm_runtimes, 0))
+    time_text += 'Mean: {0}\n'.format(stats.nanmean(norm_runtimes, 0))
+    time_text += 'Median: {0}\n'.format(stats.nanmedian(norm_runtimes, 0))
+    time_text += '\n'
+
+    print(time_text)
diff --git a/scripts/CompareFitMinimizers/test_problem.py b/scripts/CompareFitMinimizers/test_problem.py
new file mode 100644
index 0000000000000000000000000000000000000000..5f8f80854b625bf736b42f837aae07e557804640
--- /dev/null
+++ b/scripts/CompareFitMinimizers/test_problem.py
@@ -0,0 +1,43 @@
+# Copyright &copy; 2016 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>
+
+
+class FittingTestProblem(object):
+    """
+    Definition of a fitting test problem, normally loaded from a problem definition file.
+    """
+    def __init__(self):
+        self.name = None
+        # If there is an online/documentation link describing this problem
+        self.linked_name = None
+        self.equation = None
+        self.start_x = None
+        self.end_x = None
+        # can be for example the list of starting values from NIST test problems
+        self.starting_values = None
+        # The Mantid X
+        self.data_pattern_in = None
+        # The Mantid Y
+        self.data_pattern_out = None
+        # The Mantid E
+        self.data_pattern_obs_errors = None
+        # The 'certified' or reference sum of squares, if provided (for example
+        # in NIST tests).
+        self.ref_residual_sum_sq = None
diff --git a/scripts/CompareFitMinimizers/test_result.py b/scripts/CompareFitMinimizers/test_result.py
new file mode 100644
index 0000000000000000000000000000000000000000..ed4d663e957c5d031a01edee5738187ea4f25f36
--- /dev/null
+++ b/scripts/CompareFitMinimizers/test_result.py
@@ -0,0 +1,37 @@
+# Copyright &copy; 2016 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>
+
+
+class FittingTestResult(object):
+    """
+    Minimal definition of a class to hold results from a fitting problem test.
+    """
+
+    def __init__(self):
+        self.problem = None
+        self.fit_status = None
+        self.fit_chi2 = None
+        # Workspace with data to fit
+        self.fit_wks = None
+        self.params = None
+        self.errors = None
+        self.sum_err_sq = None
+        # Time it took to run the Fit algorithm
+        self.runtime = None
diff --git a/scripts/CryPowderISIS/cry_ini.py b/scripts/CryPowderISIS/cry_ini.py
index 2ce6567dc149de1266b5981e67df258e5674acea..b01aff73110abbd32471e96a7b6baacd5d06e7e7 100644
--- a/scripts/CryPowderISIS/cry_ini.py
+++ b/scripts/CryPowderISIS/cry_ini.py
@@ -1,4 +1,5 @@
-#pylint: disable=attribute-defined-outside-init,undefined-loop-variable,too-many-arguments,too-many-branches,too-many-instance-attributes,old-style-class,global-variable-not-assigned
+#pylint: disable=attribute-defined-outside-init,undefined-loop-variable,too-many-arguments,too-many-branches,
+#pylint: disable=too-many-instance-attributes,old-style-class,global-variable-not-assigned
 
 import cry_utils
 import re
diff --git a/scripts/DGSPlanner/InstrumentSetupWidget.py b/scripts/DGSPlanner/InstrumentSetupWidget.py
index dd48a3031762e6d00df70de47677720a860c6e21..295b3af826da5abf33a173422d021c67a5a74dfd 100644
--- a/scripts/DGSPlanner/InstrumentSetupWidget.py
+++ b/scripts/DGSPlanner/InstrumentSetupWidget.py
@@ -6,6 +6,7 @@ import numpy
 import matplotlib
 matplotlib.use('Qt4Agg')
 matplotlib.rcParams['backend.qt4']='PyQt4'
+#the following matplotlib imports cannot be placed before the use command, so we ignore flake8 warnings
 from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas # noqa
 from matplotlib.figure import Figure # noqa
 from mpl_toolkits.mplot3d import Axes3D # noqa
diff --git a/scripts/DiamondAttenuationCorrection/FitTrans.py b/scripts/DiamondAttenuationCorrection/FitTrans.py
new file mode 100644
index 0000000000000000000000000000000000000000..e18aeebdae721a3b435c6f046bc4b3b1968f57f2
--- /dev/null
+++ b/scripts/DiamondAttenuationCorrection/FitTrans.py
@@ -0,0 +1,1304 @@
+'''
+1. all the functions are defined and built consistently.
+
+
+
+
+Data types:
+- Use only numpy arrays to ensure consistency across formatting and type
+*** x, x0 = parameters vector - 1D numpy array
+*** setang1, setang2 = angles for refinement - 1D numpy arrays, 3 elements
+*** hkl1, hkl2 = numpy arrays (3 columns) having all the hkl indices from the 2 diamonds
+*** UB1, UB2 = numpy arrays (3x3) holds UB matrices from input files
+***
+'''
+# Import all needed libraries
+from matplotlib import pyplot as plt
+import numpy as np
+import itertools as itt
+import UBMatrixGenerator as UBMG
+import scipy.optimize as sp
+
+__author__ = 'cip'
+
+# Define global variables
+global hkl1, hkl2
+global UB1, pkcalcint1
+global UB2, pkcalcint2
+global pktype
+global lam, y, e, TOF
+global L1
+global ttot
+global fxsamediam
+global neqv1, eqvlab1, neqv2, eqvlab2
+global difa, function_verbose
+global figure_name_attenuation, run_number
+
+
+def dlmread(filename):
+    '''
+    Function to read parameters from file after previous fit
+    '''
+    content = []
+    with open(filename, "r") as f:
+        for line in f.readlines():
+            content.append(float(line))
+    return np.array(content)
+
+
+def calcDspacing(a, b, c, alp, bet, gam, h, k, l):
+    '''
+    %CALCDSPACING for general unit cell: a,b,c,alp,bet,gam returns d-spacing for
+    %reflection h,k,l
+    %
+    '''
+    ca = np.cos(np.radians(alp))
+    cb = np.cos(np.radians(bet))
+    cg = np.cos(np.radians(gam))
+    sa = np.sin(np.radians(alp))
+    sb = np.sin(np.radians(bet))
+    sg = np.sin(np.radians(gam))
+
+    oneoverdsq = (1.0 - ca**2 - cb**2 - cg**2 + 2 * ca * cb * cg)**(-1) * \
+                 ((h * sa / a)**2 + (k * sb / b)**2 + (l * sg / c)**2
+                  + (2 * k * l / (b * c)) * (cb * cg - ca) + (2 * l * h / (c * a)) * (cg * ca - cb)
+                  + (2 * h * k / (a * b)) * (ca * cb - cg))
+
+    d = np.sqrt(1.0 / oneoverdsq)
+    return d
+
+
+def genhkl(hmin, hmax, kmin, kmax, lmin, lmax):
+    '''
+    genhkl generates array of hkl values
+    total number of points will be (hmax-hmin)
+    '''
+    hvals = np.arange(hmin, hmax + 1, 1)
+    kvals = np.arange(kmin, kmax + 1, 1)
+    lvals = np.arange(lmin, lmax + 1, 1)
+
+    nh = len(hvals)
+    nk = len(kvals)
+    nl = len(lvals)
+
+    l = 0
+    hkl = np.zeros(shape=(nh * nl * nk, 3))
+    for i in range(nh):
+        for j in range(nk):
+            for k in range(nl):
+                hkl[l][0] = hvals[i]
+                hkl[l][1] = kvals[j]
+                hkl[l][2] = lvals[k]
+                l += 1
+    return hkl
+
+
+def mod(a, b):
+    return a % b
+
+
+def forbidden(h, k, l):
+    '''
+    %returns logical positive if this hkl is fobidden according to
+    %   diamond reflections conditions....
+    '''
+    ah = abs(h)
+    ak = abs(k)
+    al = abs(l)
+
+    if ((h == 0) and (k == 0) and (l == 0)):
+        result = 1
+        boolresult = bool(result)
+        return boolresult
+    else:
+        result = 0
+
+    if ((ah == 2) and (ak == 2) and (al == 2)):  # allowed, but vanishingly weak
+        result = 1
+        boolresult = bool(result)
+        return boolresult
+    else:
+        result = 0
+
+    # condition 1
+    if ((h != 0)and (k != 0) and (l != 0)):  # general hkl
+        term1 = h + k
+        term2 = h + l  # all have to be even
+        term3 = k + l
+        if not((term1 % 2) == 0 and (term2 % 2) == 0 and (term3 % 2) == 0):
+            result = 1
+            boolresult = bool(result)
+            return boolresult
+        else:
+            result = 0
+
+    #% condition 2
+    if ((h == 0) and (k != 0) and (l != 0)):  # 0kl reflections
+        term1 = k + l
+        mod4 = mod(term1, 4)
+        if not(mod4 == 0 and mod(k, 2) == 0 and mod(l, 2) == 0):
+            result = 1
+            boolresult = bool(result)
+            return boolresult
+        else:
+            result = 0
+
+    # condition 3
+    if (h == k):  # hhl reflections
+        if not(mod(h + l, 2) == 0):
+            result = 1
+            boolresult = bool(result)
+            return boolresult
+        else:
+            result = 0
+
+    # condition 4
+    if ((h == 0) and (k == 0) and (l != 0)):   # 00l reflections not including 000
+        mod4 = mod(l, 4)
+        if not(mod4 == 0):
+            result = 1
+            boolresult = bool(result)
+            return boolresult
+        else:
+            result = 0
+
+    boolresult = bool(result)
+    return boolresult
+
+
+def allowedDiamRefs(hmin, hmax, kmin, kmax, lmin, lmax):
+    '''
+    %UNTITLED6 generates a list of allowed reflections for diamond between
+    %   limits provided sorted descending according to d-spacing
+    '''
+    # obtain all hkl within limits...
+    allhkl = genhkl(hmin, hmax, kmin, kmax, lmin, lmax)
+    # now purge those violating extinction conditions...
+
+    n = len(allhkl)
+
+    # set all forbidden hkl's to zero
+    # hkl or lhk or klh
+    for i in range(n):
+        h = allhkl[i][0]
+        k = allhkl[i][1]
+        l = allhkl[i][2]
+        if forbidden(h, k, l) or forbidden(l, h, k) or forbidden(k, l, h):
+            allhkl[i] = 0  # set equal to zero
+
+    k = 0
+    d = []  # np.zeros(0)
+    # create new array with all h!=0 k!=0 l!=0
+    hkl = np.zeros(shape=(0, 3))
+    for i in range(n):
+        if not(allhkl[i][0] == 0 and allhkl[i][1] == 0 and allhkl[i][2] == 0):
+            hkl = np.vstack((hkl, [allhkl[i][0], allhkl[i][1], allhkl[i][2]]))
+            d.append(calcDspacing(3.56683, 3.56683, 3.56683, 90,
+                                  90, 90, hkl[k][0], hkl[k][1], hkl[k][2]))
+            k += 1
+    d = np.array(d)
+
+    # ORDER hkl according to d-spacing
+    B = sorted(d)[::-1]  # returns d sorted in descending order
+    IX = np.argsort(d)[::-1]  # and corresponding elements
+
+    sorthkl = np.zeros(shape=(k, 3))
+    for i in range(k):
+        sorthkl[i] = hkl[IX[i]]
+        d[i] = B[i]
+        # print('hkl: {0:0.3f} {1:0.3f} {2:0.3f} d-spacing: {3:0.3f} A'.format(sorthkl[i][0], sorthkl[i][1],
+        #    sorthkl[i][2], d[i]))
+
+    return sorthkl
+
+
+def getISAWub(fullfilename):
+    '''
+    %getISAWub reads UB determined by ISAW and stored in file "fname"
+    %   Detailed explanation goes here
+
+
+    % [filename pathname ~] = ...
+    %     uigetfile('*.dat','Choose UB file (generated by ISAW)');
+    % fullfilename = [pathname filename];
+    '''
+    fileID = fullfilename
+    if fileID == 1:
+        print('Error opening file: ' + fullfilename)
+    f = open(fileID, "r")
+    lines = f.readlines()
+    f.close()
+
+    # Build UB matrix and lattice
+    UB = np.zeros(shape=(3, 3))
+    lattice = np.zeros(shape=(2, 6))
+    for i in range(3):
+        UB[i][0], UB[i][1], UB[i][2] = lines[i].split()
+    UB = UB.transpose()
+    for i in range(3, 5):
+        lattice[i - 3][0], lattice[i - 3][1], lattice[i - 3][2], lattice[i - 3][3], lattice[i - 3][4], lattice[i - 3][5], \
+            non = lines[i].split()
+
+    print('Successfully got UB and lattice')
+
+    return UB, lattice
+
+
+def pkintread(hkl, loc):
+    '''
+    %reads calculated Fcalc and converts to
+    %Fobs using Buras-Gerard Eqn.
+    %inputs are hkl(nref,3) and
+    % loc(nref,3), which contains, lambda, d-spacing and ttheta for
+    % each of the nref reflections.
+
+    % get Fcalcs for diamond, generated by GSAS (using lattice parameter 3.5668
+    % and Uiso(C) = 0.0038
+
+    % disp('in pkintread');
+
+
+    returns pkint = np. array - 1D vector
+    '''
+    #A = np.genfromtxt('diamond_reflist.csv', delimiter=',', skip_header=True)
+    # print A
+    A = np.array([[1.00000000e+00,   1.00000000e+00,   1.00000000e+00,   8.00000000e+00,
+                   2.06110000e+00,   5.54000000e+04],
+                  [2.00000000e+00,   2.00000000e+00,   0.00000000e+00,   1.20000000e+01,
+                   1.26220000e+00,   7.52000000e+04],
+                  [3.00000000e+00,   1.00000000e+00,   1.00000000e+00,   2.40000000e+01,
+                   1.07640000e+00,   2.98000000e+04],
+                  [2.00000000e+00,   2.00000000e+00,   2.00000000e+00,   8.00000000e+00,
+                   1.03060000e+00,   2.50000000e-25],
+                  [4.00000000e+00,   0.00000000e+00,   0.00000000e+00,   6.00000000e+00,
+                   8.92500000e-01,   4.05000000e+04],
+                  [3.00000000e+00,   3.00000000e+00,   1.00000000e+00,   2.40000000e+01,
+                   8.19000000e-01,  1.61000000e+04],
+                  [4.00000000e+00,   2.00000000e+00,   2.00000000e+00,   2.40000000e+01,
+                   7.28700000e-01,   2.18000000e+04],
+                  [5.00000000e+00,   1.00000000e+00,   1.00000000e+00,   2.40000000e+01,
+                   6.87000000e-01,   8.64000000e+03],
+                  [3.00000000e+00,   3.00000000e+00,   3.00000000e+00,   8.00000000e+00,
+                   6.87000000e-01,   8.64000000e+03],
+                  [4.00000000e+00,   4.00000000e+00,   0.00000000e+00,  1.20000000e+01,
+                   6.31100000e-01,   1.17000000e+04],
+                  [5.00000000e+00,   3.00000000e+00,   1.00000000e+00,   4.80000000e+01,
+                   6.03400000e-01,   4.65000000e+03],
+                  [4.00000000e+00,   4.00000000e+00,   2.00000000e+00,   2.40000000e+01,
+                   5.95000000e-01,   1.83000000e-12],
+                  [6.00000000e+00,   2.00000000e+00,   0.00000000e+00,   2.40000000e+01,
+                   5.64500000e-01,   6.31000000e+03],
+                  [5.00000000e+00,   3.00000000e+00,   3.00000000e+00,   2.40000000e+01,
+                   5.44400000e-01,   2.50000000e+03],
+                  [6.00000000e+00,   2.00000000e+00,   2.00000000e+00,   2.40000000e+01,
+                   5.38200000e-01,   8.80000000e-26],
+                  [4.00000000e+00,   4.00000000e+00,   4.00000000e+00,   8.00000000e+00,
+                   5.15300000e-01,   3.40000000e+03],
+                  [5.00000000e+00,   5.00000000e+00,   1.00000000e+00,   2.40000000e+01,
+                   4.99900000e-01,   1.35000000e+03],
+                  [7.00000000e+00,   1.00000000e+00,   1.00000000e+00,   2.40000000e+01,
+                   4.99900000e-01,   1.35000000e+03],
+                  [6.00000000e+00,   4.00000000e+00,   2.00000000e+00,   4.80000000e+01,
+                   4.77100000e-01,   1.83000000e+03],
+                  [7.00000000e+00,   3.00000000e+00,   1.00000000e+00,   4.80000000e+01,
+                   4.64800000e-01,   7.25000000e+02],
+                  [5.00000000e+00,   5.00000000e+00,   3.00000000e+00,   2.40000000e+01,
+                   4.64800000e-01,   7.25000000e+02],
+                  [8.00000000e+00,   0.00000000e+00,   0.00000000e+00,   6.00000000e+00,
+                   4.46200000e-01,   9.84000000e+02],
+                  [7.00000000e+00,   3.00000000e+00,   3.00000000e+00,   2.40000000e+01,
+                   4.36100000e-01,   3.90000000e+02],
+                  [6.00000000e+00,   4.00000000e+00,   4.00000000e+00,   2.40000000e+01,
+                   4.32900000e-01,   1.53000000e-13],
+                  [6.00000000e+00,   6.00000000e+00,   0.00000000e+00,   1.20000000e+01,
+                   4.20700000e-01,   5.30000000e+02],
+                  [8.00000000e+00,   2.00000000e+00,   2.00000000e+00,   2.40000000e+01,
+                   4.20700000e-01,   5.30000000e+02],
+                  [5.00000000e+00,   5.00000000e+00,   5.00000000e+00,   8.00000000e+00,
+                   4.12200000e-01,   2.10000000e+02],
+                  [7.00000000e+00,   5.00000000e+00,   1.00000000e+00,   4.80000000e+01,
+                   4.12200000e-01,   2.10000000e+02],
+                  [6.00000000e+00,   6.00000000e+00,   2.00000000e+00,   2.40000000e+01,
+                   4.09500000e-01,   1.98000000e-26],
+                  [8.00000000e+00,   4.00000000e+00,   0.00000000e+00,   2.40000000e+01,
+                   3.99100000e-01,   2.85000000e+02],
+                  [7.00000000e+00,   5.00000000e+00,   3.00000000e+00,   4.80000000e+01,
+                   3.91900000e-01,   1.13000000e+02],
+                  [9.00000000e+00,   1.00000000e+00,   1.00000000e+00,   2.40000000e+01,
+                   3.91900000e-01,   1.13000000e+02],
+                  [8.00000000e+00,   4.00000000e+00,   2.00000000e+00,   4.80000000e+01,
+                   3.89500000e-01,   4.44000000e-14],
+                  [6.00000000e+00,   6.00000000e+00,   4.00000000e+00,   2.40000000e+01,
+                   3.80600000e-01,   1.53000000e+02],
+                  [9.00000000e+00,   3.00000000e+00,   1.00000000e+00,   4.80000000e+01,
+                   3.74200000e-01,   6.08000000e+01],
+                  [8.00000000e+00,   4.00000000e+00,   4.00000000e+00,   2.40000000e+01,
+                   3.64400000e-01,   8.26000000e+01],
+                  [9.00000000e+00,   3.00000000e+00,   3.00000000e+00,   2.40000000e+01,
+                   3.58800000e-01,   3.27000000e+01],
+                  [7.00000000e+00,   5.00000000e+00,   5.00000000e+00,   2.40000000e+01,
+                   3.58800000e-01,   3.27000000e+01],
+                  [7.00000000e+00,   7.00000000e+00,   1.00000000e+00,   2.40000000e+01,
+                   3.58800000e-01,   3.27000000e+01]])
+
+    diamd = A[:, 4]
+    #diamMult = A[:, 3] # unused variable
+    diamFCalcSq = A[:, 5]
+    nref = hkl.shape[0]
+    #% disp(['there are: ' num2str(nref) ' reflections']);
+    #% whos loc
+
+    '''
+    % [i,j] = size(x);
+    % dipspec = zeros(i,j); %array containing dip spectrum
+    % difspec = zeros(i,j); %array containing diffraction spectrum
+    % d = x/sqrt(2);    %dspacings for this lamda range at 90 degrees
+
+    % In order to calculate the scattered intensity I from the Fcalc^2, need to
+    % apply the Buras-Gerward formula:
+    %
+    % Fcalc^2 = I*2*sin(theta)^2/(lamda^2*A*E*incFlux*detEffic)
+    '''
+    pkint = np.zeros(nref)
+
+    for i in range(nref):
+        if loc[i][0] > 0:
+            #% satisfies Bragg condition (otherwise ignore)
+            Fsq = Fsqcalc(loc[i][1], diamd, diamFCalcSq)
+            #% Fsq = 1;
+            L = (np.sin(np.radians(loc[i][2] / 2.0)))**2  # Lorentz correction
+            R = 1.0  # %dipLam(i)^4; %reflectivity correction
+            A = 1.0  # %Absorption correction
+            Ecor = 1
+            pkint[i] = Fsq * R * A / (L * Ecor)  # %scattered intensity
+
+    '''
+    % whos difspec
+    % whos van
+    % whos dipspec
+
+    % difspec = difspec.*van;
+    % dipspec = dipspec.*van;
+
+    % figure(1)
+    % plot(d,difspec)
+    '''
+    return pkint
+
+
+def Fsqcalc(d, diamd, diamFCalcSq):
+    '''
+    % diamond reflections are identified according to their d-spacing
+    % and corresponding calculated Fsq are returned
+
+    % global sf111 sf220 sf311 sf400 sf331
+    '''
+    #n = len(diamd) # unused variable
+    ref = d
+    dif = abs(diamd - ref)
+    i = dif.argmin(0)  # i is index of diamd closest to d
+    Fsq = diamFCalcSq[i]
+    return Fsq
+
+
+def pkposcalc(hkl, UB, setang):
+    '''
+    % calculates some useful numbers from (ISAW calculated) UB
+    % hkl is a 2D array containing all hkl's
+    %
+    '''
+
+    ome = setang[0]
+    phi = setang[1]
+    chi = setang[2]
+    thkl = hkl.transpose()
+
+    Q = UB.dot(thkl)
+
+    Rx = np.array([[1, 0, 0], [0, np.cos(np.radians(ome)), -np.sin(np.radians(ome))],
+                   [0, np.sin(np.radians(ome)), np.cos(np.radians(ome))]])
+    Ry = np.array([[np.cos(np.radians(phi)), 0, np.sin(np.radians(phi))], [0, 1, 0],
+                   [-np.sin(np.radians(phi)), 0, np.cos(np.radians(phi))]])
+    Rz = np.array([[np.cos(np.radians(chi)), -np.sin(np.radians(chi)), 0],
+                   [np.sin(np.radians(chi)), np.cos(np.radians(chi)), 0], [0, 0, 1]])
+    Rall = Rz.dot(Ry).dot(Rx)  # all three rotations
+    # str = sprintf('initial: %6.4f %6.4f %6.4f',Q);
+    # disp(str)
+    Q = Rall.dot(Q)
+    magQ = np.sqrt((Q * Q).sum(axis=0))
+    '''
+    # str = sprintf('Scattering vector: %6.4f %6.4f %6.4f',Q);
+    # if show==1
+    #    disp(str)
+    # end
+    % %calculate angle with incident beam i.e. (-1 0 0)
+    % beam = [1 0 0];
+    % alpha = acosd(dot(Q,beam)/norm(Q));
+    % str = sprintf('Angle scat. vect. to beam: %6.4f',alpha);
+    % if show==1
+    %     disp(str)
+    % end
+    % beam = [0 1 0];
+    % alpha = acosd(dot(Q,beam)/norm(Q));
+    % str = sprintf('Angle scat. vect. to y: %6.4f',alpha);
+    % if show==1
+    %     disp(str)
+    % end
+    % beam = [0 0 1];
+    % alpha = acosd(dot(Q,beam)/norm(Q));
+    % str = sprintf('Angle scat. vect. to z: %6.4f',alpha);
+    % if show==1
+    %     disp(str)
+    % end
+    % Q is a vector pointing to the reciprocal lattice point corresponding to
+    % vector hkl. The coordinate system is in frame I that is right handed with x pointing along
+    % the beam direction and z vertical.
+    '''
+    d = (1.0 / magQ)  # by definition (note ISAW doesn't use 2pi factor)
+    d = d.transpose()
+    '''
+    % In frame I the incident beam vector will be of the form [k 0 0]
+    % where k = 1/lambda
+    % by considering the scattering relation that Q=k_f-k_i, can show that the dot product of
+    % -k_i.Q gives the scattering angle 2theta, thus:
+    '''
+    ttheta = 180 - 2 * np.degrees(np.arccos(-Q[0, :] / magQ))
+    ttheta = ttheta.transpose()
+    # and Bragg's law gives:
+    lambda_1 = 2 * d * np.sin(np.radians(ttheta / 2))
+    lambda_1 = lambda_1.transpose()
+    '''
+    %
+    %   str = sprintf('for hkl: %3i%3i%3i',hkl(1),hkl(2),hkl(3));
+    % disp(str)
+    % str = sprintf('d-spacing is: %6.4f',d);
+    % disp(str)
+    % str = sprintf('ttheta is: %6.4f',ttheta);
+    % disp(str)
+    % str = sprintf('lambda is: %6.4f',lambda);
+    % disp(str)
+    '''
+
+    return lambda_1, d, ttheta
+
+
+def getMANTIDdat_keepbinning(csvfile):
+    '''
+    getMANTIDdat reads data from mantid "SaveAscii" output
+    %   input file name should be 'csvfilename'.csv
+    %   data are returned with binning (xmin:xbin:xmax)
+
+    returns TOF, y , e
+    '''
+    fid = open(csvfile, "r")
+    lines = fid.readlines()
+    x = []
+    y = []
+    e = []
+    if fid < 0:
+        print('Error opening file: ' + csvfile)
+    for i in range(1, len(lines)):
+        a, b, c = lines[i].split(",")
+        x.append(float(a))
+        y.append(float(b))
+        e.append(float(c))
+    fid.close()
+    x = np.array(x)
+    y = np.array(y)
+    e = np.array(e)
+
+    return x, y, e
+
+
+def findeqvs(hkl):
+    '''
+    FINDEQVS runs through array of hkls and labels those that are equivalent
+    %in the m-3m point group.
+    %
+    % there are n reflections.
+    % hkl has dimensions nx3
+    % eqvlab has dimensions nx1
+    '''
+    n, m = hkl.shape
+    eqvlab = np.zeros(n)
+    lab = 1
+    for i in range(n):
+        if eqvlab[i] == 0:  # then it's not been checked yet, so check it
+            eqvlab[i] = lab
+            refhkl = np.array([abs(hkl[i][0]), abs(hkl[i][1]), abs(hkl[i][2])])
+            for j in range(i + 1, n):  # check remaining indices
+                comphkl = np.array(
+                    [abs(hkl[j][0]), abs(hkl[j][1]), abs(hkl[j][2])])
+                # all possible permutations
+                permcomphkl = list(itt.permutations(comphkl))
+                nperm = len(permcomphkl)
+                for k in range(nperm):
+                    if refhkl[0] == permcomphkl[k][0] and refhkl[1] == permcomphkl[k][1] and \
+                            refhkl[2] == permcomphkl[k][2]:
+                        eqvlab[j] = lab
+        lab += 1
+
+    return eqvlab, lab
+
+
+def showx3(x):
+    '''
+    %showx displays all parameters for refinement in reasonably intelligible
+    %form
+    Input : parameter vector and the sets of hkl indices for the diamons
+    '''
+    global hkl1, hkl2
+    global UB1, pkcalcint1
+    global UB2, pkcalcint2
+    global pktype
+    global lam, y, e, TOF
+    global L1
+    global ttot
+    global fxsamediam
+    global neqv1, eqvlab1, neqv2, eqvlab2
+    global difa, function_verbose
+
+    #nref1 = hkl1.shape[0]  # % number of reflections to integrate over # unused variable
+    #nref2 = hkl2.shape[0]  # % number of reflections to integrate over # unused variable
+    # % returns array with same dim as input labelling equivs
+    eqvlab1, neqv1 = findeqvs(hkl1)
+    eqvlab2, neqv2 = findeqvs(hkl2)
+    setang1 = x[0:3]
+    pkmult1 = x[3:4 + neqv1 - 1]
+    setang2 = x[4 + neqv1 - 1:6 + neqv1]
+    pkmult2 = x[6 + neqv1:7 + neqv1 + neqv2 - 1]
+    sf = x[neqv1 + neqv2 + 7 - 1]
+    pkwid1 = x[neqv1 + neqv2 + 8 - 1]
+    #bgd = x[neqv1 + neqv2 + 8 - 1:neqv1 + neqv2 + 9 + 2 - 1] # unused variable
+    pkwid2 = x[neqv1 + neqv2 + 10]
+    # % if diamond intensities the same, allow single scale f
+    relsf = x[neqv1 + neqv2 + 11]
+    delam = x[neqv1 + neqv2 + 12]
+    L2 = x[neqv1 + neqv2 + 13]
+
+    print('_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/\n')
+    print('Setting angles diam {0} : \nalp {1} bet {2} gam {3} \n'.format(
+        1, setang1[0], setang1[1], setang1[2]))
+    print('pkmult1: {0}\n'.format(pkmult1))
+    print('Setting angles diam {0} : \nalp {1} bet {2} gam {3} \n'.format(
+        2, setang2[0], setang2[1], setang2[2]))
+    print('pkmult2: {0}\n'.format(pkmult2))
+    print('Scale factor: {0}\n'.format(sf))
+    print('pkwid1: {0}\n'.format(pkwid1))
+    print('pkwid2: {0}\n'.format(pkwid2))
+    print('Rel. scale factor : {0}\n'.format(relsf))
+    print('Lambda multiplier: {0}\n'.format(delam))
+    print('L2 sample to detector: {0} m\n'.format(L2))
+    print('_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/\n')
+
+
+def SimTransOutput3(name, x):
+    '''
+    %SimTrans calculates transmission spectrum from two crystals
+    %   lam - array containing wavelengths to calc over
+    %   hkl - contains all Nref hkl's that calculation is performed for
+    %   bgd - array containing coefficients of polynomial for background
+    %   sf - overall scale factor
+    %   pktype - 1 = gauss; 2 = lorentz; ...
+    %   UB1 - UB matrix for first crystal
+    %   setang1 - setting angles for first crystal (deviations from ideal UB
+    %               location).
+    %   pkpars1 - position(lambda), position(d-spacing), position(ttheta), width, intensity for each Nref reflections
+    %   UB2,setang2,pkpars2 - as above, for second crystal
+    %
+    % M. Guthrie 21st Jan 2014
+    %
+    % calculate background profile
+    % determine number of coeffs bgd
+    '''
+    global hkl1, hkl2
+    global UB1, pkcalcint1
+    global UB2, pkcalcint2
+    global pktype
+    global lam, y, e, TOF
+    global L1
+    global ttot
+    global fxsamediam
+    global neqv1, eqvlab1, neqv2, eqvlab2
+    global difa, function_verbose
+    global figure_name_attenuation, run_number
+
+    nref1 = hkl1.shape[0]  # % number of reflections to integrate over
+    nref2 = hkl2.shape[0]  # % number of reflections to integrate over
+    # % returns array with same dim as input labelling equivs
+    eqvlab1, neqv1 = findeqvs(hkl1)
+    eqvlab2, neqv2 = findeqvs(hkl2)
+
+    setang1 = x[0:3]
+    pkmult1 = x[3:4 + neqv1 - 1]
+    setang2 = x[4 + neqv1 - 1:6 + neqv1]
+    sf = x[neqv1 + neqv2 + 7 - 1]
+    pkwid1 = x[neqv1 + neqv2 + 7]
+    bgd = x[neqv1 + neqv2 + 8:neqv1 + neqv2 + 9 + 2 - 1]
+    pkwid2 = x[neqv1 + neqv2 + 10]
+    # % if diamond intensities the same, allow single scale f
+    relsf = x[neqv1 + neqv2 + 11]
+    if fxsamediam == 1:
+        x[6 + neqv1:7 + neqv1 + neqv2 - 1] = x[3:4 + neqv2 - 1] * relsf
+        pkmult2 = x[6 + neqv1:7 + neqv1 + neqv2 - 1]
+    else:
+        pkmult2 = x[6 + neqv1:7 + neqv1 + neqv2 - 1]
+    delam = x[neqv1 + neqv2 + 12]
+    L2 = x[neqv1 + neqv2 + 13]
+
+    shftlam = 0.0039558 * TOF / (L1 + L2) + difa * (TOF**2)
+    # number of lambda points to calculate over
+    npt = shftlam.shape[0]
+    # calculate information for peaks for crystal 1 using hkl,UB1, setang,
+    # pkpos
+    a, b, c = pkposcalc(hkl1, UB1, setang1)
+    pkpars1 = np.column_stack((a, b, c))
+    # calculate information for peaks for crystal 2 using hkl,UB1, setang,
+    # pkpos
+    a, b, c = pkposcalc(hkl2, UB2, setang2)
+    pkpars2 = np.column_stack((a, b, c))
+
+    # generate nptx,nco array containing, x^0,x^1,x^2,...x^nco for
+    # all nonzero background coefficients
+    bgdco = np.where(bgd != 0)[0]
+    nco = bgdco.shape[0]
+    nonzerobgd = np.zeros(nco)
+
+    X = np.ones(shape=(nco, npt))
+    for i in range(nco):
+        X[i, :] = shftlam ** (bgd[bgdco[i]] - 1)
+        nonzerobgd[i] = bgd[bgdco[i]]
+
+    # calculate background profile by multiplying this with coefficients
+    # themselves
+    bgdprof = nonzerobgd.dot(X)
+    #bgdprof = np.outer(nonzerobgd, X)
+    # print bgdprof
+    #bgdprof = bgdprof[0, :]
+    # calculate peaks for crystal 1
+
+    t1 = np.zeros(npt)  # initialise array containing profile
+    for i in range(nref1):
+        if pktype == 1:
+            pkpars1[i][0] = pkpars1[i][0] * delam  # linear lambda shift
+            sig = pkwid1 * pkpars1[i][0] + pkwid2 * \
+                (pkpars1[i][0]**2.)  # const del(lambda)/lambda
+            extScl = pkpars1[i][0]**0  # lambda dependent extinction effect
+            t1 = t1 - extScl * pkmult1[int(eqvlab1[i])] * pkcalcint1[i] * (
+                np.exp(-((shftlam - pkpars1[i][0])**2.) / (2 * (sig**2))))
+
+    # calculate peaks for crystal 2
+    t2 = np.zeros(npt)  # initialise array containing profile
+    for i in range(nref2):
+        if pktype == 1:
+            pkpars2[i][0] = pkpars2[i][0] * delam  # linear lambda shift
+            sig = pkwid1 * pkpars2[i][0] + pkwid2 * \
+                (pkpars2[i][0]**2.)  # const del(lambda)/lambda
+            extScl = pkpars2[i][0]**0  # lambda dependent extinction effect
+            t2 = t2 - extScl * pkmult2[int(eqvlab2[i])] * pkcalcint2[i] * (
+                np.exp(-(shftlam - pkpars2[i][0])**2. / (2 * (sig**2))))
+
+    # calculate final profile
+    ttot = (bgdprof + sf * t1) * (bgdprof + sf * t2)
+    #t1 = 1.0;
+    # t2 = 1.0;
+    # introduce weighting function and calc chi2...
+    w = np.ones(len(shftlam))  # equal weighting everywhere
+    #i1 = np.where(shftlam > 2.15)[0][0]
+    #j1 = np.where(shftlam > 2.65)[0][0]
+    # w[i1:j1] = 5 #extra weighting in region of first peaks
+    # i1 = find(lam>1.68,1,'first');
+    # j1 = find(lam>2.05,1,'first');
+    # w(i1:j1)=5; %extra weighting but not too much
+
+    resid = (y - ttot) * w
+    chi2 = np.sum(resid**2. / (2 * e**2)) / npt
+
+    output = 1
+    if output == 1:
+        diam1trans = sf * t1 + bgdprof
+        diam2trans = sf * t2 + bgdprof
+        out = np.column_stack((shftlam, diam1trans, diam2trans, ttot, y))
+        np.savetxt(name, out, delimiter=',')
+
+    figure_name_attenuation = 'Attenuation ' + run_number
+
+    plt.figure(figure_name_attenuation)
+    plt.plot(shftlam, ttot, 'r', label='Total att.')
+    plt.plot(shftlam, diam1trans, 'k', label='Diam 1 att.')
+    plt.plot(shftlam, diam2trans, 'b', label='Diam 2 att.')
+    plt.legend(bbox_to_anchor=(0., 1.02, 1., .102), loc=3,
+               ncol=3, mode="expand", borderaxespad=0.)
+    plt.xlabel('Wavelength (A)')
+    plt.ylabel('Transmission')
+    plt.grid()
+    for i in range(len(pkpars1)):
+        plt.arrow(pkpars1[i, 0] * delam, 1.1, 0.0, 0.025,
+                  fc="k", ec="k", head_width=0, head_length=0)
+    for i in range(len(pkpars2)):
+        plt.arrow(pkpars2[i, 0] * delam, 1.15, 0.0, 0.025,
+                  fc="k", ec="k", head_width=0, head_length=0)
+    plt.xlim(1, 2.7)
+    plt.ylim(0, 1.2)
+    plt.show()
+
+    return chi2
+
+
+def SimTrans3(x):
+    '''
+    %SimTrans calculates transmission spectrum from two crystals
+    %   lam - array containing wavelengths to calc over
+    %   hkl - contains all Nref hkl's that calculation is performed for
+    %   bgd - array containing coefficients of polynomial for background
+    %   sf - overall scale factor
+    %   pktype - 1 = gauss; 2 = lorentz; ...
+    %   UB1 - UB matrix for first crystal
+    %   setang1 - setting angles for first crystal (deviations from ideal UB
+    %               location).
+    %   pkpars1 - position(lambda), position(d-spacing), position(ttheta), width, intensity for each Nref reflections
+    %   UB2,setang2,pkpars2 - as above, for second crystal
+    %
+    % M. Guthrie 21st Jan 2014
+    %
+    % calculate background profile
+    % determine number of coeffs bgd
+    %
+    % version 2 constrains intensities for equivalent dips to be the same
+    % M. Guthrie 3 April 2014
+    %
+    % M. Guthrie 7 April 2014, realised I was making an (obvious) mistake by
+    % adding the transmissions from the two diamonds. Clearly, they should be
+    % multiplied. I've implemented the change...will see what difference it
+    % makes.
+    %
+    % M. Guthrie 9 April 2014, introduced possiblity to refine L2 and also a
+    % scale factor for calculated dip wavelengths (to account for diamond
+    % compressibility).
+    '''
+    global hkl1, hkl2
+    global UB1, pkcalcint1
+    global UB2, pkcalcint2
+    global pktype
+    global lam, y, e, TOF
+    global L1
+    global ttot
+    global fxsamediam
+    global neqv1, eqvlab1, neqv2, eqvlab2
+    global difa, function_verbose
+
+    nref1 = hkl1.shape[0]  # % number of reflections to integrate over
+    nref2 = hkl2.shape[0]  # % number of reflections to integrate over
+    # % returns array with same dim as input labelling equivs
+    eqvlab1, neqv1 = findeqvs(hkl1)
+    eqvlab2, neqv2 = findeqvs(hkl2)
+
+    setang1 = x[0:3]
+    pkmult1 = x[3:4 + neqv1 - 1]
+    setang2 = x[4 + neqv1 - 1:6 + neqv1]
+    sf = x[neqv1 + neqv2 + 7 - 1]
+    pkwid1 = x[neqv1 + neqv2 + 7]
+    bgd = x[neqv1 + neqv2 + 8:neqv1 + neqv2 + 9 + 2 - 1]
+    pkwid2 = x[neqv1 + neqv2 + 10]
+    # % if diamond intensities the same, allow single scale f
+    relsf = x[neqv1 + neqv2 + 11]
+    if fxsamediam == 1:
+        x[6 + neqv1:7 + neqv1 + neqv2 - 1] = x[3:4 + neqv2 - 1] * relsf
+        pkmult2 = x[6 + neqv1:7 + neqv1 + neqv2 - 1]
+    else:
+        pkmult2 = x[6 + neqv1:7 + neqv1 + neqv2 - 1]
+    delam = x[neqv1 + neqv2 + 12]
+    L2 = x[neqv1 + neqv2 + 13]
+
+    shftlam = 0.0039558 * TOF / (L1 + L2) + difa * (TOF**2)
+    # number of lambda points to calculate over
+    npt = shftlam.shape[0]
+    # calculate information for peaks for crystal 1 using hkl,UB1, setang,
+    # pkpos
+    a, b, c = pkposcalc(hkl1, UB1, setang1)
+    pkpars1 = np.column_stack((a, b, c))
+    # calculate information for peaks for crystal 2 using hkl,UB1, setang,
+    # pkpos
+    a, b, c = pkposcalc(hkl2, UB2, setang2)
+    pkpars2 = np.column_stack((a, b, c))
+
+    # generate nptx,nco array containing, x^0,x^1,x^2,...x^nco for
+    # all nonzero background coefficients
+    bgdco = np.where(bgd != 0)[0]
+    nco = bgdco.shape[0]
+    nonzerobgd = np.zeros(nco)
+
+    X = np.ones(shape=(nco, npt))
+    for i in range(nco):
+        X[i, :] = shftlam ** (bgd[bgdco[i]] - 1)
+        nonzerobgd[i] = bgd[bgdco[i]]
+
+    # calculate background profile by multiplying this with coefficients
+    # themselves
+    bgdprof = nonzerobgd.dot(X)
+    #bgdprof = np.outer(nonzerobgd, X)
+    # print bgdprof
+    #bgdprof = bgdprof[0, :]
+    # calculate peaks for crystal 1
+
+    t1 = np.zeros(npt)  # initialise array containing profile
+    for i in range(nref1):
+        if pktype == 1:
+            pkpars1[i][0] = pkpars1[i][0] * delam  # linear lambda shift
+            sig = pkwid1 * pkpars1[i][0] + pkwid2 * \
+                (pkpars1[i][0]**2.)  # const del(lambda)/lambda
+            extScl = pkpars1[i][0]**0  # lambda dependent extinction effect
+            t1 = t1 - extScl * pkmult1[int(eqvlab1[i])] * pkcalcint1[i] * (
+                np.exp(-((shftlam - pkpars1[i][0])**2.) / (2 * (sig**2))))
+
+    # calculate peaks for crystal 2
+    t2 = np.zeros(npt)  # initialise array containing profile
+    for i in range(nref2):
+        if pktype == 1:
+            pkpars2[i][0] = pkpars2[i][0] * delam  # linear lambda shift
+            sig = pkwid1 * pkpars2[i][0] + pkwid2 * \
+                (pkpars2[i][0]**2.)  # const del(lambda)/lambda
+            extScl = pkpars2[i][0]**0  # lambda dependent extinction effect
+            t2 = t2 - extScl * pkmult2[int(eqvlab2[i])] * pkcalcint2[i] * (
+                np.exp(-(shftlam - pkpars2[i][0])**2. / (2 * (sig**2))))
+
+    # calculate final profile
+    ttot = (bgdprof + sf * t1) * (bgdprof + sf * t2)
+    #t1 = 1.0;
+    # t2 = 1.0;
+    # introduce weighting function and calc chi2...
+    w = np.ones(len(shftlam))  # equal weighting everywhere
+    #i1 = np.where(shftlam > 2.15)[0][0]
+    #j1 = np.where(shftlam > 2.65)[0][0]
+    # w[i1:j1] = 5 #extra weighting in region of first peaks
+    # i1 = find(lam>1.68,1,'first');
+    # j1 = find(lam>2.05,1,'first');
+    # w(i1:j1)=5; %extra weighting but not too much
+
+    resid = (y - ttot) * w
+    chi2 = np.sum(resid**2. / (2 * e**2)) / npt
+
+    # Print if the user wants verbose minimization
+    if function_verbose == 'y':
+        print('Chi^2 ... ' + str(chi2))
+
+    return chi2
+
+
+def FitTrans():
+    '''
+    Main part of the program
+    '''
+    global hkl1, hkl2
+    global UB1, pkcalcint1
+    global UB2, pkcalcint2
+    global pktype
+    global lam, y, e, TOF
+    global L1
+    global ttot
+    global fxsamediam
+    global neqv1, eqvlab1, neqv2, eqvlab2
+    global difa, function_verbose
+    global run_number
+
+    # Customize constraints
+    cnstang = 1  # if set equal to one, setting angles will be constrained between
+    # limits defined by anglim1 and anglim2.
+    anglim1 = 1.0  # if cnstang ~= 1, setting angles for D2 only move by +/- this amount
+    anglim2 = 1.0  # if cnstang ~= 1, setting angles for D2 can only move by +/- this amount
+    fxsamediam = 1  # ==1 fix intensities for given hkl to be identical for both diamonds
+    fixmult = 0  # if ==1 peak multipliers are fixed during refinement
+    initL2 = 0.340  # m dist from centre of instrument to transmission det
+    delinitL2 = 0.005  # m variation in det position allowed within refinement
+    difa = -1e-10  # of order e-10
+
+    function_verbose = 'n'
+
+    # constraint notifications
+    if fxsamediam == 0:
+        print('*diamonds constrained to have same relative dip intensity*\n')
+    else:
+        print('*diamonds allowed to have different dip intensities!*')
+
+    if cnstang == 1:
+        print(
+            '*Diam {0} setting angles constrained to range of +/- {1} about their current values*'.format(1, anglim1))
+        print(
+            '*Diam {0} setting angles constrained to range of +/- {1} about their current values*'.format(2, anglim2))
+    else:
+        print('no constraint on setting angles')
+
+    if fixmult == 1:
+        print('*intensity multipliers fixed*')
+
+    # Get Input Files...
+    peaks_file = str(raw_input('Name of file containing diamond peaks: '))
+
+    run_number = str(raw_input('Input run number for transmission data: '))
+
+    # Build input filenames
+    #fullfilename_ub1 = str(run_number) + 'UB1.dat' # unused variable
+    #fullfilename_ub2 = str(run_number) + 'UB2.dat' # unused variable
+    fullfilename_trans = 'transNorm' + str(run_number) + '.dat'
+
+    # get both UB's
+    UB1, UB2 = UBMG.UBMatrixGen(peaks_file)
+
+    # [filename pathname ~] = ...
+    #     uigetfile('*.dat','Choose UB matrix for upstream diamond:');
+    # fullfilename = [pathname filename];
+    # fullfilename_ub1 = 'snap13108UB1.dat'
+    #UB1, remainder = getISAWub(fullfilename_ub1)
+
+    # [filename pathname ~] = ...
+    #     uigetfile('*.dat','Choose UB matrix for downstream diamond:');
+    # fullfilename = [pathname filename];
+    # fullfilename_ub2 = 'snap13108UB2.dat'
+    #UB2, remainder = getISAWub(fullfilename_ub2)
+
+    # get transmission data...
+    # [filename,pathname,~] = ...
+    #     uigetfile('*.csv','Choose transmission datafile:');
+    # fullfilename = [pathname filename];
+    fullfilename_trans = 'transNorm13148.csv'
+    TOF, yin, ein = getMANTIDdat_keepbinning(fullfilename_trans)
+
+    print('Starting refinement for: ' + fullfilename_trans)
+
+    # set-up simulation
+
+    L1 = 15.0  # m dist to centre of instrument in m
+
+    # global initial conditions
+    sf = 1
+    pktype = 1  # 1 = Gaussian, only current working peaktype
+    pkwid = 0.003  # peak width 'sig' is quadratic in lamda
+    pkwid2 = 2e-4  # sig = pkwid*lam+pkwid2*lam^2
+
+    #####################
+    # Start work...
+    #####################
+
+    # rebin transmission data
+    lam = 0.0039558 * TOF / (L1 + initL2)
+
+    print('wavelength limits: ' +
+          str(lam[0]) + ' and ' + str(lam[len(lam) - 1]))
+    minlam = 0.8
+    maxlam = 3.5
+    imin = np.where(lam >= minlam)[0][0]
+    imax = np.where(lam >= maxlam)[0][0]
+    lam = lam[imin:imax + 1]
+    TOF = TOF[imin:imax + 1]  # this will be the TOF range used in fit
+    y = yin[imin:imax + 1]
+    e = ein[imin:imax + 1]
+    bgd = np.array([1.0, 0.0])
+
+    # generate all allowed diamond hkls:
+    allhkl = allowedDiamRefs(-7, 7, -7, 7, -7, 7)
+
+    # initial conditions for crystal 1
+    setang1 = np.zeros(3)
+    # setang1[1:3] = 0.0 # rotation angles applied to refined UB
+    # use these to calculate resulting peak positions in wavelength
+    # pkpars1(:,1) is lambda
+    # pkpars1(:,2) is d-spacing
+    # pkpars1(:,3) is is 2theta
+    a, b, c = pkposcalc(allhkl, UB1, setang1)
+    pkpars1 = np.column_stack((a, b, c))
+
+    # initial conditions for crystal 2
+    setang2 = np.zeros(3)
+    #setang2[1:3][0] = 0.0
+    a, b, c = pkposcalc(allhkl, UB2, setang2)
+    pkpars2 = np.column_stack((a, b, c))
+
+    # purge all reflections that don't satisfy the Bragg condition and that are
+    # out of wavelength calculation range...
+
+    laminlim = lam[0]
+    lamaxlim = lam[len(lam) - 1]
+
+    nref = len(allhkl)
+
+    k1 = 0
+    k2 = 0
+    hkl1 = np.zeros(shape=(0, 3))
+    hkl2 = np.zeros(shape=(0, 3))
+    for i in range(nref):
+        if laminlim <= pkpars1[i][0] <= lamaxlim:  # reflection in range
+            hkl1 = np.vstack([hkl1, allhkl[i]])
+            k1 += 1
+
+        if laminlim <= pkpars2[i][0] <= lamaxlim:  # reflection in range
+            hkl2 = np.vstack([hkl2, allhkl[i]])
+            k2 += 1
+
+    print('There are: ' + str(k1) + ' expected dips due to Crystal 1')
+    print('There are: ' + str(k2) + ' expected dips due to Crystal 2')
+
+    # determine equivalents
+    # returns array with same dim as input labelling equivs
+    eqvlab1, neqv1 = findeqvs(hkl1)
+    eqvlab2, neqv2 = findeqvs(hkl2)
+
+    # pkpars1 = np.zeros(shape=(k, 6))   #empty array
+    a, b, c = pkposcalc(hkl1, UB1, setang1)
+    pkpars1 = np.column_stack((a, b, c))
+    # Calculated ref intensities
+    pkcalcint1 = pkintread(hkl1, (pkpars1[:, 0:3]))
+    pkcalcint1 *= 1e-6
+    pkmult1 = np.ones(neqv1)  # intensity multiplier for each group of equivs
+
+    # pkpars2 = np.zeros(shape=(l, 6))   #empty array
+    a, b, c = pkposcalc(hkl2, UB2, setang2)
+    pkpars2 = np.column_stack((a, b, c))
+    # Calculated ref intensities
+    pkcalcint2 = pkintread(hkl2, (pkpars2[:, 0:3]))
+    pkcalcint2 *= 1e-6
+    pkmult2 = np.ones(neqv2)  # peak intensity multiplier
+
+    relsf = 1.0    # default value
+    delam = 1.0
+    L2 = initL2
+    tbgd = bgd
+
+    # Either generate, or read variable array from file
+    # This is one big array with all the parameters to be refined in it.
+
+    prevf = str(raw_input('Look for pars from a previous run ([y]/n)? '))
+
+    if prevf == 'n':
+        x0 = np.hstack((setang1, pkmult1, setang2, pkmult2, sf,
+                        pkwid, tbgd, pkwid2, relsf, delam, L2))
+    else:
+            # choose which file to use
+        parfilename = str(raw_input('Choose file with starting pars: '))
+        parfullfilename = parfilename
+        x0 = dlmread(parfullfilename)
+        tog = str(raw_input('Got parameters from: \n' +
+                            parfilename + '\nUse these ([y]/n)?'))
+        if tog == 'n':
+            x0 = np.hstack((setang1, pkmult1, setang2, pkmult2,
+                            sf, pkwid, tbgd, pkwid2, relsf, delam, L2))
+            print('discarding pars from previous run')
+
+    print(str(len(x0)) + ' parameters will be refined')
+
+    nvar = len(x0)
+    print('number of variables: ' + str(nvar))
+    #nref1 = hkl1.shape[0] # unused variable
+    #nref2 = hkl2.shape[0] # unused variable
+
+    # need to apply correction in the case that pars from previous run had
+    # fxsamediam==1 and current run also has fxsamediam==1
+    # to avoid a double multiplication by relsf
+
+    if fxsamediam == 1 and x0[neqv1 + neqv2 + 11] != 1:
+        x0[6 + neqv1:7 + neqv1 + neqv2 - 1] = x0[3:4 +
+                                                 neqv2 - 1] / x0[neqv1 + neqv2 + 11]
+        print('Diam 2 peak multipliers reset: ' + str(x0[neqv1 + neqv2 + 11]))
+
+    # check starting point
+
+    chi2 = SimTrans3(x0)
+    fig_name_start = 'Starting point ' + run_number
+    plt.figure(fig_name_start)
+    plt.plot(lam, y, label='Observed')
+    plt.plot(lam, ttot, label='Calculated')
+    plt.plot(lam, (y - ttot), label='Residual')
+    plt.xlabel('Wavelength (A)')
+    plt.ylabel('Transmission')
+    plt.grid()
+    plt.legend(bbox_to_anchor=(0., 1.02, 1., .102), loc=3,
+               ncol=3, mode="expand", borderaxespad=0.)
+    plt.show()
+    print('Initial chi^2 is: ' + str(chi2))
+
+    showx3(x0)
+
+    # Prepare minimization of chi^2 for the calculated profile
+    # Set-up default constraints...
+    # inequalities
+    A = np.zeros(len(x0))
+    A[0:3] = 0  # setang1 *no constraint
+    A[3:4 + neqv1 - 1] = -1.0  # pkmult1 Contrains intensities to be positive
+    A[4 + neqv1 - 1:6 + neqv1] = 0.0  # setang2 *no constraint
+    A[6 + neqv1:7 + neqv1 + neqv2 - 1] = -1.0  # pkmult2
+    A[6 + neqv1 + neqv2] = -1.0     # sf Scale factor must be +ve
+    A[7 + neqv1 + neqv2] = -1.0  # pkwid peak width must be +ve
+    A[neqv1 + neqv2 + 8:neqv1 + neqv2 + 9 + 2 - 1] = 0.0  # bgd *no constraint
+    A[(neqv1 + neqv2 + 10)] = 0.0  # *no constraint
+    A[(neqv1 + neqv2 + 11)] = 0.0  # *no constraint
+    A[(neqv1 + neqv2 + 12)] = 0.0  # *no constraint
+    A[(neqv1 + neqv2 + 13)] = 0.0  # *no constraint
+
+    # equalities
+    Aeq = np.zeros(len(x0))
+    Aeq[0:3] = 0.0  # setang1
+    Aeq[3:4 + neqv1 - 1] = 0.0  # pkmult1
+    Aeq[4 + neqv1 - 1:6 + neqv1] = 0.0  # setang2
+    Aeq[6 + neqv1:7 + neqv1 + neqv2 - 1] = 0.0  # pkmult2
+    Aeq[6 + neqv1 + neqv2] = 0.0     # sf
+    Aeq[7 + neqv1 + neqv2] = 0.0  # pkwid
+    Aeq[neqv1 + neqv2 + 8:neqv1 + neqv2 + 9 + 2 - 1] = 0  # unfixed bgd
+    Aeq[neqv1 + neqv2 + 10] = 0
+    Aeq[neqv1 + neqv2 + 11] = 0
+    Aeq[neqv1 + neqv2 + 12] = 0
+    Aeq[neqv1 + neqv2 + 13] = 0
+
+    #beq = 0 # unused variable
+
+    # lower bounds
+    lb = np.zeros(len(x0))
+    lb[0:3] = -10  # setang1
+    lb[3:4 + neqv1 - 1] = 0.5  # pkmult1
+    lb[4 + neqv1 - 1:6 + neqv1] = -10  # setang2
+    lb[6 + neqv1:7 + neqv1 + neqv2 - 1] = 0.5  # pkmult2
+    lb[6 + neqv1 + neqv2] = 0.0     # sf
+    lb[7 + neqv1 + neqv2] = 0.0005  # pkwid
+    lb[neqv1 + neqv2 + 8:neqv1 + neqv2 + 9 + 2 - 1] = [0.995, -0.0005]  # bgd
+    lb[neqv1 + neqv2 + 10] = 0.5e-4  # 2nd order pkwid
+    lb[neqv1 + neqv2 + 11] = 0.9  # rel scale factor must be positive
+    lb[neqv1 + neqv2 + 12] = 0.9  # min lambda shift
+    # (m) min L2 dist sample to d/stream detector
+    lb[neqv1 + neqv2 + 13] = initL2 - delinitL2
+
+    # upper bounds
+    ub = np.zeros(len(x0))
+    ub[0:3] = 10  # setang1
+    ub[3:4 + neqv1 - 1] = 50  # pkmult1
+    ub[4 + neqv1 - 1:6 + neqv1] = 10  # setang2
+    ub[6 + neqv1:7 + neqv1 + neqv2 - 1] = 50  # pkmult2
+    ub[6 + neqv1 + neqv2] = 50     # sf
+    ub[7 + neqv1 + neqv2] = 0.01  # pkwid
+    ub[neqv1 + neqv2 + 8:neqv1 + neqv2 + 9 + 2 - 1] = [1.005, 0.0005]  # bgd
+    ub[neqv1 + neqv2 + 10] = 1.0e-2  # 2nd order pkwid
+    # diamond shouldn't be more than 2 times bigger!
+    ub[neqv1 + neqv2 + 11] = 1.1
+    ub[neqv1 + neqv2 + 12] = 1.1  # max lambda shift
+    # (m) max L2 dist sample to d/stream detector
+    ub[neqv1 + neqv2 + 13] = initL2 + delinitL2
+
+    # Customize constraints
+
+    if cnstang == 1:
+        # diamond 1
+        lb[0] = x0[0] - anglim1
+        lb[1] = x0[1] - anglim1
+        lb[2] = x0[2] - anglim1
+        ub[0] = x0[0] + anglim1
+        ub[1] = x0[1] + anglim1
+        ub[2] = x0[2] + anglim1
+        # diamond 2
+        lb[3 + neqv1] = x0[3 + neqv1] - anglim2
+        lb[4 + neqv1] = x0[4 + neqv1] - anglim2
+        lb[5 + neqv1] = x0[5 + neqv1] - anglim2
+        ub[3 + neqv1] = x0[3 + neqv1] + anglim2
+        ub[4 + neqv1] = x0[4 + neqv1] + anglim2
+        ub[5 + neqv1] = x0[5 + neqv1] + anglim2
+
+    if fixmult == 1:
+        lb[3:4 + neqv1 - 1] = x0[3:4 + neqv1 - 1] - 0.01
+        lb[6 + neqv1:7 + neqv1 + neqv2 - 1] = x0[6 +
+                                                 neqv1:7 + neqv1 + neqv2 - 1] - 0.01
+        ub[3:4 + neqv1 - 1] = x0[3:4 + neqv1 - 1] + 0.01
+        ub[6 + neqv1:7 + neqv1 + neqv2 - 1] = x0[6 +
+                                                 neqv1:7 + neqv1 + neqv2 - 1] + 0.01
+
+    prompt = str(raw_input('Enter anything to begin refinement...'))
+    print('Refining...\nMight take quite a long time...')
+
+    max_number_iterations = int(
+        raw_input('Maximum number of iterations for minimization: '))
+    function_verbose = str(raw_input('Verbose minimization ([y]/n): '))
+
+    # make dictionary holding constraints for minimization
+    # equalities (all must equal 0) and inequalities
+    cons = []
+    for i in range(len(x0)):
+        cons.append({'type': 'ineq', 'fun': lambda x: -A[i] * x[i]})
+    cons = tuple(cons)
+
+    # bounds have to be list of tuples with (lower, upper) for each parameter
+    bds = np.vstack((lb, ub)).T
+    res = sp.minimize(SimTrans3, x0, method='SLSQP', bounds=bds, constraints=cons, options={'disp': True,
+                                                                                            'maxiter': max_number_iterations})
+
+    # tolerance limits to put in minimization if you want so : 'ftol': 0.001
+
+    x = np.array(res.x)
+    #
+    # minimisation...
+    #
+    # figure(2)
+    # options = optimoptions(@fmincon,'Algorithm','interior-point', 'Display','off', 'MaxFunEvals',10000*nvar,'PlotFcns'
+    #                                         @optimplotfval, 'MaxIter',4000)
+    # x, fval, exitflag, output = fmincon(@SimTrans3,x0,A,b,[],[],Aeq beq
+    # lb,ub,[],options)
+
+    # necessary to update these here...
+    if fxsamediam == 1:
+        # set peak parameters for second diamond to equal those of first
+        # but scaled by relsf
+        # len(x)
+        # neqv1+neqv2+11
+        # x[neqv1+neqv2+11]
+        x[6 + neqv1:7 + neqv1 + neqv2 - 1] = x[3:4 +
+                                               neqv2 - 1] * x[neqv1 + neqv2 + 11]
+        print('Diam 2 peak multipliers reset with factor: ' +
+              str(x[neqv1 + neqv2 + 11]))
+    else:
+        # label ensuring I know that run did not use fxsamediam
+        x[neqv1 + neqv2 + 11] = 1.0
+
+    print('AFTER REFINEMENT')
+    showx3(x)
+
+    ####
+    # output final information
+    ####
+
+    # calculate chi2 for best fit
+    chi2 = SimTrans3(x)
+    print('Final Chi2 = ' + str(chi2))
+
+    # determine output wavelength range using refined L2 value
+
+    #lamscale = x[neqv1 + neqv2 + 12] # unused variable
+    L2 = x[neqv1 + neqv2 + 13]
+    outlam = 0.0039558 * TOF / (L1 + L2) + difa * (TOF**2)
+
+    fig_name_final = 'Final result ' + run_number
+    plt.figure(fig_name_final)
+    plt.plot(outlam, y, 'k', label='Observed')
+    plt.plot(outlam, ttot, 'r', label='Calculated')
+    plt.plot(outlam, (y - ttot), 'b', label='Final residuals')
+    plt.legend(bbox_to_anchor=(0., 1.02, 1., .102), loc=3,
+               ncol=3, mode="expand", borderaxespad=0.)
+    plt.text(2.1, 0.5, 'CHI^2=' + str(chi2))
+    plt.grid()
+    for i in range(len(pkpars1)):
+        plt.arrow(pkpars1[i, 0] * delam, 1.1, 0.0, 0.025,
+                  fc="k", ec="k", head_width=0, head_length=0)
+    for i in range(len(pkpars2)):
+        plt.arrow(pkpars2[i, 0] * delam, 1.15, 0.0, 0.025,
+                  fc="k", ec="k", head_width=0, head_length=0)
+    plt.xlim(1.0, 2.7)
+    plt.ylim(ymax=1.2)
+    plt.xlabel('Wavelength (A)')
+    plt.ylabel('Transmission')
+    plt.show()
+
+    prompt = str(raw_input('output best fit to file ([y]/n): '))
+    if prompt == 'n':
+        print('Ending')
+    else:
+        fitparname = str(run_number) + '.best_fit_pars3.dat'
+        np.savetxt(fitparname, x, delimiter=',')
+        print('output parameters written to file: \n' + fitparname)
+        ofilename = str(run_number) + '.fitted3.dat'
+        SimTransOutput3(ofilename, x)  # generate output file with fitted data
+
+if __name__ == "__main__":
+    FitTrans()
diff --git a/scripts/DiamondAttenuationCorrection/README.md b/scripts/DiamondAttenuationCorrection/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..bca17ffd2d6d008698f90eace5bc6d81d911c64f
--- /dev/null
+++ b/scripts/DiamondAttenuationCorrection/README.md
@@ -0,0 +1,13 @@
+This implements a Diamond Attenuation Correction for performing
+neautron TOF measurements in Diamond Anvil Cells.
+
+It contains a functionality to generate the UB matrices for the 2
+diamonds from a peaks input file where one has selected diamond peaks
+in Mantid beforehand.
+
+Uses that and the normalised, focused and background-corrected
+transmission data to extract the diamond attenuation and outputs it
+alongside the data with the attenuation excluded.
+
+This output can then be focused and the results will be a refinable
+pattern.
diff --git a/scripts/DiamondAttenuationCorrection/UBMatrixGenerator.py b/scripts/DiamondAttenuationCorrection/UBMatrixGenerator.py
new file mode 100644
index 0000000000000000000000000000000000000000..28faf3a576c1e5344f3512cd65a033723f89c581
--- /dev/null
+++ b/scripts/DiamondAttenuationCorrection/UBMatrixGenerator.py
@@ -0,0 +1,304 @@
+'''
+Generate UB matrices from measured list of reflections
+Identifies upstream and downstream diamonds and assigns matrices to them
+'''
+
+# Import all needed libraries
+import numpy as np
+import itertools as itt
+
+# Function to read the reflections measured
+
+
+def getMANTIDpkds(filename):
+    fileID = filename
+    if fileID == 1:
+        print('Error opening file: ' + filename)
+    f = open(fileID, "r")
+    lines = f.readlines()
+    f.close()
+
+    hkl = np.zeros((len(lines) - 2, 3))
+    d = np.zeros((len(lines) - 2))
+    q = np.zeros((len(lines) - 2, 3))
+
+    for i in range(1, len(lines) - 1):
+        elem = lines[i].split(',')
+
+        hkl[i - 1] = elem[2], elem[3], elem[4]
+        d[i - 1] = elem[8]
+        q[i - 1] = float(elem[15].replace('[', '')
+                         ), float(elem[16]), float(elem[17].replace(']', ''))
+
+    return hkl, d, q
+
+# Generate all permutations (including negative) for given hkl
+
+
+def plusAndMinusPermutations(items):
+    for p in itt.permutations(items):
+        for signs in itt.product([-1, 1], repeat=len(items)):
+            yield [a * sign for a, sign in zip(p, signs)]
+
+# Identify equivalent reflections
+
+
+def m3mEquiv(hkl_input, tog):
+    hkl = hkl_input
+    h = float(hkl[0])
+    k = float(hkl[1])
+    l = float(hkl[2])
+    all_equivs = np.asarray(list(plusAndMinusPermutations([h, k, l])))
+    # print all_equivs
+
+    # Remove non-unique equivalents
+    lab = np.zeros(len(all_equivs))  # label unique reflections
+    nlab = 0
+    for i in range(len(all_equivs)):
+        if lab[i] == 0:  # not checked yet
+            nlab += 1
+            for j in range(len(all_equivs)):
+                diff = all_equivs[i] - all_equivs[j]
+                if np.linalg.norm(diff) == 0:  # an identical reflection found
+                    lab[j] = nlab
+
+    #print('number of unique reflections is: {0}\n'.format(nlab))
+
+    # red is reduced array with only distinct reflections in it
+    red = np.zeros((nlab, 3))
+    for i in range(1, nlab + 1):
+        k = np.argmax(lab == i)
+        red[i - 1] = all_equivs[k]
+
+    if tog == 1:
+        k = np.where(red[:, 0] <= 0)[0]
+        eqvs = red[k]
+    else:
+        eqvs = red
+
+    return eqvs
+
+# Match equivalent reflections
+
+
+def EquivMatch(refh, hkl, gam, tol):
+    AllEqv = m3mEquiv(hkl, 1)
+    match = np.zeros(len(AllEqv))
+    nmatch = 0
+    for i in range(len(AllEqv)):
+        h1 = AllEqv[i]
+        bet = np.degrees(np.arccos(np.dot(refh, h1) /
+                                   (np.linalg.norm(refh) * np.linalg.norm(h1))))
+        dif = np.abs(bet - gam)
+        if dif <= tol:
+            match[i] = 1
+            nmatch += 1
+
+    if nmatch == 0:
+        hklmatch = [0, 0, 0]
+    else:
+        ind = np.where(match == 1)
+        hklmatch = AllEqv[ind]
+
+    return hklmatch
+
+'''Jacobsen - Implementation of method articulated in RA Jacobsen
+ Zeitschrift fur Krystallographie(1996).
+
+Note!!!! mantidplot scales reciprocal space coordinates with a factor of
+2 pi.In contrast, ISAWev does not.This algorithm assumes the mantidplot convention!!!!
+
+h1 and h2 are vertical 3x1 coordinate matrices containing h, k, l for two reflections
+Xm_1 and Xm_2 are the corresponding coordinate matrices measured in the (Cartesian)
+diffractometer frame Xm(these are known by mantid for a calibrated instrument)
+
+First check indexing of input reflections by checking angle: angle between reciprocal
+lattice vectors
+'''
+
+
+def Jacobsen(h1, Xm_1, h2, Xm_2):
+    alp = np.degrees(np.arccos(np.dot(h1, h2) /
+                               (np.linalg.norm(h1) * np.linalg.norm(h2))))
+    bet = np.degrees(np.arccos(np.dot(Xm_1, Xm_2) /
+                               (np.linalg.norm(Xm_1) * np.linalg.norm(Xm_2))))
+    if ((alp - bet)**2) > 1:
+        print('check your indexing!')
+
+    a = 3.567  # diamond lattice parameter
+    # recip lattice par(note this is the mantid convention: no 2 pi)
+    ast = (2 * np.pi) / a
+    B = np.array([[ast, 0, 0], [0, ast, 0], [0, 0, ast]])
+    Xm_g = np.cross(Xm_1, Xm_2)
+    Xm = np.column_stack([Xm_1, Xm_2, Xm_g])
+
+    # Vector Q1 is described in reciprocal space by its coordinate matrix h1
+    Xa_1 = B.dot(h1)
+    Xa_2 = B.dot(h2)
+    Xa_g = np.cross(Xa_1, Xa_2)
+    Xa = np.column_stack((Xa_1, Xa_2, Xa_g))
+
+    R = Xa.dot(np.linalg.inv(Xm))
+    U = np.linalg.inv(R)
+
+    UB = U.dot(B)
+
+    return UB
+
+# Guess Miller indices based on d-spacing
+
+
+def guessIndx(d, tol):
+    # guessIndx accepts n d-spacings and returns guess at indexing class for
+    # diamond
+    dref = np.array([2.0593, 1.2611, 1.0754, 0.8917, 0.8183, 0.7281])
+    # note, by default assume that diamond a / a * axis is close to parallel to beam, therefore, h index
+    # will be negative for all reflections
+    href = np.array([[-1, 1, 1], [-2, 2, 0], [-3, 1, 1],
+                     [-4, 0, 0], [-3, 3, 1], [-4, 2, 2]])
+
+    h = np.zeros((len(d), 3))
+    for i in range(len(d)):
+        delta = np.abs(dref - d[i])
+        hit = np.where(delta < tol)
+        h[i] = href[hit]
+
+    return h
+
+
+def UBMatrixGen(fileName):
+    # read ascii file with mantidplot peaks list
+    h, d, q = getMANTIDpkds(fileName)
+    # sort peaks according to d-spacing
+    dsort = sorted(d)[::-1]
+    sortindx = np.argsort(d)[::-1]
+    N = len(d)
+    ublab = np.zeros(N)  # will be label for UB/diamond
+
+    hsort = np.zeros((N, 3))
+    qsort = np.zeros((N, 3))
+    for i in range(N):
+        hsort[i] = h[sortindx[i]]
+        qsort[i] = q[sortindx[i]]
+    d = dsort
+    h = hsort
+    q = qsort
+    h = guessIndx(d, 0.05)  # overwrites what's in original file with guess
+    # based on d-spacing
+
+    # display all reflections with guessed indices, allow choice of one
+    # reflection as reference reflection
+    print('First guess at indexing\n')
+    print('REF | h k l | d-spac(A)')
+    for i in range(N):
+        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: '))
+
+    print('REF | h k l | obs|  calc')
+    beta = np.zeros(N)
+    for i in range(N):
+        beta[i] = np.degrees(np.arccos(
+            np.dot(q[nref1], q[i]) / (np.linalg.norm(q[nref1]) * np.linalg.norm(q[i]))))
+        if i == nref1:
+            print('{0:0.0f} |   {1:0.0f} {2:0.0f} {3:0.0f}   |  {4:0.3f}|  0.0| REFERENCE'.format(
+                i, h[i][0], h[i][1], h[i][2], beta[i]))
+        else:
+            # check for possible index suggestion
+            hklA = h[nref1]
+            hklB = h[i]
+            hklhit = EquivMatch(hklA, hklB, beta[i], 1.0)
+            if np.linalg.norm(hklhit) == 0:
+                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], beta[i]))
+            else:  # % there is an hkl at a matching angle
+                calcang = np.degrees(np.arccos(
+                    np.dot(hklA, hklhit[0]) / (np.linalg.norm(hklA) * np.linalg.norm(hklhit[0]))))
+                h[i] = hklhit[0]
+                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: '))
+
+    h1 = h[nref1]
+    q1 = q[nref1]
+    q2 = q[nref2]
+    h2 = h[nref2]
+
+    UB1 = Jacobsen(h1, q1, h2, q2)
+
+    # 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: '))
+    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
+        # difference with nearst integer
+        dif = np.abs(hindx[i] - np.round(hindx[i]))
+        if np.sum(dif) <= 3 * tol:  # all indices within tolerance
+            h[i] = np.round(hindx[i])
+            print('{0:0.0f} |   {1:0.0f} {2:0.0f} {3:0.0f} | '.format(
+                i, hindx[i][0], hindx[i][1], hindx[i][2]))
+            nindexed1 += 1
+            ublab[i] = 1
+        else:
+            print('{0:0.0f} |   {1:0.0f} {2:0.0f} {3:0.0f} | '.format(
+                i, hindx[i][0], hindx[i][1], hindx[i][2]))
+            ublab[i] = 2
+    print('{0:0.0f} reflections indexed!'.format(nindexed1))
+    nsub = N - nindexed1
+
+    if nsub < 2:
+        print('not enough remaining reflections to index second diamond :(')
+    else:
+        k = np.where(ublab == 2)
+        hsub = np.array(h[k])   # a list of unindexed h
+        qsub = np.array(q[k])   # and their q - vectors
+        d = np.array(d)
+        dsub = d[k]
+
+        print('Now find UB for second diamond')
+        print('Remaining unindexed reflections:')
+        print(' REF|  h  k  l| d-spac(A)')
+        for i in range(nsub):
+            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: '))
+
+        for i in range(nsub):
+            beta[i] = np.degrees(np.arccos(np.dot(qsub[nref1], qsub[
+                                 i]) / (np.linalg.norm(qsub[nref1]) * np.linalg.norm(qsub[i]))))
+            if i == nref1:
+                print('{0:0.0f} |   {1:0.0f} {2:0.0f} {3:0.0f}   |  {4:0.3f}|  0.0| REFERENCE'.format(i, hsub[i][0], hsub[i][1],
+                                                                                                      hsub[i][2], beta[i]))
+            else:
+                # check for possible index suggestion
+                hklA = hsub[nref1]
+                hklB = hsub[i]
+                hklhit = EquivMatch(hklA, hklB, beta[i], 1.0)
+                if np.linalg.norm(hklhit) == 0:
+                    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],
+                                                                                         beta[i]))
+                else:  # % there is an hkl at a matching angle
+                    calcang = np.degrees(np.arccos(
+                        np.dot(hklA, hklhit[0]) / (np.linalg.norm(hklA) * np.linalg.norm(hklhit[0]))))
+                    h[i] = hklhit[0]
+                    print('{0:0.0f} |   {1:0.0f} {2:0.0f} {3:0.0f} |    {4:0.3f} | {5:0.3f}'.format(i, hsub[i][0], hsub[i][1],
+                                                                                                    hsub[i][
+                                                                                                        2], beta[i],
+                                                                                                    calcang))
+        nref2 = int(
+            raw_input('Choose a second reflection to use for indexing: '))
+
+    h1 = hsub[nref1]
+    q1 = qsub[nref1]
+    q2 = qsub[nref2]
+    h2 = hsub[nref2]
+
+    UB2 = Jacobsen(h1, q1, h2, q2)
+    print 'UB1 = ', UB1
+    print 'UB2 = ', UB2
+    return UB1, UB2
diff --git a/scripts/Diffraction/isis_powder/__init__.py b/scripts/Diffraction/isis_powder/__init__.py
index 7d4b197e67d1da50e7668bbda5ca28e0449f36c5..db02fc737e5b71c87367b441155bca69c40f5a7f 100644
--- a/scripts/Diffraction/isis_powder/__init__.py
+++ b/scripts/Diffraction/isis_powder/__init__.py
@@ -1,3 +1,4 @@
 from .pearl import Pearl
+from .polaris import Polaris
 
-__all__ = ["Pearl"]
+__all__ = ["Pearl", "Polaris"]
diff --git a/scripts/Diffraction/isis_powder/abstract_inst.py b/scripts/Diffraction/isis_powder/abstract_inst.py
index 898c58c74c284adf7d731dc2a27d337f07239bf9..47bba21a8e1acd6176d954314088473f7acba4bf 100644
--- a/scripts/Diffraction/isis_powder/abstract_inst.py
+++ b/scripts/Diffraction/isis_powder/abstract_inst.py
@@ -1,9 +1,12 @@
 from __future__ import (absolute_import, division, print_function)
 
+import os
 from abc import ABCMeta, abstractmethod
+
 from six import add_metaclass
 
-from isis_powder import common
+from isis_powder.routines import calibrate, focus, common
+
 
 # This class provides common hooks for instruments to override
 # if they want to define the behaviour of the hook. Otherwise it
@@ -12,18 +15,16 @@ from isis_powder import common
 
 @add_metaclass(ABCMeta)
 class AbstractInst(object):
-    def __init__(self, user_name=None, calibration_dir=None, raw_data_dir=None, output_dir=None,
-                 default_input_ext=".raw", tt_mode=""):
+    def __init__(self, user_name=None, calibration_dir=None, output_dir=None, **kwargs):
         # ----- Properties common to ALL instruments -------- #
         if user_name is None:
             raise ValueError("A user name must be specified")
         self._user_name = user_name
         self._calibration_dir = calibration_dir
-        self._raw_data_dir = raw_data_dir
         self._output_dir = output_dir
-        self._default_input_ext = _append_dot_to_ext(default_input_ext)
-        self._tt_mode = tt_mode
-        self._focus_mode = None
+
+        # Advanced settings
+        self._default_input_ext = _prefix_dot_to_ext(kwargs.get("default_input_ext", '.raw'))
 
     @property
     def calibration_dir(self):
@@ -43,11 +44,7 @@ class AbstractInst(object):
 
     @default_input_ext.setter
     def default_input_ext(self, new_ext):
-        self._default_input_ext = _append_dot_to_ext(new_ext)
-
-    @property
-    def tt_mode(self):
-        return self._tt_mode
+        self._default_input_ext = _prefix_dot_to_ext(new_ext)
 
     @property
     def focus_mode(self):
@@ -60,13 +57,9 @@ class AbstractInst(object):
     # --- Public API ---- #
 
     # Script entry points
-    def focus(self, run_number, focus_mode, input_ext=None, do_attenuation=True, do_van_normalisation=True):
-        self._focus_mode = focus_mode
-        if input_ext is not None:
-            self.default_input_ext = input_ext
-
-        return common.focus(instrument=self, number=run_number,
-                            attenuate=do_attenuation, van_norm=do_van_normalisation)
+    def _focus(self, run_number, do_attenuation, do_van_normalisation):
+        return focus.focus(instrument=self, number=run_number,
+                           attenuate=do_attenuation, van_norm=do_van_normalisation)
 
     def create_empty_calibration_by_names(self, calibration_numbers, output_file_name, group_names=None):
 
@@ -84,14 +77,11 @@ class AbstractInst(object):
         self._create_calibration_silicon(calibration_runs=calibration_runs, cal_file_name=cal_file_name,
                                          grouping_file_name=grouping_file_name)
 
-    def create_calibration_vanadium(self, vanadium_runs, empty_runs, output_file_name, num_of_splines,
-                                    do_absorb_corrections=True, gen_absorb_correction=False):
-
-        common.create_vanadium(startup_object=self, vanadium_runs=vanadium_runs,
-                               empty_runs=empty_runs, output_file_name=output_file_name,
-                               num_of_spline_coefficients=num_of_splines,
-                               do_absorb_corrections=do_absorb_corrections,
-                               generate_absorb_corrections=gen_absorb_correction)
+    def _create_calibration_vanadium(self, vanadium_runs, empty_runs, output_file_name=None, num_of_splines=None,
+                                     do_absorb_corrections=True, gen_absorb_correction=False):
+        return calibrate.create_van(instrument=self, van=vanadium_runs, empty=empty_runs,
+                                    output_van_file_name=output_file_name, num_of_splines=num_of_splines,
+                                    absorb=do_absorb_corrections, gen_absorb=gen_absorb_correction)
 
     @staticmethod
     def set_debug_mode(val):
@@ -102,38 +92,30 @@ class AbstractInst(object):
     # These are to be called from either concrete instruments or common not by users
     # Common steps to all instruments
 
-    def _generate_out_file_paths(self, run_number, output_directory):
-        file_name = self._generate_inst_file_name(run_number=run_number)
-        nxs_file = output_directory + str(file_name) + ".nxs"
-        gss_file = output_directory + str(file_name) + ".gss"
-        tof_xye_file = output_directory + str(file_name) + "_tof_xye.dat"
-        d_xye_file = output_directory + str(file_name) + "_d_xye.dat"
+    def _generate_out_file_paths(self, run_details, output_directory=None):
+        if not output_directory:
+            output_directory = os.path.join(self._output_dir, run_details.label, self._user_name)
+        file_name = self._generate_inst_file_name(run_number=run_details.run_number)
+        nxs_file = os.path.join(output_directory, (str(file_name) + ".nxs"))
+        gss_file = os.path.join(output_directory, (str(file_name) + ".gss"))
+        tof_xye_file = os.path.join(output_directory, (str(file_name) + "_tof_xye.dat"))
+        d_xye_file = os.path.join(output_directory, (str(file_name) + "_d_xye.dat"))
         out_name = str(file_name)
 
         out_file_names = {"nxs_filename": nxs_file,
                           "gss_filename": gss_file,
                           "tof_xye_filename": tof_xye_file,
                           "dspacing_xye_filename": d_xye_file,
-                          "output_name": out_name}
+                          "output_name": out_name,
+                          "output_folder": output_directory}
 
         return out_file_names
 
-    def _generate_raw_data_cycle_dir(self, run_cycle):
-        if self._skip_appending_cycle_to_raw_dir():
-            return self.raw_data_dir
-        str_run_cycle = str(run_cycle)
-
-        # Append current cycle to raw data directory
-        generated_dir = self.raw_data_dir + str_run_cycle
-        generated_dir = _append_path_dividers_to_end(generated_dir, self.raw_data_dir)
-
-        return generated_dir
-
     def _generate_input_full_path(self, run_number, input_dir):
         # Uses runtime polymorphism to generate the full run name
         file_name = self._generate_inst_file_name(run_number)
         extension = self.default_input_ext
-        return input_dir + file_name + extension
+        return os.path.join(input_dir, (file_name + extension))
 
     # Instrument specific properties to be implemented by base classes #
 
@@ -146,15 +128,6 @@ class AbstractInst(object):
         """
         pass
 
-    @abstractmethod
-    def _get_focus_tof_binning(self):
-        """
-        Returns the TOF binning values
-        @param self: The instrument to get TOF binning values for
-        @return: TOF binning Values
-        """
-        pass
-
     @abstractmethod
     def _get_create_van_tof_binning(self):
         """
@@ -175,13 +148,7 @@ class AbstractInst(object):
     # Instrument specific methods
 
     @abstractmethod
-    def _get_calibration_full_paths(self, cycle):
-        """
-        Gets the current calibration file names for this cycle
-        @param cycle: The cycle string to lookup for this run
-        @return: A dictionary the containing the full paths as values for the following keys:
-        "calibration", "grouping", "vanadium_absorption", "vanadium"
-        """
+    def _get_run_details(self, run_number):
         pass
 
     @staticmethod
@@ -192,30 +159,21 @@ class AbstractInst(object):
         @param run_number: The run number to turn into a filename
         @return: The filename of the file - Without the path or extension
         """
-        pass
 
     @staticmethod
     @abstractmethod
     def _get_instrument_alg_save_ranges(instrument=''):
-        #  TODO fix this documentation when we know what alg_range and save_range is used for
+        #  TODO we need to move save range out into a separate hook and make alg
+        #  range represent the number of banks
         """
         Gets the instruments ranges for running the algorithm and saving
-        @param self: The instrument to query for this information
         @param instrument: The version of the instrument if applicable
         @return: The algorithm and save range in that order
         """
 
-    @staticmethod
-    @abstractmethod
-    def _get_cycle_information(run_number):
-        """
-        Gets all the information about this run for this cycle and returns it in a dictionary
-        @param run_number: The run to match the cycle to
-        @return: Dictionary with the following keys: "cycle", "instrument_version"
-        """
-        pass
-
     # --- Instrument optional hooks ----#
+    # TODO cull some of these hooks once we unify the scripts
+
     def _attenuate_workspace(self, input_workspace):
         return _empty_hook_return_input(input_workspace)
 
@@ -238,13 +196,13 @@ class AbstractInst(object):
         """
         raise NotImplementedError("Create calibration from a silicon run is not yet implemented for this instrument")
 
-    def _get_monitor(self, run_number, input_dir, spline_terms):
+    def _normalise_ws(self, ws_to_correct, run_details=None):
         return _empty_hook_return_none()
 
     def _get_monitor_spectra(self, run_number):
         return _empty_hook_return_empty_string()
 
-    def _PEARL_use_full_path(self):
+    def _PEARL_filename_is_full_path(self):
         """
         Only used by PEARL to maintain compatibility with old routines code
         @return: Whether the "filename" is actually a full path
@@ -261,29 +219,47 @@ class AbstractInst(object):
         return _empty_hook_return_none()
 
     def _skip_appending_cycle_to_raw_dir(self):
-        return False
+        return True
+        # TODO set this to False if they just dump their raw files in one folder
+
+    def _do_tof_rebinning_focus(self, input_workspace):
+        return input_workspace
+
+    def _process_focus_output(self, processed_spectra, run_details, attenuate=False):
+        return _empty_hook_return_none()
+
+    def apply_solid_angle_efficiency_corr(self, ws_to_correct, run_details):
+        return ws_to_correct
 
+    def _apply_van_calibration_tof_rebinning(self, vanadium_ws, tof_rebin_pass, return_units):
+        return vanadium_ws
+
+    def _generate_vanadium_absorb_corrections(self, calibration_full_paths, ws_to_match):
+        raise NotImplementedError("Not implemented for this instrument yet")
+
+    def _calibration_rebin_to_workspace(self, ws_to_rebin, ws_to_match):
+        return ws_to_rebin
+
+    def correct_sample_vanadium(self, focused_ws, index, vanadium_ws=None):
+        raise NotImplementedError("Cannot process the sample with a vanadium run for this instrument")
+
+    def calculate_focus_binning_params(self, sample):
+        return None
+
+    def PEARL_setup_input_directories(self, run_number):
+        return None
 
 # ----- Private Implementation ----- #
 # These should only be called by the abstract instrument class
 
-def _append_dot_to_ext(ext):
+
+def _prefix_dot_to_ext(ext):
     if not ext.startswith('.'):
         return '.' + ext
     else:
         return ext
 
 
-def _append_path_dividers_to_end(generated_dir, raw_data_dir):
-    if raw_data_dir.endswith('\\'):
-        generated_dir += '\\'
-    elif raw_data_dir.endswith('/'):
-        generated_dir += '/'
-    else:
-        raise ValueError("Path :" + raw_data_dir + "\n Does not end with a \\ or / character")
-    return generated_dir
-
-
 # These empty hooks can be used to diagnose when an override hasn't
 # fired or if steps are correctly being skipped
 
diff --git a/scripts/Diffraction/isis_powder/common.py b/scripts/Diffraction/isis_powder/common.py
deleted file mode 100644
index bd74be2dc2590105249bfb458a29d2f074a922da..0000000000000000000000000000000000000000
--- a/scripts/Diffraction/isis_powder/common.py
+++ /dev/null
@@ -1,496 +0,0 @@
-from __future__ import (absolute_import, division, print_function)
-import mantid.simpleapi as mantid
-
-# --- Public API --- #
-
-
-def focus(number, instrument, attenuate=True, van_norm=True):
-    return _run_pearl_focus(run_number=number, perform_attenuation=attenuate,
-                            perform_vanadium_norm=van_norm, instrument=instrument)
-
-
-def create_calibration_by_names(calibration_runs, startup_objects, grouping_file_name, group_names):
-    _create_blank_cal_file(calibration_runs=calibration_runs, group_names=group_names,
-                           out_grouping_file_name=grouping_file_name, instrument=startup_objects)
-
-
-def create_vanadium(startup_object, vanadium_runs, empty_runs, output_file_name,
-                    num_of_spline_coefficients=60, do_absorb_corrections=True, generate_absorb_corrections=False):
-    _create_van(instrument=startup_object, van=vanadium_runs, empty=empty_runs,
-                output_van_file_name=output_file_name, num_of_splines=num_of_spline_coefficients,
-                absorb=do_absorb_corrections, gen_absorb=generate_absorb_corrections)
-
-
-def set_debug(debug_on=False):
-    global g_debug
-    g_debug = debug_on
-
-
-def remove_intermediate_workspace(workspace_name):
-    _remove_ws(ws_to_remove=workspace_name)
-
-# --- Private Implementation --- #
-
-# Please note these functions can change in any way at any time.
-# For this reason please do not call them directly and instead use the Public API provided.
-
-# If this doesn't quite provide what you need please let a developer know so we can create
-# another API which will not change without notice
-
-# This section is holds several counters which work around the fact that Mantid
-# takes the alias and uses it as the WS name and on subsequent calls overrides it
-# when the Python API truly implements anonymous pointers this can be removed
-
-_read_pearl_ws_count = 0
-global g_ads_workaround
-g_ads_workaround = {"read_pearl_ws" : _read_pearl_ws_count}
-
-
-def _create_blank_cal_file(calibration_runs, out_grouping_file_name, instrument, group_names):
-    input_ws = _read_ws(calibration_runs, instrument)
-    calibration_d_spacing_ws = mantid.ConvertUnits(InputWorkspace=input_ws, Target="dSpacing")
-    mantid.CreateCalFileByNames(InstrumentWorkspace=calibration_d_spacing_ws,
-                                GroupingFileName=out_grouping_file_name, GroupNames=group_names)
-    remove_intermediate_workspace(calibration_d_spacing_ws)
-    remove_intermediate_workspace(input_ws)
-
-
-def _create_van(instrument, van, empty, output_van_file_name, num_of_splines=60, absorb=True, gen_absorb=False):
-    cycle_information = instrument._get_cycle_information(van)
-
-    input_van_ws = _read_ws(number=van, instrument=instrument)
-    input_empty_ws = _read_ws(number=empty, instrument=instrument)
-
-    corrected_van_ws = mantid.Minus(LHSWorkspace=input_van_ws, RHSWorkspace=input_empty_ws)
-
-    remove_intermediate_workspace(input_empty_ws)
-    remove_intermediate_workspace(input_van_ws)
-
-    calibration_full_paths = instrument._get_calibration_full_paths(cycle=cycle_information["cycle"])
-    tof_binning = instrument._get_create_van_tof_binning()
-
-    if absorb:
-        corrected_van_ws = _apply_absorb_corrections(calibration_full_paths, corrected_van_ws, gen_absorb)
-
-    corrected_van_ws = mantid.ConvertUnits(InputWorkspace=corrected_van_ws, Target="TOF")
-    corrected_van_ws = mantid.Rebin(InputWorkspace=corrected_van_ws, Params=tof_binning["1"])
-
-    corrected_van_ws = mantid.AlignDetectors(InputWorkspace=corrected_van_ws,
-                                             CalibrationFile=calibration_full_paths["calibration"])
-
-    focused_van_file = mantid.DiffractionFocussing(InputWorkspace=corrected_van_ws,
-                                                   GroupingFileName=calibration_full_paths["grouping"])
-
-    focused_van_file = mantid.ConvertUnits(InputWorkspace=focused_van_file, Target="TOF")
-
-    focused_van_file = mantid.Rebin(InputWorkspace=focused_van_file, Params=tof_binning["2"])
-    focused_van_file = mantid.ConvertUnits(InputWorkspace=focused_van_file, Target="dSpacing")
-
-    remove_intermediate_workspace(corrected_van_ws)
-
-    splined_ws_list = instrument._spline_background(focused_van_file, num_of_splines,
-                                                    cycle_information["instrument_version"])
-
-    if instrument._PEARL_use_full_path():
-        out_van_file_path = output_van_file_name
-    else:
-        out_van_file_path = instrument.calibration_dir + output_van_file_name
-
-    append = False
-    for ws in splined_ws_list:
-        mantid.SaveNexus(Filename=out_van_file_path, InputWorkspace=ws, Append=append)
-        remove_intermediate_workspace(ws)
-        append = True
-
-    mantid.LoadNexus(Filename=out_van_file_path, OutputWorkspace="Van_data")
-
-
-def _apply_absorb_corrections(calibration_full_paths, corrected_van_ws, gen_absorb):
-    corrected_van_ws = mantid.ConvertUnits(InputWorkspace=corrected_van_ws, Target="Wavelength")
-
-    if gen_absorb:
-        raise NotImplementedError("Generating absorption corrections is not currently working correctly")
-        # TODO look into this and see what is missing from the original script based on the current
-        # TODO generated NXS file history
-        absorb_ws = _generate_vanadium_absorb_corrections(calibration_full_paths, corrected_van_ws)
-    else:
-        absorb_ws = _load_van_absorb_corr(calibration_full_paths)
-
-    corrected_van_ws = mantid.RebinToWorkspace(WorkspaceToRebin=corrected_van_ws, WorkspaceToMatch=absorb_ws)
-    corrected_van_ws = mantid.Divide(LHSWorkspace=corrected_van_ws, RHSWorkspace=absorb_ws)
-    remove_intermediate_workspace(absorb_ws)
-    return corrected_van_ws
-
-
-def _generate_vanadium_absorb_corrections(calibration_full_paths, ws_to_match):
-    # TODO are these values applicable to all instruments
-    shape_ws = mantid.CloneWorkspace(InputWorkspace=ws_to_match)
-    mantid.CreateSampleShape(InputWorkspace=shape_ws, ShapeXML='<sphere id="sphere_1"> <centre x="0" y="0" z= "0" />\
-                                                      <radius val="0.005" /> </sphere>')
-
-    absorb_ws = \
-        mantid.AbsorptionCorrection(InputWorkspace=shape_ws, AttenuationXSection="5.08",
-                                    ScatteringXSection="5.1", SampleNumberDensity="0.072",
-                                    NumberOfWavelengthPoints="25", ElementSize="0.05")
-    mantid.SaveNexus(Filename=calibration_full_paths["vanadium_absorption"],
-                     InputWorkspace=absorb_ws, Append=False)
-    remove_intermediate_workspace(shape_ws)
-    return absorb_ws
-
-
-def _load_van_absorb_corr(calibration_full_paths):
-    absorption_ws = mantid.LoadNexus(Filename=calibration_full_paths["vanadium_absorption"])
-    return absorption_ws
-
-
-def _load_monitor(number, input_dir, instrument):
-    if isinstance(number, int):
-        full_file_path = instrument._generate_input_full_path(run_number=number, input_dir=input_dir)
-        mspectra = instrument._get_monitor_spectra(number)
-        load_monitor_ws = mantid.LoadRaw(Filename=full_file_path, SpectrumMin=mspectra, SpectrumMax=mspectra,
-                                         LoadLogFiles="0")
-    else:
-        load_monitor_ws = _load_monitor_sum_range(files=number, input_dir=input_dir, instrument=instrument)
-
-    return load_monitor_ws
-
-
-def _load_monitor_sum_range(files, input_dir, instrument):
-    loop = 0
-    num = files.split("_")
-    frange = list(range(int(num[0]), int(num[1]) + 1))
-    mspectra = instrument._get_monitor_spectra(int(num[0]))
-    for i in frange:
-        file_path = instrument._generate_input_full_path(i, input_dir)
-        outwork = "mon" + str(i)
-        mantid.LoadRaw(Filename=file_path, OutputWorkspace=outwork, SpectrumMin=mspectra, SpectrumMax=mspectra,
-                       LoadLogFiles="0")
-        loop += 1
-        if loop == 2:
-            firstwk = "mon" + str(i - 1)
-            secondwk = "mon" + str(i)
-            load_monitor_summed = mantid.Plus(LHSWorkspace=firstwk, RHSWorkspace=secondwk)
-            mantid.mtd.remove(firstwk)
-            mantid.mtd.remove(secondwk)
-        elif loop > 2:
-            secondwk = "mon" + str(i)
-            load_monitor_summed = mantid.Plus(LHSWorkspace=load_monitor_summed, RHSWorkspace=secondwk)
-            mantid.mtd.remove(secondwk)
-
-    return load_monitor_summed
-
-
-def _load_raw_files(run_number, instrument, input_dir):
-    if isinstance(run_number, int):
-        infile = instrument._generate_input_full_path(run_number=run_number, input_dir=input_dir)
-        load_raw_ws = mantid.LoadRaw(Filename=infile, LoadLogFiles="0")
-    else:
-        load_raw_ws = _load_raw_file_range(run_number, input_dir, instrument)
-    return load_raw_ws
-
-
-def _load_raw_file_range(files, input_dir, instrument):
-    loop = 0
-    num = files.split("_")
-    frange = list(range(int(num[0]), int(num[1]) + 1))
-    out_ws = None
-    for i in frange:
-        file_path = instrument._generate_input_full_path(i, input_dir)
-        outwork = "run" + str(i)
-        mantid.LoadRaw(Filename=file_path, OutputWorkspace=outwork, LoadLogFiles="0")
-        loop += 1
-        if loop == 2:
-            firstwk = "run" + str(i - 1)
-            secondwk = "run" + str(i)
-            out_ws = mantid.Plus(LHSWorkspace=firstwk, RHSWorkspace=secondwk)
-            mantid.mtd.remove(firstwk)
-            mantid.mtd.remove(secondwk)
-        elif loop > 2:
-            secondwk = "run" + str(i)
-            out_ws = mantid.Plus(LHSWorkspace=out_ws, RHSWorkspace=secondwk)
-            mantid.mtd.remove(secondwk)
-    return out_ws
-
-
-def _read_ws(number, instrument):
-    cycle_information = instrument._get_cycle_information(run_number=number)
-    input_dir = instrument._generate_raw_data_cycle_dir(cycle_information["cycle"])
-    read_in_ws = _load_raw_files(run_number=number, instrument=instrument, input_dir=input_dir)
-    # TODO move this into instrument specific
-    read_ws = mantid.ConvertUnits(InputWorkspace=read_in_ws, Target="Wavelength")
-    remove_intermediate_workspace(read_in_ws)
-
-    _read_pearl_monitor = instrument._get_monitor(run_number=number, input_dir=input_dir, spline_terms=20)
-
-    read_ws = mantid.NormaliseToMonitor(InputWorkspace=read_ws, MonitorWorkspace=_read_pearl_monitor,
-                                        IntegrationRangeMin=0.6, IntegrationRangeMax=5.0)
-    output_name = "read_ws_output-" + str(g_ads_workaround["read_pearl_ws"])
-    g_ads_workaround["read_pearl_ws"] += 1
-    output_ws = mantid.ConvertUnits(InputWorkspace=read_ws,
-                                    OutputWorkspace=output_name, Target="TOF")
-
-    remove_intermediate_workspace(_read_pearl_monitor)
-    remove_intermediate_workspace(read_ws)
-    return output_ws
-
-
-def _run_pearl_focus(instrument, run_number, perform_attenuation, perform_vanadium_norm):
-
-    cycle_information = instrument._get_cycle_information(run_number=run_number)
-
-    alg_range, save_range = instrument._get_instrument_alg_save_ranges(cycle_information["instrument_version"])
-
-    input_file_paths = instrument._get_calibration_full_paths(cycle=cycle_information["cycle"])
-
-    output_file_paths = instrument._generate_out_file_paths(run_number, instrument.output_dir)
-    read_ws = _read_ws(number=run_number, instrument=instrument)
-    input_workspace = mantid.Rebin(InputWorkspace=read_ws, Params=instrument._get_focus_tof_binning())
-    input_workspace = mantid.AlignDetectors(InputWorkspace=input_workspace, CalibrationFile=input_file_paths["calibration"])
-    input_workspace = mantid.DiffractionFocussing(InputWorkspace=input_workspace, GroupingFileName=input_file_paths["grouping"])
-
-    calibrated_spectra = _focus_load(alg_range, input_workspace, input_file_paths, instrument, perform_vanadium_norm)
-
-    remove_intermediate_workspace(read_ws)
-    remove_intermediate_workspace(input_workspace)
-
-    focus_mode = instrument.focus_mode
-    if focus_mode == "all":
-        processed_nexus_files = _focus_mode_all(output_file_paths, calibrated_spectra)
-
-    elif focus_mode == "groups":
-        processed_nexus_files = _focus_mode_groups(cycle_information, output_file_paths, save_range,
-                                                   calibrated_spectra)
-
-    elif focus_mode == "trans":
-
-        processed_nexus_files = _focus_mode_trans(output_file_paths, perform_attenuation, instrument, calibrated_spectra)
-
-    elif focus_mode == "mods":
-
-        processed_nexus_files = _focus_mode_mods(output_file_paths, calibrated_spectra)
-
-    else:
-        raise ValueError("Focus mode unknown")
-
-    for ws in calibrated_spectra:
-        remove_intermediate_workspace(ws)
-
-    return processed_nexus_files
-
-
-def _focus_mode_mods(output_file_paths, calibrated_spectra):
-    index = 1
-    append = False
-    output_list = []
-    for ws in calibrated_spectra:
-
-        mantid.SaveGSS(InputWorkspace=ws, Filename=output_file_paths["gss_filename"], Append=append, Bank=index)
-        output_name = output_file_paths["output_name"] + "_mod" + str(index)
-        dspacing_ws = mantid.ConvertUnits(InputWorkspace=ws, OutputWorkspace=output_name, Target="dSpacing")
-        output_list.append(dspacing_ws)
-        mantid.SaveNexus(Filename=output_file_paths["nxs_filename"], InputWorkspace=dspacing_ws, Append=append)
-
-        append = True
-        index += 1
-    return output_list
-
-
-def _focus_mode_trans(output_file_paths, atten, instrument, calibrated_spectra):
-    summed_ws = mantid.CloneWorkspace(InputWorkspace=calibrated_spectra[0])
-    for i in range(1, 9):  # Add workspaces 2-9 to workspace 1
-        summed_ws = mantid.Plus(LHSWorkspace=summed_ws, RHSWorkspace=calibrated_spectra[i])
-
-    summed_ws = mantid.Scale(InputWorkspace=summed_ws, Factor=0.111111111111111)
-
-    if atten:
-        # Clone a workspace which is not attenuated
-        no_att = output_file_paths["output_name"] + "_noatten"
-        mantid.CloneWorkspace(InputWorkspace=summed_ws, OutputWorkspace=no_att)
-
-        summed_ws = mantid.ConvertUnits(InputWorkspace=summed_ws, Target="dSpacing")
-        summed_ws = instrument._attenuate_workspace(summed_ws)
-        summed_ws = mantid.ConvertUnits(InputWorkspace=summed_ws, Target="TOF")
-
-    mantid.SaveGSS(InputWorkspace=summed_ws, Filename=output_file_paths["gss_filename"], Append=False, Bank=1)
-    mantid.SaveFocusedXYE(InputWorkspace=summed_ws, Filename=output_file_paths["tof_xye_filename"],
-                          Append=False, IncludeHeader=False)
-
-    summed_ws = mantid.ConvertUnits(InputWorkspace=summed_ws, Target="dSpacing")
-
-    # Rename to user friendly name:
-    summed_ws_name = output_file_paths["output_name"] + "_mods1-9"
-    summed_ws = mantid.RenameWorkspace(InputWorkspace=summed_ws, OutputWorkspace=summed_ws_name)
-
-    mantid.SaveFocusedXYE(InputWorkspace=summed_ws, Filename=output_file_paths["dspacing_xye_filename"],
-                          Append=False, IncludeHeader=False)
-    mantid.SaveNexus(InputWorkspace=summed_ws, Filename=output_file_paths["nxs_filename"], Append=False)
-
-    output_list = [summed_ws]
-
-    for i in range(0, 9):
-        workspace_name = output_file_paths["output_name"] + "_mod" + str(i + 1)
-        to_save = mantid.ConvertUnits(InputWorkspace=calibrated_spectra[i], Target="dSpacing",
-                                      OutputWorkspace=workspace_name)
-        output_list.append(to_save)
-        mantid.SaveNexus(Filename=output_file_paths["nxs_filename"], InputWorkspace=to_save, Append=True)
-
-    return output_list
-
-
-def _focus_mode_groups(cycle_information, output_file_paths, save_range, calibrated_spectra):
-    output_list = []
-    to_save = _sum_groups_of_three_ws(calibrated_spectra, output_file_paths)
-
-    workspaces_4_to_9_name = output_file_paths["output_name"] + "_mods4-9"
-    workspaces_4_to_9 = mantid.Plus(LHSWorkspace=to_save[1], RHSWorkspace=to_save[2])
-    workspaces_4_to_9 = mantid.Scale(InputWorkspace=workspaces_4_to_9, Factor=0.5,
-                                     OutputWorkspace=workspaces_4_to_9_name)
-    to_save.append(workspaces_4_to_9)
-    append = False
-    index = 1
-    for ws in to_save:
-        if cycle_information["instrument_version"] == "new":
-            mantid.SaveGSS(InputWorkspace=ws, Filename=output_file_paths["gss_filename"], Append=append,
-                           Bank=index)
-        elif cycle_information["instrument_version"] == "new2":
-            mantid.SaveGSS(InputWorkspace=ws, Filename=output_file_paths["gss_filename"], Append=False,
-                           Bank=index)
-
-        workspace_names = ws.name()
-        dspacing_ws = mantid.ConvertUnits(InputWorkspace=ws, OutputWorkspace=workspace_names, Target="dSpacing")
-        remove_intermediate_workspace(ws)
-        output_list.append(dspacing_ws)
-        mantid.SaveNexus(Filename=output_file_paths["nxs_filename"], InputWorkspace=dspacing_ws, Append=append)
-        append = True
-        index += 1
-
-    for i in range(0, save_range):
-        monitor_ws_name = output_file_paths["output_name"] + "_mod" + str(i + 10)
-
-        monitor_ws = calibrated_spectra[i + 9]
-        to_save = mantid.CloneWorkspace(InputWorkspace=monitor_ws, OutputWorkspace=monitor_ws_name)
-
-        mantid.SaveGSS(InputWorkspace=to_save, Filename=output_file_paths["gss_filename"], Append=True, Bank=i + 5)
-        to_save = mantid.ConvertUnits(InputWorkspace=to_save, OutputWorkspace=monitor_ws_name, Target="dSpacing")
-        mantid.SaveNexus(Filename=output_file_paths["nxs_filename"], InputWorkspace=to_save, Append=True)
-
-        output_list.append(to_save)
-
-    return output_list
-
-
-def _sum_groups_of_three_ws(calibrated_spectra, output_file_names):
-    workspace_list = []
-    output_list = []
-    for outer_loop_count in range(0, 3):
-        # First clone workspaces 1/4/7
-        pass_multiplier = (outer_loop_count * 3)
-        workspace_names = "focus_mode_groups-" + str(pass_multiplier + 1)
-        workspace_list.append(mantid.CloneWorkspace(InputWorkspace=calibrated_spectra[pass_multiplier],
-                                                    OutputWorkspace=workspace_names))
-        # Then add workspaces 1+2+3 / 4+5+6 / 7+8+9
-        for i in range(1, 3):
-            input_ws_index = i + pass_multiplier  # Workspaces 2/3 * n
-            inner_workspace_names = "focus_mode_groups-" + str(input_ws_index)
-            workspace_list[outer_loop_count] = mantid.Plus(LHSWorkspace=workspace_list[outer_loop_count],
-                                                           RHSWorkspace=calibrated_spectra[input_ws_index],
-                                                           OutputWorkspace=inner_workspace_names)
-
-        # Finally scale the output workspaces
-        mod_first_number = str((outer_loop_count * 3) + 1)  # Generates 1/4/7
-        mod_last_number = str((outer_loop_count + 1) * 3)  # Generates 3/6/9
-        workspace_names = output_file_names["output_name"] + "_mod" + mod_first_number + '-' + mod_last_number
-        output_list.append(mantid.Scale(InputWorkspace=workspace_list[outer_loop_count],
-                                        OutputWorkspace=workspace_names, Factor=0.333333333333))
-    for ws in workspace_list:
-        remove_intermediate_workspace(ws)
-    return output_list
-
-
-def _focus_mode_all(output_file_paths, calibrated_spectra):
-    first_spectrum = calibrated_spectra[0]
-    summed_spectra = mantid.CloneWorkspace(InputWorkspace=first_spectrum)
-
-    for i in range(1, 9):  # TODO why is this 1-8
-        summed_spectra = mantid.Plus(LHSWorkspace=summed_spectra, RHSWorkspace=calibrated_spectra[i])
-
-    summed_spectra_name = output_file_paths["output_name"] + "_mods1-9"
-
-    summed_spectra = mantid.Scale(InputWorkspace=summed_spectra, Factor=0.111111111111111,
-                                  OutputWorkspace=summed_spectra_name)
-    mantid.SaveGSS(InputWorkspace=summed_spectra, Filename=output_file_paths["gss_filename"], Append=False, Bank=1)
-
-    summed_spectra = mantid.ConvertUnits(InputWorkspace=summed_spectra, Target="dSpacing",
-                                         OutputWorkspace=summed_spectra_name)
-    mantid.SaveNexus(Filename=output_file_paths["nxs_filename"], InputWorkspace=summed_spectra, Append=False)
-
-    output_list = [summed_spectra]
-    for i in range(0, 3):
-        spectra_index = (i + 9)  # We want workspaces 10/11/12 so compensate for 0 based index
-        ws_to_save = calibrated_spectra[spectra_index]  # Save out workspaces 10/11/12
-        output_name = output_file_paths["output_name"] + "_mod" + str(spectra_index + 1)
-        mantid.SaveGSS(InputWorkspace=ws_to_save, Filename=output_file_paths["gss_filename"], Append=True, Bank=i + 2)
-        ws_to_save = mantid.ConvertUnits(InputWorkspace=ws_to_save, OutputWorkspace=output_name, Target="dSpacing")
-        output_list.append(ws_to_save)
-        mantid.SaveNexus(Filename=output_file_paths["nxs_filename"], InputWorkspace=ws_to_save, Append=True)
-
-    return output_list
-
-
-def _focus_load(alg_range, focused_ws, input_file_paths, instrument, van_norm):
-    processed_spectra = []
-
-    for index in range(0, alg_range):
-        if van_norm:
-            vanadium_ws = mantid.LoadNexus(Filename=input_file_paths["vanadium"], EntryNumber=index + 1)
-            van_rebinned = mantid.Rebin(InputWorkspace=vanadium_ws, Params=instrument._get_focus_tof_binning())
-
-            processed_spectra.append(calc_calibration_with_vanadium(focused_ws, index, van_rebinned, instrument))
-
-            remove_intermediate_workspace(vanadium_ws)
-            remove_intermediate_workspace(van_rebinned)
-        else:
-            processed_spectra.append(calc_calibration_without_vanadium(focused_ws, index, instrument))
-
-    return processed_spectra
-
-
-def calc_calibration_without_vanadium(focused_ws, index, instrument):
-    focus_spectrum = mantid.ExtractSingleSpectrum(InputWorkspace=focused_ws, WorkspaceIndex=index)
-    focus_spectrum = mantid.ConvertUnits(InputWorkspace=focus_spectrum, Target="TOF")
-    focus_spectrum = mantid.Rebin(InputWorkspace=focus_spectrum, Params=instrument.tof_binning)
-    focus_calibrated = mantid.CropWorkspace(InputWorkspace=focus_spectrum, XMin=0.1)
-    return focus_calibrated
-
-
-def calc_calibration_with_vanadium(focused_ws, index, vanadium_ws, instrument):
-    data_ws = mantid.ExtractSingleSpectrum(InputWorkspace=focused_ws, WorkspaceIndex=index)
-    data_ws = mantid.ConvertUnits(InputWorkspace=data_ws, Target="TOF")
-    data_ws = mantid.Rebin(InputWorkspace=data_ws, Params=instrument._get_focus_tof_binning())
-
-    data_processed = "van_processed" + str(index)  # Workaround for Mantid overwriting the WS in a loop
-
-    mantid.Divide(LHSWorkspace=data_ws, RHSWorkspace=vanadium_ws, OutputWorkspace=data_processed)
-    mantid.CropWorkspace(InputWorkspace=data_processed, XMin=0.1, OutputWorkspace=data_processed)
-    mantid.Scale(InputWorkspace=data_processed, Factor=10, OutputWorkspace=data_processed)
-
-    remove_intermediate_workspace(data_ws)
-
-    return data_processed
-
-
-def _remove_ws(ws_to_remove):
-    """
-    Removes any intermediate workspaces if debug is set to false
-        @param ws_to_remove: The workspace to remove from the ADS
-    """
-    try:
-        if not g_debug:
-            _remove_ws_wrapper(ws=ws_to_remove)
-    except NameError:  # If g_debug has not been set
-        _remove_ws_wrapper(ws=ws_to_remove)
-
-
-def _remove_ws_wrapper(ws):
-    mantid.DeleteWorkspace(ws)
-    del ws  # Mark it as deleted so that Python can throw before Mantid preserving more information
diff --git a/scripts/Diffraction/isis_powder/mock_instrument.py b/scripts/Diffraction/isis_powder/mock_instrument.py
index 0e62d7b59cc2fbae0f28466732ec33979014086b..4b8cc76fb84b51ab79c7038b5d6b1ccfa1102790 100644
--- a/scripts/Diffraction/isis_powder/mock_instrument.py
+++ b/scripts/Diffraction/isis_powder/mock_instrument.py
@@ -3,10 +3,9 @@ from isis_powder.abstract_inst import AbstractInst
 
 class MockInstrument(AbstractInst):
 
-    def __init__(self, user_name, calibration_dir, raw_data_dir, output_dir, default_ext="", tt_mode=None):
+    def __init__(self, user_name, calibration_dir, output_dir, default_ext=""):
         super(MockInstrument, self).__init__(user_name=user_name, calibration_dir=calibration_dir,
-                                             raw_data_dir=raw_data_dir, output_dir=output_dir,
-                                             default_input_ext=default_ext, tt_mode=tt_mode)
+                                             output_dir=output_dir, default_input_ext=default_ext)
         self.generate_cycle_dir_flag = False
 
     def _get_lambda_range(self):
@@ -21,7 +20,7 @@ class MockInstrument(AbstractInst):
     def _get_default_group_names(self):
         return None
 
-    def _get_calibration_full_paths(self, cycle):
+    def _get_run_details(self, run_number):
         # This is here to help remind people of the dict that is expected
         calibration_details = {"calibration": "cal",
                                "grouping": "group",
@@ -38,7 +37,7 @@ class MockInstrument(AbstractInst):
         return None
 
     @staticmethod
-    def _get_cycle_information(run_number):
+    def _get_label_information(run_number):
         # This is here to help remind people of the dict format
         cycle_information = {"cycle" : "123",
                              "instrument_version": "test_v1"}
diff --git a/scripts/Diffraction/isis_powder/pearl.py b/scripts/Diffraction/isis_powder/pearl.py
index 3e14fdf3ed8cd212afb1072056bd20a37fa5d5dc..6a350de95d062ac87a055f6725d790e1e559f073 100644
--- a/scripts/Diffraction/isis_powder/pearl.py
+++ b/scripts/Diffraction/isis_powder/pearl.py
@@ -1,14 +1,15 @@
 from __future__ import (absolute_import, division, print_function)
 
+import os
+
 import mantid.simpleapi as mantid
 import numpy as numpy
+from mantid import config
 
-import os
-
+import isis_powder.routines.common as common
 from isis_powder.abstract_inst import AbstractInst
-from isis_powder import pearl_calib_factory
-from isis_powder import pearl_cycle_factory
-import isis_powder.common as common
+from isis_powder.pearl_routines import fmode_output, pearl_calib_factory, pearl_cycle_factory
+from isis_powder.routines.RunDetails import RunDetails
 
 
 class Pearl(AbstractInst):
@@ -25,28 +26,41 @@ class Pearl(AbstractInst):
     _create_van_first_tof_binning = "100,-0.0006,19990"
     _create_van_second_tof_binning = "150,-0.0006,19900"
 
-    def __init__(self, user_name=None, calibration_dir=None, raw_data_dir=None, output_dir=None,
-                 input_file_ext=".raw", tt_mode="TT88"):
+    def __init__(self, user_name, tt_mode="TT88", calibration_dir=None, output_dir=None, **kwargs):
 
-        super(Pearl, self).__init__(user_name=user_name, calibration_dir=calibration_dir, raw_data_dir=raw_data_dir,
-                                    output_dir=output_dir, default_input_ext=input_file_ext, tt_mode=tt_mode)
+        super(Pearl, self).__init__(user_name=user_name, calibration_dir=calibration_dir,
+                                    output_dir=output_dir, kwargs=kwargs)
+
+        self._tt_mode = tt_mode
+        self._focus_mode = None
 
         # This advanced option disables appending the current cycle to the
         # path given for raw files.
         self._disable_appending_cycle_to_raw_dir = False
 
-        # live_data_directory = None  # TODO deal with this
-
         # Old API support
         self._old_atten_file = None
-        self._old_api_uses_full_paths = False
+        self._existing_config = None
 
         # File names
-        pearl_mc_absorption_file_name = "PRL112_DC25_10MM_FF.OUT"  # TODO
-        self._attenuation_full_path = calibration_dir + pearl_mc_absorption_file_name  # TODO
+        pearl_mc_absorption_file_name = "PRL112_DC25_10MM_FF.OUT"  # TODO how often does this change
+        self._attenuation_full_path = os.path.join(calibration_dir, pearl_mc_absorption_file_name)
 
     # --- Abstract Implementation ---- #
 
+    def focus(self, run_number, focus_mode, do_attenuation=True, do_van_normalisation=True):
+        self._focus_mode = focus_mode
+        return self._focus(run_number=run_number,
+                           do_attenuation=do_attenuation, do_van_normalisation=do_van_normalisation)
+
+    def create_calibration_vanadium(self, vanadium_runs, empty_runs, output_file_name=None, num_of_splines=60,
+                                    do_absorb_corrections=True, gen_absorb_correction=False):
+
+        self._create_calibration_vanadium(vanadium_runs=vanadium_runs, empty_runs=empty_runs,
+                                          output_file_name=output_file_name, num_of_splines=num_of_splines,
+                                          do_absorb_corrections=do_absorb_corrections,
+                                          gen_absorb_correction=gen_absorb_correction)
+
     # Params #
     def _get_default_group_names(self):
         return self._default_group_names
@@ -54,9 +68,6 @@ class Pearl(AbstractInst):
     def _get_lambda_range(self):
         return self._lambda_lower, self._lambda_upper
 
-    def _get_focus_tof_binning(self):
-        return self._focus_tof_binning
-
     def _get_create_van_tof_binning(self):
         return_dict = {"1": self._create_van_first_tof_binning,
                        "2": self._create_van_second_tof_binning}
@@ -64,28 +75,46 @@ class Pearl(AbstractInst):
 
     # Methods #
 
-    def _get_calibration_full_paths(self, cycle):
+    def _get_run_details(self, run_number):
+        # TODO once we migrate this to another format (i.e. not the if/elif/else) implement cached val
+        cycle_dict = self._get_label_information(run_number=run_number)
 
         calibration_file, grouping_file, van_absorb, van_file =\
-            pearl_calib_factory.get_calibration_filename(cycle=cycle, tt_mode=self.tt_mode)
+            pearl_calib_factory.get_calibration_filename(cycle=cycle_dict["cycle"], tt_mode=self._tt_mode)
+        cycle, instrument_version = pearl_cycle_factory.get_cycle_dir(run_number)
 
         calibration_dir = self.calibration_dir
 
-        calibration_full_path = calibration_dir + calibration_file
-        grouping_full_path = calibration_dir + grouping_file
-        van_absorb_full_path = calibration_dir + van_absorb
-        van_file_full_path = calibration_dir + van_file
+        calibration_full_path = os.path.join(calibration_dir, calibration_file)
+        grouping_full_path = os.path.join(calibration_dir, grouping_file)
+        van_absorb_full_path = os.path.join(calibration_dir, van_absorb)
+        van_file_full_path = os.path.join(calibration_dir, van_file)
 
-        calibration_details = {"calibration": calibration_full_path,
-                               "grouping": grouping_full_path,
-                               "vanadium_absorption": van_absorb_full_path,
-                               "vanadium": van_file_full_path}
+        run_details = RunDetails(calibration_path=calibration_full_path, grouping_path=grouping_full_path,
+                                 vanadium_runs=van_file_full_path, run_number=run_number)
+        run_details.vanadium_absorption = van_absorb_full_path
+        run_details.label = cycle
+        run_details.instrument_version = instrument_version
 
-        return calibration_details
+        # TODO remove this when we move to saving splined van ws on PEARL
+        run_details.splined_vanadium = run_details.vanadium
 
-    @staticmethod
-    def _get_cycle_information(run_number):
-        cycle, instrument_version = pearl_cycle_factory.get_cycle_dir(run_number)
+        return run_details
+
+    def _get_label_information(self, run_number):
+        # TODO remove this when we move to combining CAL/RUN factories
+        run_input = ""
+        if isinstance(run_number, int) or run_number.isdigit():
+            run_input = int(run_number)
+        else:
+            # Only take first valid number as it is probably of the form 12345_12350
+            for character in run_number:
+                if character.isdigit():
+                    run_input += character
+                else:
+                    break
+
+        cycle, instrument_version = pearl_cycle_factory.get_cycle_dir(run_input)
 
         cycle_information = {'cycle': cycle,
                              'instrument_version': instrument_version}
@@ -105,10 +134,9 @@ class Pearl(AbstractInst):
         return self._run_attenuate_workspace(input_workspace=input_workspace)
 
     def _create_calibration(self, calibration_runs, offset_file_name, grouping_file_name):
-        input_ws = common._read_ws(number=calibration_runs, instrument=self)
-        cycle_information = self._get_cycle_information(calibration_runs)
+        input_ws = common.load_current_normalised_ws(run_number_string=calibration_runs, instrument=self)
+        cycle_information = self._get_label_information(calibration_runs)
 
-        # TODO move these hard coded params to instrument specific
         if cycle_information["instrument_version"] == "new" or cycle_information["instrument_version"] == "new2":
             input_ws = mantid.Rebin(InputWorkspace=input_ws, Params="100,-0.0006,19950")
 
@@ -129,8 +157,8 @@ class Pearl(AbstractInst):
             grouping_file_path = grouping_file_name
             offset_file_path = offset_file_name
         else:
-            offset_file_path = self.calibration_dir + offset_file_name
-            grouping_file_path = self.calibration_dir + grouping_file_name
+            offset_file_path = os.path.join(self.calibration_dir, offset_file_name)
+            grouping_file_path = os.path.join(self.calibration_dir, grouping_file_name)
 
         # Ceo Cell refined to 5.4102(3) so 220 is 1.912795
         offset_output_path = mantid.GetDetectorOffsets(InputWorkspace=cross_cor_ws, Step=0.002, DReference=1.912795,
@@ -147,8 +175,12 @@ class Pearl(AbstractInst):
     def _create_calibration_silicon(self, calibration_runs, cal_file_name, grouping_file_name):
         self._do_silicon_calibration(calibration_runs, cal_file_name, grouping_file_name)
 
-    def _get_monitor(self, run_number, input_dir, spline_terms=20):
-        return self._run_get_monitor(run_number=run_number, input_dir=input_dir, spline_terms=spline_terms)
+    def _normalise_ws(self, ws_to_correct, run_details=None):
+        if not run_details:
+            raise RuntimeError("Run details was not passed into PEARL: normalise_ws")
+        monitor_ws = common.load_monitor(run_numbers=run_details.run_number, instrument=self)
+        return self._normalise_current_ws(ws_to_correct=ws_to_correct, load_monitor_ws=monitor_ws,
+                                          spline_terms=20)
 
     def _get_monitor_spectra(self, run_number):
         return self._get_monitor_spectrum(run_number=run_number)
@@ -164,11 +196,81 @@ class Pearl(AbstractInst):
             out_list = _spline_new_background(in_workspace=focused_vanadium_ws, num_splines=spline_number,
                                               instrument_version=instrument_version)
         elif instrument_version == "old":
-            out_list = _spline_old_background(in_workspace=focused_vanadium_ws)
+            out_list = _spline_old_instrument_background(in_workspace=focused_vanadium_ws)
         else:
             raise ValueError("Spline Background - PEARL: Instrument version unknown")
         return out_list
 
+    def _do_tof_rebinning_focus(self, input_workspace):
+        input_workspace = mantid.Rebin(InputWorkspace=input_workspace, Params=self._focus_tof_binning)
+        return input_workspace
+
+    def _focus_processing(self, run_number, input_workspace, perform_vanadium_norm):
+        return self._perform_focus_loading(run_number, input_workspace, perform_vanadium_norm)
+
+    def _process_focus_output(self, processed_spectra, run_details, attenuate=False):
+        return fmode_output.generate_and_save_focus_output(self, processed_spectra=processed_spectra,
+                                                           run_details=run_details,
+                                                           perform_attenuation=attenuate,
+                                                           focus_mode=self._focus_mode)
+
+    def _apply_van_calibration_tof_rebinning(self, vanadium_ws, tof_rebin_pass, return_units):
+        tof_rebin_param_dict = self._get_create_van_tof_binning()
+        tof_rebin_param = tof_rebin_param_dict[str(tof_rebin_pass)]
+
+        rebinned_ws = mantid.ConvertUnits(InputWorkspace=vanadium_ws, Target="TOF")
+        rebinned_ws = mantid.Rebin(InputWorkspace=rebinned_ws, Params=tof_rebin_param)
+
+        rebinned_ws = mantid.ConvertUnits(InputWorkspace=rebinned_ws, Target=return_units)
+
+        common.remove_intermediate_workspace(vanadium_ws)
+        vanadium_ws = rebinned_ws
+        return vanadium_ws
+
+    def _generate_vanadium_absorb_corrections(self, calibration_full_paths, ws_to_match):
+        raise NotImplementedError("Generating absorption corrections needs to be implemented correctly")
+
+        # TODO are these values applicable to all instruments
+        shape_ws = mantid.CloneWorkspace(InputWorkspace=ws_to_match)
+        mantid.CreateSampleShape(InputWorkspace=shape_ws, ShapeXML='<sphere id="sphere_1"> <centre x="0" y="0" z= "0" />\
+                                                          <radius val="0.005" /> </sphere>')
+
+        absorb_ws = \
+            mantid.AbsorptionCorrection(InputWorkspace=shape_ws, AttenuationXSection="5.08",
+                                        ScatteringXSection="5.1", SampleNumberDensity="0.072",
+                                        NumberOfWavelengthPoints="25", ElementSize="0.05")
+        mantid.SaveNexus(Filename=calibration_full_paths["vanadium_absorption"],
+                         InputWorkspace=absorb_ws, Append=False)
+        common.remove_intermediate_workspace(shape_ws)
+        return absorb_ws
+
+    def _calibration_rebin_to_workspace(self, ws_to_rebin, ws_to_match):
+        rebinned_ws = mantid.RebinToWorkspace(WorkspaceToRebin=ws_to_rebin, WorkspaceToMatch=ws_to_match)
+        common.remove_intermediate_workspace(ws_to_rebin)
+        ws_to_rebin = rebinned_ws
+        return ws_to_rebin
+
+    def correct_sample_vanadium(self, focused_ws, index, vanadium_ws=None):
+        data_ws = mantid.ExtractSingleSpectrum(InputWorkspace=focused_ws, WorkspaceIndex=index)
+        data_ws = mantid.ConvertUnits(InputWorkspace=data_ws, Target="TOF")
+        data_ws = mantid.Rebin(InputWorkspace=data_ws, Params=self._focus_tof_binning)
+
+        if vanadium_ws:
+            data_processed = "van_processed" + str(index)  # Workaround for Mantid overwriting the WS in a loop
+            vanadium_ws = mantid.Rebin(InputWorkspace=vanadium_ws, Params=self._focus_tof_binning)
+            data_ws = mantid.Divide(LHSWorkspace=data_ws, RHSWorkspace=vanadium_ws, OutputWorkspace=data_processed)
+        else:
+            data_processed = "processed-" + str(index)
+
+        mantid.CropWorkspace(InputWorkspace=data_ws, XMin=0.1, OutputWorkspace=data_processed)
+
+        if vanadium_ws:
+            mantid.Scale(InputWorkspace=data_processed, Factor=10, OutputWorkspace=data_processed)
+
+        common.remove_intermediate_workspace(data_ws)
+
+        return data_processed
+
     # Implementation of instrument specific steps
 
     def _run_attenuate_workspace(self, input_workspace):
@@ -186,8 +288,9 @@ class Pearl(AbstractInst):
         return pearl_attenuated_ws
 
     def _do_silicon_calibration(self, runs_to_process, cal_file_name, grouping_file_name):
-        create_si_ws = common._read_ws(number=runs_to_process, instrument=self)
-        cycle_details = self._get_cycle_information(runs_to_process)
+        # TODO fix all of this as the script is too limited to be useful
+        create_si_ws = common.load_current_normalised_ws(run_number_string=runs_to_process, instrument=self)
+        cycle_details = self._get_label_information(runs_to_process)
         instrument_version = cycle_details["instrument_version"]
 
         if instrument_version == "new" or instrument_version == "new2":
@@ -227,8 +330,7 @@ class Pearl(AbstractInst):
                                                            GroupingFileName=grouping_output_path)
         del create_si_offsets_ws, create_si_grouped_ws
 
-    def _run_get_monitor(self, run_number, input_dir, spline_terms):
-        load_monitor_ws = common._load_monitor(run_number, input_dir=input_dir, instrument=self)
+    def _normalise_current_ws(self, ws_to_correct, load_monitor_ws, spline_terms):
         get_monitor_ws = mantid.ConvertUnits(InputWorkspace=load_monitor_ws, Target="Wavelength")
         common.remove_intermediate_workspace(load_monitor_ws)
         lmin, lmax = self._get_lambda_range()
@@ -238,15 +340,22 @@ class Pearl(AbstractInst):
         ex_regions[:, 1] = [2.96, 3.2]
         ex_regions[:, 2] = [2.1, 2.26]
         ex_regions[:, 3] = [1.73, 1.98]
-        # ConvertToDistribution(works)
 
         for reg in range(0, 4):
             get_monitor_ws = mantid.MaskBins(InputWorkspace=get_monitor_ws, XMin=ex_regions[0, reg],
                                              XMax=ex_regions[1, reg])
 
         monitor_ws = mantid.SplineBackground(InputWorkspace=get_monitor_ws, WorkspaceIndex=0, NCoeff=spline_terms)
+
+        normalised_ws = mantid.ConvertUnits(InputWorkspace=ws_to_correct, Target="Wavelength")
+        normalised_ws = mantid.NormaliseToMonitor(InputWorkspace=normalised_ws, MonitorWorkspace=monitor_ws,
+                                                  IntegrationRangeMin=0.6, IntegrationRangeMax=5.0)
+        normalised_ws = mantid.ConvertUnits(InputWorkspace=normalised_ws, Target="TOF")
+
         common.remove_intermediate_workspace(get_monitor_ws)
-        return monitor_ws
+        common.remove_intermediate_workspace(monitor_ws)
+
+        return normalised_ws
 
     def _get_monitor_spectrum(self, run_number):
         if run_number < 71009:
@@ -262,7 +371,18 @@ class Pearl(AbstractInst):
             mspectra = 1
         return mspectra
 
-    # Support for old API
+    def _generate_raw_data_cycle_dir(self, run_cycle):
+        if self._skip_appending_cycle_to_raw_dir():
+            return self.raw_data_dir
+        str_run_cycle = str(run_cycle)
+
+        # Append current cycle to raw data directory
+        generated_dir = os.path.join(self.raw_data_dir, str_run_cycle)
+        generated_dir += '/'
+
+        return generated_dir
+
+    # Support for old API - This can be removed when PEARL_routines is removed
     def _old_api_constructor_set(self, user_name=None, calibration_dir=None, raw_data_dir=None, output_dir=None,
                                  input_file_ext=None, tt_mode=None):
         # Any param can be set so check each individually
@@ -286,7 +406,7 @@ class Pearl(AbstractInst):
         self._calibration_dir = calib_dir
 
     def _old_api_set_raw_data_dir(self, raw_data_dir):
-        self._disable_appending_cycle_to_raw_dir = True
+        self._old_api_uses_full_paths = True
         self._raw_data_dir = raw_data_dir
 
     def _old_api_set_output_dir(self, output_dir):
@@ -301,9 +421,20 @@ class Pearl(AbstractInst):
     def _old_api_set_full_paths(self, val):
         self._old_api_uses_full_paths = val
 
-    def _PEARL_use_full_path(self):
+    def _PEARL_filename_is_full_path(self):
         return self._old_api_uses_full_paths
 
+    def PEARL_setup_input_directories(self, run_number):
+        run_details = self._get_run_details(run_number=run_number)
+        generated_path = self._generate_raw_data_cycle_dir(run_cycle=run_details.label)
+        user_dirs = config['datasearch.directories']
+        user_dirs_list = user_dirs.split(';')
+        if generated_path not in user_dirs_list:
+            config['datasearch.directories'] += ';' + generated_path
+
+    def _get_focus_tof_binning(self):
+        return self._focus_tof_binning
+
 
 def _old_api_get_file_name(in_path):
     # Gets the filename from a full path
@@ -394,7 +525,7 @@ def _perform_spline_range(instrument_version, num_splines, stripped_ws):
     return splined_ws_list
 
 
-def _spline_old_background(in_workspace):
+def _spline_old_instrument_background(in_workspace):
     van_stripped = mantid.ConvertUnits(InputWorkspace=in_workspace, Target="dSpacing")
 
     # remove bragg peaks before spline
diff --git a/Testing/SystemTests/tests/analysis/ISIS_PowderDiffractionScriptCalTest.py b/scripts/Diffraction/isis_powder/pearl_routines/__init__.py
similarity index 100%
rename from Testing/SystemTests/tests/analysis/ISIS_PowderDiffractionScriptCalTest.py
rename to scripts/Diffraction/isis_powder/pearl_routines/__init__.py
diff --git a/scripts/Diffraction/isis_powder/pearl_routines/fmode_output.py b/scripts/Diffraction/isis_powder/pearl_routines/fmode_output.py
new file mode 100644
index 0000000000000000000000000000000000000000..16dd8da3c47a53c8e7bf14e96943b2f0494f14f4
--- /dev/null
+++ b/scripts/Diffraction/isis_powder/pearl_routines/fmode_output.py
@@ -0,0 +1,192 @@
+from __future__ import (absolute_import, division, print_function)
+
+import mantid.simpleapi as mantid
+
+import isis_powder.routines.common as common
+
+# This file generates the various outputs for the PEARL instruments and saves them to their respective files
+
+
+def generate_and_save_focus_output(instrument, processed_spectra, run_details, perform_attenuation, focus_mode=None):
+    output_file_paths = instrument._generate_out_file_paths(run_details=run_details)
+    cycle_information = instrument._get_label_information(run_details.run_number)
+    unused, save_range = instrument._get_instrument_alg_save_ranges(cycle_information["instrument_version"])
+
+    if focus_mode == "all":
+        processed_nexus_files = _focus_mode_all(output_file_paths, processed_spectra)
+
+    elif focus_mode == "groups":
+        processed_nexus_files = _focus_mode_groups(cycle_information, output_file_paths, save_range,
+                                                   processed_spectra)
+
+    elif focus_mode == "trans":
+
+        processed_nexus_files = _focus_mode_trans(output_file_paths, perform_attenuation, instrument, processed_spectra)
+
+    elif focus_mode == "mods":
+
+        processed_nexus_files = _focus_mode_mods(output_file_paths, processed_spectra)
+
+    else:
+        raise ValueError("Focus mode unknown")
+
+    return processed_nexus_files
+
+
+def _focus_mode_mods(output_file_paths, calibrated_spectra):
+    index = 1
+    append = False
+    output_list = []
+    for ws in calibrated_spectra:
+
+        mantid.SaveGSS(InputWorkspace=ws, Filename=output_file_paths["gss_filename"], Append=append, Bank=index)
+        output_name = output_file_paths["output_name"] + "_mod" + str(index)
+        dspacing_ws = mantid.ConvertUnits(InputWorkspace=ws, OutputWorkspace=output_name, Target="dSpacing")
+        output_list.append(dspacing_ws)
+        mantid.SaveNexus(Filename=output_file_paths["nxs_filename"], InputWorkspace=dspacing_ws, Append=append)
+
+        append = True
+        index += 1
+    return output_list
+
+
+def _focus_mode_trans(output_file_paths, atten, instrument, calibrated_spectra):
+    summed_ws = mantid.CloneWorkspace(InputWorkspace=calibrated_spectra[0])
+    for i in range(1, 9):  # Add workspaces 2-9 to workspace 1
+        summed_ws = mantid.Plus(LHSWorkspace=summed_ws, RHSWorkspace=calibrated_spectra[i])
+
+    summed_ws = mantid.Scale(InputWorkspace=summed_ws, Factor=0.111111111111111)
+
+    if atten:
+        # Clone a workspace which is not attenuated
+        no_att = output_file_paths["output_name"] + "_noatten"
+        mantid.CloneWorkspace(InputWorkspace=summed_ws, OutputWorkspace=no_att)
+
+        summed_ws = mantid.ConvertUnits(InputWorkspace=summed_ws, Target="dSpacing")
+        summed_ws = instrument._attenuate_workspace(summed_ws)
+        summed_ws = mantid.ConvertUnits(InputWorkspace=summed_ws, Target="TOF")
+
+    mantid.SaveGSS(InputWorkspace=summed_ws, Filename=output_file_paths["gss_filename"], Append=False, Bank=1)
+    mantid.SaveFocusedXYE(InputWorkspace=summed_ws, Filename=output_file_paths["tof_xye_filename"],
+                          Append=False, IncludeHeader=False)
+
+    summed_ws = mantid.ConvertUnits(InputWorkspace=summed_ws, Target="dSpacing")
+
+    # Rename to user friendly name:
+    summed_ws_name = output_file_paths["output_name"] + "_mods1-9"
+    summed_ws = mantid.RenameWorkspace(InputWorkspace=summed_ws, OutputWorkspace=summed_ws_name)
+
+    mantid.SaveFocusedXYE(InputWorkspace=summed_ws, Filename=output_file_paths["dspacing_xye_filename"],
+                          Append=False, IncludeHeader=False)
+    mantid.SaveNexus(InputWorkspace=summed_ws, Filename=output_file_paths["nxs_filename"], Append=False)
+
+    output_list = [summed_ws]
+
+    for i in range(0, 9):
+        workspace_name = output_file_paths["output_name"] + "_mod" + str(i + 1)
+        to_save = mantid.ConvertUnits(InputWorkspace=calibrated_spectra[i], Target="dSpacing",
+                                      OutputWorkspace=workspace_name)
+        output_list.append(to_save)
+        mantid.SaveNexus(Filename=output_file_paths["nxs_filename"], InputWorkspace=to_save, Append=True)
+
+    return output_list
+
+
+def _focus_mode_groups(cycle_information, output_file_paths, save_range, calibrated_spectra):
+    output_list = []
+    to_save = _sum_groups_of_three_ws(calibrated_spectra, output_file_paths)
+
+    workspaces_4_to_9_name = output_file_paths["output_name"] + "_mods4-9"
+    workspaces_4_to_9 = mantid.Plus(LHSWorkspace=to_save[1], RHSWorkspace=to_save[2])
+    workspaces_4_to_9 = mantid.Scale(InputWorkspace=workspaces_4_to_9, Factor=0.5,
+                                     OutputWorkspace=workspaces_4_to_9_name)
+    to_save.append(workspaces_4_to_9)
+    append = False
+    index = 1
+    for ws in to_save:
+        if cycle_information["instrument_version"] == "new":
+            mantid.SaveGSS(InputWorkspace=ws, Filename=output_file_paths["gss_filename"], Append=append,
+                           Bank=index)
+        elif cycle_information["instrument_version"] == "new2":
+            mantid.SaveGSS(InputWorkspace=ws, Filename=output_file_paths["gss_filename"], Append=False,
+                           Bank=index)
+
+        workspace_names = ws.name()
+        dspacing_ws = mantid.ConvertUnits(InputWorkspace=ws, OutputWorkspace=workspace_names, Target="dSpacing")
+        common.remove_intermediate_workspace(ws)
+        output_list.append(dspacing_ws)
+        mantid.SaveNexus(Filename=output_file_paths["nxs_filename"], InputWorkspace=dspacing_ws, Append=append)
+        append = True
+        index += 1
+
+    for i in range(0, save_range):
+        monitor_ws_name = output_file_paths["output_name"] + "_mod" + str(i + 10)
+
+        monitor_ws = calibrated_spectra[i + 9]
+        to_save = mantid.CloneWorkspace(InputWorkspace=monitor_ws, OutputWorkspace=monitor_ws_name)
+
+        mantid.SaveGSS(InputWorkspace=to_save, Filename=output_file_paths["gss_filename"], Append=True, Bank=i + 5)
+        to_save = mantid.ConvertUnits(InputWorkspace=to_save, OutputWorkspace=monitor_ws_name, Target="dSpacing")
+        mantid.SaveNexus(Filename=output_file_paths["nxs_filename"], InputWorkspace=to_save, Append=True)
+
+        output_list.append(to_save)
+
+    return output_list
+
+
+def _focus_mode_all(output_file_paths, calibrated_spectra):
+    first_spectrum = calibrated_spectra[0]
+    summed_spectra = mantid.CloneWorkspace(InputWorkspace=first_spectrum)
+
+    for i in range(1, 9):
+        summed_spectra = mantid.Plus(LHSWorkspace=summed_spectra, RHSWorkspace=calibrated_spectra[i])
+
+    summed_spectra_name = output_file_paths["output_name"] + "_mods1-9"
+
+    summed_spectra = mantid.Scale(InputWorkspace=summed_spectra, Factor=0.111111111111111,
+                                  OutputWorkspace=summed_spectra_name)
+    mantid.SaveGSS(InputWorkspace=summed_spectra, Filename=output_file_paths["gss_filename"], Append=False, Bank=1)
+
+    summed_spectra = mantid.ConvertUnits(InputWorkspace=summed_spectra, Target="dSpacing",
+                                         OutputWorkspace=summed_spectra_name)
+    mantid.SaveNexus(Filename=output_file_paths["nxs_filename"], InputWorkspace=summed_spectra, Append=False)
+
+    output_list = [summed_spectra]
+    for i in range(0, 3):
+        spectra_index = (i + 9)  # We want workspaces 10/11/12 so compensate for 0 based index
+        ws_to_save = calibrated_spectra[spectra_index]  # Save out workspaces 10/11/12
+        output_name = output_file_paths["output_name"] + "_mod" + str(spectra_index + 1)
+        mantid.SaveGSS(InputWorkspace=ws_to_save, Filename=output_file_paths["gss_filename"], Append=True, Bank=i + 2)
+        ws_to_save = mantid.ConvertUnits(InputWorkspace=ws_to_save, OutputWorkspace=output_name, Target="dSpacing")
+        output_list.append(ws_to_save)
+        mantid.SaveNexus(Filename=output_file_paths["nxs_filename"], InputWorkspace=ws_to_save, Append=True)
+
+    return output_list
+
+
+def _sum_groups_of_three_ws(calibrated_spectra, output_file_names):
+    workspace_list = []
+    output_list = []
+    for outer_loop_count in range(0, 3):
+        # First clone workspaces 1/4/7
+        pass_multiplier = (outer_loop_count * 3)
+        workspace_names = "focus_mode_groups-" + str(pass_multiplier + 1)
+        workspace_list.append(mantid.CloneWorkspace(InputWorkspace=calibrated_spectra[pass_multiplier],
+                                                    OutputWorkspace=workspace_names))
+        # Then add workspaces 1+2+3 / 4+5+6 / 7+8+9
+        for i in range(1, 3):
+            input_ws_index = i + pass_multiplier  # Workspaces 2/3 * n
+            inner_workspace_names = "focus_mode_groups-" + str(input_ws_index)
+            workspace_list[outer_loop_count] = mantid.Plus(LHSWorkspace=workspace_list[outer_loop_count],
+                                                           RHSWorkspace=calibrated_spectra[input_ws_index],
+                                                           OutputWorkspace=inner_workspace_names)
+
+        # Finally scale the output workspaces
+        mod_first_number = str((outer_loop_count * 3) + 1)  # Generates 1/4/7
+        mod_last_number = str((outer_loop_count + 1) * 3)  # Generates 3/6/9
+        workspace_names = output_file_names["output_name"] + "_mod" + mod_first_number + '-' + mod_last_number
+        output_list.append(mantid.Scale(InputWorkspace=workspace_list[outer_loop_count],
+                                        OutputWorkspace=workspace_names, Factor=0.333333333333))
+    for ws in workspace_list:
+        common.remove_intermediate_workspace(ws)
+    return output_list
diff --git a/scripts/Diffraction/isis_powder/pearl_calib_factory.py b/scripts/Diffraction/isis_powder/pearl_routines/pearl_calib_factory.py
similarity index 100%
rename from scripts/Diffraction/isis_powder/pearl_calib_factory.py
rename to scripts/Diffraction/isis_powder/pearl_routines/pearl_calib_factory.py
diff --git a/scripts/Diffraction/isis_powder/pearl_cycle_factory.py b/scripts/Diffraction/isis_powder/pearl_routines/pearl_cycle_factory.py
similarity index 100%
rename from scripts/Diffraction/isis_powder/pearl_cycle_factory.py
rename to scripts/Diffraction/isis_powder/pearl_routines/pearl_cycle_factory.py
diff --git a/scripts/Diffraction/isis_powder/polaris.py b/scripts/Diffraction/isis_powder/polaris.py
new file mode 100644
index 0000000000000000000000000000000000000000..87445de16f30cef095a8e8b2a64a494e76225939
--- /dev/null
+++ b/scripts/Diffraction/isis_powder/polaris.py
@@ -0,0 +1,373 @@
+from __future__ import (absolute_import, division, print_function)
+
+import os
+
+import mantid.simpleapi as mantid
+
+import isis_powder.routines.common as common
+from isis_powder.abstract_inst import AbstractInst
+from isis_powder.polaris_routines import polaris_calib_parser
+from isis_powder.routines.RunDetails import RunDetails
+
+
+class Polaris(AbstractInst):
+
+    _focus_crop_start = 2  # These are used when calculating binning range
+    _focus_crop_end = 0.95
+    _focus_bin_widths = [-0.0050, -0.0010, -0.0010, -0.0010, -0.00050]
+
+    _calibration_grouping_names = None
+    _masking_file_name = "VanaPeaks.dat"
+
+    _number_of_banks = 5
+
+    def __init__(self, user_name, chopper_on, apply_solid_angle=True,
+                 calibration_dir=None, output_dir=None, **kwargs):
+
+        super(Polaris, self).__init__(user_name=user_name, calibration_dir=calibration_dir,
+                                      output_dir=output_dir, kwargs=kwargs)
+
+        self._chopper_on = chopper_on
+
+        # Caches the last dictionary to avoid us having to keep parsing the YAML
+        self._run_details_last_run_number = None
+        self._run_details_cached_obj = None
+
+        # Properties set in later calls:
+        self._apply_solid_angle = apply_solid_angle
+
+    def focus(self, run_number, do_attenuation=True, do_van_normalisation=True):
+        return self._focus(run_number=run_number, do_attenuation=do_attenuation,
+                           do_van_normalisation=do_van_normalisation)
+
+    def create_calibration_vanadium(self, run_in_range, do_absorb_corrections=True, gen_absorb_correction=False):
+        run_details = self._get_run_details(run_number=int(run_in_range))
+        return self._create_calibration_vanadium(vanadium_runs=run_details.vanadium,
+                                                 empty_runs=run_details.sample_empty,
+                                                 do_absorb_corrections=do_absorb_corrections,
+                                                 gen_absorb_correction=gen_absorb_correction)
+
+    # Abstract implementation
+    def _get_lambda_range(self):
+        return self._lower_lambda_range, self._upper_lambda_range
+
+    def _get_create_van_tof_binning(self):
+        return self._create_van_calib_tof_binning
+
+    def _get_default_group_names(self):
+        return self._calibration_grouping_names
+
+    def _get_run_details(self, run_number):
+        if self._run_details_last_run_number == run_number:
+            return self._run_details_cached_obj
+
+        input_run_number_list = common.generate_run_numbers(run_number_string=run_number)
+        configuration = polaris_calib_parser.get_calibration_dict(run_number=input_run_number_list[0])
+
+        if self._chopper_on:
+            chopper_config = configuration["chopper_on"]
+        else:
+            chopper_config = configuration["chopper_off"]
+
+        empty_runs = chopper_config["empty_run_numbers"]
+        vanadium_runs = chopper_config["vanadium_run_numbers"]
+        solid_angle_file_name = self._generate_solid_angle_file_name(vanadium_run_string=vanadium_runs)
+        splined_vanadium_name = self._generate_splined_van_name(vanadium_run_string=vanadium_runs)
+        cycle = configuration["label"]
+
+        calibration_dir = os.path.join(self.calibration_dir, cycle)
+        calibration_full_path = os.path.join(calibration_dir, configuration["offset_file_name"])
+        grouping_full_path = os.path.join(calibration_dir, configuration["offset_file_name"])
+        solid_angle_file_path = os.path.join(calibration_dir, solid_angle_file_name)
+        splined_vanadium = os.path.join(calibration_dir, splined_vanadium_name)
+
+        calibration_details = RunDetails(calibration_path=calibration_full_path, grouping_path=grouping_full_path,
+                                         vanadium_runs=vanadium_runs, run_number=run_number)
+        calibration_details.label = cycle
+        calibration_details.sample_empty = empty_runs
+        calibration_details.splined_vanadium = splined_vanadium
+        calibration_details.solid_angle_corr = solid_angle_file_path
+
+        # Hold obj in case same run range is requested
+        self._run_details_last_run_number = run_number
+        self._run_details_cached_obj = calibration_details
+
+        return calibration_details
+
+    @staticmethod
+    def _generate_inst_file_name(run_number):
+        if isinstance(run_number, list):
+            updated_list = ["POL" + str(val) for val in run_number]
+            return updated_list
+        else:
+            return "POL" + str(run_number)
+
+    @staticmethod
+    def _get_instrument_alg_save_ranges(instrument=''):
+        alg_range = 5
+        return alg_range, None
+
+    def _normalise_ws(self, ws_to_correct, run_details=None):
+        normalised_ws = mantid.NormaliseByCurrent(InputWorkspace=ws_to_correct)
+        return normalised_ws
+
+    def apply_solid_angle_efficiency_corr(self, ws_to_correct, run_details):
+        if not self._apply_solid_angle:
+            return ws_to_correct
+
+        if not run_details or not os.path.isfile(run_details.solid_angle_corr):
+            corrections = self.generate_solid_angle_corrections(run_details)
+        else:
+            corrections = mantid.Load(Filename=run_details.solid_angle_corr)
+
+        corrected_ws = mantid.Divide(LHSWorkspace=ws_to_correct, RHSWorkspace=corrections)
+        common.remove_intermediate_workspace(corrections)
+        common.remove_intermediate_workspace(ws_to_correct)
+        ws_to_correct = corrected_ws
+        return ws_to_correct
+
+    def generate_solid_angle_corrections(self, run_details):
+        solid_angle_vanadium_ws = common.load_current_normalised_ws(run_number_string=run_details.vanadium,
+                                                                    instrument=self)
+
+        corrections = _calculate_solid_angle_efficiency_corrections(solid_angle_vanadium_ws)
+        mantid.SaveNexusProcessed(InputWorkspace=corrections, Filename=run_details.solid_angle_corr)
+
+        common.remove_intermediate_workspace(solid_angle_vanadium_ws)
+        return corrections
+
+    def correct_sample_vanadium(self, focused_ws, index, vanadium_ws=None):
+        spectra_name = "sample_ws-" + str(index + 1)
+        mantid.CropWorkspace(InputWorkspace=focused_ws, OutputWorkspace=spectra_name,
+                             StartWorkspaceIndex=index, EndWorkspaceIndex=index)
+
+        if vanadium_ws:
+            van_rebinned = mantid.RebinToWorkspace(WorkspaceToRebin=vanadium_ws, WorkspaceToMatch=spectra_name)
+            mantid.Divide(LHSWorkspace=spectra_name, RHSWorkspace=van_rebinned, OutputWorkspace=spectra_name)
+            common.remove_intermediate_workspace(van_rebinned)
+
+        return spectra_name
+
+    def _spline_background(self, focused_vanadium_ws, spline_number, instrument_version=''):
+
+        if spline_number is None:
+            spline_number = 100
+
+        mode = "spline"  # TODO support spline modes for all instruments
+        extracted_spectra = _extract_bank_spectra(focused_vanadium_ws, self._number_of_banks)
+
+        if mode == "spline":
+            output = self._mask_spline_vanadium_ws(vanadium_spectra_list=extracted_spectra,
+                                                   spline_coefficient=spline_number)
+        else:
+            raise NotImplementedError("Other vanadium processing methods not yet implemented")
+
+        for ws in extracted_spectra:
+            common.remove_intermediate_workspace(ws)
+
+        return output
+
+    def _generate_vanadium_absorb_corrections(self, calibration_full_paths, ws_to_match):
+        absorb_ws = mantid.CloneWorkspace(InputWorkspace=ws_to_match)
+
+        # TODO move all of this into defaults
+        cylinder_sample_height = str(4)
+        cylinder_sample_radius = str(0.4)
+
+        attenuation_cross_section = str(4.88350)
+        scattering_cross_section = str(5.15775)
+        sample_number_density = str(0.0718956)
+
+        number_of_slices = str(10)
+        number_of_annuli = str(10)
+        number_of_wavelength_points = str(100)
+
+        exp_method = "Normal"
+        # TODO move all of the above into defaults
+
+        absorb_ws = mantid.CylinderAbsorption(InputWorkspace=absorb_ws,
+                                              CylinderSampleHeight=cylinder_sample_height,
+                                              CylinderSampleRadius=cylinder_sample_radius,
+                                              AttenuationXSection=attenuation_cross_section,
+                                              ScatteringXSection=scattering_cross_section,
+                                              SampleNumberDensity=sample_number_density,
+                                              NumberOfSlices=number_of_slices,
+                                              NumberOfAnnuli=number_of_annuli,
+                                              NumberOfWavelengthPoints=number_of_wavelength_points,
+                                              ExpMethod=exp_method)
+        return absorb_ws
+
+    def calculate_focus_binning_params(self, sample):
+        calculated_binning_params = []
+
+        for i in range(0, self._number_of_banks):
+            sample_data = sample.readX(i)
+            starting_bin = _calculate_focus_bin_first_edge(bin_value=sample_data[0], crop_value=self._focus_crop_start)
+            ending_bin = _calculate_focus_bin_last_edge(bin_value=sample_data[-1], crop_value=self._focus_crop_end)
+            bin_width = self._focus_bin_widths[i]
+
+            bank_binning_params = [str(starting_bin), str(bin_width), str(ending_bin)]
+            calculated_binning_params.append(bank_binning_params)
+
+        return calculated_binning_params
+
+    def _process_focus_output(self, processed_spectra, run_details, attenuate=False):
+        d_spacing_group, tof_group = _create_d_spacing_tof_output(processed_spectra)
+        output_paths = self._generate_out_file_paths(run_details=run_details)
+
+        mantid.SaveGSS(InputWorkspace=tof_group, Filename=output_paths["gss_filename"], SplitFiles=False, Append=False)
+        mantid.SaveNexusProcessed(InputWorkspace=tof_group, Filename=output_paths["nxs_filename"], Append=False)
+
+        _save_xye(ws_group=d_spacing_group, ws_units="d_spacing", run_number=run_details.run_number,
+                  output_folder=output_paths["output_folder"])
+        _save_xye(ws_group=tof_group, ws_units="TOF", run_number=run_details.run_number,
+                  output_folder=output_paths["output_folder"])
+
+        return d_spacing_group, tof_group
+
+    def _read_masking_file(self):
+        all_banks_masking_list = []
+        bank_masking_list = []
+        mask_path = os.path.join(self.calibration_dir, self._masking_file_name)
+
+        ignore_line_prefixes = (' ', '\n', '\t', '#')  # Matches whitespace or # symbol
+
+        with open(mask_path) as mask_file:
+            for line in mask_file:
+                if line.startswith(ignore_line_prefixes):
+                    # Push back onto new bank
+                    all_banks_masking_list.append(bank_masking_list)
+                    bank_masking_list = []
+                else:
+                    line.rstrip()
+                    bank_masking_list.append(line.split())
+
+        return all_banks_masking_list
+
+    def _mask_spline_vanadium_ws(self, vanadium_spectra_list, spline_coefficient):
+        masked_workspace = _apply_masking(workspaces_to_mask=vanadium_spectra_list, mask_list=self._read_masking_file())
+
+        index = 0
+        output_list = []
+        for ws in masked_workspace:
+            index += 1
+            output_ws_name = "splined_vanadium_ws-" + str(index)
+            splined_ws = mantid.SplineBackground(InputWorkspace=ws, OutputWorkspace=output_ws_name,
+                                                 WorkspaceIndex=0, NCoeff=spline_coefficient)
+            output_list.append(splined_ws)
+
+        return output_list
+
+    def _generate_solid_angle_file_name(self, vanadium_run_string):
+        if self._chopper_on:
+            return "SAC_chopperOn_" + vanadium_run_string + ".nxs"
+        else:
+            return "SAC_chopperOff_" + vanadium_run_string + ".nxs"
+
+    def _generate_splined_van_name(self, vanadium_run_string):
+        output_string = "SVan_" + str(vanadium_run_string) + "_chopper"
+        if self._chopper_on:
+            output_string += "On"
+        else:
+            output_string += "Off"
+
+        if self._apply_solid_angle:
+            output_string += "_SAC"
+        else:
+            output_string += "_noSAC"
+
+        return output_string
+
+
+def _extract_bank_spectra(ws_to_split, num_banks):
+    spectra_bank_list = []
+    for i in range(0, num_banks):
+        output_name = "bank-" + str(i + 1)
+        # Have to use crop workspace as extract single spectrum struggles with the variable bin widths
+        spectra_bank_list.append(mantid.CropWorkspace(InputWorkspace=ws_to_split, OutputWorkspace=output_name,
+                                                      StartWorkspaceIndex=i, EndWorkspaceIndex=i))
+    return spectra_bank_list
+
+
+def _apply_masking(workspaces_to_mask, mask_list):
+
+    index = 0
+    output_workspaces = []
+    for ws in workspaces_to_mask:
+        output_workspaces.append(ws)
+
+    for bank_mask_list in mask_list:
+        if not bank_mask_list:
+            continue
+
+        output_name = "masked_vanadium-" + str(index + 1)
+
+        for mask_params in bank_mask_list:
+            out_workspace = mantid.MaskBins(InputWorkspace=output_workspaces[index], OutputWorkspace=output_name,
+                                            XMin=mask_params[0], XMax=mask_params[1])
+            output_workspaces[index] = out_workspace
+
+        index += 1
+
+    return output_workspaces
+
+
+def _calculate_focus_bin_first_edge(bin_value, crop_value):
+    return bin_value * (1 + crop_value)
+
+
+def _calculate_focus_bin_last_edge(bin_value, crop_value):
+    return bin_value * crop_value
+
+
+def _create_d_spacing_tof_output(processed_spectra):
+    name_index = 1
+    d_spacing_output = []
+    tof_output = []
+    for ws in processed_spectra:
+        d_spacing_out_name = "ResultD-" + str(name_index)
+        tof_out_name = "ResultTOF-" + str(name_index)
+        name_index += 1
+        # Rename d-spacing workspaces
+        d_spacing_output.append(mantid.CloneWorkspace(InputWorkspace=ws, OutputWorkspace=d_spacing_out_name))
+        # Convert to TOF
+        tof_output.append(mantid.ConvertUnits(InputWorkspace=ws, OutputWorkspace=tof_out_name, Target="TOF"))
+
+    # Group the outputs
+    d_spacing_group_name = "Results-D-Grp"
+    d_spacing_group = mantid.GroupWorkspaces(InputWorkspaces=d_spacing_output, OutputWorkspace=d_spacing_group_name)
+    tof_group_name = "Results-TOF-Grp"
+    tof_group = mantid.GroupWorkspaces(InputWorkspaces=tof_output, OutputWorkspace=tof_group_name)
+
+    return d_spacing_group, tof_group
+
+
+def _calculate_solid_angle_efficiency_corrections(vanadium_ws):
+    solid_angle_ws = mantid.SolidAngle(InputWorkspace=vanadium_ws)
+    solid_angle_multiplicand = mantid.CreateSingleValuedWorkspace(DataValue=str(100))
+    solid_angle_ws = mantid.Multiply(LHSWorkspace=solid_angle_ws, RHSWorkspace=solid_angle_multiplicand)
+    common.remove_intermediate_workspace(solid_angle_multiplicand)
+
+    efficiency_ws = mantid.Divide(LHSWorkspace=vanadium_ws, RHSWorkspace=solid_angle_ws)
+    efficiency_ws = mantid.ConvertUnits(InputWorkspace=efficiency_ws, Target="Wavelength")
+    efficiency_ws = mantid.Integration(InputWorkspace=efficiency_ws)
+
+    corrections_ws = mantid.Multiply(LHSWorkspace=solid_angle_ws, RHSWorkspace=efficiency_ws)
+    corrections_divisor_ws = mantid.CreateSingleValuedWorkspace(DataValue=str(100000))
+    corrections_ws = mantid.Divide(LHSWorkspace=corrections_ws, RHSWorkspace=corrections_divisor_ws)
+
+    common.remove_intermediate_workspace(corrections_divisor_ws)
+    common.remove_intermediate_workspace(solid_angle_ws)
+    common.remove_intermediate_workspace(efficiency_ws)
+
+    return corrections_ws
+
+
+def _save_xye(ws_group, ws_units, run_number, output_folder):
+    bank_index = 1
+    for ws in ws_group:
+        outfile_name = str(run_number) + "-b_" + str(bank_index) + "-" + ws_units + ".dat"
+        bank_index += 1
+        full_file_path = os.path.join(output_folder, outfile_name)
+
+        mantid.SaveFocusedXYE(InputWorkspace=ws, Filename=full_file_path, SplitFiles=False, IncludeHeader=False)
diff --git a/scripts/Diffraction/isis_powder/polaris_routines/__init__.py b/scripts/Diffraction/isis_powder/polaris_routines/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/scripts/Diffraction/isis_powder/polaris_routines/polaris_calib_parser.py b/scripts/Diffraction/isis_powder/polaris_routines/polaris_calib_parser.py
new file mode 100644
index 0000000000000000000000000000000000000000..a62c54912f27922a0d63787b6a7befe96c761f45
--- /dev/null
+++ b/scripts/Diffraction/isis_powder/polaris_routines/polaris_calib_parser.py
@@ -0,0 +1,61 @@
+from __future__ import (absolute_import, division, print_function)
+
+import os
+
+import yaml
+
+import isis_powder.routines.common
+
+
+def get_calibration_dict(run_number):
+    config_file = _open_yaml_file()
+
+    # First check exceptions list as it should be shorter
+    exception_key = _check_if_run_is_exception(config_handle=config_file, run_number=run_number)
+    if exception_key:
+        exceptions_dict = config_file["exceptions"]
+        return exceptions_dict[exception_key]
+
+    # Otherwise parse the entire YAML file
+    run_key = _find_dictionary_key(dict_to_search=config_file, run_number=run_number)
+
+    # If we have not found the run in either
+    if not run_key:
+        raise ValueError("Run number " + str(run_number) + " not recognised in calibration mapping")
+
+    return config_file[run_key]
+
+
+def _open_yaml_file():
+    config_file_name = "polaris_calibration.yaml"
+    config_file_path = os.path.join(os.path.dirname(__file__), config_file_name)
+
+    read_config = None
+
+    with open(config_file_path, 'r') as input_stream:
+        try:
+            read_config = yaml.load(input_stream)
+        except yaml.YAMLError as exception:
+            print(exception)
+            raise RuntimeError("Failed to parse POLARIS calibration YAML file")
+
+    return read_config
+
+
+def _check_if_run_is_exception(config_handle, run_number):
+    try:
+        exceptions_dict = config_handle["exceptions"]
+    except KeyError:
+        return None
+
+    return _find_dictionary_key(dict_to_search=exceptions_dict, run_number=run_number)
+
+
+def _find_dictionary_key(dict_to_search, run_number):
+
+    for key in dict_to_search:
+        generated_runs = isis_powder.routines.common.generate_run_numbers(run_number_string=key)
+        if run_number in generated_runs:
+            return key
+
+    return None
diff --git a/scripts/Diffraction/isis_powder/polaris_routines/polaris_calibration.yaml b/scripts/Diffraction/isis_powder/polaris_routines/polaris_calibration.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..add54005ce5e9d9cf47e79e6b7f029e0c2ea2689
--- /dev/null
+++ b/scripts/Diffraction/isis_powder/polaris_routines/polaris_calibration.yaml
@@ -0,0 +1,37 @@
+
+# NOTE: All of the data below is TEST data - it is not representitive of any actual cycles/data values used
+
+78334-82415:
+  offset_file_name : "offsets_2011_cycle111b.cal"
+  label : "15_2"
+  chopper_on:
+    vanadium_run_numbers : "78338"
+    empty_run_numbers : "78339"
+
+  chopper_off:
+    vanadium_run_numbers : "78338"
+    empty_run_numbers : "78339"
+
+93104-93107:
+  offset_file_name : "offsets_2011_cycle111b.cal"
+  label : "15_2"
+  chopper_on:
+    vanadium_run_numbers : "93105"
+    empty_run_numbers : "93106"
+
+  chopper_off:
+    vanadium_run_numbers : "93105"
+    empty_run_numbers : "93106"
+
+
+95600-95614:
+  # Calibration run
+  offset_file_name : "offsets_2011_cycle111b.cal"
+  label : "16_4"
+  chopper_on:
+    vanadium_run_numbers : "95603-95607,95613-95614"
+    empty_run_numbers : "78339"
+  chopper_off:
+    vanadium_run_numbers : "95603-95607,95613-95614"
+    empty_run_numbers : "78339"
+
diff --git a/scripts/Diffraction/isis_powder/routines/RunDetails.py b/scripts/Diffraction/isis_powder/routines/RunDetails.py
new file mode 100644
index 0000000000000000000000000000000000000000..13ffbfe94467dd5f75f49abd5b5b248bbf26099f
--- /dev/null
+++ b/scripts/Diffraction/isis_powder/routines/RunDetails.py
@@ -0,0 +1,24 @@
+from __future__ import (absolute_import, division, print_function)
+
+
+class RunDetails(object):
+    """
+    This class holds the full file paths associated with each run and various other useful attributes
+    """
+
+    def __init__(self, calibration_path, grouping_path, vanadium_runs, run_number):
+        # Essential attributes
+        self.run_number = run_number
+        self.calibration = calibration_path
+        self.grouping = grouping_path
+        self.vanadium = vanadium_runs
+
+        # Optional Attributes
+        self.instrument_version = None
+        self.vanadium_absorption = None
+        self.splined_vanadium = None
+        self.sample_empty = None
+
+        self.solid_angle_corr = None
+
+        self.label = None
diff --git a/scripts/Diffraction/isis_powder/routines/__init__.py b/scripts/Diffraction/isis_powder/routines/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/scripts/Diffraction/isis_powder/routines/calibrate.py b/scripts/Diffraction/isis_powder/routines/calibrate.py
new file mode 100644
index 0000000000000000000000000000000000000000..fa9f807b10f9001fe3bc4c5bba313e06e30b2135
--- /dev/null
+++ b/scripts/Diffraction/isis_powder/routines/calibrate.py
@@ -0,0 +1,79 @@
+from __future__ import (absolute_import, division, print_function)
+
+import os
+
+import mantid.simpleapi as mantid
+
+import isis_powder.routines.common as common
+
+
+def create_van(instrument, van, empty, output_van_file_name, num_of_splines, absorb, gen_absorb):
+
+    input_van_ws = common.load_current_normalised_ws(run_number_string=van, instrument=instrument)
+    corrected_van_ws = common.subtract_sample_empty(ws_to_correct=input_van_ws, empty_sample_ws_string=empty,
+                                                    instrument=instrument)
+
+    common.remove_intermediate_workspace(input_van_ws)
+
+    run_details = instrument._get_run_details(run_number=van)
+
+    corrected_van_ws = instrument. _apply_van_calibration_tof_rebinning(vanadium_ws=corrected_van_ws,
+                                                                        tof_rebin_pass=1, return_units="TOF")
+
+    corrected_van_ws = mantid.AlignDetectors(InputWorkspace=corrected_van_ws,
+                                             CalibrationFile=run_details.calibration)
+
+    corrected_van_ws = instrument.apply_solid_angle_efficiency_corr(ws_to_correct=corrected_van_ws,
+                                                                    run_details=run_details)
+    if absorb:
+        corrected_van_ws = _apply_absorb_corrections(instrument=instrument,
+                                                     run_details=run_details,
+                                                     corrected_van_ws=corrected_van_ws, gen_absorb=gen_absorb)
+
+    focused_van_file = mantid.DiffractionFocussing(InputWorkspace=corrected_van_ws,
+                                                   GroupingFileName=run_details.grouping)
+
+    # Optional
+    focused_van_file = instrument. _apply_van_calibration_tof_rebinning(vanadium_ws=focused_van_file,
+                                                                        tof_rebin_pass=2, return_units="dSpacing")
+
+    common.remove_intermediate_workspace(corrected_van_ws)
+
+    cycle_information = instrument._get_run_details(run_number=van)
+    splined_ws_list = instrument._spline_background(focused_van_file, num_of_splines,
+                                                    cycle_information.instrument_version)
+    # Figure out who will provide the path name
+    if instrument._PEARL_filename_is_full_path():
+        out_van_file_path = output_van_file_name
+    elif output_van_file_name:
+        # The user has manually specified the output file
+        out_van_file_path = os.path.join(instrument.calibration_dir, output_van_file_name)
+    elif run_details.splined_vanadium:
+        out_van_file_path = run_details.splined_vanadium
+    else:
+        raise ValueError("The output name must be manually specified for this instrument/run")
+
+    append = False
+    for ws in splined_ws_list:
+        mantid.SaveNexus(Filename=out_van_file_path, InputWorkspace=ws, Append=append)
+        common.remove_intermediate_workspace(ws)
+        append = True
+
+    output_ws = mantid.LoadNexus(Filename=out_van_file_path, OutputWorkspace="Van_data")
+    return output_ws
+
+
+def _apply_absorb_corrections(instrument, run_details, corrected_van_ws, gen_absorb):
+    corrected_van_ws = mantid.ConvertUnits(InputWorkspace=corrected_van_ws, Target="Wavelength")
+
+    if gen_absorb or not run_details.vanadium_absorption:
+        absorb_ws = instrument._generate_vanadium_absorb_corrections(run_details, corrected_van_ws)
+    else:
+        absorb_ws = mantid.LoadNexus(Filename=run_details.vanadium_absorption)
+
+    # PEARL rebins whilst POLARIS does not as some of the older absorption files have different number of bins
+    corrected_van_ws = instrument._calibration_rebin_to_workspace(ws_to_rebin=corrected_van_ws, ws_to_match=absorb_ws)
+    corrected_van_ws = mantid.Divide(LHSWorkspace=corrected_van_ws, RHSWorkspace=absorb_ws)
+    corrected_van_ws = mantid.ConvertUnits(InputWorkspace=corrected_van_ws, Target="dSpacing")
+    common.remove_intermediate_workspace(absorb_ws)
+    return corrected_van_ws
diff --git a/scripts/Diffraction/isis_powder/routines/common.py b/scripts/Diffraction/isis_powder/routines/common.py
new file mode 100644
index 0000000000000000000000000000000000000000..8acbec6769f451863c5cb046399c4d987939a2b9
--- /dev/null
+++ b/scripts/Diffraction/isis_powder/routines/common.py
@@ -0,0 +1,165 @@
+from __future__ import (absolute_import, division, print_function)
+
+import mantid.simpleapi as mantid
+
+# --- Public API --- #
+
+
+def create_calibration_by_names(calibration_runs, startup_objects, grouping_file_name, group_names):
+    _create_blank_cal_file(calibration_runs=calibration_runs, group_names=group_names,
+                           out_grouping_file_name=grouping_file_name, instrument=startup_objects)
+
+
+def set_debug(debug_on=False):
+    global g_debug
+    g_debug = debug_on
+
+
+def remove_intermediate_workspace(workspace_name):
+    _remove_ws(ws_to_remove=workspace_name)
+
+# --- Private Implementation --- #
+
+# Please note these functions can change in any way at any time.
+# For this reason please do not call them directly and instead use the Public API provided.
+
+# If this doesn't quite provide what you need please let a developer know so we can create
+# another API or update an existing one
+
+
+_read_ws_count = 0
+global g_ads_workaround
+g_ads_workaround = {"read_ws": _read_ws_count}
+
+
+def _create_blank_cal_file(calibration_runs, out_grouping_file_name, instrument, group_names):
+    input_ws = load_current_normalised_ws(calibration_runs, instrument)
+    calibration_d_spacing_ws = mantid.ConvertUnits(InputWorkspace=input_ws, Target="dSpacing")
+    mantid.CreateCalFileByNames(InstrumentWorkspace=calibration_d_spacing_ws,
+                                GroupingFileName=out_grouping_file_name, GroupNames=group_names)
+    remove_intermediate_workspace(calibration_d_spacing_ws)
+    remove_intermediate_workspace(input_ws)
+
+
+def load_monitor(run_numbers, instrument):
+    number_list = generate_run_numbers(run_numbers)
+    monitor_spectra = instrument._get_monitor_spectra(number_list[0])
+
+    if len(number_list) == 1:
+        file_name = instrument._generate_inst_file_name(run_number=number_list[0])
+        load_monitor_ws = mantid.Load(Filename=file_name, LoadLogFiles="0",
+                                      SpectrumMin=monitor_spectra, SpectrumMax=monitor_spectra)
+    else:
+        load_monitor_ws = _load_sum_file_range(run_numbers_list=number_list, instrument=instrument)
+        load_monitor_ws = mantid.ExtractSingleSpectrum(InputWorkspace=load_monitor_ws, WorkspaceIndex=monitor_spectra)
+
+    return load_monitor_ws
+
+
+def subtract_sample_empty(ws_to_correct, empty_sample_ws_string, instrument):
+    output = ws_to_correct
+    if empty_sample_ws_string is not None:
+        empty_sample = load_current_normalised_ws(run_number_string=empty_sample_ws_string, instrument=instrument)
+        corrected_ws = mantid.Minus(LHSWorkspace=ws_to_correct, RHSWorkspace=empty_sample)
+        remove_intermediate_workspace(empty_sample)
+        output = corrected_ws
+    return output
+
+
+def _load_raw_files(run_number_string, instrument):
+    run_number_list = generate_run_numbers(run_number_string=run_number_string)
+    instrument.PEARL_setup_input_directories(run_number=run_number_list[0])
+    load_raw_ws = _load_sum_file_range(run_number_list, instrument)
+    return load_raw_ws
+
+
+def _load_sum_file_range(run_numbers_list, instrument):
+    read_ws_list = []
+
+    _check_load_range(list_of_runs_to_load=run_numbers_list)
+
+    for run_number in run_numbers_list:
+        file_name = instrument._generate_inst_file_name(run_number=run_number)
+        read_ws = mantid.Load(Filename=file_name, LoadLogFiles="0")
+        read_ws_list.append(mantid.RenameWorkspace(InputWorkspace=read_ws, OutputWorkspace=str(file_name)))
+
+    # Sum all workspaces
+    out_ws_name = "summed_range_load-" + str(g_ads_workaround["read_ws"])
+    g_ads_workaround["read_ws"] += 1
+    summed_ws = mantid.RenameWorkspace(InputWorkspace=read_ws_list[0], OutputWorkspace=out_ws_name)
+    for ws in read_ws_list[1:]:  # Skip first member
+        summed_ws = mantid.Plus(LHSWorkspace=summed_ws, RHSWorkspace=ws, OutputWorkspace=out_ws_name)
+        remove_intermediate_workspace(ws)
+
+    return summed_ws
+
+
+def _check_load_range(list_of_runs_to_load):
+    MAXIMUM_RANGE_LEN = 20  # If more than this number of runs is entered probably wrong
+    if len(list_of_runs_to_load) > MAXIMUM_RANGE_LEN:
+        raise ValueError("More than " + str(MAXIMUM_RANGE_LEN) + " runs were selected."
+                         " Found " + str(len(list_of_runs_to_load)) + " Aborting.")
+
+
+def generate_run_numbers(run_number_string):
+
+    # Check its not a single run
+    if isinstance(run_number_string, int) or run_number_string.isdigit():
+        return [int(run_number_string)]  # Cast into a list and return
+
+    # If its a string we must parse it
+    run_number_string = run_number_string.strip()
+    run_boundaries = run_number_string.replace('_', '-')  # Accept either _ or - delimiters
+    run_range_lists = __run_number_generator(processed_string=run_boundaries)
+    out_range = []
+    for range_list in run_range_lists:
+        out_range.extend(range_list)
+
+    return out_range
+
+
+def __run_number_generator(processed_string):
+    # Expands run numbers of the form 1-10, 12, 14-20, 23 to 1,2,3,..,8,9,10,12,14,15,16...,19,20,23
+    for entry in processed_string.split(','):
+        # Split between comma separated values
+        numbers = entry.split('-')
+        # Check if we are using a dash separator and return the range between those values
+        if len(numbers) == 1:
+            yield list(numbers)
+        elif len(numbers) == 2:
+            # Add 1 so it includes the final number '-' range
+            yield range(int(numbers[0]), int(numbers[-1]) + 1)
+        else:
+            raise ValueError("The run number " + str(entry) + " is incorrect in calibration mapping")
+
+
+def load_current_normalised_ws(run_number_string, instrument):
+    read_in_ws = _load_raw_files(run_number_string=run_number_string, instrument=instrument)
+
+    run_information = instrument._get_run_details(run_number=run_number_string)
+
+    read_ws = instrument._normalise_ws(ws_to_correct=read_in_ws, run_details=run_information)
+
+    output_name = "read_ws_output-" + str(g_ads_workaround["read_ws"])
+    g_ads_workaround["read_ws"] += 1
+    read_ws = mantid.RenameWorkspace(InputWorkspace=read_ws, OutputWorkspace=output_name)
+
+    remove_intermediate_workspace(read_in_ws)
+    return read_ws
+
+
+def _remove_ws(ws_to_remove):
+    """
+    Removes any intermediate workspaces if debug is set to false
+        @param ws_to_remove: The workspace to remove from the ADS
+    """
+    try:
+        if not g_debug:
+            _remove_ws_wrapper(ws=ws_to_remove)
+    except NameError:  # If g_debug has not been set
+        _remove_ws_wrapper(ws=ws_to_remove)
+
+
+def _remove_ws_wrapper(ws):
+    mantid.DeleteWorkspace(ws)
+    del ws  # Mark it as deleted so that Python can throw before Mantid preserving more information
diff --git a/scripts/Diffraction/isis_powder/routines/focus.py b/scripts/Diffraction/isis_powder/routines/focus.py
new file mode 100644
index 0000000000000000000000000000000000000000..ab1cf2f89123741e4f1ba0dc11321881dfd8bc9c
--- /dev/null
+++ b/scripts/Diffraction/isis_powder/routines/focus.py
@@ -0,0 +1,94 @@
+from __future__ import (absolute_import, division, print_function)
+
+import mantid.simpleapi as mantid
+
+import isis_powder.routines.common as common
+import os
+
+
+def focus(number, instrument, attenuate=True, van_norm=True):
+    return _run_focus(run_number=number, perform_attenuation=attenuate,
+                      perform_vanadium_norm=van_norm, instrument=instrument)
+
+
+def _run_focus(instrument, run_number, perform_attenuation, perform_vanadium_norm):
+    # Read
+    read_ws = common.load_current_normalised_ws(run_number_string=run_number, instrument=instrument)
+    input_workspace = instrument._do_tof_rebinning_focus(read_ws)  # Rebins for PEARL
+
+    run_details = instrument._get_run_details(run_number=run_number)
+
+    # Check the necessary splined vanadium file has been created
+    if not os.path.isfile(run_details.splined_vanadium):
+        raise ValueError("Processed vanadium runs not found at this path: "
+                         + str(run_details.splined_vanadium) +
+                         " \n\nHave you created a vanadium calibration with these settings yet?")
+
+    # Compensate for empty sample if specified
+    input_workspace = common.subtract_sample_empty(ws_to_correct=input_workspace, instrument=instrument,
+                                                   empty_sample_ws_string=run_details.sample_empty)
+
+    # Align / Focus
+    input_workspace = mantid.AlignDetectors(InputWorkspace=input_workspace,
+                                            CalibrationFile=run_details.calibration)
+
+    input_workspace = instrument.apply_solid_angle_efficiency_corr(ws_to_correct=input_workspace,
+                                                                   run_details=run_details)
+
+    focused_ws = mantid.DiffractionFocussing(InputWorkspace=input_workspace,
+                                             GroupingFileName=run_details.grouping)
+
+    # Process
+    rebinning_params = instrument.calculate_focus_binning_params(sample=focused_ws)
+
+    calibrated_spectra = _divide_sample_by_vanadium(instrument=instrument, run_number=run_number,
+                                                    input_workspace=focused_ws,
+                                                    perform_vanadium_norm=perform_vanadium_norm)
+
+    _apply_binning_to_spectra(spectra_list=calibrated_spectra, binning_list=rebinning_params)
+
+    # Output
+    processed_nexus_files = instrument._process_focus_output(calibrated_spectra, run_details=run_details,
+                                                             attenuate=perform_attenuation)
+
+    # Tidy
+    common.remove_intermediate_workspace(read_ws)
+    common.remove_intermediate_workspace(input_workspace)
+    common.remove_intermediate_workspace(focused_ws)
+    for ws in calibrated_spectra:
+        common.remove_intermediate_workspace(ws)
+        pass
+
+    return processed_nexus_files
+
+
+def _divide_sample_by_vanadium(instrument, run_number, input_workspace, perform_vanadium_norm):
+    processed_spectra = []
+
+    run_details = instrument._get_run_details(run_number=run_number)
+
+    alg_range, save_range = instrument._get_instrument_alg_save_ranges(run_details.instrument_version)
+
+    for index in range(0, alg_range):
+        if perform_vanadium_norm:
+            vanadium_ws = mantid.LoadNexus(Filename=run_details.splined_vanadium, EntryNumber=index + 1)
+
+            processed_spectra.append(
+                instrument.correct_sample_vanadium(focused_ws=input_workspace, index=index, vanadium_ws=vanadium_ws))
+
+            common.remove_intermediate_workspace(vanadium_ws)
+        else:
+            processed_spectra.append(
+                instrument.correct_sample_vanadium(focused_ws=input_workspace, index=index))
+
+    return processed_spectra
+
+
+def _apply_binning_to_spectra(spectra_list, binning_list):
+    if not binning_list:
+        return
+
+    for ws, bin_params in zip(spectra_list, binning_list):
+        # Starting bin edge / bin width / last bin edge
+        rebin_string = bin_params[0] + ',' + bin_params[1] + ',' + bin_params[2]
+        mantid.Rebin(InputWorkspace=ws, OutputWorkspace=ws, Params=rebin_string)
diff --git a/scripts/Engineering/EnggUtils.py b/scripts/Engineering/EnggUtils.py
index 6514f44832d1e0dd2de7a0549422b421d87a34db..63827fc65889229ccdf7065acfe2feef60191aa0 100644
--- a/scripts/Engineering/EnggUtils.py
+++ b/scripts/Engineering/EnggUtils.py
@@ -279,7 +279,7 @@ def convertToDSpacing(parent, ws):
     """
     # A check to catch possible errors in an understandable way
     expectedDim = 'Time-of-flight'
-    dimType = ws.getXDimension().getName()
+    dimType = ws.getXDimension().name
     if expectedDim != dimType:
         raise ValueError("This function expects a workspace with %s X dimension, but "
                          "the X dimension of the input workspace is: '%s'. This is an internal logic "
@@ -343,6 +343,7 @@ def sumSpectra(parent, ws):
     """
     alg = parent.createChildAlgorithm('SumSpectra')
     alg.setProperty('InputWorkspace', ws)
+    alg.setProperty('RemoveSpecialValues', True)
     alg.execute()
 
     return alg.getProperty('OutputWorkspace').value
diff --git a/scripts/Examples/SolidAngle_Example.py b/scripts/Examples/SolidAngle_Example.py
index ca0359a854d0b2b097f1a753d61eb399ce3f622b..c6b2bc50220d521ecc0f5cbbced38a60bbda959f 100644
--- a/scripts/Examples/SolidAngle_Example.py
+++ b/scripts/Examples/SolidAngle_Example.py
@@ -28,9 +28,9 @@ phi = detector.getPhi()
 
 print 'R = ' + str(r) + ', TwoTheta = ' + str(twoTheta)+ ', Phi = ' + str(phi)
 
-# Check if the detector is masked out and calculate the result if not
+# Check if the spectrum is masked out and calculate the result if not
 solidAngle = 0.0
-if not detector.isMasked():
+if not rawData.spectrumInfo().isMasked(0):
     sAngle = detector.solidAngle(samplePos)
 
 print "The solid angle of the spectrum located at index " + str(wsIndex) + " is: " + str(sAngle) + " steradians"
diff --git a/scripts/HFIR_4Circle_Reduction/MainWindow.ui b/scripts/HFIR_4Circle_Reduction/MainWindow.ui
index 31133931c488a937fe7ba71c7964d8c05a8ce03e..3f4c6aa6b59885cb43f09566a4c33eff1fbb64e2 100644
--- a/scripts/HFIR_4Circle_Reduction/MainWindow.ui
+++ b/scripts/HFIR_4Circle_Reduction/MainWindow.ui
@@ -637,7 +637,7 @@ p, li { white-space: pre-wrap; }
                <string>Instrument Calibration</string>
               </property>
               <layout class="QGridLayout" name="gridLayout_16">
-               <item row="0" column="7">
+               <item row="0" column="11">
                 <spacer name="horizontalSpacer_26">
                  <property name="orientation">
                   <enum>Qt::Horizontal</enum>
@@ -650,7 +650,7 @@ p, li { white-space: pre-wrap; }
                  </property>
                 </spacer>
                </item>
-               <item row="1" column="7">
+               <item row="1" column="11">
                 <spacer name="horizontalSpacer_16">
                  <property name="orientation">
                   <enum>Qt::Horizontal</enum>
@@ -664,7 +664,7 @@ p, li { white-space: pre-wrap; }
                 </spacer>
                </item>
                <item row="0" column="1">
-                <widget class="QLineEdit" name="lineEdit">
+                <widget class="QLineEdit" name="lineEdit_defaultSampleDetDistance">
                  <property name="enabled">
                   <bool>false</bool>
                  </property>
@@ -689,7 +689,7 @@ p, li { white-space: pre-wrap; }
                <item row="1" column="2">
                 <widget class="QPushButton" name="pushButton_applyCalibratedSampleDistance">
                  <property name="enabled">
-                  <bool>false</bool>
+                  <bool>true</bool>
                  </property>
                  <property name="text">
                   <string>Apply</string>
@@ -706,13 +706,6 @@ p, li { white-space: pre-wrap; }
                  </property>
                 </widget>
                </item>
-               <item row="0" column="4">
-                <widget class="QLabel" name="label_36">
-                 <property name="text">
-                  <string>Wavelength</string>
-                 </property>
-                </widget>
-               </item>
                <item row="0" column="3">
                 <spacer name="horizontalSpacer_29">
                  <property name="orientation">
@@ -732,31 +725,21 @@ p, li { white-space: pre-wrap; }
                <item row="0" column="0">
                 <widget class="QLabel" name="label_33">
                  <property name="text">
-                  <string>Standard Detector Sample Distance</string>
-                 </property>
-                </widget>
-               </item>
-               <item row="0" column="5">
-                <widget class="QLineEdit" name="lineEdit_userWaveLength">
-                 <property name="sizePolicy">
-                  <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
-                   <horstretch>0</horstretch>
-                   <verstretch>0</verstretch>
-                  </sizepolicy>
+                  <string>Default Detector Sample Distance</string>
                  </property>
                 </widget>
                </item>
-               <item row="0" column="6">
-                <widget class="QPushButton" name="pushButton_applyUserWavelength">
+               <item row="0" column="8">
+                <widget class="QLabel" name="label_36">
                  <property name="text">
-                  <string>Apply</string>
+                  <string>Wavelength</string>
                  </property>
                 </widget>
                </item>
                <item row="1" column="4">
                 <widget class="QLabel" name="label_10">
                  <property name="text">
-                  <string>Detector Center</string>
+                  <string>Calibrated Detector Center</string>
                  </property>
                 </widget>
                </item>
@@ -770,6 +753,15 @@ p, li { white-space: pre-wrap; }
                      <verstretch>0</verstretch>
                     </sizepolicy>
                    </property>
+                   <property name="maximumSize">
+                    <size>
+                     <width>100</width>
+                     <height>16777215</height>
+                    </size>
+                   </property>
+                   <property name="toolTip">
+                    <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;ROW NUMBER&lt;/span&gt; of User-specified detector center&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                   </property>
                   </widget>
                  </item>
                  <item>
@@ -780,6 +772,15 @@ p, li { white-space: pre-wrap; }
                      <verstretch>0</verstretch>
                     </sizepolicy>
                    </property>
+                   <property name="maximumSize">
+                    <size>
+                     <width>100</width>
+                     <height>16777215</height>
+                    </size>
+                   </property>
+                   <property name="toolTip">
+                    <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;COLUMN NUMBER&lt;/span&gt; of User-specified detector center&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                   </property>
                   </widget>
                  </item>
                 </layout>
@@ -787,13 +788,66 @@ p, li { white-space: pre-wrap; }
                <item row="1" column="6">
                 <widget class="QPushButton" name="pushButton_applyUserDetCenter">
                  <property name="enabled">
-                  <bool>false</bool>
+                  <bool>true</bool>
                  </property>
                  <property name="text">
                   <string>Apply</string>
                  </property>
                 </widget>
                </item>
+               <item row="0" column="4">
+                <widget class="QLabel" name="label_19">
+                 <property name="text">
+                  <string>Default Detector Center</string>
+                 </property>
+                </widget>
+               </item>
+               <item row="0" column="10">
+                <widget class="QPushButton" name="pushButton_applyUserWavelength">
+                 <property name="text">
+                  <string>Apply</string>
+                 </property>
+                </widget>
+               </item>
+               <item row="0" column="7">
+                <spacer name="horizontalSpacer_34">
+                 <property name="orientation">
+                  <enum>Qt::Horizontal</enum>
+                 </property>
+                 <property name="sizeType">
+                  <enum>QSizePolicy::Preferred</enum>
+                 </property>
+                 <property name="sizeHint" stdset="0">
+                  <size>
+                   <width>40</width>
+                   <height>20</height>
+                  </size>
+                 </property>
+                </spacer>
+               </item>
+               <item row="0" column="9">
+                <widget class="QLineEdit" name="lineEdit_userWaveLength">
+                 <property name="sizePolicy">
+                  <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+                   <horstretch>0</horstretch>
+                   <verstretch>0</verstretch>
+                  </sizepolicy>
+                 </property>
+                 <property name="text">
+                  <string/>
+                 </property>
+                </widget>
+               </item>
+               <item row="0" column="5">
+                <widget class="QLineEdit" name="lineEdit_defaultDetCenter">
+                 <property name="enabled">
+                  <bool>false</bool>
+                 </property>
+                 <property name="text">
+                  <string>115, 128</string>
+                 </property>
+                </widget>
+               </item>
               </layout>
              </widget>
             </item>
@@ -4479,6 +4533,22 @@ p, li { white-space: pre-wrap; }
             <string>Advanced Setup</string>
            </attribute>
            <layout class="QGridLayout" name="gridLayout_27">
+            <item row="0" column="2">
+             <spacer name="horizontalSpacer_25">
+              <property name="orientation">
+               <enum>Qt::Horizontal</enum>
+              </property>
+              <property name="sizeType">
+               <enum>QSizePolicy::MinimumExpanding</enum>
+              </property>
+              <property name="sizeHint" stdset="0">
+               <size>
+                <width>40</width>
+                <height>20</height>
+               </size>
+              </property>
+             </spacer>
+            </item>
             <item row="0" column="0">
              <widget class="QGroupBox" name="groupBox_16">
               <property name="title">
@@ -4495,7 +4565,7 @@ p, li { white-space: pre-wrap; }
                <item row="4" column="3">
                 <widget class="QLabel" name="label_last3Path">
                  <property name="sizePolicy">
-                  <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+                  <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
                    <horstretch>0</horstretch>
                    <verstretch>0</verstretch>
                   </sizepolicy>
@@ -4543,11 +4613,17 @@ p, li { white-space: pre-wrap; }
                <item row="1" column="3">
                 <widget class="QLabel" name="label_last1Path">
                  <property name="sizePolicy">
-                  <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+                  <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
                    <horstretch>0</horstretch>
                    <verstretch>0</verstretch>
                   </sizepolicy>
                  </property>
+                 <property name="minimumSize">
+                  <size>
+                   <width>200</width>
+                   <height>0</height>
+                  </size>
+                 </property>
                  <property name="text">
                   <string>EMPTY</string>
                  </property>
@@ -4556,7 +4632,7 @@ p, li { white-space: pre-wrap; }
                <item row="2" column="3">
                 <widget class="QLabel" name="label_last2Path">
                  <property name="sizePolicy">
-                  <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+                  <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
                    <horstretch>0</horstretch>
                    <verstretch>0</verstretch>
                   </sizepolicy>
@@ -4599,7 +4675,7 @@ p, li { white-space: pre-wrap; }
               </layout>
              </widget>
             </item>
-            <item row="1" column="0">
+            <item row="2" column="0">
              <spacer name="verticalSpacer_25">
               <property name="orientation">
                <enum>Qt::Vertical</enum>
@@ -4615,13 +4691,13 @@ p, li { white-space: pre-wrap; }
               </property>
              </spacer>
             </item>
-            <item row="0" column="1">
-             <spacer name="horizontalSpacer_25">
+            <item row="1" column="2">
+             <spacer name="horizontalSpacer_35">
               <property name="orientation">
                <enum>Qt::Horizontal</enum>
               </property>
               <property name="sizeType">
-               <enum>QSizePolicy::Expanding</enum>
+               <enum>QSizePolicy::MinimumExpanding</enum>
               </property>
               <property name="sizeHint" stdset="0">
                <size>
@@ -4631,6 +4707,117 @@ p, li { white-space: pre-wrap; }
               </property>
              </spacer>
             </item>
+            <item row="1" column="0">
+             <widget class="QGroupBox" name="groupBox_23">
+              <property name="title">
+               <string>Constants</string>
+              </property>
+              <layout class="QGridLayout" name="gridLayout_6">
+               <item row="2" column="2">
+                <widget class="QLineEdit" name="lineEdit_pixelSizeX">
+                 <property name="enabled">
+                  <bool>false</bool>
+                 </property>
+                 <property name="sizePolicy">
+                  <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
+                   <horstretch>0</horstretch>
+                   <verstretch>0</verstretch>
+                  </sizepolicy>
+                 </property>
+                 <property name="text">
+                  <string>0.0001984375</string>
+                 </property>
+                </widget>
+               </item>
+               <item row="2" column="0">
+                <widget class="QLabel" name="label_21">
+                 <property name="text">
+                  <string>Pixel Size</string>
+                 </property>
+                </widget>
+               </item>
+               <item row="1" column="0">
+                <widget class="QLabel" name="label_20">
+                 <property name="text">
+                  <string>Sample-detector Distance Tolerance</string>
+                 </property>
+                </widget>
+               </item>
+               <item row="1" column="2">
+                <widget class="QLineEdit" name="lineEdit_sampleDetDistTol">
+                 <property name="sizePolicy">
+                  <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
+                   <horstretch>0</horstretch>
+                   <verstretch>0</verstretch>
+                  </sizepolicy>
+                 </property>
+                 <property name="maximumSize">
+                  <size>
+                   <width>10000</width>
+                   <height>16777215</height>
+                  </size>
+                 </property>
+                 <property name="text">
+                  <string>0.2</string>
+                 </property>
+                </widget>
+               </item>
+               <item row="1" column="1">
+                <spacer name="horizontalSpacer_36">
+                 <property name="orientation">
+                  <enum>Qt::Horizontal</enum>
+                 </property>
+                 <property name="sizeType">
+                  <enum>QSizePolicy::Preferred</enum>
+                 </property>
+                 <property name="sizeHint" stdset="0">
+                  <size>
+                   <width>40</width>
+                   <height>20</height>
+                  </size>
+                 </property>
+                </spacer>
+               </item>
+               <item row="2" column="3">
+                <widget class="QLineEdit" name="lineEdit_pixelSizeY">
+                 <property name="enabled">
+                  <bool>false</bool>
+                 </property>
+                 <property name="text">
+                  <string>0.0001984375</string>
+                 </property>
+                </widget>
+               </item>
+               <item row="0" column="2">
+                <widget class="QLineEdit" name="lineEdit_numPixelRow">
+                 <property name="enabled">
+                  <bool>false</bool>
+                 </property>
+                 <property name="text">
+                  <string>256</string>
+                 </property>
+                </widget>
+               </item>
+               <item row="0" column="3">
+                <widget class="QLineEdit" name="lineEdit_numPixelColumn">
+                 <property name="enabled">
+                  <bool>false</bool>
+                 </property>
+                 <property name="text">
+                  <string>256</string>
+                 </property>
+                </widget>
+               </item>
+               <item row="0" column="0">
+                <widget class="QLabel" name="label_22">
+                 <property name="text">
+                  <string>Detector Pixel Size</string>
+                 </property>
+                </widget>
+               </item>
+              </layout>
+             </widget>
+            </item>
            </layout>
           </widget>
          </widget>
diff --git a/scripts/HFIR_4Circle_Reduction/NTableWidget.py b/scripts/HFIR_4Circle_Reduction/NTableWidget.py
index 13fe655c7bad77eff1ab34a1e382e32fd838796b..e8ffda0c330e0a777e2784aa40da0dbca955ec60 100644
--- a/scripts/HFIR_4Circle_Reduction/NTableWidget.py
+++ b/scripts/HFIR_4Circle_Reduction/NTableWidget.py
@@ -419,7 +419,6 @@ class NTableWidget(QtGui.QTableWidget):
         self.remove_all_rows()
 
         # add rows back
-        print '[DB-BAT] Sort by column %d. Keys = ' % column_index, key_list, 'sort_order = ', sort_order
         for key_value in key_list:
             self.append_row(row_content_dict[key_value])
         # END-FOR
diff --git a/scripts/HFIR_4Circle_Reduction/absorption.py b/scripts/HFIR_4Circle_Reduction/absorption.py
index a8bf6f3201af90ae2d47fc953699abe12b4891cd..78c87c9b36853cbfc937aa56cf8b7c405123b190 100644
--- a/scripts/HFIR_4Circle_Reduction/absorption.py
+++ b/scripts/HFIR_4Circle_Reduction/absorption.py
@@ -273,8 +273,6 @@ def calculate_b_matrix(lattice):
     b_matrix[2, 1] = 0
     b_matrix[2, 2] = 1 / lattice.get_c()
 
-    #  print '[DB...TEST] B matrix: determination = ', numpy.linalg.det(b_matrix), '\n', b_matrix
-
     return b_matrix
 
 
@@ -286,8 +284,6 @@ def calculate_upphi(omg0, theta2ave, chiave, phiave):
     up_phi[1] = m_sin(theta2ave*0.5+omg0)*m_cos(chiave)*m_sin(phiave)-m_cos(theta2ave*0.5+omg0)*m_cos(phiave)
     up_phi[2] = m_sin(theta2ave*0.5+omg0)*m_sin(chiave)
 
-    print '[DB...TEST] UP PHI = ', up_phi, '|UP PHI| = ', numpy.dot(up_phi, up_phi)
-
     return up_phi
 
 
@@ -299,8 +295,6 @@ def calculate_usphi(omg0, theta2ave, chiave, phiave):
     us_phi[1] = m_sin(theta2ave*0.5-omg0)*m_cos(chiave)*m_sin(phiave)+m_cos(theta2ave*0.5-omg0)*m_cos(phiave)
     us_phi[2] = m_sin(theta2ave*0.5-omg0)*m_sin(chiave)
 
-    print '[DB...TEST] US PHI = ', us_phi, '|US PHI| = ', numpy.dot(us_phi, us_phi)
-
     return us_phi
 
 
@@ -316,9 +310,6 @@ def calculate_absorption_correction_spice(exp_number, scan_number, lattice, ub_m
     phiave = get_average_spice_table(exp_number, scan_number, 'phi') # sum(phi(:))/length(phi);
     omg0 = theta2ave * 0.5
 
-    print '[DB...TEST] Exp = %d Scan = %d:\n2theta = %f, chi = %f, phi = %f, omega = %f' \
-          '' % (exp_number, scan_number, theta2ave, chiave, phiave, omg0)
-
     upphi = calculate_upphi(omg0, theta2ave, chiave, phiave)
     usphi = calculate_usphi(omg0, theta2ave, chiave, phiave)
 
@@ -421,9 +412,6 @@ def calculate_absorption_correction_2(exp_number, scan_number, spice_ub_matrix):
     phiave = get_average_spice_table(exp_number, scan_number, 'phi')  # sum(phi(:))/length(phi);
     avg_omega = get_average_omega(exp_number, scan_number)
 
-    print '[DB...TEST] Exp = %d Scan = %d:\n2theta = %f, chi = %f, phi = %f, omega = %s' % (
-        exp_number, scan_number, theta2ave, chiave, phiave, str(avg_omega))
-
     up_phi = calculate_upphi(avg_omega, theta2ave, chiave, phiave)
     us_phi = calculate_usphi(avg_omega, theta2ave, chiave, phiave)
 
diff --git a/scripts/HFIR_4Circle_Reduction/fourcircle_utility.py b/scripts/HFIR_4Circle_Reduction/fourcircle_utility.py
index 9e90b25bf88760bae3d7f9098d1335547f32a462..32a8c46649cb4b8b9520316aedae1b917f8ab2c5 100644
--- a/scripts/HFIR_4Circle_Reduction/fourcircle_utility.py
+++ b/scripts/HFIR_4Circle_Reduction/fourcircle_utility.py
@@ -660,8 +660,6 @@ def round_hkl_1(hkl):
     :param hkl:
     :return:
     """
-    print type(hkl)
-
     mi_h = round(hkl[0])
     mi_k = round(hkl[1])
     mi_l = round(hkl[2])
diff --git a/scripts/HFIR_4Circle_Reduction/fputility.py b/scripts/HFIR_4Circle_Reduction/fputility.py
index 86e6ead192465a9cdabecd305d647166808ec7cc..e893e95e190d50d7d1dbdf2ea2acdc533f200951 100644
--- a/scripts/HFIR_4Circle_Reduction/fputility.py
+++ b/scripts/HFIR_4Circle_Reduction/fputility.py
@@ -197,8 +197,6 @@ def write_scd_fullprof_kvector(user_header, wave_length, k_vector_dict, peak_dic
     # END-IF
 
     # peak intensities
-    print '[DB...BAT] Number of peaks to output: ', len(peak_dict_list)
-
     for i_peak, peak_dict in enumerate(peak_dict_list):
         # check
         assert isinstance(peak_dict, dict), '%d-th peak must be a dictionary but not %s.' % (i_peak,
diff --git a/scripts/HFIR_4Circle_Reduction/guiutility.py b/scripts/HFIR_4Circle_Reduction/guiutility.py
index 55371451d3db810cfe7e2bdc09582e7751d2bac0..3c7dea5d4b332044c74c543439eadc036b81806f 100644
--- a/scripts/HFIR_4Circle_Reduction/guiutility.py
+++ b/scripts/HFIR_4Circle_Reduction/guiutility.py
@@ -424,7 +424,7 @@ def show_message(parent=None, message='show message here!'):
     show message
     :param parent:
     :param message:
-    :return:
+    :return: True for accepting.  False for rejecting or cancelling
     """
     dialog = DisplayDialog(parent)
     dialog.show_message(message)
diff --git a/scripts/HFIR_4Circle_Reduction/hfctables.py b/scripts/HFIR_4Circle_Reduction/hfctables.py
index 36f01147e3e28197a5270f52151cc3326334d97e..4269976ed3b050608d85c7fa7908e6444c4dd3de 100644
--- a/scripts/HFIR_4Circle_Reduction/hfctables.py
+++ b/scripts/HFIR_4Circle_Reduction/hfctables.py
@@ -1087,11 +1087,9 @@ class ScanSurveyTable(tableBase.NTableWidget):
             # check with filters: original order is counts, scan, Pt., ...
             scan_number = sum_item[1]
             if scan_number < start_scan or scan_number > end_scan:
-                # print 'Scan %d is out of range.' % scan_number
                 continue
             counts = sum_item[0]
             if counts < min_counts or counts > max_counts:
-                # print 'Scan %d Counts %f is out of range.' % (scan_number, counts)
                 continue
 
             # modify for appending to table
diff --git a/scripts/HFIR_4Circle_Reduction/mplgraphicsview.py b/scripts/HFIR_4Circle_Reduction/mplgraphicsview.py
index cbdcd45faa357e3accccffbbbe3443c29faee552..83115051cad2cfe50bfaa7b031a88466ee7ff105 100644
--- a/scripts/HFIR_4Circle_Reduction/mplgraphicsview.py
+++ b/scripts/HFIR_4Circle_Reduction/mplgraphicsview.py
@@ -197,8 +197,6 @@ class IndicatorManager(object):
 
         for line_key in self._lineManager.keys():
 
-            print '[MplGraph DB] Exam indicator key %s' % str(self._lineManager[line_key])
-
             if x is not None and y is not None:
                 # 2 way
                 raise NotImplementedError('ASAP')
@@ -222,7 +220,6 @@ class IndicatorManager(object):
         :return:
         """
         if line_id is not None:
-            print '[DB] Get line style. ID = %s' % str(line_id)
             style = '--'
         else:
             style = '--'
@@ -306,8 +303,6 @@ class IndicatorManager(object):
         :param dy:
         :return:
         """
-        # print self._lineManager[my_id][0]
-
         if self._indicatorTypeDict[my_id] == 0:
             # horizontal
             self._lineManager[my_id][1] += dy
@@ -797,7 +792,6 @@ class MplGraphicsView(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)
 
         # update the index
         self._myLineMarkerColorIndex += 1
@@ -973,7 +967,6 @@ class Qt4MplCanvas(FigureCanvas):
         """
         if self.axes2 is None:
             self.axes2 = self.axes.twinx()
-            # print self.par1, type(self.par1)
 
         # Hold previous data
         self.axes2.hold(True)
@@ -1303,9 +1296,6 @@ class Qt4MplCanvas(FigureCanvas):
 
         handles, labels = self.axes.get_legend_handles_labels()
         self.axes.legend(handles, labels, loc=location)
-        # print handles
-        # print labels
-        #self.axes.legend(self._myLegendHandlers, self._myLegentLabels)
 
         return
 
diff --git a/scripts/HFIR_4Circle_Reduction/mplgraphicsview3d.py b/scripts/HFIR_4Circle_Reduction/mplgraphicsview3d.py
index 6d8f0af9cd4c4bcb97112071dd8629a991f37e99..da1b11b1872f77403bf9f25f08c06b7a7a9e7b87 100644
--- a/scripts/HFIR_4Circle_Reduction/mplgraphicsview3d.py
+++ b/scripts/HFIR_4Circle_Reduction/mplgraphicsview3d.py
@@ -53,7 +53,6 @@ class MplPlot3dCanvas(FigureCanvas):
         Clear all the figures from canvas
         :return:
         """
-        print '[DB-INFO] There are %d plots in current plot list.' % len(self._currPlotList)
         for plt in self._currPlotList:
             # del plt
             self._myAxes.collections.remove(plt)
diff --git a/scripts/HFIR_4Circle_Reduction/multi_threads_helpers.py b/scripts/HFIR_4Circle_Reduction/multi_threads_helpers.py
index 70bb3b8a311b78017d32e2931f8e63b13de357c9..7bc322f9e753afe495ab9c611587a7018b788509 100644
--- a/scripts/HFIR_4Circle_Reduction/multi_threads_helpers.py
+++ b/scripts/HFIR_4Circle_Reduction/multi_threads_helpers.py
@@ -178,12 +178,8 @@ class IntegratePeaksThread(QThread):
             assert isinstance(scan_tup, tuple) and len(scan_tup) == 3
             scan_number, pt_number_list, merged = scan_tup
 
-            print '[DB...BAT] IntegratePeakThread: Scan %d' % scan_number
-
             # emit signal for run start (mode 0)
             mode = int(0)
-            print '[DB...BAT] IntegratePeakThread: Sent out signal (1): %d, %d, %f' % (self._expNumber, scan_number,
-                                                                                       float(index))
             self.peakMergeSignal.emit(self._expNumber, scan_number, float(index), [0., 0., 0.], mode)
 
             # merge if not merged
@@ -214,7 +210,7 @@ class IntegratePeaksThread(QThread):
                 # self._mainWindow.ui.tableWidget_mergeScans.set_status(scan_number, 'Merged')
             else:
                 # merged
-                print '[DB...BAT] Scan %s is merged (in thread)!' % scan_number
+                pass
             # END-IF
 
             # calculate peak center
@@ -245,9 +241,6 @@ class IntegratePeaksThread(QThread):
                                                                           self._selectedMaskName)
 
             # integrate peak
-            print '[DB...BAD] Normalization: %s; Use Mask = %s, Mask Workspace = %s.' % (
-                self._normalizeType, str(self._maskDetector), self._selectedMaskName
-            )
             try:
                 status, ret_obj = self._mainWindow.controller.integrate_scan_peaks(exp=self._expNumber,
                                                                                    scan=scan_number,
@@ -258,9 +251,8 @@ class IntegratePeaksThread(QThread):
                                                                                    normalization=self._normalizeType,
                                                                                    mask_ws_name=self._selectedMaskName)
             except ValueError as val_err:
-                print '[DB] Unable to integrate scan %d due to %s.' % (scan_number, str(val_err))
                 status = False
-                ret_obj = '%s.' % str(val_err)
+                ret_obj = 'Unable to integrate scan {0} due to {1}.'.format(scan_number, str(val_err))
 
             # handle integration error
             if status:
@@ -284,8 +276,6 @@ class IntegratePeaksThread(QThread):
             mode = 1
             # center_i
             self.peakMergeSignal.emit(self._expNumber, scan_number, float(intensity_i), list(peak_centre), mode)
-            print '[DB...BAT] IntegratePeakThread: Sent out signal (2): %d, %d, %f' % (self._expNumber, scan_number,
-                                                                                       float(intensity_i))
         # END-FOR
 
         # terminate the process
diff --git a/scripts/HFIR_4Circle_Reduction/peakprocesshelper.py b/scripts/HFIR_4Circle_Reduction/peakprocesshelper.py
index af2e7ab1c536edb78aa8404f67eff5b3e0316bc3..8af4c2f98cd67567c65b6e9a8d1879f5400a09d7 100644
--- a/scripts/HFIR_4Circle_Reduction/peakprocesshelper.py
+++ b/scripts/HFIR_4Circle_Reduction/peakprocesshelper.py
@@ -293,8 +293,6 @@ class PeakProcessRecord(object):
         """
         assert isinstance(pt_intensity_dict, dict)
 
-        print '[DB...BAT] Pt intensity dict keys: ', pt_intensity_dict.keys()
-
         self._ptIntensityDict = pt_intensity_dict
 
         return
diff --git a/scripts/HFIR_4Circle_Reduction/project_manager.py b/scripts/HFIR_4Circle_Reduction/project_manager.py
index 38f1dcd15dda3bf67237817a9283e80b372c89f0..0d2463d4ed5d5a709458d7e20b4d1d7e8f742f72 100644
--- a/scripts/HFIR_4Circle_Reduction/project_manager.py
+++ b/scripts/HFIR_4Circle_Reduction/project_manager.py
@@ -73,12 +73,15 @@ class ProjectManager(object):
         :param overwrite: if specified, then any existing files with same name will be rewritten
         :return:
         """
+        # create workspace directory
         self.create_workspace_directory()
 
+        print '[INFO] Saving {0} MDEventWorkspaces to {1}.'.format(len(self._wsList), self._wsDir)
+
         # save MDs
         for ws_name in self._wsList:
             md_file_name = os.path.join(self._wsDir, ws_name + '.nxs')
-            if overwrite or os.path.exists(md_file_name):
+            if overwrite or not os.path.exists(md_file_name):
                 mantidsimple.SaveMD(InputWorkspace=ws_name, Filename=md_file_name)
 
         with open(self._projectPath, 'w') as pickle_file:
diff --git a/scripts/HFIR_4Circle_Reduction/reduce4circleControl.py b/scripts/HFIR_4Circle_Reduction/reduce4circleControl.py
index 2cc1b0dc377c77a6da691730385343c9de0c2849..f3c4afd44e3514186432b1160048e7e785205d97 100644
--- a/scripts/HFIR_4Circle_Reduction/reduce4circleControl.py
+++ b/scripts/HFIR_4Circle_Reduction/reduce4circleControl.py
@@ -56,6 +56,16 @@ class CWSCDReductionControl(object):
         # Some set up
         self._expNumber = None
 
+        # instrument default constants
+        self._defaultDetectorSampleDistance = None
+        # geometry of pixel
+        self._defaultPixelSizeX = None
+        self._defaultPixelSizeY = None
+        # user-defined wave length
+        self._userWavelengthDict = dict()
+        # default peak center
+        self._defaultDetectorCenter = None
+
         # Container for MDEventWorkspace for each Pt.
         self._myMDWsList = list()
         # Container for loaded workspaces
@@ -92,6 +102,8 @@ class CWSCDReductionControl(object):
 
         # A dictionary to manage all loaded and processed MDEventWorkspaces
         # self._expDataDict = {}
+        self._detSampleDistanceDict = dict()
+        self._detCenterDict = dict()
 
         # register startup
         mantid.UsageService.registerFeatureUsage("Interface","4-Circle Reduction",False)
@@ -182,57 +194,9 @@ class CWSCDReductionControl(object):
         sin_theta = q * wavelength/(4*math.pi)
         theta = math.asin(sin_theta)
         corrected_intensity = peak_intensity * math.sin(2*theta) * step_omega
-        print '[DB] Lorentz correction: I * sin(2*theta) * delta(omega) = %.5f * sin(2*%.5f) * %.5f =' \
-              ' %.5f; q = %.5f.' % (peak_intensity, theta*180/math.pi, step_omega, corrected_intensity, q)
 
         return corrected_intensity
 
-    # def calculate_peak_center(self, exp_number, scan_number, pt_numbers=None):
-    #     """
-    #     Calculate center of peak by weighting the peak centers of multiple Pt (slice from 3D peak)
-    #     :param exp_number:
-    #     :param scan_number:
-    #     :param pt_numbers:
-    #     :return: 2-tuple: boolean, peak center (3-tuple of float)
-    #     """
-    #     # Check & set pt. numbers
-    #     assert isinstance(exp_number, int), 'Experiment number %s must be an integer but not %s.' \
-    #                                         '' % (str(exp_number), str(type(exp_number)))
-    #     assert isinstance(scan_number, int), 'Scan number %s must be an integer but not %s.' \
-    #                                          '' % (str(scan_number), str(type(scan_number)))
-    #     if pt_numbers is None:
-    #         status, pt_number_list = self.get_pt_numbers(exp_number, scan_number)
-    #         assert status
-    #     else:
-    #         pt_number_list = pt_numbers
-    #     assert isinstance(pt_number_list, list) and len(pt_number_list) > 0
-    #
-    #     # Check whether the MDEventWorkspace used to find peaks exists
-    #     if self.has_merged_data(exp_number, scan_number, pt_number_list):
-    #         pass
-    #     else:
-    #         return False, 'Exp %d Scan %d: data must be merged already.' % (exp_number, scan_number)
-    #
-    #     # Find peak in Q-space
-    #     merged_ws_name = get_merged_md_name(self._instrumentName, exp_number, scan_number, pt_number_list)
-    #     peak_ws_name = get_peak_ws_name(exp_number, scan_number, pt_number_list)
-    #     mantidsimple.FindPeaksMD(InputWorkspace=merged_ws_name,
-    #                              MaxPeaks=10,
-    #                              PeakDistanceThreshold=5.,
-    #                              DensityThresholdFactor=0.1,
-    #                              OutputWorkspace=peak_ws_name)
-    #     assert AnalysisDataService.doesExist(peak_ws_name), 'Output PeaksWorkspace %s cannot be found.' \
-    #                                                         '' % peak_ws_name
-    #
-    #     # calculate the peaks with weight
-    #     process_record = PeakProcessRecord(exp_number, scan_number, peak_ws_name)
-    #     process_record.calculate_peak_center()
-    #     peak_center = process_record.get_peak_centre()
-    #     # set the merged peak information to data structure
-    #     self._myPeakInfoDict[(exp_number, scan_number)] = process_record
-    #
-    #     return True, peak_center
-
     def find_peak(self, exp_number, scan_number, pt_number_list=None):
         """ Find 1 peak in sample Q space for UB matrix
         :param exp_number:
@@ -501,7 +465,11 @@ class CWSCDReductionControl(object):
         if pt_number is None:
             # no pt number, then check SPICE file
             spice_file_name = get_spice_file_name(self._instrumentName, exp_number, scan_number)
-            file_name = os.path.join(self._dataDir, spice_file_name)
+            try:
+                file_name = os.path.join(self._dataDir, spice_file_name)
+            except AttributeError:
+                raise AttributeError('Unable to create SPICE file name from directory %s and file name %s.'
+                                     '' % (self._dataDir, spice_file_name))
         else:
             # pt number given, then check
             xml_file_name = get_det_xml_file_name(self._instrumentName, exp_number, scan_number,
@@ -548,14 +516,18 @@ class CWSCDReductionControl(object):
 
         return self._myUBMatrixDict[exp_number]
 
-    @staticmethod
-    def get_wave_length(exp_number, scan_number_list):
+    def get_wave_length(self, exp_number, scan_number_list):
         """
         Get the wavelength.
         Exception: RuntimeError if there are more than 1 wavelength found with all given scan numbers
+        :param exp_number:
         :param scan_number_list:
         :return:
         """
+        # check whether there is use wave length
+        if exp_number in self._userWavelengthDict:
+            return self._userWavelengthDict[exp_number]
+
         # get the SPICE workspace
         wave_length_set = set()
 
@@ -656,7 +628,6 @@ class CWSCDReductionControl(object):
 
         # get ub matrix
         ub_matrix = self.get_ub_matrix(exp_number)
-        print '[DB...BAT] UB matrix is of type ', type(ub_matrix)
 
         for scan_number in scan_number_list:
             peak_dict = dict()
@@ -782,7 +753,7 @@ class CWSCDReductionControl(object):
         array2d = numpy.ndarray(shape=(DET_X_SIZE, DET_Y_SIZE), dtype='float')
         for i in xrange(DET_X_SIZE):
             for j in xrange(DET_Y_SIZE):
-                array2d[i][j] = raw_ws.readY(i * DET_X_SIZE + j)[0]
+                array2d[i][j] = raw_ws.readY(j * DET_X_SIZE + i)[0]
 
         # Flip the 2D array to look detector from sample
         array2d = numpy.flipud(array2d)
@@ -1305,7 +1276,7 @@ class CWSCDReductionControl(object):
             final_peak_center[i] = sum_peak_center[i] * (1./sum_bin_counts)
         #final_peak_center = sum_peak_center * (1./sum_bin_counts)
 
-        print 'Avg peak center = ', final_peak_center, 'Total counts = ', sum_bin_counts
+        print '[INFO] Avg peak center = ', final_peak_center, 'Total counts = ', sum_bin_counts
 
         # Integrate peaks
         total_intensity = 0.
@@ -1434,7 +1405,6 @@ class CWSCDReductionControl(object):
         # Default for exp_no
         if exp_no is None:
             exp_no = self._expNumber
-        print '[DB...BAD] Load Spice Scan File Exp Number = %d, Stored Exp. Number = %d' % (exp_no, self._expNumber)
 
         # Check whether the workspace has been loaded
         assert isinstance(exp_no, int)
@@ -1675,6 +1645,9 @@ class CWSCDReductionControl(object):
             # - construct a configuration with 1 scan and multiple Pts.
             scan_info_table_name = get_merge_pt_info_ws_name(exp_no, scan_no)
             try:
+                # collect HB3A exp info only need corrected detector position to build virtual instrument.
+                # so it is not necessary to specify the detector center now as virtual instrument
+                # is abandoned due to speed issue.
                 mantidsimple.CollectHB3AExperimentInfo(ExperimentNumber=exp_no,
                                                        ScanList='%d' % scan_no,
                                                        PtLists=pt_list_str,
@@ -1692,10 +1665,37 @@ class CWSCDReductionControl(object):
 
             # create MD workspace in Q-sample
             try:
-                mantidsimple.ConvertCWSDExpToMomentum(InputWorkspace=scan_info_table_name,
-                                                      CreateVirtualInstrument=False,
-                                                      OutputWorkspace=out_q_name,
-                                                      Directory=self._dataDir)
+                # set up the basic algorithm parameters
+                alg_args = dict()
+                alg_args['InputWorkspace'] = scan_info_table_name
+                alg_args['CreateVirtualInstrument'] = False
+                alg_args['OutputWorkspace'] = out_q_name
+                alg_args['Directory'] = self._dataDir
+
+                # Add Detector Center and Detector Distance!!!  - Trace up how to calculate shifts!
+                # calculate the sample-detector distance shift if it is defined
+                if exp_no in self._detSampleDistanceDict:
+                    alg_args['DetectorSampleDistanceShift'] = self._detSampleDistanceDict[exp_no] - \
+                                                              self._defaultDetectorSampleDistance
+                # calculate the shift of detector center
+                if exp_no in self._detCenterDict:
+                    user_center_row, user_center_col = self._detCenterDict[exp_no]
+                    delta_row = user_center_row - self._defaultDetectorCenter[0]
+                    delta_col = user_center_col - self._defaultDetectorCenter[1]
+                    # use LoadSpiceXML2DDet's unit test as a template
+                    shift_x = float(delta_col) * self._defaultPixelSizeX
+                    shift_y = float(delta_row) * self._defaultPixelSizeY * -1.
+                    # set to argument
+                    alg_args['DetectorCenterXShift'] = shift_x
+                    alg_args['DetectorCenterYShift'] = shift_y
+
+                # set up the user-defined wave length
+                if exp_no in self._userWavelengthDict:
+                    alg_args['UserDefinedWavelength'] = self._userWavelengthDict[exp_no]
+
+                # call:
+                mantidsimple.ConvertCWSDExpToMomentum(**alg_args)
+
                 self._myMDWsList.append(out_q_name)
             except RuntimeError as e:
                 err_msg += 'Unable to convert scan %d data to Q-sample MDEvents due to %s' % (scan_no, str(e))
@@ -1777,6 +1777,74 @@ class CWSCDReductionControl(object):
 
         return
 
+    def set_detector_center(self, exp_number, center_row, center_col, default=False):
+        """
+        Set detector center
+        :param exp_number:
+        :param center_row:
+        :param center_col:
+        :param default:
+        :return:
+        """
+        # check
+        assert isinstance(exp_number, int) and exp_number > 0, 'Experiment number must be integer'
+        assert center_row is None or (isinstance(center_row, int) and center_row >= 0), \
+            'Center row number must either None or non-negative integer.'
+        assert center_col is None or (isinstance(center_col, int) and center_col >= 0), \
+            'Center column number must be either Noe or non-negative integer.'
+
+        if default:
+            self._defaultDetectorCenter = (center_row, center_col)
+        else:
+            self._detCenterDict[exp_number] = (center_row, center_col)
+
+        return
+
+    def set_detector_sample_distance(self, exp_number, sample_det_distance):
+        """
+        set instrument's detector - sample distance
+        :param exp_number:
+        :param sample_det_distance:
+        :return:
+        """
+        # check
+        assert isinstance(exp_number, int) and exp_number > 0, 'Experiment number must be integer'
+        assert isinstance(sample_det_distance, float) and sample_det_distance > 0, \
+            'Sample - detector distance must be a positive float.'
+
+        # set
+        self._detSampleDistanceDict[exp_number] = sample_det_distance
+
+        return
+
+    def set_default_detector_sample_distance(self, default_det_sample_distance):
+        """
+        set default detector-sample distance
+        :param default_det_sample_distance:
+        :return:
+        """
+        assert isinstance(default_det_sample_distance, float) and default_det_sample_distance > 0,\
+            'Wrong %s' % str(default_det_sample_distance)
+
+        self._defaultDetectorSampleDistance = default_det_sample_distance
+
+        return
+
+    def set_default_pixel_size(self, pixel_x_size, pixel_y_size):
+        """
+        set default pixel size
+        :param pixel_x_size:
+        :param pixel_y_size:
+        :return:
+        """
+        assert isinstance(pixel_x_size, float) and pixel_x_size > 0, 'Pixel size-X %s is bad!' % str(pixel_x_size)
+        assert isinstance(pixel_y_size, float) and pixel_y_size > 0, 'Pixel size-Y %s is bad!' % str(pixel_y_size)
+
+        self._defaultPixelSizeX = pixel_x_size
+        self._defaultPixelSizeY = pixel_y_size
+
+        return
+
     def set_server_url(self, server_url, check_link=True):
         """
         Set URL for server to download the data
@@ -1847,8 +1915,8 @@ class CWSCDReductionControl(object):
             except OSError as os_err:
                 return False, str(os_err)
 
-        # Check whether the target is writable
-        if os.access(local_dir, os.W_OK) is False:
+        # Check whether the target is writable: if and only if the data directory is not from data server
+        if not local_dir.startswith('/HFIR/HB3A/') and os.access(local_dir, os.W_OK) is False:
             return False, 'Specified local data directory %s is not writable.' % local_dir
 
         # Successful
@@ -1874,6 +1942,23 @@ class CWSCDReductionControl(object):
         # Set up
         self._myUBMatrixDict[exp_number] = ub_matrix
 
+        return
+
+    def set_user_wave_length(self, exp_number, wave_length):
+        """
+        set the user wave length for future operation
+        :param exp_number:
+        :param wave_length:
+        :return:
+        """
+        assert isinstance(exp_number, int)
+        assert isinstance(wave_length, float) and wave_length > 0, 'Wave length %s must be a positive float but ' \
+                                                                   'not %s.' % (str(wave_length), type(wave_length))
+
+        self._userWavelengthDict[exp_number] = wave_length
+
+        return
+
     def set_working_directory(self, work_dir):
         """
         Set up the directory for working result
@@ -2390,9 +2475,8 @@ class CWSCDReductionControl(object):
                 try:
                     mantidsimple.DownloadFile(Address=spice_file_url, Filename=spice_file_name)
                 except RuntimeError as download_error:
-                    print '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)
@@ -2460,7 +2544,6 @@ class CWSCDReductionControl(object):
                                       q_range, max_tsample])
 
             except RuntimeError as e:
-                print e
                 return False, None, str(e)
             except ValueError as e:
                 # Unable to import a SPICE file without necessary information
@@ -2468,7 +2551,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
 
diff --git a/scripts/HFIR_4Circle_Reduction/reduce4circleGUI.py b/scripts/HFIR_4Circle_Reduction/reduce4circleGUI.py
index 57f3b54c0b0b7e077f8053ecdfec712b9953590d..d7769b0f6341425c8216137d0b25f03bc80ddf83 100644
--- a/scripts/HFIR_4Circle_Reduction/reduce4circleGUI.py
+++ b/scripts/HFIR_4Circle_Reduction/reduce4circleGUI.py
@@ -97,6 +97,12 @@ class MainWindow(QtGui.QMainWindow):
                      self.do_download_spice_data)
         self.connect(self.ui.comboBox_mode, QtCore.SIGNAL('currentIndexChanged(int)'),
                      self.do_change_data_access_mode)
+        self.connect(self.ui.pushButton_applyCalibratedSampleDistance, QtCore.SIGNAL('clicked()'),
+                     self.do_set_user_detector_distance)
+        self.connect(self.ui.pushButton_applyUserDetCenter, QtCore.SIGNAL('clicked()'),
+                     self.do_set_user_detector_center)
+        self.connect(self.ui.pushButton_applyUserWavelength, QtCore.SIGNAL('clicked()'),
+                     self.do_set_user_wave_length)
 
         # Tab 'View Raw Data'
         self.connect(self.ui.pushButton_setScanInfo, QtCore.SIGNAL('clicked()'),
@@ -278,16 +284,6 @@ class MainWindow(QtGui.QMainWindow):
         self.connect(self.ui.pushButton_loadLastNthProject, QtCore.SIGNAL('clicked()'),
                      self.do_load_nth_project)
 
-        # TODO/NOW/ISSUE - Implement
-        """
-        lineEdit_userDetSampleDistance, pushButton_applyCalibratedSampleDistance,
-        add more to --> lineEdit_infoDetSampleDistance
-        pushButton_applyUserWavelength: add more to --> lineEdit_infoWavelength
-
-        lineEdit_detCenterPixHorizontal, lineEdit_detCenterPixVertical,
-        pushButton_applyUserDetCenter, lineEdit_infoDetCenter
-        """
-
         # Validator ... (NEXT)
 
         # Declaration of class variable
@@ -469,8 +465,14 @@ class MainWindow(QtGui.QMainWindow):
         project_file_name = str(QtGui.QFileDialog.getSaveFileName(self, 'Specify Project File', os.getcwd()))
         # NEXT ISSUE - consider to allow incremental project saving technique
         if os.path.exists(project_file_name):
-            self.pop_one_button_dialog('Project file %s does exist. Choose another name.' % project_file_name)
-            return
+            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.'
+            else:
+                print '[INFO] Saving activity is cancelled.'
+        else:
+            print '[INFO] Saving current project to %s.' % project_file_name
 
         # gather some useful information
         ui_dict = dict()
@@ -510,22 +512,6 @@ class MainWindow(QtGui.QMainWindow):
 
         self.load_project(project_file_name)
 
-        # # load project
-        # ui_dict = self._myControl.load_project(project_file_name)
-        #
-        # # set the UI parameters to GUI
-        # try:
-        #     self.ui.lineEdit_localSpiceDir.setText(ui_dict['local spice dir'])
-        #     self.ui.lineEdit_workDir.setText(ui_dict['work dir'])
-        #     self.ui.lineEdit_surveyStartPt.setText(ui_dict['survey start'])
-        #     self.ui.lineEdit_surveyEndPt.setText(ui_dict['survey stop'])
-        #
-        #     # now try to call some actions
-        #     self.do_apply_setup()
-        #     self.do_set_experiment()
-        # except KeyError:
-        #     print '[Error] Some field cannot be found.'
-
         return
 
     def load_project(self, project_file_name):
@@ -588,9 +574,10 @@ class MainWindow(QtGui.QMainWindow):
         :param QCloseEvent:
         :return:
         """
-        print '[QCloseEvent=]', str(QCloseEvent)
         self.menu_quit()
 
+        return
+
     def do_accept_ub(self):
         """ Accept the calculated UB matrix and thus put to controller
         """
@@ -735,7 +722,9 @@ class MainWindow(QtGui.QMainWindow):
         data_server = str(self.ui.lineEdit_url.text()).strip()
 
         # set to my controller
-        self._myControl.set_local_data_dir(local_data_dir)
+        status, err_msg = self._myControl.set_local_data_dir(local_data_dir)
+        if not status:
+            raise RuntimeError(err_msg)
         self._myControl.set_working_directory(working_dir)
         self._myControl.set_server_url(data_server, check_link=False)
 
@@ -982,7 +971,6 @@ class MainWindow(QtGui.QMainWindow):
         convert merged workspace in Q-sample frame to HKL frame
         :return:
         """
-        # TODO/NOW/ - TEST: Convert to HKL
         # get experiment number
         exp_number = int(str(self.ui.lineEdit_exp.text()))
 
@@ -1414,8 +1402,6 @@ class MainWindow(QtGui.QMainWindow):
         if len(row_number_list) == 0:
             self.pop_one_button_dialog('No scan is selected for scan')
             return
-        else:
-            print '[DB...BAT] IntegratePeaks: selected rows: ', row_number_list
 
         # get experiment number
         status, ret_obj = gutil.parse_integers_editors(self.ui.lineEdit_exp, allow_blank=False)
@@ -1877,8 +1863,6 @@ class MainWindow(QtGui.QMainWindow):
         Merge several scans to a single MDWorkspace and give suggestion for re-binning
         :return:
         """
-        # TODO/NOW/ISSUE - Test this!
-
         # find the selected scans
         selected_rows = self.ui.tableWidget_mergeScans.get_selected_rows(True)
         if len(selected_rows) < 2:
@@ -1969,7 +1953,6 @@ class MainWindow(QtGui.QMainWindow):
             else:
                 merge_status = 'Failed. Reason: %s' % ret_tup
                 merged_name = 'x'
-                print merge_status
 
             # update table
             self.ui.tableWidget_mergeScans.set_status(row_number, merge_status)
@@ -2069,9 +2052,8 @@ class MainWindow(QtGui.QMainWindow):
 
         dlg = refineubfftsetup.RefineUBFFTSetupDialog(self)
         if dlg.exec_():
-            min_d, max_d, tolerance = dlg.get_values()
-            print '[DB...BAT]', min_d, max_d, tolerance
             # Do stuff with values
+            min_d, max_d, tolerance = dlg.get_values()
         else:
             # case for cancel
             return
@@ -2377,26 +2359,57 @@ class MainWindow(QtGui.QMainWindow):
         :return:
         """
         status, ret_obj = gutil.parse_integers_editors([self.ui.lineEdit_exp])
-        if status is True:
+        if status:
+            # new experiment number
             exp_number = ret_obj[0]
+            # current experiment to be replaced: warning
             curr_exp_number = self._myControl.get_experiment()
             if curr_exp_number is not None and exp_number != curr_exp_number:
                 self.pop_one_button_dialog('Changing experiment to %d.  Clean previous experiment %d\'s result'
                                            ' in Mantid manually.' % (exp_number, curr_exp_number))
+            # set the new experiment number
             self._myControl.set_exp_number(exp_number)
             self.ui.lineEdit_exp.setStyleSheet('color: black')
-
             self.setWindowTitle('%s: Experiment %d' % (self._baseTitle, exp_number))
 
-            # TODO/NOW/ISSUE - if the current data directory is empty or as /HFIR/HB3A/, reset data directory
+            # try to set the default
+            default_data_dir = '/HFIR/HB3A/exp%d/Datafiles' % exp_number
+            if os.path.exists(default_data_dir):
+                self.ui.lineEdit_localSpiceDir.setText(default_data_dir)
 
         else:
             err_msg = ret_obj
             self.pop_one_button_dialog('Unable to set experiment as %s' % err_msg)
             self.ui.lineEdit_exp.setStyleSheet('color: red')
+            return
 
         self.ui.tabWidget.setCurrentIndex(0)
 
+        # set the instrument geometry constants
+        status, ret_obj = gutil.parse_float_editors([self.ui.lineEdit_defaultSampleDetDistance,
+                                                     self.ui.lineEdit_pixelSizeX,
+                                                     self.ui.lineEdit_pixelSizeY],
+                                                    allow_blank=False)
+        if status:
+            default_det_sample_distance, pixel_x_size, pixel_y_size = ret_obj
+            self._myControl.set_default_detector_sample_distance(default_det_sample_distance)
+            self._myControl.set_default_pixel_size(pixel_x_size, pixel_y_size)
+        else:
+            self.pop_one_button_dialog('[ERROR] Unable to parse default instrument geometry constants '
+                                       'due to %s.' % str(ret_obj))
+            return
+
+        # set the detector center
+        det_center_str = str(self.ui.lineEdit_defaultDetCenter.text())
+        try:
+            terms = det_center_str.split(',')
+            center_row = int(terms[0])
+            center_col = int(terms[1])
+            self._myControl.set_detector_center(exp_number, center_row, center_col, default=True)
+        except (IndexError, ValueError) as error:
+            self.pop_one_button_dialog('[ERROR] Unable to parse default detector center %s due to %s.'
+                                       '' % (det_center_str, str(error)))
+
         return
 
     def do_set_ub_tab_hkl_to_integers(self):
@@ -2463,7 +2476,7 @@ class MainWindow(QtGui.QMainWindow):
                 try:
                     ub_matrix = self._myControl.get_ub_matrix(exp_number)
                 except KeyError as key_err:
-                    print 'Error 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)
@@ -2494,19 +2507,20 @@ class MainWindow(QtGui.QMainWindow):
     def do_setup_dir_default(self):
         """
         Set up default directory for storing data and working
+        If directory /HFIR/HB3A exists, it means that the user can access HFIR archive server
         :return:
         """
         home_dir = os.path.expanduser('~')
 
-        # TODO/NOW/ISSUE - make this one work for server-based
-        # example: os.path.exists('/HFIR/HB3A/exp322') won't take long time to find out the server is off.
-
         # Data cache directory
-        data_cache_dir = os.path.join(home_dir, 'Temp/HB3ATest')
-        self.ui.lineEdit_localSpiceDir.setText(data_cache_dir)
-        self.ui.lineEdit_localSrcDir.setText(data_cache_dir)
+        project_cache_dir = os.path.join(home_dir, 'Temp/HB3ATest')
+        if os.path.exists('/HFIR/HB3A/'):
+            self.ui.lineEdit_localSrcDir.setText('/HFIR/HB3A/')
+        else:
+            self.ui.lineEdit_localSpiceDir.setText(project_cache_dir)
 
-        work_dir = os.path.join(data_cache_dir, 'Workspace')
+        # working directory
+        work_dir = os.path.join(project_cache_dir, 'Workspace')
         self.ui.lineEdit_workDir.setText(work_dir)
 
         return
@@ -2546,6 +2560,84 @@ class MainWindow(QtGui.QMainWindow):
 
         return ub_matrix
 
+    def do_set_user_detector_distance(self):
+        """
+        Set up the user-defined detector distance for loading instrument with data
+        :return:
+        """
+        user_det_distance_str = str(self.ui.lineEdit_userDetSampleDistance.text()).strip()
+        if len(user_det_distance_str) == 0:
+            return
+
+        # convert to float
+        try:
+            user_det_distance = float(user_det_distance_str)
+        except ValueError:
+            self.pop_one_button_dialog('User detector-sample distance %s must be a float.' % user_det_distance_str)
+            return
+
+        # check distance value because it cannot be too far
+        default_det_distance = float(str(self.ui.lineEdit_defaultSampleDetDistance.text()))
+        distance_tol = float(str(self.ui.lineEdit_sampleDetDistTol.text()))
+        if abs((user_det_distance - default_det_distance) / default_det_distance) > distance_tol:
+            self.pop_one_button_dialog('User specified sample-detector distance is not reasonable.')
+            return
+
+        # set to controller
+        exp_number = int(str(self.ui.lineEdit_exp.text()))
+        self._myControl.set_detector_sample_distance(exp_number, user_det_distance)
+
+        # update the GUI for information
+        self.ui.lineEdit_infoDetSampleDistance.setText('%.5f' % user_det_distance)
+
+        return
+
+    def do_set_user_wave_length(self):
+        """
+
+        :return:
+        """
+        try:
+            exp_number = int(str(self.ui.lineEdit_exp.text()))
+            user_lambda = float(str(self.ui.lineEdit_userWaveLength.text()))
+        except ValueError:
+            self.pop_one_button_dialog('Unable to set user wave length with value %s.'
+                                       '' % str(self.ui.lineEdit_infoWavelength.text()))
+            return
+
+        self._myControl.set_user_wave_length(exp_number, user_lambda)
+
+        # set back to GUI
+        self.ui.lineEdit_infoWavelength.setText('%.5f' % user_lambda)
+
+        return
+
+    def do_set_user_detector_center(self):
+        """
+        set the user-defined detector center
+        :return:
+        """
+        # get information
+        status, ret_obj = gutil.parse_integers_editors([self.ui.lineEdit_exp,
+                                                        self.ui.lineEdit_detCenterPixHorizontal,
+                                                        self.ui.lineEdit_detCenterPixVertical],
+                                                       allow_blank=True)
+
+        if not status:
+            self.pop_one_button_dialog(str(ret_obj))
+            return
+
+        assert isinstance(ret_obj, list) and len(ret_obj) == 3, 'Error!'
+        exp_number, user_center_row, user_center_col = ret_obj
+        assert isinstance(exp_number, int), 'Experiment number must be set up.'
+
+        self._myControl.set_detector_center(exp_number, user_center_row, user_center_col)
+
+        # apply to the GUI
+        self.ui.lineEdit_infoDetCenter.setText('%d, %d' % (user_center_row, user_center_col))
+
+        return
+
     def do_show_spice_file(self):
         """
         Show SPICE file in a window
@@ -2717,8 +2809,6 @@ class MainWindow(QtGui.QMainWindow):
         else:
             raise RuntimeError('None radio button is selected for UB')
 
-        print '[DB...BAT] UB to set: ', ub_matrix
-
         # set to in-use UB matrix and control
         self.ui.tableWidget_ubInUse.set_from_matrix(ub_matrix)
 
@@ -2807,17 +2897,11 @@ class MainWindow(QtGui.QMainWindow):
         assert len(ret_obj) == 5
         md_file_name, weight_peak_centers, weight_peak_intensities, avg_peak_centre, avg_peak_intensity = ret_obj
 
-        print 'Write file to %s' % md_file_name
-        for i_peak in xrange(len(weight_peak_centers)):
-            peak_i = weight_peak_centers[i_peak]
-            print '%f, %f, %f' % (peak_i[0], peak_i[1], peak_i[2])
-        print
-        print avg_peak_centre
-
         # Plot
         if self._my3DWindow is None:
             self._my3DWindow = plot3dwindow.Plot3DWindow(self)
 
+        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)
@@ -3405,8 +3489,6 @@ class MainWindow(QtGui.QMainWindow):
 
             # gather values for updating
             intensity = sig_value
-            print '[DB...BAT] UpdatePeakIntegrationValue: Row %d: peak center %s of type %s.' \
-                  '' % (row_number, str(peak_centre), type(peak_centre))
 
             # check intensity value
             is_error = False
@@ -3494,8 +3576,6 @@ class MainWindow(QtGui.QMainWindow):
         except RuntimeError as run_err:
             self.pop_one_button_dialog(str(run_err))
             return
-        else:
-            print '[DB...BAT] UpdateMergeInformation: Row = ', row_number
 
         # set intensity, state to table
         if mode == 0:
diff --git a/scripts/Imaging/IMAT/__init__.py b/scripts/Imaging/IMAT/__init__.py
index 7fd49397e233ebf3616d56d32aa2fa68f3ec76db..763e55451a6e0fe542b5d75bbbaec0802e4b8cd1 100644
--- a/scripts/Imaging/IMAT/__init__.py
+++ b/scripts/Imaging/IMAT/__init__.py
@@ -1,3 +1,4 @@
+from __future__ import (absolute_import, division, print_function)
 # Copyright &copy; 2015 ISIS Rutherford Appleton Laboratory, NScD
 # Oak Ridge National Laboratory & European Spallation Source
 #
diff --git a/scripts/Imaging/IMAT/tomo_reconstruct.py b/scripts/Imaging/IMAT/tomo_reconstruct.py
index 875d4e66bc2d9f156854df4bb0a9fba82ea7ffbd..b75233db360511ffd909038f388f4e6f40224b03 100644
--- a/scripts/Imaging/IMAT/tomo_reconstruct.py
+++ b/scripts/Imaging/IMAT/tomo_reconstruct.py
@@ -1,3 +1,4 @@
+from __future__ import (absolute_import, division, print_function)
 # Copyright &copy; 2014,2015 ISIS Rutherford Appleton Laboratory, NScD
 # Oak Ridge National Laboratory & European Spallation Source
 #
@@ -267,6 +268,7 @@ def grab_postproc_options(args):
 def main_tomo_rec():
     # several dependencies (numpy, scipy) are too out-of-date in standard Python 2.6
     # distributions, as found for example on rhel6
+
     vers = sys.version_info
     if vers < (2,7,0):
         raise RuntimeError("Not running this test as it requires Python >= 2.7. Version found: {0}".
@@ -274,7 +276,7 @@ def main_tomo_rec():
 
     import inspect
 
-    import IMAT.tomorec.io as tomoio
+    import tomorec.io as tomoio
 
     arg_parser = setup_cmd_options()
     args = arg_parser.parse_args()
diff --git a/scripts/Imaging/IMAT/tomorec/__init__.py b/scripts/Imaging/IMAT/tomorec/__init__.py
index a21419b4aa431c480cd4c282be31431af89824cb..a96358ca9182fababaa97b11b15930b8149590ce 100644
--- a/scripts/Imaging/IMAT/tomorec/__init__.py
+++ b/scripts/Imaging/IMAT/tomorec/__init__.py
@@ -44,7 +44,6 @@ except ImportError as exc:
     raise ImportError(IMPORT_ERR_MSG.format("'tool_imports' (for third party "
                                             "tools such as Tomopy and Astra)",
                                             exc))
-
 try:
     from . import reconstruction_command
 except ImportError as exc:
diff --git a/scripts/Imaging/IMAT/tomorec/io.py b/scripts/Imaging/IMAT/tomorec/io.py
index 716950383951a9e089a9bf245422e4507ba834dc..1af5b750ab68badeaa5706142ba56a55dcef4886 100644
--- a/scripts/Imaging/IMAT/tomorec/io.py
+++ b/scripts/Imaging/IMAT/tomorec/io.py
@@ -1,3 +1,4 @@
+from __future__ import (absolute_import, division, print_function)
 # Copyright &copy; 2014-2015 ISIS Rutherford Appleton Laboratory, NScD
 # Oak Ridge National Laboratory & European Spallation Source
 #
@@ -115,7 +116,7 @@ def write_image(img_data, min_pix, max_pix, filename, img_format=None, dtype=Non
 
         too_verbose = False
         if too_verbose:
-            print "pix min: {0}, max: {1}, scale_factor: {2}".format(min_pix, max_pix, scale_factor)
+            print("pix min: {0}, max: {1}, scale_factor: {2}".format(min_pix, max_pix, scale_factor))
         img_data = scale_factor * (old_img_data - min_pix)
         img_data = img_data.astype(dtype=dtype)
 
@@ -186,8 +187,8 @@ def avg_image_files(path, base_path, file_extension=None, agg_method='average'):
         try:
             hdu = pyfits.open(ifile)
         except IOError as exc:
-            print "Got I/O exception trying to open and load {0}: {1}. Ignoring and going on.".format(
-                ifile, str(exc))
+            print("Got I/O exception trying to open and load {0}: {1}. Ignoring and going on.".format(
+                ifile, str(exc)))
             continue
 
         accum = _agg_img(accum, hdu[0].data, agg_method=agg_method)
@@ -370,7 +371,7 @@ def read_stack_of_images(sample_path, flat_field_path=None, dark_field_path=None
     sample_path = os.path.expanduser(sample_path)
 
     if verbose:
-        print "Loading stack of images from {0}".format(sample_path)
+        print("Loading stack of images from {0}".format(sample_path))
 
     if not file_prefix:
         file_prefix = ''
@@ -383,7 +384,7 @@ def read_stack_of_images(sample_path, flat_field_path=None, dark_field_path=None
     files_match.sort(key=_alphanum_key_split)
 
     if verbose:
-        print "Found {0} image files in {1}".format(len(files_match), sample_path)
+        print("Found {0} image files in {1}".format(len(files_match), sample_path))
 
     # It is assumed that all images have the same size and properties as the first.
     try:
@@ -460,7 +461,7 @@ def save_recon_netcdf(recon_data, output_dir, filename='tomo_recon_vol.nc'):
     try:
         from scipy.io import netcdf_file
     except ImportError as exc:
-        print " WARNING: could not save NetCDF file. Import error: {0}".format(exc)
+        print(" WARNING: could not save NetCDF file. Import error: {0}".format(exc))
 
     xsize = recon_data.shape[0]
     ysize = recon_data.shape[1]
@@ -471,11 +472,11 @@ def save_recon_netcdf(recon_data, output_dir, filename='tomo_recon_vol.nc'):
     ncfile.createDimension('x', xsize)
     ncfile.createDimension('y', ysize)
     ncfile.createDimension('z', zsize)
-    print " Creating netCDF volume data variable"
+    print(" Creating netCDF volume data variable")
     dtype = 'int16'
     data = ncfile.createVariable('data', np.dtype(dtype).char, ('x','y','z'))
-    print " Data shape: {0}".format(data.shape)
-    print " Loading/assigning data..."
+    print(" Data shape: {0}".format(data.shape))
+    print(" Loading/assigning data...")
 
     # handle differences in pixel type
     save_data = recon_data
@@ -489,7 +490,7 @@ def save_recon_netcdf(recon_data, output_dir, filename='tomo_recon_vol.nc'):
         save_data = save_data.astype(dtype=dtype)
 
     data[:, :, :] = save_data[0:xsize, 0:ysize, 0:zsize]
-    print " Closing netCDF file: {0}".format(nc_path)
+    print(" Closing netCDF file: {0}".format(nc_path))
     ncfile.close()
 
 
diff --git a/scripts/Imaging/IMAT/tomorec/reconstruction_command.py b/scripts/Imaging/IMAT/tomorec/reconstruction_command.py
index 7fbe76a3036e9bd46e5673ffe5e4e20e0473547d..c03ff568de3249b1f3c8f051b841be71468dc029 100644
--- a/scripts/Imaging/IMAT/tomorec/reconstruction_command.py
+++ b/scripts/Imaging/IMAT/tomorec/reconstruction_command.py
@@ -1,3 +1,4 @@
+from __future__ import (absolute_import, division, print_function)
 # Copyright &copy; 2014,2015 ISIS Rutherford Appleton Laboratory, NScD
 # Oak Ridge National Laboratory & European Spallation Source
 #
@@ -82,7 +83,7 @@ class ReconstructionCommand(object):
 
         data, white, dark = self.read_in_stack(cfg.preproc_cfg.input_dir, cfg.preproc_cfg.in_img_format,
                                                cfg.preproc_cfg.input_dir_flat, cfg.preproc_cfg.input_dir_dark)
-        print "Shape of raw data: {0}, dtype: {1}".format(data.shape, data.dtype)
+        print("Shape of raw data: {0}, dtype: {1}".format(data.shape, data.dtype))
 
         # These imports will raise appropriate exceptions in case of error
         import tomorec.tool_imports as tti
@@ -92,7 +93,7 @@ class ReconstructionCommand(object):
             tti.import_tomo_tool('tomopy')
 
         preproc_data = self.apply_all_preproc(data, cfg.preproc_cfg, white, dark)
-        print "Shape of pre-processed data: {0}, dtype: {1}".format(preproc_data.shape, data.dtype)
+        print("Shape of pre-processed data: {0}, dtype: {1}".format(preproc_data.shape, data.dtype))
 
         # Save pre-proc images
         self.save_preproc_images(cfg.postproc_cfg.output_dir, preproc_data, cfg.preproc_cfg)
@@ -113,7 +114,7 @@ class ReconstructionCommand(object):
         self.gen_readme_summary_end(readme_fullpath, (data, preproc_data, recon_data), tstart,
                                     t_recon_end - t_recon_start)
 
-        print "Finished reconstruction."
+        print("Finished reconstruction.")
 
     def gen_readme_summary_begin(self, filename, cfg, cmd_line):
         """
@@ -246,10 +247,10 @@ class ReconstructionCommand(object):
         """
         self._check_data_stack(data)
 
-        print " * Beginning pre-processing with pixel data type:", data.dtype
+        print(" * Beginning pre-processing with pixel data type:", data.dtype)
         if 'float64' == data.dtype:
             data = data.astype(dtype='float32')
-            print " * Note: pixel data type changed to:", data.dtype
+            print(" * Note: pixel data type changed to:", data.dtype)
 
         data, white, dark = self.rotate_stack(data, cfg, white, dark)
         if self.crop_before_normaliz:
@@ -291,7 +292,7 @@ class ReconstructionCommand(object):
         self._check_data_stack(imgs_angles)
 
         if not preproc_cfg.line_projection:
-            print " * Note: not applying line projection."
+            print(" * Note: not applying line projection.")
             return imgs_angles
 
         imgs_angles = imgs_angles.astype('float32')
@@ -321,22 +322,22 @@ class ReconstructionCommand(object):
             import prep as iprep
             if 'wavelet-fourier' == cfg.stripe_removal_method.lower():
                 time1 = time.time()
-                print " * Removing stripes/ring artifacts using the method '{0}'".format(cfg.stripe_removal_method)
+                print(" * Removing stripes/ring artifacts using the method '{0}'".format(cfg.stripe_removal_method))
                 #preproc_data = tomopy.prep.stripe.remove_stripe_fw(preproc_data)
                 preproc_data = iprep.filters.remove_stripes_ring_artifacts(preproc_data, 'wavelet-fourier')
                 time2 = time.time()
-                print " * Removed stripes/ring artifacts. Time elapsed: {0:.3f}".format(time2 - time1)
+                print(" * Removed stripes/ring artifacts. Time elapsed: {0:.3f}".format(time2 - time1))
             elif 'titarenko' == cfg.stripe_removal_method.lower():
                 time1 = time.time()
-                print " * Removing stripes/ring artifacts, using the method '{0}'".format(cfg.stripe_removal_method)
+                print(" * Removing stripes/ring artifacts, using the method '{0}'".format(cfg.stripe_removal_method))
                 preproc_data = tomopy.prep.stripe.remove_stripe_ti(preproc_data)
                 time2 = time.time()
-                print " * Removed stripes/ring artifacts, Time elapsed: {0:.3f}".format(time2 - time1)
+                print(" * Removed stripes/ring artifacts, Time elapsed: {0:.3f}".format(time2 - time1))
             else:
                 print(" * WARNING: stripe removal method '{0}' is unknown. Not applying it.".
                       format(cfg.stripe_removal_method))
         else:
-            print " * Note: not applying stripe removal."
+            print(" * Note: not applying stripe removal.")
 
         # Experimental options, disabled and not present in the config objects for now
         # These and related algorithms needs more evaluation/benchmarking
@@ -392,7 +393,7 @@ class ReconstructionCommand(object):
             air_sums = np.true_divide(air_sums, np.amax(air_sums))
             too_verbose = True
             if too_verbose:
-                print " Air region sums (relative to maximum): ", air_sums
+                print(" Air region sums (relative to maximum): ", air_sums)
 
             for idx in range(0, data.shape[0]):
                 data[idx, :, :] = np.true_divide(data[idx, :, :], air_sums[idx])
@@ -403,7 +404,7 @@ class ReconstructionCommand(object):
                   format(avg, np.max(air_sums)/avg, np.min(air_sums)/avg))
 
         else:
-            print " * Note: not normalizing by air region"
+            print(" * Note: not normalizing by air region")
 
         return data
 
@@ -429,7 +430,7 @@ class ReconstructionCommand(object):
                 print("Error in crop (region of interest) parameter (expecting a list with four integers. "
                       "Got: {0}. Error details: ".format(cfg.crop_coords), exc)
         else:
-            print " * Note: not applying cropping to region of interest."
+            print(" * Note: not applying cropping to region of interest.")
 
         return data
 
@@ -451,7 +452,7 @@ class ReconstructionCommand(object):
                              "configuration")
 
         if not cfg.normalize_flat_dark:
-            print " * Note: not applying normalization by flat/dark images."
+            print(" * Note: not applying normalization by flat/dark images.")
             return data
 
         if isinstance(norm_flat_img, np.ndarray):
@@ -478,7 +479,7 @@ class ReconstructionCommand(object):
                 data[idx, :, :] = np.true_divide(data[idx, :, :] - norm_dark_img, norm_divide)
             # true_divide produces float64, we assume that precision not needed (definitely not
             # for 16-bit depth output images as we usually have).
-            print " * Finished normalization by flat/dark images with pixel data type: {0}.".format(data.dtype)
+            print(" * Finished normalization by flat/dark images with pixel data type: {0}.".format(data.dtype))
         else:
             print(" * Note: cannot apply normalization by flat/dark images because no valid flat image has been "
                   "provided in the inputs. Flat image given: {0}".format(norm_flat_img))
@@ -502,29 +503,29 @@ class ReconstructionCommand(object):
 
         # Apply cut-off for the normalization?
         if cfg.cut_off_level and cfg.cut_off_level:
-            print "* Applying cut-off with level: {0}".format(cfg.cut_off_level)
+            print("* Applying cut-off with level: {0}".format(cfg.cut_off_level))
             dmin = np.amin(data)
             dmax = np.amax(data)
             rel_cut_off = dmin + cfg.cut_off_level * (dmax - dmin)
             data[data < rel_cut_off] = dmin
-            print " * Finished cut-off stepa, with pixel data type: {0}".format(data.dtype)
+            print(" * Finished cut-off stepa, with pixel data type: {0}".format(data.dtype))
         else:
-            print " * Note: not applying cut-off."
+            print(" * Note: not applying cut-off.")
 
         if cfg.mcp_corrections:
-            print " * MCP corrections not implemented in this version"
+            print(" * MCP corrections not implemented in this version")
 
         if cfg.scale_down:
-            print " * Scale down not implemented in this version"
+            print(" * Scale down not implemented in this version")
 
         if cfg.median_filter_size and cfg.median_filter_size > 1:
             for idx in range(0, data.shape[0]):
                 data[idx] = scipy.ndimage.median_filter(data[idx], cfg.median_filter_size, mode='mirror')
                 #, mode='nearest')
-            print (" * Finished noise filter / median, with pixel data type: {0}, filter size/width: {1}.".
-                   format(data.dtype, cfg.median_filter_size))
+            print(" * Finished noise filter / median, with pixel data type: {0}, filter size/width: {1}.".
+                  format(data.dtype, cfg.median_filter_size))
         else:
-            print " * Note: not applying noise filter /median."
+            print(" * Note: not applying noise filter /median.")
 
         return data
 
@@ -543,7 +544,7 @@ class ReconstructionCommand(object):
             raise ValueError("Cannot rotate images without a valid pre-processing configuration")
 
         if not cfg.rotation or cfg.rotation < 0:
-            print " * Note: not rotating the input images."
+            print(" * Note: not rotating the input images.")
             return data, white, dark
 
         data = self._rotate_imgs(data, cfg)
@@ -552,8 +553,8 @@ class ReconstructionCommand(object):
         if dark:
             dark = self._rotate_imgs(dark, cfg)
 
-        print (" * Finished rotation step ({0} degrees clockwise), with pixel data type: {1}".
-               format(cfg.rotation * 90, data.dtype))
+        print(" * Finished rotation step ({0} degrees clockwise), with pixel data type: {1}".
+              format(cfg.rotation * 90, data.dtype))
 
         return (data, white, dark)
 
@@ -606,21 +607,29 @@ class ReconstructionCommand(object):
             return self.run_reconstruct_3d_astra_simple(proj_data, proj_angles, alg_cfg, preproc_cfg.cor)
 
         for slice_idx in [int(proj_data.shape[0]/2)]: # examples to check: [30, 130, 230, 330, 430]:
-            print " > Finding center with tomopy find_center, slice index: {0}.".format(slice_idx)
+            print(" > Finding center with tomopy find_center, slice index: {0}.".format(slice_idx))
             import tomorec.tool_imports as tti
             try:
                 tomopy = tti.import_tomo_tool('tomopy')
-                print "proj_data: ", proj_data.shape
-                print "proj_angles: ", proj_angles.shape
-                tomopy_cor = tomopy.find_center(tomo=proj_data, theta=proj_angles, ind=slice_idx, emission=False)
+                print("proj_data: ", proj_data.shape)
+                print("proj_angles: ", proj_angles.shape)
+                # Temporary fix to support newer tomopy reconstructions,
+                # this does not guarantee that their output will be correct,
+                # but only patches the removal of the emission keyword and allows the recon to run
+                if(int(tomopy.__version__[0]) < 1):
+                    # for tomopy versions 0.x.x
+                    tomopy_cor = tomopy.find_center(tomo=proj_data, theta=proj_angles, ind=slice_idx, emission=False)
+                else:
+                    # for tomopy versions 1.x.x
+                    tomopy_cor = tomopy.find_center(tomo=proj_data, theta=proj_angles, ind=slice_idx)
                 if not preproc_cfg.cor:
                     preproc_cfg.cor = tomopy_cor
-                print " > Center of rotation found by tomopy.find_center:  {0}".format(tomopy_cor)
+                print(" > Center of rotation found by tomopy.find_center:  {0}".format(tomopy_cor))
             except ImportError as exc:
                 print(" * WARNING: could not import tomopy so could not use the tomopy method to find the center "
                       "of rotation. Details: {0}".format(exc))
 
-        print "Using center of rotation: {0}".format(preproc_cfg.cor)
+        print("Using center of rotation: {0}".format(preproc_cfg.cor))
         start = time.time()
         if 'tomopy' == alg_cfg.tool and 'gridrec' != alg_cfg.algorithm and 'fbp' != alg_cfg.algorithm:
             if not alg_cfg.num_iter:
@@ -640,7 +649,7 @@ class ReconstructionCommand(object):
             rec = tomopy.recon(tomo=proj_data, theta=proj_angles, center=preproc_cfg.cor,
                                algorithm=alg_cfg.algorithm)
         tnow = time.time()
-        print "Reconstructed 3D volume. Time elapsed in reconstruction algorithm: {0:.3f}".format(tnow - start)
+        print("Reconstructed 3D volume. Time elapsed in reconstruction algorithm: {0:.3f}".format(tnow - start))
 
         return rec
 
@@ -708,7 +717,7 @@ class ReconstructionCommand(object):
 
         nSinos = get_max_frames(algorithm=algorithm)
         iterations = alg_cfg.num_iter
-        print " astra recon - doing {0} iterations".format(iterations)
+        print(" astra recon - doing {0} iterations".format(iterations))
 
         # swaps outermost dimensions so it is sinogram layout
         sinogram = proj_data
@@ -796,26 +805,26 @@ class ReconstructionCommand(object):
 
         if cfg.circular_mask:
             recon_data = iprep.filters.circular_mask(recon_data, ratio=cfg.circular_mask)
-            print " * Applied circular mask on reconstructed volume"
+            print(" * Applied circular mask on reconstructed volume")
         else:
-            print " * Note: not applied circular mask on reconstructed volume"
+            print(" * Note: not applied circular mask on reconstructed volume")
 
         if cfg.cut_off_level and cfg.cut_off_level > 0.0:
-            print "=== applying cut-off: {0}".format(cfg.cut_off)
+            print("=== applying cut-off: {0}".format(cfg.cut_off))
             dmin = np.amin(recon_data)
             dmax = np.amax(recon_data)
             rel_cut_off = dmin + cfg.cut_off * (dmax - dmin)
             recon_data[recon_data < rel_cut_off] = dmin
 
         if cfg.gaussian_filter_par:
-            print " * Gaussian filter not implemented"
+            print(" * Gaussian filter not implemented")
 
         if cfg.median_filter_size and cfg.median_filter_size > 1:
             recon_data = scipy.ndimage.median_filter(recon_data, cfg.median_filter_size)
-            print (" * Applied median_filter on reconstructed volume, with filtersize: {0}".
-                   format(cfg.median_filter_size))
+            print(" * Applied median_filter on reconstructed volume, with filtersize: {0}".
+                  format(cfg.median_filter_size))
         else:
-            print " * Note: not applied median_filter on reconstructed volume"
+            print(" * Note: not applied median_filter on reconstructed volume")
 
         if cfg.median_filter3d_size and cfg.median_filter3d_size > 1:
             kernel_size=3
@@ -824,7 +833,7 @@ class ReconstructionCommand(object):
             print(" * Applied N-dimensional median filter on reconstructed volume, with filter size: {0} ".
                   format(kernel_size))
         else:
-            print " * Note: not applied N-dimensional median filter on reconstructed volume"
+            print(" * Note: not applied N-dimensional median filter on reconstructed volume")
 
     def read_in_stack(self, sample_path, img_format, flat_field_path=None, dark_field_path=None):
         """
@@ -872,7 +881,7 @@ class ReconstructionCommand(object):
         # output_dir = 'output_recon_tomopy'
         output_dir = cfg.postproc_cfg.output_dir
         out_recon_dir = os.path.join(output_dir, 'reconstructed')
-        print "* Saving slices of the reconstructed volume in: {0}".format(out_recon_dir)
+        print("* Saving slices of the reconstructed volume in: {0}".format(out_recon_dir))
         tomoio.save_recon_as_vertical_slices(recon_data, out_recon_dir,
                                              name_prefix=self._OUT_SLICES_FILENAME_PREFIX,
                                              img_format=cfg.preproc_cfg.out_img_format)
@@ -881,13 +890,13 @@ class ReconstructionCommand(object):
         save_horiz_slices = False
         if save_horiz_slices:
             out_horiz_dir = os.path.join(output_dir, 'horiz_slices')
-            print "* Saving horizontal slices in: {0}".format(out_horiz_dir)
+            print("* Saving horizontal slices in: {0}".format(out_horiz_dir))
             tomoio.save_recon_as_horizontal_slices(recon_data, out_horiz_dir,
                                                    name_prefix=self._OUT_HORIZ_SLICES_SUBDIR,
                                                    img_format=cfg.preproc_cfg.out_img_format)
 
         if save_netcdf_vol:
-            print "* Saving reconstructed volume as NetCDF"
+            print("* Saving reconstructed volume as NetCDF")
             tomoio.save_recon_netcdf(recon_data, output_dir)
 
     def save_preproc_images(self, output_dir, preproc_data, preproc_cfg, out_dtype='uint16'):
@@ -900,13 +909,13 @@ class ReconstructionCommand(object):
         @param out_dtype :: dtype used for the pixel type/depth in the output image files
         """
 
-        print " * Pre-processed images (preproc_data) dtype:", preproc_data.dtype
+        print(" * Pre-processed images (preproc_data) dtype:", preproc_data.dtype)
         min_pix = np.amin(preproc_data)
         max_pix = np.amax(preproc_data)
-        print "   with min_pix: {0}, max_pix: {1}".format(min_pix, max_pix)
+        print("   with min_pix: {0}, max_pix: {1}".format(min_pix, max_pix))
         if preproc_cfg.save_preproc_imgs:
             preproc_dir = os.path.join(output_dir, self._PREPROC_IMGS_SUBDIR_NAME)
-            print "* Saving pre-processed images into: {0}".format(preproc_dir)
+            print("* Saving pre-processed images into: {0}".format(preproc_dir))
             tomoio.make_dirs_if_needed(preproc_dir)
             for idx in range(0, preproc_data.shape[0]):
                 # rescale_intensity has issues with float64=>int16
@@ -914,7 +923,7 @@ class ReconstructionCommand(object):
                                    os.path.join(preproc_dir, 'out_preproc_proj_image' + str(idx).zfill(6)),
                                    img_format=preproc_cfg.out_img_format, dtype=out_dtype)
         else:
-            print "* NOTE: not saving pre-processed images..."
+            print("* NOTE: not saving pre-processed images...")
 
     def _check_data_stack(self, data):
         if not isinstance(data, np.ndarray):
diff --git a/scripts/Imaging/IMAT/tomorec/tool_imports.py b/scripts/Imaging/IMAT/tomorec/tool_imports.py
index 5896d1c87cd853b9032f95acf537f8d70359a65d..066d8c266abe392b3b37d46aa4e986d496096a59 100644
--- a/scripts/Imaging/IMAT/tomorec/tool_imports.py
+++ b/scripts/Imaging/IMAT/tomorec/tool_imports.py
@@ -1,3 +1,4 @@
+from __future__ import (absolute_import, division, print_function)
 # Copyright &copy; 2014-2015 ISIS Rutherford Appleton Laboratory, NScD
 # Oak Ridge National Laboratory & European Spallation Source
 #
@@ -48,11 +49,11 @@ def _import_tool_astra():
     MIN_ASTRA_VERSION = 106
     vers = astra.astra.version()
     if isinstance(vers, int) and vers >= MIN_ASTRA_VERSION:
-        print "Imported astra successfully. Version: {0}".format(astra.astra.version())
+        print("Imported astra successfully. Version: {0}".format(astra.astra.version()))
     else:
         raise RuntimeError("Could not find the required version of astra. Found version: {0}".format(vers))
 
-    print "Astra using cuda: {0}". format(astra.astra.use_cuda())
+    print("Astra using cuda: {0}". format(astra.astra.use_cuda()))
     return astra
 
 
diff --git a/scripts/Inelastic/CrystalField/__init__.py b/scripts/Inelastic/CrystalField/__init__.py
index 41cdcffe90094d7c74d052986572a5c25116fc80..fe7324f20cca18412f3165127b090b50bc816734 100644
--- a/scripts/Inelastic/CrystalField/__init__.py
+++ b/scripts/Inelastic/CrystalField/__init__.py
@@ -1,5 +1,5 @@
 from __future__ import (absolute_import, division, print_function)
 from .fitting import CrystalField, CrystalFieldFit, CrystalFieldMulti
-from .function import PeaksFunction, Background, Function, ResolutionModel
+from .function import PeaksFunction, Background, Function, ResolutionModel, PhysicalProperties
 __all__ = ['CrystalField', 'CrystalFieldFit', 'CrystalFieldMulti', 'PeaksFunction',
-           'Background', 'Function', 'ResolutionModel']
+           'Background', 'Function', 'ResolutionModel', 'PhysicalProperties']
diff --git a/scripts/Inelastic/CrystalField/fitting.py b/scripts/Inelastic/CrystalField/fitting.py
index 5af885c879534bf3fdc2ff64c5f81d71782a2106..8330704dee697d953e0d52516ed9312dcd9500cf 100644
--- a/scripts/Inelastic/CrystalField/fitting.py
+++ b/scripts/Inelastic/CrystalField/fitting.py
@@ -1,7 +1,9 @@
 from __future__ import (absolute_import, division, print_function)
 import numpy as np
 import re
-from mantid.kernel import ConfigService
+import warnings
+from six import string_types
+
 
 # RegEx pattern matching a composite function parameter name, eg f2.Sigma.
 FN_PATTERN = re.compile('f(\\d+)\\.(.+)')
@@ -57,7 +59,8 @@ class CrystalField(object):
                         ToleranceEnergy:     energy tolerance,
                         ToleranceIntensity:  intensity tolerance,
                         ResolutionModel:     A resolution model.
-                        FWHMVariation:      Absolute value of allowed variation of a peak width during a fit.
+                        FWHMVariation:       Absolute value of allowed variation of a peak width during a fit.
+                        FixAllPeaks:         A boolean flag that fixes all parameters of the peaks.
 
                         Field parameters:
 
@@ -102,10 +105,10 @@ class CrystalField(object):
                         IntensityScaling: A scaling factor for the intensity of each spectrum.
                         FWHM: A default value for the full width at half maximum of the peaks.
                         Temperature: A temperature "of the spectrum" in Kelvin
+                        PhysicalProperty: A list of PhysicalProperties objects denoting the required data type
+                                          Note that physical properties datasets should follow inelastic spectra
+                                          See the Crystal Field Python Interface help page for more details.
         """
-        # This is to make sure that Lorentzians get evaluated properly
-        ConfigService.setString('curvefitting.peakRadius', str(100))
-
         from .function import PeaksFunction
         self._ion = Ion
         self._symmetry = Symmetry
@@ -116,9 +119,11 @@ class CrystalField(object):
         self._fieldConstraints = []
         self._temperature = None
         self._FWHM = None
-        self._intensityScaling = 1.0
+        self._intensityScaling = None
         self._resolutionModel = None
         self._fwhmVariation = None
+        self._fixAllPeaks = False
+        self._physprop = None
 
         for key in kwargs:
             if key == 'ToleranceEnergy':
@@ -135,6 +140,10 @@ class CrystalField(object):
                 self._temperature = kwargs[key]
             elif key == 'FWHMVariation':
                 self._fwhmVariation = kwargs[key]
+            elif key == 'FixAllPeaks':
+                self._fixAllPeaks = kwargs[key]
+            elif key == 'PhysicalProperty':
+                self._physprop = kwargs[key]
             else:
                 # Crystal field parameters
                 self._fieldParameters[key] = kwargs[key]
@@ -181,10 +190,14 @@ class CrystalField(object):
         temperature = self._getTemperature(i)
         out = 'name=CrystalFieldSpectrum,Ion=%s,Symmetry=%s,Temperature=%s' % (self._ion, self._symmetry, temperature)
         out += ',ToleranceEnergy=%s,ToleranceIntensity=%s' % (self._toleranceEnergy, self._toleranceIntensity)
+        out += ',FixAllPeaks=%s' % (1 if self._fixAllPeaks else 0)
         out += ',PeakShape=%s' % self.getPeak(i).name
+        if self._intensityScaling is not None:
+            out += ',IntensityScaling=%s' % self._intensityScaling
         if self._FWHM is not None:
             out += ',FWHM=%s' % self._getFWHM(i)
-        out += ',%s' % ','.join(['%s=%s' % item for item in self._fieldParameters.items()])
+        if len(self._fieldParameters) > 0:
+            out += ',%s' % ','.join(['%s=%s' % item for item in self._fieldParameters.items()])
         if self._resolutionModel is not None:
             if self._resolutionModel.multi:
                 model = self._resolutionModel.model[i]
@@ -218,35 +231,78 @@ class CrystalField(object):
             out += ',constraints=(%s)' % constraints
         return out
 
-    # pylint: disable=too-many-public-branches
-    def makeMultiSpectrumFunction(self):
-        """Form a definition string for the CrystalFieldMultiSpectrum function"""
-        out = 'name=CrystalFieldMultiSpectrum,Ion=%s,Symmetry=%s' % (self._ion, self._symmetry)
-        out += ',ToleranceEnergy=%s,ToleranceIntensity=%s' % (self._toleranceEnergy, self._toleranceIntensity)
+    def makePhysicalPropertiesFunction(self, i=0):
+        """Form a definition string for one of the crystal field physical properties functions
+        @param i: Index of the dataset (default=0), or a PhysicalProperties object.
+        """
+        if hasattr(i, 'toString'):
+            out = i.toString()
+        else:
+            if self._physprop is None:
+                raise RuntimeError('Physical properties environment not defined.')
+            ppobj = self._physprop[i] if hasattr(self._physprop, '__len__') else self._physprop
+            if hasattr(ppobj, 'toString'):
+                out = ppobj.toString()
+            else:
+                return ''
+        out += ',Ion=%s,Symmetry=%s' % (self._ion, self._symmetry)
+        if len(self._fieldParameters) > 0:
+            out += ',%s' % ','.join(['%s=%s' % item for item in self._fieldParameters.items()])
+        ties = self.getFieldTies()
+        if len(ties) > 0:
+            out += ',ties=(%s)' % ties
+        constraints = self.getFieldConstraints()
+        if len(constraints) > 0:
+            out += ',constraints=(%s)' % constraints
+        return out
+
+    def _makeMultiAttributes(self):
+        """
+        Make the main attribute part of the function string for makeMultiSpectrumFunction()
+        """
+        # Handles physical properties (PP). self._temperature applies only for INS datasets. But the
+        # C++ CrystalFieldMultiSpectrum uses it to count number of datasets, so we need to set it here
+        # as a concatenation of the INS (self._temperature and self._FWHM) and PP (self._physprop)
+        if self._temperature is None:
+            if self._physprop is None:
+                errmsg = 'Cannot run fit: No temperature (INS spectrum) or physical properties defined.'
+                raise RuntimeError(errmsg)
+            physprop = []
+            temperature = []
+            FWHM = []
+        else:
+            physprop = (len(self._temperature) if hasattr(self._temperature, '__len__') else 1) * [None]
+            temperature = self._temperature if hasattr(self._temperature, '__len__') else [self._temperature]
+            FWHM = self._FWHM if hasattr(self._FWHM, '__len__') else [self._FWHM]
+        if self._physprop is not None:
+            for pp in (self._physprop if hasattr(self._physprop, '__len__') else [self._physprop]):
+                temperature.append(pp.Temperature if (pp.Temperature is not None) else 0.)
+                FWHM.append(0.)
+                physprop.append(pp)
+            ppid = [0 if pp is None else pp.TypeID for pp in physprop]
+            ppenv = [pp.envString(i) for i, pp in enumerate(physprop) if pp is not None]
+            ppenv = filter(None, ppenv)
+        out = ',ToleranceEnergy=%s,ToleranceIntensity=%s' % (self._toleranceEnergy, self._toleranceIntensity)
         out += ',PeakShape=%s' % self.getPeak().name
+        out += ',FixAllPeaks=%s' % (1 if self._fixAllPeaks else 0)
         if self.background is not None:
             out += ',Background=%s' % self.background[0].nameString()
-        out += ',Temperatures=(%s)' % ','.join(map(str, self._temperature))
+        out += ',Temperatures=(%s)' % ','.join(map(str, temperature))
+        if self._physprop is not None:
+            out += ',PhysicalProperties=(%s)' % ','.join(map(str, ppid))
+            out += ',%s' % ','.join(map(str, ppenv))
         if self._FWHM is not None:
-            out += ',FWHMs=(%s)' % ','.join(map(str, self._FWHM))
-        out += ',%s' % ','.join(['%s=%s' % item for item in self._fieldParameters.items()])
+            out += ',FWHMs=(%s)' % ','.join(map(str, FWHM))
+        if self._intensityScaling is not None:
+            for i in range(len(self._intensityScaling)):
+                out += ',IntensityScaling%s=%s' % (i, self._intensityScaling[i])
+        return out
 
-        tieList = []
-        constraintsList = []
-        if self.background is not None:
-            i = 0
-            for background in self.background:
-                prefix = 'f%s.f0.' % i
-                bgOut = background.paramString(prefix)
-                if len(bgOut) > 0:
-                    out += ',%s' % bgOut
-                tieOut = background.tiesString(prefix)
-                if len(tieOut) > 0:
-                    tieList.append(tieOut)
-                constraintsOut = background.constraintsString(prefix)
-                if len(constraintsOut) > 0:
-                    constraintsList.append(constraintsOut)
-                i += 1
+    def _makeMultiResolutionModel(self):
+        """
+        Make the resolution model part of the function string for makeMultiSpectrumFunction()
+        """
+        out = ''
         if self._resolutionModel is not None:
             i = 0
             for model in self._resolutionModel.model:
@@ -254,8 +310,15 @@ class CrystalField(object):
                 i += 1
             if self._fwhmVariation is not None:
                 out += ',FWHMVariation=%s' % self._fwhmVariation
+        return out
+
+    def _makeMultiPeaks(self):
+        """
+        Make the peaks part of the function string for makeMultiSpectrumFunction()
+        """
+        out = ''
         i = 0
-        for peaks in self.peaks:
+        for peaks in (self.peaks if hasattr(self.peaks, '__len__') else [self.peaks]):
             parOut = peaks.paramString('f%s.' % i, 1)
             if len(parOut) > 0:
                 out += ',%s' % parOut
@@ -266,6 +329,35 @@ class CrystalField(object):
             if len(constraintsOut) > 0:
                 out += ',%s' % constraintsOut
             i += 1
+        return out
+
+    # pylint: disable=too-many-public-branches
+    def makeMultiSpectrumFunction(self):
+        """Form a definition string for the CrystalFieldMultiSpectrum function"""
+        out = 'name=CrystalFieldMultiSpectrum,Ion=%s,Symmetry=%s' % (self._ion, self._symmetry)
+        out += self._makeMultiAttributes()
+        out += ',%s' % ','.join(['%s=%s' % item for item in self._fieldParameters.items()])
+
+        tieList = []
+        constraintsList = []
+        if self.background is not None:
+            i = 0
+            for background in self.background:
+                prefix = 'f%s.f0.' % i
+                bgOut = background.paramString(prefix)
+                if len(bgOut) > 0:
+                    out += ',%s' % bgOut
+                tieOut = background.tiesString(prefix)
+                if len(tieOut) > 0:
+                    tieList.append(tieOut)
+                constraintsOut = background.constraintsString(prefix)
+                if len(constraintsOut) > 0:
+                    constraintsList.append(constraintsOut)
+                i += 1
+        if self._temperature is not None:
+            out += self._makeMultiResolutionModel()
+            out += self._makeMultiPeaks()
+
         ties = self.getFieldTies()
         if len(ties) > 0:
             tieList.append(ties)
@@ -374,9 +466,14 @@ class CrystalField(object):
 
     @Temperature.setter
     def Temperature(self, value):
-        self._temperature= value
+        lenval = len(value) if hasattr(value, '__len__') else 1
+        lentemp = len(self._temperature) if hasattr(self._temperature, '__len__') else 1
+        self._temperature = value
         self._dirty_peaks = True
         self._dirty_spectra = True
+        if lenval != lentemp:
+            peakname = self.peaks[0].name if isinstance(self.peaks, list) else self.peaks.name
+            self.setPeaks(peakname)
 
     @property
     def FWHM(self):
@@ -406,6 +503,37 @@ class CrystalField(object):
         else:
             self._resolutionModel = ResolutionModel(value)
 
+    @property
+    def FixAllPeaks(self):
+        return self._fixAllPeaks
+
+    @FixAllPeaks.setter
+    def FixAllPeaks(self, value):
+        self._fixAllPeaks = value
+
+    @property
+    def NumberOfSpectra(self):
+        return len(self._temperature)
+
+    @property
+    def PhysicalProperty(self):
+        return self._physprop
+
+    @PhysicalProperty.setter
+    def PhysicalProperty(self, value):
+        from .function import PhysicalProperties
+        vlist = value if hasattr(value, '__len__') else [value]
+        if all([isinstance(pp, PhysicalProperties) for pp in vlist]):
+            self._physprop = value
+        else:
+            errmsg = 'PhysicalProperty input must be a PhysicalProperties'
+            errmsg += ' instance or a list of such instances'
+            raise ValueError(errmsg)
+
+    @property
+    def isPhysicalPropertyOnly(self):
+        return self.Temperature is None and self.PhysicalProperty
+
     def ties(self, **kwargs):
         """Set ties on the field parameters.
 
@@ -520,6 +648,150 @@ class CrystalField(object):
         self._spectra[i] = self._calcSpectrum(i, wksp, 0)
         return self._spectra[i]
 
+    def getHeatCapacity(self, workspace=None, ws_index=0):
+        """
+        Get the heat cacpacity calculated with the current crystal field parameters
+
+        Examples:
+
+            cf.getHeatCapacity()    # Returns the heat capacity from 1 < T < 300 K in 1 K steps
+            cf.getHeatCapacity(ws)  # Returns the heat capacity with temperatures given by ws.
+            cf.getHeatCapacity(ws, ws_index)  # Use the spectrum indicated by ws_index for x-values
+
+        @param workspace: Either a Mantid workspace whose x-values will be used as the temperatures
+                          to calculate the heat capacity; or a list of numpy ndarray of temperatures.
+                          Temperatures are in Kelvin.
+        @param ws_index:  The index of a spectrum in workspace to use (default=0).
+        """
+        from .function import PhysicalProperties
+        return self._getPhysProp(PhysicalProperties('Cv'), workspace, ws_index)
+
+    def getSusceptibility(self, *args, **kwargs):
+        """
+        Get the magnetic susceptibility calculated with the current crystal field parameters.
+        The susceptibility is calculated using Van Vleck's formula (2nd order perturbation theory)
+
+        Examples:
+
+            cf.getSusceptibility()      # Returns the susceptibility || [001] for 1<T<300 K in 1 K steps
+            cf.getSusceptibility(T)     # Returns the susceptibility with temperatures given by T.
+            cf.getSusceptibility(ws, 0) # Use x-axis of spectrum 0 of workspace ws as temperature
+            cf.getSusceptibility(T, [1, 1, 1])  # Returns the susceptibility along [111].
+            cf.getSusceptibility(T, 'powder')   # Returns the powder averaged susceptibility
+            cf.getSusceptibility(T, 'cgs')      # Returns the susceptibility || [001] in cgs normalisation
+            cf.getSusceptibility(..., Inverse=True)  # Calculates the inverse susceptibility instead
+            cf.getSusceptibility(Temperature=ws, ws_index=0, Hdir=[1, 1, 0], Unit='SI', Inverse=True)
+
+        @param Temperature: Either a Mantid workspace whose x-values will be used as the temperatures
+                            to calculate the heat capacity; or a list or numpy ndarray of temperatures.
+                            Temperatures are in Kelvin.
+        @param ws_index: The index of a spectrum to use (default=0) if using a workspace for x.
+        @param Hdir: The magnetic field direction to calculate the susceptibility along. Either a
+                     Cartesian vector with z along the quantisation axis of the CF parameters, or the
+                     string 'powder' (case insensitive) to get the powder averaged susceptibility
+                     default: [0, 0, 1]
+        @param Unit: Any one of the strings 'bohr', 'SI' or 'cgs' (case insensitive) to indicate whether
+                     to output in atomic (bohr magneton/Tesla/ion), SI (m^3/mol) or cgs (cm^3/mol) units.
+                     default: 'cgs'
+        @param Inverse: Whether to calculate the susceptibility (Inverse=False, default) or inverse
+                        susceptibility (Inverse=True).
+        """
+        from .function import PhysicalProperties
+
+        # Sets defaults / parses keyword arguments
+        workspace = kwargs['Temperature'] if 'Temperature' in kwargs.keys() else None
+        ws_index = kwargs['ws_index'] if 'ws_index' in kwargs.keys() else 0
+
+        # Parses argument list
+        args = list(args)
+        if len(args) > 0:
+            workspace = args.pop(0)
+        if 'mantid' in str(type(workspace)) and len(args) > 0:
+            ws_index = args.pop(0)
+
+        # _calcSpectrum updates parameters and susceptibility has a 'Lambda' parameter which other
+        # CF functions don't have. This causes problems if you want to calculate another quantity after
+        x, y = self._getPhysProp(PhysicalProperties('chi', *args, **kwargs), workspace, ws_index)
+        self._fieldParameters.pop('Lambda', None)
+        return x, y
+
+    def getMagneticMoment(self, *args, **kwargs):
+        """
+        Get the magnetic moment calculated with the current crystal field parameters.
+        The moment is calculated by adding a Zeeman term to the CF Hamiltonian and then diagonlising
+        the result. This function calculates either M(H) [default] or M(T), but can only calculate
+        a 1D function (e.g. not M(H,T) simultaneously).
+
+        Examples:
+
+            cf.getMagneticMoment()       # Returns M(H) for H||[001] from 0 to 30 T in 0.1 T steps
+            cf.getMagneticMoment(H)      # Returns M(H) for H||[001] at specified values of H (in Tesla)
+            cf.getMagneticMoment(ws, 0)  # Use x-axis of spectrum 0 of ws as applied field magnitude.
+            cf.getMagneticMoment(H, [1, 1, 1])  # Returns the magnetic moment along [111].
+            cf.getMagneticMoment(H, 'powder')   # Returns the powder averaged M(H)
+            cf.getMagneticMoment(H, 'cgs')      # Returns the moment || [001] in cgs units (emu/mol)
+            cf.getMagneticMoment(Temperature=T) # Returns M(T) for H=1T || [001] at specified T (in K)
+            cf.getMagneticMoment(10, [1, 1, 0], Temperature=T) # Returns M(T) for H=10T || [110].
+            cf.getMagneticMoment(..., Inverse=True)  # Calculates 1/M instead (keyword only)
+            cf.getMagneticMoment(Hmag=ws, ws_index=0, Hdir=[1, 1, 0], Unit='SI', Temperature=T, Inverse=True)
+
+        @param Hmag: The magnitude of the applied magnetic field in Tesla, specified either as a Mantid
+                     workspace whose x-values will be used; or a list or numpy ndarray of field points.
+                     If Temperature is specified as a list / array / workspace, Hmag must be scalar.
+                     (default: 0-30T in 0.1T steps, or 1T if temperature vector specified)
+        @param Temperature: The temperature in Kelvin at which to calculate the moment.
+                            Temperature is a keyword argument only. Can be a list, ndarray or workspace.
+                            If Hmag is a list / array / workspace, Temperature must be scalar.
+                            (default=1K)
+        @param ws_index: The index of a spectrum to use (default=0) if using a workspace for x.
+        @param Hdir: The magnetic field direction to calculate the susceptibility along. Either a
+                     Cartesian vector with z along the quantisation axis of the CF parameters, or the
+                     string 'powder' (case insensitive) to get the powder averaged susceptibility
+                     default: [0, 0, 1]
+        @param Unit: Any one of the strings 'bohr', 'SI' or 'cgs' (case insensitive) to indicate whether
+                     to output in atomic (bohr magneton/ion), SI (Am^2/mol) or cgs (emu/mol) units.
+                     default: 'bohr'
+        @param Inverse: Whether to calculate the susceptibility (Inverse=False, default) or inverse
+                        susceptibility (Inverse=True). Inverse is a keyword argument only.
+        """
+        from .function import PhysicalProperties
+
+        # Sets defaults / parses keyword arguments
+        workspace = None
+        ws_index = kwargs['ws_index'] if 'ws_index' in kwargs.keys() else 0
+        hmag = kwargs['Hmag'] if 'Hmag' in kwargs.keys() else 1.
+        temperature = kwargs['Temperature'] if 'Temperature' in kwargs.keys() else 1.
+
+        # Checks whether to calculate M(H) or M(T)
+        hmag_isscalar = (not hasattr(hmag, '__len__') or len(hmag) == 1)
+        hmag_isvector = (hasattr(hmag, '__len__') and len(hmag) > 1)
+        t_isscalar = (not hasattr(temperature, '__len__') or len(temperature) == 1)
+        t_isvector = (hasattr(temperature, '__len__') and len(temperature) > 1)
+        if hmag_isscalar and (t_isvector or 'mantid' in str(type(temperature))):
+            typeid = 4
+            workspace = temperature
+            kwargs['Hmag'] = hmag[0] if hasattr(hmag, '__len__') else hmag
+        else:
+            typeid = 3
+            if t_isscalar and (hmag_isvector or 'mantid' in str(type(hmag))):
+                workspace = hmag
+            kwargs['Temperature'] = temperature[0] if hasattr(temperature, '__len__') else temperature
+
+        # Parses argument list
+        args = list(args)
+        if len(args) > 0:
+            if typeid == 4:
+                kwargs['Hmag'] = args.pop(0)
+            else:
+                workspace = args.pop(0)
+        if 'mantid' in str(type(workspace)) and len(args) > 0:
+            ws_index = args.pop(0)
+
+        pptype = 'M(T)' if (typeid == 4) else 'M(H)'
+        self._typeid = self._str2id(typeid) if isinstance(typeid, string_types) else int(typeid)
+
+        return self._getPhysProp(PhysicalProperties(pptype, *args, **kwargs), workspace, ws_index)
+
     def plot(self, i=0, workspace=None, ws_index=0, name=None):
         """Plot a spectrum. Parameters are the same as in getSpectrum(...)"""
         from mantidplot import plotSpectrum
@@ -624,7 +896,8 @@ class CrystalField(object):
                 if ipeak == 0:
                     if self.background is None:
                         self.setBackground(background=Function(self.default_background))
-                    background = self.background[ispec]
+                    background = (self.background[ispec]
+                                  if hasattr(self.background, '__len__') else self.background)
                     bgMatch = re.match(FN_PATTERN, par)
                     if bgMatch:
                         i = int(bgMatch.group(1))
@@ -641,7 +914,10 @@ class CrystalField(object):
                         else:
                             raise RuntimeError('Background is undefined in CrystalField instance.')
                 else:
-                    self.peaks[ispec].param[ipeak - 1][par] = value
+                    if hasattr(self.peaks, '__len__'):
+                        self.peaks[ispec].param[ipeak - 1][par] = value
+                    else:
+                        self.peaks.param[ipeak - 1][par] = value
             else:
                 self._fieldParameters[par] = value
 
@@ -662,7 +938,19 @@ class CrystalField(object):
         return x_min, x_max
 
     def __add__(self, other):
-        return CrystalFieldMulti(self, other)
+        if isinstance(other, CrystalFieldMulti):
+            return other.__radd__(self)
+        return CrystalFieldMulti(CrystalFieldSite(self, 1.0), other)
+
+    def __mul__(self, factor):
+        ffactor = float(factor)
+        if ffactor == 0.0:
+            msg = 'Intensity scaling factor for %s(%s) is set to zero ' % (self.Ion, self.Symmetry)
+            warnings.warn(msg, SyntaxWarning)
+        return CrystalFieldSite(self, ffactor)
+
+    def __rmul__(self, factor):
+        return self.__mul__(factor)
 
     def _getTemperature(self, i):
         """Get temperature value for i-th spectrum."""
@@ -674,7 +962,7 @@ class CrystalField(object):
             return float(self._temperature)
         else:
             nTemp = len(self._temperature)
-            if i >= -nTemp and i < nTemp:
+            if -nTemp <= i < nTemp:
                 return float(self._temperature[i])
             else:
                 raise RuntimeError('Cannot evaluate spectrum %s. Only %s temperatures are given.' % (i, nTemp))
@@ -698,6 +986,32 @@ class CrystalField(object):
             return self.peaks[i]
         return self.peaks
 
+    def _getPhysProp(self, ppobj, workspace, ws_index):
+        """
+        Returns a physical properties calculation
+        @param ppobj: a PhysicalProperties object indicating the physical property type and environment
+        @param workspace: workspace or array/list of x-values.
+        @param ws_index:  An index of a spectrum in workspace to use.
+        """
+        try:
+            typeid = ppobj.TypeID
+        except AttributeError:
+            raise RuntimeError('Invalid PhysicalProperties object specified')
+
+        defaultX = [np.linspace(1, 300, 300), np.linspace(1, 300, 300), np.linspace(0, 30, 300),
+                    np.linspace(0, 30, 300)]
+        funstr = self.makePhysicalPropertiesFunction(ppobj)
+        if workspace is None:
+            xArray = defaultX[typeid - 1]
+        elif isinstance(workspace, list) or isinstance(workspace, np.ndarray):
+            xArray = workspace
+        else:
+            return self._calcSpectrum(funstr, workspace, ws_index)
+
+        yArray = np.zeros_like(xArray)
+        wksp = makeWorkspace(xArray, yArray)
+        return self._calcSpectrum(funstr, wksp, ws_index)
+
     def _calcEigensystem(self):
         """Calculate the eigensystem: energies and wavefunctions.
         Also store them and the hamiltonian.
@@ -722,10 +1036,10 @@ class CrystalField(object):
             alg.execute()
             self._peakList = alg.getProperty('OutputWorkspace').value
 
-    def _calcSpectrum(self, i, workspace, ws_index):
+    def _calcSpectrum(self, i, workspace, ws_index, funstr=None):
         """Calculate i-th spectrum.
 
-        @param i: Index of a spectrum
+        @param i: Index of a spectrum or function string
         @param workspace: A workspace used to evaluate the spectrum function.
         @param ws_index:  An index of a spectrum in workspace to use.
         """
@@ -733,7 +1047,7 @@ class CrystalField(object):
         alg = AlgorithmManager.createUnmanaged('EvaluateFunction')
         alg.initialize()
         alg.setChild(True)
-        alg.setProperty('Function', self.makeSpectrumFunction(i))
+        alg.setProperty('Function', i if isinstance(i, string_types) else self.makeSpectrumFunction(i))
         alg.setProperty("InputWorkspace", workspace)
         alg.setProperty('WorkspaceIndex', ws_index)
         alg.setProperty('OutputWorkspace', 'dummy')
@@ -750,29 +1064,69 @@ class CrystalField(object):
         return hasattr(self._temperature, '__len__')
 
 
+class CrystalFieldSite(object):
+    """
+    A helper class for the multi-site algebra. It is a result of the '*' operation between a CrystalField
+    and a number. Multiplication sets the abundance for the site and which the returned object holds.
+    """
+    def __init__(self, crystalField, abundance):
+        self.crystalField = crystalField
+        self.abundance = abundance
+
+    def __add__(self, other):
+        if isinstance(other, CrystalField):
+            return CrystalFieldMulti(self, CrystalFieldSite(other, 1))
+        elif isinstance(other, CrystalFieldSite):
+            return CrystalFieldMulti(self, other)
+        elif isinstance(other, CrystalFieldMulti):
+            return other.__radd__(self)
+        raise TypeError('Unsupported operand type(s) for +: CrystalFieldSite and %s' % other.__class__.__name__)
+
+
 class CrystalFieldMulti(object):
     """CrystalFieldMulti represents crystal field of multiple ions."""
 
     def __init__(self, *args):
-        if isinstance(args, tuple):
-            self.args = args
-        else:
-            self.args = (self.args,)
+        self.sites = []
+        self.abundances = []
+        for arg in args:
+            if isinstance(arg, CrystalField):
+                self.sites.append(arg)
+                self.abundances.append(1.0)
+            elif isinstance(arg, CrystalFieldSite):
+                self.sites.append(arg.crystalField)
+                self.abundances.append(arg.abundance)
+            else:
+                raise RuntimeError('Cannot include an object of type %s into a CrystalFieldMulti' % type(arg))
         self._ties = {}
 
     def makeSpectrumFunction(self):
-        fun = ';'.join([a.makeSpectrumFunction() for a in self.args])
+        fun = ';'.join([a.makeSpectrumFunction() for a in self.sites])
+        fun += self._makeIntensityScalingTies()
+        ties = self.getTies()
+        if len(ties) > 0:
+            fun += ';ties=(%s)' % ties
+        return 'composite=CompositeFunction,NumDeriv=1;' + fun
+
+    def makePhysicalPropertiesFunction(self):
+        # Handles relative intensities. Scaling factors here a fixed attributes not
+        # variable parameters and we require the sum to be unity.
+        factors = np.array(self.abundances)
+        sum_factors = np.sum(factors)
+        factstr = [',ScaleFactor=%s' % (str(factors[i] / sum_factors)) for i in range(len(self.sites))]
+        fun = ';'.join([a.makePhysicalPropertiesFunction()+factstr[i] for a,i in enumerate(self.sites)])
         ties = self.getTies()
         if len(ties) > 0:
-            fun += ',ties=(%s)' % ties
+            fun += ';ties=(%s)' % ties
         return fun
 
     def makeMultiSpectrumFunction(self):
-        fun = ';'.join([a.makeMultiSpectrumFunction() for a in self.args])
+        fun = ';'.join([a.makeMultiSpectrumFunction() for a in self.sites])
+        fun += self._makeIntensityScalingTiesMulti()
         ties = self.getTies()
         if len(ties) > 0:
-            fun += ',ties=(%s)' % ties
-        return fun
+            fun += ';ties=(%s)' % ties
+        return 'composite=CompositeFunction,NumDeriv=1;' + fun
 
     def ties(self, **kwargs):
         """Set ties on the parameters."""
@@ -784,50 +1138,140 @@ class CrystalFieldMulti(object):
         return ','.join(ties)
 
     def getSpectrum(self, i=0, workspace=None, ws_index=0):
+        largest_abundance= max(self.abundances)
         if workspace is not None:
-            xArray, yArray = self.args[0].getSpectrum(i, workspace, ws_index)
-            for arg in self.args[1:]:
+            xArray, yArray = self.sites[0].getSpectrum(i, workspace, ws_index)
+            yArray *= self.abundances[0] / largest_abundance
+            ia = 1
+            for arg in self.sites[1:]:
                 _, yyArray = arg.getSpectrum(i, workspace, ws_index)
-                yArray += yyArray
+                yArray += yyArray * self.abundances[ia] / largest_abundance
+                ia += 1
             return xArray, yArray
         x_min = 0.0
         x_max = 0.0
-        for arg in self.args:
+        for arg in self.sites:
             xmin, xmax = arg.calc_xmin_xmax(i)
             if xmin < x_min:
                 x_min = xmin
             if xmax > x_max:
                 x_max = xmax
         xArray = np.linspace(x_min, x_max, CrystalField.default_spectrum_size)
-        _, yArray = self.args[0].getSpectrum(i, xArray, ws_index)
-        for arg in self.args[1:]:
+        _, yArray = self.sites[0].getSpectrum(i, xArray, ws_index)
+        yArray *= self.abundances[0] / largest_abundance
+        ia = 1
+        for arg in self.sites[1:]:
             _, yyArray = arg.getSpectrum(i, xArray, ws_index)
-            yArray += yyArray
+            yArray += yyArray * self.abundances[ia] / largest_abundance
+            ia += 1
         return xArray, yArray
 
     def update(self, func):
         nFunc = func.nFunctions()
-        assert nFunc == len(self.args)
+        assert nFunc == len(self.sites)
         for i in range(nFunc):
-            self.args[i].update(func[i])
+            self.sites[i].update(func[i])
 
     def update_multi(self, func):
         nFunc = func.nFunctions()
-        assert nFunc == len(self.args)
+        assert nFunc == len(self.sites)
         for i in range(nFunc):
-            self.args[i].update_multi(func[i])
+            self.sites[i].update_multi(func[i])
+
+    def _makeIntensityScalingTies(self):
+        """
+        Make a tie string that ties IntensityScaling's of the sites according to their abundances.
+        """
+        n_sites = len(self.sites)
+        if n_sites < 2:
+            return ''
+        factors = np.array(self.abundances)
+        i_largest = np.argmax(factors)
+        largest_factor = factors[i_largest]
+        tie_template = 'f%s.IntensityScaling=%s*' + 'f%s.IntensityScaling' % i_largest
+        ties = []
+        for i in range(n_sites):
+            if i != i_largest:
+                ties.append(tie_template % (i, factors[i] / largest_factor))
+        s = ';ties=(%s)' % ','.join(ties)
+        return s
+
+    def _makeIntensityScalingTiesMulti(self):
+        """
+        Make a tie string that ties IntensityScaling's of the sites according to their abundances.
+        """
+        n_sites = len(self.sites)
+        if n_sites < 2:
+            return ''
+        factors = np.array(self.abundances)
+        i_largest = np.argmax(factors)
+        largest_factor = factors[i_largest]
+        tie_template = 'f{1}.IntensityScaling{0}={2}*f%s.IntensityScaling{0}' % i_largest
+        ties = []
+        n_spectra = self.sites[0].NumberOfSpectra
+        for spec in range(n_spectra):
+            for i in range(n_sites):
+                if i != i_largest:
+                    ties.append(tie_template.format(spec, i, factors[i] / largest_factor))
+        s = ';ties=(%s)' % ','.join(ties)
+        return s
+
+    @property
+    def isPhysicalPropertyOnly(self):
+        return all([a.isPhysicalPropertyOnly for a in self.sites])
+
+    @property
+    def PhysicalProperty(self):
+        return [a.PhysicalProperty for a in self.sites]
+
+    @PhysicalProperty.setter
+    def PhysicalProperty(self, value):
+        for a in self.sites:
+            a.PhysicalProperty = value
 
     def __add__(self, other):
         if isinstance(other, CrystalFieldMulti):
-            return CrystalFieldMulti(*(self.args + other.args))
+            cfm = CrystalFieldMulti()
+            cfm.sites += self.sites + other.sites
+            cfm.abundances += self.abundances + other.abundances
+            return cfm
+        elif isinstance(other, CrystalField):
+            cfm = CrystalFieldMulti()
+            cfm.sites += self.sites + [other]
+            cfm.abundances += self.abundances + [1]
+            return cfm
+        elif isinstance(other, CrystalFieldSite):
+            cfm = CrystalFieldMulti()
+            cfm.sites += self.sites + [other.crystalField]
+            cfm.abundances += self.abundances + [other.abundance]
+            return cfm
         else:
-            return CrystalFieldMulti(*(self.args.append(other.args)))
+            raise TypeError('Cannot add %s to CrystalFieldMulti' % other.__class__.__name__)
+
+    def __radd__(self, other):
+        if isinstance(other, CrystalFieldMulti):
+            cfm = CrystalFieldMulti()
+            cfm.sites += other.sites + self.sites
+            cfm.abundances += other.abundances + self.abundances
+            return cfm
+        elif isinstance(other, CrystalField):
+            cfm = CrystalFieldMulti()
+            cfm.sites += [other] + self.sites
+            cfm.abundances += [1] + self.abundances
+            return cfm
+        elif isinstance(other, CrystalFieldSite):
+            cfm = CrystalFieldMulti()
+            cfm.sites += [other.crystalField] + self.sites
+            cfm.abundances += [other.abundance] + self.abundances
+            return cfm
+        else:
+            raise TypeError('Cannot add %s to CrystalFieldMulti' % other.__class__.__name__)
 
     def __len__(self):
-        return len(self.args)
+        return len(self.sites)
 
     def __getitem__(self, item):
-        return self.args[item]
+        return self.sites[item]
 
 
 #pylint: disable=too-few-public-methods
@@ -845,6 +1289,8 @@ class CrystalFieldFit(object):
         self._input_workspace = InputWorkspace
         self._output_workspace_base_name = 'fit'
         self._fit_properties = kwargs
+        self._function = None
+        self._estimated_parameters = None
 
     def fit(self):
         """
@@ -855,12 +1301,110 @@ class CrystalFieldFit(object):
         else:
             return self._fit_single()
 
+    def monte_carlo(self, **kwargs):
+        fix_all_peaks = self.model.FixAllPeaks
+        self.model.FixAllPeaks = True
+        if isinstance(self._input_workspace, list):
+            self._monte_carlo_multi(**kwargs)
+        else:
+            self._monte_carlo_single(**kwargs)
+        self.model.FixAllPeaks = fix_all_peaks
+
+    def estimate_parameters(self, EnergySplitting, Parameters, **kwargs):
+        from CrystalField.normalisation import split2range
+        from mantid.api import mtd
+        ranges = split2range(Ion=self.model.Ion, EnergySplitting=EnergySplitting,
+                             Parameters=Parameters)
+        constraints = [('%s<%s<%s' % (-bound, parName, bound)) for parName, bound in ranges.items()]
+        self.model.constraints(*constraints)
+        if 'Type' not in kwargs or kwargs['Type'] == 'Monte Carlo':
+            if 'OutputWorkspace' in kwargs and kwargs['OutputWorkspace'].strip() != '':
+                output_workspace = kwargs['OutputWorkspace']
+            else:
+                output_workspace = 'estimated_parameters'
+                kwargs['OutputWorkspace'] = output_workspace
+        else:
+            output_workspace = None
+        self.monte_carlo(**kwargs)
+        if output_workspace is not None:
+            self._estimated_parameters = mtd[output_workspace]
+
+    def get_number_estimates(self):
+        """
+        Get a number of parameter sets estimated with self.estimate_parameters().
+        """
+        if self._estimated_parameters is None:
+            return 0
+        else:
+            return self._estimated_parameters.columnCount() - 1
+
+    def select_estimated_parameters(self, index):
+        ne = self.get_number_estimates()
+        if ne == 0:
+            raise RuntimeError('There are no estimated parameters.')
+        if index >= ne:
+            raise RuntimeError('There are only %s sets of estimated parameters, requested set #%s' % (ne, index))
+        for row in range(self._estimated_parameters.rowCount()):
+            name = self._estimated_parameters.cell(row, 0)
+            value = self._estimated_parameters.cell(row, index)
+            self.model[name] = value
+            if self._function is not None:
+                self._function.setParameter(name, value)
+
+    def _monte_carlo_single(self, **kwargs):
+        """
+        Call EstimateFitParameters algorithm in a single spectrum case.
+        Args:
+            **kwargs: Properties of the algorithm.
+        """
+        from mantid.api import AlgorithmManager
+        fun = self.model.makeSpectrumFunction()
+        alg = AlgorithmManager.createUnmanaged('EstimateFitParameters')
+        alg.initialize()
+        alg.setProperty('Function', fun)
+        alg.setProperty('InputWorkspace', self._input_workspace)
+        for param in kwargs:
+            alg.setProperty(param, kwargs[param])
+        alg.execute()
+        function = alg.getProperty('Function').value
+        self.model.update(function)
+        self._function = function
+
+    def _monte_carlo_multi(self, **kwargs):
+        """
+        Call EstimateFitParameters algorithm in a multi-spectrum case.
+        Args:
+            **kwargs: Properties of the algorithm.
+        """
+        from mantid.api import AlgorithmManager
+        fun = self.model.makeMultiSpectrumFunction()
+        alg = AlgorithmManager.createUnmanaged('EstimateFitParameters')
+        alg.initialize()
+        alg.setProperty('Function', fun)
+        alg.setProperty('InputWorkspace', self._input_workspace[0])
+        i = 1
+        for workspace in self._input_workspace[1:]:
+            alg.setProperty('InputWorkspace_%s' % i, workspace)
+            i += 1
+        for param in kwargs:
+            alg.setProperty(param, kwargs[param])
+        alg.execute()
+        function = alg.getProperty('Function').value
+        self.model.update_multi(function)
+        self._function = function
+
     def _fit_single(self):
         """
         Fit when the model has a single spectrum.
         """
         from mantid.api import AlgorithmManager
-        fun = self.model.makeSpectrumFunction()
+        if self._function is None:
+            if self.model.isPhysicalPropertyOnly:
+                fun = self.model.makePhysicalPropertiesFunction()
+            else:
+                fun = self.model.makeSpectrumFunction()
+        else:
+            fun = str(self._function)
         alg = AlgorithmManager.createUnmanaged('Fit')
         alg.initialize()
         alg.setProperty('Function', fun)
diff --git a/scripts/Inelastic/CrystalField/function.py b/scripts/Inelastic/CrystalField/function.py
index 99c75b53db26ecc5e13397341844956f44bd5d11..76416e79fccbd1eca548b96f9c57a9c6403b2f9c 100644
--- a/scripts/Inelastic/CrystalField/function.py
+++ b/scripts/Inelastic/CrystalField/function.py
@@ -1,5 +1,6 @@
 from __future__ import (absolute_import, division, print_function)
 import re
+from six import string_types
 
 parNamePattern = re.compile(r'([a-zA-Z][\w.]+)')
 
@@ -591,3 +592,212 @@ class ResolutionModel:
             y = self._mergeArrays(y, yy)
             n = len(x)
         return x, y
+
+
+class PhysicalProperties(object):
+    """
+    Contains information about measurement conditions of physical properties
+    """
+    def _str2id(self, typeid):
+        mappings = [['cp', 'cv', 'heatcap'], ['chi', 'susc'], ['mag', 'm(h)'], ['mom', 'm(t)']]
+        for id in range(4):
+            if any([typeid.lower() in elem for elem in mappings[id]]):
+                return id + 1
+        return 0
+
+    def __init__(self, typeid, *args, **kwargs):
+        """
+        Initialize physical properties environment.
+
+        :param typeid: a flag or string (case insensitive) indicating the type of physical properties.
+                       "Cp" or "Cv" or "HeatCap*" or 1: Data is heat capacity in J/mol/K
+                       "chi" or "susc*" or 2: Data is magnetic susceptibility
+                       "mag*" or "M(H)" or 3: Data is magnetisation vs field
+                       "mom*" or "M(T)" or 4: Data is magnetic moment vs temperature
+        :param hdir: the direction of the applied magnetic field for susceptibiliy or M(T) measurements
+        :param hmag: the magnitude in Tesla of the magnetic field for M(T)
+        :param temperature: the temperature in Kelvin of measurements of M(H)
+        :param inverse: a boolean indicating whether susceptibility is chi or 1/chi or M(T) or 1/M(T)
+        :param unit: the unit the data was measured in. Either: 'bohr', 'SI' or 'cgs'.
+
+        typeid is required in all cases, and all other parameters may be specified as keyword arguments.
+        otherwise the syntax is:
+
+        PhysicalProperties('Cp')  # No further parameters required for heat capacity
+        PhysicalProperties('chi', hdir, inverse, unit)
+        PhysicalProperties('chi', unit)
+        PhysicalProperties('mag', hdir, temp, unit)
+        PhysicalProperties('mag', unit)
+        PhysicalProperties('M(T)', hmag, hdir, inverse, unit)
+        PhysicalProperties('M(T)', unit)
+
+        Defaults are: hdir=[0, 0, 1]; hmag=1; temp=1; inverse=False; unit='cgs'.
+        """
+        self._physpropUnit = 'cgs'
+        self._suscInverseFlag = False
+        self._hdir = [0., 0., 1.]
+        self._hmag = 1.
+        self._physpropTemperature = 1.
+        self._typeid = self._str2id(typeid) if isinstance(typeid, string_types) else int(typeid)
+        try:
+            initialiser = getattr(self, 'init' + str(self._typeid))
+        except AttributeError:
+            raise ValueError('Physical property type %s not recognised' % (str(typeid)))
+        initialiser(*args, **kwargs)
+
+    def _checkmagunits(self, unit, default=None):
+        """ Checks that unit string is valid and converts to correct case. """
+        if 'cgs' in unit.lower():
+            return 'cgs'
+        elif 'bohr' in unit.lower():
+            return 'bohr'
+        elif 'SI' in unit.upper():
+            return 'SI'
+        elif default is not None:
+            return default
+        else:
+            raise ValueError('Unit %s not recognised' % (unit))
+
+    def _checkhdir(self, hdir):
+        import numpy as np
+        try:
+            if isinstance(hdir, string_types):
+                if 'powder' in hdir.lower():
+                    return 'powder'
+                else:
+                    raise TypeError()
+            else:
+                hdir = np.array(hdir)
+                if len(hdir) != 3:
+                    raise TypeError()
+                hdir * hdir  # Catches most cases where elements not numeric...
+        except TypeError:
+            raise ValueError('Magnetic field direction %s not recognised' % (str(self._hdir)))
+        return hdir
+
+    @property
+    def TypeID(self):
+        return self._typeid
+
+    @property
+    def Unit(self):
+        return self._physpropUnit
+
+    @Unit.setter
+    def Unit(self, value):
+        self._physpropUnit = self._checkmagunits(value)
+
+    @property
+    def Inverse(self):
+        return self._suscInverseFlag if (self._typeid == 2 or self._typeid == 4) else None
+
+    @Inverse.setter
+    def Inverse(self, value):
+        if (self._typeid == 2 or self._typeid == 4):
+            if isinstance(value, string_types):
+                self._suscInverseFlag = value.lower() in ['true', 't', '1', 'yes', 'y']
+            else:
+                self._suscInverseFlag = bool(value)  # In some cases will always be true...
+        else:
+            raise NameError('This physical properties does not support the Inverse attribute')
+
+    @property
+    def Hdir(self):
+        return self._hdir if (self._typeid > 1) else None
+
+    @Hdir.setter
+    def Hdir(self, value):
+        if (self._typeid > 1):
+            self._hdir = self._checkhdir(value)
+
+    @property
+    def Hmag(self):
+        return self._hmag if (self._typeid == 4) else None
+
+    @Hmag.setter
+    def Hmag(self, value):
+        if (self._typeid == 4):
+            self._hmag = float(value)
+
+    @property
+    def Temperature(self):
+        return self._physpropTemperature if (self._typeid == 3) else None
+
+    @Temperature.setter
+    def Temperature(self, value):
+        if (self._typeid == 3):
+            self._physpropTemperature = float(value)
+
+    def init1(self, *args, **kwargs):
+        """ Initialises environment for heat capacity data """
+        if len(args) > 0:
+            raise ValueError('No environment arguments should be specified for heat capacity')
+
+    def _parseargs(self, mapping, *args, **kwargs):
+        args = [_f for _f in list(args) if _f]
+        # Handles special case of first argument being a unit type
+        if len(args) > 0:
+            try:
+                if self._checkmagunits(args[0], 'bad') is not 'bad':
+                    kwargs['Unit'] = args.pop(0)
+            except AttributeError:
+                pass
+        for i in range(len(mapping)):
+            if len(args) > i:
+                try:
+                    setattr(self, mapping[i], args[i])
+                except:
+                    raise RuntimeError('%s:%s' % (str(mapping[i]), str(args[i])))
+            elif mapping[i] in kwargs.keys():
+                try:
+                    setattr(self, mapping[i], kwargs[mapping[i]])
+                except:
+                    raise RuntimeError('%s:%s' % (str(mapping[i]), str(kwargs[mapping[i]])))
+
+    def init2(self, *args, **kwargs):
+        """ Initialises environment for susceptibility data """
+        mapping = ['Hdir', 'Inverse', 'Unit']
+        self._parseargs(mapping, *args, **kwargs)
+
+    def init3(self, *args, **kwargs):
+        """ Initialises environment for M(H) data """
+        mapping = ['Hdir', 'Temperature', 'Unit']
+        self._parseargs(mapping, *args, **kwargs)
+
+    def init4(self, *args, **kwargs):
+        """ Initialises environment for M(T) data """
+        mapping = ['Hmag', 'Hdir', 'Inverse', 'Unit']
+        self._parseargs(mapping, *args, **kwargs)
+
+    def toString(self):
+        """Create function initialisation string"""
+        types = ['CrystalFieldHeatCapacity', 'CrystalFieldSusceptibility',
+                 'CrystalFieldMagnetisation', 'CrystalFieldMoment']
+        out = 'name=%s' % (types[self._typeid - 1])
+        if self._typeid > 1:
+            out += ',Unit=%s' % (self._physpropUnit)
+            if 'powder' in self._hdir:
+                out += ',powder=1'
+            else:
+                out += ',Hdir=(%s)' % (','.join([str(hh) for hh in self._hdir]))
+            if self._typeid == 3:  # magnetisation M(H)
+                out += ',Temperature=%s' % (self._physpropTemperature)
+            else:            # either susceptibility or M(T)
+                out += ',inverse=%s' % (1 if self._suscInverseFlag else 0)
+                out += (',Hmag=%s' % (self._hmag)) if self._typeid==3 else ''
+        return out
+
+    def envString(self, dataset=0):
+        """Create environment string for multidataset fitting"""
+        dataset = str(dataset)
+        out = ''
+        if self._typeid > 1:
+            out += 'Unit%s=%s' % (dataset, self._physpropUnit)
+            if 'powder' in self._hdir:
+                out += ',powder%s=1' % (dataset)
+            else:
+                out += ',Hdir%s=(%s)' % (dataset, ','.join([str(hh) for hh in self._hdir]))
+            if self._typeid != 3:  # either susceptibility or M(T)
+                out += ',inverse%s=%s' % (dataset, 1 if self._suscInverseFlag else 0)
+                out += (',Hmag%s=%s' % (dataset, self._hmag)) if self._typeid==3 else ''
+        return out
diff --git a/scripts/Inelastic/CrystalField/normalisation.py b/scripts/Inelastic/CrystalField/normalisation.py
new file mode 100644
index 0000000000000000000000000000000000000000..e56dbe5b8602348796787f65ac1df8fca7b13cce
--- /dev/null
+++ b/scripts/Inelastic/CrystalField/normalisation.py
@@ -0,0 +1,214 @@
+from __future__ import (absolute_import, division, print_function)
+import numpy as np
+from CrystalField.energies import energies as CFEnergy
+from six import iteritems
+
+
+def _get_normalisation(nre, bnames):
+    """ Helper function to calculate the normalisation factor.
+        Defined as: ||Blm|| = sum_{Jz,Jz'} |<Jz|Blm|Jz'>|^2 / (2J+1)
+    """
+    J = [0, 5./2, 4, 9./2, 4, 5./2, 0, 7./2, 6, 15./2, 8, 15./2, 6, 7./2]
+    retval = {}
+    for bname in bnames:
+        bdict = {bname: 1}
+        ee, vv, ham = CFEnergy(nre, **bdict)
+        Omat = np.mat(ham)
+        norm = np.trace(np.real(Omat * np.conj(Omat))) / (2*J[nre]+1)
+        retval[bname] = np.sqrt(np.abs(norm)) * np.sign(norm)
+    return retval
+
+
+def _parse_args(**kwargs):
+    """ Parses input arguments for stev2norm() and norm2stev().
+    """
+    # Some definitions
+    Blms = ['B20', 'B21', 'B22', 'B40', 'B41', 'B42', 'B43', 'B44', 'B60', 'B61', 'B62', 'B63', 'B64', 'B65', 'B66']
+    Ions = ['Ce', 'Pr', 'Nd', 'Pm', 'Sm', 'Eu', 'Gd', 'Tb', 'Dy', 'Ho', 'Er', 'Tm', 'Yb']
+    # Some Error checking
+    if 'Ion' not in kwargs.keys() and 'IonNum' not in kwargs.keys():
+        raise NameError('You must specify the ion using either the ''Ion'', ''IonNum'' keywords')
+    if 'Ion' in kwargs.keys():
+        nre = [id for id, val in enumerate(Ions) if val == kwargs['Ion']][0] + 1
+    else:
+        nre = kwargs['IonNum']
+    # Now parses the list of input crystal field parameters
+    par_names = []
+    Blm = {}
+    for pname in Blms:
+        if pname in kwargs.keys():
+            par_names.append(pname)
+            Blm[pname] = kwargs[pname]
+    if not par_names:
+        if 'B' in kwargs.keys():
+            for ind, pname in enumerate(Blms):
+                par_names.append(pname)
+                Blm[pname] = kwargs['B'][ind]
+        else:
+            raise NameError('You must specify at least one input Blm parameter')
+    return nre, par_names, Blm
+
+
+def stev2norm(**kwargs):
+    """ Calculates the "normalised" crystal field parameters of P. Fabi
+        These parameters are defined in the appendix of the FOCUS program manual,
+        http://purl.org/net/epubs/manifestation/5723 page 59.
+
+        nlm = stev2norm(Ion=ionname, B=bvec)
+        nlm = stev2norm(Ion=ionname, B20=b20val, ...)
+        nlm = stev2norm(IonNum=ionnumber, B20=b20val, ...)
+        [B20, B40] = stev2norm(IonNum=ionnumber, B20=b20val, B40=b40val, OutputTuple=True)
+
+        Note: This function only accepts keyword inputs.
+
+        Inputs:
+            ionname - name of the (tripositive) rare earth ion, e.g. 'Ce', 'Pr'.
+            ionnumber - the number index of the rare earth ion:
+                   1=Ce 2=Pr 3=Nd 4=Pm 5=Sm 6=Eu 7=Gd 8=Tb 9=Dy 10=Ho 11=Er 12=Tm 13=Yb
+            bvec - a vector of the Stevens CF parameters in order: [B20 B21 B22 B40 B41 ... etc.]
+                    This vector can also a be dictionary instead {'B20':1, 'B40':2}
+            b20val etc. - values of the Stevens CF parameters to be converted
+
+        Outputs:
+            nlm - a dictionary of the normalised crystal field parameters (default)
+            [B20, etc] - a tuple of the normalised crystal field parameters (need to set OutputTuple flag)
+
+        Note: one of the keywords: Ion and IonNum must be specified.
+
+    """
+    # Parses the input parameters
+    nre, par_names, Blm = _parse_args(**kwargs)
+    # Gets the normalisation constants
+    norm = _get_normalisation(nre, par_names)
+    # Calculates the normalised parameters.
+    Nlm = {}
+    for pname in par_names:
+        Nlm[pname] = Blm[pname] * norm[pname]
+
+    return Nlm
+
+
+def norm2stev(**kwargs):
+    """ Calculates the Stevens (conventional) crystal field parameters from "normalised" parameters
+        The normalised parameters of P. Fabi are defined in the appendix of the FOCUS program manual,
+        http://purl.org/net/epubs/manifestation/5723 page 59.
+
+        nlm = norm2stev(Ion=ionname, B=bvec)
+        nlm = norm2stev(Ion=ionname, B20=b20val, ...)
+        nlm = norm2stev(IonNum=ionnumber, B20=b20val, ...)
+        [B20, B40] = norm2stev(IonNum=ionnumber, B20=b20val, B40=b40val, OutputTuple=True)
+
+        Note: This function only accepts keyword inputs.
+
+        Inputs:
+            ionname - name of the (tripositive) rare earth ion, e.g. 'Ce', 'Pr'.
+            ionnumber - the number index of the rare earth ion:
+                   1=Ce 2=Pr 3=Nd 4=Pm 5=Sm 6=Eu 7=Gd 8=Tb 9=Dy 10=Ho 11=Er 12=Tm 13=Yb
+            bvec - a vector of the Stevens CF parameters in order: [B20 B21 B22 B40 B41 ... etc.]
+                    This vector can also a be dictionary instead {'B20':1, 'B40':2}
+            b20val etc. - values of the Stevens CF parameters to be converted
+
+        Outputs:
+            nlm - a dictionary of the normalised crystal field parameters (default)
+            [B20, etc] - a tuple of the normalised crystal field parameters (need to set OutputTuple flag)
+
+        Note: one of the keywords: Ion and IonNum must be specified.
+
+    """
+    # Parses the input parameters
+    nre, par_names, Blm = _parse_args(**kwargs)
+    # Gets the normalisation constants
+    norm = _get_normalisation(nre, par_names)
+    # Calculates the normalised parameters.
+    Nlm = {}
+    for pname in par_names:
+        Nlm[pname] = 0 if norm[pname] == 0 else Blm[pname] / norm[pname]
+
+    return Nlm
+
+
+def split2range(*args, **kwargs):
+    """ Calculates the ranges of (Stevens) crystal field parameters to give energy splittings
+        around a specified a desired energy splitting
+
+        ranges = split2range(ionname, energy_splitting, bnames)
+        ranges = split2range(Ion=ionname, EnergySplitting=energy_splitting, Parameters=bnames)
+        ranges = split2range(IonNum=ionnumber, EnergySplitting=energy_splitting, Parameters=bnames)
+        ranges = split2range(PointGroup=point_group, EnergySplitting=energy_splitting, 'B20', 'B22', ...)
+        ranges = split2range(PointGroup=point_group, EnergySplitting=energy_splitting, B20=_, B22=_, ...)
+        ranges = split2range(..., Output='dictionary')
+        constraint_string = split2range(..., Output='constraints')
+
+        Inputs:
+            ionname - name of the (tripositive) rare earth ion, e.g. 'Ce', 'Pr'.
+            ionnumber - the number index of the rare earth ion:
+                1=Ce 2=Pr 3=Nd 4=Pm 5=Sm 6=Eu 7=Gd 8=Tb 9=Dy 10=Ho 11=Er 12=Tm 13=Yb
+            energy_splitting - the desired energy splitting (difference between the energies of the
+                highest and lowest crystal field energy levels) in meV
+            bnames - a list of names of the crystal field parameters to give the range for
+            'B20', etc - the names of the parameters can be given as individual arguments or
+                keyword arguments. In the case of keyword arguments, only the key names will be used
+
+        Output:
+            ranges - a dictionary of the ranges such that sampling uniformly in |Blm|<range[bnames]
+                will produce crystal field splittings distributed normally around the input
+                energy_splitting.
+            constraint_string - a string of the form '-[range]<Blm<[range]' where [range] is the
+                calculated range for that parameter.
+            By default, the Output keyword is set to "dictionary".
+
+        Note: ionname or ionnumber must be specified.
+    """
+    argin = {}
+    argnames = ['Ion', 'EnergySplitting', 'Parameters', 'Output', 'IonNum']
+    # Set default values.
+    argin['Output'] = 'dictionary'
+    argin['Parameters'] = []
+    # Parses the non-keyword arguments
+    for ia in range(3 if len(args)>3 else len(args)):
+        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'):
+            argin['Parameters'].append(args[ia])
+    # Parses the keyword arguments
+    for key, value in iteritems(kwargs):
+        for ia in range(len(argnames)):
+            if key == argnames[ia]:
+                argin[key] = value
+                break
+        if key.startswith('B'):
+            argin['Parameters'].append(key)
+
+    # Error checking
+    if 'Ion' not in argin.keys() and 'IonNum' not in argin.keys():
+        raise NameError('You must specify the ion using either the ''Ion'', ''IonNum'' keywords')
+    Ions = ['Ce', 'Pr', 'Nd', 'Pm', 'Sm', 'Eu', 'Gd', 'Tb', 'Dy', 'Ho', 'Er', 'Tm', 'Yb']
+    if 'Ion' in argin.keys():
+        nre = [ id for id,val in enumerate(Ions) if val==kwargs['Ion'] ][0] + 1
+    else:
+        nre = argin['IonNum']
+    if 'EnergySplitting' not in argin.keys():
+        raise NameError('You must specify the desired energy splitting')
+    if not argin['Parameters']:
+        raise NameError('You must specify at least one crystal field parameter name')
+
+    Nlm = {}
+    for bname in set(argin['Parameters']):
+        Nlm[bname] = 1
+    Blm = norm2stev(IonNum=nre, **Nlm)
+    ee, vv, ham = CFEnergy(nre, **Blm)
+    # Factor of 2 is needed to get the Gaussian centred on the desired energy splitting.
+    splitting_factor = 2 * argin['EnergySplitting'] / (np.max(ee-np.min(ee)))
+    Nlm = {}
+    for bname in Blm.keys():
+        Nlm[bname] = splitting_factor
+    ranges = norm2stev(IonNum=nre, **Nlm)
+
+    if argin['Output'].lower() is 'constraints':
+        constr = ''
+        for bname in ranges.keys():
+            constr += '%.4g<%s<%.4g,' % (-ranges[bname], bname, ranges[bname])
+        return constr[:-1]
+    else:
+        return ranges
diff --git a/scripts/Inelastic/Direct/DirectEnergyConversion.py b/scripts/Inelastic/Direct/DirectEnergyConversion.py
index 9b57909c4356de2bdff8efb95c1136eb63303591..086b7c306a7c933c4fe140cd4aa48ad92103645d 100644
--- a/scripts/Inelastic/Direct/DirectEnergyConversion.py
+++ b/scripts/Inelastic/Direct/DirectEnergyConversion.py
@@ -279,7 +279,7 @@ class DirectEnergyConversion(object):
                 bin_size = 2*(bkgd_range[1]-bkgd_range[0])
                 background_int = Rebin(result_ws,
                                        Params=[bkgd_range[0],bin_size,bkgd_range[1]],
-                                       PreserveEvents=False,FullBinsOnly=False)
+                                       PreserveEvents=False,FullBinsOnly=False, IgnoreBinErrors=True)
                 total_counts = Integration(result_ws, IncludePartialBins=True)
                 background_int = ConvertUnits(background_int, Target="Energy",EMode='Elastic', AlignBins=0)
                 self.prop_man.log("Diagnose: finished convertUnits ",'information')
@@ -888,7 +888,7 @@ class DirectEnergyConversion(object):
         """
         Mask and group detectors based on input parameters
         """
-        ws_name = result_ws.getName()
+        ws_name = result_ws.name()
         if spec_masks is not None:
             MaskDetectors(Workspace=ws_name, MaskedWorkspace=spec_masks)
         if map_file is not None:
@@ -954,7 +954,7 @@ class DirectEnergyConversion(object):
 
         if not mon_ws: # no monitors
             if self.__in_white_normalization: # we can normalize wb integrals by current separately as they often do not
-                                             # have monitors
+#have monitors
                 self.normalise(run,'current',range_offset)
                 ws = run.get_workspace()
                 new_name = ws.name()
@@ -966,10 +966,9 @@ class DirectEnergyConversion(object):
 
         int_range = self.norm_mon_integration_range
         if self._debug_mode:
-            kwargs = {'NormFactorWS':'NormMon1_WS' + data_ws.getName()}
+            kwargs = {'NormFactorWS' : 'NormMon1_WS' + data_ws.name()}
         else:
             kwargs = {}
-
         mon_spect = self.prop_man.mon1_norm_spec
         if separate_monitors:
             kwargs['MonitorWorkspace'] = mon_ws
@@ -1020,7 +1019,7 @@ class DirectEnergyConversion(object):
                                    .format(ws.name(),run.run_number()))
         #
 
-        kwargs = {'NormFactorWS':'NormMon2_WS' + mon_ws.getName()}
+        kwargs = {'NormFactorWS':'NormMon2_WS' + mon_ws.name()}
 
         mon_spect = self.prop_man.mon2_norm_spec
         mon_index = int(mon_ws.getIndexFromSpectrumNumber(mon_spect))
@@ -1158,7 +1157,7 @@ class DirectEnergyConversion(object):
                               EnergyEstimate=ei_guess,FixEi=fix_ei)
                     mon1_det = monitor_ws.getDetector(mon1_index)
                     mon1_pos = mon1_det.getPos()
-                    src_name = monitor_ws.getInstrument().getSource().getName()
+                    src_name = monitor_ws.getInstrument().getSource().name()
                 #pylint: disable=bare-except
                 except:
                     src_name = None
@@ -1232,9 +1231,9 @@ class DirectEnergyConversion(object):
                                   'warning')
                 return
             else:
-                save_file = workspace.getName()
+                save_file = workspace.name()
         elif os.path.isdir(save_file):
-            save_file = os.path.join(save_file, workspace.getName())
+            save_file = os.path.join(save_file, workspace.name())
         elif save_file == '':
             raise ValueError('Empty filename is not allowed for saving')
         else:
@@ -1415,13 +1414,11 @@ class DirectEnergyConversion(object):
         signal = []
         error = []
         izerc = 0
+        data_specInfo = data_ws.spectrumInfo()
         for i in range(nhist):
-            try:
-                det = data_ws.getDetector(i)
-#pylint: disable=broad-except
-            except Exception:
+            if not data_specInfo.hasDetectors(i):
                 continue
-            if det.isMasked():
+            if data_specInfo.isMasked(i):
                 continue
             sig = data_ws.readY(i)[0]
             err = data_ws.readE(i)[0]
@@ -1601,10 +1598,10 @@ class DirectEnergyConversion(object):
             else:
                 self._propMan = PropertyManager(instr)
         else:
-            old_name = self._propMan.instrument.getName()
+            old_name = self._propMan.instrument.name()
 #pylint: disable=protected-access
             if isinstance(instr,geometry._geometry.Instrument):
-                new_name = self._propMan.instrument.getName()
+                new_name = self._propMan.instrument.name()
             elif isinstance(instr,PropertyManager):
                 new_name = instr.instr_name
             else:
@@ -1620,7 +1617,7 @@ class DirectEnergyConversion(object):
     def setup_instrument_properties(self, workspace=None,reload_instrument=False):
         if workspace is not None:
             instrument = workspace.getInstrument()
-            name = instrument.getName()
+            name = instrument.name()
             if name != self.prop_man.instr_name:
                 self.prop_man = PropertyManager(name,workspace)
 
@@ -1698,7 +1695,8 @@ class DirectEnergyConversion(object):
 
         energy_bins = PropertyManager.energy_bins.get_abs_range(self.prop_man)
         if energy_bins:
-            Rebin(InputWorkspace=result_name,OutputWorkspace=result_name,Params= energy_bins,PreserveEvents=False)
+            Rebin(InputWorkspace=result_name,OutputWorkspace=result_name,Params= energy_bins,PreserveEvents=False,
+                  IgnoreBinErrors=True)
             if bkgr_ws:
                 #apply data ws normalization to background workspace
                 data_run.export_normalization(bkgr_ws)
@@ -1748,7 +1746,8 @@ class DirectEnergyConversion(object):
                 ScaleX(InputWorkspace=bkgr_ws,OutputWorkspace='bkgr_ws',Operation="Add",Factor=time_shift,
                        InstrumentParameter="DelayTime",Combine=True)
         else: # calculate background workspace for future usage
-            bkgr_ws = Rebin(result_ws,Params=[bkg_range_min,(bkg_range_max - bkg_range_min) * 1.001,bkg_range_max],PreserveEvents=False)
+            bkgr_ws = Rebin(result_ws,Params=[bkg_range_min,(bkg_range_max - bkg_range_min) * 1.001,bkg_range_max],PreserveEvents=False,
+                            IgnoreBinErrors=True)
             RenameWorkspace(InputWorkspace=bkgr_ws, OutputWorkspace='bkgr_ws_source')
             bkgr_ws = mtd['bkgr_ws_source']
 
@@ -1785,7 +1784,8 @@ class DirectEnergyConversion(object):
         # Make sure that our binning is consistent
         if prop_man.energy_bins:
             bins = PropertyManager.energy_bins.get_abs_range(prop_man)
-            Rebin(InputWorkspace=result_name,OutputWorkspace= result_name,Params=bins)
+            Rebin(InputWorkspace=result_name,OutputWorkspace= result_name,Params=bins,
+                  IgnoreBinErrors=True)
 
         # Masking and grouping
         result_ws = mtd[result_name]
@@ -1861,7 +1861,8 @@ class DirectEnergyConversion(object):
             raise ValueError("White beam integration range is inconsistent. low=%d, upp=%d" % (low,upp))
 
         delta = 2.0 * (upp - low)
-        white_ws = Rebin(InputWorkspace=old_name,OutputWorkspace=old_name, Params=[low, delta, upp])
+        white_ws = Rebin(InputWorkspace=old_name,OutputWorkspace=old_name, Params=[low, delta, upp],
+                         IgnoreBinErrors=True)
         # Why aren't we doing this...-> because integration does not work properly for event workspaces
         #Integration(white_ws, white_ws, RangeLower=low, RangeUpper=upp)
         AddSampleLog(white_ws,LogName = done_Log,LogText=done_log_VAL,LogType='String')
diff --git a/scripts/Inelastic/Direct/RunDescriptor.py b/scripts/Inelastic/Direct/RunDescriptor.py
index ca658dbbcafeb1231e15f76dda728417b17b1945..21b945747c38c2f0706cfc38d3e0bd871a7bc290 100644
--- a/scripts/Inelastic/Direct/RunDescriptor.py
+++ b/scripts/Inelastic/Direct/RunDescriptor.py
@@ -1228,7 +1228,7 @@ class RunDescriptor(PropDescriptor):
         bins = [x_param[0],dx_min,x_param[-1]]
         ExtractSingleSpectrum(InputWorkspace=data_ws,OutputWorkspace='tmp_mon',WorkspaceIndex=ws_index)
         Rebin(InputWorkspace='tmp_mon',OutputWorkspace='tmp_mon',Params=bins,PreserveEvents='0')
-        mon_ws_name = mon_ws.getName()
+        mon_ws_name = mon_ws.name()
         if not homo_binning:
             Rebin(InputWorkspace=mon_ws_name,OutputWorkspace=mon_ws_name,Params=bins,PreserveEvents='0')
         ConjoinWorkspaces(InputWorkspace1=mon_ws_name,InputWorkspace2='tmp_mon')
diff --git a/scripts/Inelastic/Direct/__init__.py b/scripts/Inelastic/Direct/__init__.py
index 26487e011f1089a972e5b837b851fe4ac7923050..9b6fd7146a9c051527ddacfefb934556442ff08f 100644
--- a/scripts/Inelastic/Direct/__init__.py
+++ b/scripts/Inelastic/Direct/__init__.py
@@ -3,7 +3,8 @@
 dgreduce               -- outdated functions, provided for compartibility with old qtiGenie
 DirectEnergyConversion -- main reduction class
 PropertyManager        -- helper class providing access and functionality for IDF properties
-ReductionWrapper       -- parent class for reduction, After overloading for particular insrument provides common interface for Mantid and web services
+ReductionWrapper       -- parent class for reduction, After overloading for particular insrument
+                          provides common interface for Mantid and web services
 RunDescriptor          -- Class descripbing a run and instantiated as property of Property manager to specify a
                           particular kind of run (e.g. sample run, monovan run etc...)
 
diff --git a/scripts/Inelastic/Direct/dgreduce.py b/scripts/Inelastic/Direct/dgreduce.py
index 6627d4c9770e6f1d75117fe16cba47d14845b56f..5ba53a7d27335379242ac63089b5d3e3f950d253 100644
--- a/scripts/Inelastic/Direct/dgreduce.py
+++ b/scripts/Inelastic/Direct/dgreduce.py
@@ -289,7 +289,7 @@ def abs_units(wb_for_run,sample_run,monovan_run,wb_for_monovanadium,samp_rmm,sam
 
     wksp_out = arb_units(wb_for_run,sample_run,ei_guess,rebin,map_file,monovan_run,wb_for_monovanadium,**kwargs)
 
-    if  results_name != wksp_out.getName():
+    if  results_name != wksp_out.name():
         RenameWorkspace(InputWorkspace=wksp_out,OutputWorkspace=results_name)
 
     return wksp_out
diff --git a/scripts/Inelastic/Direct/diagnostics.py b/scripts/Inelastic/Direct/diagnostics.py
index 0916cdd231a60bab54baddc1713c8e8c2ef38b2a..3e8a38ee9ac10c2063f759797ffb804de3c144cc 100644
--- a/scripts/Inelastic/Direct/diagnostics.py
+++ b/scripts/Inelastic/Direct/diagnostics.py
@@ -454,13 +454,11 @@ def get_failed_spectra_list(diag_workspace):
         diag_workspace = mtd[diag_workspace]
 
     failed_spectra = []
+    spectrumInfo = diag_workspace.spectrumInfo()
     for i in range(diag_workspace.getNumberHistograms()):
-        try:
-            det = diag_workspace.getDetector(i)
-        except RuntimeError:
-            continue
-        if det.isMasked():
-            failed_spectra.append(diag_workspace.getSpectrum(i).getSpectrumNo())
+        if spectrumInfo.hasDetectors(i):
+            if spectrumInfo.isMasked(i):
+                failed_spectra.append(diag_workspace.getSpectrum(i).getSpectrumNo())
 
     return failed_spectra
 
diff --git a/scripts/Inelastic/IndirectReductionCommon.py b/scripts/Inelastic/IndirectReductionCommon.py
index df2d844c9712fbb41c84204c6b2bf2277b55d6c0..ef51a0eeb388705661aa8365f0e0680d783de570 100644
--- a/scripts/Inelastic/IndirectReductionCommon.py
+++ b/scripts/Inelastic/IndirectReductionCommon.py
@@ -1,4 +1,3 @@
-#pylint: disable=invalid-name,too-many-branches,too-many-arguments,deprecated-module,no-name-in-module,too-many-locals
 from __future__ import (absolute_import, division, print_function)
 from mantid.api import WorkspaceGroup, AlgorithmManager
 from mantid import mtd, logger, config
@@ -34,11 +33,11 @@ def load_files(data_files, ipf_filename, spec_min, spec_max, sum_files=False, lo
 
     for filename in data_files:
         # The filename without path and extension will be the workspace name
-        ws_name = os.path.splitext(os.path.basename(filename))[0]
+        ws_name = os.path.splitext(os.path.basename(str(filename)))[0]
         logger.debug('Loading file %s as workspace %s' % (filename, ws_name))
 
         if 'VESUVIO' in ipf_filename:
-            evs_filename = os.path.basename(filename).replace('EVS', '')
+            evs_filename = os.path.basename(str(filename)).replace('EVS', '')
             LoadVesuvio(Filename=evs_filename,
                         OutputWorkspace=ws_name,
                         SpectrumList='1-198',
diff --git a/scripts/Interface/reduction_gui/reduction/inelastic/dgs_absolute_units_script.py b/scripts/Interface/reduction_gui/reduction/inelastic/dgs_absolute_units_script.py
index 405c3d7699480d890031f8ee550f01d939859d1f..a2cb686a3b79f8ecaa1ffe086858f844b6ab24af 100644
--- a/scripts/Interface/reduction_gui/reduction/inelastic/dgs_absolute_units_script.py
+++ b/scripts/Interface/reduction_gui/reduction/inelastic/dgs_absolute_units_script.py
@@ -145,7 +145,7 @@ class AbsoluteUnitsScript(BaseScriptElement):
                                                                                   default=AbsoluteUnitsScript.absunits_median_test_out_low)
             self.absunits_median_test_out_high = BaseScriptElement.getFloatElement(instrument_dom,
                                                                                    "median_test_out_high",
-                                                                                   default=AbsoluteUnitsScript.absunits_median_test_out_high)
+                                                                                   default=AbsoluteUnitsScript.absunits_median_test_out_high)# noqa
             self.absunits_median_test_low = BaseScriptElement.getFloatElement(instrument_dom,
                                                                               "median_test_low",
                                                                               default=AbsoluteUnitsScript.absunits_median_test_low)
diff --git a/scripts/Interface/reduction_gui/reduction/inelastic/dgs_reduction_script.py b/scripts/Interface/reduction_gui/reduction/inelastic/dgs_reduction_script.py
index be1813e5d6facd3f873eb8d0ed9908ca4e5b841c..5591e7f647fc7b0bc9a89a6772faa41d33f2e20a 100644
--- a/scripts/Interface/reduction_gui/reduction/inelastic/dgs_reduction_script.py
+++ b/scripts/Interface/reduction_gui/reduction/inelastic/dgs_reduction_script.py
@@ -66,11 +66,14 @@ class DgsReductionScripter(BaseReductionScripter):
 
         filenames=self.filenameParser(data_list)
         if len(filenames)==1:
-            script += "OutputFilename=os.path.join(OutputDirectory,DGS_output_data[0].getInstrument().getName()+str(DGS_output_data[0].getRunNumber())+'.nxs')\n"
+            script += "OutputFilename=os.path.join(OutputDirectory,DGS_output_data[0].getInstrument().getName()"
+            script += "+str(DGS_output_data[0].getRunNumber())+'.nxs')\n"
             script += 'SaveNexus(DGS_output_data[0],OutputFilename)\n'
         else:
             script += "for i in range("+str(len(filenames))+"):\n"
-            script += DgsReductionScripter.WIDTH+"OutputFilename=os.path.join(OutputDirectory,DGS_output_data[0][i].getInstrument().getName()+str(DGS_output_data[0][i].getRunNumber())+'.nxs')\n"
+            script += DgsReductionScripter.WIDTH
+            script +="OutputFilename=os.path.join(OutputDirectory,DGS_output_data[0][i].getInstrument().getName()"
+            script +="+str(DGS_output_data[0][i].getRunNumber())+'.nxs')\n"
             script += DgsReductionScripter.WIDTH+'SaveNexus(DGS_output_data[0][i],OutputFilename)\n'
 
         if file_name is not None:
@@ -162,7 +165,8 @@ class DgsReductionScripter(BaseReductionScripter):
                 out_dir_line='OutputDirectory="%s"\n'%output_dir
             script += out_dir_line
 
-            script +="OutputFilename=os.path.join(OutputDirectory,DGS_output_data[0].getInstrument().getName()+str(DGS_output_data[0].getRunNumber())+'.nxs')\n"
+            script +="OutputFilename=os.path.join(OutputDirectory,DGS_output_data[0].getInstrument().getName()"
+            script +="+str(DGS_output_data[0].getRunNumber())+'.nxs')\n"
             script +="SaveNexus(DGS_output_data[0],OutputFilename)\n"
 
             scripts.append(script)
diff --git a/scripts/Interface/reduction_gui/reduction/sans/hfir_detector_script.py b/scripts/Interface/reduction_gui/reduction/sans/hfir_detector_script.py
index 573be130556bb6b04cbea5e500b8ba144bb2354b..99cb94cf1b2cac5104fce9355e4c317f40160e27 100644
--- a/scripts/Interface/reduction_gui/reduction/sans/hfir_detector_script.py
+++ b/scripts/Interface/reduction_gui/reduction/sans/hfir_detector_script.py
@@ -66,7 +66,8 @@ class Detector(BaseScriptElement):
                 raise RuntimeError("Sensitivity correction was selected but no sensitivity data file was entered.")
 
             if len(str(self.sensitivity_dark).strip())>0:
-                script += "SensitivityCorrection(\"%s\", min_sensitivity=%g, max_sensitivity=%g, dark_current=\"%s\", use_sample_dc=%s)\n" % \
+                script += "SensitivityCorrection(\"%s\", min_sensitivity=%g, "\
+                          "max_sensitivity=%g, dark_current=\"%s\", use_sample_dc=%s)\n" % \
                     (self.sensitivity_data, self.min_sensitivity, self.max_sensitivity, self.sensitivity_dark, self.use_sample_dark)
             else:
                 script += "SensitivityCorrection(\"%s\", min_sensitivity=%g, max_sensitivity=%g, use_sample_dc=%s)\n" % \
diff --git a/scripts/Interface/reduction_gui/widgets/inelastic/dgs_sample_setup.py b/scripts/Interface/reduction_gui/widgets/inelastic/dgs_sample_setup.py
index fc6c562eff5eef37525ba791d1a273d96df32542..94f3b66bda7ec3da4b56b9a6b367a527f4bd533a 100644
--- a/scripts/Interface/reduction_gui/widgets/inelastic/dgs_sample_setup.py
+++ b/scripts/Interface/reduction_gui/widgets/inelastic/dgs_sample_setup.py
@@ -93,7 +93,7 @@ class SampleSetupWidget(BaseWidget):
         self._content.sample_edit = mantidqtpython.MantidQt.MantidWidgets.MWRunFiles()
         # Unfortunately, can only use live if default instrument = gui-set instrument
         if self._instrument_name == config.getInstrument().name():
-            self._content.sample_edit.setProperty("liveButton","ShowIfCanConnect")
+            self._content.sample_edit.setProperty("liveButton","Show")
         self._content.sample_edit.setProperty("multipleFiles",True)
         self._content.sample_edit.setProperty("algorithmAndProperty","Load|Filename")
         self._content.sample_edit.setProperty("label",labeltext)
diff --git a/scripts/Interface/ui/reflectometer/refl_gui.py b/scripts/Interface/ui/reflectometer/refl_gui.py
index 658fa1ce51d6114827b7569bd5f51a9110d9bca2..49a3674fa5a124bff7803ec7f9780af6b8c15c19 100644
--- a/scripts/Interface/ui/reflectometer/refl_gui.py
+++ b/scripts/Interface/ui/reflectometer/refl_gui.py
@@ -1,4 +1,5 @@
-# pylint: disable = too-many-lines, invalid-name, line-too-long, too-many-instance-attributes, too-many-branches,too-many-locals, too-many-nested-blocks
+# pylint: disable = too-many-lines, invalid-name, line-too-long, too-many-instance-attributes,
+# pylint: disable = too-many-branches,too-many-locals, too-many-nested-blocks
 
 try:
     from mantidplot import *
diff --git a/scripts/PearlPowderISIS/pearl_routines.py b/scripts/PearlPowderISIS/pearl_routines.py
index 0e1af82d14aaeb86f33cd32cbc12710d4903f226..5be77fd51fc7c0f32fbb3e998cc88059a00a0b23 100644
--- a/scripts/PearlPowderISIS/pearl_routines.py
+++ b/scripts/PearlPowderISIS/pearl_routines.py
@@ -22,8 +22,7 @@ g_pearl_obj = None
 def _pearl_obj_singleton():
     global g_pearl_obj
     if g_pearl_obj is None:
-        g_pearl_obj = Pearl(user_name="NotSet", calibration_dir="NotSet",
-                            raw_data_dir="NotSet", output_dir="NotSet",
+        g_pearl_obj = Pearl(user_name="NotSet", calibration_dir="NotSet", output_dir="NotSet",
                             input_file_ext=".raw", tt_mode="NotSet")
     return g_pearl_obj
 
@@ -100,7 +99,7 @@ def PEARL_getmonitorspectrum(runno):
 
 def PEARL_getcycle(number):
     pearl_obj = _pearl_obj_singleton()
-    cycle_information = pearl_obj._get_cycle_information(number)
+    cycle_information = pearl_obj._get_label_information(number)
     datadir = pearl_obj.output_dir
     updated_vals = {"cycle"   : cycle_information["cycle"],
                     "instver" : cycle_information["instrument_version"],
@@ -124,15 +123,8 @@ def PEARL_getcalibfiles():
     pearl_obj._old_api_set_tt_mode(g_oldParams["tt_mode"])
     pearl_obj._old_api_set_calib_dir(g_oldParams["pearl_file_dir"])
 
-    cal_dict = pearl_obj._get_calibration_full_paths(cycle=cycle)
     print ("Setting calibration for cycle", cycle)
 
-    updated_vals = {"calfile"     : cal_dict["calibration"],
-                    "groupfile"   : cal_dict["grouping"],
-                    "vabsorbfile" : cal_dict["vanadium_absorption"],
-                    "vanfile"     : cal_dict["vanadium"]}
-
-    _merge_dict_into_global(updated_vals)
     return
 
 
@@ -216,8 +208,9 @@ def PEARL_focus(number, ext="raw", fmode="trans", ttmode="TT70", atten=True, van
 
     pearl_obj = _pearl_obj_singleton()
     pearl_obj._old_api_set_tt_mode(ttmode)
+    pearl_obj._old_api_set_ext(ext)
     pearl_obj.set_debug_mode(debug)
-    return pearl_obj.focus(run_number=number, focus_mode=fmode, input_ext=ext, do_attenuation=atten,
+    return pearl_obj.focus(run_number=number, focus_mode=fmode, do_attenuation=atten,
                            do_van_normalisation=van_norm)
 
 
@@ -227,8 +220,9 @@ def pearl_run_focus(number, ext="raw", fmode="trans", ttmode="TT70", atten=True,
 
     pearl_obj = _pearl_obj_singleton()
     pearl_obj._old_api_set_tt_mode(ttmode)
+    pearl_obj._old_api_set_ext(ext)
     pearl_obj.set_debug_mode(debug)
-    return pearl_obj.focus(run_number=number, focus_mode=fmode, input_ext=ext, do_attenuation=atten,
+    return pearl_obj.focus(run_number=number, focus_mode=fmode, do_attenuation=atten,
                            do_van_normalisation=van_norm)
 
 
diff --git a/scripts/Reflectometry/isis_reflectometry/convert_to_wavelength.py b/scripts/Reflectometry/isis_reflectometry/convert_to_wavelength.py
index 49c1fe6b3e11c1d856175d082ccdffcb9c6b711d..34daedf95302bd29223ad35b49bae7942d99630e 100644
--- a/scripts/Reflectometry/isis_reflectometry/convert_to_wavelength.py
+++ b/scripts/Reflectometry/isis_reflectometry/convert_to_wavelength.py
@@ -166,5 +166,5 @@ class ConvertToWavelength(object):
         if correct_monitor and all((bg_min, bg_max)):
             _monitor_ws = msi.CalculateFlatBackground(InputWorkspace=_monitor_ws,WorkspaceIndexList=0,StartX=bg_min, EndX=bg_max)
 
-        msi.DeleteWorkspace(Workspace=sum_wavelength.getName())
+        msi.DeleteWorkspace(Workspace=sum_wavelength.name())
         return (_monitor_ws, _detector_ws)
diff --git a/scripts/Reflectometry/isis_reflectometry/quick.py b/scripts/Reflectometry/isis_reflectometry/quick.py
index c99fc588e53cae49d5f4eb3c8f50ed62cda02a35..1d02a5df946330fce9cfe36cf9c0eafb099c669b 100644
--- a/scripts/Reflectometry/isis_reflectometry/quick.py
+++ b/scripts/Reflectometry/isis_reflectometry/quick.py
@@ -144,7 +144,7 @@ def quick_explicit(run, i0_monitor_index, lambda_min, lambda_max, background_min
     if run == '0':
         RunNumber = '0'
     else:
-        RunNumber = groupGet(_sample_ws.getName(), 'samp', 'run_number')
+        RunNumber = groupGet(_sample_ws.name(), 'samp', 'run_number')
 
     if not pointdet:
         # Proccess Multi-Detector; assume MD goes to the end:
diff --git a/scripts/SANS/SANSBatchMode.py b/scripts/SANS/SANSBatchMode.py
index 4e95a8ec5e8aaa043d4cac50cc02b23d77657122..9469adcfc03e574acc164c40df9988bcca8d7ffa 100644
--- a/scripts/SANS/SANSBatchMode.py
+++ b/scripts/SANS/SANSBatchMode.py
@@ -140,8 +140,8 @@ def get_transmission_properties(workspace):
     return transmission_properties
 
 
-def BatchReduce(filename, format, plotresults=False, saveAlgs={'SaveRKH':'txt'},verbose=False,  # noqa
-                centreit=False, reducer=None, combineDet=None, save_as_zero_error_free=False):  # noqa
+def BatchReduce(filename, format, plotresults=False, saveAlgs={'SaveRKH':'txt'},verbose=False,
+                centreit=False, reducer=None, combineDet=None, save_as_zero_error_free=False):
     """
         @param filename: the CSV file with the list of runs to analyse
         @param format: type of file to load, nxs for Nexus, etc.
diff --git a/scripts/SANS/SANSUtility.py b/scripts/SANS/SANSUtility.py
index 8b4597faf0103896f547d27b4b421e319fba1418..36272bee57038df93e0c2159947b6b20d1a096cd 100644
--- a/scripts/SANS/SANSUtility.py
+++ b/scripts/SANS/SANSUtility.py
@@ -614,10 +614,10 @@ def check_child_ws_for_name_and_type_for_added_eventdata(wsGroup, number_of_entr
 
     for index in range(len(wsGroup)):
         childWorkspace = wsGroup.getItem(index)
-        if re.search(REG_DATA_NAME, childWorkspace.getName()):
+        if re.search(REG_DATA_NAME, childWorkspace.name()):
             is_in = True if isinstance(childWorkspace, IEventWorkspace) else False
             has_data.append(is_in)
-        elif re.search(REG_DATA_MONITORS_NAME, childWorkspace.getName()):
+        elif re.search(REG_DATA_MONITORS_NAME, childWorkspace.name()):
             is_in = True if isinstance(childWorkspace, MatrixWorkspace) else False
             has_monitors.append(is_in)
 
@@ -637,7 +637,7 @@ def extract_child_ws_for_added_eventdata(ws_group, appendix):
     @param appendix :: what to append to the names of the child workspaces
     '''
     # Store the name of the group workspace in a string
-    ws_group_name = ws_group.getName()
+    ws_group_name = ws_group.name()
 
     # Get a handle on each child workspace
     ws_handles = []
@@ -656,7 +656,7 @@ def extract_child_ws_for_added_eventdata(ws_group, appendix):
     data_workspaces = []
     monitor_workspaces = []
     for ws_handle in ws_handles:
-        old_workspace_name = ws_handle.getName()
+        old_workspace_name = ws_handle.name()
         # Get the index of the multiperiod workspace if it is present
         new_workspace_name = get_new_workspace_name(appendix, old_workspace_name, ws_group_name)
         RenameWorkspace(InputWorkspace = ws_handle, OutputWorkspace=new_workspace_name)
@@ -862,15 +862,14 @@ def get_masked_det_ids(ws):
 
     @returns a list of IDs for masked detectors
     """
+    spectrumInfo = ws.spectrumInfo()
     for ws_index in range(ws.getNumberHistograms()):
-        try:
-            det = ws.getDetector(ws_index)
-        except RuntimeError:
+        if not spectrumInfo.hasDetectors(ws_index):
             # Skip the rest after finding the first spectra with no detectors,
             # which is a big speed increase for SANS2D.
             break
-        if det.isMasked():
-            yield det.getID()
+        if spectrumInfo.isMasked(ws_index):
+            yield ws.getDetector(ws_index).getID()
 
 
 def create_zero_error_free_workspace(input_workspace_name, output_workspace_name):
diff --git a/scripts/SANS/SANSadd2.py b/scripts/SANS/SANSadd2.py
index 6cb4fb1b883522dce1c7479663f3fa13304bccb8..3f834d3cdc6a60c1b563f4c371307374d9846692 100644
--- a/scripts/SANS/SANSadd2.py
+++ b/scripts/SANS/SANSadd2.py
@@ -18,8 +18,8 @@ ADD_FILES_NEW_TEMPORARY = "AddFilesNewTempory"
 ADD_FILES_NEW_TEMPORARY_MONITORS = "AddFilesNewTempory_monitors"
 
 
-def add_runs(runs, inst='sans2d', defType='.nxs', rawTypes=('.raw', '.s*', 'add','.RAW'), lowMem=False, # noqa
-             binning='Monitors', saveAsEvent=False, isOverlay = False, time_shifts=None): # noqa
+def add_runs(runs, inst='sans2d', defType='.nxs', rawTypes=('.raw', '.s*', 'add','.RAW'), lowMem=False,
+             binning='Monitors', saveAsEvent=False, isOverlay = False, time_shifts=None):
     if inst.upper() == "SANS2DTUBES":
         inst = "SANS2D"
   #check if there is at least one file in the list
diff --git a/scripts/SANS/isis_reducer.py b/scripts/SANS/isis_reducer.py
index a63ae24a6447f132a2252c3ae9707e8028376d34..1724c43c5354506ba3c0104bce31cd60e1e562cd 100644
--- a/scripts/SANS/isis_reducer.py
+++ b/scripts/SANS/isis_reducer.py
@@ -384,6 +384,9 @@ class ISISReducer(Reducer):
         # which gets used during cropping and Tranmission calculation
         self.dark_run_subtraction = isis_reduction_steps.DarkRunSubtraction()
 
+        # Unwrap monitors
+        self._unwrap_monitors = False
+
     def set_instrument(self, configuration):
         """
             Sets the instrument and put in the default beam center (usually the
@@ -979,3 +982,11 @@ class ISISReducer(Reducer):
             if sample.loader.wksp_name + "_monitors" in mtd.getObjectNames():
                 was_event = True
         return was_event
+
+    def get_unwrap_monitors(self):
+        return self._unwrap_monitors
+
+    def set_unwrap_monitors(self, value):
+        self._unwrap_monitors = value
+
+    unwrap_monitors = property(get_unwrap_monitors, set_unwrap_monitors, None, None)
diff --git a/scripts/SANS/isis_reduction_steps.py b/scripts/SANS/isis_reduction_steps.py
index 848277ca22ebac6d3870b106f6d88b1ef3007d52..23a99f9d4e606d4a40e17a2ca2dc739f859a70dd 100644
--- a/scripts/SANS/isis_reduction_steps.py
+++ b/scripts/SANS/isis_reduction_steps.py
@@ -58,6 +58,17 @@ def _issueInfo(msg):
     sanslog.notice(msg)
 
 
+def is_prompt_peak_instrument(reducer):
+    if reducer.instrument.name() == 'LOQ' or reducer.instrument.name() == 'LARMOR':
+        return True
+    else:
+        return False
+
+
+def get_wavelength_min_and_max(reducer):
+    return reducer.to_wavelen.wav_low, reducer.to_wavelen.wav_high
+
+
 class LoadRun(object):
     UNSET_PERIOD = -1
 
@@ -1935,16 +1946,25 @@ class NormalizeToMonitor(ReductionStep):
 
         self.output_wksp = str(workspace) + INCIDENT_MONITOR_TAG
         mon = reducer.get_sample().get_monitor(normalization_spectrum - 1)
+
+        # Unwrap the monitors of the scatter workspace
+        if reducer.unwrap_monitors:
+            wavelength_min, wavelength_max = get_wavelength_min_and_max(reducer)
+            temp_mon = UnwrapMonitorsInTOF(InputWorkspace=mon, WavelengthMin=wavelength_min, WavelengthMax=wavelength_max)
+            DeleteWorkspace(mon)
+            mon = temp_mon
+
         if reducer.event2hist.scale != 1:
             mon *= reducer.event2hist.scale
 
         if str(mon) != self.output_wksp:
             RenameWorkspace(mon, OutputWorkspace=self.output_wksp)
 
-        if reducer.instrument.name() == 'LOQ':
+        if (is_prompt_peak_instrument(reducer) and reducer.transmission_calculator.removePromptPeakMin is not None
+            and reducer.transmission_calculator.removePromptPeakMax is not None):  # noqa
             RemoveBins(InputWorkspace=self.output_wksp, OutputWorkspace=self.output_wksp,
-                       XMin=reducer.transmission_calculator.loq_removePromptPeakMin, XMax=
-                       reducer.transmission_calculator.loq_removePromptPeakMax, Interpolation="Linear")
+                       XMin=reducer.transmission_calculator.removePromptPeakMin, XMax=
+                       reducer.transmission_calculator.removePromptPeakMax, Interpolation="Linear")
 
         # Remove flat background
         TOF_start, TOF_end = reducer.inst.get_TOFs(normalization_spectrum)
@@ -2019,9 +2039,9 @@ class TransmissionCalc(ReductionStep):
         self.calculated_can = None
         # the result of this calculation that will be used by CalculateNorm() and the ConvertToQ
         self.output_wksp = None
-        # Use for removing LOQ prompt peak from monitors. Units of micro-seconds
-        self.loq_removePromptPeakMin = 19000.0
-        self.loq_removePromptPeakMax = 20500.0
+        # Use for removing LOQ/LARMOR prompt peak from monitors. Units of micro-seconds
+        self.removePromptPeakMin = None
+        self.removePromptPeakMax = None
 
     def set_trans_fit(self, fit_method, min_=None, max_=None, override=True, selector='both'):
         """
@@ -2116,12 +2136,19 @@ class TransmissionCalc(ReductionStep):
         # problems if we don't.
         extract_spectra(mtd[inputWS], trans_det_ids, tmpWS)
 
+        # If the transmission and direct workspaces require an unwrapping of the monitors then do it here
+        if reducer.unwrap_monitors:
+            wavelength_min, wavelength_max = get_wavelength_min_and_max(reducer)
+            UnwrapMonitorsInTOF(InputWorkspace=tmpWS, OutputWorkspace=tmpWS,
+                                WavelengthMin=wavelength_min, WavelengthMax=wavelength_max)
+
         # Perform the a dark run background correction if one was specified
         self._correct_dark_run_background(reducer, tmpWS, trans_det_ids)
 
-        if inst.name() == 'LOQ':
-            RemoveBins(InputWorkspace=tmpWS, OutputWorkspace=tmpWS, XMin=self.loq_removePromptPeakMin,
-                       XMax=self.loq_removePromptPeakMax,
+        if is_prompt_peak_instrument(reducer) and self.removePromptPeakMin is not None and \
+                        self.removePromptPeakMax is not None:  # noqa
+            RemoveBins(InputWorkspace=tmpWS, OutputWorkspace=tmpWS, XMin=self.removePromptPeakMin,
+                       XMax=self.removePromptPeakMax,
                        Interpolation='Linear')
 
         tmp = mtd[tmpWS]
@@ -2222,6 +2249,9 @@ class TransmissionCalc(ReductionStep):
             or estimates the proportion of neutrons that are transmitted
             through the sample
         """
+        # Set the prompt peak default values
+        self.set_prompt_parameter_if_not_set(reducer)
+
         self.output_wksp = None
 
         # look for run files that contain transmission data
@@ -2426,6 +2456,17 @@ class TransmissionCalc(ReductionStep):
             trans_ws = reducer.dark_run_subtraction.execute_transmission(trans_ws, trans_det_ids)
             mtd.addOrReplace(workspace_name, trans_ws)
 
+    def set_prompt_parameter_if_not_set(self, reducer):
+        """
+        This method sets default prompt peak values in case the user has not provided some. Currently
+        we only use default values for LOQ.
+        """
+        is_prompt_peak_not_set = self.removePromptPeakMin is None and self.removePromptPeakMax is None
+        if is_prompt_peak_not_set:
+            if reducer.instrument.name() == "LOQ":
+                self.removePromptPeakMin = 19000.0 # Units of micro-seconds
+                self.removePromptPeakMax = 20500.0 # Units of micro-seconds
+
 
 class AbsoluteUnitsISIS(ReductionStep):
     DEFAULT_SCALING = 100.0
@@ -3192,7 +3233,8 @@ class UserFile(ReductionStep):
             'MON/': self._read_mon_line,
             'TUBECALIBFILE': self._read_calibfile_line,
             'MASKFILE': self._read_maskfile_line,
-            'QRESOL/': self._read_q_resolution_line}
+            'QRESOL/': self._read_q_resolution_line,
+            'UNWRAP': self._read_unwrap_monitors_line}
 
     def __deepcopy__(self, memo):
         """Called when a deep copy is requested
@@ -3206,7 +3248,8 @@ class UserFile(ReductionStep):
             'MON/': fresh._read_mon_line,
             'TUBECALIBFILE': self._read_calibfile_line,
             'MASKFILE': self._read_maskfile_line,
-            'QRESOL/': self._read_q_resolution_line
+            'QRESOL/': self._read_q_resolution_line,
+            'UNWRAP': self._read_unwrap_monitors_line
         }
         return fresh
 
@@ -3382,9 +3425,9 @@ class UserFile(ReductionStep):
         elif upper_line.startswith('FIT/MONITOR'):
             params = upper_line.split()
             nparams = len(params)
-            if nparams == 3 and reducer.instrument.name() == 'LOQ':
-                reducer.transmission_calculator.loq_removePromptPeakMin = float(params[1])
-                reducer.transmission_calculator.loq_removePromptPeakMax = float(params[2])
+            if nparams == 3 and is_prompt_peak_instrument(reducer):
+                reducer.transmission_calculator.removePromptPeakMin = float(params[1])
+                reducer.transmission_calculator.removePromptPeakMax = float(params[2])
             else:
                 if reducer.instrument.name() == 'LOQ':
                     _issueWarning('Incorrectly formatted FIT/MONITOR line, %s, line ignored' % upper_line)
@@ -3922,7 +3965,7 @@ class UserFile(ReductionStep):
     def _read_q_resolution_line_on_off(self, arguments, reducer):
         '''
         Handles the ON/OFF setting for QResolution
-        @param arguements: the line arguments
+        @param arguments: the line arguments
         @param reducer: a reducer object
         '''
         # Remove white space
@@ -3982,6 +4025,28 @@ class UserFile(ReductionStep):
 
         reducer.settings["MaskFiles"] = value
 
+    def _read_unwrap_monitors_line(self, arguments, reducer):
+        """
+        Checks if the montiors should be unwrapped. The arguments can be either ON or OFF. We don't care here about
+        any preceeding slash
+        Args:
+            arguments: the arguments string
+            reducer: a handle to the reducer (is not used)
+        """
+        # Remove the slash if
+        if arguments.find('/') == -1:
+            arguments.replace('/', "")
+        # Remove white space
+        on_off = "".join(arguments.split())
+        if on_off == "ON":
+            reducer.unwrap_monitors = True
+        elif on_off == "OFF":
+            reducer.unwrap_monitors = False
+        else:
+            reducer.unwrap_monitors = False
+            return 'Unknown setting {0} UNWRAP command in line: '.format(on_off)
+        return ''
+
 
 class GetOutputName(ReductionStep):
     def __init__(self):
@@ -4217,6 +4282,7 @@ class GetSampleGeom(ReductionStep):
             Reads the geometry information stored in the workspace
             but doesn't replace values that have been previously set
         """
+        _ = reducer  # noqa
         wksp = mtd[workspace]
         if isinstance(wksp, WorkspaceGroup):
             wksp = wksp[0]
diff --git a/scripts/SANS/sans/README.md b/scripts/SANS/sans/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..8b7a21d65a7ae82c7c26fd2999589358d779a71c
--- /dev/null
+++ b/scripts/SANS/sans/README.md
@@ -0,0 +1,12 @@
+# `sans`
+
+The `sans` package contains the elements of the second version of the ISIS SANS reduction, except for Python algorithms
+which can be found in the `WorkflowAlgorithm` section of Mantid's `PythonInterface`.
+
+## `common`
+
+The elements in the common package include widely used general purpose functions, constants and SANS-wide type definitions.
+
+## `state`
+
+The elements in the `state` package contain the definition of the reduction configuration and the corresponding builders.
\ No newline at end of file
diff --git a/scripts/SANS/sans/__init__.py b/scripts/SANS/sans/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/scripts/SANS/sans/common/__init__.py b/scripts/SANS/sans/common/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/scripts/SANS/sans/common/configurations.py b/scripts/SANS/sans/common/configurations.py
new file mode 100644
index 0000000000000000000000000000000000000000..1586f21f1bb8860dd07b4b61a703fdc3703442a7
--- /dev/null
+++ b/scripts/SANS/sans/common/configurations.py
@@ -0,0 +1,24 @@
+""" The SANSConfigurations class holds instrument-specific configs to centralize instrument-specific magic numbers"""
+# pylint: disable=too-few-public-methods
+
+
+class Configurations(object):
+
+    class LARMOR(object):
+        # The full wavelength range of the instrument
+        wavelength_full_range_low = 0.5
+        wavelength_full_range_high = 13.5
+
+    class SANS2D(object):
+        # The full wavelength range of the instrument
+        wavelength_full_range_low = 2.0
+        wavelength_full_range_high = 14.0
+
+    class LOQ(object):
+        # The full wavelength range of the instrument
+        wavelength_full_range_low = 2.2
+        wavelength_full_range_high = 10.0
+
+        # The default prompt peak range for LOQ
+        prompt_peak_correction_min = 19000.0
+        prompt_peak_correction_max = 20500.0
diff --git a/scripts/SANS/sans/common/constants.py b/scripts/SANS/sans/common/constants.py
new file mode 100644
index 0000000000000000000000000000000000000000..015990ba94ff23437b167a88b6a7910bd03af8e2
--- /dev/null
+++ b/scripts/SANS/sans/common/constants.py
@@ -0,0 +1,42 @@
+""" These constants  are used in the SANS reducer framework. We want a central place for them."""
+
+# pylint: disable=too-few-public-methods
+
+# ----------------------------------------
+# Proeprty names for Algorithms
+# ---------------------------------------
+MONITOR_SUFFIX = "_monitors"
+INPUT_WORKSPACE = "InputWorkspace"
+
+FILE_NAME = "Filename"
+
+OUTPUT_WORKSPACE = "OutputWorkspace"
+OUTPUT_WORKSPACE_GROUP = OUTPUT_WORKSPACE + "_"
+
+OUTPUT_MONITOR_WORKSPACE = "MonitorWorkspace"
+OUTPUT_MONITOR_WORKSPACE_GROUP = OUTPUT_MONITOR_WORKSPACE + "_"
+
+WORKSPACE = "Workspace"
+EMPTY_NAME = "dummy"
+
+
+# ----------------------------------------
+# Other
+# ---------------------------------------
+SANS_SUFFIX = "sans"
+TRANS_SUFFIX = "trans"
+
+high_angle_bank = "HAB"
+low_angle_bank = "LAB"
+
+SANS2D = "SANS2D"
+LARMOR = "LARMOR"
+LOQ = "LOQ"
+
+REDUCED_WORKSPACE_NAME_IN_LOGS = "reduced_workspace_name"
+SANS_FILE_TAG = "sans_file_tag"
+REDUCED_CAN_TAG = "reduced_can_hash"
+
+ALL_PERIODS = 0
+
+CALIBRATION_WORKSPACE_TAG = "sans_applied_calibration_file"
diff --git a/scripts/SANS/sans/common/enums.py b/scripts/SANS/sans/common/enums.py
new file mode 100644
index 0000000000000000000000000000000000000000..97ab8647c1b8b4bfeb2d3c96b8258bf06665a920
--- /dev/null
+++ b/scripts/SANS/sans/common/enums.py
@@ -0,0 +1,301 @@
+""" The elements of this module define typed enums which are used in the SANS reduction framework."""
+
+# pylint: disable=too-few-public-methods, invalid-name
+
+from __future__ import (absolute_import, division, print_function)
+from inspect import isclass
+from functools import partial
+from six import PY3
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# Serializable Enum decorator
+# ----------------------------------------------------------------------------------------------------------------------
+def serializable_enum(*inner_classes):
+    """
+    Class decorator which changes the name of an inner class to include the name of the outer class. The inner class
+    gets a method to determine the name of the outer class. This information is needed for serialization at the
+    algorithm input boundary.
+    """
+    def inner_class_builder(cls):
+        # Add each inner class to the outer class
+        for inner_class in inner_classes:
+            new_class = type(inner_class, (cls, ), {"outer_class_name": cls.__name__})
+            # We set the module of the inner class to the module of the outer class. We have to do this since we
+            # are dynamically adding the inner class which gets its module name from the module where it was added,
+            # but not where the outer class lives.
+            module_of_outer_class = getattr(cls, "__module__")
+            setattr(new_class, "__module__", module_of_outer_class)
+            # Add the inner class to the outer class
+            setattr(cls, inner_class, new_class)
+        return cls
+    return inner_class_builder
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# String conversion decorator
+# ----------------------------------------------------------------------------------------------------------------------
+def string_convertible(cls):
+    """
+    Class decorator to make the enum/sub-class entries string convertible.
+
+    We do this by creating a static  from_string and to_string method on the class.
+    IMPORTANT: It is important that the enum values are added to the class before applying this decorator. In general
+               the order has to be:
+               @string_convertible
+               @serializable_enum
+               class MyClass(object):
+                ...
+    @param cls: a reference to the class
+    @return: the class
+    """
+    def to_string(elements, convert_to_string):
+        for key, value in elements.items():
+            if convert_to_string is value:
+                return key
+        raise RuntimeError("Could not convert {0} to string. Unknown value.".format(convert_to_string))
+
+    def from_string(elements, convert_from_string):
+        if PY3 and isinstance(convert_from_string, bytes):
+            convert_from_string = convert_from_string.decode()
+        for key, value in elements.items():
+            if convert_from_string == key:
+                return value
+        raise RuntimeError("Could not convert {0} from string. Unknown value.".format(convert_from_string))
+
+    # First get all enum/sub-class elements
+    convertible_elements = {}
+    for attribute_name, attribute_value in cls.__dict__.items():
+        if isclass(attribute_value) and issubclass(attribute_value, cls):
+            convertible_elements.update({attribute_name: attribute_value})
+
+    # Add the new static methods to the class
+    partial_to_string = partial(to_string, convertible_elements)
+    partial_from_string = partial(from_string, convertible_elements)
+    setattr(cls, "to_string", staticmethod(partial_to_string))
+    setattr(cls, "from_string", staticmethod(partial_from_string))
+    return cls
+
+
+# --------------------------------
+#  Instrument and facility types
+# --------------------------------
+@string_convertible
+@serializable_enum("LOQ", "LARMOR", "SANS2D", "NoInstrument")
+class SANSInstrument(object):
+    pass
+
+
+@serializable_enum("ISIS", "NoFacility")
+class SANSFacility(object):
+    pass
+
+
+# ------------------------------------
+# Data Types
+# ------------------------------------
+@string_convertible
+@serializable_enum("SampleScatter", "SampleTransmission", "SampleDirect", "CanScatter", "CanTransmission", "CanDirect",
+                   "Calibration")
+class SANSDataType(object):
+    """
+    Defines the different data types which are required for the reduction. Besides the fundamental data of the
+    sample and the can, we can also specify a calibration.
+    """
+    pass
+
+
+# ---------------------------
+#  Coordinate Definitions (3D)
+# --------------------------
+class Coordinates(object):
+    pass
+
+
+@serializable_enum("X", "Y", "Z")
+class CanonicalCoordinates(Coordinates):
+    pass
+
+
+# --------------------------
+#  ReductionMode
+# --------------------------
+@serializable_enum("Merged", "All")
+class ReductionMode(object):
+    """
+    Defines the reduction modes which should be common to all implementations, namely All and Merged.
+    """
+    pass
+
+
+@string_convertible
+@serializable_enum("HAB", "LAB")
+class ISISReductionMode(ReductionMode):
+    """
+    Defines the different reduction modes. This can be the high-angle bank, the low-angle bank
+    """
+    pass
+
+
+# --------------------------
+#  Reduction dimensionality
+# --------------------------
+@serializable_enum("OneDim", "TwoDim")
+class ReductionDimensionality(object):
+    """
+    Defines the dimensionality for reduction. This can be either 1D or 2D
+    """
+    pass
+
+
+# --------------------------
+#  Reduction data
+# --------------------------
+@serializable_enum("Scatter", "Transmission", "Direct")
+class ReductionData(object):
+    """
+    Defines the workspace type of the reduction data. For all known instances this can be scatter, transmission
+    or direct
+    """
+    pass
+
+
+# --------------------------
+#  Type of data
+# --------------------------
+@string_convertible
+@serializable_enum("Sample", "Can")
+class DataType(object):
+    """
+    Defines the type of reduction data. This can either the sample or only the can.
+    """
+    pass
+
+
+# ---------------------------------
+#  Partial reduction output setting
+# ---------------------------------
+@serializable_enum("Count", "Norm")
+class OutputParts(object):
+    """
+    Defines the partial outputs of a reduction. They are the numerator (Count) and denominator (Norm) of a division.
+    """
+    pass
+
+
+# -----------------------------------------------------
+#  The fit type during merge of HAB and LAB reductions
+# -----------------------------------------------------
+@string_convertible
+@serializable_enum("Both", "NoFit", "ShiftOnly", "ScaleOnly")
+class FitModeForMerge(object):
+    """
+    Defines which fit operation to use during the merge of two reductions.
+    """
+    pass
+
+
+# --------------------------
+#  Detectors
+# --------------------------
+@serializable_enum("Horizontal", "Vertical", "Rotated")
+class DetectorOrientation(object):
+    """
+    Defines the detector orientation.
+    """
+    pass
+
+
+# --------------------------
+#  Detector Type
+# --------------------------
+@string_convertible
+@serializable_enum("HAB", "LAB")
+class DetectorType(object):
+    """
+    Defines the detector type
+    """
+    pass
+
+
+# --------------------------
+#  Ranges
+# --------------------------
+@string_convertible
+@serializable_enum("Lin", "Log")
+class RangeStepType(object):
+    """
+    Defines the step type of a range
+    """
+    pass
+
+
+# --------------------------
+#  Rebin
+# --------------------------
+@string_convertible
+@serializable_enum("Rebin", "InterpolatingRebin")
+class RebinType(object):
+    """
+    Defines the rebin types available
+    """
+    pass
+
+
+# --------------------------
+#  SaveType
+# --------------------------
+@string_convertible
+@serializable_enum("Nexus", "NistQxy", "CanSAS", "RKH", "CSV", "NXcanSAS")
+class SaveType(object):
+    """
+    Defines the save types available
+    """
+    pass
+
+
+# ------------------------------------------
+# Fit type for the transmission calculation
+# ------------------------------------------
+@string_convertible
+@serializable_enum("Linear", "Log", "Polynomial", "NoFit")
+class FitType(object):
+    """
+    Defines possible fit types
+    """
+    pass
+
+
+# --------------------------
+#  SampleShape
+# --------------------------
+@serializable_enum("CylinderAxisUp", "Cuboid", "CylinderAxisAlong")
+class SampleShape(object):
+    """
+    Defines the sample shape types
+    """
+    pass
+
+
+def convert_int_to_shape(shape_int):
+    """
+    Note that we convert the sample shape to an integer here. This is required for the workspace, hence we don't
+    use the string_convertible decorator.
+    """
+    if shape_int == 1:
+        as_type = SampleShape.CylinderAxisUp
+    elif shape_int == 2:
+        as_type = SampleShape.Cuboid
+    elif shape_int == 3:
+        as_type = SampleShape.CylinderAxisAlong
+    else:
+        raise ValueError("SampleShape: Cannot convert unknown sample shape integer: {0}".format(shape_int))
+    return as_type
+
+
+# ---------------------------
+# FileTypes
+# ---------------------------
+@serializable_enum("ISISNexus", "ISISNexusAdded", "ISISRaw", "NoFileType")
+class FileType(object):
+    pass
diff --git a/scripts/SANS/sans/common/file_information.py b/scripts/SANS/sans/common/file_information.py
new file mode 100644
index 0000000000000000000000000000000000000000..87990ac3e85752dab5d96cd2eeb1baaf549ff95b
--- /dev/null
+++ b/scripts/SANS/sans/common/file_information.py
@@ -0,0 +1,524 @@
+""" The elements of this module coordinate file access and information extraction from files."""
+
+# pylint: disable=too-few-public-methods, invalid-name
+
+from __future__ import (absolute_import, division, print_function)
+import os
+import h5py as h5
+from abc import (ABCMeta, abstractmethod)
+
+from mantid.api import FileFinder
+from mantid.kernel import (DateAndTime, ConfigService)
+from mantid.api import (AlgorithmManager, ExperimentInfo)
+from sans.common.enums import (SANSInstrument, FileType)
+
+from six import with_metaclass
+
+
+# -----------------------------------
+# Free Functions
+# -----------------------------------
+def find_full_file_path(file_name):
+    """
+    Gets the full path of a file name if it is available on the Mantid paths.
+
+    :param file_name: the name of the file.
+    :return: the full file path.
+    """
+    return FileFinder.getFullPath(file_name)
+
+
+def find_sans_file(file_name):
+    """
+    Finds a SANS file.
+    The file can be specified as:
+    1. file.ext or  path1 path2 file.ext
+    2. run number
+    :param file_name: a file name or a run number.
+    :return: the full path.
+    """
+    full_path = find_full_file_path(file_name)
+    if not full_path:
+        runs = FileFinder.findRuns(file_name)
+        if runs:
+            full_path = runs[0]
+    if not full_path:
+        raise RuntimeError("Trying to find the SANS file {0}, but cannot find it. Make sure that "
+                           "the relevant paths are added.".format(file_name))
+    return full_path
+
+
+def get_extension_for_file_type(file_info):
+    """
+    Get the extension for a specific file type.
+
+    :param file_info: a SANSFileInformation object.
+    :return: the extension a stirng. This can be either nxs or raw.
+    """
+    if file_info.get_type() is FileType.ISISNexus or file_info.get_type() is FileType.ISISNexusAdded:
+        extension = "nxs"
+    elif file_info.get_type() is FileType.ISISRaw:
+        extension = "raw"
+    else:
+        raise RuntimeError("The file extension type for a file of type {0} is unknown"
+                           "".format(str(file_info.get_type())))
+    return extension
+
+
+def get_number_of_periods(func, file_name):
+    """
+    Get the number of periods of the data in a file.
+
+    :param func: a function handle which extracts the relevant information.
+    :param file_name: the file name to the relevant file.
+    :return: the number of periods if it is applicable else 0.
+    """
+    is_file_type, number_of_periods = func(file_name)
+    return number_of_periods if is_file_type else 0
+
+
+def is_single_period(func, file_name):
+    """
+    Checks if a file contains only single period data.
+
+    :param func: a function handle which extracts the number of periods.
+    :param file_name: the name of the file.
+    :return: true if the number of periods is 1 else false.
+    """
+    is_file_type, number_of_periods = func(file_name)
+    return is_file_type and number_of_periods == 1
+
+
+def is_multi_period(func, file_name):
+    """
+    Checks if a file contains multi-period data.
+
+    :param func: a function handle which extracts the number of periods.
+    :param file_name: the name of the file.
+    :return: true if the number of periods is larger than one else false.
+    """
+    is_file_type, number_of_periods = func(file_name)
+    return is_file_type and number_of_periods >= 1
+
+
+def get_instrument_paths_for_sans_file(file_name):
+    """
+    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
+    :return: the IDF path and the IPF path
+    """
+    def get_file_location(path):
+        return os.path.dirname(path)
+
+    def get_ipf_equivalent_name(path):
+        # If XXX_Definition_Yyy.xml is the IDF name, then the equivalent  IPF name is: XXX_Parameters_Yyy.xml
+        base_file_name = os.path.basename(path)
+        return base_file_name.replace("Definition", "Parameters")
+
+    def get_ipf_standard_name(path):
+        # If XXX_Definition_Yyy.xml is the IDF name, then the standard IPF name is: XXX_Parameters.xml
+        base_file_name = os.path.basename(path)
+        elements = base_file_name.split("_")
+        return elements[0] + "_Parameters.xml"
+
+    def check_for_files(directory, path):
+        # Check if XXX_Parameters_Yyy.xml exists in the same folder
+        ipf_equivalent_name = get_ipf_equivalent_name(path)
+        ipf_equivalent = os.path.join(directory, ipf_equivalent_name)
+        if os.path.exists(ipf_equivalent):
+            return ipf_equivalent
+
+        # Check if XXX_Parameters.xml exists in the same folder
+        ipf_standard_name = get_ipf_standard_name(path)
+        ipf_standard = os.path.join(directory, ipf_standard_name)
+        if os.path.exists(ipf_standard):
+            return ipf_standard
+        # Does not seem to be in the folder
+        return None
+
+    def get_ipf_for_rule_1(path):
+        # Check if can be found in the same folder
+        directory = get_file_location(path)
+        return check_for_files(directory, path)
+
+    def get_ipf_for_rule_2(path):
+        # Check if can be found in the instrument folder
+        directory = ConfigService.getInstrumentDirectory()
+        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)
+    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
+    measurement_time_as_string = str(measurement_time).strip()
+
+    # Get the instrument
+    instrument = file_information.get_instrument()
+    instrument_as_string = SANSInstrument.to_string(instrument)
+
+    # Get the idf file path
+    idf_path = ExperimentInfo.getInstrumentFilename(instrument_as_string, measurement_time_as_string)
+    idf_path = os.path.normpath(idf_path)
+
+    if not os.path.exists(idf_path):
+        raise RuntimeError("SANSFileInformation: The instrument definition file {0} does not seem to "
+                           "exist.".format(str(idf_path)))
+
+    # Get the ipf path. This is slightly more complicated. See the Mantid documentation for the naming rules. Currently
+    # they are:
+    # 1. If the IDF is not in the instrument folder and there is another X_Parameters.xml in the same folder,
+    #    this one in the same folder will be used instead of any parameter file in the instrument folder.
+    # 2. If you want one parameter file for your IDF file, name your IDF file X_Definition_Yyy.xml and the parameter
+    #    file X_Parameters_Yyy.xml , where Yyy is any combination a characters you find appropriate. If your IDF
+    #    file is not in the instrument folder, the parameter file can be in either the same folder or in the instrument
+    #    folder, but it can only be in the instrument folder, if the same folder has no X_Parameters.xml or
+    #    X_Parameters_Yyy.xml file. If there is no X_Parameters_Yyy.xml file, X_Parameters.xml would be used.
+    ipf_rule1 = get_ipf_for_rule_1(idf_path)
+    if ipf_rule1:
+        return idf_path, ipf_rule1
+
+    ipf_rule2 = get_ipf_for_rule_2(idf_path)
+    if ipf_rule2:
+        return idf_path, ipf_rule2
+
+    raise RuntimeError("SANSFileInformation: There does not seem to be a corresponding instrument parameter file "
+                       "available for {0}".format(str(idf_path)))
+
+
+# ----------------------------------------------
+# Methods for ISIS Nexus
+# ---------------------------------------------
+def get_isis_nexus_info(file_name):
+    """
+    Get information if is ISIS Nexus and the number of periods.
+
+    :param file_name: the full file path.
+    :return: if the file was a Nexus file and the number of periods.
+    """
+    try:
+        with h5.File(file_name) as h5_file:
+            keys = list(h5_file.keys())
+            is_isis_nexus = u"raw_data_1" in keys
+            first_entry = h5_file["raw_data_1"]
+            period_group = first_entry["periods"]
+            proton_charge_data_set = period_group["proton_charge"]
+            number_of_periods = len(proton_charge_data_set)
+    except IOError:
+        is_isis_nexus = False
+        number_of_periods = -1
+    return is_isis_nexus, number_of_periods
+
+
+def is_isis_nexus_single_period(file_name):
+    return is_single_period(get_isis_nexus_info, file_name)
+
+
+def is_isis_nexus_multi_period(file_name):
+    return is_multi_period(get_isis_nexus_info, file_name)
+
+
+def get_number_of_periods_for_isis_nexus(file_name):
+    return get_number_of_periods(get_isis_nexus_info, file_name)
+
+
+def get_instrument_name_for_isis_nexus(file_name):
+    """
+    Instrument inforamtion is
+    file|
+        |--mantid_workspace_1/raw_data_1|
+                                        |--instrument|
+                                                     |--name
+    """
+    with h5.File(file_name) as h5_file:
+        # Open first entry
+        keys = list(h5_file.keys())
+        first_entry = h5_file[keys[0]]
+        # Open instrument group
+        instrument_group = first_entry["instrument"]
+        # Open name data set
+        name_data_set = instrument_group["name"]
+        # Read value
+        instrument_name = name_data_set[0]
+    return instrument_name
+
+
+def get_top_level_nexus_entry(file_name, entry_name):
+    """
+    Gets the first entry in a Nexus file.
+
+    :param file_name: The file name
+    :param entry_name: the entry name
+    :return:
+    """
+    with h5.File(file_name) as h5_file:
+        # Open first entry
+        keys = list(h5_file.keys())
+        top_level = h5_file[keys[0]]
+        entry = top_level[entry_name]
+        value = entry[0]
+    return value
+
+
+def get_date_for_isis_nexus(file_name):
+    value = get_top_level_nexus_entry(file_name, "start_time")
+    return DateAndTime(value)
+
+
+def get_run_number_for_isis_nexus(file_name):
+    return int(get_top_level_nexus_entry(file_name, "run_number"))
+
+
+def get_event_mode_information(file_name):
+    """
+    Event mode files have a class with a "NXevent_data" type
+    Structure:
+    |--mantid_workspace_1/raw_data_1|
+                                    |--some_group|
+                                                 |--Attribute: NX_class = NXevent_data
+    """
+    with h5.File(file_name) as h5_file:
+        # Open first entry
+        keys = list(h5_file.keys())
+        first_entry = h5_file[keys[0]]
+        # Open instrument group
+        is_event_mode = False
+        for value in first_entry.values():
+            if "NX_class" in value.attrs and "NXevent_data" == value.attrs["NX_class"]:
+                is_event_mode = True
+                break
+    return is_event_mode
+
+
+# ---------
+# ISIS Raw
+# ---------
+def get_raw_info(file_name):
+    try:
+        alg_info = AlgorithmManager.createUnmanaged("RawFileInfo")
+        alg_info.initialize()
+        alg_info.setChild(True)
+        alg_info.setProperty("Filename", file_name)
+        alg_info.setProperty("GetRunParameters", True)
+        alg_info.execute()
+
+        periods = alg_info.getProperty("PeriodCount").value
+        is_raw = True
+        number_of_periods = periods
+    except IOError:
+        is_raw = False
+        number_of_periods = -1
+
+    return is_raw, number_of_periods
+
+
+def is_raw_single_period(file_name):
+    return is_single_period(get_raw_info, file_name)
+
+
+def is_raw_multi_period(file_name):
+    return is_multi_period(get_raw_info, file_name)
+
+
+def get_from_raw_header(file_name, index):
+    alg_info = AlgorithmManager.createUnmanaged("RawFileInfo")
+    alg_info.initialize()
+    alg_info.setChild(True)
+    alg_info.setProperty("Filename", file_name)
+    alg_info.setProperty("GetRunParameters", True)
+    alg_info.execute()
+
+    header = alg_info.getProperty("RunHeader").value
+    element = header.split()[index]
+    return element
+
+
+def instrument_name_correction(instrument_name):
+    return "SANS2D" if instrument_name == "SAN" else instrument_name
+
+
+def get_instrument_name_for_raw(file_name):
+    instrument_name = get_from_raw_header(file_name, 0)
+    return instrument_name_correction(instrument_name)
+
+
+def get_run_number_for_raw(file_name):
+    return int(get_from_raw_header(file_name, 1))
+
+
+def get_number_of_periods_for_raw(file_name):
+    return get_number_of_periods(get_raw_info, file_name)
+
+
+def get_date_for_raw(file_name):
+    def get_month(month_string):
+        month_conversion = {"JAN": "01", "FEB": "02", "MAR": "03", "APR": "04",
+                            "MAY": "05", "JUN": "06", "JUL": "07", "AUG": "08",
+                            "SEP": "09", "OCT": "10", "NOV": "11", "DEC": "12"}
+        month_upper = month_string.upper()
+        if month_upper in month_conversion:
+            return month_conversion[month_upper]
+        else:
+            raise RuntimeError("Cannot get measurement time. Invalid month in Raw file: " + month_upper)
+
+    def get_raw_measurement_time(date_input, time_input):
+        year = date_input[7:(7 + 4)]
+        day = date_input[0:2]
+        month_string = date_input[3:6]
+        month = get_month(month_string)
+
+        date_and_time_string = year + "-" + month + "-" + day + "T" + time_input
+        return DateAndTime(date_and_time_string)
+
+    alg_info = AlgorithmManager.createUnmanaged("RawFileInfo")
+    alg_info.initialize()
+    alg_info.setChild(True)
+    alg_info.setProperty("Filename", file_name)
+    alg_info.setProperty("GetRunParameters", True)
+    alg_info.execute()
+
+    run_parameters = alg_info.getProperty("RunParameterTable").value
+
+    keys = run_parameters.getColumnNames()
+
+    time_id = "r_endtime"
+    date_id = "r_enddate"
+
+    time = run_parameters.column(keys.index(time_id))
+    date = run_parameters.column(keys.index(date_id))
+    time = time[0]
+    date = date[0]
+    return get_raw_measurement_time(date, time)
+
+
+# -----------------------------------------------
+# SANS file Information
+# -----------------------------------------------
+class SANSFileInformation(with_metaclass(ABCMeta, object)):
+    def __init__(self, file_name):
+        self._file_name = file_name
+
+    @abstractmethod
+    def get_file_name(self):
+        pass
+
+    @abstractmethod
+    def get_instrument(self):
+        pass
+
+    @abstractmethod
+    def get_date(self):
+        pass
+
+    @abstractmethod
+    def get_number_of_periods(self):
+        pass
+
+    @abstractmethod
+    def get_type(self):
+        pass
+
+    @abstractmethod
+    def get_run_number(self):
+        pass
+
+    @staticmethod
+    def get_full_file_name(file_name):
+        return find_sans_file(file_name)
+
+
+class SANSFileInformationISISNexus(SANSFileInformation):
+    def __init__(self, file_name):
+        super(SANSFileInformationISISNexus, self).__init__(file_name)
+        # Setup instrument name
+        self._full_file_name = SANSFileInformation.get_full_file_name(self._file_name)
+        instrument_name = get_instrument_name_for_isis_nexus(self._full_file_name)
+        self._instrument = SANSInstrument.from_string(instrument_name)
+
+        # Setup date
+        self._date = get_date_for_isis_nexus(self._full_file_name)
+
+        # Setup number of periods
+        self._number_of_periods = get_number_of_periods_for_isis_nexus(self._full_file_name)
+
+        # Setup run number
+        self._run_number = get_run_number_for_isis_nexus(self._full_file_name)
+
+        # Setup event mode check
+        self._is_event_mode = get_event_mode_information(self._full_file_name)
+
+    def get_file_name(self):
+        return self._full_file_name
+
+    def get_instrument(self):
+        return self._instrument
+
+    def get_date(self):
+        return self._date
+
+    def get_number_of_periods(self):
+        return self._number_of_periods
+
+    def get_run_number(self):
+        return self._run_number
+
+    def get_type(self):
+        return FileType.ISISNexus
+
+    def is_event_mode(self):
+        return self._is_event_mode
+
+
+class SANSFileInformationRaw(SANSFileInformation):
+    def __init__(self, file_name):
+        super(SANSFileInformationRaw, self).__init__(file_name)
+        # Setup instrument name
+        self._full_file_name = SANSFileInformation.get_full_file_name(self._file_name)
+        instrument_name = get_instrument_name_for_raw(self._full_file_name)
+        self._instrument = SANSInstrument.from_string(instrument_name)
+
+        # Setup date
+        self._date = get_date_for_raw(self._full_file_name)
+
+        # Setup number of periods
+        self._number_of_periods = get_number_of_periods_for_raw(self._full_file_name)
+
+        # Setup run number
+        self._run_number = get_run_number_for_raw(self._full_file_name)
+
+    def get_file_name(self):
+        return self._full_file_name
+
+    def get_instrument(self):
+        return self._instrument
+
+    def get_date(self):
+        return self._date
+
+    def get_number_of_periods(self):
+        return self._number_of_periods
+
+    def get_run_number(self):
+        return self._run_number
+
+    def get_type(self):
+        return FileType.ISISRaw
+
+
+class SANSFileInformationFactory(object):
+    def __init__(self):
+        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)
+        elif is_raw_single_period(full_file_name) or is_raw_multi_period(full_file_name):
+            file_information = SANSFileInformationRaw(full_file_name)
+        # TODO: ADD added nexus files here
+        else:
+            raise NotImplementedError("The file type you have provided is not implemented yet.")
+        return file_information
diff --git a/scripts/SANS/sans/common/general_functions.py b/scripts/SANS/sans/common/general_functions.py
new file mode 100644
index 0000000000000000000000000000000000000000..e6776e6a018fb1d1572c4aff8a03418e1773295c
--- /dev/null
+++ b/scripts/SANS/sans/common/general_functions.py
@@ -0,0 +1,181 @@
+""" The elements of this module contain various general-purpose functions for the SANS reduction framework."""
+
+# pylint: disable=invalid-name
+
+from math import (acos, sqrt, degrees)
+from mantid.api import AlgorithmManager, AnalysisDataService
+from mantid.kernel import (DateAndTime)
+from sans.common.constants import SANS_FILE_TAG
+from sans.common.log_tagger import (get_tag, has_tag, set_tag)
+
+
+# -------------------------------------------
+# Free functions
+# -------------------------------------------
+def get_log_value(run, log_name, log_type):
+    """
+    Find a log value.
+
+    There are two options here. Either the log is a scalar or a vector. In the case of a scalar there is not much
+    left to do. In the case of a vector we select the first element whose time_stamp is after the start time of the run
+    @param run: a Run object.
+    @param log_name: the name of the log entry
+    @param log_type: the expected type fo the log entry
+    @return: the log entry
+    """
+    try:
+        # Scalar case
+        output = log_type(run.getLogData(log_name).value)
+    except TypeError:
+        # We must be dealing with a vectorized case, ie a time series
+        log_property = run.getLogData(log_name)
+        number_of_entries = len(log_property.value)
+
+        # If we have only one item, then there is nothing left to do
+        output = None
+        if number_of_entries == 1:
+            output = log_type(run.getLogData(log_name).value[0])
+        else:
+            # Get the first entry which is past the start time log
+            start_time = DateAndTime(run.getLogData('run_start').value)
+            times = log_property.times
+            values = log_property.value
+
+            has_found_value = False
+            for index in range(0, number_of_entries):
+                if times[index] > start_time:
+                    # Not fully clear why we take index - 1, but this follows the old implementation rules
+                    value_index = index if index == 0 else index - 1
+                    has_found_value = True
+                    output = log_type(values[value_index])
+                    break
+
+            # Not fully clear why we take index - 1, but this follows the old implementation rules
+            if not has_found_value:
+                output = float(values[number_of_entries - 1])
+    return output
+
+
+def get_single_valued_logs_from_workspace(workspace, log_names, log_types, convert_from_millimeter_to_meter=False):
+    """
+    Gets non-array valued entries from the sample logs.
+
+    :param workspace: the workspace with the sample log.
+    :param log_names: the log names which are to be extracted.
+    :param log_types: the types of log entries, ie strings or numeric
+    :param convert_from_millimeter_to_meter:
+    :return: the log results
+    """
+    assert len(log_names) == len(log_types)
+    # Find the desired log names.
+    run = workspace.getRun()
+    log_results = {}
+    for log_name, log_type in zip(log_names, log_types):
+        log_value = get_log_value(run, log_name, log_type)
+        log_results.update({log_name: log_value})
+    if convert_from_millimeter_to_meter:
+        for key in log_results.keys():
+            log_results[key] /= 1000.
+    return log_results
+
+
+def create_unmanaged_algorithm(name, **kwargs):
+    """
+    Creates an unmanaged child algorithm and initializes it.
+
+    :param name: the name of the algorithm
+    :param kwargs: settings for the algorithm
+    :return: an initialized algorithm instance.
+    """
+    alg = AlgorithmManager.createUnmanaged(name)
+    alg.initialize()
+    alg.setChild(True)
+    for key, value in kwargs.items():
+        alg.setProperty(key, value)
+    return alg
+
+
+def quaternion_to_angle_and_axis(quaternion):
+    """
+    Converts a quaternion to an angle + an axis
+
+    The conversion from a quaternion to an angle + axis is explained here:
+    http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/
+    """
+    angle = 2*acos(quaternion[0])
+    s_parameter = sqrt(1 - quaternion[0]*quaternion[0])
+
+    axis = []
+    # If the the angle is zero, then it does not make sense to have an axis
+    if s_parameter < 1e-8:
+        axis.append(quaternion[1])
+        axis.append(quaternion[2])
+        axis.append(quaternion[3])
+    else:
+        axis.append(quaternion[1]/s_parameter)
+        axis.append(quaternion[2]/s_parameter)
+        axis.append(quaternion[3]/s_parameter)
+    return degrees(angle), axis
+
+
+def get_charge_and_time(workspace):
+    """
+    Gets the total charge and time from a workspace
+
+    :param workspace: the workspace from which we extract the charge and time.
+    :return: the charge, the time
+    """
+    run = workspace.getRun()
+    charges = run.getLogData('proton_charge')
+    total_charge = sum(charges.value)
+    time_passed = (charges.times[-1] - charges.times[0]).total_microseconds()
+    time_passed /= 1e6
+    return total_charge, time_passed
+
+
+def add_to_sample_log(workspace, log_name, log_value, log_type):
+    """
+    Adds a sample log to the workspace
+
+    :param workspace: the workspace to whcih the sample log is added
+    :param log_name: the name of the log
+    :param log_value: the value of the log in string format
+    :param log_type: the log value type which can be String, Number, Number Series
+    """
+    if log_type not in ["String", "Number", "Number Series"]:
+        raise ValueError("Tryint go add {0} to the sample logs but it was passed "
+                         "as an unknown type of {1}".format(log_value, log_type))
+    if not isinstance(log_value, str):
+        raise TypeError("The value which is added to the sample logs needs to be passed as a string,"
+                        " but it is passed as {0}".format(type(log_value)))
+
+    add_log_name = "AddSampleLog"
+    add_log_options = {"Workspace": workspace,
+                       "LogName": log_name,
+                       "LogText": log_value,
+                       "LogType": log_type}
+    add_log_alg = create_unmanaged_algorithm(add_log_name, **add_log_options)
+    add_log_alg.execute()
+
+
+def append_to_sans_file_tag(workspace, to_append):
+    """
+    Appends a string to the existing sans file tag.
+
+    :param workspace: the workspace which contains the sample logs with the sans file tag.
+    :param to_append: the additional tag
+    """
+    if has_tag(SANS_FILE_TAG, workspace):
+        value = get_tag(SANS_FILE_TAG, workspace)
+        value += to_append
+        set_tag(SANS_FILE_TAG, value, workspace)
+
+
+def get_ads_workspace_references():
+    """
+    Gets a list of handles of available workspaces on the ADS
+
+    @return: the workspaces on the ADS.
+    """
+    for workspace_name in AnalysisDataService.getObjectNames():
+        yield AnalysisDataService.retrieve(workspace_name)
diff --git a/scripts/SANS/sans/common/log_tagger.py b/scripts/SANS/sans/common/log_tagger.py
new file mode 100644
index 0000000000000000000000000000000000000000..cf5a006a09330e6113a5d4c3e2c4893be8c60e1c
--- /dev/null
+++ b/scripts/SANS/sans/common/log_tagger.py
@@ -0,0 +1,103 @@
+""" The elements of this module manage and add specific entries in the sample log."""
+
+# pylint: disable=invalid-name
+
+from __future__ import (absolute_import, division, print_function)
+from hashlib import sha224
+from mantid.api import MatrixWorkspace
+from six import string_types
+
+
+def get_hash_value(value):
+    """
+    Converts a value into a hash
+
+    :param value: a hashable value
+    :return: a hashed value.
+    """
+    hash_value = sha224(str(value).encode("utf8")).hexdigest()
+    if not hash_value or hash_value is None:
+        raise RuntimeError("SANSLogTagger: Something went wrong when trying to get the hash"
+                           " for {0}.".format(str(value)))
+    return hash_value
+
+
+def check_if_valid_tag_and_workspace(tag, workspace):
+    """
+    Checks if a tag and a workspace a valid for tags
+    :param tag: the tag
+    :param workspace: the workspace
+    """
+    if not(isinstance(tag, string_types) and isinstance(workspace, MatrixWorkspace)):
+        raise RuntimeError("SANSLogTagger: Either tag {0} or workspace are invalid. The tag has to be a string"
+                           " and the workspace {1} has to be a MatrixWorkspace".format(str(tag), str(workspace)))
+
+
+def set_tag(tag, value, workspace):
+    """
+    Adds/ sets a tag on a workspace
+
+    :param tag: the tag name
+    :param value: the tag value
+    :param workspace: the workspace to which the tag will be added.
+    """
+    check_if_valid_tag_and_workspace(tag, workspace)
+    run = workspace.getRun()
+    run.addProperty(tag, value, True)
+
+
+def get_tag(tag, workspace):
+    """
+    Extracts a tag from the workspace.
+
+    :param tag: the tag name
+    :param workspace: the workspace with the tag.
+    :return: the tag value if it exists else None
+    """
+    check_if_valid_tag_and_workspace(tag, workspace)
+    run = workspace.getRun()
+    return run[tag].value if tag in run else None
+
+
+def has_tag(tag, workspace):
+    """
+    Checks if workspace has a certain tag.
+
+    :param tag: the tag name.
+    :param workspace: the workspace to check.
+    :return: true if the tag exists else false.
+    """
+    check_if_valid_tag_and_workspace(tag, workspace)
+    run = workspace.getRun()
+    return tag in run
+
+
+def set_hash(tag, value, workspace):
+    """
+    Sets a value as a hashed tag on a workspace.
+
+    :param tag: the tag name
+    :param value: the tag value (which is converted to a hash)
+    :param workspace: the workspace
+    """
+    check_if_valid_tag_and_workspace(tag, workspace)
+    hash_value = get_hash_value(str(value))
+    set_tag(tag, hash_value, workspace)
+
+
+def has_hash(tag, value, workspace):
+    """
+    Checks if a certain hash exists on a workspace.
+
+    :param tag: the tag as a hash.
+    :param value: the value which is converted to a hash and checked.
+    :param workspace: the workspace.
+    :return: true if the hash exists on the workspace else false.
+    """
+    check_if_valid_tag_and_workspace(tag, workspace)
+    same_hash = False
+    if has_tag(tag, workspace):
+        saved_hash = get_tag(tag, workspace)
+        to_check_hash = get_hash_value(str(value))
+        same_hash = True if saved_hash == to_check_hash else False
+    return same_hash
diff --git a/scripts/SANS/sans/common/xml_parsing.py b/scripts/SANS/sans/common/xml_parsing.py
new file mode 100644
index 0000000000000000000000000000000000000000..cf4aad14425f73411f5054037f7bd711152c83a8
--- /dev/null
+++ b/scripts/SANS/sans/common/xml_parsing.py
@@ -0,0 +1,76 @@
+""" The elements of this module are used to extract information from IDF and IPF files."""
+
+# pylint: disable=invalid-name
+
+try:
+    import xml.etree.cElementTree as eTree
+except ImportError:
+    import xml.etree.ElementTree as eTree
+
+
+def get_named_elements_from_ipf_file(ipf_file, names_to_search, value_type):
+    """
+    Gets a named element from the IPF
+
+    This is useful for detector names etc.
+    :param ipf_file: the path to the IPF
+    :param names_to_search: the names we want to search for on the XML file.
+    :param value_type: the type we expect for the names.
+    :return: a ElementName vs Value map
+    """
+    """
+    Args:
+        ipf_file: The path to the IPF
+        names_to_search: A list of search names
+        value_type: the type of an item
+    Returns: A map of the search names and the found information
+    """
+    output = {}
+    number_of_elements_to_search = len(names_to_search)
+    for _, element in eTree.iterparse(ipf_file):
+        if element.tag == "parameter" and "name" in element.keys():
+            if element.get("name") in names_to_search:
+                sub_element = element.find("value")
+                value = sub_element.get("val")
+                output.update({element.get("name"): value_type(value)})
+                element.clear()
+                if number_of_elements_to_search == len(output):
+                    break
+    return output
+
+
+def get_monitor_names_from_idf_file(idf_file):
+    """
+    Gets the monitor names from the IDF
+
+    :param idf_file: the path to the IDF
+    :return: a NumberAsString vs Monitor Name map
+    """
+    def get_tag(tag_in):
+        return "{http://www.mantidproject.org/IDF/1.0}" + tag_in
+    output = {}
+    tag = "idlist"
+    idname = "idname"
+    id_tag = "id"
+    for _, element in eTree.iterparse(idf_file):
+        if element.tag == get_tag(tag) and idname in element.keys():
+            name = element.get(idname)
+            if "monitor" in name:
+                sub_element = element.find(get_tag(id_tag))
+                # We can have two situations here:
+                # 1. either monitors are separate, e.g. <idlist idname="monitor1"> <id val="1" /> </idlist>, ..
+                # 2. or in a range, e.g. <idlist idname="monitors"> <id start="1" end="8" /> </idlist>
+                val = sub_element.get("val")
+                start = sub_element.get("start")
+                end = sub_element.get("end")
+                if val:
+                    output.update({val: name})
+                    element.clear()
+                elif start and end:
+                    for index in range(int(start), int(end) + 1):
+                        monitor_id = "monitor" + str(index)
+                        output.update({str(index): monitor_id})
+                    element.clear()
+                else:
+                    continue
+    return output
diff --git a/scripts/SANS/sans/state/__init__.py b/scripts/SANS/sans/state/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/scripts/SANS/sans/state/adjustment.py b/scripts/SANS/sans/state/adjustment.py
new file mode 100644
index 0000000000000000000000000000000000000000..3efcc340c75640f6a200f6eab210e949e31daa87
--- /dev/null
+++ b/scripts/SANS/sans/state/adjustment.py
@@ -0,0 +1,89 @@
+# pylint: disable=too-few-public-methods
+
+"""State describing the adjustment workspace creation of the SANS reduction."""
+
+import json
+import copy
+from sans.state.state_base import (StateBase, TypedParameter, rename_descriptor_names, BoolParameter,
+                                   validator_sub_state)
+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
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# State
+# ----------------------------------------------------------------------------------------------------------------------
+@rename_descriptor_names
+class StateAdjustment(StateBase):
+    calculate_transmission = TypedParameter(StateCalculateTransmission, validator_sub_state)
+    normalize_to_monitor = TypedParameter(StateNormalizeToMonitor, validator_sub_state)
+    wavelength_and_pixel_adjustment = TypedParameter(StateWavelengthAndPixelAdjustment, validator_sub_state)
+    wide_angle_correction = BoolParameter()
+
+    def __init__(self):
+        super(StateAdjustment, self).__init__()
+        self.wide_angle_correction = False
+
+    def validate(self):
+        is_invalid = {}
+
+        # Calculate transmission
+        if not self.calculate_transmission:
+            is_invalid.update({"StateAdjustment": "The StateCalculateTransmission object is missing."})
+        if self.calculate_transmission:
+            try:
+                self.calculate_transmission.validate()
+            except ValueError as e:
+                is_invalid.update({"StateAdjustment": "The sub-CalculateTransmission state is invalid,"
+                                                      " see here {0}".format(str(e))})
+
+        # Normalize to monitor
+        if not self.normalize_to_monitor:
+            is_invalid.update({"StateAdjustment": "The StateNormalizeToMonitor object is missing."})
+        if self.normalize_to_monitor:
+            try:
+                self.normalize_to_monitor.validate()
+            except ValueError as e:
+                is_invalid.update({"StateAdjustment": "The sub-NormalizeToMonitor state is invalid,"
+                                                      " see here {0}".format(str(e))})
+
+        # Wavelength and pixel adjustment
+        if not self.wavelength_and_pixel_adjustment:
+            is_invalid.update({"StateAdjustment": "The StateWavelengthAndPixelAdjustment object is missing."})
+        if self.wavelength_and_pixel_adjustment:
+            try:
+                self.wavelength_and_pixel_adjustment.validate()
+            except ValueError as e:
+                is_invalid.update({"StateAdjustment": "The sub-WavelengthAndPixelAdjustment state is invalid,"
+                                                      " see here {0}".format(str(e))})
+        if is_invalid:
+            raise ValueError("StateAdjustment: The provided inputs are illegal. "
+                             "Please see: {0}".format(json.dumps(is_invalid)))
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# Builder
+# ----------------------------------------------------------------------------------------------------------------------
+class StateAdjustmentBuilder(object):
+    @automatic_setters(StateAdjustment)
+    def __init__(self):
+        super(StateAdjustmentBuilder, self).__init__()
+        self.state = StateAdjustment()
+
+    def build(self):
+        self.state.validate()
+        return copy.copy(self.state)
+
+
+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 instrument is of relevance.
+    instrument = data_info.instrument
+    if instrument is SANSInstrument.LARMOR or instrument is SANSInstrument.LOQ or instrument is SANSInstrument.SANS2D:
+        return StateAdjustmentBuilder()
+    else:
+        raise NotImplementedError("StateAdjustmentBuilder: Could not find any valid adjustment builder for the "
+                                  "specified StateData object {0}".format(str(data_info)))
diff --git a/scripts/SANS/sans/state/automatic_setters.py b/scripts/SANS/sans/state/automatic_setters.py
new file mode 100644
index 0000000000000000000000000000000000000000..427678c919cb23d91ae4e70f5ad8f8264abc794e
--- /dev/null
+++ b/scripts/SANS/sans/state/automatic_setters.py
@@ -0,0 +1,146 @@
+from functools import (partial, wraps)
+import inspect
+
+from sans.state.state_base import (TypedParameter, DictParameter)
+# -------------------------------------------------------------------------------------------------------------
+# Automatic Setter functionality
+# This creates setters on a builder/director instance for parameters of a state object.
+# The setter name generation is fairly simple. There are two scenarios
+# 1. Standard parameter: state -> parameter  results in setter name: "set_" + name of parameter
+# 2. Parameter which is buried in dictionary: state->dict->parameter
+#    This results in "set_" + dictionary key + name of parameter, e.g. set_HAB_x_translation_correction, where
+#    HAB is a key of a dictionary and x_translation_correction is the parameter name
+#
+# The resulting decorator automatic_setters takes the type of class (essentially which state) to operate on and
+# an exclusion list. Elements in the exclusion list will not have an automatic setter generated for them. This is
+# desirable for parameters which are set internally during the initialization phase of the builder.
+# -------------------------------------------------------------------------------------------------------------
+
+
+def forwarding_setter(value, builder_instance, attribute_name_list):
+    # The first element of the attribute list is the state object itself
+    instance = getattr(builder_instance, attribute_name_list[0])
+
+    # We need to exclude the first element, since we have already used. We also need to exclude the last
+    # element since we don't want to get it but rather set it. We need to treat the instance differently if it is
+    # a dictionary.
+    for index in range(1, len(attribute_name_list) - 1):
+        if isinstance(instance, dict):
+            instance = instance[attribute_name_list[index]]
+        else:
+            instance = getattr(instance, attribute_name_list[index])
+    # Finally, the last attribute name is used to set the value
+    setattr(instance, attribute_name_list[-1], value)
+
+
+def update_the_method(builder_instance,  new_methods, setter_name, attribute_name, attribute_name_list):
+    setter_name_copy = list(setter_name)
+    setter_name_copy.append(attribute_name)
+    method_name = "_".join(setter_name_copy)
+
+    attribute_name_list_copy = list(attribute_name_list)
+    attribute_name_list_copy.append(attribute_name)
+
+    new_method = partial(forwarding_setter, builder_instance=builder_instance,
+                         attribute_name_list=attribute_name_list_copy)
+    new_methods.update({method_name: new_method})
+
+
+def get_all_typed_parameter_descriptors(instance):
+    descriptor_types = {}
+    for descriptor_name, descriptor_object in inspect.getmembers(type(instance)):
+        if inspect.isdatadescriptor(descriptor_object) and isinstance(descriptor_object, TypedParameter):
+            descriptor_types.update({descriptor_name: descriptor_object})
+    return descriptor_types
+
+
+def create_automatic_setters_for_state(attribute_value, builder_instance, attribute_name_list,
+                                       setter_name, exclusions, new_methods):
+    # Find all typed parameter descriptors which are on the instance, i.e. on attribute_value.
+    all_descriptors = get_all_typed_parameter_descriptors(attribute_value)
+
+    # Go through each descriptor and create a setter for it.
+    for name, value in all_descriptors.items():
+        # If the name is in the exception list, then we don't want to create a setter for this attribute
+        if name in exclusions:
+            continue
+
+        # There are two scenarios. The attribute can be:
+        # 1. A dictionary which is empty or None-> install a setter
+        # 2. A dictionary containing elements -> for each element apply a recursion
+        # 3. A regular attribute -> install the setter
+        if isinstance(value, DictParameter):
+            dict_parameter_value = getattr(attribute_value, name)
+            if dict_parameter_value is None or len(dict_parameter_value) == 0:
+                update_the_method(builder_instance, new_methods, setter_name, name, attribute_name_list)
+            else:
+                for dict_key, dict_value in dict_parameter_value.items():
+                    setter_name_copy = list(setter_name)
+                    setter_name_copy.append(dict_key)
+
+                    # We need to add the dict name to the attribute list and the key we are looking at now
+                    attribute_name_list_copy = list(attribute_name_list)
+                    attribute_name_list_copy.append(name)
+                    attribute_name_list_copy.append(dict_key)
+                    create_automatic_setters_for_state(dict_value, builder_instance, attribute_name_list_copy,
+                                                       setter_name_copy, exclusions, new_methods)
+        else:
+            update_the_method(builder_instance, new_methods, setter_name, name, attribute_name_list)
+
+
+def create_automatic_setters(builder_instance, state_class, exclusions):
+    # Get the name of the state object
+    new_methods = {}
+    for attribute_name, attribute_value in builder_instance.__dict__.items():
+        if isinstance(attribute_value, state_class):
+            attribute_name_list = [attribute_name]
+            setter_name = ["set"]
+            create_automatic_setters_for_state(attribute_value, builder_instance, attribute_name_list,
+                                               setter_name, exclusions, new_methods)
+
+    # Apply the methods
+    for method_name, method in new_methods.items():
+        builder_instance.__dict__.update({method_name: method})
+
+
+def automatic_setters(state_class, exclusions=None):
+    if exclusions is None:
+        exclusions = []
+
+    def automatic_setters_decorator(func):
+        @wraps(func)
+        def func_wrapper(self, *args, **kwargs):
+            func(self, *args, **kwargs)
+            create_automatic_setters(self, state_class, exclusions)
+        return func_wrapper
+    return automatic_setters_decorator
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# Automatic setter for director object
+# Note that this is not a decorator, but just a free function for monkey patching.
+# ----------------------------------------------------------------------------------------------------------------------
+def forwarding_setter_for_director(value, builder, method_name):
+    method = getattr(builder, method_name)
+    method(value)
+
+
+def set_up_setter_forwarding_from_director_to_builder(director, builder_name):
+    """
+    This function creates setter forwarding from a director object to builder objects.
+
+    The method will look for any set_XXX method in the builder and add an equivalent method set_builder_XXX which is
+    forwarded to set_XXX.
+    @param director: a director object
+    @param builder_name: the name of the builder on the director
+    """
+    set_tag = "set"
+    builder_instance = getattr(director, builder_name)
+    new_methods = {}
+    for method in dir(builder_instance):
+        if method.startswith(set_tag):
+            method_name_director = set_tag + builder_name + "_" + method[4:]
+            new_method = partial(forwarding_setter_for_director, builder=builder_instance,
+                                 method_name=method)
+            new_methods.update({method_name_director: new_method})
+    director.__dict__.update(new_methods)
diff --git a/scripts/SANS/sans/state/calculate_transmission.py b/scripts/SANS/sans/state/calculate_transmission.py
new file mode 100644
index 0000000000000000000000000000000000000000..1388a6978831de4536f725b63c0939aa017cfdc7
--- /dev/null
+++ b/scripts/SANS/sans/state/calculate_transmission.py
@@ -0,0 +1,388 @@
+# pylint: disable=too-few-public-methods
+
+"""State describing the calculation of the transmission for SANS reduction."""
+
+import json
+import copy
+from sans.state.state_base import (StateBase, rename_descriptor_names, PositiveIntegerParameter, BoolParameter,
+                                   PositiveFloatParameter, ClassTypeParameter, FloatParameter, DictParameter,
+                                   StringListParameter, PositiveFloatWithNoneParameter)
+from sans.common.enums import (RebinType, RangeStepType, FitType, DataType, SANSInstrument)
+from sans.common.configurations import Configurations
+from sans.state.state_functions import (is_pure_none_or_not_none, validation_message,
+                                        is_not_none_and_first_larger_than_second, one_is_none)
+from sans.state.automatic_setters import (automatic_setters)
+from sans.common.file_information import (get_instrument_paths_for_sans_file)
+from sans.common.xml_parsing import get_named_elements_from_ipf_file
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# State
+# ----------------------------------------------------------------------------------------------------------------------
+@rename_descriptor_names
+class StateTransmissionFit(StateBase):
+    fit_type = ClassTypeParameter(FitType)
+    polynomial_order = PositiveIntegerParameter()
+    wavelength_low = PositiveFloatWithNoneParameter()
+    wavelength_high = PositiveFloatWithNoneParameter()
+
+    def __init__(self):
+        super(StateTransmissionFit, self).__init__()
+        self.fit_type = FitType.Linear
+        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.",
+                                       {"fit_type": self.fit_type,
+                                        "polynomial_order": self.polynomial_order})
+            is_invalid.update(entry)
+
+        if not is_pure_none_or_not_none([self.wavelength_low, self.wavelength_high]):
+            entry = validation_message("Inconsistent wavelength setting.",
+                                       "Make sure that you have specified both wavelength bounds (or none).",
+                                       {"wavelength_low": self.wavelength_low,
+                                        "wavelength_high": self.wavelength_high})
+            is_invalid.update(entry)
+
+        if is_not_none_and_first_larger_than_second([self.wavelength_low, self.wavelength_high]):
+            entry = validation_message("Incorrect wavelength bounds.",
+                                       "Make sure that lower wavelength bound is smaller then upper bound.",
+                                       {"wavelength_low": self.wavelength_low,
+                                        "wavelength_high": self.wavelength_high})
+            is_invalid.update(entry)
+        if is_invalid:
+            raise ValueError("StateTransmissionFit: The provided inputs are illegal. "
+                             "Please see: {0}".format(json.dumps(is_invalid)))
+
+
+@rename_descriptor_names
+class StateCalculateTransmission(StateBase):
+    # -----------------------
+    # Transmission
+    # -----------------------
+    transmission_radius_on_detector = PositiveFloatParameter()
+    transmission_roi_files = StringListParameter()
+    transmission_mask_files = StringListParameter()
+
+    default_transmission_monitor = PositiveIntegerParameter()
+    transmission_monitor = PositiveIntegerParameter()
+
+    default_incident_monitor = PositiveIntegerParameter()
+    incident_monitor = PositiveIntegerParameter()
+
+    # ----------------------
+    # Prompt peak correction
+    # ----------------------
+    prompt_peak_correction_min = PositiveFloatParameter()
+    prompt_peak_correction_max = PositiveFloatParameter()
+
+    # ----------------
+    # Wavelength rebin
+    # ----------------
+    rebin_type = ClassTypeParameter(RebinType)
+    wavelength_low = PositiveFloatParameter()
+    wavelength_high = PositiveFloatParameter()
+    wavelength_step = PositiveFloatParameter()
+    wavelength_step_type = ClassTypeParameter(RangeStepType)
+
+    use_full_wavelength_range = BoolParameter()
+    wavelength_full_range_low = PositiveFloatParameter()
+    wavelength_full_range_high = PositiveFloatParameter()
+
+    # -----------------------
+    # Background correction
+    # ----------------------
+    background_TOF_general_start = FloatParameter()
+    background_TOF_general_stop = FloatParameter()
+    background_TOF_monitor_start = DictParameter()
+    background_TOF_monitor_stop = DictParameter()
+    background_TOF_roi_start = FloatParameter()
+    background_TOF_roi_stop = FloatParameter()
+
+    # -----------------------
+    # Fit
+    # ----------------------
+    fit = DictParameter()
+
+    def __init__(self):
+        super(StateCalculateTransmission, self).__init__()
+        # The keys of this dictionaries are the spectrum number of the monitors (as a string)
+        self.background_TOF_monitor_start = {}
+        self.background_TOF_monitor_stop = {}
+
+        self.fit = {DataType.to_string(DataType.Sample): StateTransmissionFit(),
+                    DataType.to_string(DataType.Can): StateTransmissionFit()}
+        self.use_full_wavelength_range = False
+
+    def validate(self):  # noqa
+        is_invalid = {}
+        # -----------------
+        # Incident monitor
+        # -----------------
+        if self.incident_monitor is None and self.default_incident_monitor is None:
+            entry = validation_message("No incident monitor was specified.",
+                                       "Make sure that incident monitor has been specified.",
+                                       {"incident_monitor": self.incident_monitor,
+                                        "default_incident_monitor": self.default_incident_monitor})
+            is_invalid.update(entry)
+
+        # --------------
+        # Transmission, either we need some ROI (ie radius, roi files /mask files) or a transmission monitor
+        # --------------
+        has_no_transmission_monitor_setting = self.transmission_monitor is None and\
+                                              self.default_transmission_monitor is None  # noqa
+        has_no_transmission_roi_setting = self.transmission_radius_on_detector is None and\
+                                          self.transmission_roi_files is None  # noqa
+        if has_no_transmission_monitor_setting and has_no_transmission_roi_setting:
+            entry = validation_message("No transmission settings were specified.",
+                                       "Make sure that transmission settings are specified.",
+                                       {"transmission_monitor": self.transmission_monitor,
+                                        "default_transmission_monitor": self.default_transmission_monitor,
+                                        "transmission_radius_on_detector": self.transmission_radius_on_detector,
+                                        "transmission_roi_files": self.transmission_roi_files})
+            is_invalid.update(entry)
+
+        # -----------------
+        # Prompt peak
+        # -----------------
+        if not is_pure_none_or_not_none([self.prompt_peak_correction_min, self.prompt_peak_correction_max]):
+            entry = validation_message("Inconsistent prompt peak setting.",
+                                       "Make sure that you have specified both prompt peak bounds (or none).",
+                                       {"prompt_peak_correction_min": self.prompt_peak_correction_min,
+                                        "prompt_peak_correction_max": self.prompt_peak_correction_max})
+            is_invalid.update(entry)
+
+        if is_not_none_and_first_larger_than_second([self.prompt_peak_correction_min, self.prompt_peak_correction_max]):
+            entry = validation_message("Incorrect prompt peak bounds.",
+                                       "Make sure that lower prompt peak bound is smaller then upper bound.",
+                                       {"prompt_peak_correction_min": self.prompt_peak_correction_min,
+                                        "prompt_peak_correction_max": self.prompt_peak_correction_max})
+            is_invalid.update(entry)
+
+        # -----------------
+        # Wavelength rebin
+        # -----------------
+        if one_is_none([self.wavelength_low, self.wavelength_high, self.wavelength_step, self.wavelength_step_type,
+                        self.rebin_type]):
+            entry = validation_message("A wavelength entry has not been set.",
+                                       "Make sure that all entries are set.",
+                                       {"wavelength_low": self.wavelength_low,
+                                        "wavelength_high": self.wavelength_high,
+                                        "wavelength_step": self.wavelength_step,
+                                        "wavelength_step_type": self.wavelength_step_type,
+                                        "rebin_type": self.rebin_type})
+            is_invalid.update(entry)
+
+        if is_not_none_and_first_larger_than_second([self.wavelength_low, self.wavelength_high]):
+            entry = validation_message("Incorrect wavelength bounds.",
+                                       "Make sure that lower wavelength bound is smaller then upper bound.",
+                                       {"wavelength_low": self.wavelength_low,
+                                        "wavelength_high": self.wavelength_high})
+            is_invalid.update(entry)
+
+        if self.use_full_wavelength_range:
+            if self.wavelength_full_range_low is None or self.wavelength_full_range_high is None:
+                entry = validation_message("Incorrect full wavelength settings.",
+                                           "Make sure that both full wavelength entries have been set.",
+                                           {"wavelength_full_range_low": self.wavelength_full_range_low,
+                                            "wavelength_full_range_high": self.wavelength_full_range_high})
+                is_invalid.update(entry)
+            if is_not_none_and_first_larger_than_second([self.wavelength_full_range_low,
+                                                         self.wavelength_full_range_high]):
+                entry = validation_message("Incorrect wavelength bounds.",
+                                           "Make sure that lower full wavelength bound is smaller then upper bound.",
+                                           {"wavelength_full_range_low": self.wavelength_full_range_low,
+                                            "wavelength_full_range_high": self.wavelength_full_range_high})
+                is_invalid.update(entry)
+
+        # ----------------------
+        # Background correction
+        # ----------------------
+        if not is_pure_none_or_not_none([self.background_TOF_general_start, self.background_TOF_general_stop]):
+            entry = validation_message("A general background TOF entry has not been set.",
+                                       "Make sure that either all general background TOF entries are set or none.",
+                                       {"background_TOF_general_start": self.background_TOF_general_start,
+                                        "background_TOF_general_stop": self.background_TOF_general_stop})
+            is_invalid.update(entry)
+        if is_not_none_and_first_larger_than_second([self.background_TOF_general_start,
+                                                     self.background_TOF_general_stop]):
+            entry = validation_message("Incorrect general background TOF bounds.",
+                                       "Make sure that lower general background TOF bound is smaller then upper bound.",
+                                       {"background_TOF_general_start": self.background_TOF_general_start,
+                                        "background_TOF_general_stop": self.background_TOF_general_stop})
+            is_invalid.update(entry)
+
+        if not is_pure_none_or_not_none([self.background_TOF_roi_start, self.background_TOF_roi_stop]):
+            entry = validation_message("A ROI background TOF entry has not been set.",
+                                       "Make sure that either all ROI background TOF entries are set or none.",
+                                       {"background_TOF_roi_start": self.background_TOF_roi_start,
+                                        "background_TOF_roi_stop": self.background_TOF_roi_stop})
+            is_invalid.update(entry)
+
+        if is_not_none_and_first_larger_than_second([self.background_TOF_roi_start,
+                                                     self.background_TOF_roi_stop]):
+            entry = validation_message("Incorrect ROI background TOF bounds.",
+                                       "Make sure that lower ROI background TOF bound is smaller then upper bound.",
+                                       {"background_TOF_roi_start": self.background_TOF_roi_start,
+                                        "background_TOF_roi_stop": self.background_TOF_roi_stop})
+            is_invalid.update(entry)
+
+        if not is_pure_none_or_not_none([self.background_TOF_monitor_start, self.background_TOF_monitor_stop]):
+            entry = validation_message("A monitor background TOF entry has not been set.",
+                                       "Make sure that either all monitor background TOF entries are set or none.",
+                                       {"background_TOF_monitor_start": self.background_TOF_monitor_start,
+                                        "background_TOF_monitor_stop": self.background_TOF_monitor_stop})
+            is_invalid.update(entry)
+
+        if self.background_TOF_monitor_start is not None and self.background_TOF_monitor_stop is not None:
+            if len(self.background_TOF_monitor_start) != len(self.background_TOF_monitor_stop):
+                entry = validation_message("The monitor background TOF entries have a length mismatch.",
+                                           "Make sure that all monitor background TOF entries have the same length.",
+                                           {"background_TOF_monitor_start": self.background_TOF_monitor_start,
+                                            "background_TOF_monitor_stop": self.background_TOF_monitor_stop})
+                is_invalid.update(entry)
+            for key_start, value_start in self.background_TOF_monitor_start.items():
+                if key_start not in self.background_TOF_monitor_stop:
+                    entry = validation_message("The monitor background TOF had spectrum number mismatch.",
+                                               "Make sure that all monitors have entries for start and stop.",
+                                               {"background_TOF_monitor_start": self.background_TOF_monitor_start,
+                                                "background_TOF_monitor_stop": self.background_TOF_monitor_stop})
+                    is_invalid.update(entry)
+                else:
+                    value_stop = self.background_TOF_monitor_stop[key_start]
+                    if value_start > value_stop:
+                        entry = validation_message("Incorrect monitor background TOF bounds.",
+                                                   "Make sure that lower monitor background TOF bound is"
+                                                   " smaller then upper bound.",
+                                                   {"background_TOF_monitor_start": self.background_TOF_monitor_start,
+                                                    "background_TOF_monitor_stop": self.background_TOF_monitor_stop})
+                        is_invalid.update(entry)
+
+        # -----
+        # Fit
+        # -----
+        self.fit[DataType.to_string(DataType.Sample)].validate()
+        self.fit[DataType.to_string(DataType.Can)].validate()
+
+        if is_invalid:
+            raise ValueError("StateCalculateTransmission: The provided inputs are illegal. "
+                             "Please see: {0}".format(json.dumps(is_invalid)))
+
+
+class StateCalculateTransmissionLOQ(StateCalculateTransmission):
+    def __init__(self):
+        super(StateCalculateTransmissionLOQ, self).__init__()
+        # Set the LOQ full wavelength range
+        self.wavelength_full_range_low = Configurations.LOQ.wavelength_full_range_low
+        self.wavelength_full_range_high = Configurations.LOQ.wavelength_full_range_high
+
+        # Set the LOQ default range for prompt peak correction
+        self.prompt_peak_correction_min = Configurations.LOQ.prompt_peak_correction_min
+        self.prompt_peak_correction_max = Configurations.LOQ.prompt_peak_correction_max
+
+    def validate(self):
+        super(StateCalculateTransmissionLOQ, self).validate()
+
+
+class StateCalculateTransmissionSANS2D(StateCalculateTransmission):
+    def __init__(self):
+        super(StateCalculateTransmissionSANS2D, self).__init__()
+        # Set the LOQ full wavelength range
+        self.wavelength_full_range_low = Configurations.SANS2D.wavelength_full_range_low
+        self.wavelength_full_range_high = Configurations.SANS2D.wavelength_full_range_high
+
+    def validate(self):
+        super(StateCalculateTransmissionSANS2D, self).validate()
+
+
+class StateCalculateTransmissionLARMOR(StateCalculateTransmission):
+    def __init__(self):
+        super(StateCalculateTransmissionLARMOR, self).__init__()
+        # Set the LOQ full wavelength range
+        self.wavelength_full_range_low = Configurations.LARMOR.wavelength_full_range_low
+        self.wavelength_full_range_high = Configurations.LARMOR.wavelength_full_range_high
+
+    def validate(self):
+        super(StateCalculateTransmissionLARMOR, self).validate()
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# Builder
+# ----------------------------------------------------------------------------------------------------------------------
+def set_default_monitors(calculate_transmission_info, data_info):
+    """
+    The default incident monitor is stored on the IPF.
+    :param calculate_transmission_info: a StateCalculateTransmission object on which we set the default value
+    :param data_info: a StateData object
+    """
+    file_name = data_info.sample_scatter
+    _, ipf_path = get_instrument_paths_for_sans_file(file_name)
+    incident_tag = "default-incident-monitor-spectrum"
+    transmission_tag = "default-transmission-monitor-spectrum"
+    monitors_to_search = [incident_tag, transmission_tag]
+    found_monitor_spectrum = get_named_elements_from_ipf_file(ipf_path, monitors_to_search, int)
+    if incident_tag in found_monitor_spectrum:
+        calculate_transmission_info.default_incident_monitor = found_monitor_spectrum[incident_tag]
+    if transmission_tag in found_monitor_spectrum:
+        calculate_transmission_info.default_transmission_monitor = found_monitor_spectrum[transmission_tag]
+
+
+# ---------------------------------------
+# State builders
+# ---------------------------------------
+class StateCalculateTransmissionBuilderLOQ(object):
+    @automatic_setters(StateCalculateTransmissionLOQ)
+    def __init__(self, data_info):
+        super(StateCalculateTransmissionBuilderLOQ, self).__init__()
+        self._data = data_info
+        self.state = StateCalculateTransmissionLOQ()
+        set_default_monitors(self.state, self._data)
+
+    def build(self):
+        self.state.validate()
+        return copy.copy(self.state)
+
+
+class StateCalculateTransmissionBuilderSANS2D(object):
+    @automatic_setters(StateCalculateTransmissionSANS2D)
+    def __init__(self, data_info):
+        super(StateCalculateTransmissionBuilderSANS2D, self).__init__()
+        self._data = data_info
+        self.state = StateCalculateTransmissionSANS2D()
+        set_default_monitors(self.state, self._data)
+
+    def build(self):
+        self.state.validate()
+        return copy.copy(self.state)
+
+
+class StateCalculateTransmissionBuilderLARMOR(object):
+    @automatic_setters(StateCalculateTransmissionLARMOR)
+    def __init__(self, data_info):
+        super(StateCalculateTransmissionBuilderLARMOR, self).__init__()
+        self._data = data_info
+        self.state = StateCalculateTransmissionLARMOR()
+        set_default_monitors(self.state, self._data)
+
+    def build(self):
+        self.state.validate()
+        return copy.copy(self.state)
+
+
+# ------------------------------------------
+# Factory method for StateCalculateTransmissionBuilder
+# ------------------------------------------
+def get_calculate_transmission_builder(data_info):
+    instrument = data_info.instrument
+    if instrument is SANSInstrument.LARMOR:
+        return StateCalculateTransmissionBuilderLARMOR(data_info)
+    elif instrument is SANSInstrument.SANS2D:
+        return StateCalculateTransmissionBuilderSANS2D(data_info)
+    elif instrument is SANSInstrument.LOQ:
+        return StateCalculateTransmissionBuilderLOQ(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/convert_to_q.py b/scripts/SANS/sans/state/convert_to_q.py
new file mode 100644
index 0000000000000000000000000000000000000000..a41a566f6624f7e9b8b7fb0caee746b5c6986587
--- /dev/null
+++ b/scripts/SANS/sans/state/convert_to_q.py
@@ -0,0 +1,171 @@
+# pylint: disable=too-few-public-methods
+
+"""State describing the conversion to momentum transfer"""
+
+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.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)
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# State
+# ----------------------------------------------------------------------------------------------------------------------
+@rename_descriptor_names
+class StateConvertToQ(StateBase):
+    reduction_dimensionality = ClassTypeParameter(ReductionDimensionality)
+    use_gravity = BoolParameter()
+    gravity_extra_length = PositiveFloatParameter()
+    radius_cutoff = PositiveFloatParameter()
+    wavelength_cutoff = PositiveFloatParameter()
+
+    # 1D settings
+    # The complex binning instructions require a second step and a mid point, which produces:
+    #   start -> step -> mid -> step2 -> stop
+    # The simple form is:
+    #   start -> step -> stop
+    q_min = PositiveFloatParameter()
+    q_max = PositiveFloatParameter()
+    q_step = PositiveFloatParameter()
+    q_step_type = ClassTypeParameter(RangeStepType)
+    q_step2 = PositiveFloatParameter()
+    q_step_type2 = ClassTypeParameter(RangeStepType)
+    q_mid = PositiveFloatParameter()
+
+    # 2D settings
+    q_xy_max = PositiveFloatParameter()
+    q_xy_step = PositiveFloatParameter()
+    q_xy_step_type = ClassTypeParameter(RangeStepType)
+
+    # -----------------------
+    # Q Resolution specific
+    # ---------------------
+    use_q_resolution = BoolParameter()
+    q_resolution_collimation_length = PositiveFloatParameter()
+    q_resolution_delta_r = PositiveFloatParameter()
+    moderator_file = StringParameter()
+
+    # Circular aperture settings
+    q_resolution_a1 = PositiveFloatParameter()
+    q_resolution_a2 = PositiveFloatParameter()
+
+    # Rectangular aperture settings
+    q_resolution_h1 = PositiveFloatParameter()
+    q_resolution_h2 = PositiveFloatParameter()
+    q_resolution_w1 = PositiveFloatParameter()
+    q_resolution_w2 = PositiveFloatParameter()
+
+    def __init__(self):
+        super(StateConvertToQ, self).__init__()
+        self.reduction_dimensionality = ReductionDimensionality.OneDim
+        self.use_gravity = False
+        self.gravity_extra_length = 0.0
+        self.use_q_resolution = False
+        self.radius_cutoff = 0.0
+        self.wavelength_cutoff = 0.0
+
+    def validate(self):
+        is_invalid = {}
+
+        # 1D Q settings
+        if not is_pure_none_or_not_none([self.q_min, self.q_max]):
+            entry = validation_message("The q boundaries for the 1D reduction are inconsistent.",
+                                       "Make sure that both q boundaries are set (or none).",
+                                       {"q_min": self.q_min,
+                                        "q_max": self.q_max})
+            is_invalid.update(entry)
+        if is_not_none_and_first_larger_than_second([self.q_min, self.q_max]):
+            entry = validation_message("Incorrect q bounds for 1D reduction.",
+                                       "Make sure that the lower q bound is smaller than the upper q bound.",
+                                       {"q_min": self.q_min,
+                                        "q_max": self.q_max})
+            is_invalid.update(entry)
+
+        if self.reduction_dimensionality is ReductionDimensionality.OneDim:
+            if self.q_min is None or self.q_max is None:
+                entry = validation_message("Q bounds not set for 1D reduction.",
+                                           "Make sure to set the q boundaries when using a 1D reduction.",
+                                           {"q_min": self.q_min,
+                                            "q_max": self.q_max})
+                is_invalid.update(entry)
+
+        if self.reduction_dimensionality is ReductionDimensionality.TwoDim:
+            if self.q_xy_max is None or self.q_xy_step is None:
+                entry = validation_message("Q bounds not set for 2D reduction.",
+                                           "Make sure that the q_max value bound and the step for the 2D reduction.",
+                                           {"q_xy_max": self.q_xy_max,
+                                            "q_xy_step": self.q_xy_step})
+                is_invalid.update(entry)
+
+        # Q Resolution settings
+        if self.use_q_resolution:
+            if not is_pure_none_or_not_none([self.q_resolution_a1, self.q_resolution_a2]):
+                entry = validation_message("Inconsistent circular geometry.",
+                                           "Make sure that both diameters for the circular apertures are set.",
+                                           {"q_resolution_a1": self.q_resolution_a1,
+                                            "q_resolution_a2": self.q_resolution_a2})
+                is_invalid.update(entry)
+            if not is_pure_none_or_not_none([self.q_resolution_h1, self.q_resolution_h2, self.q_resolution_w1,
+                                             self.q_resolution_w2]):
+                entry = validation_message("Inconsistent rectangular geometry.",
+                                           "Make sure that both diameters for the circular apertures are set.",
+                                           {"q_resolution_h1": self.q_resolution_h1,
+                                            "q_resolution_h2": self.q_resolution_h2,
+                                            "q_resolution_w1": self.q_resolution_w1,
+                                            "q_resolution_w2": self.q_resolution_w2})
+                is_invalid.update(entry)
+
+            if all(element is None for element in [self.q_resolution_a1, self.q_resolution_a2, self.q_resolution_w1,
+                                                   self.q_resolution_w2, self.q_resolution_h1, self.q_resolution_h2]):
+                entry = validation_message("Aperture is undefined.",
+                                           "Make sure that you set the geometry for a circular or a "
+                                           "rectangular aperture.",
+                                           {"q_resolution_a1": self.q_resolution_a1,
+                                            "q_resolution_a2": self.q_resolution_a2,
+                                            "q_resolution_h1": self.q_resolution_h1,
+                                            "q_resolution_h2": self.q_resolution_h2,
+                                            "q_resolution_w1": self.q_resolution_w1,
+                                            "q_resolution_w2": self.q_resolution_w2})
+                is_invalid.update(entry)
+            if self.moderator_file is None:
+                entry = validation_message("Missing moderator file.",
+                                           "Make sure to specify a moderator file when using q resolution.",
+                                           {"moderator_file": self.moderator_file})
+                is_invalid.update(entry)
+                is_invalid.update({"moderator_file": "A moderator file is required for the q resolution calculation."})
+
+        if is_invalid:
+            raise ValueError("StateMoveDetectorISIS: The provided inputs are illegal. "
+                             "Please see: {0}".format(json.dumps(is_invalid)))
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# Builder
+# ----------------------------------------------------------------------------------------------------------------------
+class StateConvertToQBuilder(object):
+    @automatic_setters(StateConvertToQ)
+    def __init__(self):
+        super(StateConvertToQBuilder, self).__init__()
+        self.state = StateConvertToQ()
+
+    def build(self):
+        self.state.validate()
+        return copy.copy(self.state)
+
+
+# ------------------------------------------
+# 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:
+        return StateConvertToQBuilder()
+    else:
+        raise NotImplementedError("StateConvertToQBuilder: Could not find any valid save builder for the "
+                                  "specified StateData object {0}".format(str(data_info)))
diff --git a/scripts/SANS/sans/state/data.py b/scripts/SANS/sans/state/data.py
new file mode 100644
index 0000000000000000000000000000000000000000..8042264a3168d9acf5b5e5aa81cf7b2a4356795f
--- /dev/null
+++ b/scripts/SANS/sans/state/data.py
@@ -0,0 +1,140 @@
+# pylint: disable=too-few-public-methods
+
+"""State about the actual data which is to be reduced."""
+
+import json
+import copy
+
+from sans.state.state_base import (StateBase, StringParameter, PositiveIntegerParameter,
+                                   ClassTypeParameter, rename_descriptor_names)
+from sans.common.enums import (SANSInstrument, SANSFacility)
+from sans.common.constants import ALL_PERIODS
+from sans.state.state_functions import (is_pure_none_or_not_none, validation_message)
+from sans.common.file_information import SANSFileInformationFactory
+from sans.state.automatic_setters import automatic_setters
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# State
+# ----------------------------------------------------------------------------------------------------------------------
+@rename_descriptor_names
+class StateData(StateBase):
+    ALL_PERIODS = ALL_PERIODS
+    sample_scatter = StringParameter()
+    sample_scatter_period = PositiveIntegerParameter()
+    sample_transmission = StringParameter()
+    sample_transmission_period = PositiveIntegerParameter()
+    sample_direct = StringParameter()
+    sample_direct_period = PositiveIntegerParameter()
+
+    can_scatter = StringParameter()
+    can_scatter_period = PositiveIntegerParameter()
+    can_transmission = StringParameter()
+    can_transmission_period = PositiveIntegerParameter()
+    can_direct = StringParameter()
+    can_direct_period = PositiveIntegerParameter()
+
+    calibration = StringParameter()
+
+    sample_scatter_run_number = PositiveIntegerParameter()
+    instrument = ClassTypeParameter(SANSInstrument)
+
+    def __init__(self):
+        super(StateData, self).__init__()
+
+        # Setup default values for periods
+        self.sample_scatter_period = StateData.ALL_PERIODS
+        self.sample_transmission_period = StateData.ALL_PERIODS
+        self.sample_direct_period = StateData.ALL_PERIODS
+
+        self.can_scatter_period = StateData.ALL_PERIODS
+        self.can_transmission_period = StateData.ALL_PERIODS
+        self.can_direct_period = StateData.ALL_PERIODS
+
+        # 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
+
+    def validate(self):
+        is_invalid = dict()
+
+        # A sample scatter must be specified
+        if self.sample_scatter is None:
+            entry = validation_message("Sample scatter was not specified.",
+                                       "Make sure that the sample scatter file is specified.",
+                                       {"sample_scatter": self.sample_scatter})
+            is_invalid.update(entry)
+
+        # If the sample transmission/direct was specified, then a sample direct/transmission is required
+        if not is_pure_none_or_not_none([self.sample_transmission, self.sample_direct]):
+            entry = validation_message("If the sample transmission is specified then, the direct run needs to be "
+                                       "specified too.",
+                                       "Make sure that the transmission and direct runs are both specified (or none).",
+                                       {"sample_transmission": self.sample_transmission,
+                                        "sample_direct": self.sample_direct})
+            is_invalid.update(entry)
+
+        # If the can transmission/direct was specified, then this requires the can scatter
+        if (self.can_direct or self.can_transmission) and (not self.can_scatter):
+            entry = validation_message("If the can transmission is specified then the can scatter run needs to be "
+                                       "specified too.",
+                                       "Make sure that the can scatter file is set.",
+                                       {"can_scatter": self.can_scatter,
+                                        "can_transmission": self.can_transmission,
+                                        "can_direct": self.can_direct})
+            is_invalid.update(entry)
+
+        # If a can transmission/direct was specified, then the other can entries need to be specified as well.
+        if self.can_scatter and not is_pure_none_or_not_none([self.can_transmission, self.can_direct]):
+            entry = validation_message("Inconsistent can transmission setting.",
+                                       "Make sure that the can transmission and can direct runs are set (or none of"
+                                       " them).",
+                                       {"can_transmission": self.can_transmission,
+                                        "can_direct": self.can_direct})
+            is_invalid.update(entry)
+
+        if is_invalid:
+            raise ValueError("StateData: The provided inputs are illegal. "
+                             "Please see: {0}".format(json.dumps(is_invalid)))
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# Builder
+# ----------------------------------------------------------------------------------------------------------------------
+def set_information_from_file(data_info):
+    file_name = data_info.sample_scatter
+    file_information_factory = SANSFileInformationFactory()
+    file_information = file_information_factory.create_sans_file_information(file_name)
+    instrument = file_information.get_instrument()
+    run_number = file_information.get_run_number()
+    data_info.instrument = instrument
+    data_info.sample_scatter_run_number = run_number
+
+
+class StateDataBuilder(object):
+    @automatic_setters(StateData)
+    def __init__(self):
+        super(StateDataBuilder, self).__init__()
+        self.state = StateData()
+
+    def build(self):
+        # Make sure that the product is in a valid state, ie not incomplete
+        self.state.validate()
+
+        # There are some elements which need to be read from the file. This is currently:
+        # 1. instrument
+        # 2. sample_scatter_run_number
+        set_information_from_file(self.state)
+
+        return copy.copy(self.state)
+
+
+# ------------------------------------------
+# Factory method for StateDataBuilder
+# ------------------------------------------
+def get_data_builder(facility):
+    if facility is SANSFacility.ISIS:
+        return StateDataBuilder()
+    else:
+        raise NotImplementedError("StateDataBuilder: The selected facility {0} does not seem"
+                                  " to exist".format(str(facility)))
diff --git a/scripts/SANS/sans/state/mask.py b/scripts/SANS/sans/state/mask.py
new file mode 100644
index 0000000000000000000000000000000000000000..8c96299d50518ff2bbfa470632ed288a793eddcc
--- /dev/null
+++ b/scripts/SANS/sans/state/mask.py
@@ -0,0 +1,273 @@
+# pylint: disable=too-few-public-methods
+
+"""State describing the masking behaviour of the SANS reduction."""
+
+import json
+import copy
+from sans.state.state_base import (StateBase, BoolParameter, StringListParameter, StringParameter,
+                                   PositiveFloatParameter, FloatParameter, FloatListParameter,
+                                   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)
+from sans.common.file_information import find_full_file_path
+from sans.common.enums import (SANSInstrument, DetectorType)
+from sans.common.file_information import (get_instrument_paths_for_sans_file)
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# State
+# ----------------------------------------------------------------------------------------------------------------------
+def range_check(start, stop, invalid_dict, start_name, stop_name, general_name=None):
+    """
+    Checks a start container against a stop container
+
+    :param start: The start container
+    :param stop:  the stop container
+    :param invalid_dict: The invalid dict to which we write our error messages
+    :param start_name: The name of the start container
+    :param stop_name: The name of the stop container
+    :param general_name: The general name of this container family
+    :return: A (potentially) updated invalid_dict
+    """
+    if not is_pure_none_or_not_none([start, stop]):
+        entry = validation_message("A range element has not been set.",
+                                   "Make sure that all entries are set.",
+                                   {start_name: start,
+                                    stop_name: stop})
+        invalid_dict.update(entry)
+
+    if start is not None and stop is not None:
+        # Start and stop need to have the same length
+        if len(start) != len(stop):
+            entry = validation_message("Start and stop ranges have different lengths.",
+                                       "Make sure that all entries for {0} he same length.".format(general_name),
+                                       {start_name: start,
+                                        stop_name: stop})
+            invalid_dict.update(entry)
+        # Start values need to be smaller than the stop values
+        for a, b in zip(start, stop):
+            if a > b:
+                entry = validation_message("Incorrect start-stop bounds.",
+                                           "Make sure the lower bound is smaller than the upper bound for {0}."
+                                           "".format(general_name),
+                                           {start_name: start,
+                                            stop_name: stop})
+                invalid_dict.update(entry)
+    return invalid_dict
+
+
+# ------------------------------------------------
+# StateData
+# ------------------------------------------------
+@rename_descriptor_names
+class StateMaskDetector(StateBase):
+    # Vertical strip masks
+    single_vertical_strip_mask = PositiveIntegerListParameter()
+    range_vertical_strip_start = PositiveIntegerListParameter()
+    range_vertical_strip_stop = PositiveIntegerListParameter()
+
+    # Horizontal strip masks
+    single_horizontal_strip_mask = PositiveIntegerListParameter()
+    range_horizontal_strip_start = PositiveIntegerListParameter()
+    range_horizontal_strip_stop = PositiveIntegerListParameter()
+
+    # Spectrum Block
+    block_horizontal_start = PositiveIntegerListParameter()
+    block_horizontal_stop = PositiveIntegerListParameter()
+    block_vertical_start = PositiveIntegerListParameter()
+    block_vertical_stop = PositiveIntegerListParameter()
+
+    # Spectrum block cross
+    block_cross_horizontal = PositiveIntegerListParameter()
+    block_cross_vertical = PositiveIntegerListParameter()
+
+    # Time/Bin mask
+    bin_mask_start = FloatListParameter()
+    bin_mask_stop = FloatListParameter()
+
+    # Name of the detector
+    detector_name = StringParameter()
+    detector_name_short = StringParameter()
+
+    def __init__(self):
+        super(StateMaskDetector, self).__init__()
+
+    def validate(self):
+        is_invalid = {}
+        # --------------------
+        # Vertical strip mask
+        # --------------------
+        range_check(self.range_vertical_strip_start, self.range_vertical_strip_stop,
+                    is_invalid, "range_vertical_strip_start", "range_vertical_strip_stop", "range_vertical_strip")
+
+        # --------------------
+        # Horizontal strip mask
+        # --------------------
+        range_check(self.range_horizontal_strip_start, self.range_horizontal_strip_stop,
+                    is_invalid, "range_horizontal_strip_start", "range_horizontal_strip_stop", "range_horizontal_strip")
+
+        # --------------------
+        # Block mask
+        # --------------------
+        range_check(self.block_horizontal_start, self.block_horizontal_stop,
+                    is_invalid, "block_horizontal_start", "block_horizontal_stop", "block_horizontal")
+        range_check(self.block_vertical_start, self.block_vertical_stop,
+                    is_invalid, "block_vertical_start", "block_vertical_stop", "block_vertical")
+
+        # --------------------
+        # Time/Bin mask
+        # --------------------
+        range_check(self.bin_mask_start, self.bin_mask_stop,
+                    is_invalid, "bin_mask_start", "bin_mask_stop", "bin_mask")
+
+        if not self.detector_name:
+            entry = validation_message("Missing detector name.",
+                                       "Make sure that the detector names are set.",
+                                       {"detector_name": self.detector_name})
+            is_invalid.update(entry)
+        if not self.detector_name_short:
+            entry = validation_message("Missing short detector name.",
+                                       "Make sure that the short detector names are set.",
+                                       {"detector_name_short": self.detector_name_short})
+            is_invalid.update(entry)
+        if is_invalid:
+            raise ValueError("StateMoveDetectorISIS: The provided inputs are illegal. "
+                             "Please see: {0}".format(json.dumps(is_invalid)))
+
+
+@rename_descriptor_names
+class StateMask(StateBase):
+    # Radius Mask
+    radius_min = FloatParameter()
+    radius_max = FloatParameter()
+
+    # Bin mask
+    bin_mask_general_start = FloatListParameter()
+    bin_mask_general_stop = FloatListParameter()
+
+    # Mask files
+    mask_files = StringListParameter()
+
+    # Angle masking
+    phi_min = FloatParameter()
+    phi_max = FloatParameter()
+    use_mask_phi_mirror = BoolParameter()
+
+    # Beam stop
+    beam_stop_arm_width = PositiveFloatParameter()
+    beam_stop_arm_angle = FloatParameter()
+    beam_stop_arm_pos1 = FloatParameter()
+    beam_stop_arm_pos2 = FloatParameter()
+
+    # Clear commands
+    clear = BoolParameter()
+    clear_time = BoolParameter()
+
+    # Single Spectra
+    single_spectra = PositiveIntegerListParameter()
+
+    # Spectrum Range
+    spectrum_range_start = PositiveIntegerListParameter()
+    spectrum_range_stop = PositiveIntegerListParameter()
+
+    # The detector dependent masks
+    detectors = DictParameter()
+
+    # The idf path of the instrument
+    idf_path = StringParameter()
+
+    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 = ""
+
+    def validate(self):
+        is_invalid = dict()
+
+        # --------------------
+        # Radius Mask
+        # --------------------
+        # Radius mask rule: the min radius must be less or equal to the max radius
+        if self.radius_max is not None and self.radius_min is not None and\
+           self.radius_max != -1 and self.radius_min != -1:  # noqa
+            if self.radius_min > 0 and self.radius_max > 0 and (self.radius_min > self.radius_max):
+                entry = validation_message("Incorrect radius bounds.",
+                                           "Makes sure that the lower radius bound is smaller than the"
+                                           " upper radius bound.",
+                                           {"radius_min": self.radius_min,
+                                            "radius_max": self.radius_max})
+                is_invalid.update(entry)
+
+        # --------------------
+        # General bin mask
+        # --------------------
+        range_check(self.bin_mask_general_start, self.bin_mask_general_stop,
+                    is_invalid, "bin_mask_general_start", "bin_mask_general_stop", "bin_mask_general")
+
+        # --------------------
+        # Mask files
+        # --------------------
+        if self.mask_files:
+            for mask_file in self.mask_files:
+                if not find_full_file_path(mask_file):
+                    entry = validation_message("Mask file not found.",
+                                               "Makes sure that the mask file is in your path",
+                                               {"mask_file": self.mask_file})
+                    is_invalid.update(entry)
+
+        # --------------------
+        # Spectrum Range
+        # --------------------
+        range_check(self.spectrum_range_start, self.spectrum_range_stop,
+                    is_invalid, "spectrum_range_start", "spectrum_range_stop", "spectrum_range")
+
+        # --------------------
+        # Detectors
+        # --------------------
+        for _, value in self.detectors.items():
+            value.validate()
+
+        if is_invalid:
+            raise ValueError("StateMask: The provided inputs are illegal. "
+                             "Please see: {0}".format(json.dumps(is_invalid)))
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# Builder
+# ----------------------------------------------------------------------------------------------------------------------
+def setup_idf_and_ipf_content(move_info, data_info):
+    # Get the IDF and IPF path since they contain most of the import information
+    file_name = data_info.sample_scatter
+    idf_path, ipf_path = get_instrument_paths_for_sans_file(file_name)
+    # Set the detector names
+    set_detector_names(move_info, ipf_path)
+    # Set the idf path
+    move_info.idf_path = idf_path
+
+
+class StateMaskBuilder(object):
+    @automatic_setters(StateMask)
+    def __init__(self, data_info):
+        super(StateMaskBuilder, self).__init__()
+        self._data = data_info
+        self.state = StateMask()
+        setup_idf_and_ipf_content(self.state, data_info)
+
+    def build(self):
+        self.state.validate()
+        return copy.copy(self.state)
+
+
+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.
+    instrument = data_info.instrument
+    if instrument is SANSInstrument.LARMOR or instrument is SANSInstrument.LOQ or instrument is SANSInstrument.SANS2D:
+        return StateMaskBuilder(data_info)
+    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
new file mode 100644
index 0000000000000000000000000000000000000000..9fff81134be4ec03c07db46aace66d8e4baab425
--- /dev/null
+++ b/scripts/SANS/sans/state/move.py
@@ -0,0 +1,266 @@
+# pylint: disable=too-few-public-methods, too-many-instance-attributes
+
+"""State for moving workspaces."""
+
+import json
+import copy
+
+from sans.state.state_base import (StateBase, FloatParameter, DictParameter, ClassTypeParameter,
+                                   StringParameter, rename_descriptor_names)
+from sans.common.enums import (Coordinates, CanonicalCoordinates, SANSInstrument, DetectorType)
+from sans.common.file_information import (get_instrument_paths_for_sans_file)
+from sans.state.automatic_setters import automatic_setters
+from sans.state.state_functions import (validation_message, set_detector_names, set_monitor_names)
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# State
+# ----------------------------------------------------------------------------------------------------------------------
+@rename_descriptor_names
+class StateMoveDetector(StateBase):
+    x_translation_correction = FloatParameter()
+    y_translation_correction = FloatParameter()
+    z_translation_correction = FloatParameter()
+
+    rotation_correction = FloatParameter()
+    side_correction = FloatParameter()
+    radius_correction = FloatParameter()
+
+    x_tilt_correction = FloatParameter()
+    y_tilt_correction = FloatParameter()
+    z_tilt_correction = FloatParameter()
+
+    sample_centre_pos1 = FloatParameter()
+    sample_centre_pos2 = FloatParameter()
+
+    # Name of the detector
+    detector_name = StringParameter()
+    detector_name_short = StringParameter()
+
+    def __init__(self):
+        super(StateMoveDetector, self).__init__()
+        # Translation correction
+        self.x_translation_correction = 0.0
+        self.y_translation_correction = 0.0
+        self.z_translation_correction = 0.0
+
+        self.rotation_correction = 0.0
+        self.side_correction = 0.0
+        self.radius_correction = 0.0
+
+        self.x_tilt_correction = 0.0
+        self.y_tilt_correction = 0.0
+        self.z_tilt_correction = 0.0
+
+        # Sample centre Pos 1 + Pos 2
+        self.sample_centre_pos1 = 0.0
+        self.sample_centre_pos2 = 0.0
+
+    def validate(self):
+        is_invalid = {}
+        if not self.detector_name:
+            entry = validation_message("Missing detector name",
+                                       "Make sure that a detector name was specified.",
+                                       {"detector_name": self.detector_name})
+            is_invalid.update(entry)
+        if not self.detector_name_short:
+            entry = validation_message("Missing short detector name",
+                                       "Make sure that a short detector name was specified.",
+                                       {"detector_name_short": self.detector_name_short})
+            is_invalid.update(entry)
+        if is_invalid:
+            raise ValueError("StateMoveDetectorISIS: The provided inputs are illegal. "
+                             "Please see: {0}".format(json.dumps(is_invalid)))
+
+
+@rename_descriptor_names
+class StateMove(StateBase):
+    sample_offset = FloatParameter()
+    sample_offset_direction = ClassTypeParameter(Coordinates)
+    detectors = DictParameter()
+
+    def __init__(self):
+        super(StateMove, self).__init__()
+
+        # Setup the sample offset
+        self.sample_offset = 0.0
+
+        # The sample offset direction is Z for the ISIS instruments
+        self.sample_offset_direction = CanonicalCoordinates.Z
+
+        # Setup the detectors
+        self.detectors = {DetectorType.to_string(DetectorType.LAB): StateMoveDetector(),
+                          DetectorType.to_string(DetectorType.HAB): StateMoveDetector()}
+
+    def validate(self):
+        # No validation of the descriptors on this level, let potential exceptions from detectors "bubble" up
+        for key in self.detectors:
+            self.detectors[key].validate()
+
+
+@rename_descriptor_names
+class StateMoveLOQ(StateMove):
+    monitor_names = DictParameter()
+    center_position = FloatParameter()
+
+    def __init__(self):
+        super(StateMoveLOQ, self).__init__()
+        # Set the center_position in meter
+        self.center_position = 317.5 / 1000.
+
+        # Set the monitor names
+        self.monitor_names = {}
+
+    def validate(self):
+        # No validation of the descriptors on this level, let potential exceptions from detectors "bubble" up
+        super(StateMoveLOQ, self).validate()
+
+
+@rename_descriptor_names
+class StateMoveSANS2D(StateMove):
+    monitor_names = DictParameter()
+
+    hab_detector_radius = FloatParameter()
+    hab_detector_default_sd_m = FloatParameter()
+    hab_detector_default_x_m = FloatParameter()
+
+    lab_detector_default_sd_m = FloatParameter()
+
+    hab_detector_x = FloatParameter()
+    hab_detector_z = FloatParameter()
+
+    hab_detector_rotation = FloatParameter()
+
+    lab_detector_x = FloatParameter()
+    lab_detector_z = FloatParameter()
+
+    monitor_4_offset = FloatParameter()
+
+    def __init__(self):
+        super(StateMoveSANS2D, self).__init__()
+        # Set the descriptors which corresponds to information which we gain through the IPF
+        self.hab_detector_radius = 306.0 / 1000.
+        self.hab_detector_default_sd_m = 4.0
+        self.hab_detector_default_x_m = 1.1
+        self.lab_detector_default_sd_m = 4.0
+
+        # The actual values are found on the workspace and should be used from there. This is only a fall back.
+        self.hab_detector_x = 0.0
+        self.hab_detector_z = 0.0
+        self.hab_detector_rotation = 0.0
+        self.lab_detector_x = 0.0
+        self.lab_detector_z = 0.0
+
+        # Set the monitor names
+        self.monitor_names = {}
+
+        self.monitor_4_offset = 0.0
+
+    def validate(self):
+        super(StateMoveSANS2D, self).validate()
+
+
+@rename_descriptor_names
+class StateMoveLARMOR(StateMove):
+    monitor_names = DictParameter()
+    bench_rotation = FloatParameter()
+
+    def __init__(self):
+        super(StateMoveLARMOR, self).__init__()
+
+        # Set a default for the bench rotation
+        self.bench_rotation = 0.0
+
+        # Set the monitor names
+        self.monitor_names = {}
+
+    def validate(self):
+        super(StateMoveLARMOR, self).validate()
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# Builder
+# ----------------------------------------------------------------------------------------------------------------------
+def setup_idf_and_ipf_content(move_info, data_info):
+    # Get the IDF and IPF path since they contain most of the import information
+    file_name = data_info.sample_scatter
+    idf_path, ipf_path = get_instrument_paths_for_sans_file(file_name)
+    # Set the detector names
+    set_detector_names(move_info, ipf_path)
+    # Set the monitor names
+    set_monitor_names(move_info, idf_path)
+
+
+class StateMoveLOQBuilder(object):
+    @automatic_setters(StateMoveLOQ, exclusions=["detector_name", "detector_name_short", "monitor_names"])
+    def __init__(self, data_info):
+        super(StateMoveLOQBuilder, self).__init__()
+        self.state = StateMoveLOQ()
+        setup_idf_and_ipf_content(self.state, data_info)
+
+    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 StateMoveSANS2DBuilder(object):
+    @automatic_setters(StateMoveSANS2D, exclusions=["detector_name", "detector_name_short", "monitor_names"])
+    def __init__(self, data_info):
+        super(StateMoveSANS2DBuilder, self).__init__()
+        self.state = StateMoveSANS2D()
+        setup_idf_and_ipf_content(self.state, data_info)
+
+    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):
+        super(StateMoveLARMORBuilder, self).__init__()
+        self.state = StateMoveLARMOR()
+        setup_idf_and_ipf_content(self.state, data_info)
+        self.conversion_value = 1000.
+        self._set_conversion_value(data_info)
+
+    def _set_conversion_value(self, data_info):
+        run_number = data_info.sample_scatter_run_number
+        self.conversion_value = 1000. if run_number >= 2217 else 1.
+
+    def build(self):
+        self.state.validate()
+        return copy.copy(self.state)
+
+    def convert_pos1(self, value):
+        return value / self.conversion_value
+
+    def convert_pos2(self, value):
+        return value / 1000.
+
+
+def get_move_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.LOQ:
+        return StateMoveLOQBuilder(data_info)
+    elif instrument is SANSInstrument.SANS2D:
+        return StateMoveSANS2DBuilder(data_info)
+    elif instrument is SANSInstrument.LARMOR:
+        return StateMoveLARMORBuilder(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
new file mode 100644
index 0000000000000000000000000000000000000000..3b037e399d237aacfdfca7a15b6864c466949906
--- /dev/null
+++ b/scripts/SANS/sans/state/normalize_to_monitor.py
@@ -0,0 +1,206 @@
+# pylint: disable=too-few-public-methods
+
+"""State describing the normalization to the incident monitor for SANS reduction."""
+
+import json
+import copy
+from sans.state.state_base import (StateBase, rename_descriptor_names, PositiveIntegerParameter,
+                                   PositiveFloatParameter, FloatParameter, ClassTypeParameter, DictParameter,
+                                   PositiveFloatWithNoneParameter)
+from sans.state.automatic_setters import (automatic_setters)
+from sans.common.enums import (RebinType, RangeStepType, SANSInstrument)
+from sans.state.state_functions import (is_pure_none_or_not_none, is_not_none_and_first_larger_than_second,
+                                        one_is_none, validation_message)
+from sans.common.xml_parsing import get_named_elements_from_ipf_file
+from sans.common.file_information import (get_instrument_paths_for_sans_file)
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# State
+# ----------------------------------------------------------------------------------------------------------------------
+@rename_descriptor_names
+class StateNormalizeToMonitor(StateBase):
+    prompt_peak_correction_min = PositiveFloatWithNoneParameter()
+    prompt_peak_correction_max = PositiveFloatWithNoneParameter()
+
+    rebin_type = ClassTypeParameter(RebinType)
+    wavelength_low = PositiveFloatParameter()
+    wavelength_high = PositiveFloatParameter()
+    wavelength_step = PositiveFloatParameter()
+    wavelength_step_type = ClassTypeParameter(RangeStepType)
+
+    background_TOF_general_start = FloatParameter()
+    background_TOF_general_stop = FloatParameter()
+    background_TOF_monitor_start = DictParameter()
+    background_TOF_monitor_stop = DictParameter()
+
+    incident_monitor = PositiveIntegerParameter()
+
+    def __init__(self):
+        super(StateNormalizeToMonitor, self).__init__()
+        self.background_TOF_monitor_start = {}
+        self.background_TOF_monitor_stop = {}
+
+    def validate(self):
+        is_invalid = {}
+        # -----------------
+        # incident Monitor
+        # -----------------
+        if self.incident_monitor is None:
+            is_invalid.update({"incident_monitor": "An incident monitor must be specified."})
+
+        # -----------------
+        # Prompt peak
+        # -----------------
+        if not is_pure_none_or_not_none([self.prompt_peak_correction_min, self.prompt_peak_correction_max]):
+            entry = validation_message("A prompt peak correction entry has not been set.",
+                                       "Make sure that either all prompt peak entries have been set or none.",
+                                       {"prompt_peak_correction_min": self.prompt_peak_correction_min,
+                                        "prompt_peak_correction_max": self.prompt_peak_correction_max})
+            is_invalid.update(entry)
+
+        if is_not_none_and_first_larger_than_second([self.prompt_peak_correction_min, self.prompt_peak_correction_max]):
+            entry = validation_message("Incorrect prompt peak correction bounds.",
+                                       "Make sure that lower prompt peak time bound is smaller then upper bound.",
+                                       {"prompt_peak_correction_min": self.prompt_peak_correction_min,
+                                        "prompt_peak_correction_max": self.prompt_peak_correction_max})
+            is_invalid.update(entry)
+
+        # -----------------
+        # Wavelength rebin
+        # -----------------
+        if one_is_none([self.wavelength_low, self.wavelength_high, self.wavelength_step, self.wavelength_step_type]):
+            entry = validation_message("A wavelength entry has not been set.",
+                                       "Make sure that all entries are set.",
+                                       {"wavelength_low": self.wavelength_low,
+                                        "wavelength_high": self.wavelength_high,
+                                        "wavelength_step": self.wavelength_step,
+                                        "wavelength_step_type": self.wavelength_step_type})
+            is_invalid.update(entry)
+
+        if is_not_none_and_first_larger_than_second([self.wavelength_low, self.wavelength_high]):
+            entry = validation_message("Incorrect wavelength bounds.",
+                                       "Make sure that lower wavelength bound is smaller then upper bound.",
+                                       {"wavelength_low": self.wavelength_low,
+                                        "wavelength_high": self.wavelength_high})
+            is_invalid.update(entry)
+
+        # ----------------------
+        # Background correction
+        # ----------------------
+        if not is_pure_none_or_not_none([self.background_TOF_general_start, self.background_TOF_general_stop]):
+            entry = validation_message("A general background TOF entry has not been set.",
+                                       "Make sure that either all general background TOF entries are set or none.",
+                                       {"background_TOF_general_start": self.background_TOF_general_start,
+                                        "background_TOF_general_stop": self.background_TOF_general_stop})
+            is_invalid.update(entry)
+
+        if is_not_none_and_first_larger_than_second([self.background_TOF_general_start,
+                                                     self.background_TOF_general_stop]):
+            entry = validation_message("Incorrect general background TOF bounds.",
+                                       "Make sure that lower general background TOF bound is smaller then upper bound.",
+                                       {"background_TOF_general_start": self.background_TOF_general_start,
+                                        "background_TOF_general_stop": self.background_TOF_general_stop})
+            is_invalid.update(entry)
+
+        if not is_pure_none_or_not_none([self.background_TOF_monitor_start, self.background_TOF_monitor_stop]):
+            entry = validation_message("A monitor background TOF entry has not been set.",
+                                       "Make sure that either all monitor background TOF entries are set or none.",
+                                       {"background_TOF_monitor_start": self.background_TOF_monitor_start,
+                                        "background_TOF_monitor_stop": self.background_TOF_monitor_stop})
+            is_invalid.update(entry)
+
+        if self.background_TOF_monitor_start is not None and self.background_TOF_monitor_stop is not None:
+            if len(self.background_TOF_monitor_start) != len(self.background_TOF_monitor_stop):
+                entry = validation_message("The monitor background TOF entries have a length mismatch.",
+                                           "Make sure that all monitor background TOF entries have the same length.",
+                                           {"background_TOF_monitor_start": self.background_TOF_monitor_start,
+                                            "background_TOF_monitor_stop": self.background_TOF_monitor_stop})
+                is_invalid.update(entry)
+            for key_start, value_start in self.background_TOF_monitor_start.items():
+                if key_start not in self.background_TOF_monitor_stop:
+                    entry = validation_message("The monitor background TOF had spectrum number mismatch.",
+                                               "Make sure that all monitors have entries for start and stop.",
+                                               {"background_TOF_monitor_start": self.background_TOF_monitor_start,
+                                                "background_TOF_monitor_stop": self.background_TOF_monitor_stop})
+                    is_invalid.update(entry)
+                else:
+                    value_stop = self.background_TOF_monitor_stop[key_start]
+                    if value_start > value_stop:
+                        entry = validation_message("Incorrect monitor background TOF bounds.",
+                                                   "Make sure that lower monitor background TOF bound is"
+                                                   " smaller then upper bound.",
+                                                   {"background_TOF_monitor_start": self.background_TOF_monitor_start,
+                                                    "background_TOF_monitor_stop": self.background_TOF_monitor_stop})
+                        is_invalid.update(entry)
+
+        if is_invalid:
+            raise ValueError("StateMoveDetector: The provided inputs are illegal. "
+                             "Please see: {0}".format(json.dumps(is_invalid)))
+
+
+@rename_descriptor_names
+class StateNormalizeToMonitorLOQ(StateNormalizeToMonitor):
+    def __init__(self):
+        super(StateNormalizeToMonitorLOQ, self).__init__()
+        # Set the LOQ default range for prompt peak correction
+        self.prompt_peak_correction_min = 19000.0
+        self.prompt_peak_correction_max = 20500.0
+
+    def validate(self):
+        super(StateNormalizeToMonitorLOQ, self).validate()
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# Builder
+# ----------------------------------------------------------------------------------------------------------------------
+def set_default_incident_monitor(normalize_monitor_info, data_info):
+    """
+    The default incident monitor is stored on the IPF.
+    :param normalize_monitor_info: a StateNormalizeMonitor object on which we set the default value
+    :param data_info: a StateData object
+    """
+    file_name = data_info.sample_scatter
+    _, ipf_path = get_instrument_paths_for_sans_file(file_name)
+    named_element = "default-incident-monitor-spectrum"
+    monitor_spectrum_tag_to_search = [named_element]
+    found_monitor_spectrum = get_named_elements_from_ipf_file(ipf_path, monitor_spectrum_tag_to_search, int)
+    if named_element in found_monitor_spectrum:
+        normalize_monitor_info.incident_monitor = found_monitor_spectrum[named_element]
+
+
+class StateNormalizeToMonitorBuilder(object):
+    @automatic_setters(StateNormalizeToMonitor, exclusions=["default_incident_monitor"])
+    def __init__(self, data_info):
+        super(StateNormalizeToMonitorBuilder, self).__init__()
+        self._data = data_info
+        self.state = StateNormalizeToMonitor()
+        set_default_incident_monitor(self.state, self._data)
+
+    def build(self):
+        self.state.validate()
+        return copy.copy(self.state)
+
+
+class StateNormalizeToMonitorBuilderLOQ(object):
+    @automatic_setters(StateNormalizeToMonitorLOQ)
+    def __init__(self, data_info):
+        super(StateNormalizeToMonitorBuilderLOQ, self).__init__()
+        self._data = data_info
+        self.state = StateNormalizeToMonitorLOQ()
+        set_default_incident_monitor(self.state, self._data)
+
+    def build(self):
+        self.state.validate()
+        return copy.copy(self.state)
+
+
+def get_normalize_to_monitor_builder(data_info):
+    instrument = data_info.instrument
+    if instrument is SANSInstrument.LARMOR or instrument is SANSInstrument.SANS2D:
+        return StateNormalizeToMonitorBuilder(data_info)
+    elif instrument is SANSInstrument.LOQ:
+        return StateNormalizeToMonitorBuilderLOQ(data_info)
+    else:
+        raise NotImplementedError("StateNormalizeToMonitorBuilder: Could not find any valid normalize to monitor "
+                                  "builder for the specified StateData object {0}".format(str(data_info)))
diff --git a/scripts/SANS/sans/state/reduction_mode.py b/scripts/SANS/sans/state/reduction_mode.py
new file mode 100644
index 0000000000000000000000000000000000000000..917973e9b7008996f5dca9b34f50917e7ce7adda
--- /dev/null
+++ b/scripts/SANS/sans/state/reduction_mode.py
@@ -0,0 +1,131 @@
+# pylint: disable=too-few-public-methods
+
+""" Defines the state of the reduction."""
+
+from abc import (ABCMeta, abstractmethod)
+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)
+from sans.common.file_information import (get_instrument_paths_for_sans_file)
+from sans.common.xml_parsing import get_named_elements_from_ipf_file
+from sans.state.automatic_setters import (automatic_setters)
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# State
+# ----------------------------------------------------------------------------------------------------------------------
+class StateReductionBase(object):
+    __metaclass__ = ABCMeta
+
+    @abstractmethod
+    def get_merge_strategy(self):
+        pass
+
+    @abstractmethod
+    def get_detector_name_for_reduction_mode(self, reduction_mode):
+        pass
+
+    @abstractmethod
+    def get_all_reduction_modes(self):
+        pass
+
+
+@rename_descriptor_names
+class StateReductionMode(StateReductionBase, StateBase):
+    reduction_mode = ClassTypeParameter(ReductionMode)
+    reduction_dimensionality = ClassTypeParameter(ReductionDimensionality)
+
+    # Fitting
+    merge_fit_mode = ClassTypeParameter(FitModeForMerge)
+    merge_shift = FloatParameter()
+    merge_scale = FloatParameter()
+    merge_range_min = FloatWithNoneParameter()
+    merge_range_max = FloatWithNoneParameter()
+
+    # Map from detector type to detector name
+    detector_names = DictParameter()
+
+    def __init__(self):
+        super(StateReductionMode, self).__init__()
+        self.reduction_mode = ISISReductionMode.LAB
+        self.reduction_dimensionality = ReductionDimensionality.OneDim
+
+        # Set the shifts to defaults which essentially don't do anything.
+        self.merge_shift = 0.0
+        self.merge_scale = 1.0
+        self.merge_fit_mode = FitModeForMerge.NoFit
+        self.merge_range_min = None
+        self.merge_range_max = None
+
+        # Set the detector names to empty strings
+        self.detector_names = {DetectorType.to_string(DetectorType.LAB): "",
+                               DetectorType.to_string(DetectorType.HAB): ""}
+
+    def get_merge_strategy(self):
+        return [ISISReductionMode.LAB, ISISReductionMode.HAB]
+
+    def get_all_reduction_modes(self):
+        return [ISISReductionMode.LAB, ISISReductionMode.HAB]
+
+    def get_detector_name_for_reduction_mode(self, reduction_mode):
+        if reduction_mode is ISISReductionMode.LAB:
+            bank_type = DetectorType.to_string(DetectorType.LAB)
+        elif reduction_mode is ISISReductionMode.HAB:
+            bank_type = DetectorType.to_string(DetectorType.HAB)
+        else:
+            raise RuntimeError("SANStateReductionISIS: There is no detector available for the"
+                               " reduction mode {0}.".format(reduction_mode))
+        return self.detector_names[bank_type]
+
+    def validate(self):
+        pass
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# Builder
+# ----------------------------------------------------------------------------------------------------------------------
+def setup_detectors_from_ipf(reduction_info, data_info):
+    file_name = data_info.sample_scatter
+    _, ipf_path = get_instrument_paths_for_sans_file(file_name)
+
+    detector_names = {DetectorType.to_string(DetectorType.LAB): "low-angle-detector-name",
+                      DetectorType.to_string(DetectorType.HAB): "high-angle-detector-name"}
+
+    names_to_search = []
+    names_to_search.extend(detector_names.values())
+
+    found_detector_names = get_named_elements_from_ipf_file(ipf_path, names_to_search, str)
+
+    for detector_type in reduction_info.detector_names.keys():
+        try:
+            detector_name_tag = detector_names[detector_type]
+            detector_name = found_detector_names[detector_name_tag]
+        except KeyError:
+            continue
+        reduction_info.detector_names[detector_type] = detector_name
+
+
+class StateReductionModeBuilder(object):
+    @automatic_setters(StateReductionMode, exclusions=["detector_names"])
+    def __init__(self, data_info):
+        super(StateReductionModeBuilder, self).__init__()
+        self.state = StateReductionMode()
+        setup_detectors_from_ipf(self.state, data_info)
+
+    def build(self):
+        self.state.validate()
+        return copy.copy(self.state)
+
+
+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:
+        return StateReductionModeBuilder(data_info)
+    else:
+        raise NotImplementedError("StateReductionBuilder: Could not find any valid reduction builder for the "
+                                  "specified StateData object {0}".format(str(data_info)))
diff --git a/scripts/SANS/sans/state/save.py b/scripts/SANS/sans/state/save.py
new file mode 100644
index 0000000000000000000000000000000000000000..cb1f03ef6f07de16ac109612c7050566a919d039
--- /dev/null
+++ b/scripts/SANS/sans/state/save.py
@@ -0,0 +1,50 @@
+# pylint: disable=too-few-public-methods
+
+""" Defines the state of saving."""
+import copy
+from sans.state.state_base import (StateBase, BoolParameter, StringParameter,
+                                   ClassTypeListParameter, rename_descriptor_names)
+from sans.common.enums import (SaveType, SANSInstrument)
+from sans.state.automatic_setters import (automatic_setters)
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# State
+# ----------------------------------------------------------------------------------------------------------------------
+@rename_descriptor_names
+class StateSave(StateBase):
+    file_name = StringParameter()
+    zero_free_correction = BoolParameter()
+    file_format = ClassTypeListParameter(SaveType)
+
+    def __init__(self):
+        super(StateSave, self).__init__()
+        self.zero_free_correction = True
+
+    def validate(self):
+        pass
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# Builder
+# ----------------------------------------------------------------------------------------------------------------------
+class StateSaveBuilder(object):
+    @automatic_setters(StateSave)
+    def __init__(self):
+        super(StateSaveBuilder, self).__init__()
+        self.state = StateSave()
+
+    def build(self):
+        self.state.validate()
+        return copy.copy(self.state)
+
+
+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:
+        return StateSaveBuilder()
+    else:
+        raise NotImplementedError("StateSaveBuilder: Could not find any valid save builder for the "
+                                  "specified StateData object {0}".format(str(data_info)))
diff --git a/scripts/SANS/sans/state/scale.py b/scripts/SANS/sans/state/scale.py
new file mode 100644
index 0000000000000000000000000000000000000000..cf888b6209011d0939e3df618648522f4fd264d4
--- /dev/null
+++ b/scripts/SANS/sans/state/scale.py
@@ -0,0 +1,51 @@
+""" Defines the state of the geometry and unit scaling."""
+import copy
+from sans.state.state_base import (StateBase, rename_descriptor_names, PositiveFloatParameter, ClassTypeParameter)
+from sans.common.enums import (SampleShape, SANSInstrument)
+from sans.state.automatic_setters import (automatic_setters)
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+#  State
+# ----------------------------------------------------------------------------------------------------------------------
+@rename_descriptor_names
+class StateScale(StateBase):
+    shape = ClassTypeParameter(SampleShape)
+    thickness = PositiveFloatParameter()
+    width = PositiveFloatParameter()
+    height = PositiveFloatParameter()
+    scale = PositiveFloatParameter()
+
+    def __init__(self):
+        super(StateScale, self).__init__()
+
+    def validate(self):
+        pass
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+#  Builder
+# ----------------------------------------------------------------------------------------------------------------------
+class StateScaleBuilder(object):
+    @automatic_setters(StateScale, exclusions=[])
+    def __init__(self):
+        super(StateScaleBuilder, self).__init__()
+        self.state = StateScale()
+
+    def build(self):
+        self.state.validate()
+        return copy.copy(self.state)
+
+
+# ------------------------------------------
+# 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:
+        return StateScaleBuilder()
+    else:
+        raise NotImplementedError("StateScaleBuilder: Could not find any valid scale builder for the "
+                                  "specified StateData object {0}".format(str(data_info)))
diff --git a/scripts/SANS/sans/state/slice_event.py b/scripts/SANS/sans/state/slice_event.py
new file mode 100644
index 0000000000000000000000000000000000000000..744dd94e25523f2254acc74b80e2180d3cf6d7c7
--- /dev/null
+++ b/scripts/SANS/sans/state/slice_event.py
@@ -0,0 +1,110 @@
+""" Defines the state of the event slices which should be reduced."""
+
+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.state.automatic_setters import (automatic_setters)
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# State
+# ----------------------------------------------------------------------------------------------------------------------
+@rename_descriptor_names
+class StateSliceEvent(StateBase):
+    start_time = FloatListParameter()
+    end_time = FloatListParameter()
+
+    def __init__(self):
+        super(StateSliceEvent, self).__init__()
+
+    def validate(self):
+        is_invalid = dict()
+
+        if not is_pure_none_or_not_none([self.start_time, self.end_time]):
+            entry = validation_message("Missing slice times",
+                                       "Makes sure that either both or none are set.",
+                                       {"start_time": self.start_time,
+                                        "end_time": self.end_time})
+            is_invalid.update(entry)
+
+        if self.start_time and self.end_time:
+            # The length of start_time and end_time needs to be identical
+            if len(self.start_time) != len(self.end_time):
+                entry = validation_message("Bad relation of start and end",
+                                           "Makes sure that the start time is smaller than the end time.",
+                                           {"start_time": self.start_time,
+                                            "end_time": self.end_time})
+                is_invalid.update(entry)
+
+            # Each entry in start_time and end_time must be a float
+            if len(self.start_time) == len(self.end_time) and len(self.start_time) > 0:
+                for item in range(0, len(self.start_time)):
+                    for element1, element2 in zip(self.start_time, self.end_time):
+                        if not isinstance(element1, float) or not isinstance(element2, float):
+                            entry = validation_message("Bad relation of start and end time entries",
+                                                       "The elements need to be floats.",
+                                                       {"start_time": self.start_time,
+                                                        "end_time": self.end_time})
+                            is_invalid.update(entry)
+
+            # Check that the entries are monotonically increasing. We don't want 12, 24, 22
+            if len(self.start_time) > 1 and not monotonically_increasing(self.start_time):
+                entry = validation_message("Not monotonically increasing start time list",
+                                           "Make sure that the start times increase monotonically.",
+                                           {"start_time": self.start_time})
+                is_invalid.update(entry)
+
+            if len(self.end_time) > 1 and not monotonically_increasing(self.end_time):
+                entry = validation_message("Not monotonically increasing end time list",
+                                           "Make sure that the end times increase monotonically.",
+                                           {"end_time": self.end_time})
+                is_invalid.update(entry)
+
+            # Check that end_time is not smaller than start_time
+            if not is_smaller(self.start_time, self.end_time):
+                entry = validation_message("Start time larger than end time.",
+                                           "Make sure that the start time is not smaller than the end time.",
+                                           {"start_time": self.start_time,
+                                            "end_time": self.end_time})
+                is_invalid.update(entry)
+
+        if is_invalid:
+            raise ValueError("StateSliceEvent: The provided inputs are illegal. "
+                             "Please see: {}".format(json.dumps(is_invalid)))
+
+
+def monotonically_increasing(to_check):
+    return all(x <= y for x, y in zip(to_check, to_check[1:]))
+
+
+def is_smaller(smaller, larger):
+    return all(x <= y for x, y in zip(smaller, larger))
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# Builder
+# ----------------------------------------------------------------------------------------------------------------------
+class StateSliceEventBuilder(object):
+    @automatic_setters(StateSliceEvent)
+    def __init__(self):
+        super(StateSliceEventBuilder, self).__init__()
+        self.state = StateSliceEvent()
+
+    def build(self):
+        # Make sure that the product is in a valid state, ie not incomplete
+        self.state.validate()
+        return copy.copy(self.state)
+
+
+# ------------------------------------------
+# 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:
+        return StateSliceEventBuilder()
+    else:
+        raise NotImplementedError("StateSliceEventBuilder: Could not find any valid slice builder for the "
+                                  "specified StateData object {0}".format(str(data_info)))
diff --git a/scripts/SANS/sans/state/state.py b/scripts/SANS/sans/state/state.py
new file mode 100644
index 0000000000000000000000000000000000000000..7c5344caf767237946c3bdc54eb8fb713a88ec4b
--- /dev/null
+++ b/scripts/SANS/sans/state/state.py
@@ -0,0 +1,110 @@
+""" Defines the main State object."""
+
+# pylint: disable=too-few-public-methods
+
+import json
+import pickle
+import inspect
+import copy
+from sans.common.enums import SANSInstrument
+from sans.state.state_base import (StateBase, TypedParameter,
+                                   rename_descriptor_names, validator_sub_state)
+from sans.state.data import StateData
+from sans.state.move import StateMove
+from sans.state.reduction_mode import StateReductionMode
+from sans.state.slice_event import StateSliceEvent
+from sans.state.mask import StateMask
+from sans.state.wavelength import StateWavelength
+from sans.state.save import StateSave
+from sans.state.adjustment import StateAdjustment
+from sans.state.scale import StateScale
+from sans.state.convert_to_q import StateConvertToQ
+from sans.state.automatic_setters import (automatic_setters)
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# State
+# ----------------------------------------------------------------------------------------------------------------------
+@rename_descriptor_names
+class State(StateBase):
+    data = TypedParameter(StateData, validator_sub_state)
+    move = TypedParameter(StateMove, validator_sub_state)
+    reduction = TypedParameter(StateReductionMode, validator_sub_state)
+    slice = TypedParameter(StateSliceEvent, validator_sub_state)
+    mask = TypedParameter(StateMask, validator_sub_state)
+    wavelength = TypedParameter(StateWavelength, validator_sub_state)
+    save = TypedParameter(StateSave, validator_sub_state)
+    scale = TypedParameter(StateScale, validator_sub_state)
+    adjustment = TypedParameter(StateAdjustment, validator_sub_state)
+    convert_to_q = TypedParameter(StateConvertToQ, validator_sub_state)
+
+    def __init__(self):
+        super(State, self).__init__()
+
+    def validate(self):
+        is_invalid = dict()
+
+        # Make sure that the substates are contained
+        if not self.data:
+            is_invalid.update("State: The state object needs to include a StateData object.")
+        if not self.move:
+            is_invalid.update("State: The state object needs to include a StateMove object.")
+        if not self.reduction:
+            is_invalid.update("State: The state object needs to include a StateReduction object.")
+        if not self.slice:
+            is_invalid.update("State: The state object needs to include a StateSliceEvent object.")
+        if not self.mask:
+            is_invalid.update("State: The state object needs to include a StateMask object.")
+        if not self.wavelength:
+            is_invalid.update("State: The state object needs to include a StateWavelength object.")
+        if not self.save:
+            is_invalid.update("State: The state object needs to include a StateSave object.")
+        if not self.scale:
+            is_invalid.update("State: The state object needs to include a StateScale object.")
+        if not self.adjustment:
+            is_invalid.update("State: The state object needs to include a StateAdjustment object.")
+        if not self.convert_to_q:
+            is_invalid.update("State: The state object needs to include a StateConvertToQ object.")
+
+        if is_invalid:
+            raise ValueError("State: There is an issue with your in put. See: {0}".format(json.dumps(is_invalid)))
+
+        # Check the attributes themselves
+        is_invalid = {}
+        for descriptor_name, descriptor_object in inspect.getmembers(type(self)):
+            if inspect.isdatadescriptor(descriptor_object) and isinstance(descriptor_object, TypedParameter):
+                try:
+                    attr = getattr(self, descriptor_name)
+                    attr.validate()
+                except ValueError as err:
+                    is_invalid.update({descriptor_name: pickle.dumps(str(err))})
+
+        if is_invalid:
+            raise ValueError("State: There is an issue with your in put. See: {0}".format(json.dumps(is_invalid)))
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# Builder
+# ----------------------------------------------------------------------------------------------------------------------
+class StateBuilder(object):
+    @automatic_setters(State)
+    def __init__(self):
+        super(StateBuilder, self).__init__()
+        self.state = State()
+
+    def build(self):
+        # Make sure that the product is in a valid state, ie not incomplete
+        self.state.validate()
+        return copy.copy(self.state)
+
+
+# ------------------------------------------
+# 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:
+        return StateBuilder()
+    else:
+        raise NotImplementedError("SANSStateBuilder: Could not find any valid state builder for the "
+                                  "specified SANSStateData object {0}".format(str(data_info)))
diff --git a/scripts/SANS/sans/state/state_base.py b/scripts/SANS/sans/state/state_base.py
new file mode 100644
index 0000000000000000000000000000000000000000..cf3d64cc88a2f9e8bec927426acd01f2673faf04
--- /dev/null
+++ b/scripts/SANS/sans/state/state_base.py
@@ -0,0 +1,566 @@
+#pylint: disable=too-few-public-methods, invalid-name
+
+""" Fundamental classes and Descriptors for the State mechanism."""
+from __future__ import (absolute_import, division, print_function)
+from abc import (ABCMeta, abstractmethod)
+import copy
+import inspect
+from functools import (partial)
+from six import string_types, with_metaclass
+
+from mantid.kernel import (PropertyManager, std_vector_dbl, std_vector_str, std_vector_int, std_vector_long)
+
+
+# ---------------------------------------------------------------
+# Validator functions
+# ---------------------------------------------------------------
+def is_not_none(value):
+    return value is not None
+
+
+def is_positive(value):
+    return value >= 0
+
+
+def is_positive_or_none(value):
+    return value is None or value >= 0
+
+
+def all_list_elements_are_of_specific_type_and_not_empty(value, comparison_type,
+                                                         additional_comparison=lambda x: True, type_check=isinstance):
+    """
+    Ensures that all elements of a list are of a specific type and that the list is not empty
+
+    @param value: the list to check
+    @param comparison_type: the expected type of the elements of the list.
+    @param additional_comparison: additional comparison lambda.
+    @param type_check: the method which performs type checking.
+    @return: True if the list is not empty and all types are as expected, else False.
+    """
+    is_of_type = True
+    for element in value:
+        # Perform type check
+        if not type_check(element, comparison_type):
+            is_of_type = False
+        # Perform additional check
+        if not additional_comparison(element):
+            is_of_type = False
+
+    if not value:
+        is_of_type = False
+    return is_of_type
+
+
+def all_list_elements_are_of_instance_type_and_not_empty(value, comparison_type, additional_comparison=lambda x: True):
+    """
+    Ensures that all elements of a list are of a certain INSTANCE type and that the list is not empty.
+    """
+    return all_list_elements_are_of_specific_type_and_not_empty(value=value, comparison_type=comparison_type,
+                                                                additional_comparison=additional_comparison,
+                                                                type_check=isinstance)
+
+
+def all_list_elements_are_of_class_type_and_not_empty(value, comparison_type, additional_comparison=lambda x: True):
+    """
+    Ensures that all elements of a list are of a certain INSTANCE type and that the list is not empty.
+    """
+    return all_list_elements_are_of_specific_type_and_not_empty(value=value, comparison_type=comparison_type,
+                                                                additional_comparison=additional_comparison,
+                                                                type_check=issubclass)
+
+
+def all_list_elements_are_float_and_not_empty(value):
+    typed_comparison = partial(all_list_elements_are_of_instance_type_and_not_empty, comparison_type=float)
+    return typed_comparison(value)
+
+
+def all_list_elements_are_string_and_not_empty(value):
+    typed_comparison = partial(all_list_elements_are_of_instance_type_and_not_empty, comparison_type=str)
+    return typed_comparison(value)
+
+
+def all_list_elements_are_int_and_not_empty(value):
+    typed_comparison = partial(all_list_elements_are_of_instance_type_and_not_empty, comparison_type=int)
+    return typed_comparison(value)
+
+
+def all_list_elements_are_int_and_positive_and_not_empty(value):
+    typed_comparison = partial(all_list_elements_are_of_instance_type_and_not_empty, comparison_type=int,
+                               additional_comparison=lambda x: x >= 0)
+    return typed_comparison(value)
+
+
+def validator_sub_state(sub_state):
+    is_valid = True
+    try:
+        sub_state.validate()
+    except ValueError:
+        is_valid = False
+    return is_valid
+
+
+# -------------------------------------------------------
+# Parameters
+# -------------------------------------------------------
+class TypedParameter(object):
+    """
+    The TypedParameter descriptor allows the user to store/handle a type-checked value with an additional
+    validator option, e.g. one can restrict the held parameter to be only a positive value.
+    """
+    __counter = 0
+
+    def __init__(self, parameter_type, validator=lambda x: True):
+        cls = self.__class__
+        prefix = cls.__name__
+        # pylint: disable=protected-access
+        index = cls.__counter
+        cls.__counter += 1
+        # Name which is used to store value in the instance. This will be unique and not accessible via the standard
+        # attribute access, since the developer/user cannot apply the hash symbol in their code (it is valid though
+        # when writing into the __dict__). Note that the name which we generate here will be altered (via a
+        # class decorator) in the classes which actually use the TypedParameter descriptor, to make it more readable.
+        self.name = '_{0}#{1}'.format(prefix, index)
+        self.parameter_type = parameter_type
+        self.value = None
+        self.validator = validator
+
+    def __get__(self, instance, owner):
+        if instance is None:
+            return self
+        else:
+            if hasattr(instance, self.name):
+                return getattr(instance, self.name)
+            else:
+                return None
+
+    def __set__(self, instance, value):
+        # Perform a type check
+        self._type_check(value)
+        if self.validator(value):
+            # The descriptor should be holding onto its own data and return a deepcopy of the data.
+            copied_value = copy.deepcopy(value)
+            setattr(instance, self.name, copied_value)
+        else:
+            raise ValueError("Trying to set {0} with an invalid value of {1}".format(self.name, str(value)))
+
+    def __delete__(self):
+        raise AttributeError("Cannot delete the attribute {0}".format(self.name))
+
+    def _type_check(self, value):
+        if not isinstance(value, self.parameter_type):
+            raise TypeError("Trying to set {0} which expects a value of type {1}."
+                            " Got a value of {2} which is of type: {3}".format(self.name, str(self.parameter_type),
+                                                                               str(value), str(type(value))))
+
+
+# ---------------------------------------------------
+# Various standard cases of the TypedParameter
+# ---------------------------------------------------
+class StringParameter(TypedParameter):
+    def __init__(self):
+        super(StringParameter, self).__init__(str, is_not_none)
+
+
+class BoolParameter(TypedParameter):
+    def __init__(self):
+        super(BoolParameter, self).__init__(bool, is_not_none)
+
+
+class FloatParameter(TypedParameter):
+    def __init__(self):
+        super(FloatParameter, self).__init__(float, is_not_none)
+
+
+class PositiveFloatParameter(TypedParameter):
+    def __init__(self):
+        super(PositiveFloatParameter, self).__init__(float, is_positive)
+
+
+class PositiveIntegerParameter(TypedParameter):
+    def __init__(self):
+        super(PositiveIntegerParameter, self).__init__(int, is_positive)
+
+
+class DictParameter(TypedParameter):
+    def __init__(self):
+        super(DictParameter, self).__init__(dict, is_not_none)
+
+
+class ClassTypeParameter(TypedParameter):
+    """
+    This TypedParameter variant allows for storing a class type.
+
+    This could be for example something from the SANSType module, e.g. CanonicalCoordinates.X
+    It is something that is used frequently with the main of moving away from using strings where types
+    should be used instead.
+    """
+    def __init__(self, class_type):
+        super(ClassTypeParameter, self).__init__(class_type, is_not_none)
+
+    def _type_check(self, value):
+        if not issubclass(value, self.parameter_type):
+            raise TypeError("Trying to set {0} which expects a value of type {1}."
+                            " Got a value of {2} which is of type: {3}".format(self.name, str(self.parameter_type),
+                                                                               str(value), type(value)))
+
+
+class FloatWithNoneParameter(TypedParameter):
+    def __init__(self):
+        super(FloatWithNoneParameter, self).__init__(float)
+
+    def _type_check(self, value):
+        if not isinstance(value, self.parameter_type) and value is not None:
+            raise TypeError("Trying to set {0} which expects a value of type {1}."
+                            " Got a value of {2} which is of type: {3}".format(self.name, str(self.parameter_type),
+                                                                               str(value), type(value)))
+
+
+class PositiveFloatWithNoneParameter(TypedParameter):
+    def __init__(self):
+        super(PositiveFloatWithNoneParameter, self).__init__(float, is_positive_or_none)
+
+    def _type_check(self, value):
+        if not isinstance(value, self.parameter_type) and value is not None:
+            raise TypeError("Trying to set {0} which expects a value of type {1}."
+                            " Got a value of {2} which is of type: {3}".format(self.name, str(self.parameter_type),
+                                                                               str(value), type(value)))
+
+
+class FloatListParameter(TypedParameter):
+    def __init__(self):
+        super(FloatListParameter, self).__init__(list)
+
+    def _type_check(self, value):
+        if not isinstance(value, self.parameter_type) or not all_list_elements_are_float_and_not_empty(value):
+            raise TypeError("Trying to set {0} which expects a value of type {1}."
+                            " Got a value of {2} which is of type: {3}".format(self.name, str(self.parameter_type),
+                                                                               str(value), type(value)))
+
+
+class StringListParameter(TypedParameter):
+        def __init__(self):
+            super(StringListParameter, self).__init__(list, all_list_elements_are_string_and_not_empty)
+
+        def _type_check(self, value):
+            if not isinstance(value, self.parameter_type) or not all_list_elements_are_string_and_not_empty(value):
+                raise TypeError("Trying to set {0} which expects a value of type {1}."
+                                " Got a value of {2} which is of type: {3}".format(self.name, str(self.parameter_type),
+                                                                                   str(value), type(value)))
+
+
+class PositiveIntegerListParameter(TypedParameter):
+    def __init__(self):
+        super(PositiveIntegerListParameter, self).__init__(list,
+                                                           all_list_elements_are_int_and_positive_and_not_empty)
+
+    def _type_check(self, value):
+        if not isinstance(value, self.parameter_type) or not all_list_elements_are_int_and_not_empty(value):
+            raise TypeError("Trying to set {0} which expects a value of type {1}."
+                            " Got a value of {2} which is of type: {3}".format(self.name, str(self.parameter_type),
+                                                                               str(value), type(value)))
+
+
+class ClassTypeListParameter(TypedParameter):
+    def __init__(self, class_type):
+        typed_comparison = partial(all_list_elements_are_of_class_type_and_not_empty, comparison_type=class_type)
+        super(ClassTypeListParameter, self).__init__(list, typed_comparison)
+
+
+# ------------------------------------------------
+# StateBase
+# ------------------------------------------------
+class StateBase(with_metaclass(ABCMeta, object)):
+    """ The fundamental base of the SANS State"""
+
+    @property
+    def property_manager(self):
+        return convert_state_to_dict(self)
+
+    @property_manager.setter
+    def property_manager(self, value):
+        set_state_from_property_manager(self, value)
+
+    @abstractmethod
+    def validate(self):
+        pass
+
+
+def rename_descriptor_names(cls):
+    """
+    Class decorator which changes the names of TypedParameters in a class instance in order to make it more readable.
+
+    This is especially helpful for debugging. And also in order to find attributes in the dictionaries.
+    :param cls: The class with the TypedParameters
+    :return: The class with the TypedParameters
+    """
+    for attribute_name, attribute_value in cls.__dict__.items():
+        if isinstance(attribute_value, TypedParameter):
+            attribute_value.name = '_{0}#{1}'.format(type(attribute_value).__name__, attribute_name)
+    return cls
+
+
+# ------------------------------------------------
+# Serialization of the State
+# ------------------------------------------------
+# Serialization of the state object is currently done via generating a dict object. Reversely, we can generate a
+# State object from a property manager object, not a dict object. This quirk results from the way Mantid
+# treats property manager inputs and outputs (it reads in dicts and converts them to property manager objects).
+# We might have to live with that for now.
+#
+# During serialization we place identifier tags into the serialized object, e.g. we add a specifier if the item
+# is a State type at all and if so which state it is.
+
+
+STATE_NAME = "state_name"
+STATE_MODULE = "state_module"
+SEPARATOR_SERIAL = "#"
+class_type_parameter_id = "ClassTypeParameterID#"
+MODULE = "__module__"
+
+
+def is_state(property_manager):
+    return property_manager.existsProperty(STATE_NAME) and property_manager.existsProperty(STATE_MODULE)
+
+
+def is_float_vector(value):
+    return isinstance(value, std_vector_dbl)
+
+
+def is_string_vector(value):
+    return isinstance(value, std_vector_str)
+
+
+def is_int_vector(value):
+    return isinstance(value, std_vector_int) or isinstance(value, std_vector_long)
+
+
+def get_module_and_class_name(instance):
+    if inspect.isclass(instance):
+        module_name, class_name = str(instance.__dict__[MODULE]), str(instance.__name__)
+    else:
+        module_name, class_name = str(type(instance).__dict__[MODULE]), str(type(instance).__name__)
+    return module_name, class_name
+
+
+def provide_class_from_module_and_class_name(module_name, class_name):
+    # Importlib seems to be missing on RHEL6, hence we resort to __import__
+    try:
+        from importlib import import_module
+        module = import_module(module_name)
+    except ImportError:
+        if "." in module_name:
+            _, mod_name = module_name.rsplit(".", 1)
+        else:
+            mod_name = None
+        if not mod_name:
+            module = __import__(module_name)
+        else:
+            module = __import__(module_name, fromlist=[mod_name])
+    return getattr(module, class_name)
+
+
+def provide_class(instance):
+    module_name = instance.getProperty(STATE_MODULE).value
+    class_name = instance.getProperty(STATE_NAME).value
+    return provide_class_from_module_and_class_name(module_name, class_name)
+
+
+def is_class_type_parameter(value):
+    return isinstance(value, string_types) and class_type_parameter_id in value
+
+
+def is_vector_with_class_type_parameter(value):
+    is_vector_with_class_type = True
+    contains_str = is_string_vector(value)
+    if contains_str:
+        for element in value:
+            if not is_class_type_parameter(element):
+                is_vector_with_class_type = False
+    else:
+        is_vector_with_class_type = False
+    return is_vector_with_class_type
+
+
+def get_module_and_class_name_from_encoded_string(encoder, value):
+    without_encoder = value.replace(encoder, "")
+    return without_encoder.split(SEPARATOR_SERIAL)
+
+
+def create_module_and_class_name_from_encoded_string(class_type_id, module_name, class_name):
+    return class_type_id + module_name + SEPARATOR_SERIAL + class_name
+
+
+def create_sub_state(value):
+    # We are dealing with a sub state. We first have to create it and then populate it
+    sub_state_class = provide_class(value)
+    # Create the sub state, populate it and set it on the super state
+    sub_state = sub_state_class()
+    sub_state.property_manager = value
+    return sub_state
+
+
+def get_descriptor_values(instance):
+    # Get all descriptor names which are TypedParameter of instance's type
+    descriptor_names = []
+    descriptor_types = {}
+    for descriptor_name, descriptor_object in inspect.getmembers(type(instance)):
+        if inspect.isdatadescriptor(descriptor_object) and isinstance(descriptor_object, TypedParameter):
+            descriptor_names.append(descriptor_name)
+            descriptor_types.update({descriptor_name: descriptor_object})
+
+    # Get the descriptor values from the instance
+    descriptor_values = {}
+    for key in descriptor_names:
+        if hasattr(instance, key):
+            value = getattr(instance, key)
+            if value is not None:
+                descriptor_values.update({key: value})
+    return descriptor_values, descriptor_types
+
+
+def get_class_descriptor_types(instance):
+    # Get all descriptor names which are TypedParameter of instance's type
+    descriptors = {}
+    for descriptor_name, descriptor_object in inspect.getmembers(type(instance)):
+        if inspect.isdatadescriptor(descriptor_object) and isinstance(descriptor_object, TypedParameter):
+            descriptors.update({descriptor_name: type(descriptor_object)})
+    return descriptors
+
+
+def convert_state_to_dict(instance):
+    """
+    Converts the state object to a dictionary.
+
+    @param instance: the instance which is to be converted
+    @return: a serialized state object in the form of a dict
+    """
+    descriptor_values, descriptor_types = get_descriptor_values(instance)
+    # Add the descriptors to a dict
+    state_dict = dict()
+    for key, value in descriptor_values.items():
+        # If the value is a SANSBaseState then create a dict from it
+        # If the value is a dict, then we need to check what the sub types are
+        # If the value is a ClassTypeParameter, then we need to encode it
+        # If the value is a list of ClassTypeParameters, then we need to encode each element in the list
+        if isinstance(value, StateBase):
+            sub_state_dict = value.property_manager
+            value = sub_state_dict
+        elif isinstance(value, dict):
+            # If we have a dict, then we need to watch out since a value in the dict might be a State
+            sub_dictionary = {}
+            for key_sub, val_sub in value.items():
+                if isinstance(val_sub, StateBase):
+                    sub_dictionary_value = val_sub.property_manager
+                else:
+                    sub_dictionary_value = val_sub
+                sub_dictionary.update({key_sub: sub_dictionary_value})
+            value = sub_dictionary
+        elif isinstance(descriptor_types[key], ClassTypeParameter):
+            value = get_serialized_class_type_parameter(value)
+        elif isinstance(descriptor_types[key], ClassTypeListParameter):
+            if value:
+                # If there are entries in the list, then convert them individually and place them into a list.
+                # The list will contain a sequence of serialized ClassTypeParameters
+                serialized_value = []
+                for element in value:
+                    serialized_element = get_serialized_class_type_parameter(element)
+                    serialized_value.append(serialized_element)
+                value = serialized_value
+
+        state_dict.update({key: value})
+    # Add information about the current state object, such as in which module it lives and what its name is
+    module_name, class_name = get_module_and_class_name(instance)
+    state_dict.update({STATE_MODULE: module_name})
+    state_dict.update({STATE_NAME: class_name})
+    return state_dict
+
+
+def set_state_from_property_manager(instance, property_manager):
+    """
+    Set the State object from the information stored on a property manager object. This is the deserialization step.
+
+    @param instance: the instance which is to be set with a values of the propery manager
+    @param property_manager: the property manager withe the stored setting
+    """
+    def _set_element(inst, k_element, v_element):
+        if k_element != STATE_NAME and k_element != STATE_MODULE:
+            setattr(inst, k_element, v_element)
+
+    keys = list(property_manager.keys())
+    for key in keys:
+        value = property_manager.getProperty(key).value
+        # There are four scenarios that need to be considered
+        # 1. ParameterManager 1: This indicates (most often) that we are dealing with a new state -> create it and
+        #                      apply recursion
+        # 2. ParameterManager 2: In some cases the ParameterManager object is actually a map rather than a state ->
+        #                         populate the state
+        # 3. String with special meaning: Admittedly this is a hack, but we are limited by the input property types
+        #                                 of Mantid algorithms, which can be string, int, float and containers of these
+        #                                 types (and PropertyManagerProperties). We need a wider range of types, such
+        #                                 as ClassTypeParameters. These are encoded (as good as possible) in a string
+        # 4. Vector of strings with special meaning: See point 3)
+        # 5. Vector for float: This needs to handle Mantid's float array
+        # 6. Vector for string: This needs to handle Mantid's string array
+        # 7. Vector for int: This needs to handle Mantid's integer array
+        # 8. Normal values: all is fine, just populate them
+        if type(value) is PropertyManager and is_state(value):
+            sub_state = create_sub_state(value)
+            setattr(instance, key, sub_state)
+        elif type(value) is PropertyManager:
+            # We must be dealing with an actual dict descriptor
+            sub_dict_keys = list(value.keys())
+            dict_element = {}
+            # We need to watch out if a value of the dictionary is a sub state
+            for sub_dict_key in sub_dict_keys:
+                sub_dict_value = value.getProperty(sub_dict_key).value
+                if type(sub_dict_value) == PropertyManager and is_state(sub_dict_value):
+                    sub_state = create_sub_state(sub_dict_value)
+                    sub_dict_value_to_insert = sub_state
+                else:
+                    sub_dict_value_to_insert = sub_dict_value
+                dict_element.update({sub_dict_key: sub_dict_value_to_insert})
+            setattr(instance, key, dict_element)
+        elif is_class_type_parameter(value):
+            class_type_parameter = get_deserialized_class_type_parameter(value)
+            _set_element(instance, key, class_type_parameter)
+        elif is_vector_with_class_type_parameter(value):
+            class_type_list = []
+            for element in value:
+                class_type_parameter = get_deserialized_class_type_parameter(element)
+                class_type_list.append(class_type_parameter)
+            _set_element(instance, key, class_type_list)
+        elif is_float_vector(value):
+            float_list_value = list(value)
+            _set_element(instance, key, float_list_value)
+        elif is_string_vector(value):
+            string_list_value = list(value)
+            _set_element(instance, key, string_list_value)
+        elif is_int_vector(value):
+            int_list_value = list(value)
+            _set_element(instance, key, int_list_value)
+        else:
+            _set_element(instance, key, value)
+
+
+def get_serialized_class_type_parameter(value):
+    # The module will only know about the outer class name, therefore we need
+    # 1. The module name
+    # 2. The name of the outer class
+    # 3. The name of the actual class
+    module_name, class_name = get_module_and_class_name(value)
+    outer_class_name = value.outer_class_name
+    class_name = outer_class_name + SEPARATOR_SERIAL + class_name
+    return create_module_and_class_name_from_encoded_string(class_type_parameter_id, module_name, class_name)
+
+
+def get_deserialized_class_type_parameter(value):
+    # We need to first get the outer class from the module
+    module_name, outer_class_name, class_name = \
+        get_module_and_class_name_from_encoded_string(class_type_parameter_id, value)
+    outer_class_type_parameter = provide_class_from_module_and_class_name(module_name, outer_class_name)
+    # From the outer class we can then retrieve the inner class which normally defines the users selection
+    return getattr(outer_class_type_parameter, class_name)
+
+
+def create_deserialized_sans_state_from_property_manager(property_manager):
+    return create_sub_state(property_manager)
diff --git a/scripts/SANS/sans/state/state_functions.py b/scripts/SANS/sans/state/state_functions.py
new file mode 100644
index 0000000000000000000000000000000000000000..8f9da6622a351d756b53122806d9e8c8615e0a75
--- /dev/null
+++ b/scripts/SANS/sans/state/state_functions.py
@@ -0,0 +1,274 @@
+"""Set of general purpose functions which are related to the SANSState approach."""
+
+from copy import deepcopy
+from sans.common.enums import (ReductionDimensionality, ISISReductionMode, OutputParts, DetectorType)
+from sans.common.constants import (ALL_PERIODS, REDUCED_WORKSPACE_NAME_IN_LOGS, EMPTY_NAME, REDUCED_CAN_TAG)
+from sans.common.general_functions import (add_to_sample_log, get_ads_workspace_references)
+from sans.common.log_tagger import (has_hash, get_hash_value, set_hash)
+from sans.common.xml_parsing import (get_monitor_names_from_idf_file, get_named_elements_from_ipf_file)
+
+
+def add_workspace_name(workspace, state, reduction_mode):
+    """
+    Adds the default reduced workspace name to the sample logs
+
+    :param workspace: The output workspace
+    :param state: a SANSState object
+    :param reduction_mode: the reduction mode, i.e. LAB, HAB, MERGED
+    """
+    reduced_workspace_name = get_output_workspace_name(state, reduction_mode)
+    add_to_sample_log(workspace, REDUCED_WORKSPACE_NAME_IN_LOGS, reduced_workspace_name, "String")
+
+
+def get_output_workspace_name_from_workspace(workspace):
+    run = workspace.run()
+    if not run.hasProperty(REDUCED_WORKSPACE_NAME_IN_LOGS):
+        raise RuntimeError("The workspace does not seem to contain an entry for the output workspace name.")
+    return run.getProperty(REDUCED_WORKSPACE_NAME_IN_LOGS).value
+
+
+def get_output_workspace_name(state, reduction_mode):
+    """
+    Creates the name of the output workspace from a state object.
+
+    The name of the output workspace is:
+    1. The short run number
+    2. If specific period is being reduced: 'p' + number
+    3. Short detector name of the current reduction or "merged"
+    4. The reduction dimensionality: "_" + dimensionality
+    5. A wavelength range: wavelength_low + "_" + wavelength_high
+    6. In case of a 1D reduction, then add phi limits
+    7. If we are dealing with an actual slice limit, then specify it: "_tXX_TYY" Note that the time set to
+       two decimals
+    :param state: a SANSState object
+    :param reduction_mode: which reduction is being looked at
+    :return: the name of the reduced workspace
+    """
+    # 1. Short run number
+    data = state.data
+    short_run_number = data.sample_scatter_run_number
+    short_run_number_as_string = str(short_run_number)
+
+    # 2. Multiperiod
+    if state.data.sample_scatter_period != ALL_PERIODS:
+        period = data.sample_scatter_period
+        period_as_string = "p"+str(period)
+    else:
+        period_as_string = ""
+
+    # 3. Detector name
+    move = state.move
+    detectors = move.detectors
+    if reduction_mode is ISISReductionMode.Merged:
+        detector_name_short = "merged"
+    elif reduction_mode is ISISReductionMode.HAB:
+        detector_name_short = detectors[DetectorType.to_string(DetectorType.HAB)].detector_name_short
+    elif reduction_mode is ISISReductionMode.LAB:
+        detector_name_short = detectors[DetectorType.to_string(DetectorType.LAB)].detector_name_short
+    else:
+        raise RuntimeError("SANSStateFunctions: Unknown reduction mode {0} cannot be used to "
+                           "create an output name".format(reduction_mode))
+
+    # 4. Dimensionality
+    reduction = state.reduction
+    if reduction.reduction_dimensionality is ReductionDimensionality.OneDim:
+        dimensionality_as_string = "_1D"
+    else:
+        dimensionality_as_string = "_2D"
+
+    # 5. Wavelength range
+    wavelength = state.wavelength
+    wavelength_range_string = str(wavelength.wavelength_low) + "_" + str(wavelength.wavelength_high)
+
+    # 6. Phi Limits
+    mask = state.mask
+    if reduction.reduction_dimensionality is ReductionDimensionality.OneDim:
+        if mask.phi_min and mask.phi_max and (abs(mask.phi_max - mask.phi_min) != 180.0):
+            phi_limits_as_string = 'Phi' + str(mask.phi_min) + '_' + str(mask.phi_max)
+        else:
+            phi_limits_as_string = ""
+    else:
+        phi_limits_as_string = ""
+
+    # 7. Slice limits
+    slice_state = state.slice
+    start_time = slice_state.start_time
+    end_time = slice_state.end_time
+    if start_time and end_time:
+        start_time_as_string = '_t%.2f' % start_time[0]
+        end_time_as_string = '_T%.2f' % end_time[0]
+    else:
+        start_time_as_string = ""
+        end_time_as_string = ""
+
+    # Piece it all together
+    output_workspace_name = (short_run_number_as_string + period_as_string + detector_name_short +
+                             dimensionality_as_string + wavelength_range_string + phi_limits_as_string +
+                             start_time_as_string + end_time_as_string)
+    return output_workspace_name
+
+
+def is_pure_none_or_not_none(elements_to_check):
+    """
+    Checks a list of elements contains None entries and non-None entries
+
+    @param elements_to_check: a list with entries to check
+    @return: True if the list contains either only None or only non-None elements, else False
+    """
+    are_all_none_or_all_not_none = True
+
+    if len(elements_to_check) == 0:
+        return are_all_none_or_all_not_none
+    return all(element is not None for element in elements_to_check) or  \
+           all(element is None for element in elements_to_check)  # noqa
+
+
+def is_not_none_and_first_larger_than_second(elements_to_check):
+    """
+    This function checks if both are not none and then checks if the first element is smaller than the second element.
+
+    @param elements_to_check: a list with two entries. The first is the lower bound and the second entry is the upper
+                              bound
+    @return: False if at least one input is None or if both are not None and the first element is smaller than the
+             second else True
+    """
+    is_invalid = True
+    if len(elements_to_check) != 2:
+        return is_invalid
+    if any(element is None for element in elements_to_check):
+        is_invalid = False
+        return is_invalid
+    if elements_to_check[0] < elements_to_check[1]:
+        is_invalid = False
+    return is_invalid
+
+
+def one_is_none(elements_to_check):
+    return any(element is None for element in elements_to_check)
+
+
+def validation_message(error_message, instruction, variables):
+    """
+    Generates a validation message for the SANSState.
+
+    @param error_message: A message describing the error.
+    @param instruction: A message describing what to do to fix the error
+    @param variables: A dictionary which contains the variable names and values which are involved in the error.
+    @return: a formatted validation message string.
+    """
+    message = ""
+    for key, value in sorted(variables.items()):
+        message += "{0}: {1}\n".format(key, value)
+    message += instruction
+    return {error_message: message}
+
+
+def get_state_hash_for_can_reduction(state, partial_type=None):
+    """
+    Creates a hash for a (modified) state object.
+
+    Note that we need to modify the state object to exclude elements which are not relevant for the can reduction.
+    This is primarily the setting of the sample workspaces. This is the only place where we directly alter the value
+    of a state object
+    @param state: a SANSState object.
+    @param partial_type: if it is a partial type, then it needs to be specified here.
+    @return: the hash of the state
+    """
+    def remove_sample_related_information(full_state):
+        state_to_hash = deepcopy(full_state)
+        state_to_hash.data.sample_scatter = EMPTY_NAME
+        state_to_hash.data.sample_scatter_period = ALL_PERIODS
+        state_to_hash.data.sample_transmission = EMPTY_NAME
+        state_to_hash.data.sample_transmission_period = ALL_PERIODS
+        state_to_hash.data.sample_direct = EMPTY_NAME
+        state_to_hash.data.sample_direct_period = ALL_PERIODS
+        state_to_hash.data.sample_scatter_run_number = 1
+        return state_to_hash
+    new_state = remove_sample_related_information(state)
+    new_state_serialized = new_state.property_manager
+
+    # If we are dealing with a partial output workspace, then mark it as such
+    if partial_type is OutputParts.Count:
+        state_string = str(new_state_serialized) + "counts"
+    elif partial_type is OutputParts.Norm:
+        state_string = str(new_state_serialized) + "norm"
+    else:
+        state_string = str(new_state_serialized)
+    return str(get_hash_value(state_string))
+
+
+def get_workspace_from_ads_based_on_hash(hash_value):
+    for workspace in get_ads_workspace_references():
+        if has_hash(REDUCED_CAN_TAG, hash_value, workspace):
+            return workspace
+
+
+def get_reduced_can_workspace_from_ads(state, output_parts):
+    """
+    Get the reduced can workspace from the ADS if it exists else nothing
+
+    @param state: a SANSState object.
+    @param output_parts: if true then search also for the partial workspaces
+    @return: a reduced can object or None.
+    """
+    # Get the standard reduced can workspace
+    hashed_state = get_state_hash_for_can_reduction(state)
+    reduced_can = get_workspace_from_ads_based_on_hash(hashed_state)
+    reduced_can_count = None
+    reduced_can_norm = None
+    if output_parts:
+        hashed_state_count = get_state_hash_for_can_reduction(state, OutputParts.Count)
+        reduced_can_count = get_workspace_from_ads_based_on_hash(hashed_state_count)
+        hashed_state_norm = get_state_hash_for_can_reduction(state, OutputParts.Norm)
+        reduced_can_norm = get_workspace_from_ads_based_on_hash(hashed_state_norm)
+    return reduced_can, reduced_can_count, reduced_can_norm
+
+
+def write_hash_into_reduced_can_workspace(state, workspace, partial_type=None):
+    """
+    Writes the state hash into a reduced can workspace.
+
+    @param state: a SANSState object.
+    @param workspace: a reduced can workspace
+    @param partial_type: if it is a partial type, then it needs to be specified here.
+    """
+    hashed_state = get_state_hash_for_can_reduction(state, partial_type=partial_type)
+    set_hash(REDUCED_CAN_TAG, hashed_state, workspace)
+
+
+def set_detector_names(state, ipf_path):
+    """
+    Sets the detectors names on a State object which has a `detector` map entry, e.g. StateMask
+
+    @param state: the state object
+    @param ipf_path: the path to the Instrument Parameter File
+    """
+    lab_keyword = DetectorType.to_string(DetectorType.LAB)
+    hab_keyword = DetectorType.to_string(DetectorType.HAB)
+    detector_names = {lab_keyword: "low-angle-detector-name",
+                      hab_keyword: "high-angle-detector-name"}
+    detector_names_short = {lab_keyword: "low-angle-detector-short-name",
+                            hab_keyword: "high-angle-detector-short-name"}
+
+    names_to_search = []
+    names_to_search.extend(detector_names.values())
+    names_to_search.extend(detector_names_short.values())
+
+    found_detector_names = get_named_elements_from_ipf_file(ipf_path, names_to_search, str)
+
+    for detector_type in state.detectors:
+        try:
+            detector_name_tag = detector_names[detector_type]
+            detector_name_short_tag = detector_names_short[detector_type]
+            detector_name = found_detector_names[detector_name_tag]
+            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
+
+
+def set_monitor_names(state, idf_path):
+    monitor_names = get_monitor_names_from_idf_file(idf_path)
+    state.monitor_names = monitor_names
diff --git a/scripts/SANS/sans/state/wavelength.py b/scripts/SANS/sans/state/wavelength.py
new file mode 100644
index 0000000000000000000000000000000000000000..963e65262819daec6daabe6b02d59cb5dfbcd55e
--- /dev/null
+++ b/scripts/SANS/sans/state/wavelength.py
@@ -0,0 +1,70 @@
+""" Defines the state of the event slices which should be reduced."""
+
+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.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)
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# State
+# ----------------------------------------------------------------------------------------------------------------------
+@rename_descriptor_names
+class StateWavelength(StateBase):
+    rebin_type = ClassTypeParameter(RebinType)
+    wavelength_low = PositiveFloatParameter()
+    wavelength_high = PositiveFloatParameter()
+    wavelength_step = PositiveFloatParameter()
+    wavelength_step_type = ClassTypeParameter(RangeStepType)
+
+    def __init__(self):
+        super(StateWavelength, self).__init__()
+        self.rebin_type = RebinType.Rebin
+
+    def validate(self):
+        is_invalid = dict()
+        if one_is_none([self.wavelength_low, self.wavelength_high, self.wavelength_step]):
+            entry = validation_message("A wavelength entry has not been set.",
+                                       "Make sure that all entries for the wavelength are set.",
+                                       {"wavelength_low": self.wavelength_low,
+                                        "wavelength_high": self.wavelength_high,
+                                        "wavelength_step": self.wavelength_step})
+            is_invalid.update(entry)
+
+        if is_not_none_and_first_larger_than_second([self.wavelength_low, self.wavelength_high]):
+            entry = validation_message("Incorrect wavelength bounds.",
+                                       "Make sure that lower wavelength bound is smaller then upper bound.",
+                                       {"wavelength_low": self.wavelength_low,
+                                        "wavelength_high": self.wavelength_high})
+            is_invalid.update(entry)
+
+        if is_invalid:
+            raise ValueError("StateWavelength: The provided inputs are illegal. "
+                             "Please see: {0}".format(json.dumps(is_invalid, indent=4)))
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# Builder
+# ----------------------------------------------------------------------------------------------------------------------
+class StateWavelengthBuilder(object):
+    @automatic_setters(StateWavelength)
+    def __init__(self):
+        super(StateWavelengthBuilder, self).__init__()
+        self.state = StateWavelength()
+
+    def build(self):
+        # Make sure that the product is in a valid state, ie not incomplete
+        self.state.validate()
+        return copy.copy(self.state)
+
+
+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:
+        return StateWavelengthBuilder()
+    else:
+        raise NotImplementedError("StateWavelengthBuilder: Could not find any valid wavelength builder for the "
+                                  "specified StateData object {0}".format(str(data_info)))
diff --git a/scripts/SANS/sans/state/wavelength_and_pixel_adjustment.py b/scripts/SANS/sans/state/wavelength_and_pixel_adjustment.py
new file mode 100644
index 0000000000000000000000000000000000000000..2a363bc43d9801609a99d19053db1c13dd20d279
--- /dev/null
+++ b/scripts/SANS/sans/state/wavelength_and_pixel_adjustment.py
@@ -0,0 +1,99 @@
+# pylint: disable=too-few-public-methods
+
+"""State describing the creation of pixel and wavelength adjustment workspaces for SANS reduction."""
+
+import json
+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.state.automatic_setters import (automatic_setters)
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# State
+# ----------------------------------------------------------------------------------------------------------------------
+@rename_descriptor_names
+class StateAdjustmentFiles(StateBase):
+    pixel_adjustment_file = StringParameter()
+    wavelength_adjustment_file = StringParameter()
+
+    def __init__(self):
+        super(StateAdjustmentFiles, self).__init__()
+
+    def validate(self):
+        is_invalid = {}
+        # TODO if a file was specified then make sure that its existence is checked.
+
+        if is_invalid:
+            raise ValueError("StateAdjustmentFiles: The provided inputs are illegal. "
+                             "Please see: {0}".format(json.dumps(is_invalid)))
+
+
+@rename_descriptor_names
+class StateWavelengthAndPixelAdjustment(StateBase):
+    wavelength_low = PositiveFloatParameter()
+    wavelength_high = PositiveFloatParameter()
+    wavelength_step = PositiveFloatParameter()
+    wavelength_step_type = ClassTypeParameter(RangeStepType)
+
+    adjustment_files = DictParameter()
+
+    def __init__(self):
+        super(StateWavelengthAndPixelAdjustment, self).__init__()
+        self.adjustment_files = {DetectorType.to_string(DetectorType.LAB): StateAdjustmentFiles(),
+                                 DetectorType.to_string(DetectorType.HAB): StateAdjustmentFiles()}
+
+    def validate(self):
+        is_invalid = {}
+
+        if one_is_none([self.wavelength_low, self.wavelength_high, self.wavelength_step, self.wavelength_step_type]):
+            entry = validation_message("A wavelength entry has not been set.",
+                                       "Make sure that all entries are set.",
+                                       {"wavelength_low": self.wavelength_low,
+                                        "wavelength_high": self.wavelength_high,
+                                        "wavelength_step": self.wavelength_step,
+                                        "wavelength_step_type": self.wavelength_step_type})
+            is_invalid.update(entry)
+
+        if is_not_none_and_first_larger_than_second([self.wavelength_low, self.wavelength_high]):
+            entry = validation_message("Incorrect wavelength bounds.",
+                                       "Make sure that lower wavelength bound is smaller then upper bound.",
+                                       {"wavelength_low": self.wavelength_low,
+                                        "wavelength_high": self.wavelength_high})
+            is_invalid.update(entry)
+
+        try:
+            self.adjustment_files[DetectorType.to_string(DetectorType.LAB)].validate()
+            self.adjustment_files[DetectorType.to_string(DetectorType.HAB)].validate()
+        except ValueError as e:
+            is_invalid.update({"adjustment_files": str(e)})
+
+        if is_invalid:
+            raise ValueError("StateWavelengthAndPixelAdjustment: The provided inputs are illegal. "
+                             "Please see: {0}".format(json.dumps(is_invalid)))
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# Builder
+# ----------------------------------------------------------------------------------------------------------------------
+class StateWavelengthAndPixelAdjustmentBuilder(object):
+    @automatic_setters(StateWavelengthAndPixelAdjustment)
+    def __init__(self):
+        super(StateWavelengthAndPixelAdjustmentBuilder, self).__init__()
+        self.state = StateWavelengthAndPixelAdjustment()
+
+    def build(self):
+        self.state.validate()
+        return copy.copy(self.state)
+
+
+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:
+        return StateWavelengthAndPixelAdjustmentBuilder()
+    else:
+        raise NotImplementedError("StateWavelengthAndPixelAdjustmentBuilder: Could not find any valid "
+                                  "wavelength and pixel adjustment builder for the specified "
+                                  "StateData object {0}".format(str(data_info)))
diff --git a/scripts/test/ConvertToWavelengthTest.py b/scripts/test/ConvertToWavelengthTest.py
index e6e8c0467b2b2438d70a706c5e95ece26701e0a7..a07407479eb2f2e49ba2e6ad19ee41691fbc7e55 100644
--- a/scripts/test/ConvertToWavelengthTest.py
+++ b/scripts/test/ConvertToWavelengthTest.py
@@ -15,7 +15,7 @@ class ConvertToWavelengthTest(unittest.TestCase):
     def test_construction_from_single_ws_name(self):
         ws = CreateWorkspace(DataY=[1,2,3], DataX=[1,2,3])
 
-        converter = ConvertToWavelength(ws.getName())
+        converter = ConvertToWavelength(ws.name())
         self.assertTrue(converter != None, "Should have been able to make a valid converter from a single workspace name")
         DeleteWorkspace(ws)
 
@@ -30,7 +30,7 @@ class ConvertToWavelengthTest(unittest.TestCase):
     def test_construction_from_many_workspace_names(self):
         ws1 = CreateWorkspace(DataY=[1,2,3], DataX=[1,2,3])
         ws2 = CreateWorkspace(DataY=[1,2,3], DataX=[1,2,3])
-        converter = ConvertToWavelength([ws1.getName(), ws2.getName()])
+        converter = ConvertToWavelength([ws1.name(), ws2.name()])
         self.assertTrue(converter != None, "Should have been able to make a valid converter from many workspace objects")
         DeleteWorkspace(ws1)
         DeleteWorkspace(ws2)
@@ -38,7 +38,7 @@ class ConvertToWavelengthTest(unittest.TestCase):
     def test_construction_from_comma_separated_workspaces(self):
         ws1 = CreateWorkspace(DataY=[1,2,3], DataX=[1,2,3])
         ws2 = CreateWorkspace(DataY=[1,2,3], DataX=[1,2,3])
-        comma_separated_names = "%s, %s" % (ws1.getName(), ws2.getName())
+        comma_separated_names = "%s, %s" % (ws1.name(), ws2.name())
         converter = ConvertToWavelength(comma_separated_names)
         self.assertTrue(converter != None, "Should have been able to make a valid converter from many , separated workspace objects")
         DeleteWorkspace(ws1)
@@ -47,7 +47,7 @@ class ConvertToWavelengthTest(unittest.TestCase):
     def test_construction_from_semicolon_separated_workspaces(self):
         ws1 = CreateWorkspace(DataY=[1,2,3], DataX=[1,2,3])
         ws2 = CreateWorkspace(DataY=[1,2,3], DataX=[1,2,3])
-        colon_separated_names = "%s: %s" % (ws1.getName(), ws2.getName())
+        colon_separated_names = "%s: %s" % (ws1.name(), ws2.name())
         converter = ConvertToWavelength(colon_separated_names)
         self.assertTrue(converter != None, "Should have been able to make a valid converter from many : separated workspace objects")
         DeleteWorkspace(ws1)
diff --git a/scripts/test/CrystalFieldTest.py b/scripts/test/CrystalFieldTest.py
index ca09e18ec8fbee002ecd32f647c63d0f6d58a198..ff30d1ac5fac912c01b70b94f30e26c467c4bd21 100644
--- a/scripts/test/CrystalFieldTest.py
+++ b/scripts/test/CrystalFieldTest.py
@@ -3,15 +3,17 @@
 from __future__ import (absolute_import, division, print_function)
 import unittest
 import numpy as np
+from scipy.constants import physical_constants
 
 # Import mantid to setup the python paths to the bundled scripts
 import mantid
 from CrystalField.energies import energies
-from mantid.simpleapi import CalculateChiSquared
+from mantid.simpleapi import CalculateChiSquared, EvaluateFunction, mtd
 from mantid.kernel import ConfigService
 
 c_mbsr = 79.5774715459  # Conversion from barn to mb/sr
 
+
 class BackgroundTest(unittest.TestCase):
 
     def setUp(self):
@@ -94,14 +96,14 @@ class CrystalFieldTests(unittest.TestCase):
         for i in range(9):
             self.assertAlmostEqual(expectedEigenvalues[i], en[i], 1)
         # Now test the eigenvectors by computing the dipole transition matrix elements. Use the magnetic field
-        #   terms but divide by gJ*uB (gJ=0.8 for U4+/Pr3+ and uB=0.6715)
+        #   terms but divide by gJ*uB (gJ=0.8 for U4+/Pr3+ and uB=0.05788 meV/T)
         _, _, hx = energies(2, BextX=1.0)
         _, _, hy = energies(2, BextY=1.0)
         _, _, hz = energies(2, BextZ=1.0)
         ix = np.dot(np.conj(np.transpose(wf)), np.dot(hx, wf))
         iy = np.dot(np.conj(np.transpose(wf)), np.dot(hy, wf))
         iz = np.dot(np.conj(np.transpose(wf)), np.dot(hz, wf))
-        gJuB = 0.53716
+        gJuB = 0.8 * physical_constants['Bohr magneton in eV/T'][0] * 1000.
         trans = np.multiply(ix, np.conj(ix)) + np.multiply(iy, np.conj(iy)) + np.multiply(iz, np.conj(iz))
         # For some reason, in the paper I also divided the matrix elements by a factor of 4. (not sure why)
         trans = trans / (gJuB ** 2) / 4
@@ -342,7 +344,7 @@ class CrystalFieldTests(unittest.TestCase):
 
         x0, y0 = cf.getSpectrum()
         x1, y1 = cf.getSpectrum(1)
-        # Original test was for FOCUS convention - intensity in barn. 
+        # Original test was for FOCUS convention - intensity in barn.
         # Now use ISIS convention with intensity in milibarn/steradian
         y0 = y0 / c_mbsr
         y1 = y1 / c_mbsr
@@ -355,6 +357,42 @@ class CrystalFieldTests(unittest.TestCase):
         self.assertAlmostEqual(y1[139], 2.1635845058245273, 8)
         self.assertAlmostEqual(y1[150], 2.1826462206185795, 8)
 
+    def test_api_CrystalField_physical_properties(self):
+        from CrystalField import CrystalField
+        cf = CrystalField('Ce', 'C2v', B20=0.37737, B22=3.9770, B40=-0.031787, B42=-0.11611, B44=-0.12544)
+        # Test Heat capacity calculations
+        TCv, Cv = cf.getHeatCapacity() 
+        self.assertAlmostEqual(TCv[150], 151, 4)
+        self.assertAlmostEqual(Cv[100], 4.2264, 3)
+        self.assertAlmostEqual(Cv[150], 5.9218, 3)
+        self.assertAlmostEqual(Cv[200], 5.4599, 3)
+
+        # Test susceptibility calculations
+        Tchi_powder, chi_powder = cf.getSusceptibility(np.linspace(1,300,50), Hdir='powder')
+        self.assertAlmostEqual(Tchi_powder[10], 62.02, 2)
+        self.assertAlmostEqual(chi_powder[5], 1.92026e-2, 6)
+        self.assertAlmostEqual(chi_powder[10], 1.03471e-2, 6)
+        self.assertAlmostEqual(chi_powder[15], 0.73004e-2, 6)
+
+        # Test M(T) calculations
+        Tmt_powder, mt_powder = cf.getMagneticMoment(1., Temperature=np.linspace(1,300,50), Hdir='powder', Unit='cgs')
+        self.assertAlmostEqual(chi_powder[5], mt_powder[5], 6)
+        self.assertAlmostEqual(chi_powder[10], mt_powder[10], 6)
+        self.assertAlmostEqual(chi_powder[15], mt_powder[15], 6)
+        _, invmt_powder_SI = cf.getMagneticMoment(1., Temperature=np.linspace(1,300,50), Hdir='powder', Unit='SI', Inverse=True)
+        self.assertAlmostEqual(chi_powder[5] * 10, 1 / invmt_powder_SI[5], 2)
+        self.assertAlmostEqual(chi_powder[10] * 10, 1 / invmt_powder_SI[10], 2)
+        self.assertAlmostEqual(chi_powder[15] * 10, 1 / invmt_powder_SI[15], 2)
+
+        # Test M(H) calculations
+        Hmag_SI, mag_SI = cf.getMagneticMoment(np.linspace(0,30,15), Temperature=10, Hdir=[0,1,-1], Unit='SI')
+        self.assertAlmostEqual(mag_SI[1], 1.8139, 3)
+        self.assertAlmostEqual(mag_SI[5], 6.7859, 3)
+        self.assertAlmostEqual(mag_SI[9], 8.2705, 3)
+        _, mag_bohr = cf.getMagneticMoment(np.linspace(0,30,15), Temperature=10, Hdir=[0,1,-1], Unit='bohr')
+        self.assertAlmostEqual(mag_SI[1] / 5.5849, mag_bohr[1], 3)
+        self.assertAlmostEqual(mag_SI[5] / 5.5849, mag_bohr[5], 3)
+        self.assertAlmostEqual(mag_SI[9] / 5.5849, mag_bohr[9], 3)
 
 class CrystalFieldFitTest(unittest.TestCase):
 
@@ -442,7 +480,6 @@ class CrystalFieldFitTest(unittest.TestCase):
         self.assertAlmostEqual(cf.peaks.param[2]['FWHM'], 1.10000812804, 4)
         self.assertAlmostEqual(cf.peaks.param[2]['Amplitude'], 0.429808829601*c_mbsr, 2)
 
-
     def test_CrystalFieldFit_multi_spectrum(self):
         from CrystalField.fitting import makeWorkspace
         from CrystalField import CrystalField, CrystalFieldFit, Background, Function
@@ -529,7 +566,6 @@ class CrystalFieldFitTest(unittest.TestCase):
         self.assertNotEqual(cf.peaks[1].param[3]['FWHM'], 0.0)
         self.assertNotEqual(cf.peaks[1].param[3]['Amplitude'], 0.0)
 
-
     def test_CrystalFieldFit_multi_spectrum_simple_background(self):
         from CrystalField.fitting import makeWorkspace
         from CrystalField import CrystalField, CrystalFieldFit, Background, Function
@@ -649,6 +685,7 @@ class CrystalFieldFitTest(unittest.TestCase):
         fit = CrystalFieldFit(Model=cf, InputWorkspace=ws, MaxIterations=10)
         fit.fit()
 
+        self.assertTrue(cf.chi2 > 0.0)
         self.assertTrue(cf.chi2 < chi2)
 
         # Fit outputs are different on different platforms.
@@ -680,9 +717,11 @@ class CrystalFieldFitTest(unittest.TestCase):
 
         cf1 = CrystalField('Ce', 'C2v', B40=-0.02, B42=-0.11, B44=-0.12, Temperature=[44.0, 50.0], FWHM=[1.0, 1.0])
         cf1.ties(B20=0.37737, B22=3.977, IntensityScaling0=1.0, IntensityScaling1=1.0)
+        cf1.FixAllPeaks = True
         cf2 = CrystalField('Pr', 'C2v', B40=-0.03, B42=-0.116, B44=-0.125, Temperature=[44.0, 50.0], FWHM=[1.0, 1.0],
                            ToleranceIntensity=6.0, ToleranceEnergy=1.0)
         cf2.ties(B20=0.37737, B22=3.977, IntensityScaling0=1.0, IntensityScaling1=1.0)
+        cf2.FixAllPeaks = True
         cf = cf1 + cf2
 
         chi2 = CalculateChiSquared(cf.makeMultiSpectrumFunction(), InputWorkspace=ws1, InputWorkspace_1=ws2)[1]
@@ -690,6 +729,7 @@ class CrystalFieldFitTest(unittest.TestCase):
         fit = CrystalFieldFit(Model=cf, InputWorkspace=[ws1, ws2])
         fit.fit()
 
+        self.assertTrue(cf.chi2 > 0.0)
         self.assertTrue(cf.chi2 < chi2)
 
         # Fit outputs are different on different platforms.
@@ -1214,6 +1254,354 @@ class CrystalFieldFitTest(unittest.TestCase):
         self.assertEqual(cf1.peaks.param[1]['Amplitude'], cf2.peaks.param[1]['Amplitude'],)
         self.assertEqual(cf1.peaks.param[1]['FWHM'], cf2.peaks.param[1]['FWHM'],)
 
+    def test_monte_carlo_single_spectrum(self):
+        from CrystalField.fitting import makeWorkspace
+        from CrystalField import CrystalField, CrystalFieldFit, Background, Function
+
+        # Create some crystal field data
+        origin = CrystalField('Ce', 'C2v', B20=0.37737, B22=3.9770, B40=-0.031787, B42=-0.11611, B44=-0.12544,
+                              Temperature=44.0, FWHM=1.1)
+        x, y = origin.getSpectrum()
+        ws = makeWorkspace(x, y)
+
+        # Define a CrystalField object with parameters slightly shifted.
+        cf = CrystalField('Ce', 'C2v', B20=0, B22=0, B40=0, B42=0, B44=0,
+                          Temperature=44.0, FWHM=1.0)
+
+        # Set the ties
+        cf.ties(B20=0.37737)
+        cf.constraints('2<B22<6', '-0.2<B40<0.2', '-0.2<B42<0.2', '-0.2<B44<0.2')
+        # Create a fit object
+        fit = CrystalFieldFit(cf, InputWorkspace=ws)
+        fit.monte_carlo(NSamples=1000, Constraints='20<f1.PeakCentre<45,20<f2.PeakCentre<45')
+        # Run fit
+        fit.fit()
+        self.assertTrue(cf.chi2 > 0.0)
+        self.assertTrue(cf.chi2 < 100.0)
+
+    def test_monte_carlo_multi_spectrum(self):
+        from CrystalField.fitting import makeWorkspace
+        from CrystalField import CrystalField, CrystalFieldFit, Background, Function, ResolutionModel
+
+        # Create some crystal field data
+        origin = CrystalField('Ce', 'C2v', B20=0.37737, B22=3.9770, B40=-0.031787, B42=-0.11611, B44=-0.12544,
+                              Temperature=[44.0, 50.0], FWHM=[1.0, 1.0])
+        ws1 = makeWorkspace(*origin.getSpectrum(0))
+        ws2 = makeWorkspace(*origin.getSpectrum(1))
+
+        # Define a CrystalField object with parameters slightly shifted.
+        cf = CrystalField('Ce', 'C2v', B20=0.37737, B22=3.9770, B40=0, B42=0, B44=0, NPeaks=11,
+                          Temperature=[44.0, 50.0], FWHM=[1.0, 1.0])
+
+        # Set the ties
+        cf.ties(B20=0.37737)
+        cf.constraints('2<B22<6', '-0.2<B40<0.2', '-0.2<B42<0.2', '-0.2<B44<0.2')
+        # Create a fit object
+        fit = CrystalFieldFit(cf, InputWorkspace=[ws1, ws2])
+        fit.monte_carlo(NSamples=1000, Constraints='20<f0.f1.PeakCentre<45,20<f0.f2.PeakCentre<45')
+        # Run fit
+        fit.fit()
+        self.assertTrue(cf.chi2 > 0.0)
+        self.assertTrue(cf.chi2 < 200.0)
+
+    def test_multi_ion_intensity_scaling(self):
+        from CrystalField import CrystalField, CrystalFieldFit
+        from mantid.simpleapi import FunctionFactory
+        params = {'B20': 0.37737, 'B22': 3.9770, 'B40': -0.031787, 'B42': -0.11611, 'B44': -0.12544,
+                  'Temperature': 44.0, 'FWHM': 1.1}
+        cf1 = CrystalField('Ce', 'C2v', **params)
+        cf2 = CrystalField('Pr', 'C2v', **params)
+        cf = cf1 + cf2
+        fun = FunctionFactory.createInitialized(cf.makeSpectrumFunction())
+        s = str(fun)
+        self.assertTrue('f1.IntensityScaling=1.0*f0.IntensityScaling' in s)
+
+        cf = 2*cf1 + cf2*8
+        fun = FunctionFactory.createInitialized(cf.makeSpectrumFunction())
+        s = str(fun)
+        self.assertTrue('f0.IntensityScaling=0.25*f1.IntensityScaling' in s)
+
+        cf = 2 * cf1 + cf2
+        fun = FunctionFactory.createInitialized(cf.makeSpectrumFunction())
+        s = str(fun)
+        self.assertTrue('f1.IntensityScaling=0.5*f0.IntensityScaling' in s)
+
+        cf3 = CrystalField('Tb', 'C2v', **params)
+        cf = 2 * cf1 + cf2 * 8 + cf3
+        fun = FunctionFactory.createInitialized(cf.makeSpectrumFunction())
+        s = str(fun)
+        self.assertTrue('f0.IntensityScaling=0.25*f1.IntensityScaling' in s)
+        self.assertTrue('f2.IntensityScaling=0.125*f1.IntensityScaling' in s)
+
+        cf = 2 * cf1 + cf2 * 8 + 10 * cf3
+        fun = FunctionFactory.createInitialized(cf.makeSpectrumFunction())
+        s = str(fun)
+        self.assertTrue('f0.IntensityScaling=0.2*f2.IntensityScaling' in s)
+        self.assertTrue('f1.IntensityScaling=0.8*f2.IntensityScaling' in s)
+
+        cf = 2 * cf1 + (cf2 * 8 + 10 * cf3)
+        fun = FunctionFactory.createInitialized(cf.makeSpectrumFunction())
+        s = str(fun)
+        self.assertTrue('f0.IntensityScaling=0.2*f2.IntensityScaling' in s)
+        self.assertTrue('f1.IntensityScaling=0.8*f2.IntensityScaling' in s)
+
+        cf = cf1 + (cf2 * 8 + 10 * cf3)
+        fun = FunctionFactory.createInitialized(cf.makeSpectrumFunction())
+        s = str(fun)
+        self.assertTrue('f0.IntensityScaling=0.1*f2.IntensityScaling' in s)
+        self.assertTrue('f1.IntensityScaling=0.8*f2.IntensityScaling' in s)
+
+        cf4 = CrystalField('Yb', 'C2v', **params)
+        cf = (2 * cf1 + cf2 * 8) + (10 * cf3 + cf4)
+        fun = FunctionFactory.createInitialized(cf.makeSpectrumFunction())
+        s = str(fun)
+        self.assertTrue('f0.IntensityScaling=0.2*f2.IntensityScaling' in s)
+        self.assertTrue('f1.IntensityScaling=0.8*f2.IntensityScaling' in s)
+        self.assertTrue('f3.IntensityScaling=0.1*f2.IntensityScaling' in s)
+
+    def test_multi_ion_intensity_scaling_multi_spectrum(self):
+        from CrystalField import CrystalField, CrystalFieldFit
+        from mantid.simpleapi import FunctionFactory
+        params = {'B20': 0.37737, 'B22': 3.9770, 'B40': -0.031787, 'B42': -0.11611, 'B44': -0.12544,
+                  'Temperature': [44.0, 50.0], 'FWHM': [1.1, 1.6]}
+        cf1 = CrystalField('Ce', 'C2v', **params)
+        cf2 = CrystalField('Pr', 'C2v', **params)
+        cf = cf1 + cf2
+        fun = FunctionFactory.createInitialized(cf.makeMultiSpectrumFunction())
+        s = str(fun)
+        self.assertTrue('f1.IntensityScaling0=1.0*f0.IntensityScaling0' in s)
+        self.assertTrue('f1.IntensityScaling1=1.0*f0.IntensityScaling1' in s)
+
+        cf = 2 * cf1 + cf2 * 8
+        fun = FunctionFactory.createInitialized(cf.makeMultiSpectrumFunction())
+        s = str(fun)
+        self.assertTrue('f0.IntensityScaling0=0.25*f1.IntensityScaling0' in s)
+        self.assertTrue('f0.IntensityScaling1=0.25*f1.IntensityScaling1' in s)
+
+        cf = 2 * cf1 + cf2
+        fun = FunctionFactory.createInitialized(cf.makeMultiSpectrumFunction())
+        s = str(fun)
+        self.assertTrue('f1.IntensityScaling0=0.5*f0.IntensityScaling0' in s)
+        self.assertTrue('f1.IntensityScaling1=0.5*f0.IntensityScaling1' in s)
+
+        cf3 = CrystalField('Tb', 'C2v', **params)
+        cf = 2 * cf1 + cf2 * 8 + cf3
+        fun = FunctionFactory.createInitialized(cf.makeMultiSpectrumFunction())
+        s = str(fun)
+        self.assertTrue('f0.IntensityScaling0=0.25*f1.IntensityScaling0' in s)
+        self.assertTrue('f0.IntensityScaling1=0.25*f1.IntensityScaling1' in s)
+        self.assertTrue('f2.IntensityScaling0=0.125*f1.IntensityScaling0' in s)
+        self.assertTrue('f2.IntensityScaling1=0.125*f1.IntensityScaling1' in s)
+
+        cf = 2 * cf1 + cf2 * 8 + 10 * cf3
+        fun = FunctionFactory.createInitialized(cf.makeMultiSpectrumFunction())
+        s = str(fun)
+        self.assertTrue('f0.IntensityScaling0=0.2*f2.IntensityScaling0' in s)
+        self.assertTrue('f0.IntensityScaling1=0.2*f2.IntensityScaling1' in s)
+        self.assertTrue('f1.IntensityScaling0=0.8*f2.IntensityScaling0' in s)
+        self.assertTrue('f1.IntensityScaling1=0.8*f2.IntensityScaling1' in s)
+
+        cf = 2 * cf1 + (cf2 * 8 + 10 * cf3)
+        fun = FunctionFactory.createInitialized(cf.makeMultiSpectrumFunction())
+        s = str(fun)
+        self.assertTrue('f0.IntensityScaling0=0.2*f2.IntensityScaling0' in s)
+        self.assertTrue('f0.IntensityScaling1=0.2*f2.IntensityScaling1' in s)
+        self.assertTrue('f1.IntensityScaling0=0.8*f2.IntensityScaling0' in s)
+        self.assertTrue('f1.IntensityScaling1=0.8*f2.IntensityScaling1' in s)
+
+        cf = cf1 + (cf2 * 8 + 10 * cf3)
+        fun = FunctionFactory.createInitialized(cf.makeMultiSpectrumFunction())
+        s = str(fun)
+        self.assertTrue('f0.IntensityScaling0=0.1*f2.IntensityScaling0' in s)
+        self.assertTrue('f0.IntensityScaling1=0.1*f2.IntensityScaling1' in s)
+        self.assertTrue('f1.IntensityScaling0=0.8*f2.IntensityScaling0' in s)
+        self.assertTrue('f1.IntensityScaling1=0.8*f2.IntensityScaling1' in s)
+
+        cf4 = CrystalField('Yb', 'C2v', **params)
+        cf = (2 * cf1 + cf2 * 8) + (10 * cf3 + cf4)
+        fun = FunctionFactory.createInitialized(cf.makeMultiSpectrumFunction())
+        s = str(fun)
+        self.assertTrue('f0.IntensityScaling0=0.2*f2.IntensityScaling0' in s)
+        self.assertTrue('f0.IntensityScaling1=0.2*f2.IntensityScaling1' in s)
+        self.assertTrue('f1.IntensityScaling0=0.8*f2.IntensityScaling0' in s)
+        self.assertTrue('f1.IntensityScaling1=0.8*f2.IntensityScaling1' in s)
+        self.assertTrue('f3.IntensityScaling0=0.1*f2.IntensityScaling0' in s)
+        self.assertTrue('f3.IntensityScaling1=0.1*f2.IntensityScaling1' in s)
+
+    def test_normalisation(self):
+        from CrystalField.normalisation import split2range
+        ranges = split2range(Ion='Pr', EnergySplitting=10,
+                             Parameters=['B20', 'B22', 'B40', 'B42', 'B44', 'B60', 'B62', 'B64', 'B66'])
+        self.assertAlmostEqual(ranges['B44'], 0.013099063718959822, 7)
+        self.assertAlmostEqual(ranges['B60'], 0.00010601965319487525, 7)
+        self.assertAlmostEqual(ranges['B40'], 0.0022141458870077678, 7)
+        self.assertAlmostEqual(ranges['B42'], 0.009901961430901874, 7)
+        self.assertAlmostEqual(ranges['B64'], 0.00084150490931686321, 7)
+        self.assertAlmostEqual(ranges['B22'], 0.19554806997215959, 7)
+        self.assertAlmostEqual(ranges['B20'], 0.11289973083793813, 7)
+        self.assertAlmostEqual(ranges['B66'], 0.0011394030334966495, 7)
+        self.assertAlmostEqual(ranges['B62'], 0.00076818536847364201, 7)
+
+    def test_estimate_parameters_cross_entropy(self):
+        from CrystalField.fitting import makeWorkspace
+        from CrystalField import CrystalField, CrystalFieldFit, Background, Function
+
+        # Create some crystal field data
+        origin = CrystalField('Ce', 'C2v', B20=0.37737, B22=3.9770, B40=-0.031787, B42=-0.11611, B44=-0.12544,
+                              Temperature=44.0, FWHM=1.1)
+        x, y = origin.getSpectrum()
+        ws = makeWorkspace(x, y)
+
+        # Define a CrystalField object with parameters slightly shifted.
+        cf = CrystalField('Ce', 'C2v', B20=0, B22=0, B40=0, B42=0, B44=0,
+                          Temperature=44.0, FWHM=1.0)
+
+        # Set the ties
+        cf.ties(B20=0.37737)
+        # Create a fit object
+        fit = CrystalFieldFit(cf, InputWorkspace=ws)
+        fit.estimate_parameters(50, ['B22', 'B40', 'B42', 'B44'],
+                                constraints='20<f1.PeakCentre<45,20<f2.PeakCentre<45',
+                                Type='Cross Entropy', NSamples=100)
+        # Run fit
+        fit.fit()
+        self.assertTrue(cf.chi2 < 100.0)
+
+    def test_estimate_parameters_multiple_results(self):
+        from CrystalField.fitting import makeWorkspace
+        from CrystalField import CrystalField, CrystalFieldFit, Background, Function
+
+        # Create some crystal field data
+        origin = CrystalField('Ce', 'C2v', B20=0.37737, B22=3.9770, B40=-0.031787, B42=-0.11611, B44=-0.12544,
+                              Temperature=44.0, FWHM=1.1)
+        x, y = origin.getSpectrum()
+        ws = makeWorkspace(x, y)
+
+        # Define a CrystalField object with parameters slightly shifted.
+        cf = CrystalField('Ce', 'C2v', B20=0, B22=0, B40=0, B42=0, B44=0,
+                          Temperature=44.0, FWHM=1.0)
+
+        # Set the ties
+        cf.ties(B20=0.37737)
+        # Create a fit object
+        fit = CrystalFieldFit(cf, InputWorkspace=ws)
+        fit.estimate_parameters(50, ['B22', 'B40', 'B42', 'B44'],
+                                constraints='20<f1.PeakCentre<45,20<f2.PeakCentre<45', NSamples=1000)
+        self.assertEqual(fit.get_number_estimates(), 10)
+        fit.fit()
+        self.assertTrue(cf.chi2 < 100.0)
+
+    def test_intensity_scaling_single_spectrum(self):
+        from CrystalField import CrystalField, CrystalFieldFit, Background, Function
+
+        # Define a CrystalField object with parameters slightly shifted.
+        cf = CrystalField('Ce', 'C2v', B20=0.37737, B22=3.9770, B40=-0.031787, B42=-0.11611, B44=-0.12544,
+                          Temperature=44.0, FWHM=1.0)
+        _, y0 = cf.getSpectrum()
+
+        cf.IntensityScaling = 2.5
+        _, y1 = cf.getSpectrum()
+
+        self.assertTrue(np.all(y1 / y0 > 2.49999999999))
+        self.assertTrue(np.all(y1 / y0 < 2.50000000001))
+
+    def test_intensity_scaling_single_spectrum_1(self):
+        from CrystalField import CrystalField, CrystalFieldFit, Background, Function
+
+        # Define a CrystalField object with parameters slightly shifted.
+        cf = CrystalField('Ce', 'C2v', IntensityScaling=2.5, B20=0.37737, B22=3.9770, B40=-0.031787,
+                          B42=-0.11611, B44=-0.12544, Temperature=44.0, FWHM=1.0)
+        _, y0 = cf.getSpectrum()
+
+        cf.IntensityScaling = 1.0
+        _, y1 = cf.getSpectrum()
+
+        self.assertTrue(np.all(y0 / y1 > 2.49999999999))
+        self.assertTrue(np.all(y0 / y1 < 2.50000000001))
+
+    def test_intensity_scaling_multi_spectrum(self):
+        from CrystalField.fitting import makeWorkspace
+        from CrystalField import CrystalField, CrystalFieldFit, Background, Function
+
+        # Define a CrystalField object with parameters slightly shifted.
+        cf = CrystalField('Ce', 'C2v', B20=0.37737, B22=3.9770, B40=-0.031787, B42=-0.11611, B44=-0.12544,
+                          Temperature=[44.0, 50.0], FWHM=[1.0, 1.2])
+        x, y0 = cf.getSpectrum(0)
+        ws0 = makeWorkspace(x, y0)
+        x, y1 = cf.getSpectrum(1)
+        ws1 = makeWorkspace(x, y1)
+
+        cf.IntensityScaling = [2.5, 1.5]
+
+        EvaluateFunction(cf.makeMultiSpectrumFunction(), InputWorkspace=ws0, InputWorkspace_1=ws1,
+                         OutputWorkspace='out')
+        out = mtd['out']
+        out0 = out[0].readY(1)
+        out1 = out[1].readY(1)
+
+        self.assertTrue(np.all(out0 / y0 > 2.49999999999))
+        self.assertTrue(np.all(out0 / y0 < 2.50000000001))
+
+        self.assertTrue(np.all(out1 / y1 > 1.49999999999))
+        self.assertTrue(np.all(out1 / y1 < 1.50000000001))
+
+    def test_CrystalFieldFit_physical_properties(self):
+        from CrystalField.fitting import makeWorkspace
+        from CrystalField import CrystalField, CrystalFieldFit, PhysicalProperties
+        origin = CrystalField('Ce', 'C2v', B20=0.37737, B22=3.9770, B40=-0.031787, B42=-0.11611, B44=-0.12544, 
+                              Temperature=[10, 100], FWHM=[1.1, 1.2])
+        ws0 = makeWorkspace(*origin.getSpectrum(0))
+        ws1 = makeWorkspace(*origin.getSpectrum(1))
+        wscv = makeWorkspace(*origin.getHeatCapacity())
+        wschi = makeWorkspace(*origin.getSusceptibility(Hdir='powder'))
+        wsmag = makeWorkspace(*origin.getMagneticMoment(Hdir=[0,1,0]))
+        wsmom = makeWorkspace(*origin.getMagneticMoment(H=100, T=np.linspace(1,300,300), Unit='cgs'))
+
+        # Fits single physical properties dataset
+        cf = CrystalField('Ce', 'C2v', B20=0.37, B22=3.97, B40=-0.0317, B42=-0.116, B44=-0.12)
+        cf.PhysicalProperty = PhysicalProperties('susc', Hdir='powder')
+        fit = CrystalFieldFit(Model=cf, InputWorkspace=wschi, MaxIterations=100)
+        fit.fit()
+        self.assertAlmostEqual(cf['B20'], 0.37737, 4)
+        self.assertAlmostEqual(cf['B22'], 3.97700087765, 4)
+        self.assertAlmostEqual(cf['B40'], -0.0317867635188, 4)
+        self.assertAlmostEqual(cf['B42'], -0.116110640723, 4)
+        self.assertAlmostEqual(cf['B44'], -0.125439939584, 4)
+        
+        # Fits multiple physical properties
+        cf = CrystalField('Ce', 'C2v', B20=0.37, B22=3.97, B40=-0.0317, B42=-0.116, B44=-0.12)
+        cf.PhysicalProperty = [PhysicalProperties('susc', 'powder'), PhysicalProperties('M(H)', Hdir=[0,1,0])]
+        fit = CrystalFieldFit(Model=cf, InputWorkspace=[wschi, wsmag], MaxIterations=100)
+        fit.fit()
+        self.assertAlmostEqual(cf['B20'], 0.37737, 4)
+        self.assertAlmostEqual(cf['B22'], 3.97700087765, 4)
+        self.assertAlmostEqual(cf['B40'], -0.0317867635188, 4)
+        self.assertAlmostEqual(cf['B42'], -0.116110640723, 4)
+        self.assertAlmostEqual(cf['B44'], -0.125439939584, 4)
+
+        # Fits one INS spectrum and one physical property
+        cf = CrystalField('Ce', 'C2v', B20=0.37, B22=3.97, B40=-0.0317, B42=-0.116, B44=-0.12, Temperature=10, FWHM=1.1)
+        cf.PhysicalProperty = PhysicalProperties('M(H)',Hdir=[0,1,0])
+        fit = CrystalFieldFit(Model=cf, InputWorkspace=[ws0, wsmag], MaxIterations=100)
+        fit.fit()
+        self.assertAlmostEqual(cf['B20'], 0.37737, 4)
+        self.assertAlmostEqual(cf['B22'], 3.97700087765, 4)
+        self.assertAlmostEqual(cf['B40'], -0.0317867635188, 4)
+        self.assertAlmostEqual(cf['B42'], -0.116110640723, 4)
+        self.assertAlmostEqual(cf['B44'], -0.125439939584, 4)
+
+        # Fits multiple INS spectra and multiple physical properties
+        cf = CrystalField('Ce', 'C2v', B20=0.37, B22=3.97, B40=-0.0317, B42=-0.116, B44=-0.12, 
+                          Temperature=[10, 100], FWHM=[1.1, 1.2])
+        cf.PhysicalProperty = [PhysicalProperties('susc', 'powder'), PhysicalProperties('M(H)', Hdir=[0,1,0])]
+        fit = CrystalFieldFit(Model=cf, InputWorkspace=[ws0, ws1, wschi, wsmag], MaxIterations=100)
+        fit.fit()
+        self.assertAlmostEqual(cf['B20'], 0.37737, 4)
+        self.assertAlmostEqual(cf['B22'], 3.97700087765, 4)
+        self.assertAlmostEqual(cf['B40'], -0.0317867635188, 4)
+        self.assertAlmostEqual(cf['B42'], -0.116110640723, 4)
+        self.assertAlmostEqual(cf['B44'], -0.125439939584, 4)
+
 
 if __name__ == "__main__":
     unittest.main()
diff --git a/scripts/test/ISIS_Powder_AbstractInstTest.py b/scripts/test/ISIS_Powder_AbstractInstTest.py
index 325a10e36d93689a5cdd6f5f78a02c4daa93040d..80fcb072d0792fefd1ba9fac915b92528c487706 100644
--- a/scripts/test/ISIS_Powder_AbstractInstTest.py
+++ b/scripts/test/ISIS_Powder_AbstractInstTest.py
@@ -2,6 +2,8 @@ import unittest
 
 import mantid as mantid  # For next import to work
 from isis_powder.mock_instrument import MockInstrument
+import os
+
 
 class isis_powder_AbstractInstTest(unittest.TestCase):
 
@@ -11,70 +13,18 @@ class isis_powder_AbstractInstTest(unittest.TestCase):
         # Default Params
 
         self.assertEquals(inst.calibration_dir, self.calibration_dir)
-        self.assertEquals(inst.raw_data_dir, self.raw_data_dir)
         self.assertEquals(inst.output_dir, self.output_dir)
 
         # Optional Params
-        self.assertEquals(inst.tt_mode, self.tt_mode)
         self.assertEquals(inst.default_input_ext, self.default_ext)
 
-    def test_generate_out_file_paths(self):
-        inst = self._get_abstract_inst_defaults()
-
-        test_out_dir = "testDir\\"
-        reference_name = inst._generate_inst_file_name(run_number="123")
-        file_name_without_ext = test_out_dir + reference_name
-
-        output = inst._generate_out_file_paths(123, test_out_dir)
-
-        self.assertEquals(output["nxs_filename"], file_name_without_ext+".nxs")
-        self.assertEquals(output["gss_filename"], file_name_without_ext+".gss")
-        self.assertEquals(output["tof_xye_filename"], file_name_without_ext+"_tof_xye.dat")
-        self.assertEquals(output["dspacing_xye_filename"], file_name_without_ext+"_d_xye.dat")
-
-        self.assertEquals(output["output_name"], reference_name)
-
-    def test_generate_cycle_dir(self):
-        inst = self._get_abstract_inst_defaults()
-        # Have to manually set it for Windows path separator
-        input_dir = self.raw_data_dir + '\\'
-        inst.test_set_raw_data_dir(input_dir)
-        inst_cycle = "test_1"
-        reference_output = input_dir + inst_cycle + '\\'
-
-        output = inst._generate_raw_data_cycle_dir(inst_cycle)
-        self.assertEquals(output, reference_output)
-
-        # Next test for UNIX paths
-        unix_input_dir = self.raw_data_dir + '/'
-        inst.test_set_raw_data_dir(unix_input_dir)
-        reference_output = unix_input_dir + inst_cycle + '/'
-
-        output = inst._generate_raw_data_cycle_dir(inst_cycle)
-        self.assertEquals(output, reference_output)
-
-    def test_generate_cycle_dir_throws(self):
-        # Test generate cycle throws if there is no path seperator at the end
-        inst = self._get_abstract_inst_defaults()
-        inst_cycle = "test"
-
-        self.assertRaises(ValueError, lambda: inst._generate_raw_data_cycle_dir(inst_cycle))
-
-    def test_generate_cycle_dir_respects_skip_flag(self):
-        # This test is for a function which supports the old API - it should
-        # not change the path which was set for calibration dir
-        inst = self._get_abstract_inst_defaults()
-        inst.generate_cycle_dir_flag = True
-
-        output = inst._generate_raw_data_cycle_dir("test_not_appended")
-        self.assertEquals(output, self.raw_data_dir)
 
     def test_generate_full_input_path(self):
         inst = self._get_abstract_inst_all_specified()
         run_number = 12345
         inst_file_name = inst._generate_inst_file_name(run_number)
-        input_path = "test\\"
-        reference_output = input_path + inst_file_name + self.default_ext
+        input_path = "test"
+        reference_output = os.path.join(input_path, (inst_file_name + self.default_ext))
 
         output = inst._generate_input_full_path(run_number, input_path)
         self.assertEquals(output, reference_output)
@@ -95,14 +45,6 @@ class isis_powder_AbstractInstTest(unittest.TestCase):
         inst = self._get_abstract_inst_defaults()
         self.assertRaises(NotImplementedError, lambda: inst.create_calibration("", "", ""))
 
-    def test_get_monitor_hook(self):
-        inst = self._get_abstract_inst_defaults()
-        # Use type this isn't None to make sure its not returning to us
-        unused_param = "unused"
-        output = inst._get_monitor(unused_param, unused_param, unused_param)
-
-        self.assertEquals(isinstance(output, type(None)), True)
-
     def test_get_monitor_spectra_hook(self):
         inst = self._get_abstract_inst_defaults()
         unused_param = None
@@ -123,22 +65,19 @@ class isis_powder_AbstractInstTest(unittest.TestCase):
 
     def _get_abstract_inst_defaults(self):
         return MockInstrument(user_name=self.user_name, calibration_dir=self.calibration_dir,
-                              raw_data_dir=self.raw_data_dir, output_dir=self.output_dir)
+                              output_dir=self.output_dir)
     
     def _get_abstract_inst_all_specified(self):
         return MockInstrument(user_name=self.user_name, calibration_dir=self.calibration_dir,
-                              raw_data_dir=self.raw_data_dir, output_dir=self.output_dir,
-                              default_ext=self.default_ext, tt_mode=self.tt_mode)
+                              output_dir=self.output_dir, default_ext=self.default_ext)
 
     # Test params
     user_name = "unit_test_abstract_inst"
     calibration_dir = "calDir"
-    raw_data_dir = "rawDir"
     output_dir = "outDir"
 
     # Optional Params
     default_ext = ".ext"
-    tt_mode = "tt_test"
 
 
 if __name__ == '__main__':
diff --git a/scripts/test/ISIS_Powder_PearlTest.py b/scripts/test/ISIS_Powder_PearlTest.py
index be5e62039d086c09335aac7b4daf94bb4e84705f..6b28ba161a65ff061d6b517abf226f46dd280545 100644
--- a/scripts/test/ISIS_Powder_PearlTest.py
+++ b/scripts/test/ISIS_Powder_PearlTest.py
@@ -1,3 +1,4 @@
+from __future__ import (absolute_import, division, print_function)
 
 import os
 import unittest
@@ -12,7 +13,7 @@ class isis_powder_PearlTest(unittest.TestCase):
 
     def test_cycle_information_generates_correctly(self):
         # This checks that the cycle information generates using the correct keys for the dict
-        output = self._get_pearl_inst_defaults()._get_cycle_information(85500)
+        output = self._get_pearl_inst_defaults()._get_label_information(85500)
         expected_cycle = "14_1"
         expected_inst_vers = "new2"
         self.assertEquals(output["cycle"], expected_cycle)
@@ -44,28 +45,9 @@ class isis_powder_PearlTest(unittest.TestCase):
         self.assertEquals(expected_new_name, new_output)
 
     # Non static methods
-    def test_get_calibration_full_paths(self):
-        input_cycle = "15_4"
-        input_tt_mode = self.default_tt_mode
-
-        expected_calfile = "pearl_offset_15_3.cal"
-        expected_van_aborb_file = "pearl_absorp_sphere_10mm_newinst2_long.nxs"
-        expected_grouping_file = "pearl_group_12_1_TT88.cal"
-        expected_vanadium_file = "van_spline_TT88_cycle_15_4.nxs"
-
-        expected_calibration_dir = self.calibration_dir
-
-        pearl_obj = self._get_pearl_inst_defaults()
-        output = pearl_obj._get_calibration_full_paths(input_cycle)
-
-        self.assertEquals(output["calibration"], expected_calibration_dir + expected_calfile)
-        self.assertEquals(output["grouping"], expected_calibration_dir + expected_grouping_file)
-        self.assertEquals(output["vanadium_absorption"], expected_calibration_dir + expected_van_aborb_file)
-        self.assertEquals(output["vanadium"], expected_calibration_dir + expected_vanadium_file)
-
     def _get_pearl_inst_defaults(self):
         return pearl.Pearl(user_name="unitTest-PEARL", calibration_dir=self.calibration_dir,
-                                       raw_data_dir=self.raw_data_dir, output_dir=self.output_dir)
+                           raw_data_dir=self.raw_data_dir, output_dir=self.output_dir)
 
     def _get_pearl_inst_all_specified(self):
         return pearl.Pearl(calibration_dir=self.calibration_dir, raw_data_dir=self.raw_data_dir,
diff --git a/scripts/test/SANS/CMakeLists.txt b/scripts/test/SANS/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..54e6432619097844410a4a521a8e4c60d535ebf3
--- /dev/null
+++ b/scripts/test/SANS/CMakeLists.txt
@@ -0,0 +1,4 @@
+add_subdirectory(common)
+add_subdirectory(state)
+
+
diff --git a/scripts/test/SANS/common/CMakeLists.txt b/scripts/test/SANS/common/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..a701f70af35ec385310db87ef17a4aabfcf58896
--- /dev/null
+++ b/scripts/test/SANS/common/CMakeLists.txt
@@ -0,0 +1,17 @@
+##
+## Tests for SANS
+##
+
+set ( TEST_PY_FILES
+  enums_test.py
+  file_information_test.py
+  log_tagger_test.py
+  general_functions_test.py
+  xml_parsing_test.py
+)
+
+check_tests_valid ( ${CMAKE_CURRENT_SOURCE_DIR} ${TEST_PY_FILES} )
+
+# Prefix for test name=Python
+pyunittest_add_test ( ${CMAKE_CURRENT_SOURCE_DIR} PythonSANS ${TEST_PY_FILES} )
+
diff --git a/scripts/test/SANS/common/enums_test.py b/scripts/test/SANS/common/enums_test.py
new file mode 100644
index 0000000000000000000000000000000000000000..0db5728abc48344a3aa7be702ea305cb64c1f90f
--- /dev/null
+++ b/scripts/test/SANS/common/enums_test.py
@@ -0,0 +1,33 @@
+import unittest
+import mantid
+
+from sans.common.enums import serializable_enum, string_convertible
+
+
+# ----Create a test class
+@string_convertible
+@serializable_enum("TypeA", "TypeB", "TypeC")
+class DummyClass(object):
+    pass
+
+
+class SANSFileInformationTest(unittest.TestCase):
+    def test_that_can_create_enum_value_and_is_sub_class_of_base_type(self):
+        type_a = DummyClass.TypeA
+        self.assertTrue(issubclass(type_a, DummyClass))
+
+    def test_that_can_convert_to_string(self):
+        type_b = DummyClass.TypeB
+        self.assertTrue(DummyClass.to_string(type_b) == "TypeB")
+
+    def test_that_raises_run_time_error_if_enum_value_is_not_known(self):
+        self.assertRaises(RuntimeError, DummyClass.to_string, DummyClass)
+
+    def test_that_can_convert_from_string(self):
+        self.assertTrue(DummyClass.from_string("TypeC") is DummyClass.TypeC)
+
+    def test_that_raises_run_time_error_if_string_is_not_known(self):
+        self.assertRaises(RuntimeError, DummyClass.from_string, "TypeD")
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/scripts/test/SANS/common/file_information_test.py b/scripts/test/SANS/common/file_information_test.py
new file mode 100644
index 0000000000000000000000000000000000000000..c4bc6d20115d76ee7eaec249b0bf5f8708c7e327
--- /dev/null
+++ b/scripts/test/SANS/common/file_information_test.py
@@ -0,0 +1,58 @@
+import unittest
+import mantid
+
+from sans.common.file_information import (SANSFileInformationFactory, SANSFileInformation, FileType,
+                                          SANSInstrument, get_instrument_paths_for_sans_file)
+from mantid.kernel import DateAndTime
+
+
+class SANSFileInformationTest(unittest.TestCase):
+    def test_that_can_extract_information_from_file_for_SANS2D_single_period_and_ISISNexus(self):
+        # Arrange
+        # The file is a single period
+        file_name = "SANS2D00022024"
+        factory = SANSFileInformationFactory()
+
+        # Act
+        file_information = factory.create_sans_file_information(file_name)
+
+        # Assert
+        self.assertTrue(file_information.get_number_of_periods() == 1)
+        self.assertTrue(file_information.get_date() == DateAndTime("2013-10-25T14:21:19"))
+        self.assertTrue(file_information.get_instrument() == SANSInstrument.SANS2D)
+        self.assertTrue(file_information.get_type() == FileType.ISISNexus)
+        self.assertTrue(file_information.get_run_number() == 22024)
+        self.assertFalse(file_information.is_event_mode())
+
+    def test_that_can_extract_information_from_file_for_LOQ_single_period_and_raw_format(self):
+        # Arrange
+        # The file is a single period
+        file_name = "LOQ48094"
+        factory = SANSFileInformationFactory()
+
+        # Act
+        file_information = factory.create_sans_file_information(file_name)
+
+        # Assert
+        self.assertTrue(file_information.get_number_of_periods() == 1)
+        self.assertTrue(file_information.get_date() == DateAndTime("2008-12-18T11:20:58"))
+        self.assertTrue(file_information.get_instrument() == SANSInstrument.LOQ)
+        self.assertTrue(file_information.get_type() == FileType.ISISRaw)
+        self.assertTrue(file_information.get_run_number() == 48094)
+
+
+class SANSFileInformationGeneralFunctionsTest(unittest.TestCase):
+    def test_that_finds_idf_and_ipf_paths(self):
+        # Arrange
+        file_name = "SANS2D00022024"
+        # Act
+        idf_path, ipf_path = get_instrument_paths_for_sans_file(file_name)
+        # Assert
+        self.assertTrue(idf_path is not None)
+        self.assertTrue(ipf_path is not None)
+        self.assertTrue("Definition" in idf_path)
+        self.assertTrue("Parameters" in ipf_path)
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/scripts/test/SANS/common/general_functions_test.py b/scripts/test/SANS/common/general_functions_test.py
new file mode 100644
index 0000000000000000000000000000000000000000..bce83417d581cc553e727e60771b77a43b4d29de
--- /dev/null
+++ b/scripts/test/SANS/common/general_functions_test.py
@@ -0,0 +1,98 @@
+import unittest
+import mantid
+
+from mantid.kernel import (V3D, Quat)
+from sans.common.general_functions import (quaternion_to_angle_and_axis, create_unmanaged_algorithm, add_to_sample_log)
+
+
+class SANSFunctionsTest(unittest.TestCase):
+    @staticmethod
+    def _create_sample_workspace():
+        sample_name = "CreateSampleWorkspace"
+        sample_options = {"OutputWorkspace": "dummy"}
+        sample_alg = create_unmanaged_algorithm(sample_name, **sample_options)
+        sample_alg.execute()
+        return sample_alg.getProperty("OutputWorkspace").value
+
+    def _do_test_quaternion(self, angle, axis, expected_axis=None):
+        # Act
+        quaternion = Quat(angle, axis)
+        converted_angle, converted_axis = quaternion_to_angle_and_axis(quaternion)
+
+        # Assert
+        if expected_axis is not None:
+            axis = expected_axis
+        self.assertAlmostEqual(angle, converted_angle)
+        self.assertAlmostEqual(axis[0], converted_axis[0])
+        self.assertAlmostEqual(axis[1], converted_axis[1])
+        self.assertAlmostEqual(axis[2], converted_axis[2])
+
+    def test_that_quaternion_can_be_converted_to_axis_and_angle_for_regular(self):
+        # Arrange
+        angle = 23.0
+        axis = V3D(0.0, 1.0, 0.0)
+        self._do_test_quaternion(angle, axis)
+
+    def test_that_quaternion_can_be_converted_to_axis_and_angle_for_0_degree(self):
+        # Arrange
+        angle = 0.0
+        axis = V3D(1.0, 0.0, 0.0)
+        # There shouldn't be an axis for angle 0
+        expected_axis = V3D(0.0, 0.0, 0.0)
+        self._do_test_quaternion(angle, axis, expected_axis)
+
+    def test_that_quaternion_can_be_converted_to_axis_and_angle_for_180_degree(self):
+        # Arrange
+        angle = 180.0
+        axis = V3D(0.0, 1.0, 0.0)
+        # There shouldn't be an axis for angle 0
+        self._do_test_quaternion(angle, axis)
+
+    def test_that_sample_log_is_added(self):
+        # Arrange
+        workspace = SANSFunctionsTest._create_sample_workspace()
+        log_name = "TestName"
+        log_value = "TestValue"
+        log_type = "String"
+
+        # Act
+        add_to_sample_log(workspace, log_name, log_value, log_type)
+
+        # Assert
+        run = workspace.run()
+        self.assertTrue(run.hasProperty(log_name))
+        self.assertTrue(run.getProperty(log_name).value == log_value)
+
+    def test_that_sample_log_raises_for_non_string_type_arguments(self):
+        # Arrange
+        workspace = SANSFunctionsTest._create_sample_workspace()
+        log_name = "TestName"
+        log_value = 123
+        log_type = "String"
+
+        # Act + Assert
+        try:
+            add_to_sample_log(workspace, log_name, log_value, log_type)
+            did_raise = False
+        except TypeError:
+            did_raise = True
+        self.assertTrue(did_raise)
+
+    def test_that_sample_log_raises_for_wrong_type_selection(self):
+        # Arrange
+        workspace = SANSFunctionsTest._create_sample_workspace()
+        log_name = "TestName"
+        log_value = "test"
+        log_type = "sdfsdfsdf"
+
+        # Act + Assert
+        try:
+            add_to_sample_log(workspace, log_name, log_value, log_type)
+            did_raise = False
+        except ValueError:
+            did_raise = True
+        self.assertTrue(did_raise)
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/scripts/test/SANS/common/log_tagger_test.py b/scripts/test/SANS/common/log_tagger_test.py
new file mode 100644
index 0000000000000000000000000000000000000000..ab6610a4f5ca163c6910329eccb8ae2f8618ed2e
--- /dev/null
+++ b/scripts/test/SANS/common/log_tagger_test.py
@@ -0,0 +1,44 @@
+import unittest
+import mantid
+from mantid.api import AlgorithmManager
+from sans.common.log_tagger import (has_tag, set_tag, get_tag, has_hash, set_hash)
+
+
+class SANSLogTaggerTest(unittest.TestCase):
+    @staticmethod
+    def _provide_sample_workspace():
+        alg = AlgorithmManager.createUnmanaged("CreateSampleWorkspace")
+        alg.setChild(True)
+        alg.initialize()
+        alg.setProperty("OutputWorkspace", "dummy")
+        alg.execute()
+        return alg.getProperty("OutputWorkspace").value
+
+    def test_that_can_read_and_write_tag_in_sample_logs(self):
+        # Arrange
+        ws1 = SANSLogTaggerTest._provide_sample_workspace()
+        tag1 = "test"
+        value1 = 123
+
+        # Act + Assert
+        self.assertFalse(has_tag(tag1, ws1))
+        set_tag(tag1, value1, ws1)
+        self.assertTrue(has_tag(tag1, ws1))
+        self.assertTrue(get_tag(tag1, ws1) == value1)
+
+    def test_that_can_read_and_write_hash_in_sample_log(self):
+        # Arrange
+        ws1 = self._provide_sample_workspace()
+        tag1 = "test"
+        value1 = "tested"
+        value2 = "tested2"
+
+        # Act + Assert
+        self.assertFalse(has_hash(tag1, value1, ws1))
+        set_hash(tag1, value1, ws1)
+        self.assertTrue(has_hash(tag1, value1, ws1))
+        self.assertFalse(has_hash(tag1, value2, ws1))
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/scripts/test/SANS/common/xml_parsing_test.py b/scripts/test/SANS/common/xml_parsing_test.py
new file mode 100644
index 0000000000000000000000000000000000000000..d71aaedb314dd4c3bdcd5004da0b9f6d30f391d7
--- /dev/null
+++ b/scripts/test/SANS/common/xml_parsing_test.py
@@ -0,0 +1,64 @@
+import unittest
+import mantid
+
+from sans.common.file_information import (SANSFileInformationFactory, get_instrument_paths_for_sans_file)
+from sans.common.xml_parsing import (get_named_elements_from_ipf_file, get_monitor_names_from_idf_file)
+
+
+class XMLParsingTest(unittest.TestCase):
+    def test_that_named_entries_in_instrument_parameter_file_can_be_retrieved(self):
+        # Arrange
+        test_file = "LARMOR00003368"
+        file_information_factory = SANSFileInformationFactory()
+        file_information = file_information_factory.create_sans_file_information(test_file)
+        full_file_path = file_information.get_file_name()
+
+        _, ipf = get_instrument_paths_for_sans_file(full_file_path)
+        to_search = ["low-angle-detector-name", "high-angle-detector-short-name"]
+
+        # Act
+        results = get_named_elements_from_ipf_file(ipf, to_search, str)
+
+        # Assert
+        self.assertTrue(len(results) == 2)
+
+        self.assertTrue(results["low-angle-detector-name"] == "DetectorBench")
+        self.assertTrue(results["high-angle-detector-short-name"] == "front")
+
+    def test_that_monitors_can_be_found(self):
+        # Arrange
+        test_file = "LARMOR00003368"
+        file_information_factory = SANSFileInformationFactory()
+        file_information = file_information_factory.create_sans_file_information(test_file)
+        full_file_path = file_information.get_file_name()
+
+        idf, _ = get_instrument_paths_for_sans_file(full_file_path)
+
+        # Act
+        results = get_monitor_names_from_idf_file(idf)
+
+        # Assert
+        self.assertTrue(len(results) == 10)
+        for key, value in results.items():
+            self.assertTrue(value == ("monitor"+str(key)))
+
+    def test_that_monitors_can_be_found_v2(self):
+        # Arrange
+        test_file = "LOQ74044"
+        file_information_factory = SANSFileInformationFactory()
+        file_information = file_information_factory.create_sans_file_information(test_file)
+        full_file_path = file_information.get_file_name()
+
+        idf, _ = get_instrument_paths_for_sans_file(full_file_path)
+
+        # Act
+        results = get_monitor_names_from_idf_file(idf)
+
+        # Assert
+        self.assertTrue(len(results) == 2)
+        for key, value in results.items():
+            self.assertTrue(value == ("monitor"+str(key)))
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/scripts/test/SANS/state/CMakeLists.txt b/scripts/test/SANS/state/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..d16f314ce579ef44ceafc1807e494d732c08b7bb
--- /dev/null
+++ b/scripts/test/SANS/state/CMakeLists.txt
@@ -0,0 +1,26 @@
+#
+## Tests for SANSState
+##
+
+set ( TEST_PY_FILES
+   adjustment_test.py
+   calculate_transmission_test.py
+   convert_to_q_test.py
+   data_test.py
+   mask_test.py
+   move_test.py
+   normalize_to_monitor_test.py
+   reduction_mode_test.py
+   save_test.py
+   scale_test.py
+   slice_event_test.py
+   state_base_test.py
+   state_functions_test.py
+   state_test.py
+   wavelength_and_pixel_adjustment_test.py
+   wavelength_test.py
+)
+check_tests_valid ( ${CMAKE_CURRENT_SOURCE_DIR} ${TEST_PY_FILES} )
+
+# Prefix for test name=Python
+pyunittest_add_test ( ${CMAKE_CURRENT_SOURCE_DIR} PythonSANS ${TEST_PY_FILES} )
diff --git a/scripts/test/SANS/state/adjustment_test.py b/scripts/test/SANS/state/adjustment_test.py
new file mode 100644
index 0000000000000000000000000000000000000000..eaa0c7de8c0f8b5e6361db0c9b9f66697f9ec247
--- /dev/null
+++ b/scripts/test/SANS/state/adjustment_test.py
@@ -0,0 +1,98 @@
+import unittest
+import mantid
+
+from sans.state.adjustment import (StateAdjustment, get_adjustment_builder)
+from sans.state.data import (get_data_builder)
+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.common.enums import (SANSFacility, SANSInstrument, FitType)
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# State
+# ----------------------------------------------------------------------------------------------------------------------
+class MockStateNormalizeToMonitor(StateNormalizeToMonitor):
+    def validate(self):
+        pass
+
+
+class MockStateCalculateTransmission(StateCalculateTransmission):
+    def validate(self):
+        pass
+
+
+class MockStateWavelengthAndPixelAdjustment(StateWavelengthAndPixelAdjustment):
+    def validate(self):
+        pass
+
+
+class StateReductionTest(unittest.TestCase):
+    def test_that_raises_when_calculate_transmission_is_not_set(self):
+        state = StateAdjustment()
+        state.normalize_to_monitor = MockStateNormalizeToMonitor()
+        state.wavelength_and_pixel_adjustment = MockStateWavelengthAndPixelAdjustment()
+        self.assertRaises(ValueError, state.validate)
+        state.calculate_transmission = MockStateCalculateTransmission()
+        try:
+            state.validate()
+        except ValueError:
+            self.fail()
+
+    def test_that_raises_when_normalize_to_monitor_is_not_set(self):
+        state = StateAdjustment()
+        state.calculate_transmission = MockStateCalculateTransmission()
+        state.wavelength_and_pixel_adjustment = MockStateWavelengthAndPixelAdjustment()
+        self.assertRaises(ValueError, state.validate)
+        state.normalize_to_monitor = MockStateNormalizeToMonitor()
+        try:
+            state.validate()
+        except ValueError:
+            self.fail()
+
+    def test_that_raises_when_wavelength_and_pixel_adjustment_is_not_set(self):
+        state = StateAdjustment()
+        state.calculate_transmission = MockStateCalculateTransmission()
+        state.normalize_to_monitor = MockStateNormalizeToMonitor()
+        self.assertRaises(ValueError, state.validate)
+        state.wavelength_and_pixel_adjustment = MockStateWavelengthAndPixelAdjustment()
+        try:
+            state.validate()
+        except ValueError:
+            self.fail()
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# Builder
+# ----------------------------------------------------------------------------------------------------------------------
+class StateAdjustmentBuilderTest(unittest.TestCase):
+    def test_that_reduction_state_can_be_built(self):
+        # Arrange
+        facility = SANSFacility.ISIS
+        data_builder = get_data_builder(facility)
+        data_builder.set_sample_scatter("LOQ74044")
+        data_info = data_builder.build()
+
+        # Act
+        builder = get_adjustment_builder(data_info)
+        self.assertTrue(builder)
+
+        builder.set_calculate_transmission(MockStateCalculateTransmission())
+        builder.set_normalize_to_monitor(MockStateNormalizeToMonitor())
+        builder.set_wavelength_and_pixel_adjustment(MockStateWavelengthAndPixelAdjustment())
+        builder.set_wide_angle_correction(False)
+        state = builder.build()
+
+        # # Assert
+        self.assertTrue(not state.wide_angle_correction)
+
+        try:
+            state.validate()
+            is_valid = True
+        except ValueError:
+            is_valid = False
+        self.assertTrue(is_valid)
+
+
+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
new file mode 100644
index 0000000000000000000000000000000000000000..05bfc162aea4833a1e159ca12d7e97fd341eb45c
--- /dev/null
+++ b/scripts/test/SANS/state/calculate_transmission_test.py
@@ -0,0 +1,283 @@
+import unittest
+import mantid
+
+from sans.state.calculate_transmission import (StateCalculateTransmission, StateCalculateTransmissionLOQ,
+                                               get_calculate_transmission_builder)
+from sans.state.data import get_data_builder
+from sans.common.enums import (RebinType, RangeStepType, FitType, DataType, SANSFacility)
+from state_test_helper import assert_validate_error, assert_raises_nothing
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# State
+# ----------------------------------------------------------------------------------------------------------------------
+class StateCalculateTransmissionTest(unittest.TestCase):
+    @staticmethod
+    def _set_fit(state, default_settings, custom_settings, fit_key):
+        fit = state.fit[fit_key]
+        for key, value in default_settings.items():
+            if key in custom_settings:
+                value = custom_settings[key]
+            if value is not None:  # If the value is None, then don't set it
+                setattr(fit, key, value)
+        state.fit[fit_key] = fit
+
+    @staticmethod
+    def _get_calculate_transmission_state(trans_entries, fit_entries):
+        state = StateCalculateTransmission()
+        if trans_entries is None:
+            trans_entries = {}
+        trans_settings = {"transmission_radius_on_detector": 12., "transmission_roi_files": ["test.xml"],
+                          "transmission_mask_files": ["test.xml"], "default_transmission_monitor": 3,
+                          "transmission_monitor": 4, "default_incident_monitor": 1, "incident_monitor": 2,
+                          "prompt_peak_correction_min": 123., "prompt_peak_correction_max": 1234.,
+                          "rebin_type": RebinType.Rebin, "wavelength_low": 1., "wavelength_high": 2.7,
+                          "wavelength_step": 0.5,  "wavelength_step_type": RangeStepType.Lin,
+                          "use_full_wavelength_range": True, "wavelength_full_range_low": 12.,
+                          "wavelength_full_range_high": 434., "background_TOF_general_start": 1.4,
+                          "background_TOF_general_stop": 24.5, "background_TOF_monitor_start": {"1": 123, "2": 123},
+                          "background_TOF_monitor_stop": {"1": 234, "2": 2323}, "background_TOF_roi_start": 12.,
+                          "background_TOF_roi_stop": 123.}
+
+        for key, value in trans_settings.items():
+            if key in trans_entries:
+                value = trans_entries[key]
+            if value is not None:  # If the value is None, then don't set it
+                setattr(state, key, value)
+
+        fit_settings = {"fit_type": FitType.Polynomial, "polynomial_order": 1, "wavelength_low": 12.,
+                        "wavelength_high": 232.}
+        if fit_entries is None:
+            fit_entries = {}
+        StateCalculateTransmissionTest._set_fit(state, fit_settings, fit_entries,
+                                                DataType.to_string(DataType.Sample))
+        StateCalculateTransmissionTest._set_fit(state, fit_settings, fit_entries,
+                                                DataType.to_string(DataType.Can))
+        return state
+
+    @staticmethod
+    def _get_dict(entry_name, value):
+        output = {}
+        if value is not None:
+            output.update({entry_name: value})
+        return output
+
+    def check_bad_and_good_values(self, bad_trans=None, bad_fit=None, good_trans=None, good_fit=None):
+        # Bad values
+        state = self._get_calculate_transmission_state(bad_trans, bad_fit)
+        assert_validate_error(self, ValueError, state)
+
+        # Good values
+        state = self._get_calculate_transmission_state(good_trans, good_fit)
+        assert_raises_nothing(self, state)
+
+    def test_that_is_sans_state_data_object(self):
+        state = StateCalculateTransmissionLOQ()
+        self.assertTrue(isinstance(state, StateCalculateTransmission))
+
+    def test_that_raises_when_no_incident_monitor_is_available(self):
+        self.check_bad_and_good_values(bad_trans={"incident_monitor": None, "default_incident_monitor": None},
+                                       good_trans={"incident_monitor": 1, "default_incident_monitor": None})
+        self.check_bad_and_good_values(bad_trans={"incident_monitor": None, "default_incident_monitor": None},
+                                       good_trans={"incident_monitor": None, "default_incident_monitor": 1})
+
+    def test_that_raises_when_no_transmission_is_specified(self):
+        self.check_bad_and_good_values(bad_trans={"transmission_monitor": None, "default_transmission_monitor": None,
+                                                  "transmission_radius_on_detector": None,
+                                                  "transmission_roi_files": None},
+                                       good_trans={"transmission_monitor": 4, "default_transmission_monitor": None,
+                                                   "transmission_radius_on_detector": None,
+                                                   "transmission_roi_files": None})
+
+    def test_that_raises_for_inconsistent_prompt_peak(self):
+        self.check_bad_and_good_values(bad_trans={"prompt_peak_correction_min": 1., "prompt_peak_correction_max": None},
+                                       good_trans={"prompt_peak_correction_min": None,
+                                                   "prompt_peak_correction_max": None})
+        self.check_bad_and_good_values(bad_trans={"prompt_peak_correction_min": 1.,
+                                                  "prompt_peak_correction_max": None},
+                                       good_trans={"prompt_peak_correction_min": 1., "prompt_peak_correction_max": 2.})
+
+    def test_that_raises_for_lower_bound_larger_than_upper_bound_for_prompt_peak(self):
+        self.check_bad_and_good_values(bad_trans={"prompt_peak_correction_min": 2., "prompt_peak_correction_max": 1.},
+                                       good_trans={"prompt_peak_correction_min": 1., "prompt_peak_correction_max": 2.})
+
+    def test_that_raises_when_not_all_elements_are_set_for_wavelength(self):
+        self.check_bad_and_good_values(bad_trans={"wavelength_low": 1., "wavelength_high": 2.,
+                                                  "wavelength_step": 0.5, "wavelength_step_type": None},
+                                       good_trans={"wavelength_low": 1., "wavelength_high": 2.,
+                                                   "wavelength_step": 0.5, "wavelength_step_type": RangeStepType.Lin})
+
+    def test_that_raises_for_lower_bound_larger_than_upper_bound_for_wavelength(self):
+        self.check_bad_and_good_values(bad_trans={"wavelength_low": 2., "wavelength_high": 1.,
+                                                  "wavelength_step": 0.5, "wavelength_step_type":  RangeStepType.Lin},
+                                       good_trans={"wavelength_low": 1., "wavelength_high": 2.,
+                                                   "wavelength_step": 0.5, "wavelength_step_type": RangeStepType.Lin})
+
+    def test_that_raises_for_missing_full_wavelength_entry(self):
+        self.check_bad_and_good_values(bad_trans={"use_full_wavelength_range": True, "wavelength_full_range_low": None,
+                                                  "wavelength_full_range_high": 12.},
+                                       good_trans={"use_full_wavelength_range": True, "wavelength_full_range_low": 11.,
+                                                   "wavelength_full_range_high": 12.})
+
+    def test_that_raises_for_lower_bound_larger_than_upper_bound_for_full_wavelength(self):
+        self.check_bad_and_good_values(bad_trans={"use_full_wavelength_range": True, "wavelength_full_range_low": 2.,
+                                                  "wavelength_full_range_high": 1.},
+                                       good_trans={"use_full_wavelength_range": True, "wavelength_full_range_low": 1.,
+                                                   "wavelength_full_range_high": 2.})
+
+    def test_that_raises_for_inconsistent_general_background(self):
+        self.check_bad_and_good_values(bad_trans={"background_TOF_general_start": 1.,
+                                                  "background_TOF_general_stop": None},
+                                       good_trans={"background_TOF_general_start": None,
+                                                   "background_TOF_general_stop": None})
+
+    def test_that_raises_for_lower_bound_larger_than_upper_bound_for_general_background(self):
+        self.check_bad_and_good_values(bad_trans={"background_TOF_general_start": 2.,
+                                                  "background_TOF_general_stop": 1.},
+                                       good_trans={"background_TOF_general_start": 1.,
+                                                   "background_TOF_general_stop": 2.})
+
+    def test_that_raises_for_inconsistent_roi_background(self):
+        self.check_bad_and_good_values(bad_trans={"background_TOF_roi_start": 1.,
+                                                  "background_TOF_roi_stop": None},
+                                       good_trans={"background_TOF_roi_start": None,
+                                                   "background_TOF_roi_stop": None})
+
+    def test_that_raises_for_lower_bound_larger_than_upper_bound_for_roi_background(self):
+        self.check_bad_and_good_values(bad_trans={"background_TOF_roi_start": 2.,
+                                                  "background_TOF_roi_stop": 1.},
+                                       good_trans={"background_TOF_roi_start": 1.,
+                                                   "background_TOF_roi_stop": 2.})
+
+    def test_that_raises_for_inconsistent_monitor_background(self):
+        self.check_bad_and_good_values(bad_trans={"background_TOF_monitor_start": {"1": 12., "2": 1.},
+                                                  "background_TOF_monitor_stop": None},
+                                       good_trans={"background_TOF_monitor_start": None,
+                                                   "background_TOF_monitor_stop": None})
+
+    def test_that_raises_when_lengths_of_monitor_backgrounds_are_different(self):
+        self.check_bad_and_good_values(bad_trans={"background_TOF_monitor_start": {"1": 1., "2": 1.},
+                                                  "background_TOF_monitor_stop": {"1": 2.}},
+                                       good_trans={"background_TOF_monitor_start": {"1": 1., "2": 1.},
+                                                   "background_TOF_monitor_stop": {"1": 2., "2": 2.}})
+
+    def test_that_raises_when_monitor_name_mismatch_exists_for_monitor_backgrounds(self):
+        self.check_bad_and_good_values(bad_trans={"background_TOF_monitor_start": {"1": 1., "2": 1.},
+                                                  "background_TOF_monitor_stop": {"1": 2., "3": 2.}},
+                                       good_trans={"background_TOF_monitor_start": {"1": 1., "2": 1.},
+                                                   "background_TOF_monitor_stop": {"1": 2., "2": 2.}})
+
+    def test_that_raises_lower_bound_larger_than_upper_bound_for_monitor_backgrounds(self):
+        self.check_bad_and_good_values(bad_trans={"background_TOF_monitor_start": {"1": 1., "2": 2.},
+                                                  "background_TOF_monitor_stop": {"1": 2., "2": 1.}},
+                                       good_trans={"background_TOF_monitor_start": {"1": 1., "2": 1.},
+                                                   "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},
+                                       good_fit={"fit_type": FitType.Polynomial,  "polynomial_order": 4})
+
+    def test_that_raises_for_inconsistent_wavelength_in_fit(self):
+        self.check_bad_and_good_values(bad_trans={"wavelength_low": None,  "wavelength_high": 2.},
+                                       good_trans={"wavelength_low": 1.,  "wavelength_high": 2.})
+
+    def test_that_raises_for_lower_bound_larger_than_upper_bound_for_wavelength_in_fit(self):
+        self.check_bad_and_good_values(bad_trans={"wavelength_low": 2.,  "wavelength_high": 1.},
+                                       good_trans={"wavelength_low": 1.,  "wavelength_high": 2.})
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# Builder
+# ----------------------------------------------------------------------------------------------------------------------
+class StateCalculateTransmissionBuilderTest(unittest.TestCase):
+    def test_that_reduction_state_can_be_built(self):
+        # Arrange
+        facility = SANSFacility.ISIS
+        data_builder = get_data_builder(facility)
+        data_builder.set_sample_scatter("LOQ74044")
+        data_info = data_builder.build()
+
+        # Act
+        builder = get_calculate_transmission_builder(data_info)
+        self.assertTrue(builder)
+
+        builder.set_prompt_peak_correction_min(12.0)
+        builder.set_prompt_peak_correction_max(17.0)
+
+        builder.set_incident_monitor(1)
+        builder.set_default_incident_monitor(2)
+        builder.set_transmission_monitor(3)
+        builder.set_default_transmission_monitor(4)
+        builder.set_transmission_radius_on_detector(1.)
+        builder.set_transmission_roi_files(["sdfs", "sddfsdf"])
+        builder.set_transmission_mask_files(["sdfs", "bbbbbb"])
+
+        builder.set_rebin_type(RebinType.Rebin)
+        builder.set_wavelength_low(1.5)
+        builder.set_wavelength_high(2.7)
+        builder.set_wavelength_step(0.5)
+        builder.set_wavelength_step_type(RangeStepType.Lin)
+        builder.set_use_full_wavelength_range(True)
+        builder.set_wavelength_full_range_low(12.)
+        builder.set_wavelength_full_range_high(24.)
+
+        builder.set_background_TOF_general_start(1.4)
+        builder.set_background_TOF_general_stop(34.4)
+        builder.set_background_TOF_monitor_start({"1": 123, "2": 123})
+        builder.set_background_TOF_monitor_stop({"1": 234, "2": 2323})
+        builder.set_background_TOF_roi_start(1.4)
+        builder.set_background_TOF_roi_stop(34.4)
+
+        builder.set_Sample_fit_type(FitType.Linear)
+        builder.set_Sample_polynomial_order(0)
+        builder.set_Sample_wavelength_low(10.0)
+        builder.set_Sample_wavelength_high(20.0)
+
+        builder.set_Can_fit_type(FitType.Polynomial)
+        builder.set_Can_polynomial_order(3)
+        builder.set_Can_wavelength_low(10.0)
+        builder.set_Can_wavelength_high(20.0)
+
+        state = builder.build()
+
+        # Assert
+        self.assertTrue(state.prompt_peak_correction_min == 12.0)
+        self.assertTrue(state.prompt_peak_correction_max == 17.0)
+
+        self.assertTrue(state.incident_monitor == 1)
+        self.assertTrue(state.default_incident_monitor == 2)
+        self.assertTrue(state.transmission_monitor == 3)
+        self.assertTrue(state.default_transmission_monitor == 4)
+        self.assertTrue(state.transmission_radius_on_detector == 1.)
+        self.assertTrue(state.transmission_roi_files == ["sdfs", "sddfsdf"])
+        self.assertTrue(state.transmission_mask_files == ["sdfs", "bbbbbb"])
+
+        self.assertTrue(state.rebin_type is RebinType.Rebin)
+        self.assertTrue(state.wavelength_low == 1.5)
+        self.assertTrue(state.wavelength_high == 2.7)
+        self.assertTrue(state.wavelength_step == 0.5)
+        self.assertTrue(state.wavelength_step_type is RangeStepType.Lin)
+        self.assertTrue(state.use_full_wavelength_range is True)
+        self.assertTrue(state.wavelength_full_range_low == 12.)
+        self.assertTrue(state.wavelength_full_range_high == 24.)
+
+        self.assertTrue(state.background_TOF_general_start == 1.4)
+        self.assertTrue(state.background_TOF_general_stop == 34.4)
+        self.assertTrue(len(set(state.background_TOF_monitor_start.items()) & set({"1": 123, "2": 123}.items())) == 2)
+        self.assertTrue(len(set(state.background_TOF_monitor_stop.items()) & set({"1": 234, "2": 2323}.items())) == 2)
+        self.assertTrue(state.background_TOF_roi_start == 1.4)
+        self.assertTrue(state.background_TOF_roi_stop == 34.4)
+
+        self.assertTrue(state.fit[DataType.to_string(DataType.Sample)].fit_type is FitType.Linear)
+        self.assertTrue(state.fit[DataType.to_string(DataType.Sample)].polynomial_order == 0)
+        self.assertTrue(state.fit[DataType.to_string(DataType.Sample)].wavelength_low == 10.)
+        self.assertTrue(state.fit[DataType.to_string(DataType.Sample)].wavelength_high == 20.)
+
+        self.assertTrue(state.fit[DataType.to_string(DataType.Can)].fit_type is
+                        FitType.Polynomial)
+        self.assertTrue(state.fit[DataType.to_string(DataType.Can)].polynomial_order == 3)
+        self.assertTrue(state.fit[DataType.to_string(DataType.Can)].wavelength_low == 10.)
+        self.assertTrue(state.fit[DataType.to_string(DataType.Can)].wavelength_high == 20.)
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/scripts/test/SANS/state/convert_to_q_test.py b/scripts/test/SANS/state/convert_to_q_test.py
new file mode 100644
index 0000000000000000000000000000000000000000..67713b964472f12911abbe041c78791f0912d30c
--- /dev/null
+++ b/scripts/test/SANS/state/convert_to_q_test.py
@@ -0,0 +1,117 @@
+import unittest
+import mantid
+
+from sans.state.convert_to_q import (StateConvertToQ, get_convert_to_q_builder)
+from sans.state.data import get_data_builder
+from sans.common.enums import (RangeStepType, ReductionDimensionality, SANSFacility)
+from state_test_helper import (assert_validate_error, assert_raises_nothing)
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# State
+# ----------------------------------------------------------------------------------------------------------------------
+class StateConvertToQTest(unittest.TestCase):
+    @staticmethod
+    def _get_convert_to_q_state(convert_to_q_entries):
+        state = StateConvertToQ()
+        default_entries = {"reduction_dimensionality": ReductionDimensionality.OneDim, "use_gravity": True,
+                           "gravity_extra_length": 12., "radius_cutoff": 1.5, "wavelength_cutoff": 2.7,
+                           "q_min": 0.5, "q_max": 1., "q_step": 1., "q_step_type": RangeStepType.Lin,
+                           "q_step2": 1., "q_step_type2": RangeStepType.Lin, "q_mid": 1.,
+                           "q_xy_max": 1.4, "q_xy_step": 24.5, "q_xy_step_type": RangeStepType.Lin,
+                           "use_q_resolution": True, "q_resolution_collimation_length": 12.,
+                           "q_resolution_delta_r": 12., "moderator_file": "test.txt", "q_resolution_a1": 1.,
+                           "q_resolution_a2": 2., "q_resolution_h1": 1., "q_resolution_h2": 2., "q_resolution_w1": 1.,
+                           "q_resolution_w2": 2.}
+
+        for key, value in default_entries.items():
+            if key in convert_to_q_entries:
+                value = convert_to_q_entries[key]
+            if value is not None:  # If the value is None, then don't set it
+                setattr(state, key, value)
+        return state
+
+    def check_bad_and_good_value(self, bad_convert_to_q, good_convert_to_q):
+        # Bad values
+        state = self._get_convert_to_q_state(bad_convert_to_q)
+        assert_validate_error(self, ValueError, state)
+
+        # Good values
+        state = self._get_convert_to_q_state(good_convert_to_q)
+        assert_raises_nothing(self, state)
+
+    def test_that_raises_with_inconsistent_1D_q_values(self):
+        self.check_bad_and_good_value({"q_min": None, "q_max": 2.}, {"q_min": 1., "q_max": 2.})
+
+    def test_that_raises_when_the_lower_bound_is_larger_than_the_upper_bound_for_q_1D(self):
+        self.check_bad_and_good_value({"q_min": 2., "q_max": 1.}, {"q_min": 1., "q_max": 2.})
+
+    def test_that_raises_when_no_q_bounds_are_set_for_explicit_1D_reduction(self):
+        self.check_bad_and_good_value({"q_min": None, "q_max": None,
+                                       "reduction_dimensionality": ReductionDimensionality.OneDim},
+                                      {"q_min": 1., "q_max": 2.,
+                                       "reduction_dimensionality": ReductionDimensionality.OneDim})
+
+    def test_that_raises_when_no_q_bounds_are_set_for_explicit_2D_reduction(self):
+        self.check_bad_and_good_value({"q_xy_max": None, "q_xy_step": None,
+                                       "reduction_dimensionality": ReductionDimensionality.TwoDim},
+                                      {"q_xy_max": 1., "q_xy_step": 2.,
+                                       "reduction_dimensionality": ReductionDimensionality.TwoDim})
+
+    def test_that_raises_when_inconsistent_circular_values_for_q_resolution_are_specified(self):
+        self.check_bad_and_good_value({"use_q_resolution": True, "q_resolution_a1": None,
+                                       "q_resolution_a2": 12.},
+                                      {"use_q_resolution": True, "q_resolution_a1": 11.,
+                                       "q_resolution_a2": 12.})
+
+    def test_that_raises_when_inconsistent_rectangular_values_for_q_resolution_are_specified(self):
+        self.check_bad_and_good_value({"use_q_resolution": True, "q_resolution_h1": None,
+                                       "q_resolution_h2": 12., "q_resolution_w1": 1., "q_resolution_w2": 2.},
+                                      {"use_q_resolution": True, "q_resolution_h1": 1.,
+                                       "q_resolution_h2": 12., "q_resolution_w1": 1., "q_resolution_w2": 2.})
+
+    def test_that_raises_when_no_geometry_for_q_resolution_was_specified(self):
+        self.check_bad_and_good_value({"use_q_resolution": True, "q_resolution_h1": None, "q_resolution_a1": None,
+                                       "q_resolution_a2": None, "q_resolution_h2": None, "q_resolution_w1": None,
+                                       "q_resolution_w2": None},
+                                      {"use_q_resolution": True, "q_resolution_h1": 1., "q_resolution_a1": 1.,
+                                       "q_resolution_a2": 2., "q_resolution_h2": 12., "q_resolution_w1": 1.,
+                                       "q_resolution_w2": 2.})
+
+    def test_that_raises_when_moderator_file_has_not_been_set(self):
+        self.check_bad_and_good_value({"moderator_file": None}, {"moderator_file": "test"})
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# Builder
+# ----------------------------------------------------------------------------------------------------------------------
+class StateConvertToQBuilderTest(unittest.TestCase):
+    def test_that_reduction_state_can_be_built(self):
+        # Arrange
+        facility = SANSFacility.ISIS
+        data_builder = get_data_builder(facility)
+        data_builder.set_sample_scatter("LOQ74044")
+        data_info = data_builder.build()
+
+        # Act
+        builder = get_convert_to_q_builder(data_info)
+        self.assertTrue(builder)
+
+        builder.set_q_min(12.0)
+        builder.set_q_max(17.0)
+        builder.set_q_step(1.)
+        builder.set_q_step_type(RangeStepType.Lin)
+        builder.set_reduction_dimensionality(ReductionDimensionality.OneDim)
+
+        state = builder.build()
+
+        # Assert
+        self.assertTrue(state.q_min == 12.0)
+        self.assertTrue(state.q_max == 17.0)
+        self.assertTrue(state.q_step == 1.)
+        self.assertTrue(state.q_step_type is RangeStepType.Lin)
+        self.assertTrue(state.reduction_dimensionality is ReductionDimensionality.OneDim)
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/scripts/test/SANS/state/data_test.py b/scripts/test/SANS/state/data_test.py
new file mode 100644
index 0000000000000000000000000000000000000000..39ead90f26597895d96fc394cf5e1dc9c45e4e3a
--- /dev/null
+++ b/scripts/test/SANS/state/data_test.py
@@ -0,0 +1,90 @@
+import unittest
+import mantid
+
+from sans.state.data import (StateData, get_data_builder)
+from state_test_helper import (assert_validate_error, assert_raises_nothing)
+from sans.common.enums import (SANSFacility, SANSInstrument)
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# State test
+# ----------------------------------------------------------------------------------------------------------------------
+class StateDataTest(unittest.TestCase):
+    @staticmethod
+    def _get_data_state(**data_entries):
+        state = StateData()
+        data_settings = {"sample_scatter": "test", "sample_transmission": "test",
+                         "sample_direct": "test", "can_scatter": "test",
+                         "can_transmission": "test", "can_direct": "test"}
+
+        for key, value in data_settings.items():
+            if key in data_entries:
+                value = data_entries[key]
+            if value is not None:  # If the value is None, then don't set it
+                setattr(state, key, value)
+        return state
+
+    def assert_raises_for_bad_value_and_raises_nothing_for_good_value(self, data_entries_bad,
+                                                                      data_entries_good):
+        # Bad values
+        state = StateDataTest._get_data_state(**data_entries_bad)
+        assert_validate_error(self, ValueError, state)
+
+        # Good values
+        state = StateDataTest._get_data_state(**data_entries_good)
+        assert_raises_nothing(self, state)
+
+    def test_that_raises_when_sample_scatter_is_missing(self):
+        self.assert_raises_for_bad_value_and_raises_nothing_for_good_value({"sample_scatter": None},
+                                                                           {"sample_scatter": "test"})
+
+    def test_that_raises_when_transmission_and_direct_are_inconsistently_specified_for_sample(self):
+        self.assert_raises_for_bad_value_and_raises_nothing_for_good_value({"sample_transmission": None,
+                                                                            "sample_direct": "test",
+                                                                            "can_transmission": None,
+                                                                            "can_direct": None},
+                                                                           {"sample_transmission": "test",
+                                                                            "sample_direct": "test",
+                                                                            "can_transmission": None,
+                                                                            "can_direct": None})
+
+    def test_that_raises_when_transmission_and_direct_are_inconsistently_specified_for_can(self):
+        self.assert_raises_for_bad_value_and_raises_nothing_for_good_value({"can_transmission": "test",
+                                                                            "can_direct": None},
+                                                                           {"can_transmission": "test",
+                                                                            "can_direct": "test"})
+
+    def test_that_raises_when_transmission_but_not_scatter_was_specified_for_can(self):
+        self.assert_raises_for_bad_value_and_raises_nothing_for_good_value({"can_scatter": None,
+                                                                            "can_transmission": "test",
+                                                                            "can_direct": "test"},
+                                                                           {"can_scatter": "test",
+                                                                            "can_transmission": "test",
+                                                                            "can_direct": "test"})
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# Builder test
+# ----------------------------------------------------------------------------------------------------------------------
+class StateDataBuilderTest(unittest.TestCase):
+    def test_that_data_state_can_be_built(self):
+        # Arrange
+        facility = SANSFacility.ISIS
+
+        # Act
+        data_builder = get_data_builder(facility)
+
+        data_builder.set_sample_scatter("LOQ74044")
+        data_builder.set_sample_scatter_period(3)
+        data_state = data_builder.build()
+
+        # # Assert
+        self.assertTrue(data_state.sample_scatter == "LOQ74044")
+        self.assertTrue(data_state.sample_scatter_period == 3)
+        self.assertTrue(data_state.sample_direct_period == 0)
+        self.assertTrue(data_state.instrument is SANSInstrument.LOQ)
+        self.assertTrue(data_state.sample_scatter_run_number == 74044)
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/scripts/test/SANS/state/mask_test.py b/scripts/test/SANS/state/mask_test.py
new file mode 100644
index 0000000000000000000000000000000000000000..40c5561893055186619ebdc277a9d8aedc2baee0
--- /dev/null
+++ b/scripts/test/SANS/state/mask_test.py
@@ -0,0 +1,224 @@
+import unittest
+import mantid
+
+from sans.state.mask import (StateMask, 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)
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# State
+# ----------------------------------------------------------------------------------------------------------------------
+EXPLICIT_NONE = "explict_none"
+
+
+class StateMaskTest(unittest.TestCase):
+    @staticmethod
+    def _set_detector(state, default_settings, custom_settings, detector_key):
+        detector = state.detectors[detector_key]
+        for key, value in default_settings.items():
+            if key in custom_settings:
+                value = custom_settings[key]
+            if value is not None:  # If the value is None, then don't set it
+                setattr(detector, key, value)
+        state.detectors[detector_key] = detector
+
+    @staticmethod
+    def _get_mask_state(general_entries, detector_entries):
+        state = StateMask()
+        # 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.],
+                         "mask_files": None,
+                         "phi_min": 0.5, "phi_max": 1., "use_mask_phi_mirror": True,
+                         "beam_stop_arm_width": 1., "beam_stop_arm_angle": 24.5, "beam_stop_arm_pos1": 12.,
+                         "beam_stop_arm_pos2": 34.,
+                         "clear": False, "clear_time": False, "single_spectra": [1, 4, 6],
+                         "spectrum_range_start": [1, 5, 7], "spectrum_range_stop": [2, 6, 8],
+                         "idf_path": ""}
+
+        for key, value in mask_settings.items():
+            if key in general_entries:
+                value = general_entries[key]
+            if value is not None:  # If the value is None, then don't set it
+                setattr(state, key, value)
+
+        # Now setup the detector-specific settings
+        detector_settings = {"single_vertical_strip_mask": [1, 2, 4], "range_vertical_strip_start": [1, 2, 4],
+                             "range_vertical_strip_stop": [2, 3, 5], "single_horizontal_strip_mask": [1, 2, 4],
+                             "range_horizontal_strip_start": [1, 2, 4], "range_horizontal_strip_stop": [2, 3, 5],
+                             "block_horizontal_start": [1, 2, 4], "block_horizontal_stop": [2, 3, 5],
+                             "block_vertical_start": [1, 2, 4], "block_vertical_stop": [2, 3, 5],
+                             "block_cross_horizontal": [1, 2, 4], "block_cross_vertical": [2, 3, 5],
+                             "bin_mask_start": [1., 2., 4.], "bin_mask_stop": [2., 3., 5.],
+                             "detector_name": "name", "detector_name_short": "name_short"}
+
+        StateMaskTest._set_detector(state, detector_settings, detector_entries,
+                                    DetectorType.to_string(DetectorType.LAB))
+        StateMaskTest._set_detector(state, detector_settings, detector_entries,
+                                    DetectorType.to_string(DetectorType.HAB))
+
+        return state
+
+    @staticmethod
+    def _get_dict(entry_name, value):
+        is_explicit_none = value == EXPLICIT_NONE
+        output = {}
+        if value is not None:
+            value = None if is_explicit_none else value
+            output.update({entry_name: value})
+        return output
+
+    def assert_raises_for_bad_value_and_raises_nothing_for_good_value(self, entry_name=None, bad_value_general=None,
+                                                                      bad_value_detector=None, good_value_general=None,
+                                                                      good_value_detector=None):
+        # Bad values
+        bad_value_general_dict = StateMaskTest._get_dict(entry_name, bad_value_general)
+        bad_value_detector_dict = StateMaskTest._get_dict(entry_name, bad_value_detector)
+        state = self._get_mask_state(bad_value_general_dict, bad_value_detector_dict)
+        assert_validate_error(self, ValueError, state)
+
+        # Good values
+        good_value_general_dict = StateMaskTest._get_dict(entry_name, good_value_general)
+        good_value_detector_dict = StateMaskTest._get_dict(entry_name, good_value_detector)
+        state = self._get_mask_state(good_value_general_dict, good_value_detector_dict)
+        assert_raises_nothing(self, state)
+
+    def test_that_raises_when_lower_radius_bound_larger_than_upper_bound(self):
+        self.assert_raises_for_bad_value_and_raises_nothing_for_good_value("radius_min", 500., None, 12., None)
+
+    def test_that_raises_when_only_one_bin_mask_has_been_set(self):
+        self.assert_raises_for_bad_value_and_raises_nothing_for_good_value("bin_mask_general_start", EXPLICIT_NONE,
+                                                                           None, [1., 2., 3.], None)
+
+    def test_that_raises_when_bin_mask_lengths_are_mismatched(self):
+        self.assert_raises_for_bad_value_and_raises_nothing_for_good_value("bin_mask_general_start", [1., 3.],
+                                                                           None, [1., 2., 3.], None)
+
+    def test_that_raises_lower_bound_is_larger_than_upper_bound_for_bin_mask(self):
+        self.assert_raises_for_bad_value_and_raises_nothing_for_good_value("bin_mask_general_start", [1., 10., 3.],
+                                                                           None, [1., 2., 3.], None)
+
+    def test_that_raises_when_only_one_spectrum_range_has_been_set(self):
+        self.assert_raises_for_bad_value_and_raises_nothing_for_good_value("spectrum_range_start", EXPLICIT_NONE,
+                                                                           None, [1, 5, 7], None)
+
+    def test_that_raises_when_spectrum_range_lengths_are_mismatched(self):
+        self.assert_raises_for_bad_value_and_raises_nothing_for_good_value("spectrum_range_start", [1, 3],
+                                                                           None, [1, 5, 7], None)
+
+    def test_that_raises_lower_bound_is_larger_than_upper_bound_for_spectrum_range(self):
+        self.assert_raises_for_bad_value_and_raises_nothing_for_good_value("spectrum_range_start", [1, 10, 3],
+                                                                           None, [1, 5, 7], None)
+
+    def test_that_raises_when_only_one_vertical_strip_has_been_set(self):
+        self.assert_raises_for_bad_value_and_raises_nothing_for_good_value("range_vertical_strip_start", None,
+                                                                           EXPLICIT_NONE, None, [1, 2, 4])
+
+    def test_that_raises_when_vertical_strip_lengths_are_mismatched(self):
+        self.assert_raises_for_bad_value_and_raises_nothing_for_good_value("range_vertical_strip_start", None, [1, 2],
+                                                                           None, [1, 2, 4])
+
+    def test_that_raises_lower_bound_is_larger_than_upper_bound_for_vertical_strip(self):
+        self.assert_raises_for_bad_value_and_raises_nothing_for_good_value("range_vertical_strip_start", None,
+                                                                           [1, 10, 3], None, [1, 2, 4])
+
+    def test_that_raises_when_only_one_horizontal_strip_has_been_set(self):
+        self.assert_raises_for_bad_value_and_raises_nothing_for_good_value("range_horizontal_strip_start", None,
+                                                                           EXPLICIT_NONE, None, [1, 2, 4])
+
+    def test_that_raises_when_horizontal_strip_lengths_are_mismatched(self):
+        self.assert_raises_for_bad_value_and_raises_nothing_for_good_value("range_horizontal_strip_start", None, [1, 2],
+                                                                           None, [1, 2, 4])
+
+    def test_that_raises_lower_bound_is_larger_than_upper_bound_for_horizontal_strip(self):
+        self.assert_raises_for_bad_value_and_raises_nothing_for_good_value("range_horizontal_strip_start", None,
+                                                                           [1, 10, 3], None, [1, 2, 4])
+
+    def test_that_raises_when_only_one_horizontal_block_has_been_set(self):
+        self.assert_raises_for_bad_value_and_raises_nothing_for_good_value("block_horizontal_start", None,
+                                                                           EXPLICIT_NONE, None, [1, 2, 4])
+
+    def test_that_raises_when_horizontal_block_lengths_are_mismatched(self):
+        self.assert_raises_for_bad_value_and_raises_nothing_for_good_value("block_horizontal_start", None, [1, 2],
+                                                                           None, [1, 2, 4])
+
+    def test_that_raises_lower_bound_is_larger_than_upper_bound_for_horiztonal_block(self):
+        self.assert_raises_for_bad_value_and_raises_nothing_for_good_value("block_horizontal_start", None,
+                                                                           [1, 10, 3], None, [1, 2, 4])
+
+    def test_that_raises_when_only_one_vertical_block_has_been_set(self):
+        self.assert_raises_for_bad_value_and_raises_nothing_for_good_value("block_vertical_start", None,
+                                                                           EXPLICIT_NONE, None, [1, 2, 4])
+
+    def test_that_raises_when_vertical_block_lengths_are_mismatched(self):
+        self.assert_raises_for_bad_value_and_raises_nothing_for_good_value("block_vertical_start", None,
+                                                                           [1, 2],
+                                                                           None, [1, 2, 4])
+
+    def test_that_raises_lower_bound_is_larger_than_upper_bound_for_vertical_block(self):
+        self.assert_raises_for_bad_value_and_raises_nothing_for_good_value("block_vertical_start", None,
+                                                                           [1, 10, 3], None, [1, 2, 4])
+
+    def test_that_raises_when_only_one_time_mask_has_been_set(self):
+        self.assert_raises_for_bad_value_and_raises_nothing_for_good_value("bin_mask_start", None,
+                                                                           EXPLICIT_NONE, None, [1., 2., 4.])
+
+    def test_that_raises_when_time_mask_lengths_are_mismatched(self):
+        self.assert_raises_for_bad_value_and_raises_nothing_for_good_value("bin_mask_start", None,
+                                                                           [1., 2.],
+                                                                           None, [1., 2., 4.])
+
+    def test_that_raises_lower_bound_is_larger_than_upper_bound_for_time_mask(self):
+        self.assert_raises_for_bad_value_and_raises_nothing_for_good_value("bin_mask_start", None,
+                                                                           [1., 10., 3.], None, [1., 2., 4.])
+
+    def test_that_raises_if_detector_names_have_not_been_set(self):
+        self.assert_raises_for_bad_value_and_raises_nothing_for_good_value("detector_name", None,
+                                                                           EXPLICIT_NONE, None, "name")
+
+    def test_that_raises_if_short_detector_names_have_not_been_set(self):
+        self.assert_raises_for_bad_value_and_raises_nothing_for_good_value("detector_name_short", None,
+                                                                           EXPLICIT_NONE, None, "name")
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# Builder
+# ----------------------------------------------------------------------------------------------------------------------
+class StateMaskBuilderTest(unittest.TestCase):
+    def test_that_mask_can_be_built(self):
+        # Arrange
+        facility = SANSFacility.ISIS
+        data_builder = get_data_builder(facility)
+        data_builder.set_sample_scatter("LOQ74044")
+        data_builder.set_sample_scatter_period(3)
+        data_info = data_builder.build()
+
+        # Act
+        builder = get_mask_builder(data_info)
+        self.assertTrue(builder)
+
+        start_time = [0.1, 1.3]
+        end_time = [0.2, 1.6]
+        builder.set_bin_mask_general_start(start_time)
+        builder.set_bin_mask_general_stop(end_time)
+        builder.set_LAB_single_vertical_strip_mask([1, 2, 3])
+
+        # Assert
+        state = builder.build()
+        self.assertTrue(len(state.bin_mask_general_start) == 2)
+        self.assertTrue(state.bin_mask_general_start[0] == start_time[0])
+        self.assertTrue(state.bin_mask_general_start[1] == start_time[1])
+
+        self.assertTrue(len(state.bin_mask_general_stop) == 2)
+        self.assertTrue(state.bin_mask_general_stop[0] == end_time[0])
+        self.assertTrue(state.bin_mask_general_stop[1] == end_time[1])
+
+        strip_mask = state.detectors[DetectorType.to_string(DetectorType.LAB)].single_vertical_strip_mask
+        self.assertTrue(len(strip_mask) == 3)
+        self.assertTrue(strip_mask[2] == 3)
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/scripts/test/SANS/state/move_test.py b/scripts/test/SANS/state/move_test.py
new file mode 100644
index 0000000000000000000000000000000000000000..a993884455d1a5865aace873e6d62bb21be39f28
--- /dev/null
+++ b/scripts/test/SANS/state/move_test.py
@@ -0,0 +1,166 @@
+import unittest
+import mantid
+
+from sans.state.move import (StateMoveLOQ, StateMoveSANS2D, StateMoveLARMOR, StateMove, 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
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# State
+# ----------------------------------------------------------------------------------------------------------------------
+class StateMoveWorkspaceTest(unittest.TestCase):
+    def test_that_raises_if_the_detector_name_is_not_set_up(self):
+        state = StateMove()
+        state.detectors[DetectorType.to_string(DetectorType.LAB)].detector_name = "test"
+        state.detectors[DetectorType.to_string(DetectorType.HAB)].detector_name_short = "test"
+        state.detectors[DetectorType.to_string(DetectorType.LAB)].detector_name_short = "test"
+        assert_validate_error(self, ValueError, state)
+        state.detectors[DetectorType.to_string(DetectorType.HAB)].detector_name = "test"
+        assert_raises_nothing(self, state)
+
+    def test_that_raises_if_the_short_detector_name_is_not_set_up(self):
+        state = StateMove()
+        state.detectors[DetectorType.to_string(DetectorType.HAB)].detector_name = "test"
+        state.detectors[DetectorType.to_string(DetectorType.LAB)].detector_name = "test"
+        state.detectors[DetectorType.to_string(DetectorType.HAB)].detector_name_short = "test"
+        assert_validate_error(self, ValueError, state)
+        state.detectors[DetectorType.to_string(DetectorType.LAB)].detector_name_short = "test"
+        assert_raises_nothing(self, state)
+
+    def test_that_general_isis_default_values_are_set_up(self):
+        state = StateMove()
+        self.assertTrue(state.sample_offset == 0.0)
+        self.assertTrue(state.sample_offset_direction is CanonicalCoordinates.Z)
+        self.assertTrue(state.detectors[DetectorType.to_string(DetectorType.HAB)].x_translation_correction == 0.0)
+        self.assertTrue(state.detectors[DetectorType.to_string(DetectorType.HAB)].y_translation_correction == 0.0)
+        self.assertTrue(state.detectors[DetectorType.to_string(DetectorType.HAB)].z_translation_correction == 0.0)
+        self.assertTrue(state.detectors[DetectorType.to_string(DetectorType.HAB)].rotation_correction == 0.0)
+        self.assertTrue(state.detectors[DetectorType.to_string(DetectorType.HAB)].side_correction == 0.0)
+        self.assertTrue(state.detectors[DetectorType.to_string(DetectorType.HAB)].radius_correction == 0.0)
+        self.assertTrue(state.detectors[DetectorType.to_string(DetectorType.HAB)].x_tilt_correction == 0.0)
+        self.assertTrue(state.detectors[DetectorType.to_string(DetectorType.HAB)].y_tilt_correction == 0.0)
+        self.assertTrue(state.detectors[DetectorType.to_string(DetectorType.HAB)].z_tilt_correction == 0.0)
+        self.assertTrue(state.detectors[DetectorType.to_string(DetectorType.HAB)].sample_centre_pos1 == 0.0)
+        self.assertTrue(state.detectors[DetectorType.to_string(DetectorType.HAB)].sample_centre_pos2 == 0.0)
+
+
+class StateMoveWorkspaceLOQTest(unittest.TestCase):
+    def test_that_is_sans_state_move_object(self):
+        state = StateMoveLOQ()
+        self.assertTrue(isinstance(state, StateMove))
+
+    def test_that_LOQ_has_centre_position_set_up(self):
+        state = StateMoveLOQ()
+        self.assertTrue(state.center_position == 317.5 / 1000.)
+        self.assertTrue(state.monitor_names == {})
+
+
+class StateMoveWorkspaceSANS2DTest(unittest.TestCase):
+    def test_that_is_sans_state_data_object(self):
+        state = StateMoveSANS2D()
+        self.assertTrue(isinstance(state, StateMove))
+
+    def test_that_sans2d_has_default_values_set_up(self):
+        # Arrange
+        state = StateMoveSANS2D()
+        self.assertTrue(state.hab_detector_radius == 306.0/1000.)
+        self.assertTrue(state.hab_detector_default_sd_m == 4.0)
+        self.assertTrue(state.hab_detector_default_x_m == 1.1)
+        self.assertTrue(state.lab_detector_default_sd_m == 4.0)
+        self.assertTrue(state.hab_detector_x == 0.0)
+        self.assertTrue(state.hab_detector_z == 0.0)
+        self.assertTrue(state.hab_detector_rotation == 0.0)
+        self.assertTrue(state.lab_detector_x == 0.0)
+        self.assertTrue(state.lab_detector_z == 0.0)
+        self.assertTrue(state.monitor_names == {})
+        self.assertTrue(state.monitor_4_offset == 0.0)
+
+
+class StateMoveWorkspaceLARMORTest(unittest.TestCase):
+    def test_that_is_sans_state_data_object(self):
+        state = StateMoveLARMOR()
+        self.assertTrue(isinstance(state, StateMove))
+
+    def test_that_can_set_and_get_values(self):
+        state = StateMoveLARMOR()
+        self.assertTrue(state.bench_rotation == 0.0)
+        self.assertTrue(state.monitor_names == {})
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# Builder
+# ----------------------------------------------------------------------------------------------------------------------
+class StateMoveBuilderTest(unittest.TestCase):
+    def test_that_state_for_loq_can_be_built(self):
+        # Arrange
+        facility = SANSFacility.ISIS
+        data_builder = get_data_builder(facility)
+        data_builder.set_sample_scatter("LOQ74044")
+        data_builder.set_sample_scatter_period(3)
+        data_info = data_builder.build()
+
+        # Act
+        builder = get_move_builder(data_info)
+        self.assertTrue(builder)
+        value = 324.2
+        builder.set_center_position(value)
+        builder.set_HAB_x_translation_correction(value)
+        builder.set_LAB_sample_centre_pos1(value)
+
+        # Assert
+        state = builder.build()
+        self.assertTrue(state.center_position == value)
+        self.assertTrue(state.detectors[DetectorType.to_string(DetectorType.HAB)].x_translation_correction == value)
+        self.assertTrue(state.detectors[DetectorType.to_string(DetectorType.HAB)].detector_name_short == "HAB")
+        self.assertTrue(state.detectors[DetectorType.to_string(DetectorType.LAB)].detector_name == "main-detector-bank")
+        self.assertTrue(state.monitor_names[str(2)] == "monitor2")
+        self.assertTrue(len(state.monitor_names) == 2)
+        self.assertTrue(state.detectors[DetectorType.to_string(DetectorType.LAB)].sample_centre_pos1 == value)
+
+    def test_that_state_for_sans2d_can_be_built(self):
+        # Arrange
+        facility = SANSFacility.ISIS
+        data_builder = get_data_builder(facility)
+        data_builder.set_sample_scatter("SANS2D00022048")
+        data_info = data_builder.build()
+
+        # Act
+        builder = get_move_builder(data_info)
+        self.assertTrue(builder)
+        value = 324.2
+        builder.set_HAB_x_translation_correction(value)
+
+        # Assert
+        state = builder.build()
+        self.assertTrue(state.detectors[DetectorType.to_string(DetectorType.HAB)].x_translation_correction == value)
+        self.assertTrue(state.detectors[DetectorType.to_string(DetectorType.HAB)].detector_name_short == "front")
+        self.assertTrue(state.detectors[DetectorType.to_string(DetectorType.LAB)].detector_name == "rear-detector")
+        self.assertTrue(state.monitor_names[str(7)] == "monitor7")
+        self.assertTrue(len(state.monitor_names) == 8)
+
+    def test_that_state_for_larmor_can_be_built(self):
+        # Arrange
+        facility = SANSFacility.ISIS
+        data_builder = get_data_builder(facility)
+        data_builder.set_sample_scatter("LARMOR00002260")
+        data_info = data_builder.build()
+
+        # Act
+        builder = get_move_builder(data_info)
+        self.assertTrue(builder)
+        value = 324.2
+        builder.set_HAB_x_translation_correction(value)
+
+        # Assert
+        state = builder.build()
+        self.assertTrue(state.detectors[DetectorType.to_string(DetectorType.HAB)].x_translation_correction == value)
+        self.assertTrue(state.detectors[DetectorType.to_string(DetectorType.HAB)].detector_name_short == "front")
+        self.assertTrue(state.detectors[DetectorType.to_string(DetectorType.LAB)].detector_name == "DetectorBench")
+        self.assertTrue(state.monitor_names[str(5)] == "monitor5")
+        self.assertTrue(len(state.monitor_names) == 10)
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/scripts/test/SANS/state/normalize_to_monitor_test.py b/scripts/test/SANS/state/normalize_to_monitor_test.py
new file mode 100644
index 0000000000000000000000000000000000000000..f7c902bf8f57e979c68844f748824b1b29cadb32
--- /dev/null
+++ b/scripts/test/SANS/state/normalize_to_monitor_test.py
@@ -0,0 +1,128 @@
+import unittest
+import mantid
+
+from sans.state.normalize_to_monitor import (StateNormalizeToMonitor, StateNormalizeToMonitorLOQ,
+                                             get_normalize_to_monitor_builder)
+from sans.state.data import get_data_builder
+from sans.common.enums import (RebinType, RangeStepType, SANSFacility)
+from state_test_helper import assert_validate_error, assert_raises_nothing
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# State
+# ----------------------------------------------------------------------------------------------------------------------
+class StateNormalizeToMonitorTest(unittest.TestCase):
+    @staticmethod
+    def _get_normalize_to_monitor_state(**kwargs):
+        state = StateNormalizeToMonitor()
+        default_entries = {"prompt_peak_correction_min": 12., "prompt_peak_correction_max": 17.,
+                           "rebin_type": RebinType.Rebin, "wavelength_low": 1.5, "wavelength_high": 2.7,
+                           "wavelength_step": 0.5, "incident_monitor": 1, "wavelength_step_type": RangeStepType.Lin,
+                           "background_TOF_general_start": 1.4, "background_TOF_general_stop": 24.5,
+                           "background_TOF_monitor_start": {"1": 123, "2": 123},
+                           "background_TOF_monitor_stop": {"1": 234, "2": 2323}}
+
+        for key, value in default_entries.items():
+            if key in kwargs:
+                value = kwargs[key]
+            if value is not None:  # If the value is None, then don't set it
+                setattr(state, key, value)
+        return state
+
+    def assert_raises_for_bad_value_and_raises_nothing_for_good_value(self, entry_name, bad_value, good_value):
+        kwargs = {entry_name: bad_value}
+        state = self._get_normalize_to_monitor_state(**kwargs)
+        assert_validate_error(self, ValueError, state)
+        setattr(state, entry_name, good_value)
+        assert_raises_nothing(self, state)
+
+    def test_that_is_sans_state_normalize_to_monitor_object(self):
+        state = StateNormalizeToMonitorLOQ()
+        self.assertTrue(isinstance(state, StateNormalizeToMonitor))
+
+    def test_that_normalize_to_monitor_for_loq_has_default_prompt_peak(self):
+        state = StateNormalizeToMonitorLOQ()
+        self.assertTrue(state.prompt_peak_correction_max == 20500.)
+        self.assertTrue(state.prompt_peak_correction_min == 19000.)
+
+    def test_that_raises_for_partially_set_prompt_peak(self):
+        self.assert_raises_for_bad_value_and_raises_nothing_for_good_value("prompt_peak_correction_min", None, 1.)
+
+    def test_that_raises_for_inconsistent_prompt_peak(self):
+        self.assert_raises_for_bad_value_and_raises_nothing_for_good_value("prompt_peak_correction_max", 1., 30.)
+
+    def test_that_raises_for_missing_incident_monitor(self):
+        self.assert_raises_for_bad_value_and_raises_nothing_for_good_value("incident_monitor", None, 1)
+
+    def test_that_raises_for_partially_set_general_background_tof(self):
+        self.assert_raises_for_bad_value_and_raises_nothing_for_good_value("background_TOF_general_start", None, 1.)
+
+    def test_that_raises_for_inconsistent_general_background_tof(self):
+        self.assert_raises_for_bad_value_and_raises_nothing_for_good_value("background_TOF_general_start", 100., 1.)
+
+    def test_that_raises_for_partially_set_monitor_background_tof(self):
+        self.assert_raises_for_bad_value_and_raises_nothing_for_good_value("background_TOF_monitor_start", None,
+                                                                           {"1": 123, "2": 123})
+
+    def test_that_raises_for_monitor_background_tof_with_different_lengths(self):
+        self.assert_raises_for_bad_value_and_raises_nothing_for_good_value("background_TOF_monitor_start", {"1": 123},
+                                                                           {"1": 123, "2": 123})
+
+    def test_that_raises_for_monitor_background_tof_with_differing_spectrum_numbers(self):
+        self.assert_raises_for_bad_value_and_raises_nothing_for_good_value("background_TOF_monitor_start",
+                                                                           {"1": 123, "5": 123},
+                                                                           {"1": 123, "2": 123})
+
+    def test_that_raises_for_monitor_background_tof_with_inconsistent_bounds(self):
+        self.assert_raises_for_bad_value_and_raises_nothing_for_good_value("background_TOF_monitor_start",
+                                                                           {"1": 123, "2": 191123},
+                                                                           {"1": 123, "2": 123})
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# Builder
+# ----------------------------------------------------------------------------------------------------------------------
+class StateReductionBuilderTest(unittest.TestCase):
+    def test_that_reduction_state_can_be_built(self):
+        # Arrange
+        facility = SANSFacility.ISIS
+        data_builder = get_data_builder(facility)
+        data_builder.set_sample_scatter("LOQ74044")
+        data_info = data_builder.build()
+
+        # Act
+        builder = get_normalize_to_monitor_builder(data_info)
+        self.assertTrue(builder)
+
+        builder.set_prompt_peak_correction_min(12.0)
+        builder.set_prompt_peak_correction_max(17.0)
+        builder.set_rebin_type(RebinType.Rebin)
+        builder.set_wavelength_low(1.5)
+        builder.set_wavelength_high(2.7)
+        builder.set_wavelength_step(0.5)
+        builder.set_wavelength_step_type(RangeStepType.Lin)
+        builder.set_incident_monitor(1)
+        builder.set_background_TOF_general_start(1.4)
+        builder.set_background_TOF_general_stop(34.4)
+        builder.set_background_TOF_monitor_start({"1": 123, "2": 123})
+        builder.set_background_TOF_monitor_stop({"1": 234, "2": 2323})
+
+        state = builder.build()
+
+        # Assert
+        self.assertTrue(state.prompt_peak_correction_min == 12.0)
+        self.assertTrue(state.prompt_peak_correction_max == 17.0)
+        self.assertTrue(state.rebin_type is RebinType.Rebin)
+        self.assertTrue(state.wavelength_low == 1.5)
+        self.assertTrue(state.wavelength_high == 2.7)
+        self.assertTrue(state.wavelength_step == 0.5)
+        self.assertTrue(state.wavelength_step_type is RangeStepType.Lin)
+        self.assertTrue(state.background_TOF_general_start == 1.4)
+        self.assertTrue(state.background_TOF_general_stop == 34.4)
+        self.assertTrue(len(set(state.background_TOF_monitor_start.items()) & set({"1": 123, "2": 123}.items())) == 2)
+        self.assertTrue(len(set(state.background_TOF_monitor_stop.items()) & set({"1": 234, "2": 2323}.items())) == 2)
+        self.assertTrue(state.incident_monitor == 1)
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/scripts/test/SANS/state/reduction_mode_test.py b/scripts/test/SANS/state/reduction_mode_test.py
new file mode 100644
index 0000000000000000000000000000000000000000..c4f87b9644cfa41625282a266297811e34a98b1b
--- /dev/null
+++ b/scripts/test/SANS/state/reduction_mode_test.py
@@ -0,0 +1,85 @@
+import unittest
+import mantid
+
+from sans.state.reduction_mode import (StateReductionMode, get_reduction_mode_builder)
+from sans.state.data import get_data_builder
+from sans.common.enums import (ISISReductionMode, ReductionDimensionality, FitModeForMerge,
+                               SANSFacility, SANSInstrument, DetectorType)
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# State
+# ----------------------------------------------------------------------------------------------------------------------
+class StateReductionModeTest(unittest.TestCase):
+    def test_that_converter_methods_work(self):
+        # Arrange
+        state = StateReductionMode()
+
+        state.reduction_mode = ISISReductionMode.Merged
+        state.dimensionality = ReductionDimensionality.TwoDim
+        state.merge_shift = 12.65
+        state.merge_scale = 34.6
+        state.merge_fit_mode = FitModeForMerge.ShiftOnly
+
+        state.detector_names[DetectorType.to_string(DetectorType.LAB)] = "Test1"
+        state.detector_names[DetectorType.to_string(DetectorType.HAB)] = "Test2"
+
+        # Assert
+        merge_strategy = state.get_merge_strategy()
+        self.assertTrue(merge_strategy[0] is ISISReductionMode.LAB)
+        self.assertTrue(merge_strategy[1] is ISISReductionMode.HAB)
+
+        all_reductions = state.get_all_reduction_modes()
+        self.assertTrue(len(all_reductions) == 2)
+        self.assertTrue(all_reductions[0] is ISISReductionMode.LAB)
+        self.assertTrue(all_reductions[1] is ISISReductionMode.HAB)
+
+        result_lab = state.get_detector_name_for_reduction_mode(ISISReductionMode.LAB)
+        self.assertTrue(result_lab == "Test1")
+        result_hab = state.get_detector_name_for_reduction_mode(ISISReductionMode.HAB)
+        self.assertTrue(result_hab == "Test2")
+
+        self.assertRaises(RuntimeError, state.get_detector_name_for_reduction_mode, "non_sense")
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# Builder
+# ----------------------------------------------------------------------------------------------------------------------
+class StateReductionModeBuilderTest(unittest.TestCase):
+    def test_that_reduction_state_can_be_built(self):
+        # Arrange
+        facility = SANSFacility.ISIS
+        data_builder = get_data_builder(facility)
+        data_builder.set_sample_scatter("LOQ74044")
+        data_info = data_builder.build()
+
+        # Act
+        builder = get_reduction_mode_builder(data_info)
+        self.assertTrue(builder)
+
+        mode = ISISReductionMode.Merged
+        dim = ReductionDimensionality.OneDim
+        builder.set_reduction_mode(mode)
+        builder.set_reduction_dimensionality(dim)
+
+        merge_shift = 324.2
+        merge_scale = 3420.98
+        fit_mode = FitModeForMerge.Both
+        builder.set_merge_fit_mode(fit_mode)
+        builder.set_merge_shift(merge_shift)
+        builder.set_merge_scale(merge_scale)
+
+        state = builder.build()
+
+        # Assert
+        self.assertTrue(state.reduction_mode is mode)
+        self.assertTrue(state.reduction_dimensionality is dim)
+        self.assertTrue(state.merge_fit_mode == fit_mode)
+        self.assertTrue(state.merge_shift == merge_shift)
+        self.assertTrue(state.merge_scale == merge_scale)
+        detector_names = state.detector_names
+        self.assertTrue(detector_names[DetectorType.to_string(DetectorType.LAB)] == "main-detector-bank")
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/scripts/test/SANS/state/save_test.py b/scripts/test/SANS/state/save_test.py
new file mode 100644
index 0000000000000000000000000000000000000000..5cac8305027d05afcf15daae50b4d08b7e68001d
--- /dev/null
+++ b/scripts/test/SANS/state/save_test.py
@@ -0,0 +1,46 @@
+import unittest
+import mantid
+
+from sans.state.save import (get_save_builder)
+from sans.state.data import (get_data_builder)
+from sans.common.enums import (SANSFacility, SaveType)
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# State
+# No tests required
+# ----------------------------------------------------------------------------------------------------------------------
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# Builder
+# ----------------------------------------------------------------------------------------------------------------------
+class StateReductionBuilderTest(unittest.TestCase):
+    def test_that_reduction_state_can_be_built(self):
+        # Arrange
+        facility = SANSFacility.ISIS
+        data_builder = get_data_builder(facility)
+        data_builder.set_sample_scatter("LOQ74044")
+        data_info = data_builder.build()
+
+        # Act
+        builder = get_save_builder(data_info)
+        self.assertTrue(builder)
+
+        file_name = "test_file_name"
+        zero_free_correction = True
+        file_format = [SaveType.Nexus, SaveType.CanSAS]
+
+        builder.set_file_name(file_name)
+        builder.set_zero_free_correction(zero_free_correction)
+        builder.set_file_format(file_format)
+        state = builder.build()
+
+        # Assert
+        self.assertTrue(state.file_name == file_name)
+        self.assertTrue(state.zero_free_correction == zero_free_correction)
+        self.assertTrue(state.file_format == file_format)
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/scripts/test/SANS/state/scale_test.py b/scripts/test/SANS/state/scale_test.py
new file mode 100644
index 0000000000000000000000000000000000000000..144ece7f2dc8192676b54359fa4247183ffa894c
--- /dev/null
+++ b/scripts/test/SANS/state/scale_test.py
@@ -0,0 +1,45 @@
+import unittest
+import mantid
+
+from sans.state.scale import get_scale_builder
+from sans.state.data import get_data_builder
+from sans.common.enums import (SANSFacility, SANSInstrument, SampleShape)
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+#  State
+# No tests required for the current states
+# ----------------------------------------------------------------------------------------------------------------------
+
+# ----------------------------------------------------------------------------------------------------------------------
+#  Builder
+# ----------------------------------------------------------------------------------------------------------------------
+class StateSliceEventBuilderTest(unittest.TestCase):
+    def test_that_slice_event_state_can_be_built(self):
+        # Arrange
+        facility = SANSFacility.ISIS
+        data_builder = get_data_builder(facility)
+        data_builder.set_sample_scatter("LOQ74044")
+        data_info = data_builder.build()
+
+        # Act
+        builder = get_scale_builder(data_info)
+        self.assertTrue(builder)
+
+        builder.set_scale(1.0)
+        builder.set_shape(SampleShape.Cuboid)
+        builder.set_thickness(3.6)
+        builder.set_width(3.7)
+        builder.set_height(5.8)
+
+        # Assert
+        state = builder.build()
+        self.assertTrue(state.shape is SampleShape.Cuboid)
+        self.assertTrue(state.scale == 1.0)
+        self.assertTrue(state.thickness == 3.6)
+        self.assertTrue(state.width == 3.7)
+        self.assertTrue(state.height == 5.8)
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/scripts/test/SANS/state/slice_event_test.py b/scripts/test/SANS/state/slice_event_test.py
new file mode 100644
index 0000000000000000000000000000000000000000..15f24eaf5fb328f0157853940551e571eb5ecd2a
--- /dev/null
+++ b/scripts/test/SANS/state/slice_event_test.py
@@ -0,0 +1,80 @@
+import unittest
+import mantid
+
+from sans.state.slice_event import (StateSliceEvent, get_slice_event_builder)
+from sans.state.data import get_data_builder
+from sans.common.enums import (SANSFacility, SANSInstrument)
+from state_test_helper import (assert_validate_error)
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# State
+# ----------------------------------------------------------------------------------------------------------------------
+class StateSliceEventTest(unittest.TestCase):
+    def test_that_raises_when_only_one_time_is_set(self):
+        state = StateSliceEvent()
+        state.start_time = [1.0, 2.0]
+        assert_validate_error(self, ValueError, state)
+        state.end_time = [2.0, 3.0]
+
+    def test_validate_method_raises_value_error_for_mismatching_start_and_end_time_length(self):
+        # Arrange
+        state = StateSliceEvent()
+        state.start_time = [1.0, 2.0]
+        state.end_time = [5.0]
+
+        # Act + Assert
+        self.assertRaises(ValueError, state.validate)
+
+    def test_validate_method_raises_value_error_for_non_increasing_time(self):
+        # Arrange
+        state = StateSliceEvent()
+        state.start_time = [1.0, 2.0, 1.5]
+        state.end_time = [1.1, 2.1, 2.5]
+
+        # Act + Assert
+        self.assertRaises(ValueError, state.validate)
+
+    def test_validate_method_raises_value_error_for_end_time_smaller_than_start_time(self):
+        # Arrange
+        state = StateSliceEvent()
+        state.start_time = [1.0, 2.0, 4.6]
+        state.end_time = [1.1, 2.1, 2.5]
+
+        # Act + Assert
+        self.assertRaises(ValueError, state.validate)
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# Builder
+# ----------------------------------------------------------------------------------------------------------------------
+class StateSliceEventBuilderTest(unittest.TestCase):
+    def test_that_slice_event_state_can_be_built(self):
+        # Arrange
+        facility = SANSFacility.ISIS
+        data_builder = get_data_builder(facility)
+        data_builder.set_sample_scatter("LOQ74044")
+        data_info = data_builder.build()
+
+        # Act
+        builder = get_slice_event_builder(data_info)
+        self.assertTrue(builder)
+
+        start_time = [0.1, 1.3]
+        end_time = [0.2, 1.6]
+        builder.set_start_time(start_time)
+        builder.set_end_time(end_time)
+
+        # Assert
+        state = builder.build()
+        self.assertTrue(len(state.start_time) == 2)
+        self.assertTrue(state.start_time[0] == start_time[0])
+        self.assertTrue(state.start_time[1] == start_time[1])
+
+        self.assertTrue(len(state.end_time) == 2)
+        self.assertTrue(state.end_time[0] == end_time[0])
+        self.assertTrue(state.end_time[1] == end_time[1])
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/scripts/test/SANS/state/state_base_test.py b/scripts/test/SANS/state/state_base_test.py
new file mode 100644
index 0000000000000000000000000000000000000000..21c3ecea15b30fd56f3dd28f58e790bf8c86f442
--- /dev/null
+++ b/scripts/test/SANS/state/state_base_test.py
@@ -0,0 +1,290 @@
+from __future__ import (absolute_import, division, print_function)
+
+import unittest
+import mantid
+
+from mantid.kernel import (PropertyManagerProperty, PropertyManager)
+from mantid.api import Algorithm
+
+from sans.state.state_base import (StringParameter, BoolParameter, FloatParameter, PositiveFloatParameter,
+                                   PositiveIntegerParameter, DictParameter, ClassTypeParameter,
+                                   FloatWithNoneParameter, PositiveFloatWithNoneParameter, FloatListParameter,
+                                   StringListParameter, PositiveIntegerListParameter, ClassTypeListParameter,
+                                   StateBase, rename_descriptor_names, TypedParameter, validator_sub_state,
+                                   create_deserialized_sans_state_from_property_manager)
+from sans.common.enums import serializable_enum
+
+
+@serializable_enum("TypeA", "TypeB")
+class TestType(object):
+    pass
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# ----------------------------------------------------------------------------------------------------------------------
+# Test the typed parameters
+# ----------------------------------------------------------------------------------------------------------------------
+# ----------------------------------------------------------------------------------------------------------------------
+@rename_descriptor_names
+class StateBaseTestClass(StateBase):
+    string_parameter = StringParameter()
+    bool_parameter = BoolParameter()
+    float_parameter = FloatParameter()
+    positive_float_parameter = PositiveFloatParameter()
+    positive_integer_parameter = PositiveIntegerParameter()
+    dict_parameter = DictParameter()
+    float_with_none_parameter = FloatWithNoneParameter()
+    positive_float_with_none_parameter = PositiveFloatWithNoneParameter()
+    float_list_parameter = FloatListParameter()
+    string_list_parameter = StringListParameter()
+    positive_integer_list_parameter = PositiveIntegerListParameter()
+    class_type_parameter = ClassTypeParameter(TestType)
+    class_type_list_parameter = ClassTypeListParameter(TestType)
+
+    def __init__(self):
+        super(StateBaseTestClass, self).__init__()
+
+    def validate(self):
+        pass
+
+
+class TypedParameterTest(unittest.TestCase):
+    def _check_that_raises(self, error_type, obj, descriptor_name, value):
+        try:
+            setattr(obj, descriptor_name, value)
+            self.fail()
+        except error_type:
+            pass
+        except:  # noqa
+            self.fail()
+
+    def test_that_can_set_to_valid_value_of_correct_type(self):
+        test_class = StateBaseTestClass()
+        try:
+            test_class.string_parameter = "Test"
+            test_class.bool_parameter = True
+            test_class.float_parameter = -23.5768
+            test_class.positive_float_parameter = 234.5
+            test_class.positive_integer_parameter = 12
+            test_class.dict_parameter = {}
+            test_class.dict_parameter = {"test": 12, "test2": 13}
+            test_class.float_with_none_parameter = None
+            test_class.float_with_none_parameter = -123.67
+            test_class.positive_float_with_none_parameter = None
+            test_class.positive_float_with_none_parameter = 123.67
+            test_class.float_list_parameter = [12., -123., 2355.]
+            test_class.string_list_parameter = ["test", "test"]
+            test_class.positive_integer_list_parameter = [1, 2, 4]
+            test_class.class_type_parameter = TestType.TypeA
+            test_class.class_type_list_parameter = [TestType.TypeA, TestType.TypeB]
+
+        except ValueError:
+            self.fail()
+
+    def test_that_will_raise_type_error_if_set_with_wrong_type(self):
+        test_class = StateBaseTestClass()
+        self._check_that_raises(TypeError, test_class, "string_parameter", 1.)
+        self._check_that_raises(TypeError, test_class, "bool_parameter", 1.)
+        self._check_that_raises(TypeError, test_class, "float_parameter", "test")
+        self._check_that_raises(TypeError, test_class, "positive_float_parameter", "test")
+        self._check_that_raises(TypeError, test_class, "positive_integer_parameter", "test")
+        self._check_that_raises(TypeError, test_class, "dict_parameter", "test")
+        self._check_that_raises(TypeError, test_class, "float_with_none_parameter", "test")
+        self._check_that_raises(TypeError, test_class, "positive_float_with_none_parameter", "test")
+        self._check_that_raises(TypeError, test_class, "float_list_parameter", [1.23, "test"])
+        self._check_that_raises(TypeError, test_class, "string_list_parameter", ["test", "test", 123.])
+        self._check_that_raises(TypeError, test_class, "positive_integer_list_parameter", [1, "test"])
+        self._check_that_raises(TypeError, test_class, "class_type_parameter", "test")
+        self._check_that_raises(TypeError, test_class, "class_type_list_parameter", ["test", TestType.TypeA])
+
+    def test_that_will_raise_if_set_with_wrong_value(self):
+        # Note that this check does not apply to all parameter, it checks the validator
+        test_class = StateBaseTestClass()
+        self._check_that_raises(ValueError, test_class, "positive_float_parameter", -1.2)
+        self._check_that_raises(ValueError, test_class, "positive_integer_parameter", -1)
+        self._check_that_raises(ValueError, test_class, "positive_float_with_none_parameter", -234.)
+        self._check_that_raises(ValueError, test_class, "positive_integer_list_parameter", [1, -2, 4])
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# ----------------------------------------------------------------------------------------------------------------------
+# Test the sans_parameters decorator
+# ----------------------------------------------------------------------------------------------------------------------
+# ----------------------------------------------------------------------------------------------------------------------
+
+class SANSParameterTest(unittest.TestCase):
+    @rename_descriptor_names
+    class SANSParameterTestClass(object):
+        my_string_parameter = StringParameter()
+        my_bool_parameter = BoolParameter()
+
+    class SANSParameterTestClass2(object):
+        my_string_parameter = StringParameter()
+        my_bool_parameter = BoolParameter()
+
+    def test_that_name_is_in_readable_format_in_instance_dictionary(self):
+        test_class = SANSParameterTest.SANSParameterTestClass()
+        test_class.my_string_parameter = "test"
+        test_class.my_bool_parameter = True
+        keys = test_class.__dict__.keys()
+        # We don't have a sensible name in the instance dictionary
+        self.assertTrue("_BoolParameter#my_bool_parameter" in keys)
+        self.assertTrue("_StringParameter#my_string_parameter" in keys)
+
+    def test_that_name_cannot_be_found_in_instance_dictionary_when_sans_parameters_decorator_is_not_applied(self):
+        test_class = SANSParameterTest.SANSParameterTestClass2()
+        test_class.my_string_parameter = "test"
+        test_class.my_bool_parameter = True
+        keys = test_class.__dict__.keys()
+        # We don't have a sensible name in the instance dictionary.
+        # It will be rather stored as something like: _BoolParameter#2 etc.
+        self.assertTrue("_BoolParameter#my_bool_parameter" not in keys)
+        self.assertTrue("_StringParameter#my_string_parameter" not in keys)
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# ----------------------------------------------------------------------------------------------------------------------
+# StateBase
+# This will mainly test serialization
+# ----------------------------------------------------------------------------------------------------------------------
+# ----------------------------------------------------------------------------------------------------------------------
+
+@rename_descriptor_names
+class VerySimpleState(StateBase):
+    string_parameter = StringParameter()
+
+    def __init__(self):
+        super(VerySimpleState, self).__init__()
+        self.string_parameter = "test_in_very_simple"
+
+    def validate(self):
+        pass
+
+
+@rename_descriptor_names
+class SimpleState(StateBase):
+    string_parameter = StringParameter()
+    bool_parameter = BoolParameter()
+    float_parameter = FloatParameter()
+    positive_float_parameter = PositiveFloatParameter()
+    positive_integer_parameter = PositiveIntegerParameter()
+    dict_parameter = DictParameter()
+    float_with_none_parameter = FloatWithNoneParameter()
+    positive_float_with_none_parameter = PositiveFloatWithNoneParameter()
+    float_list_parameter = FloatListParameter()
+    string_list_parameter = StringListParameter()
+    positive_integer_list_parameter = PositiveIntegerListParameter()
+    class_type_parameter = ClassTypeParameter(TestType)
+    class_type_list_parameter = ClassTypeListParameter(TestType)
+
+    sub_state_very_simple = TypedParameter(VerySimpleState, validator_sub_state)
+
+    def __init__(self):
+        super(SimpleState, self).__init__()
+        self.string_parameter = "String_in_SimpleState"
+        self.bool_parameter = False
+        # We explicitly leave out the float_parameter
+        self.positive_float_parameter = 1.
+        self.positive_integer_parameter = 6
+        self.dict_parameter = {"1": 123, "2": "test"}
+        self.float_with_none_parameter = 325.
+        # We expliclty leave out the positive_float_with_none_parameter
+        self.float_list_parameter = [123., 234.]
+        self.string_list_parameter = ["test1", "test2"]
+        self.positive_integer_list_parameter = [1, 2, 3]
+        self.class_type_parameter = TestType.TypeA
+        self.class_type_list_parameter = [TestType.TypeA, TestType.TypeB]
+        self.sub_state_very_simple = VerySimpleState()
+
+    def validate(self):
+        pass
+
+
+@rename_descriptor_names
+class ComplexState(StateBase):
+    float_parameter = FloatParameter()
+    positive_float_with_none_parameter = PositiveFloatWithNoneParameter()
+    sub_state_1 = TypedParameter(SimpleState, validator_sub_state)
+    dict_parameter = DictParameter()
+
+    def __init__(self):
+        super(ComplexState, self).__init__()
+        self.float_parameter = 23.
+        self.positive_float_with_none_parameter = 234.
+        self.sub_state_1 = SimpleState()
+        self.dict_parameter = {"A": SimpleState(), "B": SimpleState()}
+
+    def validate(self):
+        pass
+
+
+class TestStateBase(unittest.TestCase):
+    def _assert_simple_state(self, state):
+        self.assertTrue(state.string_parameter == "String_in_SimpleState")
+        self.assertFalse(state.bool_parameter)
+        self.assertTrue(state.float_parameter is None)  # We did not set it on the instance
+        self.assertTrue(state.positive_float_parameter == 1.)
+        self.assertTrue(state.positive_integer_parameter == 6)
+        self.assertTrue(state.dict_parameter["1"] == 123)
+        self.assertTrue(state.dict_parameter["2"] == "test")
+        self.assertTrue(state.float_with_none_parameter == 325.)
+        self.assertTrue(state.positive_float_with_none_parameter is None)
+
+        self.assertTrue(len(state.float_list_parameter) == 2)
+        self.assertTrue(state.float_list_parameter[0] == 123.)
+        self.assertTrue(state.float_list_parameter[1] == 234.)
+
+        self.assertTrue(len(state.string_list_parameter) == 2)
+        self.assertTrue(state.string_list_parameter[0] == "test1")
+        self.assertTrue(state.string_list_parameter[1] == "test2")
+
+        self.assertTrue(len(state.positive_integer_list_parameter) == 3)
+        self.assertTrue(state.positive_integer_list_parameter[0] == 1)
+        self.assertTrue(state.positive_integer_list_parameter[1] == 2)
+        self.assertTrue(state.positive_integer_list_parameter[2] == 3)
+
+        self.assertTrue(state.class_type_parameter is TestType.TypeA)
+        self.assertTrue(len(state.class_type_list_parameter) == 2)
+        self.assertTrue(state.class_type_list_parameter[0] == TestType.TypeA)
+        self.assertTrue(state.class_type_list_parameter[1] == TestType.TypeB)
+
+        self.assertTrue(state.sub_state_very_simple.string_parameter == "test_in_very_simple")
+        
+    def test_that_sans_state_can_be_serialized_and_deserialized_when_going_through_an_algorithm(self):
+        class FakeAlgorithm(Algorithm):
+            def PyInit(self):
+                self.declareProperty(PropertyManagerProperty("Args"))
+
+            def PyExec(self):
+                pass
+
+        # Arrange
+        state = ComplexState()
+
+        # Act
+        serialized = state.property_manager
+        fake = FakeAlgorithm()
+        fake.initialize()
+        fake.setProperty("Args", serialized)
+        property_manager = fake.getProperty("Args").value
+
+        # Assert
+        self.assertTrue(type(serialized) == dict)
+        self.assertTrue(type(property_manager) == PropertyManager)
+        state_2 = create_deserialized_sans_state_from_property_manager(property_manager)
+        state_2.property_manager = property_manager
+
+        # The direct sub state
+        self._assert_simple_state(state_2.sub_state_1)
+
+        # The two states in the dictionary
+        self._assert_simple_state(state_2.dict_parameter["A"])
+        self._assert_simple_state(state_2.dict_parameter["B"])
+
+        # The regular parameters
+        self.assertTrue(state_2.float_parameter == 23.)
+        self.assertTrue(state_2.positive_float_with_none_parameter == 234.)
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/scripts/test/SANS/state/state_functions_test.py b/scripts/test/SANS/state/state_functions_test.py
new file mode 100644
index 0000000000000000000000000000000000000000..e974ae3624c80b4727bd4cf2544326944dfd575b
--- /dev/null
+++ b/scripts/test/SANS/state/state_functions_test.py
@@ -0,0 +1,158 @@
+from __future__ import (absolute_import, division, print_function)
+import unittest
+import mantid
+
+from mantid.api import AnalysisDataService
+from sans.state.state_functions import (get_output_workspace_name, is_pure_none_or_not_none, one_is_none,
+                                            validation_message, is_not_none_and_first_larger_than_second,
+                                            write_hash_into_reduced_can_workspace, get_reduced_can_workspace_from_ads)
+from test_director import TestDirector
+from sans.state.data import StateData
+from sans.common.enums import (ReductionDimensionality, ISISReductionMode, OutputParts)
+from sans.common.general_functions import create_unmanaged_algorithm
+
+
+class StateFunctionsTest(unittest.TestCase):
+    @staticmethod
+    def _get_state():
+        test_director = TestDirector()
+        state = test_director.construct()
+
+        state.data.sample_scatter_run_number = 12345
+        state.data.sample_scatter_period = StateData.ALL_PERIODS
+
+        state.reduction.dimensionality = ReductionDimensionality.OneDim
+
+        state.wavelength.wavelength_low = 12.0
+        state.wavelength.wavelength_high = 34.0
+
+        state.mask.phi_min = 12.0
+        state.mask.phi_max = 56.0
+
+        state.slice.start_time = [4.56778]
+        state.slice.end_time = [12.373938]
+        return state
+
+    @staticmethod
+    def _prepare_workspaces(number_of_workspaces, tagged_workspace_names=None, state=None):
+        create_name = "CreateSampleWorkspace"
+        create_options = {"OutputWorkspace": "test",
+                          "NumBanks": 1,
+                          "BankPixelWidth": 2,
+                          "XMin": 1,
+                          "XMax": 10,
+                          "BinWidth": 2}
+        create_alg = create_unmanaged_algorithm(create_name, **create_options)
+
+        for index in range(number_of_workspaces):
+            create_alg.execute()
+            workspace = create_alg.getProperty("OutputWorkspace").value
+            workspace_name = "test" + "_" + str(index)
+            AnalysisDataService.addOrReplace(workspace_name, workspace)
+
+        if tagged_workspace_names is not None:
+            for key, value in tagged_workspace_names.items():
+                create_alg.execute()
+                workspace = create_alg.getProperty("OutputWorkspace").value
+                AnalysisDataService.addOrReplace(value, workspace)
+                write_hash_into_reduced_can_workspace(state, workspace, key)
+
+    @staticmethod
+    def _remove_workspaces():
+        for element in AnalysisDataService.getObjectNames():
+            AnalysisDataService.remove(element)
+
+    def test_that_unknown_reduction_mode_raises(self):
+        # Arrange
+        state = StateFunctionsTest._get_state()
+
+        # Act + Assert
+        try:
+            get_output_workspace_name(state, ISISReductionMode.All)
+            did_raise = False
+        except RuntimeError:
+            did_raise = True
+        self.assertTrue(did_raise)
+
+    def test_that_creates_correct_workspace_name_for_1D(self):
+        # Arrange
+        state = StateFunctionsTest._get_state()
+        # Act
+        output_workspace = get_output_workspace_name(state, ISISReductionMode.LAB)
+        # Assert
+        self.assertTrue("12345rear_1D12.0_34.0Phi12.0_56.0_t4.57_T12.37" == output_workspace)
+
+    def test_that_detects_if_all_entries_are_none_or_not_none_as_true(self):
+        self.assertFalse(is_pure_none_or_not_none(["test", None, "test"]))
+        self.assertTrue(is_pure_none_or_not_none([None, None, None]))
+        self.assertTrue(is_pure_none_or_not_none(["test", "test", "test"]))
+        self.assertTrue(is_pure_none_or_not_none([]))
+
+    def test_that_detects_if_one_is_none(self):
+        self.assertTrue(one_is_none(["test", None, "test"]))
+        self.assertFalse(one_is_none([]))
+        self.assertFalse(one_is_none(["test", "test", "test"]))
+
+    def test_test_that_can_detect_when_first_is_larger_than_second(self):
+        self.assertTrue(is_not_none_and_first_larger_than_second([1, 2, 3]))
+        self.assertTrue(is_not_none_and_first_larger_than_second([2, 1]))
+        self.assertFalse(is_not_none_and_first_larger_than_second([1, 2]))
+
+    def test_that_produces_correct_validation_message(self):
+        # Arrange
+        error_message = "test message."
+        instruction = "do this."
+        variables = {"var1": 12,
+                     "var2": "test"}
+        # Act
+        val_message = validation_message(error_message, instruction, variables)
+        # Assert
+        expected_text = "var1: 12\n" \
+                        "var2: test\n" \
+                        "" + instruction
+        self.assertTrue(list(val_message.keys())[0] == error_message)
+        self.assertTrue(val_message[error_message] == expected_text)
+
+    def test_that_can_find_can_reduction_if_it_exists(self):
+        # Arrange
+        test_director = TestDirector()
+        state = test_director.construct()
+        tagged_workspace_names = {None: "test_ws",
+                                  OutputParts.Count: "test_ws_count",
+                                  OutputParts.Norm: "test_ws_norm"}
+        StateFunctionsTest._prepare_workspaces(number_of_workspaces=4,
+                                               tagged_workspace_names=tagged_workspace_names,
+                                               state=state)
+        # Act
+        workspace, workspace_count, workspace_norm = get_reduced_can_workspace_from_ads(state, output_parts=True)
+
+        # Assert
+        self.assertTrue(workspace is not None)
+        self.assertTrue(workspace.name() == AnalysisDataService.retrieve("test_ws").name())
+        self.assertTrue(workspace_count is not None)
+        self.assertTrue(workspace_count.name() == AnalysisDataService.retrieve("test_ws_count").name())
+        self.assertTrue(workspace_norm is not None)
+        self.assertTrue(workspace_norm.name() == AnalysisDataService.retrieve("test_ws_norm").name())
+
+        # Clean up
+        StateFunctionsTest._remove_workspaces()
+
+    def test_that_returns_none_if_it_does_not_exist(self):
+        # Arrange
+        test_director = TestDirector()
+        state = test_director.construct()
+        StateFunctionsTest._prepare_workspaces(number_of_workspaces=4, tagged_workspace_names=None, state=state)
+
+        # Act
+        workspace, workspace_count, workspace_norm = get_reduced_can_workspace_from_ads(state, output_parts=False)
+
+        # Assert
+        self.assertTrue(workspace is None)
+        self.assertTrue(workspace_count is None)
+        self.assertTrue(workspace_norm is None)
+
+        # Clean up
+        StateFunctionsTest._remove_workspaces()
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/scripts/test/SANS/state/state_test.py b/scripts/test/SANS/state/state_test.py
new file mode 100644
index 0000000000000000000000000000000000000000..7dea7471e46784143f7511df974db694f65581cb
--- /dev/null
+++ b/scripts/test/SANS/state/state_test.py
@@ -0,0 +1,153 @@
+import unittest
+import mantid
+
+from sans.state.state import (State)
+from sans.state.data import (StateData)
+from sans.state.move import (StateMove)
+from sans.state.reduction_mode import (StateReductionMode)
+from sans.state.slice_event import (StateSliceEvent)
+from sans.state.mask import (StateMask)
+from sans.state.wavelength import (StateWavelength)
+from sans.state.save import (StateSave)
+from sans.state.normalize_to_monitor import (StateNormalizeToMonitor)
+from sans.state.scale import (StateScale)
+from sans.state.calculate_transmission import (StateCalculateTransmission)
+from sans.state.wavelength_and_pixel_adjustment import (StateWavelengthAndPixelAdjustment)
+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
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+#  State
+# ----------------------------------------------------------------------------------------------------------------------
+class MockStateData(StateData):
+    def validate(self):
+        pass
+
+
+class MockStateMove(StateMove):
+    def validate(self):
+        pass
+
+
+class MockStateReduction(StateReductionMode):
+    def get_merge_strategy(self):
+        pass
+
+    def get_detector_name_for_reduction_mode(self, reduction_mode):
+        pass
+
+    def get_all_reduction_modes(self):
+        pass
+
+    def validate(self):
+        pass
+
+
+class MockStateSliceEvent(StateSliceEvent):
+    def validate(self):
+        pass
+
+
+class MockStateMask(StateMask):
+    def validate(self):
+        pass
+
+
+class MockStateWavelength(StateWavelength):
+    def validate(self):
+        pass
+
+
+class MockStateSave(StateSave):
+    def validate(self):
+        pass
+
+
+class MockStateNormalizeToMonitor(StateNormalizeToMonitor):
+    def validate(self):
+        pass
+
+
+class MockStateScale(StateScale):
+    def validate(self):
+        pass
+
+
+class MockStateCalculateTransmission(StateCalculateTransmission):
+    def validate(self):
+        pass
+
+
+class MockStateWavelengthAndPixelAdjustment(StateWavelengthAndPixelAdjustment):
+    def validate(self):
+        pass
+
+
+class MockStateAdjustment(StateAdjustment):
+    def validate(self):
+        pass
+
+
+class MockStateConvertToQ(StateConvertToQ):
+    def validate(self):
+        pass
+
+
+class StateTest(unittest.TestCase):
+    @staticmethod
+    def _get_state(entries):
+        state = State()
+        default_entries = {"data": MockStateData(), "move": MockStateMove(), "reduction": MockStateReduction(),
+                           "slice": MockStateSliceEvent(), "mask": MockStateMask(), "wavelength": MockStateWavelength(),
+                           "save": MockStateSave(), "scale": MockStateScale(), "adjustment": MockStateAdjustment(),
+                           "convert_to_q": MockStateConvertToQ()}
+
+        for key, value in default_entries.items():
+            if key in entries:
+                value = entries[key]
+            if value is not None:  # If the value is None, then don't set it
+                setattr(state, key, value)
+        return state
+
+    def check_bad_and_good_values(self, bad_state, good_state):
+        # Bad values
+        state = self._get_state(bad_state)
+        assert_validate_error(self, ValueError, state)
+
+        # Good values
+        state = self._get_state(good_state)
+        assert_raises_nothing(self, state)
+
+    def test_that_raises_when_move_has_not_been_set(self):
+        self.check_bad_and_good_values({"move": None}, {"move": MockStateMove()})
+
+    def test_that_raises_when_reduction_has_not_been_set(self):
+        self.check_bad_and_good_values({"reduction": None}, {"reduction": MockStateReduction()})
+
+    def test_that_raises_when_slice_has_not_been_set(self):
+        self.check_bad_and_good_values({"slice": None}, {"slice": MockStateSliceEvent()})
+
+    def test_that_raises_when_mask_has_not_been_set(self):
+        self.check_bad_and_good_values({"mask": None}, {"mask": MockStateMask()})
+
+    def test_that_raises_when_wavelength_has_not_been_set(self):
+        self.check_bad_and_good_values({"wavelength": None}, {"wavelength": MockStateWavelength()})
+
+    def test_that_raises_when_save_has_not_been_set(self):
+        self.check_bad_and_good_values({"save": None}, {"save": MockStateSave()})
+
+    def test_that_raises_when_scale_has_not_been_set(self):
+        self.check_bad_and_good_values({"scale": None}, {"scale": MockStateScale()})
+
+    def test_that_raises_when_adjustment_has_not_been_set(self):
+        self.check_bad_and_good_values({"adjustment": None}, {"adjustment": MockStateAdjustment()})
+
+    def test_that_raises_when_convert_to_q_has_not_been_set(self):
+        self.check_bad_and_good_values({"convert_to_q": None}, {"convert_to_q": MockStateConvertToQ()})
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/scripts/test/SANS/state/state_test_helper.py b/scripts/test/SANS/state/state_test_helper.py
new file mode 100644
index 0000000000000000000000000000000000000000..b8752e37bf56d0debb1f9b3f2439f5f450a06bb0
--- /dev/null
+++ b/scripts/test/SANS/state/state_test_helper.py
@@ -0,0 +1,17 @@
+def assert_validate_error(caller, error_type, obj):
+    try:
+        obj.validate()
+        raised_correct = False
+    except error_type:
+        raised_correct = True
+    except:  # noqa
+        raised_correct = False
+    caller.assertTrue(raised_correct)
+
+
+def assert_raises_nothing(caller, obj):
+    obj.validate()
+    try:
+        obj.validate()
+    except:  # noqa
+        caller.fail()
diff --git a/scripts/test/SANS/state/test_director.py b/scripts/test/SANS/state/test_director.py
new file mode 100644
index 0000000000000000000000000000000000000000..8f17df8b1502a491055d62c256ce8de125931dcc
--- /dev/null
+++ b/scripts/test/SANS/state/test_director.py
@@ -0,0 +1,196 @@
+""" A Test director """
+from sans.state.state import get_state_builder
+from sans.state.data import get_data_builder
+from sans.state.move import get_move_builder
+from sans.state.reduction_mode import get_reduction_mode_builder
+from sans.state.slice_event import get_slice_event_builder
+from sans.state.mask import get_mask_builder
+from sans.state.wavelength import get_wavelength_builder
+from sans.state.save import get_save_builder
+from sans.state.normalize_to_monitor import get_normalize_to_monitor_builder
+from sans.state.scale import get_scale_builder
+from sans.state.calculate_transmission import get_calculate_transmission_builder
+from sans.state.wavelength_and_pixel_adjustment import get_wavelength_and_pixel_adjustment_builder
+from sans.state.adjustment import get_adjustment_builder
+from sans.state.convert_to_q import get_convert_to_q_builder
+
+from sans.common.enums import (SANSFacility, ISISReductionMode, ReductionDimensionality,
+                               FitModeForMerge, RebinType, RangeStepType, SaveType, FitType, SampleShape)
+
+
+class TestDirector(object):
+    """ The purpose of this builder is to create a valid state object for tests"""
+    def __init__(self):
+        super(TestDirector, self).__init__()
+        self.data_state = None
+        self.move_state = None
+        self.reduction_state = None
+        self.slice_state = None
+        self.mask_state = None
+        self.wavelength_state = None
+        self.save_state = None
+        self.scale_state = None
+        self.adjustment_state = None
+        self.convert_to_q_state = None
+
+    def set_states(self, data_state=None, move_state=None, reduction_state=None, slice_state=None,
+                   mask_state=None, wavelength_state=None, save_state=None, scale_state=None, adjustment_state=None,
+                   convert_to_q_state=None):
+        self.data_state = data_state
+        self.data_state = data_state
+        self.move_state = move_state
+        self.reduction_state = reduction_state
+        self.slice_state = slice_state
+        self.mask_state = mask_state
+        self.wavelength_state = wavelength_state
+        self.save_state = save_state
+        self.scale_state = scale_state
+        self.adjustment_state = adjustment_state
+        self.convert_to_q_state = convert_to_q_state
+
+    def construct(self):
+        facility = SANSFacility.ISIS
+
+        # Build the SANSStateData
+        if self.data_state is None:
+            data_builder = get_data_builder(facility)
+            data_builder.set_sample_scatter("SANS2D00022024")
+            data_builder.set_can_scatter("SANS2D00022024")
+            self.data_state = data_builder.build()
+
+        # Build the SANSStateMove
+        if self.move_state is None:
+            move_builder = get_move_builder(self.data_state)
+            move_builder.set_HAB_x_translation_correction(21.2)
+            move_builder.set_LAB_x_translation_correction(12.1)
+            self.move_state = move_builder.build()
+
+        # Build the SANSStateReduction
+        if self.reduction_state is None:
+            reduction_builder = get_reduction_mode_builder(self.data_state)
+            reduction_builder.set_reduction_mode(ISISReductionMode.Merged)
+            reduction_builder.set_reduction_dimensionality(ReductionDimensionality.OneDim)
+            reduction_builder.set_merge_fit_mode(FitModeForMerge.Both)
+            reduction_builder.set_merge_shift(324.2)
+            reduction_builder.set_merge_scale(3420.98)
+            self.reduction_state = reduction_builder.build()
+
+        # Build the SANSStateSliceEvent
+        if self.slice_state is None:
+            slice_builder = get_slice_event_builder(self.data_state)
+            slice_builder.set_start_time([0.1, 1.3])
+            slice_builder.set_end_time([0.2, 1.6])
+            self.slice_state = slice_builder.build()
+
+        # Build the SANSStateMask
+        if self.mask_state is None:
+            mask_builder = get_mask_builder(self.data_state)
+            mask_builder.set_radius_min(10.0)
+            mask_builder.set_radius_max(20.0)
+            self.mask_state = mask_builder.build()
+
+        # Build the SANSStateWavelength
+        if self.wavelength_state is None:
+            wavelength_builder = get_wavelength_builder(self.data_state)
+            wavelength_builder.set_wavelength_low(1.0)
+            wavelength_builder.set_wavelength_high(10.0)
+            wavelength_builder.set_wavelength_step(2.0)
+            wavelength_builder.set_wavelength_step_type(RangeStepType.Lin)
+            wavelength_builder.set_rebin_type(RebinType.Rebin)
+            self.wavelength_state = wavelength_builder.build()
+
+        # Build the SANSStateSave
+        if self.save_state is None:
+            save_builder = get_save_builder(self.data_state)
+            save_builder.set_file_name("test_file_name")
+            save_builder.set_file_format([SaveType.Nexus])
+            self.save_state = save_builder.build()
+
+        # Build the SANSStateScale
+        if self.scale_state is None:
+            scale_builder = get_scale_builder(self.data_state)
+            scale_builder.set_shape(SampleShape.Cuboid)
+            scale_builder.set_width(1.0)
+            scale_builder.set_height(2.0)
+            scale_builder.set_thickness(3.0)
+            scale_builder.set_scale(4.0)
+            self.scale_state = scale_builder.build()
+
+        # Build the SANSAdjustmentState
+        if self.adjustment_state is None:
+            # NormalizeToMonitor
+            normalize_to_monitor_builder = get_normalize_to_monitor_builder(self.data_state)
+            normalize_to_monitor_builder.set_wavelength_low(1.0)
+            normalize_to_monitor_builder.set_wavelength_high(10.0)
+            normalize_to_monitor_builder.set_wavelength_step(2.0)
+            normalize_to_monitor_builder.set_wavelength_step_type(RangeStepType.Lin)
+            normalize_to_monitor_builder.set_rebin_type(RebinType.Rebin)
+            normalize_to_monitor_builder.set_background_TOF_general_start(1000.)
+            normalize_to_monitor_builder.set_background_TOF_general_stop(2000.)
+            normalize_to_monitor_builder.set_incident_monitor(1)
+            normalize_to_monitor = normalize_to_monitor_builder.build()
+
+            # CalculateTransmission
+            calculate_transmission_builder = get_calculate_transmission_builder(self.data_state)
+            calculate_transmission_builder.set_transmission_monitor(3)
+            calculate_transmission_builder.set_incident_monitor(2)
+            calculate_transmission_builder.set_wavelength_low(1.0)
+            calculate_transmission_builder.set_wavelength_high(10.0)
+            calculate_transmission_builder.set_wavelength_step(2.0)
+            calculate_transmission_builder.set_wavelength_step_type(RangeStepType.Lin)
+            calculate_transmission_builder.set_rebin_type(RebinType.Rebin)
+            calculate_transmission_builder.set_background_TOF_general_start(1000.)
+            calculate_transmission_builder.set_background_TOF_general_stop(2000.)
+
+            calculate_transmission_builder.set_Sample_fit_type(FitType.Linear)
+            calculate_transmission_builder.set_Sample_polynomial_order(0)
+            calculate_transmission_builder.set_Sample_wavelength_low(1.0)
+            calculate_transmission_builder.set_Sample_wavelength_high(10.0)
+            calculate_transmission_builder.set_Can_fit_type(FitType.Polynomial)
+            calculate_transmission_builder.set_Can_polynomial_order(3)
+            calculate_transmission_builder.set_Can_wavelength_low(10.0)
+            calculate_transmission_builder.set_Can_wavelength_high(20.0)
+            calculate_transmission = calculate_transmission_builder.build()
+
+            # Wavelength and pixel adjustment
+            wavelength_and_pixel_builder = get_wavelength_and_pixel_adjustment_builder(self.data_state)
+            wavelength_and_pixel_builder.set_wavelength_low(1.0)
+            wavelength_and_pixel_builder.set_wavelength_high(10.0)
+            wavelength_and_pixel_builder.set_wavelength_step(2.0)
+            wavelength_and_pixel_builder.set_wavelength_step_type(RangeStepType.Lin)
+            wavelength_and_pixel = wavelength_and_pixel_builder.build()
+
+            # Adjustment
+            adjustment_builder = get_adjustment_builder(self.data_state)
+            adjustment_builder.set_normalize_to_monitor(normalize_to_monitor)
+            adjustment_builder.set_calculate_transmission(calculate_transmission)
+            adjustment_builder.set_wavelength_and_pixel_adjustment(wavelength_and_pixel)
+            self.adjustment_state = adjustment_builder.build()
+
+        # SANSStateConvertToQ
+        if self.convert_to_q_state is None:
+            convert_to_q_builder = get_convert_to_q_builder(self.data_state)
+            convert_to_q_builder.set_reduction_dimensionality(ReductionDimensionality.OneDim)
+            convert_to_q_builder.set_use_gravity(False)
+            convert_to_q_builder.set_radius_cutoff(0.002)
+            convert_to_q_builder.set_wavelength_cutoff(12.)
+            convert_to_q_builder.set_q_min(0.1)
+            convert_to_q_builder.set_q_max(0.8)
+            convert_to_q_builder.set_q_step(0.01)
+            convert_to_q_builder.set_q_step_type(RangeStepType.Lin)
+            convert_to_q_builder.set_use_q_resolution(False)
+            self.convert_to_q_state = convert_to_q_builder.build()
+
+        # Set the sub states on the SANSState
+        state_builder = get_state_builder(self.data_state)
+        state_builder.set_data(self.data_state)
+        state_builder.set_move(self.move_state)
+        state_builder.set_reduction(self.reduction_state)
+        state_builder.set_slice(self.slice_state)
+        state_builder.set_mask(self.mask_state)
+        state_builder.set_wavelength(self.wavelength_state)
+        state_builder.set_save(self.save_state)
+        state_builder.set_scale(self.scale_state)
+        state_builder.set_adjustment(self.adjustment_state)
+        state_builder.set_convert_to_q(self.convert_to_q_state)
+        return state_builder.build()
diff --git a/scripts/test/SANS/state/wavelength_and_pixel_adjustment_test.py b/scripts/test/SANS/state/wavelength_and_pixel_adjustment_test.py
new file mode 100644
index 0000000000000000000000000000000000000000..15b54ab808adb5c0714930cd1c94d7a9364cf10a
--- /dev/null
+++ b/scripts/test/SANS/state/wavelength_and_pixel_adjustment_test.py
@@ -0,0 +1,73 @@
+import unittest
+import mantid
+
+from sans.state.wavelength_and_pixel_adjustment import (StateWavelengthAndPixelAdjustment,
+                                                        get_wavelength_and_pixel_adjustment_builder)
+from sans.state.data import get_data_builder
+from sans.common.enums import (RebinType, RangeStepType, DetectorType, SANSFacility, SANSInstrument)
+from state_test_helper import assert_validate_error, assert_raises_nothing
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# State
+# ----------------------------------------------------------------------------------------------------------------------
+class StateWavelengthAndPixelAdjustmentTest(unittest.TestCase):
+    def test_that_raises_when_wavelength_entry_is_missing(self):
+        # Arrange
+        state = StateWavelengthAndPixelAdjustment()
+        assert_validate_error(self, ValueError, state)
+        state.wavelength_low = 1.
+        assert_validate_error(self, ValueError, state)
+        state.wavelength_high = 2.
+        assert_validate_error(self, ValueError, state)
+        state.wavelength_step = 2.
+        assert_validate_error(self, ValueError, state)
+        state.wavelength_step_type = RangeStepType.Lin
+        assert_raises_nothing(self, state)
+
+    def test_that_raises_when_lower_wavelength_is_smaller_than_high_wavelength(self):
+        state = StateWavelengthAndPixelAdjustment()
+        state.wavelength_low = 2.
+        state.wavelength_high = 1.
+        state.wavelength_step = 2.
+        state.wavelength_step_type = RangeStepType.Lin
+        assert_validate_error(self, ValueError, state)
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# Builder
+# ----------------------------------------------------------------------------------------------------------------------
+class StateWavelengthAndPixelAdjustmentBuilderTest(unittest.TestCase):
+    def test_that_wavelength_and_pixel_adjustment_state_can_be_built(self):
+        # Arrange
+        facility = SANSFacility.ISIS
+        data_builder = get_data_builder(facility)
+        data_builder.set_sample_scatter("LOQ74044")
+        data_info = data_builder.build()
+
+        # Act
+        builder = get_wavelength_and_pixel_adjustment_builder(data_info)
+        self.assertTrue(builder)
+
+        builder.set_HAB_pixel_adjustment_file("test")
+        builder.set_HAB_wavelength_adjustment_file("test2")
+        builder.set_wavelength_low(1.5)
+        builder.set_wavelength_high(2.7)
+        builder.set_wavelength_step(0.5)
+        builder.set_wavelength_step_type(RangeStepType.Lin)
+
+        state = builder.build()
+
+        # Assert
+        self.assertTrue(state.adjustment_files[DetectorType.to_string(
+                                                                     DetectorType.HAB)].pixel_adjustment_file == "test")
+        self.assertTrue(state.adjustment_files[DetectorType.to_string(
+                                                              DetectorType.HAB)].wavelength_adjustment_file == "test2")
+        self.assertTrue(state.wavelength_low == 1.5)
+        self.assertTrue(state.wavelength_high == 2.7)
+        self.assertTrue(state.wavelength_step == 0.5)
+        self.assertTrue(state.wavelength_step_type is RangeStepType.Lin)
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/scripts/test/SANS/state/wavelength_test.py b/scripts/test/SANS/state/wavelength_test.py
new file mode 100644
index 0000000000000000000000000000000000000000..11dd84c6e3f49f6a4b241deeb8314db5253a8d6c
--- /dev/null
+++ b/scripts/test/SANS/state/wavelength_test.py
@@ -0,0 +1,70 @@
+import unittest
+import mantid
+
+from sans.state.wavelength import (StateWavelength, get_wavelength_builder)
+from sans.state.data import get_data_builder
+from sans.common.enums import (SANSFacility, SANSInstrument, RebinType, RangeStepType)
+from state_test_helper import assert_validate_error, assert_raises_nothing
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# State
+# ----------------------------------------------------------------------------------------------------------------------
+class StateWavelengthTest(unittest.TestCase):
+
+    def test_that_is_sans_state_data_object(self):
+        state = StateWavelength()
+        self.assertTrue(isinstance(state, StateWavelength))
+
+    def test_that_raises_when_wavelength_entry_is_missing(self):
+        # Arrange
+        state = StateWavelength()
+        assert_validate_error(self, ValueError, state)
+        state.wavelength_low = 1.
+        assert_validate_error(self, ValueError, state)
+        state.wavelength_high = 2.
+        assert_validate_error(self, ValueError, state)
+        state.wavelength_step = 2.
+        assert_raises_nothing(self, state)
+
+    def test_that_raises_when_lower_wavelength_is_smaller_than_high_wavelength(self):
+        state = StateWavelength()
+        state.wavelength_low = 2.
+        state.wavelength_high = 1.
+        state.wavelength_step = 2.
+        assert_validate_error(self, ValueError, state)
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# Builder
+# ----------------------------------------------------------------------------------------------------------------------
+
+class StateSliceEventBuilderTest(unittest.TestCase):
+    def test_that_slice_event_state_can_be_built(self):
+        # Arrange
+        facility = SANSFacility.ISIS
+        data_builder = get_data_builder(facility)
+        data_builder.set_sample_scatter("LOQ74044")
+        data_info = data_builder.build()
+
+        # Act
+        builder = get_wavelength_builder(data_info)
+        self.assertTrue(builder)
+
+        builder.set_wavelength_low(10.0)
+        builder.set_wavelength_high(20.0)
+        builder.set_wavelength_step(3.0)
+        builder.set_wavelength_step_type(RangeStepType.Lin)
+        builder.set_rebin_type(RebinType.Rebin)
+
+        # Assert
+        state = builder.build()
+
+        self.assertTrue(state.wavelength_low == 10.0)
+        self.assertTrue(state.wavelength_high == 20.0)
+        self.assertTrue(state.wavelength_step_type is RangeStepType.Lin)
+        self.assertTrue(state.rebin_type is RebinType.Rebin)
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/tools/scripts/ConvertBadAlgmLinks.py b/tools/scripts/ConvertBadAlgmLinks.py
index 848d84b431acac0d717c6cedf251032c72d6607c..05cbd6b87c6dc221de06976879a80d41cac0efe2 100644
--- a/tools/scripts/ConvertBadAlgmLinks.py
+++ b/tools/scripts/ConvertBadAlgmLinks.py
@@ -2,6 +2,7 @@
 import re
 import glob
 import os
+from mantid.api import AlgorithmFactory
 
 
 def grep(patt,lines):
diff --git a/tools/scripts/CorrectConceptLinksinAlgPages.py b/tools/scripts/CorrectConceptLinksinAlgPages.py
index 3591e2349db0880aeb05cfcbaf99d76fe1b3031c..79ceea38e64419043739c6e8e19a5de86de37a76 100644
--- a/tools/scripts/CorrectConceptLinksinAlgPages.py
+++ b/tools/scripts/CorrectConceptLinksinAlgPages.py
@@ -1,6 +1,7 @@
 #pylint: disable=invalid-name
 import os
 import re
+from mantid.api import AlgorithmFactory
 
 concepts = ['Algorithm',
             'Analysis_Data_Service',
diff --git a/tools/scripts/FindIncompleteAlgRSTPages.py b/tools/scripts/FindIncompleteAlgRSTPages.py
index 5e2e00d21e7cea952b2ca776b35cf2f744bd7a82..59a0e81a22a59216b7e97e025e4699e10dcac252 100644
--- a/tools/scripts/FindIncompleteAlgRSTPages.py
+++ b/tools/scripts/FindIncompleteAlgRSTPages.py
@@ -2,6 +2,7 @@
 import os
 import re
 import urllib2
+from mantid.api import AlgorithmFactory
 
 
 def readWebPage(url):
diff --git a/tools/scripts/extractAlgorithmNames.py b/tools/scripts/extractAlgorithmNames.py
index 8945b898c9e698c5c3d261c1d0ba9d35ad42635e..1412d90797e4bbe8364d276108b53bb9fdb95f1b 100644
--- a/tools/scripts/extractAlgorithmNames.py
+++ b/tools/scripts/extractAlgorithmNames.py
@@ -1,7 +1,7 @@
 #pylint: disable=invalid-name
 # simply just print out all algorithm names in a directory which can be piped
 # to a file
-
+import os
 import glob
 
 os.chdir("PythonInterface/plugins/algorithms/WorkflowAlgorithms")