diff --git a/Framework/API/inc/MantidAPI/Algorithm.h b/Framework/API/inc/MantidAPI/Algorithm.h
index 88ee8013221918ce495a0d7d7ada462a59ac8293..99b06db1bcda1eaaf9407db85902ac1a803e3cbd 100644
--- a/Framework/API/inc/MantidAPI/Algorithm.h
+++ b/Framework/API/inc/MantidAPI/Algorithm.h
@@ -10,13 +10,11 @@
 
 // -- These headers will (most-likely) be used by every inheriting algorithm
 #include "MantidAPI/AlgorithmFactory.h" //for the factory macro
-#include "MantidAPI/IndexTypeProperty.h"
 #include "MantidAPI/Progress.h"
 #include "MantidAPI/WorkspaceOpOverloads.h"
 #include "MantidAPI/WorkspaceProperty.h"
 #include "MantidKernel/EmptyValues.h"
 #include "MantidKernel/MultiThreaded.h"
-#include <MantidIndexing/SpectrumIndexSet.h>
 
 #include "MantidParallel/ExecutionMode.h"
 #include "MantidParallel/StorageMode.h"
@@ -37,6 +35,9 @@ class Value;
 }
 
 namespace Mantid {
+namespace Indexing {
+class SpectrumIndexSet;
+}
 namespace Parallel {
 class Communicator;
 }
@@ -201,7 +202,7 @@ public:
                 std::is_convertible<T1 *, MatrixWorkspace *>::value>::type,
             typename = typename std::enable_if<
                 std::is_convertible<T2 *, std::string *>::value ||
-                std::is_convertible<T2 *, std::vector<int> *>::value>::type>
+                std::is_convertible<T2 *, std::vector<int64_t> *>::value>::type>
   void setWorkspaceInputProperties(const std::string &name,
                                    const boost::shared_ptr<T1> &wksp,
                                    IndexType type, const T2 &list);
@@ -211,7 +212,7 @@ public:
                 std::is_convertible<T1 *, MatrixWorkspace *>::value>::type,
             typename = typename std::enable_if<
                 std::is_convertible<T2 *, std::string *>::value ||
-                std::is_convertible<T2 *, std::vector<int> *>::value>::type>
+                std::is_convertible<T2 *, std::vector<int64_t> *>::value>::type>
   void setWorkspaceInputProperties(const std::string &name,
                                    const std::string &wsName, IndexType type,
                                    const T2 &list);
@@ -291,6 +292,10 @@ public:
       const std::string &name, const double startProgress = -1.,
       const double endProgress = -1., const bool enableLogging = true,
       const int &version = -1);
+  void setupAsChildAlgorithm(boost::shared_ptr<Algorithm> algorithm,
+                             const double startProgress = -1.,
+                             const double endProgress = -1.,
+                             const bool enableLogging = true);
 
   /// set whether we wish to track the child algorithm's history and pass it the
   /// parent object to fill.
diff --git a/Framework/API/inc/MantidAPI/Algorithm.tcc b/Framework/API/inc/MantidAPI/Algorithm.tcc
index dfb429a918bd4c58edf0cc23928124bfe964bfa8..b5f1f07fb1d89152bf7348dd2b67d11a4f26f271 100644
--- a/Framework/API/inc/MantidAPI/Algorithm.tcc
+++ b/Framework/API/inc/MantidAPI/Algorithm.tcc
@@ -110,7 +110,7 @@ void Algorithm::setWorkspaceInputProperties(const std::string &name,
 
 /** Mechanism for setting the index property with a workspace shared pointer.
 * This method can only be used if T1 is convertible to a MatrixWorkspace and
-* T2 is either std::string or std::vector<int>
+* T2 is either std::string or std::vector<int64_t>
 
 @param name Property name
 @param wsName Workspace name as string
diff --git a/Framework/API/inc/MantidAPI/ISpectrum.h b/Framework/API/inc/MantidAPI/ISpectrum.h
index 764002a85bf313193cb2882b254572171b4fb867..25137e84324db06c3bcea266a156acf55266527f 100644
--- a/Framework/API/inc/MantidAPI/ISpectrum.h
+++ b/Framework/API/inc/MantidAPI/ISpectrum.h
@@ -8,7 +8,12 @@
 
 #include <set>
 
+class SpectrumTester;
 namespace Mantid {
+namespace DataObjects {
+class Histogram1D;
+class EventList;
+}
 namespace API {
 class MatrixWorkspace;
 
@@ -54,6 +59,9 @@ public:
 
   void copyInfoFrom(const ISpectrum &other);
 
+  /// Copy data from another ISpectrum with double-dynamic dispatch.
+  virtual void copyDataFrom(const ISpectrum &source) = 0;
+
   virtual void setX(const Kernel::cow_ptr<HistogramData::HistogramX> &X) = 0;
   virtual MantidVec &dataX() = 0;
   virtual const MantidVec &dataX() const = 0;
@@ -242,6 +250,10 @@ public:
 
   void setMatrixWorkspace(MatrixWorkspace *matrixWorkspace, const size_t index);
 
+  virtual void copyDataInto(DataObjects::EventList &) const;
+  virtual void copyDataInto(DataObjects::Histogram1D &) const;
+  virtual void copyDataInto(SpectrumTester &) const;
+
 protected:
   virtual void checkAndSanitizeHistogram(HistogramData::Histogram &){};
   virtual void checkWorksWithPoints() const {}
diff --git a/Framework/API/inc/MantidAPI/IndexProperty.h b/Framework/API/inc/MantidAPI/IndexProperty.h
index acddee7702027616b5e1644ef6bb181a66e0dfe1..1952a88d54c173ceae0e07af0c54bd02043681ce 100644
--- a/Framework/API/inc/MantidAPI/IndexProperty.h
+++ b/Framework/API/inc/MantidAPI/IndexProperty.h
@@ -8,6 +8,9 @@
 #include "MantidKernel/ArrayProperty.h"
 
 namespace Mantid {
+namespace Indexing {
+class IndexInfo;
+}
 namespace API {
 
 /** IndexProperty : Implementation of a property type which returns a
@@ -40,7 +43,7 @@ namespace API {
   File change history is stored at: <https://github.com/mantidproject/mantid>
   Code Documentation is available at: <http://doxygen.mantidproject.org>
 */
-class MANTID_API_DLL IndexProperty : public Kernel::ArrayProperty<int> {
+class MANTID_API_DLL IndexProperty : public Kernel::ArrayProperty<int64_t> {
 public:
   IndexProperty(const std::string &name,
                 const IWorkspaceProperty &workspaceProp,
@@ -50,17 +53,20 @@ public:
 
   IndexProperty *clone() const override;
 
-  using Kernel::ArrayProperty<int>::operator=;
+  using Kernel::ArrayProperty<int64_t>::operator=;
 
   bool isDefault() const override;
   std::string isValid() const override;
   std::string operator=(const std::string &rhs);
   operator Indexing::SpectrumIndexSet() const;
   Indexing::SpectrumIndexSet getIndices() const;
+  Indexing::IndexInfo getFilteredIndexInfo() const;
 
   static std::string generatePropertyName(const std::string &name = "");
 
 private:
+  const Indexing::IndexInfo &getIndexInfoFromWorkspace() const;
+
   const IWorkspaceProperty &m_workspaceProp;
   const IndexTypeProperty &m_indexTypeProp;
   mutable Indexing::SpectrumIndexSet m_indices;
@@ -71,4 +77,4 @@ private:
 } // namespace API
 } // namespace Mantid
 
-#endif /* MANTID_API_INDEXPROPERTY_H_ */
\ No newline at end of file
+#endif /* MANTID_API_INDEXPROPERTY_H_ */
diff --git a/Framework/API/inc/MantidAPI/MatrixWorkspace.h b/Framework/API/inc/MantidAPI/MatrixWorkspace.h
index 45ed1ea4688dbb825f2cdff168379f008e4a7599..32dba628494e8065b97bd633bc3b34eb4f3f80d8 100644
--- a/Framework/API/inc/MantidAPI/MatrixWorkspace.h
+++ b/Framework/API/inc/MantidAPI/MatrixWorkspace.h
@@ -451,6 +451,7 @@ public:
   /// index, weight>
   typedef std::map<size_t, double> MaskList;
   const MaskList &maskedBins(const size_t &workspaceIndex) const;
+  void setMaskedBins(const size_t workspaceIndex, const MaskList &maskedBins);
 
   // Methods handling the internal monitor workspace
   virtual void
diff --git a/Framework/API/src/Algorithm.cpp b/Framework/API/src/Algorithm.cpp
index 5204ce09f55aee54497d96c57e999b6416985a7e..fe785b499ef4b21cb3d5c446bdd4ae2cb5dd96ad 100644
--- a/Framework/API/src/Algorithm.cpp
+++ b/Framework/API/src/Algorithm.cpp
@@ -743,6 +743,20 @@ Algorithm_sptr Algorithm::createChildAlgorithm(const std::string &name,
                                                const int &version) {
   Algorithm_sptr alg =
       AlgorithmManager::Instance().createUnmanaged(name, version);
+  setupAsChildAlgorithm(alg, startProgress, endProgress, enableLogging);
+  return alg;
+}
+
+/** Setup algorithm as child algorithm.
+ *
+ * Used internally by createChildAlgorithm. Arguments are as documented there.
+ * Can also be used manually for algorithms created otherwise. This allows
+ * running algorithms that are not declared into the factory as child
+ * algorithms. */
+void Algorithm::setupAsChildAlgorithm(Algorithm_sptr alg,
+                                      const double startProgress,
+                                      const double endProgress,
+                                      const bool enableLogging) {
   // set as a child
   alg->setChild(true);
   alg->setLogging(enableLogging);
@@ -751,8 +765,8 @@ Algorithm_sptr Algorithm::createChildAlgorithm(const std::string &name,
   try {
     alg->initialize();
   } catch (std::runtime_error &) {
-    throw std::runtime_error("Unable to initialise Child Algorithm '" + name +
-                             "'");
+    throw std::runtime_error("Unable to initialise Child Algorithm '" +
+                             alg->name() + "'");
   }
 
   // If output workspaces are nameless, give them a temporary name to satisfy
@@ -783,8 +797,6 @@ Algorithm_sptr Algorithm::createChildAlgorithm(const std::string &name,
   PARALLEL_CRITICAL(Algorithm_StoreWeakPtr) {
     m_ChildAlgorithms.push_back(weakPtr);
   }
-
-  return alg;
 }
 
 //=============================================================================================
diff --git a/Framework/API/src/ISpectrum.cpp b/Framework/API/src/ISpectrum.cpp
index 3bdb384dee1c4953fc39519dfa6dedbcde64bdf6..5006b7be2b72ab6b4903d5d146b27b4f932952db 100644
--- a/Framework/API/src/ISpectrum.cpp
+++ b/Framework/API/src/ISpectrum.cpp
@@ -199,5 +199,19 @@ void ISpectrum::invalidateSpectrumDefinition() const {
     m_matrixWorkspace->invalidateSpectrumDefinition(m_index);
 }
 
+/// Override in child classes for polymorphic copying of data.
+void ISpectrum::copyDataInto(DataObjects::EventList &) const {
+  throw std::runtime_error("Incompatible types in ISpectrum::copyDataFrom");
+}
+/// Override in child classes for polymorphic copying of data.
+void ISpectrum::copyDataInto(DataObjects::Histogram1D &) const {
+  throw std::runtime_error("Incompatible types in ISpectrum::copyDataFrom");
+}
+
+/// Override in child classes for polymorphic copying of data.
+void ISpectrum::copyDataInto(SpectrumTester &) const {
+  throw std::runtime_error("Incompatible types in ISpectrum::copyDataFrom");
+}
+
 } // namespace Mantid
 } // namespace API
diff --git a/Framework/API/src/IndexProperty.cpp b/Framework/API/src/IndexProperty.cpp
index 3d8c808025a15ab0fcbabdd5427ac9076e197fb9..fa8dedb614158378416296d0df4446720019eea6 100644
--- a/Framework/API/src/IndexProperty.cpp
+++ b/Framework/API/src/IndexProperty.cpp
@@ -42,25 +42,15 @@ IndexProperty::operator Indexing::SpectrumIndexSet() const {
 }
 
 Indexing::SpectrumIndexSet IndexProperty::getIndices() const {
-  MatrixWorkspace_sptr wksp = boost::dynamic_pointer_cast<MatrixWorkspace>(
-      m_workspaceProp.getWorkspace());
-  if (!wksp)
-    throw std::runtime_error("Invalid workspace type provided to "
-                             "IndexProperty. Must be convertible to "
-                             "MatrixWorkspace.");
-
-  const auto &indexInfo = wksp->indexInfo();
+  const auto &indexInfo = getIndexInfoFromWorkspace();
   auto type = m_indexTypeProp.selectedType();
 
   if (m_value.empty()) {
     return indexInfo.makeIndexSet();
   } else {
-    auto res = std::minmax_element(m_value.cbegin(), m_value.cend());
-    auto min = *res.first;
-    auto max = *res.second;
-
+    auto min = m_value.front();
+    auto max = m_value.back();
     auto isRange = (max - min) == static_cast<int>(m_value.size() - 1);
-
     if (isRange) {
       switch (type) {
       case IndexType::WorkspaceIndex:
@@ -69,8 +59,8 @@ Indexing::SpectrumIndexSet IndexProperty::getIndices() const {
             static_cast<Indexing::GlobalSpectrumIndex>(max));
       case IndexType::SpectrumNum:
         return indexInfo.makeIndexSet(
-            static_cast<Indexing::SpectrumNumber>(min),
-            static_cast<Indexing::SpectrumNumber>(max));
+            static_cast<Indexing::SpectrumNumber>(static_cast<int32_t>(min)),
+            static_cast<Indexing::SpectrumNumber>(static_cast<int32_t>(max)));
       }
     } else {
       switch (type) {
@@ -78,9 +68,13 @@ Indexing::SpectrumIndexSet IndexProperty::getIndices() const {
         return indexInfo.makeIndexSet(
             std::vector<Indexing::GlobalSpectrumIndex>(m_value.begin(),
                                                        m_value.end()));
-      case IndexType::SpectrumNum:
-        return indexInfo.makeIndexSet(std::vector<Indexing::SpectrumNumber>(
-            m_value.begin(), m_value.end()));
+      case IndexType::SpectrumNum: {
+        std::vector<Indexing::SpectrumNumber> spectrumNumbers;
+        for (const auto index : m_value)
+          spectrumNumbers.push_back(static_cast<Indexing::SpectrumNumber>(
+              static_cast<int32_t>(index)));
+        return indexInfo.makeIndexSet(spectrumNumbers);
+      }
       }
     }
   }
@@ -89,8 +83,47 @@ Indexing::SpectrumIndexSet IndexProperty::getIndices() const {
   return m_indices;
 }
 
+/** Return IndexInfo created from workspace but containing selected spectra.
+ *
+ * The selected spectra are the same as in the SpectrumIndexSet returned by this
+ * property and the order is guaranteed to be consistent. That is, if the Nth
+ * entry in the SpectrumIndexSet is M, the spectrum with index M in the input
+ * workspace is equal to the spectrum with index N in the returned IndexInfo. */
+Indexing::IndexInfo IndexProperty::getFilteredIndexInfo() const {
+  const auto &indexInfo = getIndexInfoFromWorkspace();
+  if (m_value.empty())
+    return indexInfo;
+  switch (m_indexTypeProp.selectedType()) {
+  case IndexType::WorkspaceIndex:
+    return {std::vector<Indexing::GlobalSpectrumIndex>(m_value.begin(),
+                                                       m_value.end()),
+            indexInfo};
+  case IndexType::SpectrumNum: {
+    std::vector<Indexing::SpectrumNumber> spectrumNumbers;
+    for (const auto index : m_value)
+      spectrumNumbers.push_back(
+          static_cast<Indexing::SpectrumNumber>(static_cast<int32_t>(index)));
+    return {spectrumNumbers, indexInfo};
+  }
+  default:
+    throw std::runtime_error(
+        "IndexProperty::getFilteredIndexInfo -- unsupported index type");
+  }
+}
+
 std::string IndexProperty::generatePropertyName(const std::string &name) {
   return name + "IndexSet";
 }
+
+const Indexing::IndexInfo &IndexProperty::getIndexInfoFromWorkspace() const {
+  auto wksp = boost::dynamic_pointer_cast<MatrixWorkspace>(
+      m_workspaceProp.getWorkspace());
+  if (!wksp)
+    throw std::runtime_error("Invalid workspace type provided to "
+                             "IndexProperty. Must be convertible to "
+                             "MatrixWorkspace.");
+  return wksp->indexInfo();
+}
+
 } // namespace API
-} // namespace Mantid
\ No newline at end of file
+} // namespace Mantid
diff --git a/Framework/API/src/MatrixWorkspace.cpp b/Framework/API/src/MatrixWorkspace.cpp
index 3e01e7c589644a2621d4124c342b831f875d19f7..f957db8ec78ca57ea6dea03e9d71b8611cb55301 100644
--- a/Framework/API/src/MatrixWorkspace.cpp
+++ b/Framework/API/src/MatrixWorkspace.cpp
@@ -581,6 +581,11 @@ MatrixWorkspace::getIndexFromSpectrumNumber(const specnum_t specNo) const {
  */
 std::vector<size_t> MatrixWorkspace::getIndicesFromDetectorIDs(
     const std::vector<detid_t> &detIdList) const {
+  if (m_indexInfo->size() != m_indexInfo->globalSize())
+    throw std::runtime_error("MatrixWorkspace: Using getIndicesFromDetectorIDs "
+                             "in a parallel run is most likely incorrect. "
+                             "Aborting.");
+
   std::map<detid_t, std::set<size_t>> detectorIDtoWSIndices;
   for (size_t i = 0; i < getNumberHistograms(); ++i) {
     auto detIDs = getSpectrum(i).getDetectorIDs();
@@ -1084,6 +1089,16 @@ MatrixWorkspace::maskedBins(const size_t &workspaceIndex) const {
   return it->second;
 }
 
+/** Set the list of masked bins for given workspaceIndex. Not thread safe.
+ *
+ * No data is masked and previous masking for any bin for this workspace index
+ * is overridden, so this should only be used for copying flags into a new
+ * workspace, not for performing masking operations. */
+void MatrixWorkspace::setMaskedBins(const size_t workspaceIndex,
+                                    const MaskList &maskedBins) {
+  m_masks[workspaceIndex] = maskedBins;
+}
+
 /** Sets the internal monitor workspace to the provided workspace.
  *  This method is intended for use by data-loading algorithms.
  *  Note that no checking is performed as to whether this workspace actually
@@ -1896,7 +1911,7 @@ void MatrixWorkspace::setImageE(const MantidImage &image, size_t start,
 }
 
 void MatrixWorkspace::invalidateCachedSpectrumNumbers() {
-  if (storageMode() == Parallel::StorageMode::Distributed &&
+  if (m_isInitialized && storageMode() == Parallel::StorageMode::Distributed &&
       m_indexInfo->communicator().size() > 1)
     throw std::logic_error("Setting spectrum numbers in MatrixWorkspace via "
                            "ISpectrum::setSpectrumNo is not possible in MPI "
diff --git a/Framework/API/src/WorkspaceFactory.cpp b/Framework/API/src/WorkspaceFactory.cpp
index 88525dfa5d5b01926b840b8c6e748effe8e890b0..ffea8dc23753712aba98cc4a68887401eb3d8b6b 100644
--- a/Framework/API/src/WorkspaceFactory.cpp
+++ b/Framework/API/src/WorkspaceFactory.cpp
@@ -105,8 +105,10 @@ void WorkspaceFactoryImpl::initializeFromParent(
 
   // Same number of histograms = copy over the spectra data
   if (parent.getNumberHistograms() == child.getNumberHistograms()) {
+    child.m_isInitialized = false;
     for (size_t i = 0; i < parent.getNumberHistograms(); ++i)
       child.getSpectrum(i).copyInfoFrom(parent.getSpectrum(i));
+    child.m_isInitialized = true;
     // We use this variant without ISpectrum update to avoid costly rebuilds
     // triggered by setIndexInfo(). ISpectrum::copyInfoFrom sets invalid flags
     // for spectrum definitions, so it is important to call this *afterwards*,
diff --git a/Framework/API/test/AlgorithmTest.h b/Framework/API/test/AlgorithmTest.h
index 3eb061f2bc32a54c1f380a353c43b794b68001b0..92f3c17252ceb9c6a6e124cc28390e644b356b16 100644
--- a/Framework/API/test/AlgorithmTest.h
+++ b/Framework/API/test/AlgorithmTest.h
@@ -836,10 +836,9 @@ public:
         WorkspaceFactory::Instance().create("WorkspaceTester", 10, 10, 9);
     IndexingAlgorithm indexAlg;
     indexAlg.init();
-    TS_ASSERT_THROWS_NOTHING((
-        indexAlg.setWorkspaceInputProperties<MatrixWorkspace, std::vector<int>>(
-            "InputWorkspace", wksp, IndexType::WorkspaceIndex,
-            std::vector<int>{1, 2, 3, 4, 5})));
+    TS_ASSERT_THROWS_NOTHING((indexAlg.setWorkspaceInputProperties(
+        "InputWorkspace", wksp, IndexType::WorkspaceIndex,
+        std::vector<int64_t>{1, 2, 3, 4, 5})));
   }
 
   void
@@ -861,10 +860,10 @@ public:
     IndexingAlgorithm indexAlg;
     indexAlg.init();
     // Requires workspace in ADS due to validity checks
-    TS_ASSERT_THROWS_NOTHING((
-        indexAlg.setWorkspaceInputProperties<MatrixWorkspace, std::vector<int>>(
+    TS_ASSERT_THROWS_NOTHING(
+        (indexAlg.setWorkspaceInputProperties<MatrixWorkspace>(
             "InputWorkspace", "wksp", IndexType::WorkspaceIndex,
-            std::vector<int>{1, 2, 3, 4, 5})));
+            std::vector<int64_t>{1, 2, 3, 4, 5})));
     AnalysisDataService::Instance().remove("wksp");
   }
 
diff --git a/Framework/API/test/IndexPropertyTest.h b/Framework/API/test/IndexPropertyTest.h
index e802b61aae122aa661995d8931f125301b6f0c49..aab2ffb9ea173969e159b80652cf740ebe3ff023 100644
--- a/Framework/API/test/IndexPropertyTest.h
+++ b/Framework/API/test/IndexPropertyTest.h
@@ -7,6 +7,7 @@
 #include "MantidAPI/WorkspaceProperty.h"
 #include "MantidKernel/PropertyManager.h"
 #include "MantidKernel/make_unique.h"
+#include "MantidIndexing/IndexInfo.h"
 #include "MantidTestHelpers/FakeObjects.h"
 #include <boost/shared_ptr.hpp>
 #include <cxxtest/TestSuite.h>
@@ -60,7 +61,7 @@ public:
     auto indexSet = indexProp.getIndices();
 
     TS_ASSERT_EQUALS(indexSet.size(), 6);
-    std::vector<int> testVec{0, 1, 2, 3, 4, 7};
+    std::vector<int64_t> testVec{0, 1, 2, 3, 4, 7};
 
     for (size_t i = 0; i < indexSet.size(); i++)
       TS_ASSERT_EQUALS(indexSet[i], testVec[i]);
@@ -77,7 +78,7 @@ public:
     auto indexSet = indexProp.getIndices();
 
     TS_ASSERT_EQUALS(indexSet.size(), 6);
-    std::vector<int> testVec{0, 1, 2, 3, 4, 5};
+    std::vector<int64_t> testVec{0, 1, 2, 3, 4, 5};
 
     for (size_t i = 0; i < indexSet.size(); i++)
       TS_ASSERT_EQUALS(indexSet[i], testVec[i]);
@@ -89,7 +90,7 @@ public:
 
     IndexTypeProperty itypeProp("IndexType", IndexType::SpectrumNum);
     IndexProperty indexProp("IndexSet", m_wkspProp, itypeProp);
-    std::vector<int> input{1, 3, 5, 7};
+    std::vector<int64_t> input{1, 3, 5, 7};
     indexProp = input;
 
     auto indexSet = indexProp.getIndices();
@@ -100,6 +101,22 @@ public:
       TS_ASSERT_EQUALS(indexSet[i], input[i] - 1);
   }
 
+  void testIndexOrderOfFullRangePreserved() {
+    auto ws = WorkspaceFactory::Instance().create("WorkspaceTester", 3, 1, 1);
+    m_wkspProp = ws;
+    IndexTypeProperty itypeProp("IndexType", IndexType::WorkspaceIndex);
+    IndexProperty indexProp("IndexSet", m_wkspProp, itypeProp);
+    std::vector<int64_t> input{0, 2, 1};
+    indexProp = input;
+
+    auto indexSet = indexProp.getIndices();
+
+    TS_ASSERT_EQUALS(indexSet.size(), 3);
+    TS_ASSERT_EQUALS(indexSet[0], 0);
+    TS_ASSERT_EQUALS(indexSet[1], 2);
+    TS_ASSERT_EQUALS(indexSet[2], 1);
+  }
+
   void testInvalidWhenIndicesOutOfRange() {
     auto ws = WorkspaceFactory::Instance().create("WorkspaceTester", 10, 10, 9);
     m_wkspProp = ws;
@@ -123,7 +140,7 @@ public:
     auto indices = Mantid::Indexing::SpectrumIndexSet(indexProp);
 
     TS_ASSERT(indices.size() == 5);
-    for (int i = 0; i < 5; i++)
+    for (int64_t i = 0; i < 5; i++)
       TS_ASSERT_EQUALS(indices[i], i + 1)
   }
 
@@ -133,9 +150,43 @@ public:
                      IndexProperty::generatePropertyName(propName));
   }
 
+  void testGetFilteredIndexInfo_WorkspaceIndex() {
+    auto ws = WorkspaceFactory::Instance().create("WorkspaceTester", 3, 1, 1);
+    m_wkspProp = ws;
+    IndexTypeProperty itypeProp("IndexType", IndexType::WorkspaceIndex);
+    IndexProperty indexProp("IndexSet", m_wkspProp, itypeProp);
+
+    auto indexInfo = indexProp.getFilteredIndexInfo();
+    TS_ASSERT_EQUALS(indexInfo.size(), 3);
+
+    std::vector<int64_t> input{1, 2};
+    indexProp = input;
+    indexInfo = indexProp.getFilteredIndexInfo();
+    TS_ASSERT_EQUALS(indexInfo.size(), 2);
+    TS_ASSERT_EQUALS(indexInfo.spectrumNumber(0), 2);
+    TS_ASSERT_EQUALS(indexInfo.spectrumNumber(1), 3);
+  }
+
+  void testGetFilteredIndexInfo_SpectrumNum() {
+    auto ws = WorkspaceFactory::Instance().create("WorkspaceTester", 3, 1, 1);
+    m_wkspProp = ws;
+    IndexTypeProperty itypeProp("IndexType", IndexType::SpectrumNum);
+    IndexProperty indexProp("IndexSet", m_wkspProp, itypeProp);
+
+    auto indexInfo = indexProp.getFilteredIndexInfo();
+    TS_ASSERT_EQUALS(indexInfo.size(), 3);
+
+    std::vector<int64_t> input{1, 2};
+    indexProp = input;
+    indexInfo = indexProp.getFilteredIndexInfo();
+    TS_ASSERT_EQUALS(indexInfo.size(), 2);
+    TS_ASSERT_EQUALS(indexInfo.spectrumNumber(0), 1);
+    TS_ASSERT_EQUALS(indexInfo.spectrumNumber(1), 2);
+  }
+
 private:
   WorkspaceProperty<MatrixWorkspace> m_wkspProp;
   IndexTypeProperty m_itypeProp;
 };
 
-#endif /* MANTID_API_INDEXPROPERTYTEST_H_ */
\ No newline at end of file
+#endif /* MANTID_API_INDEXPROPERTYTEST_H_ */
diff --git a/Framework/API/test/MatrixWorkspaceTest.h b/Framework/API/test/MatrixWorkspaceTest.h
index 623f5f33f160d612cd8d135bd27ade5a269e969f..6403661dc8269ab77e97510b591b4ba6352a0db2 100644
--- a/Framework/API/test/MatrixWorkspaceTest.h
+++ b/Framework/API/test/MatrixWorkspaceTest.h
@@ -742,6 +742,16 @@ public:
     }
   }
 
+  void testSetMaskedBins() {
+    auto ws = makeWorkspaceWithDetectors(2, 2);
+    ws->flagMasked(0, 1);
+    ws->flagMasked(1, 0);
+    ws->setMaskedBins(1, ws->maskedBins(0));
+    TS_ASSERT(ws->hasMaskedBins(1));
+    TS_ASSERT_EQUALS(ws->maskedBins(1).size(), 1);
+    TS_ASSERT_EQUALS(ws->maskedBins(0).begin()->first, 1);
+  }
+
   void testSize() {
     WorkspaceTester wkspace;
     wkspace.initialize(1, 4, 3);
diff --git a/Framework/Algorithms/CMakeLists.txt b/Framework/Algorithms/CMakeLists.txt
index 8873708619f5de06029ec5444e40efe2a70dad30..9b4830fb17ce9799d1616ed06cf8eeb55f418b21 100644
--- a/Framework/Algorithms/CMakeLists.txt
+++ b/Framework/Algorithms/CMakeLists.txt
@@ -17,9 +17,9 @@ set ( SRC_FILES
 	src/ApplyTransmissionCorrection.cpp
 	src/AsymmetryCalc.cpp
 	src/AverageLogData.cpp
+	src/Bin2DPowderDiffraction.cpp
 	src/BinaryOperateMasks.cpp
-       src/BinaryOperation.cpp
-       src/Bin2DPowderDiffraction.cpp
+	src/BinaryOperation.cpp
 	src/CalMuonDeadTime.cpp
 	src/CalMuonDetectorPhases.cpp
 	src/CalculateCountRate.cpp
@@ -46,8 +46,8 @@ set ( SRC_FILES
 	src/Comment.cpp
 	src/CommutativeBinaryOperation.cpp
 	src/CompareWorkspaces.cpp
-	src/ConjoinXRuns.cpp
 	src/ConjoinWorkspaces.cpp
+	src/ConjoinXRuns.cpp
 	src/ConvertAxesToRealSpace.cpp
 	src/ConvertAxisByFormula.cpp
 	src/ConvertDiffCal.cpp
@@ -121,6 +121,7 @@ set ( SRC_FILES
 	src/ExtractMaskToTable.cpp
 	src/ExtractSingleSpectrum.cpp
 	src/ExtractSpectra.cpp
+	src/ExtractSpectra2.cpp
 	src/ExtractUnmaskedSpectra.cpp
 	src/FFT.cpp
 	src/FFTDerivative.cpp
@@ -159,6 +160,7 @@ set ( SRC_FILES
 	src/GroupWorkspaces.cpp
 	src/HRPDSlabCanAbsorption.cpp
 	src/He3TubeEfficiency.cpp
+	src/HyspecScharpfCorrection.cpp
 	src/IQTransform.cpp
 	src/IdentifyNoisyDetectors.cpp
 	src/IntegrateByComponent.cpp
@@ -197,11 +199,11 @@ set ( SRC_FILES
 	src/MultiplyRange.cpp
 	src/MuonAsymmetryHelper.cpp
 	src/MuonGroupDetectors.cpp
+	src/NRCalculateSlitResolution.cpp
 	src/NormaliseByCurrent.cpp
 	src/NormaliseByDetector.cpp
 	src/NormaliseToMonitor.cpp
 	src/NormaliseToUnity.cpp
-	src/NRCalculateSlitResolution.cpp
 	src/OneMinusExponentialCor.cpp
 	src/PDCalibration.cpp
 	src/PDDetermineCharacterizations.cpp
@@ -334,17 +336,17 @@ set ( INC_FILES
 	inc/MantidAlgorithms/AlphaCalc.h
 	inc/MantidAlgorithms/AnnularRingAbsorption.h
 	inc/MantidAlgorithms/AnyShapeAbsorption.h
+	inc/MantidAlgorithms/ApodizationFunctions.h
 	inc/MantidAlgorithms/AppendSpectra.h
-    inc/MantidAlgorithms/ApodizationFunctions.h
 	inc/MantidAlgorithms/ApplyCalibration.h
 	inc/MantidAlgorithms/ApplyDeadTimeCorr.h
 	inc/MantidAlgorithms/ApplyDetailedBalance.h
 	inc/MantidAlgorithms/ApplyTransmissionCorrection.h
 	inc/MantidAlgorithms/AsymmetryCalc.h
 	inc/MantidAlgorithms/AverageLogData.h
+	inc/MantidAlgorithms/Bin2DPowderDiffraction.h
 	inc/MantidAlgorithms/BinaryOperateMasks.h
 	inc/MantidAlgorithms/BinaryOperation.h
-       inc/MantidAlgorithms/Bin2DPowderDiffraction.h
 	inc/MantidAlgorithms/BoostOptionalToAlgorithmProperty.h
 	inc/MantidAlgorithms/CalMuonDeadTime.h
 	inc/MantidAlgorithms/CalMuonDetectorPhases.h
@@ -447,6 +449,7 @@ set ( INC_FILES
 	inc/MantidAlgorithms/ExtractMaskToTable.h
 	inc/MantidAlgorithms/ExtractSingleSpectrum.h
 	inc/MantidAlgorithms/ExtractSpectra.h
+	inc/MantidAlgorithms/ExtractSpectra2.h
 	inc/MantidAlgorithms/ExtractUnmaskedSpectra.h
 	inc/MantidAlgorithms/FFT.h
 	inc/MantidAlgorithms/FFTDerivative.h
@@ -486,6 +489,7 @@ set ( INC_FILES
 	inc/MantidAlgorithms/GroupWorkspaces.h
 	inc/MantidAlgorithms/HRPDSlabCanAbsorption.h
 	inc/MantidAlgorithms/He3TubeEfficiency.h
+	inc/MantidAlgorithms/HyspecScharpfCorrection.h
 	inc/MantidAlgorithms/IQTransform.h
 	inc/MantidAlgorithms/IdentifyNoisyDetectors.h
 	inc/MantidAlgorithms/IntegrateByComponent.h
@@ -527,16 +531,16 @@ set ( INC_FILES
 	inc/MantidAlgorithms/MultiplyRange.h
 	inc/MantidAlgorithms/MuonAsymmetryHelper.h
 	inc/MantidAlgorithms/MuonGroupDetectors.h
+	inc/MantidAlgorithms/NRCalculateSlitResolution.h
 	inc/MantidAlgorithms/NormaliseByCurrent.h
 	inc/MantidAlgorithms/NormaliseByDetector.h
 	inc/MantidAlgorithms/NormaliseToMonitor.h
 	inc/MantidAlgorithms/NormaliseToUnity.h
-	inc/MantidAlgorithms/NRCalculateSlitResolution.h
 	inc/MantidAlgorithms/OneMinusExponentialCor.h
-	inc/MantidAlgorithms/PaddingAndApodization.h
 	inc/MantidAlgorithms/PDCalibration.h
 	inc/MantidAlgorithms/PDDetermineCharacterizations.h
 	inc/MantidAlgorithms/PDFFourierTransform.h
+	inc/MantidAlgorithms/PaddingAndApodization.h
 	inc/MantidAlgorithms/Pause.h
 	inc/MantidAlgorithms/PerformIndexOperations.h
 	inc/MantidAlgorithms/PhaseQuadMuon.h
@@ -684,9 +688,9 @@ set ( TEST_FILES
 	ApplyTransmissionCorrectionTest.h
 	AsymmetryCalcTest.h
 	AverageLogDataTest.h
+	Bin2DPowderDiffractionTest.h
 	BinaryOperateMasksTest.h
 	BinaryOperationTest.h
-       Bin2DPowderDiffractionTest.h
 	CalMuonDeadTimeTest.h
 	CalMuonDetectorPhasesTest.h
 	CalculateCountRateTest.h
@@ -702,8 +706,8 @@ set ( TEST_FILES
 	ChainedOperatorTest.h
 	ChangeBinOffsetTest.h
 	ChangeLogTimeTest.h
-	ChangePulsetimeTest.h
 	ChangePulsetime2Test.h
+	ChangePulsetimeTest.h
 	ChangeTimeZeroTest.h
 	CheckWorkspacesMatchTest.h
 	ChopDataTest.h
@@ -785,6 +789,7 @@ set ( TEST_FILES
 	ExtractMaskTest.h
 	ExtractMaskToTableTest.h
 	ExtractSingleSpectrumTest.h
+	ExtractSpectra2Test.h
 	ExtractSpectraTest.h
 	ExtractUnmaskedSpectraTest.h
 	FFTDerivativeTest.h
@@ -822,6 +827,7 @@ set ( TEST_FILES
 	GroupWorkspacesTest.h
 	HRPDSlabCanAbsorptionTest.h
 	He3TubeEfficiencyTest.h
+	HyspecScharpfCorrectionTest.h
 	IQTransformTest.h
 	IdentifyNoisyDetectorsTest.h
 	IntegrateByComponentTest.h
@@ -860,15 +866,15 @@ set ( TEST_FILES
 	MultiplyRangeTest.h
 	MultiplyTest.h
 	MuonGroupDetectorsTest.h
+	NRCalculateSlitResolutionTest.h
 	NormaliseByCurrentTest.h
 	NormaliseByDetectorTest.h
 	NormaliseToMonitorTest.h
-	NRCalculateSlitResolutionTest.h
 	OneMinusExponentialCorTest.h
-	PaddingAndApodizationTest.h
 	PDCalibrationTest.h
 	PDDetermineCharacterizationsTest.h
 	PDFFourierTransformTest.h
+	PaddingAndApodizationTest.h
 	PauseTest.h
 	PerformIndexOperationsTest.h
 	PhaseQuadMuonTest.h
@@ -933,8 +939,8 @@ set ( TEST_FILES
 	SortEventsTest.h
 	SparseInstrumentTest.h
 	SpatialGroupingTest.h
-	SpecularReflectionCalculateThetaTest.h
 	SpecularReflectionCalculateTheta2Test.h
+	SpecularReflectionCalculateThetaTest.h
 	SpecularReflectionPositionCorrect2Test.h
 	SpecularReflectionPositionCorrectTest.h
 	SphericalAbsorptionTest.h
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/CropWorkspace.h b/Framework/Algorithms/inc/MantidAlgorithms/CropWorkspace.h
index 2861c43ce0dc5426f509ada66e38d8146565c956..23d072c16163a538d982aa05a3af705079b157c9 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/CropWorkspace.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/CropWorkspace.h
@@ -1,10 +1,7 @@
 #ifndef MANTID_ALGORITHMS_CROPWORKSPACE_H_
 #define MANTID_ALGORITHMS_CROPWORKSPACE_H_
 
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
-#include "MantidAPI/Algorithm.h"
+#include "MantidAPI/ParallelAlgorithm.h"
 
 namespace Mantid {
 namespace Algorithms {
@@ -66,7 +63,7 @@ namespace Algorithms {
     File change history is stored at: <https://github.com/mantidproject/mantid>
     Code Documentation is available at: <http://doxygen.mantidproject.org>
 */
-class DLLExport CropWorkspace : public API::Algorithm {
+class DLLExport CropWorkspace : public API::ParallelAlgorithm {
 public:
   /// Algorithm's name
   const std::string name() const override { return "CropWorkspace"; }
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/ExtractSpectra.h b/Framework/Algorithms/inc/MantidAlgorithms/ExtractSpectra.h
index eda7d0939fa56808b607aca9dd59aba0359a3232..6f94a82a1991816d6f14723a4f381016d9e35a18 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/ExtractSpectra.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/ExtractSpectra.h
@@ -2,7 +2,7 @@
 #define MANTID_ALGORITHMS_EXTRACTSPECTRA_H_
 
 #include "MantidKernel/System.h"
-#include "MantidAPI/Algorithm.h"
+#include "MantidAPI/ParallelAlgorithm.h"
 #include "MantidDataObjects/EventWorkspace.h"
 
 namespace Mantid {
@@ -33,7 +33,7 @@ namespace Algorithms {
   File change history is stored at: <https://github.com/mantidproject/mantid>
   Code Documentation is available at: <http://doxygen.mantidproject.org>
 */
-class DLLExport ExtractSpectra : public API::Algorithm {
+class DLLExport ExtractSpectra : public API::ParallelAlgorithm {
 public:
   const std::string name() const override;
   int version() const override;
@@ -46,11 +46,11 @@ private:
   void execHistogram();
   void execEvent();
 
+  void propagateBinMasking(API::MatrixWorkspace &workspace, const int i) const;
   void checkProperties();
   std::size_t getXMin(const size_t wsIndex = 0);
   std::size_t getXMax(const size_t wsIndex = 0);
-  void cropRagged(API::MatrixWorkspace_sptr outputWorkspace, int inIndex,
-                  int outIndex);
+  void cropRagged(API::MatrixWorkspace &workspace, int index);
 
   /// The input workspace
   API::MatrixWorkspace_sptr m_inputWorkspace;
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/ExtractSpectra2.h b/Framework/Algorithms/inc/MantidAlgorithms/ExtractSpectra2.h
new file mode 100644
index 0000000000000000000000000000000000000000..208febc4d661da8d4b63a2c2e9192fe26b4915dd
--- /dev/null
+++ b/Framework/Algorithms/inc/MantidAlgorithms/ExtractSpectra2.h
@@ -0,0 +1,55 @@
+#ifndef MANTID_ALGORITHMS_EXTRACTSPECTRA2_H_
+#define MANTID_ALGORITHMS_EXTRACTSPECTRA2_H_
+
+#include "MantidAlgorithms/DllConfig.h"
+#include "MantidAPI/ParallelAlgorithm.h"
+
+namespace Mantid {
+namespace Algorithms {
+
+/** Extracts specified spectra from a workspace and places them in a new
+  workspace. In contrast to ExtractSpectra version 1 this does not support
+  cropping X at the same time.
+
+  @author Simon Heybrock
+  @date 2017
+
+  Copyright &copy; 2017 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge
+  National Laboratory & European Spallation Source
+
+  This file is part of Mantid.
+
+  Mantid is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 3 of the License, or
+  (at your option) any later version.
+
+  Mantid is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+  File change history is stored at: <https://github.com/mantidproject/mantid>
+  Code Documentation is available at: <http://doxygen.mantidproject.org>
+*/
+class MANTID_ALGORITHMS_DLL ExtractSpectra2 : public API::ParallelAlgorithm {
+public:
+  const std::string name() const override;
+  int version() const override;
+  const std::string category() const override;
+  const std::string summary() const override;
+
+private:
+  void init() override;
+  void exec() override;
+  template <class T>
+  void exec(const T &inputWS, const Indexing::SpectrumIndexSet &indexSet);
+};
+
+} // namespace Algorithms
+} // namespace Mantid
+
+#endif /* MANTID_ALGORITHMS_EXTRACTSPECTRA2_H_ */
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/HyspecScharpfCorrection.h b/Framework/Algorithms/inc/MantidAlgorithms/HyspecScharpfCorrection.h
new file mode 100644
index 0000000000000000000000000000000000000000..2d465d3843e0035f318427b3dc97084189f6e0e3
--- /dev/null
+++ b/Framework/Algorithms/inc/MantidAlgorithms/HyspecScharpfCorrection.h
@@ -0,0 +1,76 @@
+#ifndef MANTID_ALGORITHMS_HYSPECSCHARPFCORRECTION_H_
+#define MANTID_ALGORITHMS_HYSPECSCHARPFCORRECTION_H_
+
+#include "MantidAlgorithms/DllConfig.h"
+#include "MantidAPI/Algorithm.h"
+
+namespace Mantid {
+namespace Algorithms {
+
+/** HyspecScharpfCorrection : Divide by cos(2alpha) where alpha is the angle
+  between incident beam and the polarization direction. It assumes scattering
+  in the horizontal plane
+
+  Copyright &copy; 2017 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge
+  National Laboratory & European Spallation Source
+
+  This file is part of Mantid.
+
+  Mantid is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 3 of the License, or
+  (at your option) any later version.
+
+  Mantid is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+  File change history is stored at: <https://github.com/mantidproject/mantid>
+  Code Documentation is available at: <http://doxygen.mantidproject.org>
+*/
+class MANTID_ALGORITHMS_DLL HyspecScharpfCorrection : 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:
+  void init() override;
+  void exec() override;
+  void execEvent();
+  /**
+   * Execute Scharpf correction for event lists
+   * @param wevector the list of events to correct
+   * @param thPlane the in-plane angle for the detector corresponding to the
+   * event list
+   */
+  template <class T>
+  void ScharpfEventHelper(std::vector<T> &wevector, double thPlane);
+  /**
+   * @brief calculate the Scharph angle correction factor
+   * @param kfki kf/ki
+   * @param thPlane the in-plane angle of the detector
+   * @return factor
+   */
+  float calculateFactor(const double kfki, const double thPlane);
+  /// The user selected (input) workspace
+  Mantid::API::MatrixWorkspace_const_sptr m_inputWS;
+  /// The output workspace, maybe the same as the input one
+  Mantid::API::MatrixWorkspace_sptr m_outputWS;
+  /// In plane angle beween polarization and incident beam (in degrees)
+  double m_angle;
+  /// Lower limit  for abs(cos(2*Scharpf angle)), below which intensities are 0
+  double m_precision;
+  /// Incident energy
+  double m_Ei;
+};
+
+} // namespace Algorithms
+} // namespace Mantid
+
+#endif /* MANTID_ALGORITHMS_HYSPECSCHARPFCORRECTION_H_ */
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/MaskBins.h b/Framework/Algorithms/inc/MantidAlgorithms/MaskBins.h
index 340ae9eb9341fac432631961f0ca59cd9ee3f5f6..708ee013796682e9d1118e0eda412eb80a109189 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/MaskBins.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/MaskBins.h
@@ -4,6 +4,7 @@
 #include "MantidAPI/ParallelAlgorithm.h"
 #include "MantidDataObjects/EventList.h"
 #include "MantidDataObjects/EventWorkspace.h"
+#include "MantidIndexing/SpectrumIndexSet.h"
 
 namespace Mantid {
 
diff --git a/Framework/Algorithms/src/CalculatePolynomialBackground.cpp b/Framework/Algorithms/src/CalculatePolynomialBackground.cpp
index 472ef3c87cdd7312a1e81eb92319bda955733f17..5d4691b252d205a6d0ca8dd1cfbd4447e04501b1 100644
--- a/Framework/Algorithms/src/CalculatePolynomialBackground.cpp
+++ b/Framework/Algorithms/src/CalculatePolynomialBackground.cpp
@@ -9,18 +9,26 @@
 #include "MantidKernel/ArrayOrderedPairsValidator.h"
 #include "MantidKernel/ArrayProperty.h"
 #include "MantidKernel/BoundedValidator.h"
+#include "MantidKernel/ListValidator.h"
 
 #include <utility>
 
 namespace {
 /// String constants for algorithm's properties.
 namespace Prop {
+const static std::string COST_FUNCTION = "CostFunction";
 const static std::string INPUT_WS = "InputWorkspace";
 const static std::string OUTPUT_WS = "OutputWorkspace";
 const static std::string POLY_DEGREE = "Degree";
 const static std::string XRANGES = "XRanges";
 }
 
+/// String constants for cost function options.
+namespace CostFunc {
+const static std::string UNWEIGHTED_LEAST_SQUARES = "Unweighted least squares";
+const static std::string WEIGHTED_LEAST_SQUARES = "Least squares";
+}
+
 /** Filters ranges completely outside the histogram X values.
  *  @param ranges a vector of start-end pairs to filter
  *  @param ws a workspace
@@ -155,11 +163,10 @@ std::vector<double> invertRanges(const std::vector<double> &ranges) {
  *  @param ranges a vector defining the fitting intervals
  *  @return a vector of final fitted parameters
  */
-std::vector<double> executeFit(Mantid::API::Algorithm &fit,
-                               const std::string &function,
-                               Mantid::API::MatrixWorkspace_sptr &ws,
-                               const size_t wsIndex,
-                               const std::vector<double> &ranges) {
+std::vector<double>
+executeFit(Mantid::API::Algorithm &fit, const std::string &function,
+           Mantid::API::MatrixWorkspace_sptr &ws, const size_t wsIndex,
+           const std::vector<double> &ranges, const std::string &costFunction) {
   const auto fitRanges = histogramRanges(ranges, *ws, wsIndex);
   const auto excludedRanges = invertRanges(fitRanges);
   fit.setProperty("Function", function);
@@ -168,6 +175,8 @@ std::vector<double> executeFit(Mantid::API::Algorithm &fit,
   fit.setProperty("StartX", fitRanges.front());
   fit.setProperty("EndX", fitRanges.back());
   fit.setProperty("Exclude", excludedRanges);
+  fit.setProperty("Minimizer", "Levenberg-MarquardtMD");
+  fit.setProperty(Prop::COST_FUNCTION, costFunction);
   fit.setProperty("CreateOutput", true);
   fit.executeAsChildAlg();
   Mantid::API::ITableWorkspace_sptr fitResult =
@@ -268,6 +277,12 @@ void CalculatePolynomialBackground::init() {
   declareProperty(Kernel::make_unique<Kernel::ArrayProperty<double>>(
                       Prop::XRANGES, std::vector<double>(), orderedPairs),
                   "A list of fitting ranges given as pairs of X values.");
+  std::array<std::string, 2> costFuncOpts{
+      {CostFunc::WEIGHTED_LEAST_SQUARES, CostFunc::UNWEIGHTED_LEAST_SQUARES}};
+  declareProperty(
+      Prop::COST_FUNCTION, CostFunc::WEIGHTED_LEAST_SQUARES.c_str(),
+      boost::make_shared<Kernel::ListValidator<std::string>>(costFuncOpts),
+      "The cost function to be passed to the Fit algorithm.");
 }
 
 //----------------------------------------------------------------------------------------------
@@ -279,6 +294,7 @@ void CalculatePolynomialBackground::exec() {
   API::MatrixWorkspace_sptr outWS{
       DataObjects::create<DataObjects::Workspace2D>(*inWS)};
   const std::vector<double> inputRanges = getProperty(Prop::XRANGES);
+  const std::string costFunction = getProperty(Prop::COST_FUNCTION);
   const auto polyDegree =
       static_cast<size_t>(static_cast<int>(getProperty(Prop::POLY_DEGREE)));
   const std::vector<double> initialParams(polyDegree + 1, 0.1);
@@ -290,7 +306,8 @@ void CalculatePolynomialBackground::exec() {
     PARALLEL_START_INTERUPT_REGION
     const bool logging{false};
     auto fit = createChildAlgorithm("Fit", 0, 0, logging);
-    const auto parameters = executeFit(*fit, fitFunction, inWS, i, inputRanges);
+    const auto parameters =
+        executeFit(*fit, fitFunction, inWS, i, inputRanges, costFunction);
     const auto bkgFunction = makeFunctionString(parameters);
     evaluateInPlace(bkgFunction, *outWS, i);
     progress.report();
diff --git a/Framework/Algorithms/src/CropWorkspace.cpp b/Framework/Algorithms/src/CropWorkspace.cpp
index 620e15a10e607bb53e95a3b0c8049dcb7c3e5752..eee69eaab8cbac3372dcf8a8e30e9aa90be21897 100644
--- a/Framework/Algorithms/src/CropWorkspace.cpp
+++ b/Framework/Algorithms/src/CropWorkspace.cpp
@@ -1,6 +1,3 @@
-//----------------------------------------------------------------------
-// Includes
-//----------------------------------------------------------------------
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAlgorithms/CropWorkspace.h"
 #include "MantidKernel/BoundedValidator.h"
diff --git a/Framework/Algorithms/src/ExtractSpectra.cpp b/Framework/Algorithms/src/ExtractSpectra.cpp
index 216e46bc3a6aee87acee4e45b7d6fe29d9b7df27..3c2609c073c0f562dde9645f0d63b19dfda79072 100644
--- a/Framework/Algorithms/src/ExtractSpectra.cpp
+++ b/Framework/Algorithms/src/ExtractSpectra.cpp
@@ -1,14 +1,16 @@
 #include "MantidAlgorithms/ExtractSpectra.h"
+#include "MantidAlgorithms/ExtractSpectra2.h"
 
 #include "MantidDataObjects/WorkspaceCreation.h"
+#include "MantidAPI/Algorithm.tcc"
 #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 "MantidHistogramData/Slice.h"
 
 #include <algorithm>
 
@@ -23,13 +25,12 @@ namespace Algorithms {
 using namespace Kernel;
 using namespace API;
 using namespace DataObjects;
+using namespace HistogramData;
 using Types::Event::TofEvent;
 
 // Register the algorithm into the AlgorithmFactory
 DECLARE_ALGORITHM(ExtractSpectra)
 
-//----------------------------------------------------------------------------------------------
-
 /// Algorithms name for identification. @see Algorithm::name
 const std::string ExtractSpectra::name() const { return "ExtractSpectra"; }
 
@@ -47,7 +48,6 @@ const std::string ExtractSpectra::summary() const {
          "workspace.";
 }
 
-//----------------------------------------------------------------------------------------------
 /** Initialize the algorithm's properties.
  */
 void ExtractSpectra::init() {
@@ -91,127 +91,50 @@ void ExtractSpectra::init() {
                   "the latter is being selected.");
 }
 
-//----------------------------------------------------------------------------------------------
 /** Executes the algorithm
  *  @throw std::out_of_range If a property is set to an invalid value for the
  * input workspace
  */
 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);
+  this->checkProperties();
+
+  auto extract = boost::make_shared<ExtractSpectra2>();
+  setupAsChildAlgorithm(extract);
+  extract->setWorkspaceInputProperties(
+      "InputWorkspace", m_inputWorkspace, IndexType::WorkspaceIndex,
+      std::vector<int64_t>(m_workspaceIndexList.begin(),
+                           m_workspaceIndexList.end()));
+  extract->execute();
+  m_inputWorkspace = extract->getProperty("OutputWorkspace");
+  setProperty("OutputWorkspace", m_inputWorkspace);
+
+  if (isDefault("XMin") && isDefault("XMax"))
+    return;
 
   eventW = boost::dynamic_pointer_cast<EventWorkspace>(m_inputWorkspace);
-  if (eventW != nullptr) {
-    // Input workspace is an event workspace. Use the other exec method
+  if (eventW)
     this->execEvent();
-  } else {
-    // Otherwise it's a Workspace2D
+  else
     this->execHistogram();
-  }
 }
 
 /// Execute the algorithm in case of a histogrammed data.
 void ExtractSpectra::execHistogram() {
-  // Retrieve and validate the input properties
-  this->checkProperties();
-
-  // Create the output workspace
-  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
-  Axis *inAxis1(nullptr);
-  TextAxis *outTxtAxis(nullptr);
-  NumericAxis *outNumAxis(nullptr);
-  if (m_inputWorkspace->axes() > 1) {
-    inAxis1 = m_inputWorkspace->getAxis(1);
-    auto outAxis1 = outputWorkspace->getAxis(1);
-    outTxtAxis = dynamic_cast<TextAxis *>(outAxis1);
-    if (!outTxtAxis)
-      outNumAxis = dynamic_cast<NumericAxis *>(outAxis1);
-  }
-
-  cow_ptr<HistogramData::HistogramX> newX(nullptr);
-  if (m_commonBoundaries) {
-    auto &oldX = m_inputWorkspace->x(m_workspaceIndexList.front());
-    newX = make_cow<HistogramData::HistogramX>(oldX.begin() + m_minX,
-                                               oldX.begin() + m_maxX);
-  }
-
-  bool doCrop = ((m_minX != 0) || (m_maxX != m_inputWorkspace->x(0).size()));
-
-  Progress prog(this, 0.0, 1.0, (m_workspaceIndexList.size()));
-  // Loop over the required workspace indices, copying in the desired bins
-  for (int j = 0; j < static_cast<int>(m_workspaceIndexList.size()); ++j) {
-    auto i = m_workspaceIndexList[j];
-
-    bool hasDx = m_inputWorkspace->hasDx(i);
-
-    // Preserve/restore sharing if X vectors are the same
+  int size = static_cast<int>(m_inputWorkspace->getNumberHistograms());
+  Progress prog(this, 0.0, 1.0, size);
+  for (int i = 0; i < size; ++i) {
     if (m_commonBoundaries) {
-      outputWorkspace->setSharedX(j, newX);
-      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)));
-      }
-    } else {
-      // Safe to just copy whole vector 'cos can't be cropping in X if not
-      // common
-      outputWorkspace->setSharedX(j, m_inputWorkspace->sharedX(i));
-      outputWorkspace->setSharedDx(j, m_inputWorkspace->sharedDx(i));
-    }
-
-    if (doCrop) {
-      auto &oldY = m_inputWorkspace->y(i);
-      outputWorkspace->mutableY(j)
-          .assign(oldY.begin() + m_minX, oldY.begin() + (m_maxX - m_histogram));
-      auto &oldE = m_inputWorkspace->e(i);
-      outputWorkspace->mutableE(j)
-          .assign(oldE.begin() + m_minX, oldE.begin() + (m_maxX - m_histogram));
+      m_inputWorkspace->setHistogram(i, slice(m_inputWorkspace->histogram(i),
+                                              m_minX, m_maxX - m_histogram));
     } else {
-      outputWorkspace->setSharedY(j, m_inputWorkspace->sharedY(i));
-      outputWorkspace->setSharedE(j, m_inputWorkspace->sharedE(i));
-    }
-
-    // copy over the axis entry for each spectrum, regardless of the type of
-    // axes present
-    if (inAxis1) {
-      if (outTxtAxis) {
-        outTxtAxis->setLabel(j, inAxis1->label(i));
-      } else if (outNumAxis) {
-        outNumAxis->setValue(j, inAxis1->operator()(i));
-      }
-      // spectra axis is implicit in workspace creation
-    }
-
-    if (!m_commonBoundaries)
-      this->cropRagged(outputWorkspace, static_cast<int>(i), j);
-
-    // Propagate bin masking if there is any
-    if (m_inputWorkspace->hasMaskedBins(i)) {
-      const MatrixWorkspace::MaskList &inputMasks =
-          m_inputWorkspace->maskedBins(i);
-      MatrixWorkspace::MaskList::const_iterator it;
-      for (it = inputMasks.begin(); it != inputMasks.end(); ++it) {
-        const size_t maskIndex = (*it).first;
-        if (maskIndex >= m_minX && maskIndex < m_maxX - m_histogram)
-          outputWorkspace->flagMasked(j, maskIndex - m_minX, (*it).second);
-      }
+      this->cropRagged(*m_inputWorkspace, i);
     }
+    propagateBinMasking(*m_inputWorkspace, i);
     prog.report();
   }
-
-  setProperty("OutputWorkspace", outputWorkspace);
 }
 
 namespace { // anonymous namespace
@@ -222,7 +145,7 @@ template <class T> struct eventFilter {
 
   bool operator()(const T &value) {
     const double tof = value.tof();
-    return (tof <= maxValue && tof >= minValue);
+    return !(tof <= maxValue && tof >= minValue);
   }
 
   double minValue;
@@ -230,11 +153,11 @@ template <class T> struct eventFilter {
 };
 
 template <class T>
-void copyEventsHelper(const std::vector<T> &inputEvents,
-                      std::vector<T> &outputEvents, const double xmin,
-                      const double xmax) {
-  copy_if(inputEvents.begin(), inputEvents.end(),
-          std::back_inserter(outputEvents), eventFilter<T>(xmin, xmax));
+void filterEventsHelper(std::vector<T> &events, const double xmin,
+                        const double xmax) {
+  events.erase(
+      std::remove_if(events.begin(), events.end(), eventFilter<T>(xmin, xmax)),
+      events.end());
 }
 }
 
@@ -250,110 +173,68 @@ void ExtractSpectra::execEvent() {
   if (isEmpty(maxX_val))
     maxX_val = eventW->getTofMax();
 
-  // Retrieve and validate the input properties
-  this->checkProperties();
-  HistogramData::BinEdges XValues_new(2);
+  BinEdges binEdges(2);
   if (m_commonBoundaries) {
-    auto &oldX = m_inputWorkspace->x(m_workspaceIndexList.front());
-    XValues_new =
-        HistogramData::BinEdges(oldX.begin() + m_minX, oldX.begin() + m_maxX);
+    auto &oldX = m_inputWorkspace->x(0);
+    binEdges = BinEdges(oldX.begin() + m_minX, oldX.begin() + m_maxX);
   }
-
   if (m_maxX - m_minX < 2) {
     // create new output X axis
-    std::vector<double> rb_params{minX_val, maxX_val - minX_val, maxX_val};
-    static_cast<void>(VectorHelper::createAxisFromRebinParams(
-        rb_params, XValues_new.mutableRawData()));
+    binEdges = {minX_val, maxX_val};
   }
 
-  // run inplace branch if appropriate
-  MatrixWorkspace_sptr OutputWorkspace = this->getProperty("OutputWorkspace");
-  bool inPlace = (OutputWorkspace == m_inputWorkspace);
-  if (inPlace)
-    g_log.debug("Cropping EventWorkspace in-place.");
-
-  // Create the output workspace
   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);
-
-  Progress prog(this, 0.0, 1.0, 2 * m_workspaceIndexList.size());
-  eventW->sortAll(Mantid::DataObjects::TOF_SORT, &prog);
-  // Loop over the required workspace indices, copying in the desired bins
-  PARALLEL_FOR_IF(Kernel::threadSafe(*m_inputWorkspace, *outputWorkspace))
-  for (int j = 0; j < static_cast<int>(m_workspaceIndexList.size()); ++j) {
+
+  Progress prog(this, 0.0, 1.0, eventW->getNumberHistograms());
+  PARALLEL_FOR_IF(Kernel::threadSafe(*eventW))
+  for (int i = 0; i < static_cast<int>(eventW->getNumberHistograms()); ++i) {
     PARALLEL_START_INTERUPT_REGION
-    auto i = m_workspaceIndexList[j];
-    const EventList &el = eventW->getSpectrum(i);
-    // The output event list
-    EventList &outEL = outputWorkspace->getSpectrum(j);
+    EventList &el = eventW->getSpectrum(i);
 
     switch (el.getEventType()) {
     case TOF: {
-      std::vector<TofEvent> moreevents;
-      moreevents.reserve(el.getNumberEvents()); // assume all will make it
-      copyEventsHelper(el.getEvents(), moreevents, minX_val, maxX_val);
-      outEL += moreevents;
+      filterEventsHelper(el.getEvents(), minX_val, maxX_val);
       break;
     }
     case WEIGHTED: {
-      std::vector<WeightedEvent> moreevents;
-      moreevents.reserve(el.getNumberEvents()); // assume all will make it
-      copyEventsHelper(el.getWeightedEvents(), moreevents, minX_val, maxX_val);
-      outEL += moreevents;
+      filterEventsHelper(el.getWeightedEvents(), minX_val, maxX_val);
       break;
     }
     case WEIGHTED_NOTIME: {
-      std::vector<WeightedEventNoTime> moreevents;
-      moreevents.reserve(el.getNumberEvents()); // assume all will make it
-      copyEventsHelper(el.getWeightedEventsNoTime(), moreevents, minX_val,
-                       maxX_val);
-      outEL += moreevents;
+      filterEventsHelper(el.getWeightedEventsNoTime(), minX_val, maxX_val);
       break;
     }
     }
-    outEL.setSortOrder(el.getSortType());
-
-    bool hasDx = eventW->hasDx(i);
 
-    if (!m_commonBoundaries) {
-      // If the X axis is NOT common, then keep the initial X axis, just clear
-      // the events
-      outEL.setX(el.ptrX());
-      outEL.setSharedDx(el.sharedDx());
-    } else {
-      // 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));
-      }
-    }
-
-    // Propagate bin masking if there is any
-    if (m_inputWorkspace->hasMaskedBins(i)) {
-      const MatrixWorkspace::MaskList &inputMasks =
-          m_inputWorkspace->maskedBins(i);
-      MatrixWorkspace::MaskList::const_iterator it;
-      for (it = inputMasks.begin(); it != inputMasks.end(); ++it) {
-        const size_t maskIndex = (*it).first;
-        if (maskIndex >= m_minX && maskIndex < m_maxX - m_histogram)
-          outputWorkspace->flagMasked(j, maskIndex - m_minX, (*it).second);
+    // If the X axis is NOT common, then keep the initial X axis, just clear the
+    // events, otherwise:
+    if (m_commonBoundaries) {
+      const auto oldDx = el.pointStandardDeviations();
+      el.setHistogram(binEdges);
+      if (oldDx) {
+        el.setPointStandardDeviations(oldDx.begin() + m_minX,
+                                      oldDx.begin() + (m_maxX - m_histogram));
       }
     }
-    // When cropping in place, you can clear out old memory from the input one!
-    if (inPlace) {
-      eventW->getSpectrum(i).clear();
-    }
+    propagateBinMasking(*eventW, i);
     prog.report();
     PARALLEL_END_INTERUPT_REGION
   }
   PARALLEL_CHECK_INTERUPT_REGION
+}
 
-  setProperty("OutputWorkspace", std::move(outputWorkspace));
+/// Propagate bin masking if there is any.
+void ExtractSpectra::propagateBinMasking(MatrixWorkspace &workspace,
+                                         const int i) const {
+  if (workspace.hasMaskedBins(i)) {
+    MatrixWorkspace::MaskList filteredMask;
+    for (const auto &mask : workspace.maskedBins(i)) {
+      const size_t maskIndex = mask.first;
+      if (maskIndex >= m_minX && maskIndex < m_maxX - m_histogram)
+        filteredMask[maskIndex - m_minX] = mask.second;
+    }
+    workspace.setMaskedBins(i, filteredMask);
+  }
 }
 
 /** Retrieves the optional input properties and checks that they have valid
@@ -365,6 +246,29 @@ void ExtractSpectra::execEvent() {
  * input workspace
  */
 void ExtractSpectra::checkProperties() {
+  m_minX = this->getXMin();
+  m_maxX = this->getXMax();
+  const size_t xSize = m_inputWorkspace->x(0).size();
+  if (m_minX > 0 || m_maxX < xSize) {
+    if (m_minX > m_maxX) {
+      g_log.error("XMin must be less than XMax");
+      throw std::out_of_range("XMin must be less than XMax");
+    }
+    if ((m_minX == m_maxX ||
+         (m_inputWorkspace->isHistogramData() && m_maxX == m_minX + 1)) &&
+        m_commonBoundaries &&
+        !boost::dynamic_pointer_cast<EventWorkspace>(m_inputWorkspace)) {
+      g_log.error("The X range given lies entirely within a single bin");
+      throw std::out_of_range(
+          "The X range given lies entirely within a single bin");
+    }
+    m_croppingInX = true;
+  }
+  if (!m_commonBoundaries)
+    m_minX = 0;
+  if (!m_commonBoundaries)
+    m_maxX = static_cast<int>(m_inputWorkspace->x(0).size());
+
   // The hierarchy of inputs is (one is being selected):
   // 1. DetectorList
   // 2. WorkspaceIndexList
@@ -379,21 +283,11 @@ void ExtractSpectra::checkProperties() {
     if (m_workspaceIndexList.empty()) {
       int minSpec_i = getProperty("StartWorkspaceIndex");
       size_t minSpec = static_cast<size_t>(minSpec_i);
-      const size_t numberOfSpectra = m_inputWorkspace->getNumberHistograms();
+      const size_t numberOfSpectra = m_inputWorkspace->indexInfo().globalSize();
       int maxSpec_i = getProperty("EndWorkspaceIndex");
       size_t maxSpec = static_cast<size_t>(maxSpec_i);
       if (isEmpty(maxSpec_i))
         maxSpec = numberOfSpectra - 1;
-
-      // Check 'StartSpectrum' is in range 0-numberOfSpectra
-      if (minSpec > numberOfSpectra - 1) {
-        g_log.error("StartWorkspaceIndex out of range!");
-        throw std::out_of_range("StartSpectrum out of range!");
-      }
-      if (maxSpec > numberOfSpectra - 1) {
-        g_log.error("EndWorkspaceIndex out of range!");
-        throw std::out_of_range("EndWorkspaceIndex out of range!");
-      }
       if (maxSpec < minSpec) {
         g_log.error("StartWorkspaceIndex must be less than or equal to "
                     "EndWorkspaceIndex");
@@ -402,38 +296,10 @@ void ExtractSpectra::checkProperties() {
             "to EndWorkspaceIndex");
       }
       m_workspaceIndexList.reserve(maxSpec - minSpec + 1);
-      for (size_t i = static_cast<size_t>(minSpec);
-           i <= static_cast<size_t>(maxSpec); ++i) {
+      for (size_t i = minSpec; i <= maxSpec; ++i)
         m_workspaceIndexList.push_back(i);
-      }
     }
   }
-
-  // get the x-range from the used spectra
-  size_t spectrumIndex = 0; // default is just look at the initial spectrum
-  if (!m_workspaceIndexList.empty())
-    spectrumIndex =
-        m_workspaceIndexList.front(); // or the first one being extracted
-
-  m_minX = this->getXMin(spectrumIndex);
-  m_maxX = this->getXMax(spectrumIndex);
-  const size_t xSize = m_inputWorkspace->x(spectrumIndex).size();
-  if (m_minX > 0 || m_maxX < xSize) {
-    if (m_minX > m_maxX) {
-      g_log.error("XMin must be less than XMax");
-      throw std::out_of_range("XMin must be less than XMax");
-    }
-    if (m_minX == m_maxX && m_commonBoundaries && eventW == nullptr) {
-      g_log.error("The X range given lies entirely within a single bin");
-      throw std::out_of_range(
-          "The X range given lies entirely within a single bin");
-    }
-    m_croppingInX = true;
-  }
-  if (!m_commonBoundaries)
-    m_minX = 0;
-  if (!m_commonBoundaries)
-    m_maxX = static_cast<int>(m_inputWorkspace->x(spectrumIndex).size());
 }
 
 /** Find the X index corresponding to (or just within) the value given in the
@@ -491,26 +357,21 @@ size_t ExtractSpectra::getXMax(const size_t wsIndex) {
 }
 
 /** Zeroes all data points outside the X values given
- *  @param outputWorkspace :: The output workspace - data has already been
- * copied
- *  @param inIndex ::         The workspace index of the spectrum in the input
- * workspace
- *  @param outIndex ::        The workspace index of the spectrum in the output
- * workspace
+ *  @param workspace :: The output workspace to crop
+ *  @param index ::         The workspace index of the spectrum
  */
-void ExtractSpectra::cropRagged(API::MatrixWorkspace_sptr outputWorkspace,
-                                int inIndex, int outIndex) {
-  auto &Y = outputWorkspace->mutableY(outIndex);
-  auto &E = outputWorkspace->mutableE(outIndex);
+void ExtractSpectra::cropRagged(MatrixWorkspace &workspace, int index) {
+  auto &Y = workspace.mutableY(index);
+  auto &E = workspace.mutableE(index);
   const size_t size = Y.size();
-  size_t startX = this->getXMin(inIndex);
+  size_t startX = this->getXMin(index);
   if (startX > size)
     startX = size;
   for (size_t i = 0; i < startX; ++i) {
     Y[i] = 0.0;
     E[i] = 0.0;
   }
-  size_t endX = this->getXMax(inIndex);
+  size_t endX = this->getXMax(index);
   if (endX > 0)
     endX -= m_histogram;
   for (size_t i = endX; i < size; ++i) {
diff --git a/Framework/Algorithms/src/ExtractSpectra2.cpp b/Framework/Algorithms/src/ExtractSpectra2.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f4df15fb16db83e6a36f66386778ed11b6feb629
--- /dev/null
+++ b/Framework/Algorithms/src/ExtractSpectra2.cpp
@@ -0,0 +1,96 @@
+#include "MantidAlgorithms/ExtractSpectra2.h"
+#include "MantidDataObjects/EventWorkspace.h"
+#include "MantidDataObjects/Workspace2D.h"
+#include "MantidDataObjects/WorkspaceCreation.h"
+#include "MantidAPI/Algorithm.tcc"
+#include "MantidAPI/NumericAxis.h"
+#include "MantidAPI/TextAxis.h"
+#include "MantidIndexing/IndexInfo.h"
+#include "MantidKernel/make_unique.h"
+
+namespace Mantid {
+using namespace API;
+using namespace DataObjects;
+using namespace Kernel;
+namespace Algorithms {
+
+// Currently we DO NOT REGISTER the algorithm into the AlgorithmFactory. The API
+// is different from version 1 and thus cannot replace it without breaking
+// scripts. It can be used internally directly without being registered.
+
+/// Algorithms name for identification. @see Algorithm::name
+const std::string ExtractSpectra2::name() const { return "ExtractSpectra2"; }
+
+/// Algorithm's version for identification. @see Algorithm::version
+int ExtractSpectra2::version() const { return 2; }
+
+/// Algorithm's category for identification. @see Algorithm::category
+const std::string ExtractSpectra2::category() const {
+  return "Transforms\\Splitting";
+}
+
+/// Algorithm's summary for use in the GUI and help. @see Algorithm::summary
+const std::string ExtractSpectra2::summary() const {
+  return "Extracts a list of spectra from a workspace and places them in a new "
+         "workspace.";
+}
+
+/// Initialize the algorithm's properties.
+void ExtractSpectra2::init() {
+  declareWorkspaceInputProperties<
+      MatrixWorkspace, IndexType::SpectrumNum | IndexType::WorkspaceIndex>(
+      "InputWorkspace", "The input workspace");
+  declareProperty(Kernel::make_unique<WorkspaceProperty<>>(
+                      "OutputWorkspace", "", Direction::Output),
+                  "Name of the output workspace");
+}
+
+/// Executes the algorithm
+void ExtractSpectra2::exec() {
+  boost::shared_ptr<MatrixWorkspace> inputWS;
+  Indexing::SpectrumIndexSet indexSet;
+  std::tie(inputWS, indexSet) =
+      getWorkspaceAndIndices<MatrixWorkspace>("InputWorkspace");
+
+  auto outputWS = create<MatrixWorkspace>(
+      *inputWS, dynamic_cast<IndexProperty *>(
+                    getPointerToProperty("InputWorkspaceIndexSet"))
+                    ->getFilteredIndexInfo(),
+      HistogramData::BinEdges(2));
+
+  Axis *inAxis1(nullptr);
+  TextAxis *outTxtAxis(nullptr);
+  NumericAxis *outNumAxis(nullptr);
+  if (inputWS->axes() > 1) {
+    inAxis1 = inputWS->getAxis(1);
+    auto outAxis1 = outputWS->getAxis(1);
+    outTxtAxis = dynamic_cast<TextAxis *>(outAxis1);
+    if (!outTxtAxis)
+      outNumAxis = dynamic_cast<NumericAxis *>(outAxis1);
+  }
+
+  Progress prog(this, 0.0, 1.0, indexSet.size());
+  for (size_t j = 0; j < indexSet.size(); ++j) {
+    // Rely on Indexing::IndexSet preserving index order.
+    const size_t i = indexSet[j];
+    // Copy spectrum data, automatically setting up sharing for histogram.
+    outputWS->getSpectrum(j).copyDataFrom(inputWS->getSpectrum(i));
+
+    // Copy axis entry, SpectraAxis is implicit in workspace creation
+    if (outTxtAxis)
+      outTxtAxis->setLabel(j, inAxis1->label(i));
+    else if (outNumAxis)
+      outNumAxis->setValue(j, inAxis1->operator()(i));
+
+    // Copy bin masking if it exists.
+    if (inputWS->hasMaskedBins(i))
+      outputWS->setMaskedBins(j, inputWS->maskedBins(i));
+
+    prog.report();
+  }
+
+  setProperty("OutputWorkspace", std::move(outputWS));
+}
+
+} // namespace Algorithms
+} // namespace Mantid
diff --git a/Framework/Algorithms/src/HyspecScharpfCorrection.cpp b/Framework/Algorithms/src/HyspecScharpfCorrection.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ac4200f5ed18d990bf4f65222363dad336ba6ff9
--- /dev/null
+++ b/Framework/Algorithms/src/HyspecScharpfCorrection.cpp
@@ -0,0 +1,248 @@
+#include "MantidAlgorithms/HyspecScharpfCorrection.h"
+#include "MantidKernel/BoundedValidator.h"
+#include "MantidKernel/CompositeValidator.h"
+#include "MantidAPI/InstrumentValidator.h"
+#include "MantidAPI/WorkspaceUnitValidator.h"
+#include "MantidAPI/Run.h"
+#include "MantidAPI/WorkspaceFactory.h"
+#include "MantidGeometry/Instrument/ReferenceFrame.h"
+#include "MantidGeometry/Instrument.h"
+#include "MantidDataObjects/EventWorkspace.h"
+#include "MantidAPI/SpectrumInfo.h"
+
+namespace Mantid {
+namespace Algorithms {
+
+using Mantid::Kernel::Direction;
+using Mantid::API::WorkspaceProperty;
+
+// Register the algorithm into the AlgorithmFactory
+DECLARE_ALGORITHM(HyspecScharpfCorrection)
+
+//----------------------------------------------------------------------------------------------
+
+/// Algorithms name for identification. @see Algorithm::name
+const std::string HyspecScharpfCorrection::name() const {
+  return "HyspecScharpfCorrection";
+}
+
+/// Algorithm's version for identification. @see Algorithm::version
+int HyspecScharpfCorrection::version() const { return 1; }
+
+/// Algorithm's category for identification. @see Algorithm::category
+const std::string HyspecScharpfCorrection::category() const {
+  return "CorrectionFunctions\\SpecialCorrections; Inelastic\\Corrections";
+}
+
+/// Algorithm's summary for use in the GUI and help. @see Algorithm::summary
+const std::string HyspecScharpfCorrection::summary() const {
+  return "Apply polarization factor as part of getting the spin incoherent "
+         "scattering";
+}
+
+//----------------------------------------------------------------------------------------------
+/** Initialize the algorithm's properties.
+ */
+void HyspecScharpfCorrection::init() {
+  auto wsValidator = boost::make_shared<Mantid::Kernel::CompositeValidator>();
+  wsValidator->add<Mantid::API::WorkspaceUnitValidator>("DeltaE");
+  wsValidator->add<Mantid::API::InstrumentValidator>();
+  declareProperty(Kernel::make_unique<WorkspaceProperty<API::MatrixWorkspace>>(
+                      "InputWorkspace", "", Direction::Input, wsValidator),
+                  "An input workspace in units of energy transfer.");
+
+  auto angleValidator =
+      boost::make_shared<Mantid::Kernel::BoundedValidator<double>>();
+  angleValidator->setLower(-180.0);
+  angleValidator->setUpper(180.0);
+  declareProperty("PolarizationAngle", EMPTY_DBL(), angleValidator,
+                  "In plane angle between polatrization and incident beam"
+                  "Must be between -180 and +180 degrees");
+  auto precisionValidator =
+      boost::make_shared<Mantid::Kernel::BoundedValidator<double>>();
+  precisionValidator->setLower(0.0);
+  precisionValidator->setUpper(1.0);
+  declareProperty(
+      "Precision", 0.1, precisionValidator,
+      "If cosine of twice the "
+      "Scharpf angle is closer to 0 than the precision, the intensities "
+      "and errors will be set to 0");
+  declareProperty(Kernel::make_unique<WorkspaceProperty<API::MatrixWorkspace>>(
+                      "OutputWorkspace", "", Direction::Output),
+                  "An output workspace.");
+}
+
+//----------------------------------------------------------------------------------------------
+/** Execute the algorithm.
+ */
+void HyspecScharpfCorrection::exec() {
+  // Get the workspaces
+  m_inputWS = this->getProperty("InputWorkspace");
+  m_outputWS = this->getProperty("OutputWorkspace");
+  m_angle = getProperty("PolarizationAngle");
+  m_angle *= M_PI / 180.;
+  m_precision = getProperty("Precision");
+  if (m_inputWS->run().hasProperty("Ei")) {
+    m_Ei = m_inputWS->run().getPropertyValueAsType<double>("Ei");
+  } else {
+    throw std::invalid_argument(
+        "No Ei value has been set or stored within the run information.");
+  }
+
+  // Check if it is an event workspace
+  if (dynamic_cast<const Mantid::DataObjects::EventWorkspace *>(
+          m_inputWS.get()) != nullptr) {
+    this->execEvent();
+    return;
+  }
+
+  // If input and output workspaces are not the same, create a new workspace for
+  // the output
+  if (m_outputWS != m_inputWS) {
+    m_outputWS = API::WorkspaceFactory::Instance().create(m_inputWS);
+  }
+
+  const auto &spectrumInfo = m_inputWS->spectrumInfo();
+
+  // Get number of spectra in this workspace
+  const int64_t numberOfSpectra =
+      static_cast<int64_t>(m_inputWS->getNumberHistograms());
+  Mantid::Kernel::V3D samplePos = spectrumInfo.samplePosition();
+  const auto refFrame = m_inputWS->getInstrument()->getReferenceFrame();
+  API::Progress prog(this, 0.0, 1.0, numberOfSpectra);
+  PARALLEL_FOR_IF(Kernel::threadSafe(*m_inputWS, *m_outputWS))
+  for (int64_t i = 0; i < numberOfSpectra; ++i) {
+    PARALLEL_START_INTERUPT_REGION
+    auto &yOut = m_outputWS->mutableY(i);
+    auto &eOut = m_outputWS->mutableE(i);
+
+    const auto &xIn = m_inputWS->points(i); // get the centers
+    auto &yIn = m_inputWS->y(i);
+    auto &eIn = m_inputWS->e(i);
+    // Copy the energy transfer axis
+    m_outputWS->setSharedX(i, m_inputWS->sharedX(i));
+
+    prog.report();
+    // continue if no detectors, if monitor, or is masked
+    if ((!spectrumInfo.hasDetectors(i)) || spectrumInfo.isMonitor(i) ||
+        spectrumInfo.isMasked(i)) {
+      continue;
+    }
+    // get detector info and calculate the in plane angle
+    Mantid::Kernel::V3D detPos = spectrumInfo.position(i);
+    const auto l2 = detPos - samplePos;
+    const double thPlane = std::atan2(l2[refFrame->pointingHorizontal()],
+                                      l2[refFrame->pointingAlongBeam()]);
+    size_t spectrumSize = xIn.size();
+    for (size_t j = 0; j < spectrumSize; ++j) {
+      double factor = 0.;
+      if (xIn[j] < m_Ei) {
+        double kfki = std::sqrt(1. - xIn[j] / m_Ei); // k_f/k_i
+        factor = static_cast<double>(this->calculateFactor(kfki, thPlane));
+      }
+      yOut[j] = yIn[j] * factor;
+      eOut[j] = eIn[j] * factor;
+    }
+    PARALLEL_END_INTERUPT_REGION
+  } // end for i
+  PARALLEL_CHECK_INTERUPT_REGION
+  this->setProperty("OutputWorkspace", m_outputWS);
+}
+
+/** Execute for events
+ */
+void HyspecScharpfCorrection::execEvent() {
+  g_log.information("Processing event workspace");
+
+  // If input and output workspaces are not the same, create a new workspace for
+  // the output
+  if (m_outputWS != m_inputWS) {
+    m_outputWS = m_inputWS->clone();
+    setProperty("OutputWorkspace", m_outputWS);
+  }
+
+  Mantid::DataObjects::EventWorkspace_sptr eventWS =
+      boost::dynamic_pointer_cast<Mantid::DataObjects::EventWorkspace>(
+          m_outputWS);
+
+  const auto &spectrumInfo = m_inputWS->spectrumInfo();
+
+  // Get number of spectra in this workspace
+  const int64_t numberOfSpectra =
+      static_cast<int64_t>(m_inputWS->getNumberHistograms());
+  Mantid::Kernel::V3D samplePos = spectrumInfo.samplePosition();
+  const auto refFrame = m_inputWS->getInstrument()->getReferenceFrame();
+  API::Progress prog(this, 0.0, 1.0, numberOfSpectra);
+  PARALLEL_FOR_IF(Kernel::threadSafe(*m_inputWS, *m_outputWS))
+  for (int64_t i = 0; i < numberOfSpectra; ++i) {
+    PARALLEL_START_INTERUPT_REGION
+    prog.report();
+    // continue if no detectors, if monitor, or is masked
+    if ((!spectrumInfo.hasDetectors(i)) || spectrumInfo.isMonitor(i) ||
+        spectrumInfo.isMasked(i)) {
+      continue;
+    }
+    Mantid::Kernel::V3D detPos = spectrumInfo.position(i);
+    const auto l2 = detPos - samplePos;
+    const double thPlane = std::atan2(l2[refFrame->pointingHorizontal()],
+                                      l2[refFrame->pointingAlongBeam()]);
+    // Do the correction
+    auto &evlist = eventWS->getSpectrum(i);
+    switch (evlist.getEventType()) {
+    case Mantid::API::TOF:
+      // Switch to weights if needed.
+      evlist.switchTo(Mantid::API::WEIGHTED);
+    /* no break */
+    // Fall through
+
+    case Mantid::API::WEIGHTED:
+      ScharpfEventHelper(evlist.getWeightedEvents(), thPlane);
+      break;
+
+    case Mantid::API::WEIGHTED_NOTIME:
+      ScharpfEventHelper(evlist.getWeightedEventsNoTime(), thPlane);
+      break;
+    }
+    PARALLEL_END_INTERUPT_REGION
+  } // end for i
+  PARALLEL_CHECK_INTERUPT_REGION
+}
+
+template <class T>
+void HyspecScharpfCorrection::ScharpfEventHelper(std::vector<T> &wevector,
+                                                 double thPlane) {
+  for (auto it = wevector.begin(); it < wevector.end();) {
+    double Ef = m_Ei - it->tof();
+    if (Ef <= 0) {
+      it = wevector.erase(it);
+    } else {
+      double kfki = std::sqrt(Ef / m_Ei);
+
+      float factor = this->calculateFactor(kfki, thPlane);
+
+      it->m_weight *= factor;
+      it->m_errorSquared *= factor * factor;
+      ++it;
+    }
+  }
+}
+
+float HyspecScharpfCorrection::calculateFactor(const double kfki,
+                                               const double thPlane) {
+  // angle between in plane Q and z axis
+  const double angleQ =
+      std::atan2(-kfki * std::sin(thPlane), 1. - kfki * std::cos(thPlane));
+  // Scarpf agle = angle - angleQ
+  float factor = static_cast<float>(std::cos(2. * (m_angle - angleQ)));
+  // set intensity to 0 if the Scarpf angle is close to 45 degrees
+  if (std::abs(factor) > m_precision) {
+    factor = 1.f / factor;
+  } else {
+    factor = 0.;
+  }
+
+  return (factor);
+}
+
+} // namespace Algorithms
+} // namespace Mantid
diff --git a/Framework/Algorithms/src/MaskBins.cpp b/Framework/Algorithms/src/MaskBins.cpp
index 8212595cde6d38d37ceab6b701708bc3457af780..e964c3687154f3b11db6c3fa6b2d7c1372e352bc 100644
--- a/Framework/Algorithms/src/MaskBins.cpp
+++ b/Framework/Algorithms/src/MaskBins.cpp
@@ -41,7 +41,7 @@ void MaskBins::init() {
   declareProperty("XMax", std::numeric_limits<double>::max(), required,
                   "The value to end masking at.");
 
-  this->declareProperty(make_unique<ArrayProperty<int>>("SpectraList"),
+  this->declareProperty(make_unique<ArrayProperty<int64_t>>("SpectraList"),
                         "Deprecated, use InputWorkspaceIndexSet.");
 }
 
@@ -62,7 +62,7 @@ void MaskBins::exec() {
   }
 
   // Copy indices from legacy property
-  std::vector<int> spectraList = this->getProperty("SpectraList");
+  std::vector<int64_t> spectraList = this->getProperty("SpectraList");
   if (!spectraList.empty()) {
     if (!isDefault("InputWorkspaceIndexSet"))
       throw std::runtime_error("Cannot provide both InputWorkspaceIndexSet and "
diff --git a/Framework/Algorithms/test/CalculatePolynomialBackgroundTest.h b/Framework/Algorithms/test/CalculatePolynomialBackgroundTest.h
index 8106f6d6b51eeacf7d9e516f735049abef51639a..19122f111200a432ca1e11103474c94512bf92a5 100644
--- a/Framework/Algorithms/test/CalculatePolynomialBackgroundTest.h
+++ b/Framework/Algorithms/test/CalculatePolynomialBackgroundTest.h
@@ -98,7 +98,73 @@ public:
       const auto &bkgEs = outWS->e(histI);
       const auto &bkgXs = outWS->x(histI);
       for (size_t binI = 0; binI < nBin; ++binI) {
-        TS_ASSERT_DELTA(bkgYs[binI], ys[binI], 1e-12)
+        TS_ASSERT_DELTA(bkgYs[binI], ys[binI], 1e-10)
+        TS_ASSERT_EQUALS(bkgEs[binI], 0)
+        TS_ASSERT_EQUALS(bkgXs[binI], xs[binI])
+      }
+    }
+  }
+
+  void test_costFuctionLeastSquares() {
+    using namespace WorkspaceCreationHelper;
+    const size_t nHist{2};
+    const HistogramData::Counts counts{0, 4, 0, 0};
+    const HistogramData::CountStandardDeviations stdDevs{0, 0.001, 0, 0};
+    const HistogramData::BinEdges edges{0, 1, 2, 3, 4};
+    API::MatrixWorkspace_sptr ws(
+        DataObjects::create<DataObjects::Workspace2D>(
+            nHist, HistogramData::Histogram(edges, counts, stdDevs)).release());
+    auto alg = makeAlgorithm();
+    TS_ASSERT_THROWS_NOTHING(alg->setProperty("InputWorkspace", ws))
+    TS_ASSERT_THROWS_NOTHING(alg->setProperty("OutputWorkspace", "outputWS"))
+    TS_ASSERT_THROWS_NOTHING(alg->setProperty("Degree", 0))
+    TS_ASSERT_THROWS_NOTHING(alg->setProperty("CostFunction", "Least squares"))
+    TS_ASSERT_THROWS_NOTHING(alg->execute())
+    TS_ASSERT(alg->isExecuted())
+    API::MatrixWorkspace_sptr outWS = alg->getProperty("OutputWorkspace");
+    TS_ASSERT(outWS)
+    for (size_t histI = 0; histI < nHist; ++histI) {
+      const auto &xs = ws->x(histI);
+      const auto &bkgYs = outWS->y(histI);
+      const auto &bkgEs = outWS->e(histI);
+      const auto &bkgXs = outWS->x(histI);
+      for (size_t binI = 0; binI < counts.size(); ++binI) {
+        // Number 4 in counts is heavily weighted by the small error.
+        TS_ASSERT_DELTA(bkgYs[binI], 4, 1e-5)
+        TS_ASSERT_EQUALS(bkgEs[binI], 0)
+        TS_ASSERT_EQUALS(bkgXs[binI], xs[binI])
+      }
+    }
+  }
+
+  void test_costFuctionUnweightedLeastSquares() {
+    using namespace WorkspaceCreationHelper;
+    const size_t nHist{2};
+    const HistogramData::Counts counts{0, 4, 0, 0};
+    const HistogramData::BinEdges edges{0, 1, 2, 3, 4};
+    API::MatrixWorkspace_sptr ws(
+        DataObjects::create<DataObjects::Workspace2D>(
+            nHist, HistogramData::Histogram(edges, counts)).release());
+    auto alg = makeAlgorithm();
+    TS_ASSERT_THROWS_NOTHING(alg->setProperty("InputWorkspace", ws))
+    TS_ASSERT_THROWS_NOTHING(alg->setProperty("OutputWorkspace", "outputWS"))
+    TS_ASSERT_THROWS_NOTHING(alg->setProperty("Degree", 0))
+    TS_ASSERT_THROWS_NOTHING(
+        alg->setProperty("CostFunction", "Unweighted least squares"))
+    TS_ASSERT_THROWS_NOTHING(alg->execute())
+    TS_ASSERT(alg->isExecuted())
+    API::MatrixWorkspace_sptr outWS = alg->getProperty("OutputWorkspace");
+    TS_ASSERT(outWS)
+    // Unweighted fitting of zeroth order polynomial is equivalent to the mean.
+    const double result = std::accumulate(counts.cbegin(), counts.cend(), 0.0) /
+                          static_cast<double>(counts.size());
+    for (size_t histI = 0; histI < nHist; ++histI) {
+      const auto &xs = ws->x(histI);
+      const auto &bkgYs = outWS->y(histI);
+      const auto &bkgEs = outWS->e(histI);
+      const auto &bkgXs = outWS->x(histI);
+      for (size_t binI = 0; binI < counts.size(); ++binI) {
+        TS_ASSERT_DELTA(bkgYs[binI], result, 1e-5)
         TS_ASSERT_EQUALS(bkgEs[binI], 0)
         TS_ASSERT_EQUALS(bkgXs[binI], xs[binI])
       }
@@ -176,7 +242,7 @@ public:
     const auto &bkgXs = outWS->x(0);
     const std::vector<double> expected{1.0, 2.0, 3.0, 4.0, 5.0, 6.0};
     for (size_t binI = 0; binI < nBin; ++binI) {
-      TS_ASSERT_DELTA(bkgYs[binI], expected[binI], 1e-12)
+      TS_ASSERT_DELTA(bkgYs[binI], expected[binI], 1e-10)
       TS_ASSERT_EQUALS(bkgEs[binI], 0)
       TS_ASSERT_EQUALS(bkgXs[binI], xs[binI])
     }
diff --git a/Framework/Algorithms/test/ExtractSpectra2Test.h b/Framework/Algorithms/test/ExtractSpectra2Test.h
new file mode 100644
index 0000000000000000000000000000000000000000..87d6f8bb44f2b8d163efc15e35f9363ef6317293
--- /dev/null
+++ b/Framework/Algorithms/test/ExtractSpectra2Test.h
@@ -0,0 +1,124 @@
+#ifndef MANTID_ALGORITHMS_EXTRACTSPECTRA2TEST_H_
+#define MANTID_ALGORITHMS_EXTRACTSPECTRA2TEST_H_
+
+#include <cxxtest/TestSuite.h>
+
+#include "MantidAlgorithms/ExtractSpectra2.h"
+#include "MantidDataObjects/Workspace2D.h"
+#include "MantidDataObjects/WorkspaceCreation.h"
+#include "MantidAPI/AnalysisDataService.h"
+#include "MantidIndexing/IndexInfo.h"
+
+#include "MantidTestHelpers/FakeObjects.h"
+#include "MantidTestHelpers/ParallelAlgorithmCreation.h"
+#include "MantidTestHelpers/ParallelRunner.h"
+
+using Mantid::Algorithms::ExtractSpectra2;
+using namespace Mantid;
+using namespace API;
+using namespace Kernel;
+using namespace DataObjects;
+using namespace HistogramData;
+
+namespace {
+void run_parallel(const Parallel::Communicator &comm) {
+  Indexing::IndexInfo indexInfo(1000, Parallel::StorageMode::Distributed, comm);
+  auto alg = ParallelTestHelpers::create<ExtractSpectra2>(comm);
+  alg->setProperty("InputWorkspace", create<Workspace2D>(indexInfo, Points(1)));
+  alg->setProperty("InputWorkspaceIndexSet",
+                   "0-" + std::to_string(comm.size()));
+  TS_ASSERT_THROWS_NOTHING(alg->execute());
+  MatrixWorkspace_const_sptr out = alg->getProperty("OutputWorkspace");
+  TS_ASSERT_EQUALS(out->storageMode(), Parallel::StorageMode::Distributed);
+  if (0 % comm.size() == comm.rank()) {
+    TS_ASSERT_EQUALS(out->getNumberHistograms(), 2);
+  } else {
+    TS_ASSERT_EQUALS(out->getNumberHistograms(), 1);
+  }
+}
+
+boost::shared_ptr<Workspace2D> createWorkspace() {
+  auto ws = create<Workspace2D>(5, Points(1));
+  ws->setHistogram(0, Points{0.0}, Counts{1.0});
+  ws->setHistogram(1, Points{1.0}, Counts{1.0});
+  ws->setHistogram(2, Points{2.0}, Counts{1.0});
+  ws->setHistogram(3, Points{3.0}, Counts{1.0});
+  ws->setHistogram(4, Points{4.0}, Counts{1.0});
+  return std::move(ws);
+}
+}
+
+class ExtractSpectra2Test : 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 ExtractSpectra2Test *createSuite() {
+    return new ExtractSpectra2Test();
+  }
+  static void destroySuite(ExtractSpectra2Test *suite) { delete suite; }
+
+  void test_full() {
+    auto input = createWorkspace();
+    ExtractSpectra2 alg;
+    alg.initialize();
+    alg.setProperty("InputWorkspace", std::move(input));
+    alg.setProperty("OutputWorkspace", "out");
+    alg.execute();
+    auto ws =
+        AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("out");
+    TS_ASSERT_EQUALS(ws->getNumberHistograms(), 5);
+  }
+
+  void test_reorder() {
+    auto input = createWorkspace();
+    ExtractSpectra2 alg;
+    alg.initialize();
+    alg.setProperty("InputWorkspace", std::move(input));
+    alg.setProperty("InputWorkspaceIndexSet", "4,0-3");
+    alg.setProperty("OutputWorkspace", "out");
+    alg.execute();
+    auto ws =
+        AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("out");
+    TS_ASSERT_EQUALS(ws->getNumberHistograms(), 5);
+    const auto &indexInfo = ws->indexInfo();
+    TS_ASSERT_EQUALS(indexInfo.spectrumNumber(0), 5);
+    TS_ASSERT_EQUALS(indexInfo.spectrumNumber(1), 1);
+    TS_ASSERT_EQUALS(indexInfo.spectrumNumber(2), 2);
+    TS_ASSERT_EQUALS(indexInfo.spectrumNumber(3), 3);
+    TS_ASSERT_EQUALS(indexInfo.spectrumNumber(4), 4);
+    TS_ASSERT_EQUALS(ws->getSpectrum(0).getSpectrumNo(), 5);
+    TS_ASSERT_EQUALS(ws->getSpectrum(1).getSpectrumNo(), 1);
+    TS_ASSERT_EQUALS(ws->getSpectrum(2).getSpectrumNo(), 2);
+    TS_ASSERT_EQUALS(ws->getSpectrum(3).getSpectrumNo(), 3);
+    TS_ASSERT_EQUALS(ws->getSpectrum(4).getSpectrumNo(), 4);
+    TS_ASSERT_EQUALS(ws->x(0)[0], 4.0);
+    TS_ASSERT_EQUALS(ws->x(1)[0], 0.0);
+    TS_ASSERT_EQUALS(ws->x(2)[0], 1.0);
+    TS_ASSERT_EQUALS(ws->x(3)[0], 2.0);
+    TS_ASSERT_EQUALS(ws->x(4)[0], 3.0);
+  }
+
+  void test_extract() {
+    auto input = createWorkspace();
+    ExtractSpectra2 alg;
+    alg.initialize();
+    alg.setProperty("InputWorkspace", std::move(input));
+    alg.setProperty("InputWorkspaceIndexSet", "4,1-2");
+    alg.setProperty("OutputWorkspace", "out");
+    alg.execute();
+    auto ws =
+        AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("out");
+    TS_ASSERT_EQUALS(ws->getNumberHistograms(), 3);
+    const auto &indexInfo = ws->indexInfo();
+    TS_ASSERT_EQUALS(indexInfo.spectrumNumber(0), 5);
+    TS_ASSERT_EQUALS(indexInfo.spectrumNumber(1), 2);
+    TS_ASSERT_EQUALS(indexInfo.spectrumNumber(2), 3);
+    TS_ASSERT_EQUALS(ws->x(0)[0], 4.0);
+    TS_ASSERT_EQUALS(ws->x(1)[0], 1.0);
+    TS_ASSERT_EQUALS(ws->x(2)[0], 2.0);
+  }
+
+  void test_parallel() { ParallelTestHelpers::runParallel(run_parallel); }
+};
+
+#endif /* MANTID_ALGORITHMS_EXTRACTSPECTRA2TEST_H_ */
diff --git a/Framework/Algorithms/test/ExtractSpectraTest.h b/Framework/Algorithms/test/ExtractSpectraTest.h
index dc3654efe3abe35d66b9a4246cd8625747538c1b..43124749136f226a2e3e1032fa8a791e10bea25a 100644
--- a/Framework/Algorithms/test/ExtractSpectraTest.h
+++ b/Framework/Algorithms/test/ExtractSpectraTest.h
@@ -7,15 +7,69 @@
 #include "MantidAPI/SpectrumInfo.h"
 #include "MantidAlgorithms/ExtractSpectra.h"
 #include "MantidDataObjects/EventWorkspace.h"
+#include "MantidDataObjects/WorkspaceCreation.h"
 #include "MantidKernel/UnitFactory.h"
+#include "MantidIndexing/IndexInfo.h"
+
 #include "MantidTestHelpers/ComponentCreationHelper.h"
+#include "MantidTestHelpers/ParallelAlgorithmCreation.h"
+#include "MantidTestHelpers/ParallelRunner.h"
 #include "MantidTestHelpers/WorkspaceCreationHelper.h"
 
 using Mantid::Algorithms::ExtractSpectra;
-using namespace Mantid::API;
-using namespace Mantid::Kernel;
-using namespace Mantid::DataObjects;
 using namespace Mantid;
+using namespace API;
+using namespace Kernel;
+using namespace DataObjects;
+using namespace HistogramData;
+
+namespace {
+void run_parallel_DetectorList_fails(const Parallel::Communicator &comm) {
+  Indexing::IndexInfo indexInfo(1000, Parallel::StorageMode::Distributed, comm);
+  auto alg = ParallelTestHelpers::create<ExtractSpectra>(comm);
+  alg->setProperty("InputWorkspace", create<Workspace2D>(indexInfo, Points(1)));
+  alg->setProperty("DetectorList", "1");
+  if (comm.size() == 1) {
+    TS_ASSERT_THROWS_NOTHING(alg->execute());
+  } else {
+    TS_ASSERT_THROWS_EQUALS(
+        alg->execute(), const std::runtime_error &e, std::string(e.what()),
+        "MatrixWorkspace: Using getIndicesFromDetectorIDs in "
+        "a parallel run is most likely incorrect. Aborting.");
+  }
+}
+
+void run_parallel_WorkspaceIndexList(const Parallel::Communicator &comm) {
+  Indexing::IndexInfo indexInfo(1000, Parallel::StorageMode::Distributed, comm);
+  auto alg = ParallelTestHelpers::create<ExtractSpectra>(comm);
+  alg->setProperty("InputWorkspace", create<Workspace2D>(indexInfo, Points(1)));
+  alg->setProperty("WorkspaceIndexList", "0-" + std::to_string(comm.size()));
+  TS_ASSERT_THROWS_NOTHING(alg->execute());
+  MatrixWorkspace_const_sptr out = alg->getProperty("OutputWorkspace");
+  TS_ASSERT_EQUALS(out->storageMode(), Parallel::StorageMode::Distributed);
+  if (comm.rank() == 0) {
+    TS_ASSERT_EQUALS(out->getNumberHistograms(), 2);
+  } else {
+    TS_ASSERT_EQUALS(out->getNumberHistograms(), 1);
+  }
+}
+
+void run_parallel_WorkspaceIndexRange(const Parallel::Communicator &comm) {
+  Indexing::IndexInfo indexInfo(3 * comm.size(),
+                                Parallel::StorageMode::Distributed, comm);
+  auto alg = ParallelTestHelpers::create<ExtractSpectra>(comm);
+  alg->setProperty("InputWorkspace", create<Workspace2D>(indexInfo, Points(1)));
+  alg->setProperty("StartWorkspaceIndex", std::to_string(comm.size() + 1));
+  TS_ASSERT_THROWS_NOTHING(alg->execute());
+  MatrixWorkspace_const_sptr out = alg->getProperty("OutputWorkspace");
+  TS_ASSERT_EQUALS(out->storageMode(), Parallel::StorageMode::Distributed);
+  if (comm.rank() == 0) {
+    TS_ASSERT_EQUALS(out->getNumberHistograms(), 1);
+  } else {
+    TS_ASSERT_EQUALS(out->getNumberHistograms(), 2);
+  }
+}
+}
 
 class ExtractSpectraTest : public CxxTest::TestSuite {
 public:
@@ -262,12 +316,7 @@ public:
   void test_invalid_x_range_event() {
     Parameters params("event");
     params.setInvalidXRange();
-    auto ws = runAlgorithm(params, true);
-    // this is a bit unexpected but at least no crash
-    TS_ASSERT_EQUALS(ws->getNumberHistograms(), nSpec);
-    TS_ASSERT_EQUALS(ws->blocksize(), 1);
-    TS_ASSERT_EQUALS(ws->x(0)[0], 2);
-    TS_ASSERT_EQUALS(ws->x(0)[1], 1);
+    auto ws = runAlgorithm(params, false);
   }
 
   void test_invalid_index_range_event() {
@@ -385,6 +434,16 @@ public:
     auto ws = runAlgorithm(params, false);
   }
 
+  void test_parallel_DetectorList_fails() {
+    ParallelTestHelpers::runParallel(run_parallel_DetectorList_fails);
+  }
+  void test_parallel_WorkspaceIndexList() {
+    ParallelTestHelpers::runParallel(run_parallel_WorkspaceIndexList);
+  }
+  void test_parallel_WorkspaceIndexRange() {
+    ParallelTestHelpers::runParallel(run_parallel_WorkspaceIndexRange);
+  }
+
 private:
   // -----------------------  helper methods ------------------------
 
diff --git a/Framework/Algorithms/test/HyspecScharpfCorrectionTest.h b/Framework/Algorithms/test/HyspecScharpfCorrectionTest.h
new file mode 100644
index 0000000000000000000000000000000000000000..952f382003c0632c0fd0bcf1c1b41788f03baf60
--- /dev/null
+++ b/Framework/Algorithms/test/HyspecScharpfCorrectionTest.h
@@ -0,0 +1,72 @@
+#ifndef MANTID_ALGORITHMS_HYSPECSCHARPFCORRECTIONTEST_H_
+#define MANTID_ALGORITHMS_HYSPECSCHARPFCORRECTIONTEST_H_
+
+#include <cxxtest/TestSuite.h>
+
+#include "MantidAlgorithms/HyspecScharpfCorrection.h"
+#include "MantidTestHelpers/WorkspaceCreationHelper.h"
+
+using Mantid::Algorithms::HyspecScharpfCorrection;
+
+class HyspecScharpfCorrectionTest : 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 HyspecScharpfCorrectionTest *createSuite() {
+    return new HyspecScharpfCorrectionTest();
+  }
+  static void destroySuite(HyspecScharpfCorrectionTest *suite) { delete suite; }
+
+  void test_Init() {
+    HyspecScharpfCorrection alg;
+    TS_ASSERT_THROWS_NOTHING(alg.initialize())
+    TS_ASSERT(alg.isInitialized())
+  }
+
+  void test_exec() {
+    // Create test input
+    std::vector<double> L2 = {1.0}, polar = {M_PI_4}, azimuthal = {0.};
+    auto inputWS = WorkspaceCreationHelper::createProcessedInelasticWS(
+        L2, polar, azimuthal, 30, -10, 20, 17.1);
+    HyspecScharpfCorrection alg;
+
+    alg.setChild(true);
+    alg.setRethrows(true);
+    TS_ASSERT_THROWS_NOTHING(alg.initialize())
+    TS_ASSERT(alg.isInitialized())
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("InputWorkspace", inputWS));
+    TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue(
+        "OutputWorkspace", "HyspecScharpfCorrectionOutput"));
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("PolarizationAngle", -11.0));
+    TS_ASSERT_THROWS_NOTHING(alg.execute(););
+    TS_ASSERT(alg.isExecuted());
+
+    // Retrieve the workspace from the algorithm.
+    Mantid::API::MatrixWorkspace_sptr outputWS =
+        alg.getProperty("OutputWorkspace");
+    TS_ASSERT(outputWS);
+    auto histo = outputWS->histogram(0);
+    auto x = histo.points();
+    auto y = histo.y();
+    for (size_t i = 0; i < x.size(); ++i) {
+      if (x[i] < 4) {
+        TS_ASSERT_LESS_THAN(y[i], 0);
+      } else if (x[i] < 6. || x[i] > 17.) {
+        TS_ASSERT_EQUALS(y[i], 0.);
+      } else {
+        TS_ASSERT_LESS_THAN(0, y[i]);
+      }
+    }
+    // test one value, say DeltaE=6.5
+    double kikf = std::sqrt(1. - 6.5 / 17.1);
+    auto alpha =
+        std::atan2(-kikf * std::sin(M_PI_4), 1. - kikf * std::cos(M_PI_4)) +
+        11. * M_PI / 180.;
+    TS_ASSERT_DELTA(x[16], 6.5, 1e-10);
+    // note that it does the correction factor as a float
+    // as it is a common code with events
+    TS_ASSERT_DELTA(y[16], 1. / std::cos(2. * alpha), 1e-6);
+  }
+};
+
+#endif /* MANTID_ALGORITHMS_HYSPECSCHARPFCORRECTIONTEST_H_ */
diff --git a/Framework/DataHandling/inc/MantidDataHandling/MaskDetectors.h b/Framework/DataHandling/inc/MantidDataHandling/MaskDetectors.h
index c251c1ec12b7947d463ecccbc5c8898158c4ff54..eeb72c9fea0682d8bc75a9dd9b57c3ff71e00040 100644
--- a/Framework/DataHandling/inc/MantidDataHandling/MaskDetectors.h
+++ b/Framework/DataHandling/inc/MantidDataHandling/MaskDetectors.h
@@ -99,10 +99,11 @@ private:
                                    const RangeInfo &rangeInfo);
 
   void execPeaks(DataObjects::PeaksWorkspace_sptr WS);
-  void fillIndexListFromSpectra(
-      std::vector<size_t> &indexList,
-      const std::vector<Indexing::SpectrumNumber> &spectraList,
-      const API::MatrixWorkspace_sptr WS, const RangeInfo &range_info);
+  void
+  fillIndexListFromSpectra(std::vector<size_t> &indexList,
+                           std::vector<Indexing::SpectrumNumber> spectraList,
+                           const API::MatrixWorkspace_sptr WS,
+                           const RangeInfo &range_info);
   void appendToDetectorListFromComponentList(
       std::vector<detid_t> &detectorList,
       const std::vector<std::string> &componentList,
diff --git a/Framework/DataHandling/src/LoadEventNexusIndexSetup.cpp b/Framework/DataHandling/src/LoadEventNexusIndexSetup.cpp
index 7442d8846eea97f15c4918a6f6a2e73914d33a9b..046ed078ab6d404824f116db8477c434e3e9212c 100644
--- a/Framework/DataHandling/src/LoadEventNexusIndexSetup.cpp
+++ b/Framework/DataHandling/src/LoadEventNexusIndexSetup.cpp
@@ -183,6 +183,7 @@ LoadEventNexusIndexSetup::filterIndexInfo(const IndexInfo &indexInfo) {
   }
   // Check if SpectrumList was supplied (or filled via min/max above)
   if (!m_range.empty()) {
+    std::sort(m_range.begin(), m_range.end());
     const auto indices = indexInfo.makeIndexSet(
         std::vector<SpectrumNumber>(m_range.begin(), m_range.end()));
     m_min = static_cast<int32_t>(indexInfo.spectrumNumber(*indices.begin()));
diff --git a/Framework/DataHandling/src/MaskDetectors.cpp b/Framework/DataHandling/src/MaskDetectors.cpp
index bf34627a16294e9b84014a9637336f999646ae16..09d2823db8df68e428e4558bc3ca8b8ee2ae84bc 100644
--- a/Framework/DataHandling/src/MaskDetectors.cpp
+++ b/Framework/DataHandling/src/MaskDetectors.cpp
@@ -11,6 +11,7 @@
 #include "MantidKernel/ArrayProperty.h"
 #include "MantidKernel/BoundedValidator.h"
 #include "MantidKernel/EnabledWhenProperty.h"
+#include <algorithm>
 #include <numeric>
 #include <set>
 
@@ -170,7 +171,8 @@ void MaskDetectors::exec() {
   // appropriate spectra number and adding the indices they are linked to the
   // list to be processed
   if (!spectraList.empty()) {
-    fillIndexListFromSpectra(indexList, spectraList, WS, ranges_info);
+    fillIndexListFromSpectra(indexList, std::move(spectraList), WS,
+                             ranges_info);
   } // End dealing with spectraList
   if (!detectorList.empty()) {
     // Convert from detectors to workspace indexes
@@ -451,7 +453,7 @@ void MaskDetectors::execPeaks(PeaksWorkspace_sptr WS) {
  */
 void MaskDetectors::fillIndexListFromSpectra(
     std::vector<size_t> &indexList,
-    const std::vector<Indexing::SpectrumNumber> &spectraList,
+    std::vector<Indexing::SpectrumNumber> spectraList,
     const API::MatrixWorkspace_sptr WS,
     const std::tuple<size_t, size_t, bool> &range_info) {
 
@@ -466,6 +468,12 @@ void MaskDetectors::fillIndexListFromSpectra(
     tmp_index.swap(indexList);
   }
 
+  // Ignore duplicate entries.
+  std::sort(spectraList.begin(), spectraList.end());
+  auto last = std::unique(spectraList.begin(), spectraList.end());
+  if (last != spectraList.end())
+    g_log.warning("Duplicate entries in spectrum list.");
+  spectraList.erase(last, spectraList.end());
   for (auto ws_index : WS->indexInfo().makeIndexSet(spectraList)) {
     if (range_constrained && (ws_index < startIndex || ws_index > endIndex)) {
       continue;
diff --git a/Framework/DataObjects/inc/MantidDataObjects/EventList.h b/Framework/DataObjects/inc/MantidDataObjects/EventList.h
index 8468f490acd264b76f304bfc51a624c197977e58..a7a5e3e49c345d37294e7dce90d3d68149aaac6f 100644
--- a/Framework/DataObjects/inc/MantidDataObjects/EventList.h
+++ b/Framework/DataObjects/inc/MantidDataObjects/EventList.h
@@ -84,6 +84,8 @@ public:
 
   ~EventList() override;
 
+  void copyDataFrom(const ISpectrum &source) override;
+
   void createFromHistogram(const ISpectrum *inSpec, bool GenerateZeros,
                            bool GenerateMultipleEvents, int MaxEventsPerBin);
 
@@ -362,6 +364,10 @@ protected:
   void checkIsYAndEWritable() const override;
 
 private:
+  using ISpectrum::copyDataInto;
+  void copyDataInto(EventList &sink) const override;
+  void copyDataInto(Histogram1D &sink) const override;
+
   const HistogramData::Histogram &histogramRef() const override {
     return m_histogram;
   }
diff --git a/Framework/DataObjects/inc/MantidDataObjects/Histogram1D.h b/Framework/DataObjects/inc/MantidDataObjects/Histogram1D.h
index 4537c851f9e2bca1fd85f92fe6b39000847d714d..dad0efa1b9181ebca2a2d05a5121ed5ad816799b 100644
--- a/Framework/DataObjects/inc/MantidDataObjects/Histogram1D.h
+++ b/Framework/DataObjects/inc/MantidDataObjects/Histogram1D.h
@@ -48,6 +48,8 @@ public:
   Histogram1D &operator=(Histogram1D &&) = default;
   Histogram1D &operator=(const ISpectrum &rhs);
 
+  void copyDataFrom(const ISpectrum &source) override;
+
   void setX(const Kernel::cow_ptr<HistogramData::HistogramX> &X) override;
   MantidVec &dataX() override;
   const MantidVec &dataX() const override;
@@ -85,6 +87,9 @@ public:
   }
 
 private:
+  using ISpectrum::copyDataInto;
+  void copyDataInto(Histogram1D &sink) const override;
+
   void checkAndSanitizeHistogram(HistogramData::Histogram &histogram) override;
   const HistogramData::Histogram &histogramRef() const override {
     return m_histogram;
diff --git a/Framework/DataObjects/inc/MantidDataObjects/WorkspaceCreation.h b/Framework/DataObjects/inc/MantidDataObjects/WorkspaceCreation.h
index 7a3d895a65962c561b7996c1fcbf5202b00bcabf..a7e550fa8454130e57062d63118bb8809b7d332b 100644
--- a/Framework/DataObjects/inc/MantidDataObjects/WorkspaceCreation.h
+++ b/Framework/DataObjects/inc/MantidDataObjects/WorkspaceCreation.h
@@ -9,6 +9,9 @@
 #include <type_traits>
 
 namespace Mantid {
+namespace Indexing {
+class IndexInfo;
+}
 namespace Geometry {
 class Instrument;
 }
@@ -142,9 +145,13 @@ MANTID_DATAOBJECTS_DLL void
 fixDistributionFlag(API::MatrixWorkspace &workspace,
                     const HistogramData::Histogram &histArg);
 
-MANTID_DATAOBJECTS_DLL void
-initializeFromParent(const API::MatrixWorkspace &parent,
-                     API::MatrixWorkspace &ws);
+template <class T> struct IsIndexInfo { using type = std::false_type; };
+template <> struct IsIndexInfo<Indexing::IndexInfo> {
+  using type = std::true_type;
+};
+template <class UseIndexInfo>
+void initializeFromParent(const API::MatrixWorkspace &parent,
+                          API::MatrixWorkspace &workspace);
 }
 
 /** This is the create() method that all the other create() methods call.
@@ -181,7 +188,8 @@ std::unique_ptr<T> create(const P &parent, const IndexArg &indexArg,
   // future of WorkspaceFactory.
   ws->setInstrument(parent.getInstrument());
   ws->initialize(indexArg, HistogramData::Histogram(histArg));
-  detail::initializeFromParent(parent, *ws);
+  detail::initializeFromParent<typename detail::IsIndexInfo<IndexArg>::type>(
+      parent, *ws);
   // initializeFromParent sets the distribution flag to the same value as
   // parent. In case histArg is an actual Histogram that is not the correct
   // behavior so we have to set it back to the value given by histArg.
diff --git a/Framework/DataObjects/src/EventList.cpp b/Framework/DataObjects/src/EventList.cpp
index 917b57063dc0a12a74fd1c72b9ed9c7bd5f31a92..2ae4a697ad722d666c33a3dde492ef0a70dd4700 100644
--- a/Framework/DataObjects/src/EventList.cpp
+++ b/Framework/DataObjects/src/EventList.cpp
@@ -1,4 +1,5 @@
 #include "MantidDataObjects/EventList.h"
+#include "MantidDataObjects/Histogram1D.h"
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidDataObjects/EventWorkspaceMRU.h"
 #include "MantidKernel/DateAndTime.h"
@@ -190,6 +191,26 @@ EventList::~EventList() {
   // std::vector<TofEvent>().swap(events); //Trick to release the vector memory.
 }
 
+/// Copy data from another EventList, via ISpectrum reference.
+void EventList::copyDataFrom(const ISpectrum &source) {
+  source.copyDataInto(*this);
+}
+
+/// Used by copyDataFrom for dynamic dispatch for its `source`.
+void EventList::copyDataInto(EventList &sink) const {
+  sink.m_histogram = m_histogram;
+  sink.events = events;
+  sink.weightedEvents = weightedEvents;
+  sink.weightedEventsNoTime = weightedEventsNoTime;
+  sink.eventType = eventType;
+  sink.order = order;
+}
+
+/// Used by Histogram1D::copyDataFrom for dynamic dispatch for `other`.
+void EventList::copyDataInto(Histogram1D &sink) const {
+  sink.setHistogram(histogram());
+}
+
 // --------------------------------------------------------------------------
 /** Create an EventList from a histogram. This converts bins to weighted
  * events.
diff --git a/Framework/DataObjects/src/Histogram1D.cpp b/Framework/DataObjects/src/Histogram1D.cpp
index 31971b661c9ad9d3f9f1f585b88aba6fb4fe43fd..12c2c710f4a3f9408f5b517baee96f24f618b867 100644
--- a/Framework/DataObjects/src/Histogram1D.cpp
+++ b/Framework/DataObjects/src/Histogram1D.cpp
@@ -31,6 +31,16 @@ Histogram1D &Histogram1D::operator=(const ISpectrum &rhs) {
   return *this;
 }
 
+/// Copy data from a Histogram1D or EventList, via ISpectrum reference.
+void Histogram1D::copyDataFrom(const ISpectrum &source) {
+  source.copyDataInto(*this);
+}
+
+/// Used by copyDataFrom for dynamic dispatch for its `source`.
+void Histogram1D::copyDataInto(Histogram1D &sink) const {
+  sink.m_histogram = m_histogram;
+}
+
 void Histogram1D::clearData() {
   MantidVec &yValues = this->dataY();
   std::fill(yValues.begin(), yValues.end(), 0.0);
diff --git a/Framework/DataObjects/src/WorkspaceCreation.cpp b/Framework/DataObjects/src/WorkspaceCreation.cpp
index 92ecff01b8353a8025e330d6a02b29052576f128..3389c78de85144970ae8fcc09d4a5f15653826db 100644
--- a/Framework/DataObjects/src/WorkspaceCreation.cpp
+++ b/Framework/DataObjects/src/WorkspaceCreation.cpp
@@ -3,6 +3,7 @@
 #include "MantidDataObjects/EventWorkspace.h"
 #include "MantidDataObjects/WorkspaceCreation.h"
 #include "MantidDataObjects/Workspace2D.h"
+#include "MantidIndexing/IndexInfo.h"
 
 namespace Mantid {
 namespace DataObjects {
@@ -34,18 +35,53 @@ template <> std::unique_ptr<API::HistoWorkspace> createConcreteHelper() {
   return {nullptr};
 }
 
+template <class UseIndexInfo>
+void doInitializeFromParent(const API::MatrixWorkspace &parent,
+                            API::MatrixWorkspace &workspace,
+                            const bool differentSize) {
+  API::WorkspaceFactory::Instance().initializeFromParent(parent, workspace,
+                                                         differentSize);
+}
+
+/** Same as WorkspaceFactory::initializeFromParent, with modifications for
+ * changed IndexInfo.
+ *
+ * IndexInfo used for initialization this implies that the following data from
+ * the parent is not applicable (since no automatic mapping possible):
+ * - Bin masking
+ * - Spectrum numbers and detector ID grouping
+ * - Y axis
+ */
+template <>
+void doInitializeFromParent<std::true_type>(const API::MatrixWorkspace &parent,
+                                            API::MatrixWorkspace &child,
+                                            const bool differentSize) {
+  // Ignore flag since with IndexInfo the size is the same but we nevertheless
+  // do not want to copy some data since spectrum order or definitions may have
+  // changed. This should take care of not copying bin masks and Y axis.
+  static_cast<void>(differentSize);
+
+  const auto indexInfo = child.indexInfo();
+  API::WorkspaceFactory::Instance().initializeFromParent(parent, child, true);
+  // Restore previously set IndexInfo of child, undo changes to spectrum numbers
+  // and detector ID grouping initializeFromParent does by default. This hack is
+  // not optimal performance wise but copying data between workspaces is too
+  // complicated and dangerous currently without using initializeFromParent.
+  child.setIndexInfo(indexInfo);
+}
+
 /** Initialize a MatrixWorkspace from its parent including instrument, unit,
  * number of spectra and Run
  * @brief initializeFromParent
  * @param parent
  * @param ws
  */
+template <class UseIndexInfo>
 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);
+  doInitializeFromParent<UseIndexInfo>(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.
@@ -58,6 +94,13 @@ void fixDistributionFlag(API::MatrixWorkspace &workspace,
   workspace.setDistribution(histArg.yMode() ==
                             HistogramData::Histogram::YMode::Frequencies);
 }
+
+template void MANTID_DATAOBJECTS_DLL
+initializeFromParent<std::true_type>(const API::MatrixWorkspace &,
+                                     API::MatrixWorkspace &);
+template void MANTID_DATAOBJECTS_DLL
+initializeFromParent<std::false_type>(const API::MatrixWorkspace &,
+                                      API::MatrixWorkspace &);
 }
 } // namespace DataObjects
 } // namespace Mantid
diff --git a/Framework/DataObjects/test/EventListTest.h b/Framework/DataObjects/test/EventListTest.h
index 93b909c7efff214949b1ce4af59d0d3736aa8550..7ce3c4f4ad6ac77bf450c99d914adac205b2abbb 100644
--- a/Framework/DataObjects/test/EventListTest.h
+++ b/Framework/DataObjects/test/EventListTest.h
@@ -4,9 +4,11 @@
 #include <cxxtest/TestSuite.h>
 #include "MantidDataObjects/EventList.h"
 #include "MantidDataObjects/EventWorkspace.h"
+#include "MantidDataObjects/Histogram1D.h"
 #include "MantidKernel/Timer.h"
 #include "MantidKernel/CPUTimer.h"
 #include "MantidKernel/Unit.h"
+#include "MantidKernel/make_unique.h"
 
 #include <boost/scoped_ptr.hpp>
 #include <cmath>
@@ -55,6 +57,77 @@ public:
     el = EventList(mylist);
   }
 
+  void test_copyDataFrom() {
+    Histogram1D histogram{Histogram::XMode::Points, Histogram::YMode::Counts};
+    histogram.setHistogram(Points(1), Counts(1));
+    EventList eventList;
+    eventList.setHistogram(BinEdges{0.0, 2.0});
+    eventList += TofEvent(1.0, 2);
+    std::unique_ptr<const ISpectrum> specHist =
+        Kernel::make_unique<Histogram1D>(histogram);
+    std::unique_ptr<const ISpectrum> specEvent =
+        Kernel::make_unique<EventList>(eventList);
+    std::unique_ptr<ISpectrum> target = make_unique<EventList>();
+
+    TS_ASSERT_THROWS_EQUALS(target->copyDataFrom(*specHist),
+                            const std::runtime_error &e, std::string(e.what()),
+                            "Incompatible types in ISpectrum::copyDataFrom");
+
+    TS_ASSERT_THROWS_NOTHING(target->copyDataFrom(*specEvent));
+    TS_ASSERT(target->binEdges());
+    TS_ASSERT_EQUALS(&target->binEdges()[0], &eventList.binEdges()[0]);
+    TS_ASSERT_EQUALS(target->counts()[0], 1.0);
+  }
+
+  void test_copyDataFrom_does_not_copy_indices() {
+    EventList eventList;
+    eventList.setHistogram(BinEdges{0.0, 2.0});
+    eventList += TofEvent(1.0, 2);
+    std::unique_ptr<const ISpectrum> specEvent =
+        Kernel::make_unique<EventList>(eventList);
+    std::unique_ptr<ISpectrum> target = make_unique<EventList>();
+    target->setSpectrumNo(37);
+    target->setDetectorID(42);
+
+    TS_ASSERT_THROWS_NOTHING(target->copyDataFrom(*specEvent));
+    TS_ASSERT(target->binEdges());
+    TS_ASSERT_EQUALS(&target->binEdges()[0], &eventList.binEdges()[0]);
+    TS_ASSERT_EQUALS(target->counts()[0], 1.0);
+    TS_ASSERT_EQUALS(target->getSpectrumNo(), 37);
+    TS_ASSERT_EQUALS(target->getDetectorIDs(), std::set<detid_t>{42});
+  }
+
+  void test_copyDataFrom_event_data_details() {
+    EventList eventList;
+    eventList.setHistogram(BinEdges{0.0, 2.0});
+    eventList += TofEvent(1.0, 2);
+    EventList target;
+
+    target.copyDataFrom(eventList);
+    TS_ASSERT_EQUALS(target.getEventType(), EventType::TOF)
+    TS_ASSERT_EQUALS(target.getSortType(), eventList.getSortType());
+    TS_ASSERT_EQUALS(target.getEvents(), eventList.getEvents());
+    TS_ASSERT_THROWS(target.getWeightedEvents(), std::runtime_error);
+    TS_ASSERT_THROWS(target.getWeightedEventsNoTime(), std::runtime_error);
+
+    eventList.switchTo(EventType::WEIGHTED);
+    target.copyDataFrom(eventList);
+    TS_ASSERT_EQUALS(target.getEventType(), EventType::WEIGHTED)
+    TS_ASSERT_EQUALS(target.getSortType(), eventList.getSortType());
+    TS_ASSERT_THROWS(target.getEvents(), std::runtime_error);
+    TS_ASSERT_EQUALS(target.getWeightedEvents(), eventList.getWeightedEvents());
+    TS_ASSERT_THROWS(target.getWeightedEventsNoTime(), std::runtime_error);
+
+    eventList.switchTo(EventType::WEIGHTED_NOTIME);
+    target.copyDataFrom(eventList);
+    TS_ASSERT_EQUALS(target.getEventType(), EventType::WEIGHTED_NOTIME)
+    TS_ASSERT_EQUALS(target.getSortType(), eventList.getSortType());
+    TS_ASSERT_THROWS(target.getEvents(), std::runtime_error);
+    TS_ASSERT_THROWS(target.getWeightedEvents(), std::runtime_error);
+    TS_ASSERT_EQUALS(target.getWeightedEventsNoTime(),
+                     eventList.getWeightedEventsNoTime());
+  }
+
   //==================================================================================
   //--- Basics  ----
   //==================================================================================
diff --git a/Framework/DataObjects/test/Histogram1DTest.h b/Framework/DataObjects/test/Histogram1DTest.h
index b8c764d32f5a609ab99c1184d56cefcc40a5f7ca..8caa93e411e8d49069426a362e5a2b377fc06c7f 100644
--- a/Framework/DataObjects/test/Histogram1DTest.h
+++ b/Framework/DataObjects/test/Histogram1DTest.h
@@ -7,12 +7,15 @@
 #include <cxxtest/TestSuite.h>
 
 #include "MantidHistogramData/LinearGenerator.h"
+#include "MantidDataObjects/EventList.h"
 #include "MantidDataObjects/Histogram1D.h"
+#include "MantidKernel/make_unique.h"
 
-using Mantid::DataObjects::Histogram1D;
-using Mantid::MantidVec;
-using Mantid::Kernel::make_cow;
-using namespace Mantid::HistogramData;
+using namespace Mantid;
+using namespace API;
+using namespace Kernel;
+using namespace DataObjects;
+using namespace HistogramData;
 
 class Histogram1DTest : public CxxTest::TestSuite {
 private:
@@ -45,6 +48,54 @@ public:
     h2.setCountStandardDeviations(100);
   }
 
+  void test_copyDataFrom() {
+    Histogram1D histogram{Histogram::XMode::Points, Histogram::YMode::Counts};
+    histogram.setHistogram(Points(1), Counts(1));
+    EventList eventList;
+    eventList.setHistogram(BinEdges(2));
+    std::unique_ptr<const ISpectrum> specHist =
+        Kernel::make_unique<Histogram1D>(histogram);
+    std::unique_ptr<const ISpectrum> specEvent =
+        Kernel::make_unique<EventList>(eventList);
+    std::unique_ptr<ISpectrum> target = make_unique<Histogram1D>(
+        Histogram::XMode::Points, Histogram::YMode::Counts);
+
+    TS_ASSERT_THROWS_NOTHING(target->copyDataFrom(*specHist));
+    TS_ASSERT(target->points());
+    TS_ASSERT_EQUALS(&target->points()[0], &histogram.points()[0]);
+
+    TS_ASSERT_THROWS_NOTHING(target->copyDataFrom(*specEvent));
+    TS_ASSERT(target->binEdges());
+    TS_ASSERT_EQUALS(&target->binEdges()[0], &eventList.binEdges()[0]);
+  }
+
+  void test_copyDataFrom_does_not_copy_indices() {
+    Histogram1D histogram{Histogram::XMode::Points, Histogram::YMode::Counts};
+    histogram.setHistogram(Points(1), Counts(1));
+    EventList eventList;
+    eventList.setHistogram(BinEdges(2));
+    std::unique_ptr<const ISpectrum> specHist =
+        Kernel::make_unique<Histogram1D>(histogram);
+    std::unique_ptr<const ISpectrum> specEvent =
+        Kernel::make_unique<EventList>(eventList);
+    std::unique_ptr<ISpectrum> target = make_unique<Histogram1D>(
+        Histogram::XMode::Points, Histogram::YMode::Counts);
+    target->setSpectrumNo(37);
+    target->setDetectorID(42);
+
+    TS_ASSERT_THROWS_NOTHING(target->copyDataFrom(*specHist));
+    TS_ASSERT(target->points());
+    TS_ASSERT_EQUALS(&target->points()[0], &histogram.points()[0]);
+    TS_ASSERT_EQUALS(target->getSpectrumNo(), 37);
+    TS_ASSERT_EQUALS(target->getDetectorIDs(), std::set<detid_t>{42});
+
+    TS_ASSERT_THROWS_NOTHING(target->copyDataFrom(*specEvent));
+    TS_ASSERT(target->binEdges());
+    TS_ASSERT_EQUALS(&target->binEdges()[0], &eventList.binEdges()[0]);
+    TS_ASSERT_EQUALS(target->getSpectrumNo(), 37);
+    TS_ASSERT_EQUALS(target->getDetectorIDs(), std::set<detid_t>{42});
+  }
+
   void testcheckAndSanitizeHistogramThrowsNullY() {
     Histogram1D h{Histogram::XMode::Points, Histogram::YMode::Counts};
     BinEdges edges{-0.04, 1.7};
diff --git a/Framework/DataObjects/test/WorkspaceCreationTest.h b/Framework/DataObjects/test/WorkspaceCreationTest.h
index dccc28d59ee2daf4cd37e614521de4aaf4094033..e788ffe3c44daecf7dd6b6062b9a61c480b17f2d 100644
--- a/Framework/DataObjects/test/WorkspaceCreationTest.h
+++ b/Framework/DataObjects/test/WorkspaceCreationTest.h
@@ -41,6 +41,33 @@ void run_create_partitioned(const Parallel::Communicator &comm) {
     }
   }
   TS_ASSERT_EQUALS(i.size(), expectedSize);
+  TS_ASSERT_EQUALS(ws->storageMode(), Parallel::StorageMode::Distributed);
+}
+
+void run_create_partitioned_parent(const Parallel::Communicator &comm) {
+  IndexInfo indices(47, Parallel::StorageMode::Distributed, comm);
+  indices.setSpectrumDefinitions(
+      std::vector<SpectrumDefinition>(indices.size()));
+  const auto parent =
+      create<Workspace2D>(indices, Histogram(BinEdges{1, 2, 4}));
+  const auto ws = create<MatrixWorkspace>(*parent);
+  const auto &i = ws->indexInfo();
+  TS_ASSERT_EQUALS(i.globalSize(), 47);
+  size_t expectedSize = 0;
+  for (size_t globalIndex = 0; globalIndex < i.globalSize(); ++globalIndex) {
+    // Current default is RoundRobinPartitioner
+    if (static_cast<int>(globalIndex) % comm.size() == comm.rank()) {
+      TS_ASSERT_EQUALS(i.spectrumNumber(expectedSize),
+                       static_cast<int>(globalIndex) + 1);
+      ++expectedSize;
+    }
+  }
+  TS_ASSERT_EQUALS(parent->indexInfo().globalSize(),
+                   ws->indexInfo().globalSize());
+  TS_ASSERT_EQUALS(parent->indexInfo().size(), ws->indexInfo().size());
+  TS_ASSERT_EQUALS(parent->getNumberHistograms(), ws->getNumberHistograms());
+  TS_ASSERT_EQUALS(i.size(), expectedSize);
+  TS_ASSERT_EQUALS(ws->storageMode(), Parallel::StorageMode::Distributed);
 }
 
 void run_create_partitioned_with_instrument(
@@ -334,12 +361,26 @@ public:
     check_zeroed_data(*ws);
   }
 
-  void test_create_parent_IndexInfo_same_size() {
+  void test_create_parent_same_size_does_not_ignore_IndexInfo_no_instrument() {
     const auto parent = create<Workspace2D>(2, Histogram(BinEdges{1, 2, 4}));
     const auto ws = create<Workspace2D>(*parent, make_indices_no_detectors(),
                                         parent->histogram(0));
-    // If parent has same size, data in IndexInfo is ignored
-    check_default_indices(*ws);
+    // Even if parent has same size data in IndexInfo should not be ignored
+    // since it is given explicitly.
+    check_indices_no_detectors(*ws);
+    check_zeroed_data(*ws);
+  }
+
+  void test_create_parent_same_size_does_not_ignore_IndexInfo() {
+    auto parentIndices = make_indices();
+    parentIndices.setSpectrumNumbers({666, 1});
+    const auto parent = create<Workspace2D>(m_instrument, parentIndices,
+                                            Histogram(BinEdges{1, 2, 4}));
+    const auto ws =
+        create<Workspace2D>(*parent, make_indices(), parent->histogram(0));
+    // Even if parent has same size data in IndexInfo should not be ignored
+    // since it is given explicitly.
+    check_indices(*ws);
     check_zeroed_data(*ws);
   }
 
@@ -441,9 +482,10 @@ public:
     TS_ASSERT_EQUALS(ws->storageMode(), Parallel::StorageMode::Distributed);
   }
 
-  void test_create_partitioned() {
-    run_create_partitioned(Parallel::Communicator{});
-    runParallel(run_create_partitioned);
+  void test_create_partitioned() { runParallel(run_create_partitioned); }
+
+  void test_create_partitioned_parent() {
+    runParallel(run_create_partitioned_parent);
   }
 
   void test_create_partitioned_with_instrument() {
diff --git a/Framework/Indexing/inc/MantidIndexing/IndexInfo.h b/Framework/Indexing/inc/MantidIndexing/IndexInfo.h
index 6333ef278cd0a1010773a8b0097aa150ad802132..b96a988ca0a99235f8c381acc52fbf0695404f16 100644
--- a/Framework/Indexing/inc/MantidIndexing/IndexInfo.h
+++ b/Framework/Indexing/inc/MantidIndexing/IndexInfo.h
@@ -83,6 +83,8 @@ public:
   IndexInfo(std::vector<SpectrumNumber> spectrumNumbers,
             const Parallel::StorageMode storageMode,
             const Parallel::Communicator &communicator);
+  template <class IndexType>
+  IndexInfo(std::vector<IndexType> indices, const IndexInfo &parent);
 
   IndexInfo(const IndexInfo &other);
   IndexInfo(IndexInfo &&other);
diff --git a/Framework/Indexing/inc/MantidIndexing/IndexSet.h b/Framework/Indexing/inc/MantidIndexing/IndexSet.h
index d1030119495fcbc92d8e1db5168572a367a692bc..455c5324aecb9f879e52ea9c4fcdd33ff32618bb 100644
--- a/Framework/Indexing/inc/MantidIndexing/IndexSet.h
+++ b/Framework/Indexing/inc/MantidIndexing/IndexSet.h
@@ -140,15 +140,18 @@ IndexSet<T>::IndexSet(int64_t min, int64_t max, size_t fullRange) {
 }
 
 /// Constructor for a set containing all specified indices. Range is verified at
-/// construction time and duplicates are removed.
+/// construction time and duplicates cause an error.
 template <class T>
 IndexSet<T>::IndexSet(const std::vector<size_t> &indices, size_t fullRange)
     : m_isRange(false) {
-  // We use a set to create unique and ordered indices.
-  std::set<size_t> index_set(indices.cbegin(), indices.cend());
-  if (!index_set.empty() && *(index_set.rbegin()) >= fullRange)
+  // Validate indices, using m_indices as buffer (reassigned later).
+  m_indices = indices;
+  std::sort(m_indices.begin(), m_indices.end());
+  if (!m_indices.empty() && *m_indices.rbegin() >= fullRange)
     throw std::out_of_range("IndexSet: specified index is out of range");
-  m_indices = std::vector<size_t>(index_set.begin(), index_set.end());
+  if (std::adjacent_find(m_indices.begin(), m_indices.end()) != m_indices.end())
+    throw std::runtime_error("IndexSet: duplicate indices are not allowed");
+  m_indices = indices;
   m_size = m_indices.size();
 }
 
diff --git a/Framework/Indexing/inc/MantidIndexing/SpectrumNumberTranslator.h b/Framework/Indexing/inc/MantidIndexing/SpectrumNumberTranslator.h
index a4ca36f1d938dab45058024b3cb3a5a5f672ebae..eadb19a261b6b5dc35c945233fc71594786fbb96 100644
--- a/Framework/Indexing/inc/MantidIndexing/SpectrumNumberTranslator.h
+++ b/Framework/Indexing/inc/MantidIndexing/SpectrumNumberTranslator.h
@@ -50,6 +50,11 @@ public:
   SpectrumNumberTranslator(const std::vector<SpectrumNumber> &spectrumNumbers,
                            std::unique_ptr<Partitioner> partitioner,
                            const PartitionIndex &partition);
+  SpectrumNumberTranslator(const std::vector<SpectrumNumber> &spectrumNumbers,
+                           const SpectrumNumberTranslator &parent);
+  SpectrumNumberTranslator(
+      const std::vector<GlobalSpectrumIndex> &globalIndices,
+      const SpectrumNumberTranslator &parent);
 
   size_t globalSize() const;
   size_t localSize() const;
@@ -70,6 +75,8 @@ private:
   void checkUniqueSpectrumNumbers() const;
   // Not thread-safe! Use only in combination with std::call_once!
   void setupSpectrumNumberToIndexMap() const;
+  std::vector<SpectrumNumber>
+  spectrumNumbers(const std::vector<GlobalSpectrumIndex> &globalIndices) const;
 
   struct SpectrumNumberHash {
     std::size_t operator()(const SpectrumNumber &spectrumNumber) const {
diff --git a/Framework/Indexing/src/Extract.cpp b/Framework/Indexing/src/Extract.cpp
index 58910a360e54f83e74d3b917a42ceba9b7f230be..a1d0ce74590cc6ea969a66e217cae6b7ab95864e 100644
--- a/Framework/Indexing/src/Extract.cpp
+++ b/Framework/Indexing/src/Extract.cpp
@@ -6,6 +6,15 @@
 namespace Mantid {
 namespace Indexing {
 
+namespace {
+void checkStorageMode(const IndexInfo &indexInfo) {
+  using namespace Parallel;
+  if (indexInfo.storageMode() == StorageMode::Distributed)
+    throw std::runtime_error("extract() does not support " +
+                             Parallel::toString(StorageMode::Distributed));
+}
+}
+
 /// Extracts IndexInfo from source IndexInfo, extracting data for all indices
 /// specified by index set.
 IndexInfo extract(const IndexInfo &source, const SpectrumIndexSet &indices) {
@@ -15,6 +24,7 @@ IndexInfo extract(const IndexInfo &source, const SpectrumIndexSet &indices) {
 /// Extracts IndexInfo from source IndexInfo, extracting data for all indices
 /// specified by vector.
 IndexInfo extract(const IndexInfo &source, const std::vector<size_t> &indices) {
+  checkStorageMode(source);
   std::vector<SpectrumNumber> specNums;
   std::vector<SpectrumDefinition> specDefs;
   const auto &sourceDefs = source.spectrumDefinitions();
@@ -31,6 +41,7 @@ IndexInfo extract(const IndexInfo &source, const std::vector<size_t> &indices) {
 /// specified by range.
 IndexInfo extract(const IndexInfo &source, const size_t minIndex,
                   const size_t maxIndex) {
+  checkStorageMode(source);
   std::vector<SpectrumNumber> specNums;
   std::vector<SpectrumDefinition> specDefs;
   const auto &sourceDefs = source.spectrumDefinitions();
diff --git a/Framework/Indexing/src/IndexInfo.cpp b/Framework/Indexing/src/IndexInfo.cpp
index 1d12a6dfe4232f559995b017ccce1a9a4073464c..fa151a5a233a27f7a9f80b84caf6a92c184d72f2 100644
--- a/Framework/Indexing/src/IndexInfo.cpp
+++ b/Framework/Indexing/src/IndexInfo.cpp
@@ -14,13 +14,13 @@ namespace Mantid {
 namespace Indexing {
 
 /// Construct a default IndexInfo, with contiguous spectrum numbers starting at
-/// 1 and no detector IDs.
+/// 1 and no spectrum definitions.
 IndexInfo::IndexInfo(const size_t globalSize,
                      const Parallel::StorageMode storageMode)
     : IndexInfo(globalSize, storageMode, Parallel::Communicator{}) {}
 
 /// Construct a default IndexInfo, with contiguous spectrum numbers starting at
-/// 1 and no detector IDs.
+/// 1 and no spectrum definitions.
 IndexInfo::IndexInfo(const size_t globalSize,
                      const Parallel::StorageMode storageMode,
                      const Parallel::Communicator &communicator)
@@ -33,15 +33,15 @@ IndexInfo::IndexInfo(const size_t globalSize,
   makeSpectrumNumberTranslator(std::move(specNums));
 }
 
-/// Construct with given spectrum number and vector of detector IDs for each
-/// index.
+/// Construct with given spectrum number for each index and no spectrum
+/// definitions.
 IndexInfo::IndexInfo(std::vector<SpectrumNumber> spectrumNumbers,
                      const Parallel::StorageMode storageMode)
     : IndexInfo(std::move(spectrumNumbers), storageMode,
                 Parallel::Communicator{}) {}
 
-/// Construct with given spectrum number and vector of detector IDs for each
-/// index.
+/// Construct with given spectrum number for each index and no spectrum
+/// definitions.
 IndexInfo::IndexInfo(std::vector<SpectrumNumber> spectrumNumbers,
                      const Parallel::StorageMode storageMode,
                      const Parallel::Communicator &communicator)
@@ -51,6 +51,30 @@ IndexInfo::IndexInfo(std::vector<SpectrumNumber> spectrumNumbers,
   makeSpectrumNumberTranslator(std::move(spectrumNumbers));
 }
 
+/** Construct with given index subset of parent.
+ *
+ * The template argument IndexType can be SpectrumNumber or GlobalSpectrumIndex.
+ * The parent defines the partitioning of the spectrum numbers, i.e., the
+ * partition assigned to a given spectrum number in the constructed IndexInfo is
+ * given by the partition that spectrum number has in parent. This is used to
+ * extract spectrum numbers while maintaining the partitioning, avoiding the
+ * need to redistribute data between partitions (MPI ranks). Throws if any of
+ * the spectrum numbers is not present in parent. */
+template <class IndexType>
+IndexInfo::IndexInfo(std::vector<IndexType> indices, const IndexInfo &parent)
+    : m_storageMode(parent.m_storageMode),
+      m_communicator(
+          Kernel::make_unique<Parallel::Communicator>(*parent.m_communicator)) {
+  if (const auto parentSpectrumDefinitions = parent.spectrumDefinitions()) {
+    m_spectrumDefinitions = Kernel::make_cow<std::vector<SpectrumDefinition>>();
+    auto &specDefs = m_spectrumDefinitions.access();
+    for (const auto i : parent.makeIndexSet(indices))
+      specDefs.push_back(parentSpectrumDefinitions->operator[](i));
+  }
+  m_spectrumNumberTranslator = Kernel::make_cow<SpectrumNumberTranslator>(
+      std::move(indices), *parent.m_spectrumNumberTranslator);
+}
+
 IndexInfo::IndexInfo(const IndexInfo &other)
     : m_storageMode(other.m_storageMode),
       m_communicator(
@@ -286,5 +310,10 @@ void IndexInfo::makeSpectrumNumberTranslator(
       std::move(spectrumNumbers), std::move(partitioner), partition);
 }
 
+template MANTID_INDEXING_DLL IndexInfo::IndexInfo(std::vector<SpectrumNumber>,
+                                                  const IndexInfo &);
+template MANTID_INDEXING_DLL
+IndexInfo::IndexInfo(std::vector<GlobalSpectrumIndex>, const IndexInfo &);
+
 } // namespace Indexing
 } // namespace Mantid
diff --git a/Framework/Indexing/src/SpectrumNumberTranslator.cpp b/Framework/Indexing/src/SpectrumNumberTranslator.cpp
index ac613909860e3df63d815d1d40beb5dbe8704ec9..60ad3ac1e61fe4af82ee61de5d3931cf04dab72c 100644
--- a/Framework/Indexing/src/SpectrumNumberTranslator.cpp
+++ b/Framework/Indexing/src/SpectrumNumberTranslator.cpp
@@ -63,6 +63,31 @@ SpectrumNumberTranslator::SpectrumNumberTranslator(
   // called.
 }
 
+SpectrumNumberTranslator::SpectrumNumberTranslator(
+    const std::vector<SpectrumNumber> &spectrumNumbers,
+    const SpectrumNumberTranslator &parent)
+    : m_isPartitioned(parent.m_isPartitioned), m_partition(parent.m_partition),
+      m_globalSpectrumNumbers(spectrumNumbers) {
+  size_t currentIndex = 0;
+  for (size_t i = 0; i < m_globalSpectrumNumbers.size(); ++i) {
+    auto partition = parent.m_spectrumNumberToPartition.at(spectrumNumbers[i]);
+    auto number = m_globalSpectrumNumbers[i];
+    m_spectrumNumberToPartition.emplace(number, partition);
+    if (partition == m_partition) {
+      m_spectrumNumberToIndex.emplace_back(number, currentIndex);
+      m_globalToLocal.emplace_back(GlobalSpectrumIndex(i), currentIndex);
+      if (m_isPartitioned)
+        m_spectrumNumbers.emplace_back(number);
+      ++currentIndex;
+    }
+  }
+}
+
+SpectrumNumberTranslator::SpectrumNumberTranslator(
+    const std::vector<GlobalSpectrumIndex> &globalIndices,
+    const SpectrumNumberTranslator &parent)
+    : SpectrumNumberTranslator(parent.spectrumNumbers(globalIndices), parent) {}
+
 SpectrumIndexSet
 SpectrumNumberTranslator::makeIndexSet(SpectrumNumber min,
                                        SpectrumNumber max) const {
@@ -144,5 +169,14 @@ void SpectrumNumberTranslator::setupSpectrumNumberToIndexMap() const {
                 -> bool { return std::get<0>(a) < std::get<0>(b); });
 }
 
+std::vector<SpectrumNumber> SpectrumNumberTranslator::spectrumNumbers(
+    const std::vector<GlobalSpectrumIndex> &globalIndices) const {
+  std::vector<SpectrumNumber> spectrumNumbers;
+  for (const auto index : globalIndices)
+    spectrumNumbers.push_back(
+        m_globalSpectrumNumbers[static_cast<size_t>(index)]);
+  return spectrumNumbers;
+}
+
 } // namespace Indexing
 } // namespace Mantid
diff --git a/Framework/Indexing/test/IndexInfoTest.h b/Framework/Indexing/test/IndexInfoTest.h
index 7e16ef641f317550f9d78c9cb4fc31629f3c6ae8..08ef126fbbaa73d5b5910230647584a2ba12d8b9 100644
--- a/Framework/Indexing/test/IndexInfoTest.h
+++ b/Framework/Indexing/test/IndexInfoTest.h
@@ -74,6 +74,26 @@ void run_isOnThisPartition_StorageMode_Distributed(
     }
   }
 }
+
+void run_construct_from_parent_StorageMode_Distributed(
+    const Parallel::Communicator &comm) {
+  IndexInfo parent(47, Parallel::StorageMode::Distributed, comm);
+  IndexInfo i(std::vector<GlobalSpectrumIndex>{10, 11, 12, 13, 14, 15, 16},
+              parent);
+  size_t expectedSize = 0;
+  // Rank in `i` is given by rank in parent, so we iterate parent!
+  for (size_t globalIndex = 0; globalIndex < parent.globalSize();
+       ++globalIndex) {
+    if (static_cast<int>(globalIndex) % comm.size() == comm.rank()) {
+      if (globalIndex >= 10 && globalIndex <= 16) {
+        TS_ASSERT_EQUALS(i.spectrumNumber(expectedSize),
+                         static_cast<int>(globalIndex) + 1);
+        ++expectedSize;
+      }
+    }
+  }
+  TS_ASSERT_EQUALS(i.size(), expectedSize);
+}
 }
 
 class IndexInfoTest : public CxxTest::TestSuite {
@@ -104,6 +124,46 @@ public:
     TS_ASSERT_EQUALS(info.spectrumNumber(2), 1);
   }
 
+  void test_construct_from_parent_reorder() {
+    IndexInfo parent({3, 2, 1});
+    std::vector<SpectrumDefinition> specDefs(3);
+    specDefs[0].add(6);
+    specDefs[0].add(7);
+    specDefs[2].add(8);
+    parent.setSpectrumDefinitions(specDefs);
+
+    IndexInfo i(std::vector<SpectrumNumber>{2, 1, 3}, parent);
+
+    TS_ASSERT_EQUALS(i.size(), 3);
+    TS_ASSERT_EQUALS(i.globalSize(), 3);
+    TS_ASSERT_EQUALS(i.spectrumNumber(0), 2);
+    TS_ASSERT_EQUALS(i.spectrumNumber(1), 1);
+    TS_ASSERT_EQUALS(i.spectrumNumber(2), 3);
+    TS_ASSERT(i.spectrumDefinitions());
+    TS_ASSERT_EQUALS((*i.spectrumDefinitions())[0], specDefs[1]);
+    TS_ASSERT_EQUALS((*i.spectrumDefinitions())[1], specDefs[2]);
+    TS_ASSERT_EQUALS((*i.spectrumDefinitions())[2], specDefs[0]);
+  }
+
+  void test_construct_from_parent_filter() {
+    IndexInfo parent({3, 2, 1});
+    std::vector<SpectrumDefinition> specDefs(3);
+    specDefs[0].add(6);
+    specDefs[0].add(7);
+    specDefs[2].add(8);
+    parent.setSpectrumDefinitions(specDefs);
+
+    IndexInfo i(std::vector<SpectrumNumber>{1, 2}, parent);
+
+    TS_ASSERT_EQUALS(i.size(), 2);
+    TS_ASSERT_EQUALS(i.globalSize(), 2);
+    TS_ASSERT_EQUALS(i.spectrumNumber(0), 1);
+    TS_ASSERT_EQUALS(i.spectrumNumber(1), 2);
+    TS_ASSERT(i.spectrumDefinitions());
+    TS_ASSERT_EQUALS((*i.spectrumDefinitions())[0], specDefs[2]);
+    TS_ASSERT_EQUALS((*i.spectrumDefinitions())[1], specDefs[1]);
+  }
+
   void test_size() { TS_ASSERT_EQUALS(IndexInfo(3).size(), 3); }
 
   void test_copy() {
@@ -301,6 +361,10 @@ public:
     run_isOnThisPartition_StorageMode_Distributed(Parallel::Communicator{});
   }
 
+  void test_construct_from_parent_StorageMode_Distributed() {
+    runParallel(run_construct_from_parent_StorageMode_Distributed);
+  }
+
 private:
 #ifdef MPI_EXPERIMENTAL
   boost::mpi::environment m_environment;
diff --git a/Framework/Indexing/test/IndexSetTest.h b/Framework/Indexing/test/IndexSetTest.h
index bb74b45d535d65e42663e673300ac9895cbaeeb1..461bc224edea4482bf09df74528f3dbfdfdbab06 100644
--- a/Framework/Indexing/test/IndexSetTest.h
+++ b/Framework/Indexing/test/IndexSetTest.h
@@ -84,12 +84,18 @@ public:
     TS_ASSERT_EQUALS(set[1], 2);
   }
 
-  void test_indexList() {
-    // Note duplicate index
-    IndexSetTester set({2, 1, 2}, 3);
-    TS_ASSERT_EQUALS(set.size(), 2);
-    TS_ASSERT_EQUALS(set[0], 1);
-    TS_ASSERT_EQUALS(set[1], 2);
+  void test_indexList_order_preserved() {
+    IndexSetTester set({2, 1, 3}, 4);
+    TS_ASSERT_EQUALS(set.size(), 3);
+    TS_ASSERT_EQUALS(set[0], 2);
+    TS_ASSERT_EQUALS(set[1], 1);
+    TS_ASSERT_EQUALS(set[2], 3);
+  }
+
+  void test_indexList_duplicate_throws() {
+    TS_ASSERT_THROWS_EQUALS(IndexSetTester({2, 1, 2}, 3),
+                            const std::runtime_error &e, std::string(e.what()),
+                            "IndexSet: duplicate indices are not allowed");
   }
 
   void test_iterator_basics() {
diff --git a/Framework/Indexing/test/SpectrumNumberTranslatorTest.h b/Framework/Indexing/test/SpectrumNumberTranslatorTest.h
index 0f988d382ba4522ac67f99cb2b2b225c6d6b495d..476c07d7ffed9d45f90401c83496d7231ca55b9a 100644
--- a/Framework/Indexing/test/SpectrumNumberTranslatorTest.h
+++ b/Framework/Indexing/test/SpectrumNumberTranslatorTest.h
@@ -64,6 +64,16 @@ public:
         PartitionIndex(0)));
   }
 
+  void test_construct_empty() {
+    std::vector<SpectrumNumber> spectrumNumbers;
+    TS_ASSERT_THROWS_NOTHING(SpectrumNumberTranslator(
+        spectrumNumbers, Kernel::make_unique<RoundRobinPartitioner>(
+                             1, PartitionIndex(0),
+                             Partitioner::MonitorStrategy::CloneOnEachPartition,
+                             std::vector<GlobalSpectrumIndex>{}),
+        PartitionIndex(0)));
+  }
+
   void test_construct_bad_spectrum_numbers() {
     auto numbers = {1, 2, 3, 3};
     std::vector<SpectrumNumber> spectrumNumbers(numbers.begin(), numbers.end());
@@ -76,6 +86,58 @@ public:
         PartitionIndex(0)));
   }
 
+  void test_construct_parent() {
+    auto numbers = {1, 2, 3, 4};
+    std::vector<SpectrumNumber> spectrumNumbers(numbers.begin(), numbers.end());
+    SpectrumNumberTranslator parent(
+        spectrumNumbers, Kernel::make_unique<RoundRobinPartitioner>(
+                             1, PartitionIndex(0),
+                             Partitioner::MonitorStrategy::CloneOnEachPartition,
+                             std::vector<GlobalSpectrumIndex>{}),
+        PartitionIndex(0));
+
+    TS_ASSERT_THROWS_NOTHING(SpectrumNumberTranslator(spectrumNumbers, parent));
+    spectrumNumbers.erase(spectrumNumbers.begin() + 1);
+    TS_ASSERT_THROWS_NOTHING(SpectrumNumberTranslator(spectrumNumbers, parent));
+    spectrumNumbers.erase(spectrumNumbers.begin());
+    TS_ASSERT_THROWS_NOTHING(SpectrumNumberTranslator(spectrumNumbers, parent));
+    spectrumNumbers.erase(spectrumNumbers.begin());
+    TS_ASSERT_THROWS_NOTHING(SpectrumNumberTranslator(spectrumNumbers, parent));
+    spectrumNumbers.erase(spectrumNumbers.begin());
+    TS_ASSERT_THROWS_NOTHING(SpectrumNumberTranslator(spectrumNumbers, parent));
+  }
+
+  void test_construct_parent_reorder() {
+    auto numbers = {1, 2, 3, 4};
+    std::vector<SpectrumNumber> spectrumNumbers(numbers.begin(), numbers.end());
+    SpectrumNumberTranslator parent(
+        spectrumNumbers, Kernel::make_unique<RoundRobinPartitioner>(
+                             1, PartitionIndex(0),
+                             Partitioner::MonitorStrategy::CloneOnEachPartition,
+                             std::vector<GlobalSpectrumIndex>{}),
+        PartitionIndex(0));
+
+    std::iter_swap(spectrumNumbers.begin(), spectrumNumbers.end() - 1);
+    SpectrumNumberTranslator reordered(spectrumNumbers, parent);
+    TS_ASSERT_EQUALS(reordered.spectrumNumber(0), 4);
+    TS_ASSERT_EQUALS(reordered.spectrumNumber(3), 1);
+  }
+
+  void test_construct_parent_bad_spectrum_numbers() {
+    auto numbers = {1, 2, 3, 4};
+    std::vector<SpectrumNumber> spectrumNumbers(numbers.begin(), numbers.end());
+    SpectrumNumberTranslator parent(
+        spectrumNumbers, Kernel::make_unique<RoundRobinPartitioner>(
+                             1, PartitionIndex(0),
+                             Partitioner::MonitorStrategy::CloneOnEachPartition,
+                             std::vector<GlobalSpectrumIndex>{}),
+        PartitionIndex(0));
+
+    spectrumNumbers[1] = 7; // 7 is not in parent.
+    TS_ASSERT_THROWS(SpectrumNumberTranslator(spectrumNumbers, parent),
+                     std::out_of_range);
+  }
+
   void test_access_bad_spectrum_numbers() {
     auto numbers = {1, 2, 3, 3};
     std::vector<SpectrumNumber> spectrumNumbers(numbers.begin(), numbers.end());
@@ -182,8 +244,9 @@ public:
     auto translator = makeTranslator(1, 0);
     auto set = translator->makeIndexSet(SpectrumNumber(1), SpectrumNumber(5));
     TS_ASSERT_EQUALS(set.size(), 4);
-    TS_ASSERT_EQUALS(set[0], 0);
-    TS_ASSERT_EQUALS(set[1], 1);
+    // IndexSet is ordered by spectrum number.
+    TS_ASSERT_EQUALS(set[0], 1);
+    TS_ASSERT_EQUALS(set[1], 0);
     TS_ASSERT_EQUALS(set[2], 2);
     TS_ASSERT_EQUALS(set[3], 3);
   }
@@ -269,8 +332,9 @@ public:
     auto translator = makeTranslator(1, 0);
     auto set1 = translator->makeIndexSet(makeSpectrumNumbers({1, 2}));
     TS_ASSERT_EQUALS(set1.size(), 2);
-    TS_ASSERT_EQUALS(set1[0], 0);
-    TS_ASSERT_EQUALS(set1[1], 1);
+    // Order of spectrum numbers preserved.
+    TS_ASSERT_EQUALS(set1[0], 1);
+    TS_ASSERT_EQUALS(set1[1], 0);
     auto set2 = translator->makeIndexSet(makeSpectrumNumbers({4, 5}));
     TS_ASSERT_EQUALS(set2.size(), 2);
     TS_ASSERT_EQUALS(set2[0], 2);
@@ -332,6 +396,31 @@ public:
     TS_ASSERT_EQUALS(set2.size(), 1);
     TS_ASSERT_EQUALS(set2[0], 1);
   }
+
+  void test_construct_parent_3_ranks() {
+    auto parent = makeTranslator(3, 0);
+    auto numbers = {2, 1, 4, 5};
+    std::vector<SpectrumNumber> spectrumNumbers(numbers.begin(), numbers.end());
+
+    SpectrumNumberTranslator translator1(spectrumNumbers, *parent);
+    TS_ASSERT_EQUALS(translator1.globalSize(), 4);
+    TS_ASSERT_EQUALS(translator1.localSize(), 2); // 2 and 5 are on this rank.
+
+    spectrumNumbers.erase(spectrumNumbers.begin());
+    SpectrumNumberTranslator translator2(spectrumNumbers, *parent);
+    TS_ASSERT_EQUALS(translator2.globalSize(), 3);
+    TS_ASSERT_EQUALS(translator2.localSize(), 1);
+
+    spectrumNumbers.erase(spectrumNumbers.begin());
+    SpectrumNumberTranslator translator3(spectrumNumbers, *parent);
+    TS_ASSERT_EQUALS(translator3.globalSize(), 2);
+    TS_ASSERT_EQUALS(translator3.localSize(), 1);
+
+    spectrumNumbers.erase(spectrumNumbers.end() - 1);
+    SpectrumNumberTranslator translator4(spectrumNumbers, *parent);
+    TS_ASSERT_EQUALS(translator4.globalSize(), 1);
+    TS_ASSERT_EQUALS(translator4.localSize(), 0);
+  }
 };
 
 #endif /* MANTID_INDEXING_SPECTRUMNUMBERTRANSLATORTEST_H_ */
diff --git a/Framework/PythonInterface/plugins/algorithms/BASISReduction.py b/Framework/PythonInterface/plugins/algorithms/BASISReduction.py
index 35b7c4ee2b4a1d44666c65ae3f44ab6011c057d2..16a9ffa65b9cc6261b9a187c038ff994a532df76 100644
--- a/Framework/PythonInterface/plugins/algorithms/BASISReduction.py
+++ b/Framework/PythonInterface/plugins/algorithms/BASISReduction.py
@@ -104,12 +104,17 @@ class BASISReduction(PythonAlgorithm):
         self.declareProperty("DoIndividual", False, "Do each run individually")
         self.declareProperty("NoMonitorNorm", False,
                              "Stop monitor normalization")
+        self.declareProperty('ExcludeTimeSegment', '',
+                             'Exclude a contigous time segment; '+
+                             'Examples: "71546:0-60" filter run 71546 from '+
+                             'start to 60 seconds, "71546:300-600", '+
+                             '"71546:120-end" from 120s to the end of the run')
         grouping_type = ["None", "Low-Resolution", "By-Tube"]
         self.declareProperty("GroupDetectors", "None",
                              StringListValidator(grouping_type),
                              "Switch for grouping detectors")
-        self.declareProperty("NormalizeToFirst", False, "Normalize spectra \
-        to intensity of spectrum with lowest Q?")
+        self.declareProperty('NormalizeToFirst', False, 'Normalize spectra '+
+                             'to intensity of spectrum with lowest Q?')
 
         # Properties affected by the reflection selected
         titleReflection = "Reflection Selector"
@@ -353,6 +358,10 @@ class BASISReduction(PythonAlgorithm):
                 sapi.DeleteWorkspace(self._normWs)  # Delete vanadium S(Q)
                 if self._normalizationType == "by Q slice":
                     sapi.DeleteWorkspace(normWs)  # Delete vanadium events file
+            if self.getProperty("ExcludeTimeSegment").value:
+                sapi.DeleteWorkspace('splitted_unfiltered')
+                sapi.DeleteWorkspace('splitter')
+                sapi.DeleteWorkspace('TOFCorrectWS')
 
     def _getRuns(self, rlist, doIndiv=True):
         """
@@ -411,12 +420,16 @@ class BASISReduction(PythonAlgorithm):
                 kwargs = {"BankName": "bank2"}  # 311 analyzers only in bank2
             else:
                 kwargs = {}
+
             sapi.LoadEventNexus(Filename=run_file,
                                 OutputWorkspace=ws_name, **kwargs)
+            if str(run)+':' in self.getProperty("ExcludeTimeSegment").value:
+                self._filterEvents(str(run), ws_name)
 
             if not self._noMonNorm:
                 sapi.LoadNexusMonitors(Filename=run_file,
                                        OutputWorkspace=mon_ws_name)
+
             if sam_ws != ws_name:
                 sapi.Plus(LHSWorkspace=sam_ws,
                           RHSWorkspace=ws_name,
@@ -560,6 +573,53 @@ class BASISReduction(PythonAlgorithm):
                    Factor=1./maximumYvalue,
                    Operation="Multiply")
 
+    def generateSplitterWorkspace(self, fragment):
+        r"""Create a table workspace with time intervals to keep
+
+        Parameters
+        ----------
+        fragment: str
+            a-b  start and end of time fragment to filter out
+        """
+        inf = 86400  # a run a full day long
+        a, b = fragment.split('-')
+        b = inf if 'end' in b else float(b)
+        a = float(a)
+        splitter = sapi.CreateEmptyTableWorkspace(OutputWorkspace='splitter')
+        splitter.addColumn('double', 'start')
+        splitter.addColumn('double', 'stop')
+        splitter.addColumn('str', 'target') #, 'str')
+        if a == 0.0:
+            splitter.addRow([b, inf, '0'])
+        elif b == inf:
+            splitter.addRow([0, a, '0'])
+        else:
+            splitter.addRow([0, a, '0'])
+            splitter.addRow([b, inf, '0'])
+
+    def _filterEvents(self, run, ws_name):
+        r"""Filter out ExcludeTimeSegment if applicable
+
+        Parameters
+        ----------
+        run: str
+            run number
+        ws_name : str
+            name of the workspace to filter
+        """
+        for run_fragment in self.getProperty("ExcludeTimeSegment").value.split(';'):
+            if run+':' in run_fragment:
+                self.generateSplitterWorkspace(run_fragment.split(':')[1])
+                sapi.FilterEvents(InputWorkspace=ws_name,
+                                  SplitterWorkspace='splitter',
+                                  OutputWorkspaceBaseName='splitted',
+                                  GroupWorkspaces=True,
+                                  OutputWorkspaceIndexedFrom1=True,
+                                  RelativeTime=True)
+                sapi.UnGroupWorkspace('splitted')
+                sapi.RenameWorkspace(InputWorkspace='splitted_0',
+                                     OutputWorkspace=ws_name)
+                break
 
 # Register algorithm with Mantid.
 AlgorithmFactory.subscribe(BASISReduction)
diff --git a/Framework/TestHelpers/inc/MantidTestHelpers/FakeObjects.h b/Framework/TestHelpers/inc/MantidTestHelpers/FakeObjects.h
index 981e8b10e3ffc36189178d57a81365c629dcab70..14b0eebabb29782941ff494c58c9a9b43df5cb5f 100644
--- a/Framework/TestHelpers/inc/MantidTestHelpers/FakeObjects.h
+++ b/Framework/TestHelpers/inc/MantidTestHelpers/FakeObjects.h
@@ -54,6 +54,10 @@ public:
     m_histogram.setCountStandardDeviations(0);
   }
 
+  void copyDataFrom(const ISpectrum &other) override {
+    other.copyDataInto(*this);
+  }
+
   void setX(const Mantid::Kernel::cow_ptr<Mantid::HistogramData::HistogramX> &X)
       override {
     m_histogram.setX(X);
@@ -93,6 +97,11 @@ protected:
   Mantid::HistogramData::Histogram m_histogram;
 
 private:
+  using ISpectrum::copyDataInto;
+  void copyDataInto(SpectrumTester &other) const override {
+    other.m_histogram = m_histogram;
+  }
+
   const Mantid::HistogramData::Histogram &histogramRef() const override {
     return m_histogram;
   }
diff --git a/MantidPlot/CMakeLists.txt b/MantidPlot/CMakeLists.txt
index c7567758772821a19898000ac909536187c63749..e6517ffbf7693059adcd26e79bbfda79de158722 100644
--- a/MantidPlot/CMakeLists.txt
+++ b/MantidPlot/CMakeLists.txt
@@ -824,6 +824,8 @@ if (OSX_VERSION VERSION_GREATER 10.8)
   set_target_properties(MantidPlot PROPERTIES INSTALL_RPATH "@executable_path;@executable_path/../Libraries")
 endif ()
 
+set_target_properties ( MantidPlot PROPERTIES FOLDER "Qt4" )
+
 ###########################################################################
 # Custom Info.plist file for OS X
 ###########################################################################
diff --git a/buildconfig/CMake/Bootstrap.cmake b/buildconfig/CMake/Bootstrap.cmake
index 6027149ee4ae214be7acd6eb77c1fee16185146a..d927789189a04c9ed68379f9a25e0b25789bd047 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 CACHE PATH "Location to clone third party dependencies to" )
   set( THIRD_PARTY_GIT_URL "https://github.com/mantidproject/thirdparty-msvc2015.git" )
-  set ( THIRD_PARTY_GIT_SHA1 9af2288ba00e184b8659edbeedb12ce771b87bb5 )
+  set ( THIRD_PARTY_GIT_SHA1 ef72b6d824ff2df21cca80c87b565136cc4020aa )
   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/FindPyUnitTest.cmake b/buildconfig/CMake/FindPyUnitTest.cmake
index 07a701f6e99ab44444b5fc946e7c5eb89544f0cf..9bfc279dca311adcce015b4edb2496a8d1a7179a 100644
--- a/buildconfig/CMake/FindPyUnitTest.cmake
+++ b/buildconfig/CMake/FindPyUnitTest.cmake
@@ -2,7 +2,9 @@
 # PYUNITTEST_ADD_TEST (public macro to add unit tests)
 #   Adds a set of python tests based upon the unittest module
 #   Parameters:
-#       _test_src_dir :: The directory where the src files reside
+#       _test_src_dir_base :: A base directory when added to the relative test paths gives
+#                             an absolute path to that test. This directory is added to the
+#                             PYTHONPATH when tests are executed
 #       _testname_prefix :: A prefix for each test that is added to ctest, the name will be
 #                           ${_testname_prefix}_TestName
 #       ${ARGN} :: List of test files
@@ -10,7 +12,7 @@ function ( PYUNITTEST_ADD_TEST _test_src_dir _testname_prefix )
   # Property for the module directory
   set ( _working_dir ${CMAKE_BINARY_DIR}/bin/Testing )
   if ( CMAKE_GENERATOR MATCHES "Visual Studio" OR CMAKE_GENERATOR MATCHES "Xcode" )
-    set ( _module_dir ${CMAKE_BINARY_DIR}/bin/$<CONFIGURATION> )
+    set ( _module_dir ${CMAKE_BINARY_DIR}/bin/$<CONFIG> )
   else()
     set ( _module_dir ${CMAKE_BINARY_DIR}/bin )
   endif()
@@ -18,18 +20,27 @@ function ( PYUNITTEST_ADD_TEST _test_src_dir _testname_prefix )
   if ( WIN32 )
     set ( _test_runner ${_test_runner}.bat )
   endif ()
+  set ( _test_runner_module ${CMAKE_SOURCE_DIR}/Framework/PythonInterface/test/testhelpers/testrunner.py )
+  # Environment
+  if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
+    set ( _python_path ${PYTHON_XMLRUNNER_DIR};${_test_src_dir};$ENV{PYTHONPATH} )
+    # cmake list separator and Windows environment seprator are the same so escape the cmake one
+    string ( REPLACE ";" "\\;" _python_path "${_python_path}" )
+  else()
+    set ( _python_path ${PYTHON_XMLRUNNER_DIR}:${_test_src_dir}:$ENV{PYTHONPATH} )
+  endif()
 
   # Add all of the individual tests so that they can be run in parallel
   foreach ( part ${ARGN} )
-    get_filename_component( _filename ${part} NAME )
+    set ( _filename ${part} )
     get_filename_component( _suitename ${part} NAME_WE )
     # We duplicate the suitename so that it matches the junit output name
     set ( _pyunit_separate_name "${_testname_prefix}.${_suitename}.${_suitename}" )
     add_test ( NAME ${_pyunit_separate_name}
-               COMMAND ${_test_runner} --classic -m testhelpers.testrunner ${_test_src_dir}/${_filename} )
+               COMMAND ${_test_runner} --classic ${_test_runner_module} ${_test_src_dir}/${_filename} )
     # Set the PYTHONPATH so that the built modules can be found
     set_tests_properties ( ${_pyunit_separate_name} PROPERTIES
-                           ENVIRONMENT PYTHONPATH=${PYTHON_XMLRUNNER_DIR}
+                           ENVIRONMENT "PYTHONPATH=${_python_path}"
                            WORKING_DIRECTORY ${_working_dir}
                            TIMEOUT ${TESTING_TIMEOUT} )
   endforeach ( part ${ARGN} )
diff --git a/buildconfig/CMake/PythonTargetFunctions.cmake b/buildconfig/CMake/PythonTargetFunctions.cmake
deleted file mode 100644
index f8cb5151614eaaaef5dfa11a56a47852f8284e6c..0000000000000000000000000000000000000000
--- a/buildconfig/CMake/PythonTargetFunctions.cmake
+++ /dev/null
@@ -1,36 +0,0 @@
-# Utility functions to add targets that "build" from pure python
-# sources
-
-# Add rules to create a target that will copy and copy the
-# given python sources to a given destination. The file names should
-# be given without any directory prefix, e.g
-#
-#   set ( SRCS
-#     __init__.py
-#   )
-#   add_python_package ( TARGET_NAME mypkg
-#     SRCS ${SRCS}
-#     OUTPUT_DIR ${CMAKE_BINARY_DIR}/bin/mypkg
-#   )
-#
-# will produce a directory in the specified location containing the listed
-# files.
-#
-# Arguments:
-#   TARGET_NAME: The name of the target
-#   OUTPUT_DIR: The directory for the copied and compiled files
-#   SRCS: A list of python source files for this package
-function (add_python_package)
-  set (options)
-  set (oneValueArgs TARGET_NAME OUTPUT_DIR)
-  set (multiValueArgs SRCS)
-  cmake_parse_arguments (PARSED "${options}" "${oneValueArgs}"
-                         "${multiValueArgs}" ${ARGN})
-
-  foreach( _it ${PARSED_SRCS} )
-    get_filename_component( _filename ${_it} NAME_WE )
-    set ( _pyc ${_filename}.pyc )
-    add_custom_command ( OUTPUT )
-  endforeach()
-  add_custom_target ( ${PARSED_TARGET_NAME} )
-endfunction ()
diff --git a/buildconfig/CMake/QtTargetFunctions.cmake b/buildconfig/CMake/QtTargetFunctions.cmake
index d33dde593531a9db7e5e1cd7c0a67cd9db5a99f2..f7e4ee530cc0947c8200ce1a1ada836eb44f20e7 100644
--- a/buildconfig/CMake/QtTargetFunctions.cmake
+++ b/buildconfig/CMake/QtTargetFunctions.cmake
@@ -188,6 +188,16 @@ function (mtd_add_qt_target)
     endif()
     install ( TARGETS ${_target} ${SYSTEM_PACKAGE_TARGET} DESTINATION ${_install_dir} )
   endif()
+
+  # Group into folder for VS
+  set_target_properties ( ${_target} PROPERTIES FOLDER "Qt${PARSED_QT_VERSION}" )
+  # Target encompassing all Qt-based dependencies
+  set ( _alltarget "AllQt${PARSED_QT_VERSION}" )
+  if ( TARGET ${_alltarget} )
+    add_dependencies ( ${_alltarget} ${_target} )
+  else ()
+    add_custom_target ( ${_alltarget} DEPENDS ${_target} )
+  endif()
 endfunction()
 
 function (mtd_add_qt_tests)
@@ -262,6 +272,11 @@ function (mtd_add_qt_test_executable)
   foreach (_dep ${PARSED_PARENT_DEPENDENCIES})
     add_dependencies (${_dep} ${_target_name})
   endforeach()
+
+  # set folder
+  if ( CMAKE_GENERATOR MATCHES "Visual Studio" )
+    set_target_properties ( ${_target_name} PROPERTIES FOLDER "Qt${PARSED_QT_VERSION}Tests" )
+  endif()
 endfunction ()
 
 # Given a list of arguments decide which Qt versions
diff --git a/buildconfig/CMake/SipQtTargetFunctions.cmake b/buildconfig/CMake/SipQtTargetFunctions.cmake
index 6500d5e9f640fea8d1249224d1cfa36a79c972bd..f3ac6294068d45640e6410455f6709eb929a7a51 100644
--- a/buildconfig/CMake/SipQtTargetFunctions.cmake
+++ b/buildconfig/CMake/SipQtTargetFunctions.cmake
@@ -52,7 +52,7 @@ function ( mtd_add_sip_module )
       -I ${PARSED_SIP_SRC_DIR} -I ${_pyqt_sip_dir}
       ${_pyqt_sip_flags}
       -c ${CMAKE_CURRENT_BINARY_DIR} -j1 -w -e ${_module_spec}
-    DEPENDS ${_module_spec} ${SIP_SRCS} ${PARSED_HEADER_DEPS}
+    DEPENDS ${_module_spec} ${SIP_SRCS} ${PARSED_HEADER_DEPS} ${SIP_INCLUDE_DIR}/sip.h
     COMMENT "Generating ${PARSED_MODULE_NAME} python bindings with sip"
   )
 
diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt
index 458264537c814d20205980504305f74652541c99..3378c933d330532d3f3b6503dd737ee06da57aa3 100644
--- a/docs/CMakeLists.txt
+++ b/docs/CMakeLists.txt
@@ -47,7 +47,7 @@ if ( SPHINX_FOUND )
     add_custom_command ( OUTPUT qthelp/MantidProject.qhcp
                                 qthelp/MantidProject.qhp
                        COMMAND ${DOCS_RUNNER_EXE} -xq runsphinx_qthelp.py
-                       DEPENDS Framework MantidPlot MantidQt ${CMAKE_CURRENT_BINARY_DIR}/runsphinx_qthelp.py
+                       DEPENDS Framework AllQt4 ${CMAKE_CURRENT_BINARY_DIR}/runsphinx_qthelp.py
                        COMMENT "Building qt-assistant index files")
 
     add_custom_command ( OUTPUT qthelp/MantidProject.qhc
@@ -76,7 +76,7 @@ if ( SPHINX_FOUND )
     configure_file ( runsphinx.py.in runsphinx_html.py @ONLY )
     add_custom_target ( ${TARGET_PREFIX}-html
                        COMMAND ${DOCS_RUNNER_EXE} -xq runsphinx_html.py
-                       DEPENDS Framework MantidPlot MantidQt ${CMAKE_CURRENT_BINARY_DIR}/runsphinx_html.py ${SPHINX_CONF_DIR}/conf.py conf-html.py
+                       DEPENDS Framework AllQt4 ${CMAKE_CURRENT_BINARY_DIR}/runsphinx_html.py ${SPHINX_CONF_DIR}/conf.py conf-html.py
                        COMMENT "Building html documentation"
                        )
     # Group within VS and exclude from whole build
@@ -95,7 +95,7 @@ if ( SPHINX_FOUND )
     configure_file ( runsphinx.py.in runsphinx_epub.py @ONLY )
     add_custom_target ( ${TARGET_PREFIX}-epub
                        COMMAND ${DOCS_RUNNER_EXE} -xq runsphinx_epub.py
-                       DEPENDS Framework MantidPlot MantidQt ${CMAKE_CURRENT_BINARY_DIR}/runsphinx_epub.py ${SPHINX_CONF_DIR}/conf.py                        COMMENT "Building html documentation"
+                       DEPENDS Framework AllQt4 ${CMAKE_CURRENT_BINARY_DIR}/runsphinx_epub.py ${SPHINX_CONF_DIR}/conf.py                        COMMENT "Building html documentation"
                        )
     # Group within VS and exclude from whole build
     set_target_properties ( ${TARGET_PREFIX}-epub PROPERTIES FOLDER "Documentation"
@@ -112,7 +112,7 @@ if ( SPHINX_FOUND )
   configure_file ( runsphinx.py.in runsphinx_linkcheck.py @ONLY )
   add_custom_target ( ${TARGET_PREFIX}-linkcheck
                       COMMAND ${DOCS_RUNNER_EXE} -xq runsphinx_linkcheck.py
-                      DEPENDS Framework MantidPlot MantidQt ${CMAKE_CURRENT_BINARY_DIR}/runsphinx_linkcheck.py ${SPHINX_CONF_DIR}/conf.py
+                      DEPENDS Framework AllQt4 ${CMAKE_CURRENT_BINARY_DIR}/runsphinx_linkcheck.py ${SPHINX_CONF_DIR}/conf.py
                       COMMENT "Checking documentation links"
                       )
   # Group within VS and exclude from whole build
@@ -135,7 +135,7 @@ if ( SPHINX_FOUND )
   configure_file ( runsphinx.py.in runsphinx_doctest.py @ONLY )
   add_custom_target ( ${TARGET_PREFIX}-test
     COMMAND ${DOCS_RUNNER_EXE} -xq runsphinx_doctest.py
-    DEPENDS Framework MantidPlot ${CMAKE_CURRENT_BINARY_DIR}/runsphinx_doctest.py
+    DEPENDS Framework AllQt4 ${CMAKE_CURRENT_BINARY_DIR}/runsphinx_doctest.py
             ${SPHINX_CONF_DIR}/conf.py
     COMMENT "Running documentation tests"
   )
diff --git a/docs/source/algorithms/BASISReduction-v1.rst b/docs/source/algorithms/BASISReduction-v1.rst
index 8fe53f129b319b87ce7d65630b49eaeff1827296..93dc4a8b287f91f860bd693e02ee020b9ce650cb 100644
--- a/docs/source/algorithms/BASISReduction-v1.rst
+++ b/docs/source/algorithms/BASISReduction-v1.rst
@@ -27,6 +27,17 @@ Examples:
 If *DoIndividual* is checked, then each run number is reduced separately
 from the rest. The semicolon symbol is ignored.
 
+**ExcludeTimeSegment**:
+Events happening in a time segment with no proton charge are most likely
+noise. Those events can be filtered out of the reduction process.
+
+Example:
+
+- "71465:0-500;71466:900-2100;71467:4000-end" will filter out events
+  happening between the start of the run and 500 seconds for run 71465, then
+  between 900 and 2100 seconds for run 71466 and between 4000 seconds and the
+  end of the run for 71467. Only one time segment can be excluded per run number.
+
 **Momentum transfer binning scheme**: Three values are required, the
 center of the bin with the minimum momentum, the bin width, and the
 center of the bin with the maximum momentum.
@@ -132,4 +143,3 @@ Workflow
 --------
 
 .. diagram:: BASISReduction-v1_wkflw.dot
-
diff --git a/docs/source/algorithms/CalculatePolynomialBackground-v1.rst b/docs/source/algorithms/CalculatePolynomialBackground-v1.rst
index 56d052de6697a9bb1b02acd7872218dd24ba0f13..4887185a85b59e06f4367d95b6008ed308fefab5 100644
--- a/docs/source/algorithms/CalculatePolynomialBackground-v1.rst
+++ b/docs/source/algorithms/CalculatePolynomialBackground-v1.rst
@@ -12,6 +12,8 @@ Description
 
 This algorithm calculates backgrounds for the histograms in a workspace by fitting a polynomial to ranges given by *XRanges*. The fitting is done using :ref:`algm-Fit`. The backgrounds are returned as the *OutputWorkspace* which can be subsequently subtracted from the original workspace. The degree of the polynomial can be given by *Degree*. A zeroth degree polynomial would correspond to fitting a constant value. The *XRanges* property is a list of range start and range end value pairs in the X axis units. Overlapping ranges are merged. If no *XRanges* are given, full histograms are used.
 
+The value of *CostFunction* is passed to :ref:`algm-Fit` as-is. The default option is 'Least squares' which uses the histogram errors as weights. This might not be desirable, e.g. when there are bins with zero counts and zero errors. An 'Unweighted least squares' option is available to deal with such cases.
+
 Usage
 -----
 
diff --git a/docs/source/algorithms/HyspecScharpfCorrection-v1.rst b/docs/source/algorithms/HyspecScharpfCorrection-v1.rst
new file mode 100644
index 0000000000000000000000000000000000000000..dff4da2f7ebdbc2bd781e5d2f629a935976257f1
--- /dev/null
+++ b/docs/source/algorithms/HyspecScharpfCorrection-v1.rst
@@ -0,0 +1,108 @@
+
+.. algorithm::
+
+.. summary::
+
+.. alias::
+
+.. properties::
+
+Description
+-----------
+
+This algorithm is applying a polarization correction for single crystal
+inelastic experiments. If one measures scattering intensity with polarization 
+along the momentum transfer  :math:`Q`, perpendicular to it in the horizontal 
+plane, and in the vertical direction, one can write the spin incoherent 
+contribution as:
+
+.. math::
+    
+    I_{SI}=\frac{3}{2}\left(\Sigma_x^{nsf}-\Sigma_y^{nsf}+\Sigma_z^{sf}\right)
+    
+where the *sf* and *nsf* subscripts stand for spin flip and non-spin flip.
+The *x* direction is parallel to :math:`Q`, *y* is perpendicular in the horizontal
+plane, while *z* is vertically up. **NOTE**: this is not the Mantid convention.
+
+However, for instruments with multiple detectors and using time of flight
+neutrons, one has a constantly varying angle between :math:`Q` and polarization.
+If we call this angle  :math:`\alpha` (Scharpf angle), the above equation can
+be written as:
+
+.. math::
+    
+    I_{SI}=\frac{3}{2}\left(\frac{\Sigma_{x'}^{nsf}-\Sigma_{y'}^{nsf}}{\cos^2\alpha-\sin^2\alpha}\right)+\frac{3}{2}\Sigma_z^{sf}
+
+This algorithm calculates the Scharpf angle for every event or energy transfer bin,
+then divides the intensity by :math:`F=\cos^2\alpha-\sin^2\alpha=\cos(2\alpha)`. 
+In places where *F* is less than the `Precision`, the intensity of the output workspace is set to 0.
+
+For a detector at angle :math:`\theta` in the horizontal plane, the angle
+between :math:`Q` and :math:`k_i` is given by
+
+.. math::
+    
+    \gamma=\arctan2\left(-\frac{k_f}{k_i}\sin\theta, 1-\frac{k_f}{k_i}\cos\theta\right)
+    
+The Scharpf angle is then:
+
+.. math::
+    \alpha = \gamma- PolarizationAngle
+ 
+.. Note::
+
+    This algorithm assumes that all scattering is in the horizontal plane (good enough approximation
+    for Hyspec instrument, in polarized mode).
+    
+For more information, see 
+
+#. Werner Schweika - *XYZ-polarisation analysis of diffuse magnetic neutron scattering from single crystals*, Journal of Physics: Conference Series, **211**,012026, (2010) doi: `10.1088/1742-6596/211/1/012026 <http://dx.doi.org/10.1088/1742-6596/211/1/012026>`_
+  
+
+
+Usage
+-----
+
+**Example - HyspecScharpfCorrection**
+
+.. testcode:: HyspecScharpfCorrectionExample
+
+   # Create a workspace (NXSPE equivalent)
+   w = CreateSampleWorkspace(Function='Flat background', NumBanks=1, 
+                             BankPixelWidth=1, XUnit='DeltaE',
+                             XMin=-10.25, XMax=20, BinWidth=0.5)
+   MoveInstrumentComponent(Workspace=w, ComponentName='bank1', X=3, Z=3, RelativePosition=False)
+   AddSampleLog(Workspace=w,LogName='Ei', LogText='17.1', LogType='Number')
+
+   wsOut = HyspecScharpfCorrection(InputWorkspace=w,
+                                   PolarizationAngle=-10,
+                                   Precision=0.2)
+
+   # Get the data
+   intensity = wsOut.readY(0)
+   bin_boundaries = wsOut.readX(0)
+   energy_transfer = 0.5*(bin_boundaries[1:]+bin_boundaries[:-1])
+   # at DeltaE=5meV, Q makes an angle of 55.7 degrees with incident beam
+   # If polarization angle is -10 degrees, the intensity should be 0
+   # Below this energy, the Scharpf angle correction is negative, above
+   # is positive. If energy transfer is greater than Ei, intensity is
+   # set to 0 
+   print('Intensity at DeltaE= 0meV: {0:.2f}'.format((intensity[energy_transfer==0])[0]))
+   print('Intensity at DeltaE= 5meV: {0:.2f}'.format((intensity[energy_transfer==5])[0]))
+   print('Intensity at DeltaE=10meV: {0:.2f}'.format((intensity[energy_transfer==10])[0]))
+   print('Intensity at DeltaE=19meV: {0:.2f}'.format((intensity[energy_transfer==19])[0]))
+
+
+Output:
+
+.. testoutput:: HyspecScharpfCorrectionExample
+
+  Intensity at DeltaE= 0meV: -2.37
+  Intensity at DeltaE= 5meV: 0.00
+  Intensity at DeltaE=10meV: 1.99
+  Intensity at DeltaE=19meV: 0.00
+  
+.. categories::
+
+.. sourcelink::
+
diff --git a/docs/source/development/AlgorithmMPISupport.rst b/docs/source/development/AlgorithmMPISupport.rst
index 06d5ee74fdbab6eaa2725dd81db3aeb43169b6f4..13cc17ab6d1e3d607eab08c4a4833d009a9958ea 100644
--- a/docs/source/development/AlgorithmMPISupport.rst
+++ b/docs/source/development/AlgorithmMPISupport.rst
@@ -266,8 +266,8 @@ In that case the execution mode can simply be determined from the input workspac
 Here the helper ``Parallel::getCorrespondingExecutionMode`` is used to obtain the 'natural' execution mode from a storage mode, i.e., ``ExecutionMode::Identical`` for ``StorageMode::Cloned``, ``ExecutionMode::Distributed`` for ``StorageMode::Distributed``, and ``ExecutionMode::MasterOnly`` for ``StorageMode::MasterOnly``.
 More complex algorithms may require more complex decision mechanism, e.g., when there is more than one input workspace.
 
-For many algorithms the base class ``API::TriviallyParallelAlgorithm`` provides a sufficient default implementation of ``Algorithm::getParallelExecutionMode()``.
-MPI support can simply be enabled by inheriting from ``TriviallyParallelAlgorithm`` instead of from ``Algorithm``.
+For many algorithms the base class ``API::ParallelAlgorithm`` provides a sufficient default implementation of ``Algorithm::getParallelExecutionMode()``.
+MPI support can simply be enabled by inheriting from ``ParallelAlgorithm`` instead of from ``Algorithm``.
 Generally this works only for algorithms with a single input and a single output that either process only non-spectrum data or process all spectra independently.
 
 If none of the other virtual methods listed above is implemented, ``Algorithm`` will run the normal ``exec()`` method on all MPI ranks.
@@ -456,6 +456,9 @@ Algorithm         Supported modes Comments
 ================= =============== ========
 CompressEvents    all
 CreateWorkspace   all
+CropWorkspace     all             see ExtractSpectra regarding X cropping
+ExtractSpectra2   all             currently not available via algorithm factory or Python
+ExtractSpectra    all             not supported with ``DetectorList``, cropping in X may exhibit inconsistent behavior in case spectra have common boundaries within some ranks but not within all ranks or across ranks
 FilterBadPulses   all
 FilterByLogValue  all
 LoadEventNexus    Distributed     storage mode of output cannot be changed via a parameter currently, min and max bin boundary are not globally the same
@@ -468,6 +471,8 @@ RemovePromptPulse all
 SortEvents        all
 ================= =============== ========
 
+Currently none of the above algorithms works with ``StorageMode::Distributed`` in case there are zero spectra on any rank.
+
 .. rubric:: Footnotes
 
 .. [#split-instrument] The complexity and overhead of splitting the instrument, in particular given the overhead ensuing from handling all cases exemplified above, led to the decision split only the neutron data based on spectra, but not detectors.
diff --git a/docs/source/release/v3.12.0/diffraction.rst b/docs/source/release/v3.12.0/diffraction.rst
index 79174ecb3939e6ada94c7ff15821a054b6fecc3b..967c8a6e5b59a730b92dd8230123218c22cd310a 100644
--- a/docs/source/release/v3.12.0/diffraction.rst
+++ b/docs/source/release/v3.12.0/diffraction.rst
@@ -37,4 +37,10 @@ Single Crystal Diffraction
 Imaging
 -------
 
+Features Removed
+----------------
+
+* The "Test the Curve Fit widget" graphical interface has been removed, it was a test harness for developers and was not intended to be exposed during earlier releases.
+
+
 :ref:`Release 3.12.0 <v3.12.0>`
diff --git a/docs/source/release/v3.12.0/framework.rst b/docs/source/release/v3.12.0/framework.rst
index 6b9e84934a55dcd01114f7af196ae37a089f3bb1..6453e06fc3f81b8fc841b1fb3bc5e10e075ee190 100644
--- a/docs/source/release/v3.12.0/framework.rst
+++ b/docs/source/release/v3.12.0/framework.rst
@@ -23,6 +23,7 @@ Algorithms
 ----------
 
 :ref:`NormaliseToMonitor <algm-NormaliseToMonitor>` now supports workspaces with detector scans and workspaces with single-count point data.
+- It is now possible to choose between weighted and unweighted fitting in :ref:`CalculatePolynomialBackground <algm-CalculatePolynomialBackground>`.
 - :ref:`CreateWorkspace <algm-CreateWorkspace>` will no longer create a default (and potentially wrong) mapping from spectra to detectors, unless a parent workspace is given. This change ensures that accidental bad mappings that could lead to corrupted data are not created silently anymore. This change does *not* affect the use of this algorithm if: (1) a parent workspace is given, or (2) no instrument is loaded into to workspace at a later point, or (3) an instrument is loaded at a later point but ``LoadInstrument`` is used with ``RewriteSpectraMapping=True``. See also the algorithm documentation for details.
 - :ref:`ConjoinWorkspaces <algm-ConjoinWorkspaces>` now supports non-constant bins.
 - :ref:`Fit <algm-Fit>` will now respect excluded ranges when ``CostFunction = 'Unweighted least squares'``.
diff --git a/docs/source/release/v3.12.0/indirect_inelastic.rst b/docs/source/release/v3.12.0/indirect_inelastic.rst
index 6759792bee11b44c4a2c2cfa8e89ca33c6649c2c..140f023bac9f6d69e129dee8d130d2097f31283d 100644
--- a/docs/source/release/v3.12.0/indirect_inelastic.rst
+++ b/docs/source/release/v3.12.0/indirect_inelastic.rst
@@ -14,6 +14,8 @@ New
 Improved
 ########
 
+- BASISReduction now permits the user to exclude a contiguous time segment from the reduction process
+
 Vesuvio
 -------
 
diff --git a/docs/source/release/v3.12.0/spectroscopy.rst b/docs/source/release/v3.12.0/spectroscopy.rst
index 7ec4f715360f51b3de20aa1590ec1ee55aef1760..7f0a85f4d3c8309443b69c0b004ad2f408a50da2 100644
--- a/docs/source/release/v3.12.0/spectroscopy.rst
+++ b/docs/source/release/v3.12.0/spectroscopy.rst
@@ -12,6 +12,7 @@ Spectroscopy Changes
 Direct Geometry
 ---------------
 
+- New algorithm :ref:`HyspecScharpfCorrection <algm-HyspecScharpfCorrection-v1>` that can be used to calculate spin incoherent scattering from polarized neutron data
 - TOFTOF data reduction GUI has been improved. In the new version it has options to delete intermediate workspaces, to replace NaNs in S(Q,W), to create diffractograms and to save the reduced data in NXSPE and NeXus format.
 
 Indirect Geometry
@@ -19,4 +20,4 @@ Indirect Geometry
 
 - New algorithm :ref:`BASISDiffraction <algm-BASISDiffraction-v1>` to determine the orientation of crystal samples for the BASIS beamline.
 
-:ref:`Release 3.12.0 <v3.12.0>`
\ No newline at end of file
+:ref:`Release 3.12.0 <v3.12.0>`
diff --git a/qt/CMakeLists.txt b/qt/CMakeLists.txt
index 3189ce2ebb43188657aebbfbc3c78f6d51c03503..f32ea2d43b601759de7fee94d1e408599e404bc2 100644
--- a/qt/CMakeLists.txt
+++ b/qt/CMakeLists.txt
@@ -4,7 +4,7 @@
 find_package ( QScintillaQt4 REQUIRED )
 
 # Utilities for defining targets
-include (QtTargetFunctions)
+include ( QtTargetFunctions )
 
 add_subdirectory ( widgets )
 add_subdirectory ( python )
@@ -12,32 +12,3 @@ add_subdirectory ( scientific_interfaces )
 if ( MAKE_VATES )
   add_subdirectory ( paraview_ext )
 endif ( MAKE_VATES )
-
-###########################################################################
-# Add a custom target to build all of the MantidQt packages
-###########################################################################
-
-if ( MSVC_IDE )
-#  # Add to the 'MantidQt' group in VS
-  set_property ( TARGET MantidQtWidgetsCommonQt4 PROPERTY FOLDER "MantidQt" )
-  set_property ( TARGET MantidQtWidgetsLegacyQwtQt4 PROPERTY FOLDER "MantidQt" )
-  set_property ( TARGET MantidQtWidgetsFactoryQt4 PROPERTY FOLDER "MantidQt" )
-  set_property ( TARGET MantidQtWidgetsInstrumentViewQt4 PROPERTY FOLDER "MantidQt" )
-  set_property ( TARGET MantidQtWidgetsRefDetectorViewQt4 PROPERTY FOLDER "MantidQt" )
-  set_property ( TARGET MantidQtWidgetsSliceViewerQt4 PROPERTY FOLDER "MantidQt" )
-  set_property ( TARGET MantidQtWidgetsSpectrumViewerQt4 PROPERTY FOLDER "MantidQt" )
-  set_property ( TARGET MantidQtWidgetsPluginsDesignerQt4 PROPERTY FOLDER "MantidQt" )
-  set_property ( TARGET MantidQtWidgetsPluginsAlgorithmDialogsQt4 PROPERTY FOLDER "MantidQt" )
-  set_property ( TARGET mantidqtpython PROPERTY FOLDER "MantidQt" )
-else ()
-  add_custom_target ( MantidQt DEPENDS MantidQtWidgetsCommonQt4
-     MantidQtWidgetsLegacyQwtQt4
-     MantidQtWidgetsFactoryQt4
-     MantidQtWidgetsInstrumentViewQt4
-     MantidQtWidgetsSliceViewerQt4
-     MantidQtWidgetsSpectrumViewerQt4
-     MantidQtWidgetsRefDetectorViewQt4
-     MantidQtWidgetsPluginsAlgorithmDialogsQt4
-     mantidqtpython
-  )
-endif ()
diff --git a/qt/python/CMakeLists.txt b/qt/python/CMakeLists.txt
index 7e9a393f5e028b6bc87aac2ee9a55e94ea939c9a..d8ae39214d00fa852f081fc9e32e00a3e8bd99cf 100644
--- a/qt/python/CMakeLists.txt
+++ b/qt/python/CMakeLists.txt
@@ -1,2 +1,18 @@
+# This file manages building/installation of the mantidqt and mantidqtpython
+# Python wrappers.
+#
+
 # Legacy wrappers for MantidPlot
 add_subdirectory ( mantidqtpython )
+
+# mantidqt is run from the source directory so just add tests
+set ( PYTHON_TEST_FILES
+  mantidqt/test/import_test.py
+)
+
+# Tests
+pyunittest_add_test ( ${CMAKE_CURRENT_SOURCE_DIR}
+  mantidqt ${PYTHON_TEST_FILES}
+)
+
+# No package installation yet...
diff --git a/qt/python/mantidqt/__init__.py b/qt/python/mantidqt/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..fa2759b174eda6295744b9b70988c80551ca6df6
--- /dev/null
+++ b/qt/python/mantidqt/__init__.py
@@ -0,0 +1,22 @@
+#  This file is part of the mantidqt package
+#
+#  Copyright (C) 2017 mantidproject
+#
+#  This program 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.
+#
+#  This program 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/>.
+""" A collection of Qt widgets and functionality common to many
+Mantid-based applications/interfaces.
+"""
+
+# This file should be left free of PyQt imports to allow quick importing
+# of the main package.
diff --git a/qt/python/mantidqt/test/import_test.py b/qt/python/mantidqt/test/import_test.py
new file mode 100644
index 0000000000000000000000000000000000000000..672afdaaf1ff83ca644c112f0badebeb1557854e
--- /dev/null
+++ b/qt/python/mantidqt/test/import_test.py
@@ -0,0 +1,12 @@
+from __future__ import (absolute_import, division, print_function,
+                        unicode_literals)
+
+import unittest
+
+class ImportTest(unittest.TestCase):
+
+    def test_import(self):
+        import mantidqt # noqa
+
+if __name__ == "__main__":
+    unittest.main()
diff --git a/qt/python/mantidqtpython/CMakeLists.txt b/qt/python/mantidqtpython/CMakeLists.txt
index 96a1ae717769629f01673d87b3e15f4465ae5129..9b75792fa65d1b9814d250a88ac30c92a5e4b08e 100644
--- a/qt/python/mantidqtpython/CMakeLists.txt
+++ b/qt/python/mantidqtpython/CMakeLists.txt
@@ -95,7 +95,7 @@ mtd_add_sip_module (
     Qt4::QtOpenGL
     Qwt5
     ${PYTHON_LIBRARIES}
-  FOLDER MantidQt4
+  FOLDER Qt4
 )
 
 if ( MSVC )
diff --git a/qt/scientific_interfaces/DynamicPDF/CMakeLists.txt b/qt/scientific_interfaces/DynamicPDF/CMakeLists.txt
index 91366ed47ed97205bb7a955bc509cbb3e6a60cac..44b0c90ddc870dbf622dedd3d738145d57a67375 100644
--- a/qt/scientific_interfaces/DynamicPDF/CMakeLists.txt
+++ b/qt/scientific_interfaces/DynamicPDF/CMakeLists.txt
@@ -5,7 +5,6 @@ set ( SRC_FILES
 	DPDFFitOptionsBrowser.cpp
 	DPDFFourierTransform.cpp
 	DPDFInputDataControl.cpp
-	DisplayCurveFitTest.cpp
 	SliceSelector.cpp
 )
 
@@ -19,12 +18,10 @@ set ( INC_FILES
 	DPDFFitOptionsBrowser.h
 	DPDFFourierTransform.h
 	DPDFInputDataControl.h
-	DisplayCurveFitTest.h
 	SliceSelector.h
 )
 
-set ( MOC_FILES
-    DisplayCurveFitTest.h
+set ( MOC_FILES 
     DPDFBackgroundRemover.h
     DPDFDisplayControl.h
     DPDFFitControl.h
@@ -34,8 +31,8 @@ set ( MOC_FILES
     SliceSelector.h
 )
 
-set ( UI_FILES
-    DisplayCurveFitTest.ui
+
+set ( UI_FILES 
     DPDFBackgroundRemover.ui
     DPDFFitControl.ui
     DPDFFourierTransform.ui
@@ -68,8 +65,3 @@ mtd_add_qt_library (TARGET_NAME MantidScientificInterfacesDynamicPDF
   OSX_INSTALL_RPATH
     @loader_path/../../Contents/MacOS
 )
-
-if ( MSVC_IDE )
-  # Add to the 'ScientificInterfaces' group in VS
-  set_property ( TARGET MantidScientificInterfacesDynamicPDFQt4 PROPERTY FOLDER "ScientificInterfaces" )
-endif()
diff --git a/qt/scientific_interfaces/DynamicPDF/DisplayCurveFitTest.cpp b/qt/scientific_interfaces/DynamicPDF/DisplayCurveFitTest.cpp
deleted file mode 100644
index 542dab3e167a3f8fab629c0850e4be8ed9d8709e..0000000000000000000000000000000000000000
--- a/qt/scientific_interfaces/DynamicPDF/DisplayCurveFitTest.cpp
+++ /dev/null
@@ -1,106 +0,0 @@
-#include "DisplayCurveFitTest.h"
-// includes for workspace handling
-#include "MantidAPI/AnalysisDataService.h"
-#include "MantidAPI/MatrixWorkspace.h"
-// includes for interface functionality
-#include "MantidQtWidgets/LegacyQwt/DisplayCurveFit.h"
-#include "MantidQtWidgets/LegacyQwt/RangeSelector.h"
-
-namespace {
-Mantid::Kernel::Logger g_log("DynamicPDF");
-}
-
-namespace MantidQt {
-namespace CustomInterfaces {
-namespace DynamicPDF {
-
-// Add this class to the list of specialised dialogs in this namespace only if
-// compiling in Debug mode
-//#ifndef NDEBUG
-DECLARE_SUBWINDOW(DisplayCurveFitTest)
-//#endif
-
-using curveType = MantidQt::MantidWidgets::DisplayCurveFit::curveType;
-using dcRange = MantidQt::MantidWidgets::DisplayCurveFit::dcRange;
-
-//           ++++++++++++++++++++++++++++
-//           +++++  Public Members  +++++
-//           ++++++++++++++++++++++++++++
-
-/// Constructor
-DisplayCurveFitTest::DisplayCurveFitTest(QWidget *parent)
-    : UserSubWindow{parent} {}
-
-DisplayCurveFitTest::~DisplayCurveFitTest() {}
-
-/**
- * @brief Initialize the widgets defined within the form generated in
- * Qt-Designer. Also, defined the SIGNALS to SLOTS connections.
- */
-void DisplayCurveFitTest::initLayout() {
-  m_uiForm.setupUi(this);
-  connect(m_uiForm.dataSelector, SIGNAL(dataReady(const QString &)), this,
-          SLOT(loadSpectra(const QString &)));
-}
-
-//           +++++++++++++++++++++++++++
-//           +++++  Private Slots  +++++
-//           +++++++++++++++++++++++++++
-
-/**
- * @brief The test proper that loads the fit curves to be
- * displayed and the two ranges.
- * @param workspaceName the name of the workspace containing
- * the data of the curves to be displayed.
- */
-void DisplayCurveFitTest::loadSpectra(const QString &workspaceName) {
-  auto workspace = Mantid::API::AnalysisDataService::Instance()
-                       .retrieveWS<Mantid::API::MatrixWorkspace>(
-                           workspaceName.toStdString());
-  if (!workspace) {
-    auto title = QString::fromStdString(this->name());
-    auto error =
-        QString::fromStdString("Workspace must be of type MatrixWorkspace");
-    QMessageBox::warning(this, title, error);
-    return;
-  }
-  if (workspace->getNumberHistograms() < 4) {
-    auto title = QString::fromStdString(this->name());
-    auto error = QString("Not enough number of histograms in the workspace");
-    QMessageBox::warning(this, title, error);
-    return;
-  }
-  m_uiForm.displayFit->addSpectrum(curveType::data, workspace, 0);
-  auto curveRange = m_uiForm.displayFit->getCurveRange(curveType::data);
-  static bool firstPass{TRUE};
-
-  // Set up the range selector for the fit
-  m_uiForm.displayFit->addRangeSelector(dcRange::fit);
-  auto rangeSelectorFit = m_uiForm.displayFit->m_rangeSelector.at(dcRange::fit);
-  if (firstPass || m_uiForm.updateRangeSelectors->isChecked()) {
-    rangeSelectorFit->setRange(curveRange.first, curveRange.second);
-    rangeSelectorFit->setMinimum(1.05 * curveRange.first);
-    rangeSelectorFit->setMaximum(0.95 * curveRange.second);
-  }
-
-  // Set up the range evaluate range selector
-  m_uiForm.displayFit->addRangeSelector(dcRange::evaluate);
-  auto rangeSelectorEvaluate =
-      m_uiForm.displayFit->m_rangeSelector.at(dcRange::evaluate);
-  if (firstPass || m_uiForm.updateRangeSelectors->isChecked()) {
-    rangeSelectorEvaluate->setRange(curveRange.first, curveRange.second);
-    rangeSelectorEvaluate->setMinimum(curveRange.first);
-    rangeSelectorEvaluate->setMaximum(curveRange.second);
-  }
-
-  m_uiForm.displayFit->addSpectrum(curveType::fit, workspace, 1);
-  m_uiForm.displayFit->addSpectrum(curveType::residuals, workspace, 2);
-  m_uiForm.displayFit->addSpectrum(curveType::guess, workspace, 3);
-
-  m_uiForm.displayFit->addResidualsZeroline();
-  firstPass = FALSE;
-}
-
-} // namespace MantidQt
-} // namespace CustomInterfaces
-} // namespace DynamicPDF
diff --git a/qt/scientific_interfaces/DynamicPDF/DisplayCurveFitTest.h b/qt/scientific_interfaces/DynamicPDF/DisplayCurveFitTest.h
deleted file mode 100644
index 86e5d8ed7c48fb3f29481bbdcbbe9d4a7140b424..0000000000000000000000000000000000000000
--- a/qt/scientific_interfaces/DynamicPDF/DisplayCurveFitTest.h
+++ /dev/null
@@ -1,65 +0,0 @@
-#ifndef MANTIDQTCUSTOMINTERFACES_DYNAMICPDF_DISPLAYCURVEFITTEST_H_
-#define MANTIDQTCUSTOMINTERFACES_DYNAMICPDF_DISPLAYCURVEFITTEST_H_
-
-// includes for interace functionailty
-#include "DllConfig.h"
-#include "MantidQtWidgets/Common/UserSubWindow.h"
-#include "ui_DisplayCurveFitTest.h"
-
-namespace MantidQt {
-namespace CustomInterfaces {
-namespace DynamicPDF {
-
-/** An interface whose only purpose is to test widget DisplayCurveFit
-  The interface is visible in MantidPlot only when compiled in Debug mode.
-
-  @date 2016-02-22
-
-  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 MANTIDQT_DYNAMICPDF_DLL DisplayCurveFitTest
-    : public MantidQt::API::UserSubWindow {
-  Q_OBJECT
-
-public:
-  /// The name of the interface as registered into the factory
-  static std::string name() { return "Test the DisplayCurveFit widget"; }
-  // This interface's categories.
-  static QString categoryInfo() { return "DynamicPDF"; }
-
-  DisplayCurveFitTest(QWidget *parent = nullptr);
-  ~DisplayCurveFitTest() override;
-
-private slots:
-  void loadSpectra(const QString &workspaceName);
-
-private:
-  void initLayout() override;
-  /// The object containing the widgets defined in the form created in Qt
-  /// Designer
-  Ui::DisplayCurveFitTest m_uiForm;
-
-}; // class DisplayCurveFitTest
-} // namespace CustomInterfaces
-} // namespace DynamicPDF
-} // namespace MantidQt
-#endif // MANTIDQTCUSTOMINTERFACES_DYNAMICPDF_DISPLAYCURVEFITTEST_H_
diff --git a/qt/scientific_interfaces/DynamicPDF/DisplayCurveFitTest.ui b/qt/scientific_interfaces/DynamicPDF/DisplayCurveFitTest.ui
deleted file mode 100644
index b88a6e54bc845f60c557fbf95deee141757016c2..0000000000000000000000000000000000000000
--- a/qt/scientific_interfaces/DynamicPDF/DisplayCurveFitTest.ui
+++ /dev/null
@@ -1,79 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>DisplayCurveFitTest</class>
- <widget class="QMainWindow" name="DisplayCurveFitTest">
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>613</width>
-    <height>740</height>
-   </rect>
-  </property>
-  <property name="sizePolicy">
-   <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
-    <horstretch>0</horstretch>
-    <verstretch>0</verstretch>
-   </sizepolicy>
-  </property>
-  <property name="windowTitle">
-   <string>Dynamic PDF - Test DisplayCurveFit</string>
-  </property>
-  <widget class="QWidget" name="centralwidget">
-   <property name="sizePolicy">
-    <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
-     <horstretch>0</horstretch>
-     <verstretch>0</verstretch>
-    </sizepolicy>
-   </property>
-   <layout class="QVBoxLayout" name="verticalLayout">
-    <item>
-     <widget class="MantidQt::MantidWidgets::DataSelector" name="dataSelector">
-      <property name="sizePolicy">
-       <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
-        <horstretch>0</horstretch>
-        <verstretch>0</verstretch>
-       </sizepolicy>
-      </property>
-     </widget>
-    </item>
-    <item>
-     <widget class="MantidQt::MantidWidgets::DisplayCurveFit" name="displayFit">
-      <property name="sizePolicy">
-       <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
-        <horstretch>0</horstretch>
-        <verstretch>1</verstretch>
-       </sizepolicy>
-      </property>
-     </widget>
-    </item>
-    <item>
-     <layout class="QHBoxLayout" name="horizontalLayout">
-      <item>
-       <widget class="QCheckBox" name="updateRangeSelectors">
-        <property name="text">
-         <string>Update range selectors?</string>
-        </property>
-       </widget>
-      </item>
-     </layout>
-    </item>
-   </layout>
-  </widget>
- </widget>
- <customwidgets>
-  <customwidget>
-   <class>MantidQt::MantidWidgets::DataSelector</class>
-   <extends>QWidget</extends>
-   <header>MantidQtWidgets/Common/DataSelector.h</header>
-  </customwidget>
-  <customwidget>
-   <class>MantidQt::MantidWidgets::DisplayCurveFit</class>
-   <extends>QWidget</extends>
-   <header>MantidQtWidgets/LegacyQwt/DisplayCurveFit.h</header>
-   <container>1</container>
-  </customwidget>
- </customwidgets>
- <resources/>
- <connections/>
-</ui>
diff --git a/qt/scientific_interfaces/EnggDiffraction/CMakeLists.txt b/qt/scientific_interfaces/EnggDiffraction/CMakeLists.txt
index e5e0b3be88254d266056ec745716c1e6405d0117..9981de062e1f80f82a29d8fb2b871eee08abcf4c 100644
--- a/qt/scientific_interfaces/EnggDiffraction/CMakeLists.txt
+++ b/qt/scientific_interfaces/EnggDiffraction/CMakeLists.txt
@@ -70,7 +70,3 @@ mtd_add_qt_library (TARGET_NAME MantidScientificInterfacesEnggDiffraction
     @loader_path/../../plugins/qt4
 )
 
-if ( MSVC_IDE )
-#  # Add to the 'ScientificInterfaces' group in VS
-  set_property ( TARGET MantidScientificInterfacesEnggDiffractionQt4 PROPERTY FOLDER "ScientificInterfaces" )
-endif()
diff --git a/qt/scientific_interfaces/General/CMakeLists.txt b/qt/scientific_interfaces/General/CMakeLists.txt
index 04d87b24ddcc6c48e016bd5335525204ae615e2d..527a2876ce5f98bce4aa6e55f04ebd0a5d916ddc 100644
--- a/qt/scientific_interfaces/General/CMakeLists.txt
+++ b/qt/scientific_interfaces/General/CMakeLists.txt
@@ -63,8 +63,3 @@ mtd_add_qt_library (TARGET_NAME MantidScientificInterfacesGeneral
   OSX_INSTALL_RPATH
     @loader_path/../../Contents/MacOS
 )
-
-if ( MSVC_IDE )
-#  # Add to the 'ScientificInterfaces' group in VS
-  set_property ( TARGET MantidScientificInterfacesGeneralQt4 PROPERTY FOLDER "ScientificInterfaces" )
-endif()
diff --git a/qt/scientific_interfaces/ISISReflectometry/CMakeLists.txt b/qt/scientific_interfaces/ISISReflectometry/CMakeLists.txt
index a08497c63bf51f2237ccaf46e24d2f2b81f8d3e7..7f418e9aa0c0f1c439a9b18e53fccc6c2269d79c 100644
--- a/qt/scientific_interfaces/ISISReflectometry/CMakeLists.txt
+++ b/qt/scientific_interfaces/ISISReflectometry/CMakeLists.txt
@@ -120,8 +120,3 @@ mtd_add_qt_library (TARGET_NAME MantidScientificInterfacesISISReflectometry
   OSX_INSTALL_RPATH
     @loader_path/../../Contents/MacOS
 )
-
-if ( MSVC_IDE )
-#  # Add to the 'ScientificInterfaces' group in VS
-  set_property ( TARGET MantidScientificInterfacesISISReflectometryQt4 PROPERTY FOLDER "ScientificInterfaces" )
-endif()
diff --git a/qt/scientific_interfaces/ISISSANS/CMakeLists.txt b/qt/scientific_interfaces/ISISSANS/CMakeLists.txt
index ca813efd77391f7d4db591050bcb8eff9231b7ca..1a1ef18afcddebbfe3cf7e06da196adb6750f509 100644
--- a/qt/scientific_interfaces/ISISSANS/CMakeLists.txt
+++ b/qt/scientific_interfaces/ISISSANS/CMakeLists.txt
@@ -67,8 +67,3 @@ mtd_add_qt_library (TARGET_NAME MantidScientificInterfacesISISSANS
     @loader_path/../../Contents/MacOS
     @loader_path/../../plugins/qt4
 )
-
-if ( MSVC_IDE )
-#  # Add to the 'ScientificInterfaces' group in VS
-  set_property ( TARGET MantidScientificInterfacesISISSANSQt4 PROPERTY FOLDER "ScientificInterfaces" )
-endif()
diff --git a/qt/scientific_interfaces/Indirect/CMakeLists.txt b/qt/scientific_interfaces/Indirect/CMakeLists.txt
index d65cae357e47891e037a1e97f795a0b36a4e8ef3..500aef356aab3ee169534937fd53f3bc39859357 100644
--- a/qt/scientific_interfaces/Indirect/CMakeLists.txt
+++ b/qt/scientific_interfaces/Indirect/CMakeLists.txt
@@ -194,8 +194,3 @@ mtd_add_qt_library (TARGET_NAME MantidScientificInterfacesIndirect
     @loader_path/../../Contents/MacOS
     @loader_path/../../plugins/qt4
 )
-
-if ( MSVC_IDE )
-#  # Add to the 'ScientificInterfaces' group in VS
-  set_property ( TARGET MantidScientificInterfacesIndirectQt4 PROPERTY FOLDER "ScientificInterfaces" )
-endif()
diff --git a/qt/scientific_interfaces/MultiDatasetFit/CMakeLists.txt b/qt/scientific_interfaces/MultiDatasetFit/CMakeLists.txt
index d7cd8395f8dcaa453db20cec40519256a73e4901..9c403e3c37ba47be2ab5fa11c3dae6c84141bd3c 100644
--- a/qt/scientific_interfaces/MultiDatasetFit/CMakeLists.txt
+++ b/qt/scientific_interfaces/MultiDatasetFit/CMakeLists.txt
@@ -70,8 +70,3 @@ mtd_add_qt_library (TARGET_NAME MantidScientificInterfacesMultiDatasetFit
   OSX_INSTALL_RPATH
     @loader_path/../../Contents/MacOS
 )
-
-if ( MSVC_IDE )
-#  # Add to the 'ScientificInterfaces' group in VS
-  set_property ( TARGET MantidScientificInterfacesMultiDatasetFitQt4 PROPERTY FOLDER "ScientificInterfaces" )
-endif()
diff --git a/qt/scientific_interfaces/Muon/CMakeLists.txt b/qt/scientific_interfaces/Muon/CMakeLists.txt
index 7b796e65e03fef64e2cc1659d52c014fa2980158..f8c390d5e06514b6a07f916b1d043979315f19de 100644
--- a/qt/scientific_interfaces/Muon/CMakeLists.txt
+++ b/qt/scientific_interfaces/Muon/CMakeLists.txt
@@ -110,8 +110,3 @@ mtd_add_qt_library (TARGET_NAME MantidScientificInterfacesMuon
     @loader_path/../../Contents/MacOS
     @loader_path/../../plugins/qt4
 )
-
-if ( MSVC_IDE )
-#  # Add to the 'ScientificInterfaces' group in VS
-  set_property ( TARGET MantidScientificInterfacesMuonQt4 PROPERTY FOLDER "ScientificInterfaces" )
-endif()
diff --git a/qt/widgets/sliceviewer/CMakeLists.txt b/qt/widgets/sliceviewer/CMakeLists.txt
index 1c28881fa3a90567328873d65c5adfe3a390161f..597f9066dab5d3cd0f27eddc7356c51fefa2657c 100644
--- a/qt/widgets/sliceviewer/CMakeLists.txt
+++ b/qt/widgets/sliceviewer/CMakeLists.txt
@@ -195,5 +195,5 @@ set ( TEST_PY_FILES
 )
 
 if ( PYUNITTEST_FOUND )
-  pyunittest_add_test (${CMAKE_CURRENT_SOURCE_DIR}/test python.test ${TEST_PY_FILES} )
+  pyunittest_add_test (${CMAKE_CURRENT_SOURCE_DIR} python.test ${TEST_PY_FILES} )
 endif ()
diff --git a/scripts/CMakeLists.txt b/scripts/CMakeLists.txt
index 8bcb5b217cd908bede84e175a511231f78d99e9d..1620a4dbd752066953d234418d34a9d9c69ce832 100644
--- a/scripts/CMakeLists.txt
+++ b/scripts/CMakeLists.txt
@@ -84,9 +84,7 @@ add_subdirectory(test/Muon)
 
 # python unit tests
 if (PYUNITTEST_FOUND)
-  pyunittest_add_test ( ${CMAKE_CURRENT_SOURCE_DIR}/test python.scripts ${TEST_PY_FILES} )
-  # Trying to add tested modules to python system path
-  #set (ENV{PYTHONPATH}  "ENV{PYTHONPATH} ${CMAKE_CURRENT_SOURCE_DIR}/Inelastic" )
+  pyunittest_add_test ( ${CMAKE_CURRENT_SOURCE_DIR} python.scripts ${TEST_PY_FILES} )
 endif ()
 
 # Ensure we don't get stale pyc files around
diff --git a/scripts/test/CrystalFieldMultiSiteTest.py b/scripts/test/CrystalFieldMultiSiteTest.py
index 8a0e085df566692906083615fe4686ff86fa12cc..a786460ffff0f2730f0cde83b2441662b0c2d029 100644
--- a/scripts/test/CrystalFieldMultiSiteTest.py
+++ b/scripts/test/CrystalFieldMultiSiteTest.py
@@ -1,5 +1,7 @@
 import numpy as np
 import unittest
+
+import mantid # noqa
 from CrystalField.CrystalFieldMultiSite import CrystalFieldMultiSite
 
 c_mbsr = 79.5774715459  # Conversion from barn to mb/sr
@@ -235,7 +237,7 @@ class CrystalFieldMultiSiteTests(unittest.TestCase):
         cf = CrystalFieldMultiSite(Ions=['Ce', 'Pr'], Symmetries=['C2v', 'C2v'], Temperatures=[44.0], FWHMs=[1.1],
                                    ToleranceIntensity=6.0, ToleranceEnergy=1.0, FixAllPeaks=True, parameters=params)
 
-        cf.fix('ion0.BmolX', 'ion0.BmolY', 'ion0.BmolZ', 'ion0.BextX', 'ion0.BextY', 'ion0.BextZ', 'ion0.B40', 
+        cf.fix('ion0.BmolX', 'ion0.BmolY', 'ion0.BmolZ', 'ion0.BextX', 'ion0.BextY', 'ion0.BextZ', 'ion0.B40',
                'ion0.B42', 'ion0.B44', 'ion0.B60', 'ion0.B62', 'ion0.B64', 'ion0.B66', 'ion0.IntensityScaling',
                'ion1.BmolX', 'ion1.BmolY', 'ion1.BmolZ', 'ion1.BextX', 'ion1.BextY', 'ion1.BextZ', 'ion1.B40',
                'ion1.B42', 'ion1.B44', 'ion1.B60', 'ion1.B62', 'ion1.B64', 'ion1.B66', 'ion1.IntensityScaling')
@@ -591,4 +593,4 @@ class CrystalFieldMultiSiteTests(unittest.TestCase):
         s = str(cf.function)
         self.assertTrue('ion0.IntensityScaling=0.2*ion2.IntensityScaling' in s)
         self.assertTrue('ion1.IntensityScaling=0.8*ion2.IntensityScaling' in s)
-        self.assertTrue('ion3.IntensityScaling=0.1*ion2.IntensityScaling' in s)
\ No newline at end of file
+        self.assertTrue('ion3.IntensityScaling=0.1*ion2.IntensityScaling' in s)
diff --git a/scripts/test/Muon/FFTModel_test.py b/scripts/test/Muon/FFTModel_test.py
index 68de091be30a4f90a68d6441819575fd993b1df9..73954c2c51dd70eea014270896f6c53693d595f2 100644
--- a/scripts/test/Muon/FFTModel_test.py
+++ b/scripts/test/Muon/FFTModel_test.py
@@ -1,5 +1,6 @@
 import sys
 
+import mantid #noqa
 from  Muon import fft_model
 
 import unittest
diff --git a/scripts/test/Muon/FFTPresenter_test.py b/scripts/test/Muon/FFTPresenter_test.py
index b011a993df32d3fb438170c74ec77a5ee3c50fcd..35be28522dfe3d6d1b71d26835c399ff0e26f675 100644
--- a/scripts/test/Muon/FFTPresenter_test.py
+++ b/scripts/test/Muon/FFTPresenter_test.py
@@ -1,5 +1,6 @@
 import sys
 
+import mantid #noqa
 from  Muon import load_utils
 from  Muon import fft_presenter
 from  Muon import fft_view
diff --git a/scripts/test/Muon/MaxEntPresenter_test.py b/scripts/test/Muon/MaxEntPresenter_test.py
index e23637202c7d87667bd455d9dc6d8e227886d5c1..be69c677d9f703d550195762a71f672c45ef5005 100644
--- a/scripts/test/Muon/MaxEntPresenter_test.py
+++ b/scripts/test/Muon/MaxEntPresenter_test.py
@@ -2,6 +2,7 @@ from __future__ import (absolute_import, division, print_function)
 
 import sys
 
+import mantid #noqa
 from  Muon import load_utils
 from  Muon import maxent_presenter
 from  Muon import maxent_view
diff --git a/scripts/test/Muon/transformPresenter_test.py b/scripts/test/Muon/transformPresenter_test.py
index fa51ed4cee96c7637ca79a936e30d40cf9a498a6..b184745a590a14e7b0f443af3332b3e371b93207 100644
--- a/scripts/test/Muon/transformPresenter_test.py
+++ b/scripts/test/Muon/transformPresenter_test.py
@@ -1,5 +1,6 @@
 import sys
 
+import mantid #noqa
 from  Muon import fft_presenter
 from  Muon import load_utils
 from  Muon import transform_presenter
diff --git a/scripts/test/SANS/common/enums_test.py b/scripts/test/SANS/common/enums_test.py
index 6b39c4dcee941d4ef6147b082bb3a7e50bc69fb3..28102498d9f2040d81d7798aa4909fd6616753f4 100644
--- a/scripts/test/SANS/common/enums_test.py
+++ b/scripts/test/SANS/common/enums_test.py
@@ -1,6 +1,7 @@
 from __future__ import (absolute_import, division, print_function)
 import unittest
 
+import mantid #noqa
 from sans.common.enums import serializable_enum, string_convertible