diff --git a/Framework/Algorithms/CMakeLists.txt b/Framework/Algorithms/CMakeLists.txt
index 4780746b5984885c3351dca413f4a12703397529..686aa3012da1c3d0bc822767c5c7308f889a27a0 100644
--- a/Framework/Algorithms/CMakeLists.txt
+++ b/Framework/Algorithms/CMakeLists.txt
@@ -221,7 +221,8 @@ set ( SRC_FILES
 	src/Plus.cpp
 	src/PointByPointVCorrection.cpp
 	src/PoissonErrors.cpp
-	src/PolarizationCorrection.cpp
+	src/PolarizationCorrectionFredrikze.cpp
+	src/PolarizationCorrectionWildes.cpp
 	src/PolarizationEfficiencyCor.cpp
 	src/PolynomialCorrection.cpp
 	src/Power.cpp
@@ -559,7 +560,8 @@ set ( INC_FILES
 	inc/MantidAlgorithms/Plus.h
 	inc/MantidAlgorithms/PointByPointVCorrection.h
 	inc/MantidAlgorithms/PoissonErrors.h
-	inc/MantidAlgorithms/PolarizationCorrection.h
+	inc/MantidAlgorithms/PolarizationCorrectionFredrikze.h
+	inc/MantidAlgorithms/PolarizationCorrectionWildes.h
 	inc/MantidAlgorithms/PolarizationEfficiencyCor.h
 	inc/MantidAlgorithms/PolynomialCorrection.h
 	inc/MantidAlgorithms/Power.h
@@ -899,7 +901,8 @@ set ( TEST_FILES
 	PlusTest.h
 	PointByPointVCorrectionTest.h
 	PoissonErrorsTest.h
-	PolarizationCorrectionTest.h
+	PolarizationCorrectionFredrikzeTest.h
+	PolarizationCorrectionWildesTest.h
 	PolarizationEfficiencyCorTest.h
 	PolynomialCorrectionTest.h
 	PowerLawCorrectionTest.h
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/PolarizationCorrection.h b/Framework/Algorithms/inc/MantidAlgorithms/PolarizationCorrectionFredrikze.h
similarity index 75%
rename from Framework/Algorithms/inc/MantidAlgorithms/PolarizationCorrection.h
rename to Framework/Algorithms/inc/MantidAlgorithms/PolarizationCorrectionFredrikze.h
index 07a29b9ac673c631055fc1bef90e9b75fe0a5c06..05b1066acaca172064a381fbc168b17029eee58d 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/PolarizationCorrection.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/PolarizationCorrectionFredrikze.h
@@ -1,5 +1,5 @@
-#ifndef MANTID_ALGORITHMS_POLARIZATIONCORRECTION_H_
-#define MANTID_ALGORITHMS_POLARIZATIONCORRECTION_H_
+#ifndef MANTID_ALGORITHMS_POLARIZATIONCORRECTIONFREDRIKZE_H_
+#define MANTID_ALGORITHMS_POLARIZATIONCORRECTIONFREDRIKZE_H_
 
 #include "MantidKernel/System.h"
 #include "MantidAPI/Algorithm.h"
@@ -13,8 +13,11 @@ class MatrixWorkspace;
 }
 namespace Algorithms {
 
-/** PolarizationCorrection : Algorithm to perform polarisation corrections on
- multi-period group workspaces.
+/** PolarizationCorrectionFredrikze : Algorithm to perform polarisation
+ corrections on
+ multi-period group workspaces that implements the Fredrikze (Dutch) method.
+ Fredrikze, H, et al. “Calibration of a polarized neutron reflectometer” Physica
+ B 297 (2001)
 
  Copyright © 2014 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge
  National Laboratory & European Spallation Source
@@ -37,7 +40,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 PolarizationCorrection : public API::Algorithm {
+class DLLExport PolarizationCorrectionFredrikze : public API::Algorithm {
 public:
   const std::string name() const override;
   int version() const override;
@@ -50,9 +53,8 @@ public:
 private:
   void init() override;
   void exec() override;
-  boost::shared_ptr<Mantid::API::MatrixWorkspace> execPolynomialCorrection(
-      boost::shared_ptr<Mantid::API::MatrixWorkspace> &input,
-      const std::vector<double> &coefficients);
+  boost::shared_ptr<Mantid::API::MatrixWorkspace>
+  getEfficiencyWorkspace(const std::string &label);
   boost::shared_ptr<Mantid::API::WorkspaceGroup>
   execPA(boost::shared_ptr<Mantid::API::WorkspaceGroup> inWS);
   boost::shared_ptr<Mantid::API::WorkspaceGroup>
@@ -63,13 +65,9 @@ private:
   boost::shared_ptr<Mantid::API::MatrixWorkspace>
   multiply(boost::shared_ptr<Mantid::API::MatrixWorkspace> &lhsWS,
            const double &rhs);
-  boost::shared_ptr<Mantid::API::MatrixWorkspace>
-  copyShapeAndFill(boost::shared_ptr<Mantid::API::MatrixWorkspace> &base,
-                   const double &value);
-  bool isPropertyDefault(const std::string &propertyName) const;
 };
 
 } // namespace Algorithms
 } // namespace Mantid
 
-#endif /* MANTID_ALGORITHMS_POLARIZATIONCORRECTION_H_ */
+#endif /* MANTID_ALGORITHMS_POLARIZATIONCORRECTIONFREDRIKZE_H_ */
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/PolarizationCorrectionWildes.h b/Framework/Algorithms/inc/MantidAlgorithms/PolarizationCorrectionWildes.h
new file mode 100644
index 0000000000000000000000000000000000000000..08b67c08cb8c9a41c7cbaa92164e3b9a4a75acc5
--- /dev/null
+++ b/Framework/Algorithms/inc/MantidAlgorithms/PolarizationCorrectionWildes.h
@@ -0,0 +1,98 @@
+#ifndef MANTID_ALGORITHMS_POLARIZATIONCORRECTIONWILDES_H_
+#define MANTID_ALGORITHMS_POLARIZATIONCORRECTIONWILDES_H_
+
+#include "MantidAlgorithms/DllConfig.h"
+#include "MantidAPI/Algorithm.h"
+#include "MantidAPI/WorkspaceGroup_fwd.h"
+
+namespace Mantid {
+namespace API {
+class ISpectrum;
+}
+
+namespace Algorithms {
+
+/** PolarizationCorrectionWildes : This algorithm corrects for non-ideal
+  component efficiencies in polarized neutron analysis. It is based on
+  [A. R. Wildes (2006) Neutron News, 17:2, 17-25,
+  DOI: 10.1080/10448630600668738]
+
+  Copyright &copy; 2018 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 PolarizationCorrectionWildes
+    : 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:
+  /// A convenience set of workspaces corresponding flipper configurations.
+  struct WorkspaceMap {
+    API::MatrixWorkspace_sptr mmWS{nullptr};
+    API::MatrixWorkspace_sptr mpWS{nullptr};
+    API::MatrixWorkspace_sptr pmWS{nullptr};
+    API::MatrixWorkspace_sptr ppWS{nullptr};
+    size_t size() const noexcept;
+  };
+
+  /// A convenience set of efficiency factors.
+  struct EfficiencyMap {
+    const API::ISpectrum *P1{nullptr};
+    const API::ISpectrum *P2{nullptr};
+    const API::ISpectrum *F1{nullptr};
+    const API::ISpectrum *F2{nullptr};
+  };
+
+  void init() override;
+  void exec() override;
+  std::map<std::string, std::string> validateInputs() override;
+  void checkConsistentNumberHistograms(const WorkspaceMap &inputs);
+  void checkConsistentX(const WorkspaceMap &inputs,
+                        const EfficiencyMap &efficiencies);
+  EfficiencyMap efficiencyFactors();
+  WorkspaceMap directBeamCorrections(const WorkspaceMap &inputs,
+                                     const EfficiencyMap &efficiencies);
+  WorkspaceMap analyzerlessCorrections(const WorkspaceMap &inputs,
+                                       const EfficiencyMap &efficiencies);
+  WorkspaceMap twoInputCorrections(const WorkspaceMap &inputs,
+                                   const EfficiencyMap &efficiencies);
+  WorkspaceMap threeInputCorrections(const WorkspaceMap &inputs,
+                                     const EfficiencyMap &efficiencies);
+  WorkspaceMap fullCorrections(const WorkspaceMap &inputs,
+                               const EfficiencyMap &efficiencies);
+  API::WorkspaceGroup_sptr groupOutput(const WorkspaceMap &outputs);
+  WorkspaceMap mapInputsToDirections(const std::vector<std::string> &flippers);
+  void threeInputsSolve01(WorkspaceMap &inputs,
+                          const EfficiencyMap &efficiencies);
+  void threeInputsSolve10(WorkspaceMap &inputs,
+                          const EfficiencyMap &efficiencies);
+  void twoInputsSolve01And10(WorkspaceMap &fullInputs,
+                             const WorkspaceMap &inputs,
+                             const EfficiencyMap &efficiencies);
+};
+
+} // namespace Algorithms
+} // namespace Mantid
+
+#endif /* MANTID_ALGORITHMS_POLARIZATIONCORRECTIONWILDES_H_ */
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/PolarizationEfficiencyCor.h b/Framework/Algorithms/inc/MantidAlgorithms/PolarizationEfficiencyCor.h
index a84f32e031f8438b57c56ca2048771cc9befbc91..11f12d56958e2fa63dfb4b6af188d79acf7acbcc 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/PolarizationEfficiencyCor.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/PolarizationEfficiencyCor.h
@@ -6,16 +6,12 @@
 #include "MantidAPI/WorkspaceGroup_fwd.h"
 
 namespace Mantid {
-namespace API {
-class ISpectrum;
-}
-
 namespace Algorithms {
 
-/** PolarizationEfficiencyCor : This algorithm corrects for non-ideal
-  component efficiencies in polarized neutron analysis. It is based on
-  [A. R. Wildes (2006) Neutron News, 17:2, 17-25,
-  DOI: 10.1080/10448630600668738]
+/** PolarizationEfficiencyCor: a generalised polarization correction
+  algorithm. Depending on the value of property "CorrectionMethod" it
+  calls either PolarizationCorrectionFredrikze or PolarizationCorrectionWildes
+  inetrnally.
 
   Copyright &copy; 2018 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge
   National Laboratory & European Spallation Source
@@ -49,49 +45,24 @@ public:
   const std::string summary() const override;
 
 private:
-  /// A convenience set of workspaces corresponding flipper configurations.
-  struct WorkspaceMap {
-    API::MatrixWorkspace_sptr mmWS{nullptr};
-    API::MatrixWorkspace_sptr mpWS{nullptr};
-    API::MatrixWorkspace_sptr pmWS{nullptr};
-    API::MatrixWorkspace_sptr ppWS{nullptr};
-    size_t size() const noexcept;
-  };
-
-  /// A convenience set of efficiency factors.
-  struct EfficiencyMap {
-    const API::ISpectrum *P1{nullptr};
-    const API::ISpectrum *P2{nullptr};
-    const API::ISpectrum *F1{nullptr};
-    const API::ISpectrum *F2{nullptr};
-  };
-
   void init() override;
   void exec() override;
-  std::map<std::string, std::string> validateInputs() override;
-  void checkConsistentNumberHistograms(const WorkspaceMap &inputs);
-  void checkConsistentX(const WorkspaceMap &inputs,
-                        const EfficiencyMap &efficiencies);
-  EfficiencyMap efficiencyFactors();
-  WorkspaceMap directBeamCorrections(const WorkspaceMap &inputs,
-                                     const EfficiencyMap &efficiencies);
-  WorkspaceMap analyzerlessCorrections(const WorkspaceMap &inputs,
-                                       const EfficiencyMap &efficiencies);
-  WorkspaceMap twoInputCorrections(const WorkspaceMap &inputs,
-                                   const EfficiencyMap &efficiencies);
-  WorkspaceMap threeInputCorrections(const WorkspaceMap &inputs,
-                                     const EfficiencyMap &efficiencies);
-  WorkspaceMap fullCorrections(const WorkspaceMap &inputs,
-                               const EfficiencyMap &efficiencies);
-  API::WorkspaceGroup_sptr groupOutput(const WorkspaceMap &outputs);
-  WorkspaceMap mapInputsToDirections(const std::vector<std::string> &flippers);
-  void threeInputsSolve01(WorkspaceMap &inputs,
-                          const EfficiencyMap &efficiencies);
-  void threeInputsSolve10(WorkspaceMap &inputs,
-                          const EfficiencyMap &efficiencies);
-  void twoInputsSolve01And10(WorkspaceMap &fullInputs,
-                             const WorkspaceMap &inputs,
-                             const EfficiencyMap &efficiencies);
+  void execWildes();
+  void execFredrikze();
+
+  void checkWorkspaces() const;
+  void checkWildesProperties() const;
+  void checkFredrikzeProperties() const;
+
+  std::vector<std::string> getWorkspaceNameList() const;
+  API::WorkspaceGroup_sptr getWorkspaceGroup() const;
+  API::MatrixWorkspace_sptr getEfficiencies();
+  bool needInterpolation(API::MatrixWorkspace const &efficiencies,
+                         API::MatrixWorkspace const &inWS) const;
+  API::MatrixWorkspace_sptr
+  convertToHistogram(API::MatrixWorkspace_sptr efficiencies);
+  API::MatrixWorkspace_sptr interpolate(API::MatrixWorkspace_sptr efficiencies,
+                                        API::MatrixWorkspace_sptr inWS);
 };
 
 } // namespace Algorithms
diff --git a/Framework/Algorithms/src/PolarizationCorrection.cpp b/Framework/Algorithms/src/PolarizationCorrectionFredrikze.cpp
similarity index 59%
rename from Framework/Algorithms/src/PolarizationCorrection.cpp
rename to Framework/Algorithms/src/PolarizationCorrectionFredrikze.cpp
index b3c949ab0997a07d1c6a669a21fae007e0109d2c..ccc49951484ab2c478347ec7601c21c1f3ca7b4f 100644
--- a/Framework/Algorithms/src/PolarizationCorrection.cpp
+++ b/Framework/Algorithms/src/PolarizationCorrectionFredrikze.cpp
@@ -1,13 +1,13 @@
-#include "MantidAlgorithms/PolarizationCorrection.h"
+#include "MantidAlgorithms/PolarizationCorrectionFredrikze.h"
 #include "MantidAPI/Axis.h"
+#include "MantidAPI/TextAxis.h"
+#include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidAPI/WorkspaceGroup.h"
 #include "MantidAPI/WorkspaceHistory.h"
 #include "MantidDataObjects/WorkspaceSingleValue.h"
-#include "MantidKernel/ArrayProperty.h"
-#include "MantidKernel/ListValidator.h"
-#include "MantidKernel/Unit.h"
 #include "MantidGeometry/Instrument.h"
+#include "MantidKernel/ListValidator.h"
 
 #include <boost/shared_ptr.hpp>
 
@@ -19,22 +19,24 @@ using namespace Mantid::Geometry;
 
 namespace {
 
-const std::string pNRLabel() { return "PNR"; }
+const std::string pNRLabel("PNR");
+
+const std::string pALabel("PA");
 
-const std::string pALabel() { return "PA"; }
+const std::string crhoLabel("Rho");
 
-const std::string crhoLabel() { return "CRho"; }
+const std::string cppLabel("Pp");
 
-const std::string cppLabel() { return "CPp"; }
+const std::string cAlphaLabel("Alpha");
 
-const std::string cAlphaLabel() { return "CAlpha"; }
+const std::string cApLabel("Ap");
 
-const std::string cApLabel() { return "CAp"; }
+const std::string efficienciesLabel("Efficiencies");
 
 std::vector<std::string> modes() {
   std::vector<std::string> modes;
-  modes.push_back(pALabel());
-  modes.push_back(pNRLabel());
+  modes.push_back(pALabel);
+  modes.push_back(pNRLabel);
   return modes;
 }
 
@@ -103,38 +105,32 @@ void validateInputWorkspace(WorkspaceGroup_sptr &ws) {
 }
 
 using VecDouble = std::vector<double>;
-}
+} // namespace
 
 namespace Mantid {
 namespace Algorithms {
 
 // Register the algorithm into the AlgorithmFactory
-DECLARE_ALGORITHM(PolarizationCorrection)
+DECLARE_ALGORITHM(PolarizationCorrectionFredrikze)
 
 //----------------------------------------------------------------------------------------------
 /// Algorithm's name for identification. @see Algorithm::name
-const std::string PolarizationCorrection::name() const {
-  return "PolarizationCorrection";
+const std::string PolarizationCorrectionFredrikze::name() const {
+  return "PolarizationCorrectionFredrikze";
 }
 
 /// Algorithm's version for identification. @see Algorithm::version
-int PolarizationCorrection::version() const { return 1; }
+int PolarizationCorrectionFredrikze::version() const { return 1; }
 
 /// Algorithm's category for identification. @see Algorithm::category
-const std::string PolarizationCorrection::category() const {
+const std::string PolarizationCorrectionFredrikze::category() const {
   return "Reflectometry";
 }
 
-bool PolarizationCorrection::isPropertyDefault(
-    const std::string &propertyName) const {
-  Property *prop = this->getProperty(propertyName);
-  return prop->isDefault();
-}
-
 /**
  * @return Return the algorithm summary.
  */
-const std::string PolarizationCorrection::summary() const {
+const std::string PolarizationCorrectionFredrikze::summary() const {
   return "Makes corrections for polarization efficiencies of the polarizer and "
          "analyzer in a reflectometry neutron spectrometer.";
 }
@@ -146,8 +142,8 @@ const std::string PolarizationCorrection::summary() const {
  * @return Multiplied Workspace.
  */
 MatrixWorkspace_sptr
-PolarizationCorrection::multiply(MatrixWorkspace_sptr &lhsWS,
-                                 const double &rhs) {
+PolarizationCorrectionFredrikze::multiply(MatrixWorkspace_sptr &lhsWS,
+                                          const double &rhs) {
   auto multiply = this->createChildAlgorithm("Multiply");
   auto rhsWS = boost::make_shared<DataObjects::WorkspaceSingleValue>(rhs);
   multiply->initialize();
@@ -164,8 +160,9 @@ PolarizationCorrection::multiply(MatrixWorkspace_sptr &lhsWS,
  * @param rhs Value to add
  * @return Summed workspace
  */
-MatrixWorkspace_sptr PolarizationCorrection::add(MatrixWorkspace_sptr &lhsWS,
-                                                 const double &rhs) {
+MatrixWorkspace_sptr
+PolarizationCorrectionFredrikze::add(MatrixWorkspace_sptr &lhsWS,
+                                     const double &rhs) {
   auto plus = this->createChildAlgorithm("Plus");
   auto rhsWS = boost::make_shared<DataObjects::WorkspaceSingleValue>(rhs);
   plus->initialize();
@@ -179,7 +176,7 @@ MatrixWorkspace_sptr PolarizationCorrection::add(MatrixWorkspace_sptr &lhsWS,
 //----------------------------------------------------------------------------------------------
 /** Initialize the algorithm's properties.
  */
-void PolarizationCorrection::init() {
+void PolarizationCorrectionFredrikze::init() {
   declareProperty(make_unique<WorkspaceProperty<Mantid::API::WorkspaceGroup>>(
                       "InputWorkspace", "", Direction::Input),
                   "An input workspace to process.");
@@ -192,67 +189,18 @@ void PolarizationCorrection::init() {
                   "PA: Full Polarization Analysis PNR-PA");
 
   declareProperty(
-      Kernel::make_unique<ArrayProperty<double>>(cppLabel(), Direction::Input),
-      "Effective polarizing power of the polarizing system. "
-      "Expressed as a ratio 0 < Pp < 1");
-
-  declareProperty(
-      Kernel::make_unique<ArrayProperty<double>>(cApLabel(), Direction::Input),
-      "Effective polarizing power of the analyzing system. "
-      "Expressed as a ratio 0 < Ap < 1");
-
-  declareProperty(
-      Kernel::make_unique<ArrayProperty<double>>(crhoLabel(), Direction::Input),
-      "Ratio of efficiencies of polarizer spin-down to polarizer "
-      "spin-up. This is characteristic of the polarizer flipper. "
-      "Values are constants for each term in a polynomial "
-      "expression.");
-
-  declareProperty(Kernel::make_unique<ArrayProperty<double>>(cAlphaLabel(),
-                                                             Direction::Input),
-                  "Ratio of efficiencies of analyzer spin-down to analyzer "
-                  "spin-up. This is characteristic of the analyzer flipper. "
-                  "Values are factors for each term in a polynomial "
-                  "expression.");
+      Kernel::make_unique<API::WorkspaceProperty<API::MatrixWorkspace>>(
+          efficienciesLabel, "", Kernel::Direction::Input),
+      "A workspace containing the efficiency factors Pp, Ap, Rho and Alpha "
+      "as histograms");
 
   declareProperty(make_unique<WorkspaceProperty<Mantid::API::WorkspaceGroup>>(
                       "OutputWorkspace", "", Direction::Output),
                   "An output workspace.");
 }
 
-MatrixWorkspace_sptr PolarizationCorrection::execPolynomialCorrection(
-    MatrixWorkspace_sptr &input, const VecDouble &coefficients) {
-  auto polyCorr = this->createChildAlgorithm("PolynomialCorrection");
-  polyCorr->initialize();
-  polyCorr->setProperty("InputWorkspace", input);
-  polyCorr->setProperty("Coefficients", coefficients);
-  polyCorr->execute();
-  MatrixWorkspace_sptr corrected = polyCorr->getProperty("OutputWorkspace");
-  return corrected;
-}
-
-MatrixWorkspace_sptr
-PolarizationCorrection::copyShapeAndFill(MatrixWorkspace_sptr &base,
-                                         const double &value) {
-  MatrixWorkspace_sptr wsTemplate = WorkspaceFactory::Instance().create(base);
-  // Copy the x-array across to the new workspace.
-  for (size_t i = 0; i < wsTemplate->getNumberHistograms(); ++i) {
-    wsTemplate->setSharedX(i, base->sharedX(i));
-  }
-  auto zeroed = this->multiply(wsTemplate, 0);
-  auto filled = this->add(zeroed, value);
-  return filled;
-}
-
-WorkspaceGroup_sptr PolarizationCorrection::execPA(WorkspaceGroup_sptr inWS) {
-
-  if (isPropertyDefault(cAlphaLabel())) {
-    throw std::invalid_argument("Must provide as input for PA: " +
-                                cAlphaLabel());
-  }
-  if (isPropertyDefault(cApLabel())) {
-    throw std::invalid_argument("Must provide as input for PA: " + cApLabel());
-  }
+WorkspaceGroup_sptr
+PolarizationCorrectionFredrikze::execPA(WorkspaceGroup_sptr inWS) {
 
   size_t itemIndex = 0;
   MatrixWorkspace_sptr Ipp =
@@ -269,30 +217,10 @@ WorkspaceGroup_sptr PolarizationCorrection::execPA(WorkspaceGroup_sptr inWS) {
   Ipa->setTitle("Ipa");
   Iap->setTitle("Iap");
 
-  auto cropAlg = this->createChildAlgorithm("CropWorkspace");
-  cropAlg->initialize();
-  cropAlg->setProperty("InputWorkspace", Ipp);
-  cropAlg->setProperty("EndWorkspaceIndex", 0);
-  cropAlg->execute();
-  MatrixWorkspace_sptr croppedIpp = cropAlg->getProperty("OutputWorkspace");
-
-  MatrixWorkspace_sptr ones = copyShapeAndFill(croppedIpp, 1.0);
-  // The ones workspace is now identical to the input workspaces in x, but has 1
-  // as y values. It can therefore be used to build real polynomial functions.
-
-  const VecDouble c_rho = getProperty(crhoLabel());
-  const VecDouble c_alpha = getProperty(cAlphaLabel());
-  const VecDouble c_pp = getProperty(cppLabel());
-  const VecDouble c_ap = getProperty(cApLabel());
-
-  const auto rho = this->execPolynomialCorrection(
-      ones, c_rho); // Execute polynomial expression
-  const auto pp = this->execPolynomialCorrection(
-      ones, c_pp); // Execute polynomial expression
-  const auto alpha = this->execPolynomialCorrection(
-      ones, c_alpha); // Execute polynomial expression
-  const auto ap = this->execPolynomialCorrection(
-      ones, c_ap); // Execute polynomial expression
+  const auto rho = this->getEfficiencyWorkspace(crhoLabel);
+  const auto pp = this->getEfficiencyWorkspace(cppLabel);
+  const auto alpha = this->getEfficiencyWorkspace(cAlphaLabel);
+  const auto ap = this->getEfficiencyWorkspace(cApLabel);
 
   const auto A0 = (Iaa * pp * ap) + (ap * Ipa * rho * pp) +
                   (ap * Iap * alpha * pp) + (Ipp * ap * alpha * rho * pp);
@@ -341,22 +269,16 @@ WorkspaceGroup_sptr PolarizationCorrection::execPA(WorkspaceGroup_sptr inWS) {
   return dataOut;
 }
 
-WorkspaceGroup_sptr PolarizationCorrection::execPNR(WorkspaceGroup_sptr inWS) {
+WorkspaceGroup_sptr
+PolarizationCorrectionFredrikze::execPNR(WorkspaceGroup_sptr inWS) {
   size_t itemIndex = 0;
   MatrixWorkspace_sptr Ip =
       boost::dynamic_pointer_cast<MatrixWorkspace>(inWS->getItem(itemIndex++));
   MatrixWorkspace_sptr Ia =
       boost::dynamic_pointer_cast<MatrixWorkspace>(inWS->getItem(itemIndex++));
 
-  MatrixWorkspace_sptr ones = copyShapeAndFill(Ip, 1.0);
-
-  const VecDouble c_rho = getProperty(crhoLabel());
-  const VecDouble c_pp = getProperty(cppLabel());
-
-  const auto rho = this->execPolynomialCorrection(
-      ones, c_rho); // Execute polynomial expression
-  const auto pp = this->execPolynomialCorrection(
-      ones, c_pp); // Execute polynomial expression
+  const auto rho = this->getEfficiencyWorkspace(crhoLabel);
+  const auto pp = this->getEfficiencyWorkspace(cppLabel);
 
   const auto D = pp * (rho + 1);
 
@@ -374,55 +296,74 @@ WorkspaceGroup_sptr PolarizationCorrection::execPNR(WorkspaceGroup_sptr inWS) {
   return dataOut;
 }
 
+/** Extract a spectrum from the Efficiencies workspace as a 1D workspace.
+ * @param label :: A label of the spectrum to extract.
+ * @return :: A workspace with a single spectrum.
+ */
+boost::shared_ptr<Mantid::API::MatrixWorkspace>
+PolarizationCorrectionFredrikze::getEfficiencyWorkspace(
+    const std::string &label) {
+  MatrixWorkspace_sptr efficiencies = getProperty(efficienciesLabel);
+  auto const &axis = dynamic_cast<TextAxis &>(*efficiencies->getAxis(1));
+  size_t index = axis.length();
+  for (size_t i = 0; i < axis.length(); ++i) {
+    if (axis.label(i) == label) {
+      index = i;
+      break;
+    }
+  }
+
+  if (index == axis.length()) {
+    // Check if we need to fetch polarization parameters from the instrument's
+    // parameters
+    static std::map<std::string, std::string> loadableProperties{
+        {crhoLabel, "crho"},
+        {cppLabel, "cPp"},
+        {cApLabel, "cAp"},
+        {cAlphaLabel, "calpha"}};
+    WorkspaceGroup_sptr inWS = getProperty("InputWorkspace");
+    Instrument_const_sptr instrument = fetchInstrument(inWS.get());
+    auto vals = instrument->getStringParameter(loadableProperties[label]);
+    if (vals.empty()) {
+      throw std::invalid_argument("Efficiencey property not found: " + label);
+    }
+    auto extract = createChildAlgorithm("CreatePolarizationEfficiencies");
+    extract->initialize();
+    extract->setProperty("InputWorkspace", efficiencies);
+    extract->setProperty(label, vals.front());
+    extract->execute();
+    MatrixWorkspace_sptr outWS = extract->getProperty("OutputWorkspace");
+    return outWS;
+  } else {
+    auto extract = createChildAlgorithm("ExtractSingleSpectrum");
+    extract->initialize();
+    extract->setProperty("InputWorkspace", efficiencies);
+    extract->setProperty("WorkspaceIndex", static_cast<int>(index));
+    extract->execute();
+    MatrixWorkspace_sptr outWS = extract->getProperty("OutputWorkspace");
+    return outWS;
+  }
+}
+
 //----------------------------------------------------------------------------------------------
 /** Execute the algorithm.
  */
-void PolarizationCorrection::exec() {
+void PolarizationCorrectionFredrikze::exec() {
   WorkspaceGroup_sptr inWS = getProperty("InputWorkspace");
   const std::string analysisMode = getProperty("PolarizationAnalysis");
   const size_t nWorkspaces = inWS->size();
 
   validateInputWorkspace(inWS);
 
-  Instrument_const_sptr instrument = fetchInstrument(inWS.get());
-
-  // Check if we need to fetch polarization parameters from the instrument's
-  // parameters
-  std::map<std::string, std::string> loadableProperties;
-  loadableProperties[crhoLabel()] = "crho";
-  loadableProperties[cppLabel()] = "cPp";
-
-  // In PA mode, we also require cap and calpha
-  if (analysisMode == pALabel()) {
-    loadableProperties[cApLabel()] = "cAp";
-    loadableProperties[cAlphaLabel()] = "calpha";
-  }
-
-  for (auto &loadableProperty : loadableProperties) {
-    Property *prop = getProperty(loadableProperty.first);
-
-    if (!prop)
-      continue;
-
-    if (prop->isDefault()) {
-      auto vals = instrument->getStringParameter(loadableProperty.second);
-      if (vals.empty())
-        throw std::runtime_error(
-            "Cannot find value for " + loadableProperty.first +
-            " in parameter file. Please specify this property manually.");
-      prop->setValue(vals[0]);
-    }
-  }
-
   WorkspaceGroup_sptr outWS;
-  if (analysisMode == pALabel()) {
+  if (analysisMode == pALabel) {
     if (nWorkspaces != 4) {
       throw std::invalid_argument(
           "For PA analysis, input group must have 4 periods.");
     }
     g_log.notice("PA polarization correction");
     outWS = execPA(inWS);
-  } else if (analysisMode == pNRLabel()) {
+  } else if (analysisMode == pNRLabel) {
     if (nWorkspaces != 2) {
       throw std::invalid_argument(
           "For PNR analysis, input group must have 2 periods.");
diff --git a/Framework/Algorithms/src/PolarizationCorrectionWildes.cpp b/Framework/Algorithms/src/PolarizationCorrectionWildes.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9e9fb51d74c413abd4c59216f54da0355ec7f76e
--- /dev/null
+++ b/Framework/Algorithms/src/PolarizationCorrectionWildes.cpp
@@ -0,0 +1,1036 @@
+#include "MantidAlgorithms/PolarizationCorrectionWildes.h"
+
+#include "MantidAPI/ADSValidator.h"
+#include "MantidAPI/Axis.h"
+#include "MantidAPI/MatrixWorkspace.h"
+#include "MantidAPI/WorkspaceGroup.h"
+#include "MantidDataObjects/Workspace2D.h"
+#include "MantidDataObjects/WorkspaceCreation.h"
+#include "MantidKernel/ArrayProperty.h"
+#include "MantidKernel/ListValidator.h"
+#include "MantidKernel/StringTokenizer.h"
+
+#include <Eigen/Dense>
+#include <boost/math/special_functions/pow.hpp>
+
+namespace {
+/// Property names.
+namespace Prop {
+static const std::string FLIPPERS{"Flippers"};
+static const std::string EFFICIENCIES{"Efficiencies"};
+static const std::string INPUT_WS{"InputWorkspaces"};
+static const std::string OUTPUT_WS{"OutputWorkspace"};
+} // namespace Prop
+
+/// Flipper configurations.
+namespace Flippers {
+static const std::string Off{"0"};
+static const std::string OffOff{"00"};
+static const std::string OffOn{"01"};
+static const std::string On{"1"};
+static const std::string OnOff{"10"};
+static const std::string OnOn{"11"};
+} // namespace Flippers
+
+/**
+ * Parse a flipper configuration string.
+ * @param setupString a configuration string
+ * @return a vector of individual configurations
+ */
+std::vector<std::string> parseFlipperSetup(const std::string &setupString) {
+  using Mantid::Kernel::StringTokenizer;
+  StringTokenizer tokens{setupString, ",", StringTokenizer::TOK_TRIM};
+  return std::vector<std::string>{tokens.begin(), tokens.end()};
+}
+
+/**
+ * Throw if given ws is nullptr.
+ * @param ws a workspace to check
+ * @param tag a flipper configuration for the error message
+ */
+void checkInputExists(const Mantid::API::MatrixWorkspace_sptr &ws,
+                      const std::string &tag) {
+  if (!ws) {
+    throw std::runtime_error("A workspace designated as " + tag +
+                             " is missing in inputs.");
+  }
+}
+
+/**
+ * Calculate the corrected intensities and error estimates.
+ * @param corrected an output vector for R00, R01, R10 and R11
+ * @param errors an output vector for the error estimates
+ * @param ppy intensity I00
+ * @param ppyE error of ppy
+ * @param pmy intensity I01
+ * @param pmyE error of pmy
+ * @param mpy intensity I10
+ * @param mpyE error of mpy
+ * @param mmy intensity I11
+ * @param mmyE error of mmy
+ * @param f1 polarizer efficiency
+ * @param f1E error of f1
+ * @param f2 analyzer efficiency
+ * @param f2E error of f2
+ * @param p1 polarizer flipper efficiency
+ * @param p1E error of p1
+ * @param p2 analyzer flipper efficiency
+ * @param p2E error of p2
+ */
+void fourInputsCorrectedAndErrors(
+    Eigen::Vector4d &corrected, Eigen::Vector4d &errors, const double ppy,
+    const double ppyE, const double pmy, const double pmyE, const double mpy,
+    const double mpyE, const double mmy, const double mmyE, const double f1,
+    const double f1E, const double f2, const double f2E, const double p1,
+    const double p1E, const double p2, const double p2E) {
+  using namespace boost::math;
+  // Note that f1 and f2 correspond to 1-F1 and 1-F2 in [Wildes, 1999].
+  // These are inverted forms of the efficiency matrices.
+  const auto diag1 = 1. / f1;
+  const auto off1 = (f1 - 1.) / f1;
+  Eigen::Matrix4d F1m;
+  F1m << 1., 0., 0., 0., 0., 1., 0., 0., off1, 0., diag1, 0., 0., off1, 0.,
+      diag1;
+  const auto diag2 = 1. / f2;
+  const auto off2 = (f2 - 1.) / f2;
+  Eigen::Matrix4d F2m;
+  F2m << 1., 0., 0., 0., off2, diag2, 0., 0., 0., 0., 1., 0., 0., 0., off2,
+      diag2;
+  const auto diag3 = (p1 - 1.) / (2. * p1 - 1.);
+  const auto off3 = p1 / (2. * p1 - 1);
+  Eigen::Matrix4d P1m;
+  P1m << diag3, 0, off3, 0, 0, diag3, 0, off3, off3, 0, diag3, 0, 0, off3, 0,
+      diag3;
+  const auto diag4 = (p2 - 1.) / (2. * p2 - 1.);
+  const auto off4 = p2 / (2. * p2 - 1.);
+  Eigen::Matrix4d P2m;
+  P2m << diag4, off4, 0., 0., off4, diag4, 0., 0., 0., 0., diag4, off4, 0., 0.,
+      off4, diag4;
+  const Eigen::Vector4d intensities(ppy, pmy, mpy, mmy);
+  const auto FProduct = F2m * F1m;
+  const auto PProduct = P2m * P1m;
+  const auto PFProduct = PProduct * FProduct;
+  corrected = PFProduct * intensities;
+  // The error matrices here are element-wise algebraic derivatives of
+  // the matrices above, multiplied by the error.
+  const auto elemE1 = -1. / pow<2>(f1) * f1E;
+  Eigen::Matrix4d F1Em;
+  F1Em << 0., 0., 0., 0., 0., 0., 0., 0., -elemE1, 0., elemE1, 0., 0., -elemE1,
+      0., elemE1;
+  const auto elemE2 = -1. / pow<2>(f2) * f2E;
+  Eigen::Matrix4d F2Em;
+  F2Em << 0., 0., 0., 0., -elemE2, elemE2, 0., 0., 0., 0., 0., 0., 0., 0.,
+      -elemE2, elemE2;
+  const auto elemE3 = 1. / pow<2>(2. * p1 - 1.) * p1E;
+  Eigen::Matrix4d P1Em;
+  P1Em << elemE3, 0., -elemE3, 0., 0., elemE3, 0., -elemE3, -elemE3, 0., elemE3,
+      0., 0., -elemE3, 0., elemE3;
+  const auto elemE4 = 1. / pow<2>(2. * p2 - 1.) * p2E;
+  Eigen::Matrix4d P2Em;
+  P2Em << elemE4, -elemE4, 0., 0., -elemE4, elemE4, 0., 0., 0., 0., elemE4,
+      -elemE4, 0., 0., -elemE4, elemE4;
+  const Eigen::Vector4d yErrors(ppyE, pmyE, mpyE, mmyE);
+  const auto e1 = (P2Em * P1m * FProduct * intensities).array();
+  const auto e2 = (P2m * P1Em * FProduct * intensities).array();
+  const auto e3 = (PProduct * F2Em * F1m * intensities).array();
+  const auto e4 = (PProduct * F2m * F1Em * intensities).array();
+  const auto sqPFProduct = (PFProduct.array() * PFProduct.array()).matrix();
+  const auto sqErrors = (yErrors.array() * yErrors.array()).matrix();
+  const auto e5 = (sqPFProduct * sqErrors).array();
+  errors = (e1 * e1 + e2 * e2 + e3 * e3 + e4 * e4 + e5).sqrt();
+}
+
+/**
+ * Estimate errors for I01 in the two inputs case.
+ * @param i00 intensity of 00 flipper configuration
+ * @param e00 error of i00
+ * @param i11 intensity of 11 flipper configuration
+ * @param e11 error of i11
+ * @param p1 polarizer efficiency
+ * @param p1E error of p1
+ * @param p2 analyzer efficiency
+ * @param p2E error of p2
+ * @param f1 polarizer flipper efficiency
+ * @param f1E error of f1
+ * @param f2 analyzer flipper efficiency
+ * @param f2E error of f2
+ * @return the error estimate
+ */
+double twoInputsErrorEstimate01(const double i00, const double e00,
+                                const double i11, const double e11,
+                                const double p1, const double p1E,
+                                const double p2, const double p2E,
+                                const double f1, const double f1E,
+                                const double f2, const double f2E) {
+  using namespace boost::math;
+  // Derivatives of the equation which solves the I01 intensities
+  // with respect to i00, i11, f1, etc.
+  const auto pmdi00 =
+      -((f1 * (-1. + 2. * p1) *
+         (-f2 * pow<2>(1. - 2. * p2) + pow<2>(f2) * pow<2>(1. - 2. * p2) +
+          (-1. + p2) * p2)) /
+        (f2 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) +
+         f1 * (-1. + 2. * p1) *
+             ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2))));
+  const auto pmdi11 =
+      (f2 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2)) /
+      (f2 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) +
+       f1 * (-1. + 2. * p1) *
+           ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2)));
+  const auto pmdf1 =
+      -(((-1. + 2. * p1) *
+         ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2)) *
+         (f2 * i11 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) -
+          f1 * i00 * (-1. + 2. * p1) *
+              (-f2 * pow<2>(1. - 2. * p2) + pow<2>(f2) * pow<2>(1. - 2. * p2) +
+               (-1. + p2) * p2))) /
+        pow<2>(f2 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) +
+               f1 * (-1. + 2. * p1) *
+                   ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2)))) -
+      (i00 * (-1. + 2. * p1) *
+       (-f2 * pow<2>(1. - 2. * p2) + pow<2>(f2) * pow<2>(1. - 2. * p2) +
+        (-1. + p2) * p2)) /
+          (f2 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) +
+           f1 * (-1. + 2. * p1) *
+               ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2)));
+  const auto pmdf2 =
+      -(((f1 * (-1. + 2. * p1) * (-1. + p1 + p2) * (-1 + 2 * p2) +
+          p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2)) *
+         (f2 * i11 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) -
+          f1 * i00 * (-1. + 2. * p1) *
+              (-f2 * pow<2>(1. - 2. * p2) + pow<2>(f2) * pow<2>(1. - 2. * p2) +
+               (-1. + p2) * p2))) /
+        pow<2>(f2 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) +
+               f1 * (-1. + 2. * p1) *
+                   ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2)))) +
+      (-f1 * i00 * (-1. + 2. * p1) *
+           (-pow<2>(1. - 2. * p2) + 2 * f2 * pow<2>(1. - 2. * p2)) +
+       i11 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2)) /
+          (f2 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) +
+           f1 * (-1. + 2. * p1) *
+               ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2)));
+  const auto pmdp1 =
+      -(((f2 * i11 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) -
+          f1 * i00 * (-1. + 2. * p1) *
+              (-f2 * pow<2>(1. - 2. * p2) + pow<2>(f2) * pow<2>(1. - 2. * p2) +
+               (-1. + p2) * p2)) *
+         (f2 * p1 * (1. - 2. * p2) +
+          f1 * f2 * (-1. + 2. * p1) * (-1. + 2. * p2) +
+          f2 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) +
+          2. * f1 *
+              ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2)))) /
+        pow<2>(f2 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) +
+               f1 * (-1. + 2. * p1) *
+                   ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2)))) +
+      (f2 * i11 * p1 * (1. - 2. * p2) +
+       f2 * i11 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) -
+       2. * f1 * i00 * (-f2 * pow<2>(1. - 2. * p2) +
+                        pow<2>(f2) * pow<2>(1. - 2. * p2) + (-1. + p2) * p2)) /
+          (f2 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) +
+           f1 * (-1. + 2. * p1) *
+               ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2)));
+  const auto pmdp2 =
+      -(((f2 * i11 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) -
+          f1 * i00 * (-1. + 2. * p1) *
+              (-f2 * pow<2>(1. - 2. * p2) + pow<2>(f2) * pow<2>(1. - 2. * p2) +
+               (-1. + p2) * p2)) *
+         (f2 * (2. - 2. * p1) * p1 +
+          f1 * (-1. + 2. * p1) * (1. - 2. * p2 + 2. * f2 * (-1. + p1 + p2) +
+                                  f2 * (-1. + 2. * p2)))) /
+        pow<2>(f2 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) +
+               f1 * (-1. + 2. * p1) *
+                   ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2)))) +
+      (f2 * i11 * (2. - 2. * p1) * p1 -
+       f1 * i00 * (-1. + 2. * p1) *
+           (-1. + 4. * f2 * (1. - 2. * p2) - 4. * pow<2>(f2) * (1. - 2. * p2) +
+            2. * p2)) /
+          (f2 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) +
+           f1 * (-1. + 2. * p1) *
+               ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2)));
+  // Estimate the error components using linearized extrapolation,
+  // sum in squares.
+  const auto e01_I00 = pow<2>(pmdi00 * e00);
+  const auto e01_I11 = pow<2>(pmdi11 * e11);
+  const auto e01_F1 = pow<2>(pmdf1 * f1E);
+  const auto e01_F2 = pow<2>(pmdf2 * f2E);
+  const auto e01_P1 = pow<2>(pmdp1 * p1E);
+  const auto e01_P2 = pow<2>(pmdp2 * p2E);
+  return std::sqrt(e01_I00 + e01_I11 + e01_F1 + e01_F2 + e01_P1 + e01_P2);
+}
+
+/**
+ * Estimate errors for I10 in the two inputs case.
+ * @param i00 intensity of 00 flipper configuration
+ * @param e00 error of i00
+ * @param i11 intensity of 11 flipper configuration
+ * @param e11 error of i11
+ * @param p1 polarizer efficiency
+ * @param p1E error of p1
+ * @param p2 analyzer efficiency
+ * @param p2E error of p2
+ * @param f1 polarizer flipper efficiency
+ * @param f1E error of f1
+ * @param f2 analyzer flipper efficiency
+ * @param f2E error of f2
+ * @return the error estimate
+ */
+double twoInputsErrorEstimate10(const double i00, const double e00,
+                                const double i11, const double e11,
+                                const double p1, const double p1E,
+                                const double p2, const double p2E,
+                                const double f1, const double f1E,
+                                const double f2, const double f2E) {
+  using namespace boost::math;
+  // Derivatives of the equation which solves the I10 intensities
+  // with respect to i00, i11, f1, etc.
+  const auto a = -1. + p1 + 2. * p2 - 2. * p1 * p2;
+  const auto b = -1. + 2. * p1;
+  const auto c = -1. + 2. * p2;
+  const auto d = -1. + p2;
+  const auto mpdi00 = (-pow<2>(f1) * f2 * pow<2>(b) * c +
+                       f1 * f2 * pow<2>(b) * c + f2 * p1 * a) /
+                      (f2 * p1 * a + f1 * b * (-d * p2 + f2 * (p1 + d) * c));
+  const auto mpdi11 = -((f1 * b * d * p2) /
+                        (f2 * p1 * a + f1 * b * (-d * p2 + f2 * (p1 + d) * c)));
+  const auto mpdf1 =
+      -(((-1. + 2. * p1) *
+         ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2)) *
+         (-pow<2>(f1) * f2 * i00 * pow<2>(1. - 2. * p1) * (-1. + 2. * p2) +
+          f2 * i00 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) +
+          f1 * (-1. + 2. * p1) *
+              (-i11 * (-1. + p2) * p2 +
+               f2 * i00 * (-1. + 2. * p1) * (-1. + 2. * p2)))) /
+        pow<2>(f2 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) +
+               f1 * (-1. + 2. * p1) *
+                   ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2)))) +
+      (-2. * f1 * f2 * i00 * pow<2>(1. - 2. * p1) * (-1. + 2. * p2) +
+       (-1. + 2. * p1) * (-i11 * (-1. + p2) * p2 +
+                          f2 * i00 * (-1. + 2. * p1) * (-1. + 2. * p2))) /
+          (f2 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) +
+           f1 * (-1. + 2. * p1) *
+               ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2)));
+  const auto mpdf2 =
+      -(((f1 * b * (p1 + d) * c + p1 * a) *
+         (-pow<2>(f1) * f2 * i00 * pow<2>(b) * c + f2 * i00 * p1 * a +
+          f1 * b * (-i11 * d * p2 + f2 * i00 * b * c))) /
+        pow<2>(f2 * p1 * a + f1 * b * (-d * p2 + f2 * (p1 + d) * c))) +
+      (-pow<2>(f1) * i00 * pow<2>(b) * c + f1 * i00 * pow<2>(b) * c +
+       i00 * p1 * a) /
+          (f2 * p1 * a + f1 * b * (-d * p2 + f2 * (p1 + d) * c));
+  const auto mpdp1 =
+      -(((-pow<2>(f1) * f2 * i00 * pow<2>(b) * c + f2 * i00 * p1 * a +
+          f1 * b * (-i11 * d * p2 + f2 * i00 * b * c)) *
+         (f2 * p1 * -c + f1 * f2 * b * c + f2 * a +
+          2. * f1 * (-d * p2 + f2 * (p1 + d) * c))) /
+        pow<2>(f2 * p1 * a + f1 * b * (-d * p2 + f2 * (p1 + d) * c))) +
+      (f2 * i00 * p1 * -c + 4. * pow<2>(f1) * f2 * i00 * -b * c +
+       2. * f1 * f2 * i00 * b * c + f2 * i00 * a +
+       2. * f1 * (-i11 * d * p2 + f2 * i00 * b * c)) /
+          (f2 * p1 * a + f1 * b * (-d * p2 + f2 * (p1 + d) * c));
+  const auto mpdp2 =
+      -(((f2 * (2. - 2. * p1) * p1 +
+          f1 * b * (1. - 2. * p2 + 2. * f2 * (p1 + d) + f2 * c)) *
+         (-pow<2>(f1) * f2 * i00 * pow<2>(b) * c + f2 * i00 * p1 * a +
+          f1 * b * (-i11 * d * p2 + f2 * i00 * b * c))) /
+        pow<2>(f2 * p1 * a + f1 * b * (-d * p2 + f2 * (p1 + d) * c))) +
+      (-2. * pow<2>(f1) * f2 * i00 * pow<2>(b) +
+       f2 * i00 * (2. - 2. * p1) * p1 +
+       f1 * b * (2. * f2 * i00 * b - i11 * d - i11 * p2)) /
+          (f2 * p1 * a + f1 * b * (-d * p2 + f2 * (p1 + d) * c));
+  // Estimate the error components using linearized extrapolation,
+  // sum in squares.
+  const auto e10_I00 = pow<2>(mpdi00 * e00);
+  const auto e10_I11 = pow<2>(mpdi11 * e11);
+  const auto e10_F1 = pow<2>(mpdf1 * f1E);
+  const auto e10_F2 = pow<2>(mpdf2 * f2E);
+  const auto e10_P1 = pow<2>(mpdp1 * p1E);
+  const auto e10_P2 = pow<2>(mpdp2 * p2E);
+  return std::sqrt(e10_I00 + e10_I11 + e10_F1 + e10_F2 + e10_P1 + e10_P2);
+}
+} // namespace
+
+namespace Mantid {
+namespace Algorithms {
+
+// Register the algorithm into the AlgorithmFactory
+DECLARE_ALGORITHM(PolarizationCorrectionWildes)
+
+//----------------------------------------------------------------------------------------------
+
+/// Algorithms name for identification. @see Algorithm::name
+const std::string PolarizationCorrectionWildes::name() const {
+  return "PolarizationCorrectionWildes";
+}
+
+/// Algorithm's version for identification. @see Algorithm::version
+int PolarizationCorrectionWildes::version() const { return 1; }
+
+/// Algorithm's category for identification. @see Algorithm::category
+const std::string PolarizationCorrectionWildes::category() const {
+  return "Reflectometry";
+}
+
+/// Algorithm's summary for use in the GUI and help. @see Algorithm::summary
+const std::string PolarizationCorrectionWildes::summary() const {
+  return "Corrects a group of polarization analysis workspaces for polarizer "
+         "and analyzer efficiencies.";
+}
+
+/**
+ * Count the non-nullptr workspaces
+ * @return the count on non-nullptr workspaces.
+ */
+size_t PolarizationCorrectionWildes::WorkspaceMap::size() const noexcept {
+  return (mmWS ? 1 : 0) + (mpWS ? 1 : 0) + (pmWS ? 1 : 0) + (ppWS ? 1 : 0);
+}
+
+//----------------------------------------------------------------------------------------------
+/** Initialize the algorithm's properties.
+ */
+void PolarizationCorrectionWildes::init() {
+  declareProperty(Kernel::make_unique<Kernel::ArrayProperty<std::string>>(
+                      Prop::INPUT_WS, "",
+                      boost::make_shared<API::ADSValidator>(),
+                      Kernel::Direction::Input),
+                  "A list of workspaces to be corrected corresponding to the "
+                  "flipper configurations.");
+  declareProperty(
+      Kernel::make_unique<API::WorkspaceProperty<API::WorkspaceGroup>>(
+          Prop::OUTPUT_WS, "", Kernel::Direction::Output),
+      "A group of polarization efficiency corrected workspaces.");
+  const std::string full = Flippers::OffOff + ", " + Flippers::OffOn + ", " +
+                           Flippers::OnOff + ", " + Flippers::OnOn;
+  const std::string missing01 =
+      Flippers::OffOff + ", " + Flippers::OnOff + ", " + Flippers::OnOn;
+  const std::string missing10 =
+      Flippers::OffOff + ", " + Flippers::OffOn + ", " + Flippers::OnOn;
+  const std::string missing0110 = Flippers::OffOff + ", " + Flippers::OnOn;
+  const std::string noAnalyzer = Flippers::Off + ", " + Flippers::On;
+  const std::string directBeam = Flippers::Off;
+  const std::vector<std::string> setups{
+      {full, missing01, missing10, missing0110, noAnalyzer, directBeam}};
+  declareProperty(
+      Prop::FLIPPERS, full,
+      boost::make_shared<Kernel::ListValidator<std::string>>(setups),
+      "Flipper configurations of the input workspaces.");
+  declareProperty(
+      Kernel::make_unique<API::WorkspaceProperty<API::MatrixWorkspace>>(
+          Prop::EFFICIENCIES, "", Kernel::Direction::Input),
+      "A workspace containing the efficiency factors P1, P2, F1 and F2 as "
+      "histograms");
+}
+
+//----------------------------------------------------------------------------------------------
+/** Execute the algorithm.
+ */
+void PolarizationCorrectionWildes::exec() {
+  const std::string flipperProperty = getProperty(Prop::FLIPPERS);
+  const auto flippers = parseFlipperSetup(flipperProperty);
+  const bool analyzer = flippers.front() != "0" && flippers.back() != "1";
+  const auto inputs = mapInputsToDirections(flippers);
+  checkConsistentNumberHistograms(inputs);
+  const EfficiencyMap efficiencies = efficiencyFactors();
+  checkConsistentX(inputs, efficiencies);
+  WorkspaceMap outputs;
+  switch (inputs.size()) {
+  case 1:
+    outputs = directBeamCorrections(inputs, efficiencies);
+    break;
+  case 2:
+    if (analyzer) {
+      outputs = twoInputCorrections(inputs, efficiencies);
+    } else {
+      outputs = analyzerlessCorrections(inputs, efficiencies);
+    }
+    break;
+  case 3:
+    outputs = threeInputCorrections(inputs, efficiencies);
+    break;
+  case 4:
+    outputs = fullCorrections(inputs, efficiencies);
+  }
+  setProperty(Prop::OUTPUT_WS, groupOutput(outputs));
+}
+
+/**
+ * Validate the algorithm's input properties.
+ * @return a map from property names to discovered issues
+ */
+std::map<std::string, std::string>
+PolarizationCorrectionWildes::validateInputs() {
+  std::map<std::string, std::string> issues;
+  API::MatrixWorkspace_const_sptr factorWS = getProperty(Prop::EFFICIENCIES);
+  const auto &factorAxis = factorWS->getAxis(1);
+  if (!factorAxis) {
+    issues[Prop::EFFICIENCIES] = "The workspace is missing a vertical axis.";
+  } else if (!factorAxis->isText()) {
+    issues[Prop::EFFICIENCIES] =
+        "The vertical axis in the workspace is not text axis.";
+  } else if (factorWS->getNumberHistograms() < 4) {
+    issues[Prop::EFFICIENCIES] =
+        "The workspace should contain at least 4 histograms.";
+  } else {
+    std::vector<std::string> tags{{"P1", "P2", "F1", "F2"}};
+    for (size_t i = 0; i != factorAxis->length(); ++i) {
+      const auto label = factorAxis->label(i);
+      auto found = std::find(tags.begin(), tags.end(), label);
+      if (found != tags.cend()) {
+        std::swap(tags.back(), *found);
+        tags.pop_back();
+      }
+    }
+    if (!tags.empty()) {
+      issues[Prop::EFFICIENCIES] = "A histogram labeled " + tags.front() +
+                                   " is missing from the workspace.";
+    }
+  }
+  const std::vector<std::string> inputs = getProperty(Prop::INPUT_WS);
+  const std::string flipperProperty = getProperty(Prop::FLIPPERS);
+  const auto flippers = parseFlipperSetup(flipperProperty);
+  if (inputs.size() != flippers.size()) {
+    issues[Prop::FLIPPERS] =
+        "The number of flipper configurations (" +
+        std::to_string(flippers.size()) +
+        ") does not match the number of input workspaces (" +
+        std::to_string(inputs.size()) + ")";
+  }
+  return issues;
+}
+
+/**
+ * Check that all workspaces in inputs have the same number of histograms.
+ * @param inputs a set of workspaces to check
+ */
+void PolarizationCorrectionWildes::checkConsistentNumberHistograms(
+    const WorkspaceMap &inputs) {
+  size_t nHist{0};
+  bool nHistValid{false};
+  // A local helper function to check the number of histograms.
+  auto checkNHist = [&nHist, &nHistValid](const API::MatrixWorkspace_sptr &ws,
+                                          const std::string &tag) {
+    if (nHistValid) {
+      if (nHist != ws->getNumberHistograms()) {
+        throw std::runtime_error("Number of histograms mismatch in " + tag);
+      }
+    } else {
+      nHist = ws->getNumberHistograms();
+      nHistValid = true;
+    }
+  };
+  if (inputs.mmWS) {
+    checkNHist(inputs.mmWS, Flippers::OffOff);
+  }
+  if (inputs.mpWS) {
+    checkNHist(inputs.mpWS, Flippers::OffOn);
+  }
+  if (inputs.pmWS) {
+    checkNHist(inputs.pmWS, Flippers::OnOff);
+  }
+  if (inputs.ppWS) {
+    checkNHist(inputs.ppWS, Flippers::OnOn);
+  }
+}
+
+/**
+ * Check that all workspaces and efficicencies have the same X data.
+ * @param inputs a set of workspaces to check
+ * @param efficiencies efficiencies to check
+ */
+void PolarizationCorrectionWildes::checkConsistentX(
+    const WorkspaceMap &inputs, const EfficiencyMap &efficiencies) {
+  // Compare everything to F1 efficiency.
+  const auto &F1x = efficiencies.F1->x();
+  // A local helper function to check a HistogramX against F1.
+  auto checkX =
+      [&F1x](const HistogramData::HistogramX &x, const std::string &tag) {
+        if (x.size() != F1x.size()) {
+          throw std::runtime_error(
+              "Mismatch of histogram lengths between F1 and " + tag + '.');
+        }
+        for (size_t i = 0; i != x.size(); ++i) {
+          if (x[i] != F1x[i]) {
+            throw std::runtime_error("Mismatch of X data between F1 and " +
+                                     tag + '.');
+          }
+        }
+      };
+  const auto &F2x = efficiencies.F2->x();
+  checkX(F2x, "F2");
+  const auto &P1x = efficiencies.P1->x();
+  checkX(P1x, "P1");
+  const auto &P2x = efficiencies.P2->x();
+  checkX(P2x, "P2");
+  // A local helper function to check an input workspace against F1.
+  auto checkWS =
+      [&checkX](const API::MatrixWorkspace_sptr &ws, const std::string &tag) {
+        const auto nHist = ws->getNumberHistograms();
+        for (size_t i = 0; i != nHist; ++i) {
+          checkX(ws->x(i), tag);
+        }
+      };
+  if (inputs.mmWS) {
+    checkWS(inputs.mmWS, Flippers::OffOff);
+  }
+  if (inputs.mpWS) {
+    checkWS(inputs.mpWS, Flippers::OffOn);
+  }
+  if (inputs.pmWS) {
+    checkWS(inputs.pmWS, Flippers::OnOff);
+  }
+  if (inputs.ppWS) {
+    checkWS(inputs.ppWS, Flippers::OnOn);
+  }
+}
+
+/**
+ * Make a workspace group out of the given set of workspaces.
+ * The workspaces will be published in the ADS, their names appended by
+ * appropriate suffices.
+ * @param outputs a set of workspaces to group
+ * @return a group workspace
+ */
+API::WorkspaceGroup_sptr
+PolarizationCorrectionWildes::groupOutput(const WorkspaceMap &outputs) {
+  const std::string outWSName = getProperty(Prop::OUTPUT_WS);
+  std::vector<std::string> names;
+  if (outputs.mmWS) {
+    names.emplace_back(outWSName + "_--");
+    API::AnalysisDataService::Instance().addOrReplace(names.back(),
+                                                      outputs.mmWS);
+  }
+  if (outputs.mpWS) {
+    names.emplace_back(outWSName + "_-+");
+    API::AnalysisDataService::Instance().addOrReplace(names.back(),
+                                                      outputs.mpWS);
+  }
+  if (outputs.pmWS) {
+    names.emplace_back(outWSName + "_+-");
+    API::AnalysisDataService::Instance().addOrReplace(names.back(),
+                                                      outputs.pmWS);
+  }
+  if (outputs.ppWS) {
+    names.emplace_back(outWSName + "_++");
+    API::AnalysisDataService::Instance().addOrReplace(names.back(),
+                                                      outputs.ppWS);
+  }
+  auto group = createChildAlgorithm("GroupWorkspaces");
+  group->initialize();
+  group->setProperty("InputWorkspaces", names);
+  group->setProperty("OutputWorkspace", outWSName);
+  group->execute();
+  API::WorkspaceGroup_sptr outWS = group->getProperty("OutputWorkspace");
+  return outWS;
+}
+
+/**
+ * Make a convenience access object to the efficiency factors.
+ * @return an EfficiencyMap object
+ */
+PolarizationCorrectionWildes::EfficiencyMap
+PolarizationCorrectionWildes::efficiencyFactors() {
+  EfficiencyMap e;
+  API::MatrixWorkspace_const_sptr factorWS = getProperty(Prop::EFFICIENCIES);
+  const auto &vertAxis = factorWS->getAxis(1);
+  for (size_t i = 0; i != vertAxis->length(); ++i) {
+    const auto label = vertAxis->label(i);
+    if (label == "P1") {
+      e.P1 = &factorWS->getSpectrum(i);
+    } else if (label == "P2") {
+      e.P2 = &factorWS->getSpectrum(i);
+    } else if (label == "F1") {
+      e.F1 = &factorWS->getSpectrum(i);
+    } else if (label == "F2") {
+      e.F2 = &factorWS->getSpectrum(i);
+    }
+    // Ignore other histograms such as 'Phi' in ILL's efficiency ws.
+  }
+  return e;
+}
+
+/**
+ * Correct a direct beam measurement for non-ideal instrument effects.
+ * Only the non-analyzer, polarizer flipper off case is considered here.
+ * @param inputs a set of workspaces to correct
+ * @param efficiencies a set of efficiency factors
+ * @return set of corrected workspaces
+ */
+PolarizationCorrectionWildes::WorkspaceMap
+PolarizationCorrectionWildes::directBeamCorrections(
+    const WorkspaceMap &inputs, const EfficiencyMap &efficiencies) {
+  using namespace boost::math;
+  checkInputExists(inputs.ppWS, Flippers::Off);
+  WorkspaceMap outputs;
+  outputs.ppWS = DataObjects::create<DataObjects::Workspace2D>(*inputs.ppWS);
+  const size_t nHisto = inputs.ppWS->getNumberHistograms();
+  for (size_t wsIndex = 0; wsIndex != nHisto; ++wsIndex) {
+    const auto &ppY = inputs.ppWS->y(wsIndex);
+    const auto &ppE = inputs.ppWS->e(wsIndex);
+    auto &ppYOut = outputs.ppWS->mutableY(wsIndex);
+    auto &ppEOut = outputs.ppWS->mutableE(wsIndex);
+    for (size_t binIndex = 0; binIndex < ppY.size(); ++binIndex) {
+      const auto P1 = efficiencies.P1->y()[binIndex];
+      const auto P2 = efficiencies.P2->y()[binIndex];
+      const double f = 1. - P1 - P2 + 2. * P1 * P2;
+      ppYOut[binIndex] = ppY[binIndex] / f;
+      const auto P1E = efficiencies.P1->e()[binIndex];
+      const auto P2E = efficiencies.P2->e()[binIndex];
+      const auto e1 = pow<2>(P1E * (2. * P1 - 1.) / pow<2>(f) * ppY[binIndex]);
+      const auto e2 = pow<2>(P2E * (2. * P2 - 1.) / pow<2>(f) * ppY[binIndex]);
+      const auto e3 = pow<2>(ppE[binIndex] / f);
+      const auto errorSum = std::sqrt(e1 + e2 + e3);
+      ppEOut[binIndex] = errorSum;
+    }
+  }
+  return outputs;
+}
+
+/**
+ * Correct for non-ideal instrument effects.
+ * Deals with the case when the data was taken without the analyzer:
+ * only the polarizer flipper is used.
+ * @param inputs a set of workspaces to correct
+ * @param efficiencies a set of efficiency factors
+ * @return a set of corrected workspaces
+ */
+PolarizationCorrectionWildes::WorkspaceMap
+PolarizationCorrectionWildes::analyzerlessCorrections(
+    const WorkspaceMap &inputs, const EfficiencyMap &efficiencies) {
+  using namespace boost::math;
+  checkInputExists(inputs.mmWS, Flippers::On);
+  checkInputExists(inputs.ppWS, Flippers::Off);
+  WorkspaceMap outputs;
+  outputs.mmWS = DataObjects::create<DataObjects::Workspace2D>(*inputs.mmWS);
+  outputs.ppWS = DataObjects::create<DataObjects::Workspace2D>(*inputs.ppWS);
+  const size_t nHisto = inputs.mmWS->getNumberHistograms();
+  for (size_t wsIndex = 0; wsIndex != nHisto; ++wsIndex) {
+    const auto &mmY = inputs.mmWS->y(wsIndex);
+    const auto &mmE = inputs.mmWS->e(wsIndex);
+    const auto &ppY = inputs.ppWS->y(wsIndex);
+    const auto &ppE = inputs.ppWS->e(wsIndex);
+    auto &mmYOut = outputs.mmWS->mutableY(wsIndex);
+    auto &mmEOut = outputs.mmWS->mutableE(wsIndex);
+    auto &ppYOut = outputs.ppWS->mutableY(wsIndex);
+    auto &ppEOut = outputs.ppWS->mutableE(wsIndex);
+    for (size_t binIndex = 0; binIndex < mmY.size(); ++binIndex) {
+      const auto F1 = efficiencies.F1->y()[binIndex];
+      const auto P1 = efficiencies.P1->y()[binIndex];
+      Eigen::Matrix2d F1m;
+      F1m << 1., 0., (F1 - 1.) / F1, 1. / F1;
+      const double divisor = (2. * P1 - 1.);
+      const double diag = (P1 - 1.) / divisor;
+      const double off = P1 / divisor;
+      Eigen::Matrix2d P1m;
+      P1m << diag, off, off, diag;
+      const Eigen::Vector2d intensities(ppY[binIndex], mmY[binIndex]);
+      const auto PFProduct = P1m * F1m;
+      const auto corrected = PFProduct * intensities;
+      ppYOut[binIndex] = corrected[0];
+      mmYOut[binIndex] = corrected[1];
+      const auto F1E = efficiencies.F1->e()[binIndex];
+      const auto P1E = efficiencies.P1->e()[binIndex];
+      const auto elemE1 = -1. / pow<2>(F1) * F1E;
+      Eigen::Matrix2d F1Em;
+      F1Em << 0., 0., -elemE1, elemE1;
+      const auto elemE2 = 1. / pow<2>(divisor) * P1E;
+      Eigen::Matrix2d P1Em;
+      P1Em << elemE2, -elemE2, -elemE2, elemE2;
+      const Eigen::Vector2d errors(ppE[binIndex], mmE[binIndex]);
+      const auto e1 = (P1Em * F1m * intensities).array();
+      const auto e2 = (P1m * F1Em * intensities).array();
+      const auto sqPFProduct = (PFProduct.array() * PFProduct.array()).matrix();
+      const auto sqErrors = (errors.array() * errors.array()).matrix();
+      const auto e3 = (sqPFProduct * sqErrors).array();
+      const auto errorSum = (e1 * e1 + e2 * e2 + e3).sqrt();
+      ppEOut[binIndex] = errorSum[0];
+      mmEOut[binIndex] = errorSum[1];
+    }
+  }
+  return outputs;
+}
+
+/**
+ * Correct for non-ideal instrument effects.
+ * Only 00 and 11 flipper configurations need to be provided;
+ * the missing 01 and 10 data is solved from the assumption that
+ * in the corrected data, R01 = R10 = 0.
+ * @param inputs a set of workspaces to correct
+ * @param efficiencies a set of efficiency factors
+ * @return a set of corrected workspaces
+ */
+PolarizationCorrectionWildes::WorkspaceMap
+PolarizationCorrectionWildes::twoInputCorrections(
+    const WorkspaceMap &inputs, const EfficiencyMap &efficiencies) {
+  using namespace boost::math;
+  checkInputExists(inputs.mmWS, Flippers::OnOn);
+  checkInputExists(inputs.ppWS, Flippers::OffOff);
+  WorkspaceMap fullInputs = inputs;
+  fullInputs.mpWS = DataObjects::create<DataObjects::Workspace2D>(*inputs.mmWS);
+  fullInputs.pmWS = DataObjects::create<DataObjects::Workspace2D>(*inputs.ppWS);
+  twoInputsSolve01And10(fullInputs, inputs, efficiencies);
+  return fullCorrections(fullInputs, efficiencies);
+}
+
+/**
+ * Correct for non-ideal instrument effects.
+ * Needs the 00 and 11 flipper configurations as well as either 01 or 10.
+ * The missing intensity (01 or 10) is solved from the assumption
+ * that the corrected R01 = R10.
+ * @param inputs a set of workspaces to correct
+ * @param efficiencies a set of efficiency factors
+ * @return a set of corrected workspaces
+ */
+PolarizationCorrectionWildes::WorkspaceMap
+PolarizationCorrectionWildes::threeInputCorrections(
+    const WorkspaceMap &inputs, const EfficiencyMap &efficiencies) {
+  WorkspaceMap fullInputs = inputs;
+  checkInputExists(inputs.mmWS, Flippers::OnOn);
+  checkInputExists(inputs.ppWS, Flippers::OffOff);
+  if (!inputs.mpWS) {
+    checkInputExists(inputs.pmWS, Flippers::OffOn);
+    threeInputsSolve10(fullInputs, efficiencies);
+  } else {
+    checkInputExists(inputs.mpWS, Flippers::OnOff);
+    threeInputsSolve01(fullInputs, efficiencies);
+  }
+  return fullCorrections(fullInputs, efficiencies);
+}
+
+/**
+ * Correct for non-ideal instrument effects.
+ * Perform full polarization corrections. All flipper configurations
+ * (00, 01, 10 and 11) are needed for this.
+ * @param inputs a set of workspaces to correct
+ * @param efficiencies a set of efficiency factors
+ * @return a set of corrected workspaces
+ */
+PolarizationCorrectionWildes::WorkspaceMap
+PolarizationCorrectionWildes::fullCorrections(
+    const WorkspaceMap &inputs, const EfficiencyMap &efficiencies) {
+  using namespace boost::math;
+  checkInputExists(inputs.mmWS, Flippers::OnOn);
+  checkInputExists(inputs.mpWS, Flippers::OnOff);
+  checkInputExists(inputs.pmWS, Flippers::OffOn);
+  checkInputExists(inputs.ppWS, Flippers::OffOff);
+  WorkspaceMap outputs;
+  outputs.mmWS = DataObjects::create<DataObjects::Workspace2D>(*inputs.mmWS);
+  outputs.mpWS = DataObjects::create<DataObjects::Workspace2D>(*inputs.mpWS);
+  outputs.pmWS = DataObjects::create<DataObjects::Workspace2D>(*inputs.pmWS);
+  outputs.ppWS = DataObjects::create<DataObjects::Workspace2D>(*inputs.ppWS);
+  const auto F1 = efficiencies.F1->y();
+  const auto F1E = efficiencies.F1->e();
+  const auto F2 = efficiencies.F2->y();
+  const auto F2E = efficiencies.F2->e();
+  const auto P1 = efficiencies.P1->y();
+  const auto P1E = efficiencies.P1->e();
+  const auto P2 = efficiencies.P2->y();
+  const auto P2E = efficiencies.P2->e();
+  const size_t nHisto = inputs.mmWS->getNumberHistograms();
+  for (size_t wsIndex = 0; wsIndex != nHisto; ++wsIndex) {
+    const auto &mmY = inputs.mmWS->y(wsIndex);
+    const auto &mmE = inputs.mmWS->e(wsIndex);
+    const auto &mpY = inputs.mpWS->y(wsIndex);
+    const auto &mpE = inputs.mpWS->e(wsIndex);
+    const auto &pmY = inputs.pmWS->y(wsIndex);
+    const auto &pmE = inputs.pmWS->e(wsIndex);
+    const auto &ppY = inputs.ppWS->y(wsIndex);
+    const auto &ppE = inputs.ppWS->e(wsIndex);
+    auto &mmYOut = outputs.mmWS->mutableY(wsIndex);
+    auto &mmEOut = outputs.mmWS->mutableE(wsIndex);
+    auto &mpYOut = outputs.mpWS->mutableY(wsIndex);
+    auto &mpEOut = outputs.mpWS->mutableE(wsIndex);
+    auto &pmYOut = outputs.pmWS->mutableY(wsIndex);
+    auto &pmEOut = outputs.pmWS->mutableE(wsIndex);
+    auto &ppYOut = outputs.ppWS->mutableY(wsIndex);
+    auto &ppEOut = outputs.ppWS->mutableE(wsIndex);
+    for (size_t binIndex = 0; binIndex < mmY.size(); ++binIndex) {
+      Eigen::Vector4d corrected;
+      Eigen::Vector4d errors;
+      fourInputsCorrectedAndErrors(corrected, errors, ppY[binIndex],
+                                   ppE[binIndex], pmY[binIndex], pmE[binIndex],
+                                   mpY[binIndex], mpE[binIndex], mmY[binIndex],
+                                   mmE[binIndex], F1[binIndex], F1E[binIndex],
+                                   F2[binIndex], F2E[binIndex], P1[binIndex],
+                                   P1E[binIndex], P2[binIndex], P2E[binIndex]);
+      ppYOut[binIndex] = corrected[0];
+      pmYOut[binIndex] = corrected[1];
+      mpYOut[binIndex] = corrected[2];
+      mmYOut[binIndex] = corrected[3];
+      ppEOut[binIndex] = errors[0];
+      pmEOut[binIndex] = errors[1];
+      mpEOut[binIndex] = errors[2];
+      mmEOut[binIndex] = errors[3];
+    }
+  }
+  return outputs;
+}
+
+/**
+ * Make a set of workspaces to correct from input properties.
+ * @param flippers a vector of flipper configurations
+ * @return a set of workspaces to correct
+ */
+PolarizationCorrectionWildes::WorkspaceMap
+PolarizationCorrectionWildes::mapInputsToDirections(
+    const std::vector<std::string> &flippers) {
+  const std::vector<std::string> inputNames = getProperty(Prop::INPUT_WS);
+  WorkspaceMap inputs;
+  for (size_t i = 0; i < flippers.size(); ++i) {
+    auto ws =
+        (API::AnalysisDataService::Instance().retrieveWS<API::MatrixWorkspace>(
+            inputNames[i]));
+    if (!ws) {
+      throw std::runtime_error(
+          "One of the input workspaces doesn't seem to be a MatrixWorkspace.");
+    }
+    const auto &f = flippers[i];
+    if (f == Flippers::OnOn || f == Flippers::On) {
+      inputs.mmWS = ws;
+    } else if (f == Flippers::OnOff) {
+      inputs.mpWS = ws;
+    } else if (f == Flippers::OffOn) {
+      inputs.pmWS = ws;
+    } else if (f == Flippers::OffOff || f == Flippers::Off) {
+      inputs.ppWS = ws;
+    } else {
+      throw std::runtime_error(std::string{"Unknown entry in "} +
+                               Prop::FLIPPERS);
+    }
+  }
+  return inputs;
+}
+
+/**
+ * Solve in-place the 01 flipper configuration from the assumption that
+ * for the corrected intensities, R01 = R10.
+ * @param inputs a set of input workspaces
+ * @param efficiencies a set of efficiency factors
+ */
+void PolarizationCorrectionWildes::threeInputsSolve01(
+    WorkspaceMap &inputs, const EfficiencyMap &efficiencies) {
+  using namespace Mantid::DataObjects;
+  inputs.pmWS = create<Workspace2D>(*inputs.mpWS);
+  const auto &F1 = efficiencies.F1->y();
+  const auto &F2 = efficiencies.F2->y();
+  const auto &P1 = efficiencies.P1->y();
+  const auto &P2 = efficiencies.P2->y();
+  const auto nHisto = inputs.pmWS->getNumberHistograms();
+  for (size_t wsIndex = 0; wsIndex != nHisto; ++wsIndex) {
+    const auto &I00 = inputs.ppWS->y(wsIndex);
+    auto &I01 = inputs.pmWS->mutableY(wsIndex);
+    const auto &I10 = inputs.mpWS->y(wsIndex);
+    const auto &I11 = inputs.mmWS->y(wsIndex);
+    for (size_t binIndex = 0; binIndex != I00.size(); ++binIndex) {
+      const auto f1 = F1[binIndex];
+      const auto f2 = F2[binIndex];
+      const auto p1 = P1[binIndex];
+      const auto p2 = P2[binIndex];
+      const auto i00 = I00[binIndex];
+      const auto i10 = I10[binIndex];
+      const auto i11 = I11[binIndex];
+      I01[binIndex] =
+          (f1 * i00 * (-1. + 2. * p1) - (i00 - i10 + i11) * (p1 - p2) -
+           f2 * (i00 - i10) * (-1. + 2. * p2)) /
+          (-p1 + f1 * (-1. + 2. * p1) + p2);
+      // The errors are left to zero.
+    }
+  }
+}
+
+/**
+ * Solve in-place the 10 flipper configuration from the assumption that
+ * for the corrected intensities R01 = R10.
+ * @param inputs a set of input workspaces
+ * @param efficiencies a set of efficiency factors
+ */
+void PolarizationCorrectionWildes::threeInputsSolve10(
+    WorkspaceMap &inputs, const EfficiencyMap &efficiencies) {
+  inputs.mpWS = DataObjects::create<DataObjects::Workspace2D>(*inputs.pmWS);
+  const auto &F1 = efficiencies.F1->y();
+  const auto &F2 = efficiencies.F2->y();
+  const auto &P1 = efficiencies.P1->y();
+  const auto &P2 = efficiencies.P2->y();
+  const auto nHisto = inputs.mpWS->getNumberHistograms();
+  for (size_t wsIndex = 0; wsIndex != nHisto; ++wsIndex) {
+    const auto &I00 = inputs.ppWS->y(wsIndex);
+    const auto &I01 = inputs.pmWS->y(wsIndex);
+    auto &I10 = inputs.mpWS->mutableY(wsIndex);
+    const auto &I11 = inputs.mmWS->y(wsIndex);
+    for (size_t binIndex = 0; binIndex != I00.size(); ++binIndex) {
+      const auto f1 = F1[binIndex];
+      const auto f2 = F2[binIndex];
+      const auto p1 = P1[binIndex];
+      const auto p2 = P2[binIndex];
+      const auto i00 = I00[binIndex];
+      const auto i01 = I01[binIndex];
+      const auto i11 = I11[binIndex];
+      I10[binIndex] =
+          (-f1 * (i00 - i01) * (-1. + 2. * p1) + (i00 - i01 + i11) * (p1 - p2) +
+           f2 * i00 * (-1. + 2. * p2)) /
+          (p1 - p2 + f2 * (-1. + 2. * p2));
+      // The errors are left to zero.
+    }
+  }
+}
+
+/**
+ * Solve in-place the 01 and 10 flipper configurations from the assumption that
+ * for the corrected intensities R01 = R10 = 0.
+ * @param fullInputs a set of output workspaces
+ * @param inputs a set of input workspaces
+ * @param efficiencies a set of efficiency factors
+ */
+void PolarizationCorrectionWildes::twoInputsSolve01And10(
+    WorkspaceMap &fullInputs, const WorkspaceMap &inputs,
+    const EfficiencyMap &efficiencies) {
+  using namespace boost::math;
+  const auto &F1 = efficiencies.F1->y();
+  const auto &F1E = efficiencies.F1->e();
+  const auto &F2 = efficiencies.F2->y();
+  const auto &F2E = efficiencies.F2->e();
+  const auto &P1 = efficiencies.P1->y();
+  const auto &P1E = efficiencies.P1->e();
+  const auto &P2 = efficiencies.P2->y();
+  const auto &P2E = efficiencies.P2->e();
+  const auto nHisto = inputs.mmWS->getNumberHistograms();
+  for (size_t wsIndex = 0; wsIndex != nHisto; ++wsIndex) {
+    const auto &I00 = inputs.ppWS->y(wsIndex);
+    const auto &E00 = inputs.ppWS->e(wsIndex);
+    const auto &I11 = inputs.mmWS->y(wsIndex);
+    const auto &E11 = inputs.mmWS->e(wsIndex);
+    auto &I01 = fullInputs.pmWS->mutableY(wsIndex);
+    auto &E01 = fullInputs.pmWS->mutableE(wsIndex);
+    auto &I10 = fullInputs.mpWS->mutableY(wsIndex);
+    auto &E10 = fullInputs.mpWS->mutableE(wsIndex);
+    for (size_t binIndex = 0; binIndex != I00.size(); ++binIndex) {
+      const auto i00 = I00[binIndex];
+      const auto i11 = I11[binIndex];
+      const auto f1 = F1[binIndex];
+      const auto f2 = F2[binIndex];
+      const auto p1 = P1[binIndex];
+      const auto p2 = P2[binIndex];
+      const auto a = -1. + p1 + 2. * p2 - 2. * p1 * p2;
+      const auto b = -1. + 2. * p1;
+      const auto c = -1. + 2. * p2;
+      const auto d = -1. + p2;
+      // Case: 01
+      const auto divisor = f2 * p1 * a + f1 * b * (-d * p2 + f2 * (p1 + d) * c);
+      I01[binIndex] =
+          (f2 * i11 * p1 * a -
+           f1 * i00 * b * (-f2 * pow<2>(c) + pow<2>(f2 * c) + d * p2)) /
+          divisor;
+      E01[binIndex] = twoInputsErrorEstimate01(
+          i00, E00[binIndex], i11, E11[binIndex], p1, P1E[binIndex], p2,
+          P2E[binIndex], f1, F1E[binIndex], f2, F2E[binIndex]);
+      // Case: 10
+      I10[binIndex] =
+          (-pow<2>(f1) * f2 * i00 * pow<2>(b) * c + f2 * i00 * p1 * a +
+           f1 * b * (-i11 * d * p2 + f2 * i00 * b * c)) /
+          divisor;
+      E10[binIndex] = twoInputsErrorEstimate10(
+          i00, E00[binIndex], i11, E11[binIndex], p1, P1E[binIndex], p2,
+          P2E[binIndex], f1, F1E[binIndex], f2, F2E[binIndex]);
+    }
+  }
+}
+} // namespace Algorithms
+} // namespace Mantid
diff --git a/Framework/Algorithms/src/PolarizationEfficiencyCor.cpp b/Framework/Algorithms/src/PolarizationEfficiencyCor.cpp
index 8a143b35f67b0825a31152b1d68be1cbaafeb94f..44b10eae96c3cad947d1f2e5591b1ebf26579422 100644
--- a/Framework/Algorithms/src/PolarizationEfficiencyCor.cpp
+++ b/Framework/Algorithms/src/PolarizationEfficiencyCor.cpp
@@ -10,16 +10,22 @@
 #include "MantidKernel/ListValidator.h"
 #include "MantidKernel/StringTokenizer.h"
 
+#include "MantidAPI/WorkspaceFactory.h"
+
 #include <Eigen/Dense>
 #include <boost/math/special_functions/pow.hpp>
 
 namespace {
+
 /// Property names.
 namespace Prop {
 static const std::string FLIPPERS{"Flippers"};
+static const std::string POLARIZATION_ANALYSIS{"PolarizationAnalysis"};
 static const std::string EFFICIENCIES{"Efficiencies"};
-static const std::string INPUT_WS{"InputWorkspaces"};
-static const std::string OUTPUT_WS{"OutputWorkspace"};
+static const std::string INPUT_WORKSPACES{"InputWorkspaces"};
+static const std::string INPUT_WORKSPACE_GROUP{"InputWorkspaceGroup"};
+static const std::string OUTPUT_WORKSPACES{"OutputWorkspace"};
+static const std::string CORRECTION_METHOD{"CorrectionMethod"};
 } // namespace Prop
 
 /// Flipper configurations.
@@ -32,326 +38,19 @@ static const std::string OnOff{"10"};
 static const std::string OnOn{"11"};
 } // namespace Flippers
 
-/**
- * Parse a flipper configuration string.
- * @param setupString a configuration string
- * @return a vector of individual configurations
- */
-std::vector<std::string> parseFlipperSetup(const std::string &setupString) {
-  using Mantid::Kernel::StringTokenizer;
-  StringTokenizer tokens{setupString, ",", StringTokenizer::TOK_TRIM};
-  return std::vector<std::string>{tokens.begin(), tokens.end()};
-}
-
-/**
- * Throw if given ws is nullptr.
- * @param ws a workspace to check
- * @param tag a flipper configuration for the error message
- */
-void checkInputExists(const Mantid::API::MatrixWorkspace_sptr &ws,
-                      const std::string &tag) {
-  if (!ws) {
-    throw std::runtime_error("A workspace designated as " + tag +
-                             " is missing in inputs.");
-  }
-}
-
-/**
- * Calculate the corrected intensities and error estimates.
- * @param corrected an output vector for R00, R01, R10 and R11
- * @param errors an output vector for the error estimates
- * @param ppy intensity I00
- * @param ppyE error of ppy
- * @param pmy intensity I01
- * @param pmyE error of pmy
- * @param mpy intensity I10
- * @param mpyE error of mpy
- * @param mmy intensity I11
- * @param mmyE error of mmy
- * @param f1 polarizer efficiency
- * @param f1E error of f1
- * @param f2 analyzer efficiency
- * @param f2E error of f2
- * @param p1 polarizer flipper efficiency
- * @param p1E error of p1
- * @param p2 analyzer flipper efficiency
- * @param p2E error of p2
- */
-void fourInputsCorrectedAndErrors(
-    Eigen::Vector4d &corrected, Eigen::Vector4d &errors, const double ppy,
-    const double ppyE, const double pmy, const double pmyE, const double mpy,
-    const double mpyE, const double mmy, const double mmyE, const double f1,
-    const double f1E, const double f2, const double f2E, const double p1,
-    const double p1E, const double p2, const double p2E) {
-  using namespace boost::math;
-  // Note that f1 and f2 correspond to 1-F1 and 1-F2 in [Wildes, 1999].
-  // These are inverted forms of the efficiency matrices.
-  const auto diag1 = 1. / f1;
-  const auto off1 = (f1 - 1.) / f1;
-  Eigen::Matrix4d F1m;
-  F1m << 1., 0., 0., 0., 0., 1., 0., 0., off1, 0., diag1, 0., 0., off1, 0.,
-      diag1;
-  const auto diag2 = 1. / f2;
-  const auto off2 = (f2 - 1.) / f2;
-  Eigen::Matrix4d F2m;
-  F2m << 1., 0., 0., 0., off2, diag2, 0., 0., 0., 0., 1., 0., 0., 0., off2,
-      diag2;
-  const auto diag3 = (p1 - 1.) / (2. * p1 - 1.);
-  const auto off3 = p1 / (2. * p1 - 1);
-  Eigen::Matrix4d P1m;
-  P1m << diag3, 0, off3, 0, 0, diag3, 0, off3, off3, 0, diag3, 0, 0, off3, 0,
-      diag3;
-  const auto diag4 = (p2 - 1.) / (2. * p2 - 1.);
-  const auto off4 = p2 / (2. * p2 - 1.);
-  Eigen::Matrix4d P2m;
-  P2m << diag4, off4, 0., 0., off4, diag4, 0., 0., 0., 0., diag4, off4, 0., 0.,
-      off4, diag4;
-  const Eigen::Vector4d intensities(ppy, pmy, mpy, mmy);
-  const auto FProduct = F2m * F1m;
-  const auto PProduct = P2m * P1m;
-  const auto PFProduct = PProduct * FProduct;
-  corrected = PFProduct * intensities;
-  // The error matrices here are element-wise algebraic derivatives of
-  // the matrices above, multiplied by the error.
-  const auto elemE1 = -1. / pow<2>(f1) * f1E;
-  Eigen::Matrix4d F1Em;
-  F1Em << 0., 0., 0., 0., 0., 0., 0., 0., -elemE1, 0., elemE1, 0., 0., -elemE1,
-      0., elemE1;
-  const auto elemE2 = -1. / pow<2>(f2) * f2E;
-  Eigen::Matrix4d F2Em;
-  F2Em << 0., 0., 0., 0., -elemE2, elemE2, 0., 0., 0., 0., 0., 0., 0., 0.,
-      -elemE2, elemE2;
-  const auto elemE3 = 1. / pow<2>(2. * p1 - 1.) * p1E;
-  Eigen::Matrix4d P1Em;
-  P1Em << elemE3, 0., -elemE3, 0., 0., elemE3, 0., -elemE3, -elemE3, 0., elemE3,
-      0., 0., -elemE3, 0., elemE3;
-  const auto elemE4 = 1. / pow<2>(2. * p2 - 1.) * p2E;
-  Eigen::Matrix4d P2Em;
-  P2Em << elemE4, -elemE4, 0., 0., -elemE4, elemE4, 0., 0., 0., 0., elemE4,
-      -elemE4, 0., 0., -elemE4, elemE4;
-  const Eigen::Vector4d yErrors(ppyE, pmyE, mpyE, mmyE);
-  const auto e1 = (P2Em * P1m * FProduct * intensities).array();
-  const auto e2 = (P2m * P1Em * FProduct * intensities).array();
-  const auto e3 = (PProduct * F2Em * F1m * intensities).array();
-  const auto e4 = (PProduct * F2m * F1Em * intensities).array();
-  const auto sqPFProduct = (PFProduct.array() * PFProduct.array()).matrix();
-  const auto sqErrors = (yErrors.array() * yErrors.array()).matrix();
-  const auto e5 = (sqPFProduct * sqErrors).array();
-  errors = (e1 * e1 + e2 * e2 + e3 * e3 + e4 * e4 + e5).sqrt();
-}
+namespace CorrectionMethod {
+static const std::string WILDES{"Wildes"};
+static const std::string FREDRIKZE{"Fredrikze"};
+} // namespace CorrectionMethod
 
-/**
- * Estimate errors for I01 in the two inputs case.
- * @param i00 intensity of 00 flipper configuration
- * @param e00 error of i00
- * @param i11 intensity of 11 flipper configuration
- * @param e11 error of i11
- * @param p1 polarizer efficiency
- * @param p1E error of p1
- * @param p2 analyzer efficiency
- * @param p2E error of p2
- * @param f1 polarizer flipper efficiency
- * @param f1E error of f1
- * @param f2 analyzer flipper efficiency
- * @param f2E error of f2
- * @return the error estimate
- */
-double twoInputsErrorEstimate01(const double i00, const double e00,
-                                const double i11, const double e11,
-                                const double p1, const double p1E,
-                                const double p2, const double p2E,
-                                const double f1, const double f1E,
-                                const double f2, const double f2E) {
-  using namespace boost::math;
-  // Derivatives of the equation which solves the I01 intensities
-  // with respect to i00, i11, f1, etc.
-  const auto pmdi00 =
-      -((f1 * (-1. + 2. * p1) *
-         (-f2 * pow<2>(1. - 2. * p2) + pow<2>(f2) * pow<2>(1. - 2. * p2) +
-          (-1. + p2) * p2)) /
-        (f2 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) +
-         f1 * (-1. + 2. * p1) *
-             ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2))));
-  const auto pmdi11 =
-      (f2 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2)) /
-      (f2 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) +
-       f1 * (-1. + 2. * p1) *
-           ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2)));
-  const auto pmdf1 =
-      -(((-1. + 2. * p1) *
-         ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2)) *
-         (f2 * i11 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) -
-          f1 * i00 * (-1. + 2. * p1) *
-              (-f2 * pow<2>(1. - 2. * p2) + pow<2>(f2) * pow<2>(1. - 2. * p2) +
-               (-1. + p2) * p2))) /
-        pow<2>(f2 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) +
-               f1 * (-1. + 2. * p1) *
-                   ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2)))) -
-      (i00 * (-1. + 2. * p1) *
-       (-f2 * pow<2>(1. - 2. * p2) + pow<2>(f2) * pow<2>(1. - 2. * p2) +
-        (-1. + p2) * p2)) /
-          (f2 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) +
-           f1 * (-1. + 2. * p1) *
-               ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2)));
-  const auto pmdf2 =
-      -(((f1 * (-1. + 2. * p1) * (-1. + p1 + p2) * (-1 + 2 * p2) +
-          p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2)) *
-         (f2 * i11 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) -
-          f1 * i00 * (-1. + 2. * p1) *
-              (-f2 * pow<2>(1. - 2. * p2) + pow<2>(f2) * pow<2>(1. - 2. * p2) +
-               (-1. + p2) * p2))) /
-        pow<2>(f2 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) +
-               f1 * (-1. + 2. * p1) *
-                   ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2)))) +
-      (-f1 * i00 * (-1. + 2. * p1) *
-           (-pow<2>(1. - 2. * p2) + 2 * f2 * pow<2>(1. - 2. * p2)) +
-       i11 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2)) /
-          (f2 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) +
-           f1 * (-1. + 2. * p1) *
-               ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2)));
-  const auto pmdp1 =
-      -(((f2 * i11 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) -
-          f1 * i00 * (-1. + 2. * p1) *
-              (-f2 * pow<2>(1. - 2. * p2) + pow<2>(f2) * pow<2>(1. - 2. * p2) +
-               (-1. + p2) * p2)) *
-         (f2 * p1 * (1. - 2. * p2) +
-          f1 * f2 * (-1. + 2. * p1) * (-1. + 2. * p2) +
-          f2 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) +
-          2. * f1 *
-              ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2)))) /
-        pow<2>(f2 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) +
-               f1 * (-1. + 2. * p1) *
-                   ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2)))) +
-      (f2 * i11 * p1 * (1. - 2. * p2) +
-       f2 * i11 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) -
-       2. * f1 * i00 * (-f2 * pow<2>(1. - 2. * p2) +
-                        pow<2>(f2) * pow<2>(1. - 2. * p2) + (-1. + p2) * p2)) /
-          (f2 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) +
-           f1 * (-1. + 2. * p1) *
-               ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2)));
-  const auto pmdp2 =
-      -(((f2 * i11 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) -
-          f1 * i00 * (-1. + 2. * p1) *
-              (-f2 * pow<2>(1. - 2. * p2) + pow<2>(f2) * pow<2>(1. - 2. * p2) +
-               (-1. + p2) * p2)) *
-         (f2 * (2. - 2. * p1) * p1 +
-          f1 * (-1. + 2. * p1) * (1. - 2. * p2 + 2. * f2 * (-1. + p1 + p2) +
-                                  f2 * (-1. + 2. * p2)))) /
-        pow<2>(f2 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) +
-               f1 * (-1. + 2. * p1) *
-                   ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2)))) +
-      (f2 * i11 * (2. - 2. * p1) * p1 -
-       f1 * i00 * (-1. + 2. * p1) *
-           (-1. + 4. * f2 * (1. - 2. * p2) - 4. * pow<2>(f2) * (1. - 2. * p2) +
-            2. * p2)) /
-          (f2 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) +
-           f1 * (-1. + 2. * p1) *
-               ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2)));
-  // Estimate the error components using linearized extrapolation,
-  // sum in squares.
-  const auto e01_I00 = pow<2>(pmdi00 * e00);
-  const auto e01_I11 = pow<2>(pmdi11 * e11);
-  const auto e01_F1 = pow<2>(pmdf1 * f1E);
-  const auto e01_F2 = pow<2>(pmdf2 * f2E);
-  const auto e01_P1 = pow<2>(pmdp1 * p1E);
-  const auto e01_P2 = pow<2>(pmdp2 * p2E);
-  return std::sqrt(e01_I00 + e01_I11 + e01_F1 + e01_F2 + e01_P1 + e01_P2);
-}
-
-/**
- * Estimate errors for I10 in the two inputs case.
- * @param i00 intensity of 00 flipper configuration
- * @param e00 error of i00
- * @param i11 intensity of 11 flipper configuration
- * @param e11 error of i11
- * @param p1 polarizer efficiency
- * @param p1E error of p1
- * @param p2 analyzer efficiency
- * @param p2E error of p2
- * @param f1 polarizer flipper efficiency
- * @param f1E error of f1
- * @param f2 analyzer flipper efficiency
- * @param f2E error of f2
- * @return the error estimate
- */
-double twoInputsErrorEstimate10(const double i00, const double e00,
-                                const double i11, const double e11,
-                                const double p1, const double p1E,
-                                const double p2, const double p2E,
-                                const double f1, const double f1E,
-                                const double f2, const double f2E) {
-  using namespace boost::math;
-  // Derivatives of the equation which solves the I10 intensities
-  // with respect to i00, i11, f1, etc.
-  const auto a = -1. + p1 + 2. * p2 - 2. * p1 * p2;
-  const auto b = -1. + 2. * p1;
-  const auto c = -1. + 2. * p2;
-  const auto d = -1. + p2;
-  const auto mpdi00 = (-pow<2>(f1) * f2 * pow<2>(b) * c +
-                       f1 * f2 * pow<2>(b) * c + f2 * p1 * a) /
-                      (f2 * p1 * a + f1 * b * (-d * p2 + f2 * (p1 + d) * c));
-  const auto mpdi11 = -((f1 * b * d * p2) /
-                        (f2 * p1 * a + f1 * b * (-d * p2 + f2 * (p1 + d) * c)));
-  const auto mpdf1 =
-      -(((-1. + 2. * p1) *
-         ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2)) *
-         (-pow<2>(f1) * f2 * i00 * pow<2>(1. - 2. * p1) * (-1. + 2. * p2) +
-          f2 * i00 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) +
-          f1 * (-1. + 2. * p1) *
-              (-i11 * (-1. + p2) * p2 +
-               f2 * i00 * (-1. + 2. * p1) * (-1. + 2. * p2)))) /
-        pow<2>(f2 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) +
-               f1 * (-1. + 2. * p1) *
-                   ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2)))) +
-      (-2. * f1 * f2 * i00 * pow<2>(1. - 2. * p1) * (-1. + 2. * p2) +
-       (-1. + 2. * p1) * (-i11 * (-1. + p2) * p2 +
-                          f2 * i00 * (-1. + 2. * p1) * (-1. + 2. * p2))) /
-          (f2 * p1 * (-1. + p1 + 2. * p2 - 2. * p1 * p2) +
-           f1 * (-1. + 2. * p1) *
-               ((1. - p2) * p2 + f2 * (-1. + p1 + p2) * (-1. + 2. * p2)));
-  const auto mpdf2 =
-      -(((f1 * b * (p1 + d) * c + p1 * a) *
-         (-pow<2>(f1) * f2 * i00 * pow<2>(b) * c + f2 * i00 * p1 * a +
-          f1 * b * (-i11 * d * p2 + f2 * i00 * b * c))) /
-        pow<2>(f2 * p1 * a + f1 * b * (-d * p2 + f2 * (p1 + d) * c))) +
-      (-pow<2>(f1) * i00 * pow<2>(b) * c + f1 * i00 * pow<2>(b) * c +
-       i00 * p1 * a) /
-          (f2 * p1 * a + f1 * b * (-d * p2 + f2 * (p1 + d) * c));
-  const auto mpdp1 =
-      -(((-pow<2>(f1) * f2 * i00 * pow<2>(b) * c + f2 * i00 * p1 * a +
-          f1 * b * (-i11 * d * p2 + f2 * i00 * b * c)) *
-         (f2 * p1 * -c + f1 * f2 * b * c + f2 * a +
-          2. * f1 * (-d * p2 + f2 * (p1 + d) * c))) /
-        pow<2>(f2 * p1 * a + f1 * b * (-d * p2 + f2 * (p1 + d) * c))) +
-      (f2 * i00 * p1 * -c + 4. * pow<2>(f1) * f2 * i00 * -b * c +
-       2. * f1 * f2 * i00 * b * c + f2 * i00 * a +
-       2. * f1 * (-i11 * d * p2 + f2 * i00 * b * c)) /
-          (f2 * p1 * a + f1 * b * (-d * p2 + f2 * (p1 + d) * c));
-  const auto mpdp2 =
-      -(((f2 * (2. - 2. * p1) * p1 +
-          f1 * b * (1. - 2. * p2 + 2. * f2 * (p1 + d) + f2 * c)) *
-         (-pow<2>(f1) * f2 * i00 * pow<2>(b) * c + f2 * i00 * p1 * a +
-          f1 * b * (-i11 * d * p2 + f2 * i00 * b * c))) /
-        pow<2>(f2 * p1 * a + f1 * b * (-d * p2 + f2 * (p1 + d) * c))) +
-      (-2. * pow<2>(f1) * f2 * i00 * pow<2>(b) +
-       f2 * i00 * (2. - 2. * p1) * p1 +
-       f1 * b * (2. * f2 * i00 * b - i11 * d - i11 * p2)) /
-          (f2 * p1 * a + f1 * b * (-d * p2 + f2 * (p1 + d) * c));
-  // Estimate the error components using linearized extrapolation,
-  // sum in squares.
-  const auto e10_I00 = pow<2>(mpdi00 * e00);
-  const auto e10_I11 = pow<2>(mpdi11 * e11);
-  const auto e10_F1 = pow<2>(mpdf1 * f1E);
-  const auto e10_F2 = pow<2>(mpdf2 * f2E);
-  const auto e10_P1 = pow<2>(mpdp1 * p1E);
-  const auto e10_P2 = pow<2>(mpdp2 * p2E);
-  return std::sqrt(e10_I00 + e10_I11 + e10_F1 + e10_F2 + e10_P1 + e10_P2);
-}
 } // namespace
 
 namespace Mantid {
 namespace Algorithms {
 
+using namespace API;
+using namespace Kernel;
+
 // Register the algorithm into the AlgorithmFactory
 DECLARE_ALGORITHM(PolarizationEfficiencyCor)
 
@@ -376,28 +75,37 @@ const std::string PolarizationEfficiencyCor::summary() const {
          "and analyzer efficiencies.";
 }
 
-/**
- * Count the non-nullptr workspaces
- * @return the count on non-nullptr workspaces.
- */
-size_t PolarizationEfficiencyCor::WorkspaceMap::size() const noexcept {
-  return (mmWS ? 1 : 0) + (mpWS ? 1 : 0) + (pmWS ? 1 : 0) + (ppWS ? 1 : 0);
-}
-
 //----------------------------------------------------------------------------------------------
 /** Initialize the algorithm's properties.
  */
 void PolarizationEfficiencyCor::init() {
-  declareProperty(Kernel::make_unique<Kernel::ArrayProperty<std::string>>(
-                      Prop::INPUT_WS, "",
-                      boost::make_shared<API::ADSValidator>(),
-                      Kernel::Direction::Input),
-                  "A list of workspaces to be corrected corresponding to the "
-                  "flipper configurations.");
+  bool const allowMultiSelection = true;
+  bool const isOptional = true;
+  declareProperty(
+      Kernel::make_unique<Kernel::ArrayProperty<std::string>>(
+          Prop::INPUT_WORKSPACES, "",
+          boost::make_shared<ADSValidator>(allowMultiSelection, isOptional),
+          Kernel::Direction::Input),
+      "A list of names of workspaces to be corrected.");
+
+  declareProperty(Kernel::make_unique<WorkspaceProperty<WorkspaceGroup>>(
+                      Prop::INPUT_WORKSPACE_GROUP, "", Kernel::Direction::Input,
+                      PropertyMode::Optional),
+                  "A group of workspaces to be corrected.");
+
+  const std::vector<std::string> methods{CorrectionMethod::WILDES,
+                                         CorrectionMethod::FREDRIKZE};
   declareProperty(
-      Kernel::make_unique<API::WorkspaceProperty<API::WorkspaceGroup>>(
-          Prop::OUTPUT_WS, "", Kernel::Direction::Output),
-      "A group of polarization efficiency corrected workspaces.");
+      Prop::CORRECTION_METHOD, CorrectionMethod::WILDES,
+      boost::make_shared<Kernel::ListValidator<std::string>>(methods),
+      "Correction method.");
+
+  declareProperty(Kernel::make_unique<WorkspaceProperty<MatrixWorkspace>>(
+                      Prop::EFFICIENCIES, "", Kernel::Direction::Input),
+                  "A workspace containing the efficiency factors as "
+                  "histograms: P1, P2, F1 and F2 in the Wildes method and Pp, "
+                  "Ap, Rho and Alpha for Fredrikze.");
+
   const std::string full = Flippers::OffOff + ", " + Flippers::OffOn + ", " +
                            Flippers::OnOff + ", " + Flippers::OnOn;
   const std::string missing01 =
@@ -408,625 +116,233 @@ void PolarizationEfficiencyCor::init() {
   const std::string noAnalyzer = Flippers::Off + ", " + Flippers::On;
   const std::string directBeam = Flippers::Off;
   const std::vector<std::string> setups{
-      {full, missing01, missing10, missing0110, noAnalyzer, directBeam}};
+      {"", full, missing01, missing10, missing0110, noAnalyzer, directBeam}};
   declareProperty(
-      Prop::FLIPPERS, full,
+      Prop::FLIPPERS, "",
       boost::make_shared<Kernel::ListValidator<std::string>>(setups),
-      "Flipper configurations of the input workspaces.");
-  declareProperty(
-      Kernel::make_unique<API::WorkspaceProperty<API::MatrixWorkspace>>(
-          Prop::EFFICIENCIES, "", Kernel::Direction::Input),
-      "A workspace containing the efficiency factors P1, P2, F1 and F2 as "
-      "histograms");
+      "Flipper configurations of the input workspaces  (Wildes method only)");
+
+  std::vector<std::string> propOptions{"", "PA", "PNR"};
+  declareProperty("PolarizationAnalysis", "",
+                  boost::make_shared<StringListValidator>(propOptions),
+                  "What Polarization mode will be used?\n"
+                  "PNR: Polarized Neutron Reflectivity mode\n"
+                  "PA: Full Polarization Analysis PNR-PA "
+                  "(Fredrikze method only)");
+
+  declareProperty(Kernel::make_unique<WorkspaceProperty<WorkspaceGroup>>(
+                      Prop::OUTPUT_WORKSPACES, "", Kernel::Direction::Output),
+                  "A group of polarization efficiency corrected workspaces.");
 }
 
 //----------------------------------------------------------------------------------------------
 /** Execute the algorithm.
  */
 void PolarizationEfficiencyCor::exec() {
-  const std::string flipperProperty = getProperty(Prop::FLIPPERS);
-  const auto flippers = parseFlipperSetup(flipperProperty);
-  const bool analyzer = flippers.front() != "0" && flippers.back() != "1";
-  const auto inputs = mapInputsToDirections(flippers);
-  checkConsistentNumberHistograms(inputs);
-  const EfficiencyMap efficiencies = efficiencyFactors();
-  checkConsistentX(inputs, efficiencies);
-  WorkspaceMap outputs;
-  switch (inputs.size()) {
-  case 1:
-    outputs = directBeamCorrections(inputs, efficiencies);
-    break;
-  case 2:
-    if (analyzer) {
-      outputs = twoInputCorrections(inputs, efficiencies);
-    } else {
-      outputs = analyzerlessCorrections(inputs, efficiencies);
-    }
-    break;
-  case 3:
-    outputs = threeInputCorrections(inputs, efficiencies);
-    break;
-  case 4:
-    outputs = fullCorrections(inputs, efficiencies);
-  }
-  setProperty(Prop::OUTPUT_WS, groupOutput(outputs));
-}
-
-/**
- * Validate the algorithm's input properties.
- * @return a map from property names to discovered issues
- */
-std::map<std::string, std::string> PolarizationEfficiencyCor::validateInputs() {
-  std::map<std::string, std::string> issues;
-  API::MatrixWorkspace_const_sptr factorWS = getProperty(Prop::EFFICIENCIES);
-  const auto &factorAxis = factorWS->getAxis(1);
-  if (!factorAxis) {
-    issues[Prop::EFFICIENCIES] = "The workspace is missing a vertical axis.";
-  } else if (!factorAxis->isText()) {
-    issues[Prop::EFFICIENCIES] =
-        "The vertical axis in the workspace is not text axis.";
-  } else if (factorWS->getNumberHistograms() < 4) {
-    issues[Prop::EFFICIENCIES] =
-        "The workspace should contain at least 4 histograms.";
+  std::string const method = getProperty(Prop::CORRECTION_METHOD);
+  if (method == CorrectionMethod::WILDES) {
+    execWildes();
   } else {
-    std::vector<std::string> tags{{"P1", "P2", "F1", "F2"}};
-    for (size_t i = 0; i != factorAxis->length(); ++i) {
-      const auto label = factorAxis->label(i);
-      auto found = std::find(tags.begin(), tags.end(), label);
-      if (found != tags.cend()) {
-        std::swap(tags.back(), *found);
-        tags.pop_back();
-      }
-    }
-    if (!tags.empty()) {
-      issues[Prop::EFFICIENCIES] = "A histogram labeled " + tags.front() +
-                                   " is missing from the workspace.";
-    }
+    execFredrikze();
   }
-  const std::vector<std::string> inputs = getProperty(Prop::INPUT_WS);
-  const std::string flipperProperty = getProperty(Prop::FLIPPERS);
-  const auto flippers = parseFlipperSetup(flipperProperty);
-  if (inputs.size() != flippers.size()) {
-    issues[Prop::FLIPPERS] = "The number of flipper configurations does not "
-                             "match the number of input workspaces";
-  }
-  return issues;
 }
 
-/**
- * Check that all workspaces in inputs have the same number of histograms.
- * @param inputs a set of workspaces to check
- */
-void PolarizationEfficiencyCor::checkConsistentNumberHistograms(
-    const WorkspaceMap &inputs) {
-  size_t nHist{0};
-  bool nHistValid{false};
-  // A local helper function to check the number of histograms.
-  auto checkNHist = [&nHist, &nHistValid](const API::MatrixWorkspace_sptr &ws,
-                                          const std::string &tag) {
-    if (nHistValid) {
-      if (nHist != ws->getNumberHistograms()) {
-        throw std::runtime_error("Number of histograms mismatch in " + tag);
-      }
-    } else {
-      nHist = ws->getNumberHistograms();
-      nHistValid = true;
-    }
-  };
-  if (inputs.mmWS) {
-    checkNHist(inputs.mmWS, Flippers::OffOff);
-  }
-  if (inputs.mpWS) {
-    checkNHist(inputs.mpWS, Flippers::OffOn);
-  }
-  if (inputs.pmWS) {
-    checkNHist(inputs.pmWS, Flippers::OnOff);
-  }
-  if (inputs.ppWS) {
-    checkNHist(inputs.ppWS, Flippers::OnOn);
+//----------------------------------------------------------------------------------------------
+void PolarizationEfficiencyCor::execWildes() {
+  checkWildesProperties();
+  std::vector<std::string> workspaces = getWorkspaceNameList();
+
+  MatrixWorkspace_sptr efficiencies = getEfficiencies();
+  auto alg = createChildAlgorithm("PolarizationCorrectionWildes");
+  alg->initialize();
+  alg->setProperty("InputWorkspaces", workspaces);
+  alg->setProperty("Efficiencies", efficiencies);
+  if (!isDefault(Prop::FLIPPERS)) {
+    alg->setPropertyValue("Flippers", getPropertyValue(Prop::FLIPPERS));
   }
+  auto out = getPropertyValue(Prop::OUTPUT_WORKSPACES);
+  alg->setPropertyValue("OutputWorkspace", out);
+  alg->execute();
+  API::WorkspaceGroup_sptr outWS = alg->getProperty("OutputWorkspace");
+  setProperty(Prop::OUTPUT_WORKSPACES, outWS);
 }
 
-/**
- * Check that all workspaces and efficicencies have the same X data.
- * @param inputs a set of workspaces to check
- * @param efficiencies efficiencies to check
- */
-void PolarizationEfficiencyCor::checkConsistentX(
-    const WorkspaceMap &inputs, const EfficiencyMap &efficiencies) {
-  // Compare everything to F1 efficiency.
-  const auto &F1x = efficiencies.F1->x();
-  // A local helper function to check a HistogramX against F1.
-  auto checkX =
-      [&F1x](const HistogramData::HistogramX &x, const std::string &tag) {
-        if (x.size() != F1x.size()) {
-          throw std::runtime_error(
-              "Mismatch of histogram lengths between F1 and " + tag + '.');
-        }
-        for (size_t i = 0; i != x.size(); ++i) {
-          if (x[i] != F1x[i]) {
-            throw std::runtime_error("Mismatch of X data between F1 and " +
-                                     tag + '.');
-          }
-        }
-      };
-  const auto &F2x = efficiencies.F2->x();
-  checkX(F2x, "F2");
-  const auto &P1x = efficiencies.P1->x();
-  checkX(P1x, "P1");
-  const auto &P2x = efficiencies.P2->x();
-  checkX(P2x, "P2");
-  // A local helper function to check an input workspace against F1.
-  auto checkWS =
-      [&checkX](const API::MatrixWorkspace_sptr &ws, const std::string &tag) {
-        const auto nHist = ws->getNumberHistograms();
-        for (size_t i = 0; i != nHist; ++i) {
-          checkX(ws->x(i), tag);
-        }
-      };
-  if (inputs.mmWS) {
-    checkWS(inputs.mmWS, Flippers::OffOff);
-  }
-  if (inputs.mpWS) {
-    checkWS(inputs.mpWS, Flippers::OffOn);
-  }
-  if (inputs.pmWS) {
-    checkWS(inputs.pmWS, Flippers::OnOff);
-  }
-  if (inputs.ppWS) {
-    checkWS(inputs.ppWS, Flippers::OnOn);
+//----------------------------------------------------------------------------------------------
+void PolarizationEfficiencyCor::execFredrikze() {
+  checkFredrikzeProperties();
+  WorkspaceGroup_sptr group = getWorkspaceGroup();
+  MatrixWorkspace_sptr efficiencies = getEfficiencies();
+  auto alg = createChildAlgorithm("PolarizationCorrectionFredrikze");
+  alg->initialize();
+  alg->setProperty("InputWorkspace", group);
+  alg->setProperty("Efficiencies", efficiencies);
+  if (!isDefault(Prop::POLARIZATION_ANALYSIS)) {
+    alg->setPropertyValue("PolarizationAnalysis",
+                          getPropertyValue(Prop::POLARIZATION_ANALYSIS));
   }
+  alg->setPropertyValue("OutputWorkspace",
+                        getPropertyValue(Prop::OUTPUT_WORKSPACES));
+  alg->execute();
+  API::WorkspaceGroup_sptr outWS = alg->getProperty("OutputWorkspace");
+  setProperty(Prop::OUTPUT_WORKSPACES, outWS);
 }
 
-/**
- * Make a workspace group out of the given set of workspaces.
- * The workspaces will be published in the ADS, their names appended by
- * appropriate suffices.
- * @param outputs a set of workspaces to group
- * @return a group workspace
+//----------------------------------------------------------------------------------------------
+/** Check that the inputs workspaces are set.
  */
-API::WorkspaceGroup_sptr
-PolarizationEfficiencyCor::groupOutput(const WorkspaceMap &outputs) {
-  const std::string outWSName = getProperty(Prop::OUTPUT_WS);
-  std::vector<std::string> names;
-  if (outputs.mmWS) {
-    names.emplace_back(outWSName + "_--");
-    API::AnalysisDataService::Instance().addOrReplace(names.back(),
-                                                      outputs.mmWS);
-  }
-  if (outputs.mpWS) {
-    names.emplace_back(outWSName + "_-+");
-    API::AnalysisDataService::Instance().addOrReplace(names.back(),
-                                                      outputs.mpWS);
+void PolarizationEfficiencyCor::checkWorkspaces() const {
+  if (isDefault(Prop::INPUT_WORKSPACES) &&
+      isDefault(Prop::INPUT_WORKSPACE_GROUP)) {
+    throw std::invalid_argument("Input workspaces are missing. Either a "
+                                "workspace group or a list of workspace names "
+                                "must be given.");
   }
-  if (outputs.pmWS) {
-    names.emplace_back(outWSName + "_+-");
-    API::AnalysisDataService::Instance().addOrReplace(names.back(),
-                                                      outputs.pmWS);
+  if (!isDefault(Prop::INPUT_WORKSPACES) &&
+      !isDefault(Prop::INPUT_WORKSPACE_GROUP)) {
+    throw std::invalid_argument("Input workspaces must be given either as a "
+                                "workspace group or a list of names.");
   }
-  if (outputs.ppWS) {
-    names.emplace_back(outWSName + "_++");
-    API::AnalysisDataService::Instance().addOrReplace(names.back(),
-                                                      outputs.ppWS);
-  }
-  auto group = createChildAlgorithm("GroupWorkspaces");
-  group->initialize();
-  group->setProperty("InputWorkspaces", names);
-  group->setProperty("OutputWorkspace", outWSName);
-  group->execute();
-  API::WorkspaceGroup_sptr outWS = group->getProperty("OutputWorkspace");
-  return outWS;
 }
 
-/**
- * Make a convenience access object to the efficiency factors.
- * @return an EfficiencyMap object
+//----------------------------------------------------------------------------------------------
+/** Check that the inputs for the Wildes are correct and consistent.
  */
-PolarizationEfficiencyCor::EfficiencyMap
-PolarizationEfficiencyCor::efficiencyFactors() {
-  EfficiencyMap e;
-  API::MatrixWorkspace_const_sptr factorWS = getProperty(Prop::EFFICIENCIES);
-  const auto &vertAxis = factorWS->getAxis(1);
-  for (size_t i = 0; i != vertAxis->length(); ++i) {
-    const auto label = vertAxis->label(i);
-    if (label == "P1") {
-      e.P1 = &factorWS->getSpectrum(i);
-    } else if (label == "P2") {
-      e.P2 = &factorWS->getSpectrum(i);
-    } else if (label == "F1") {
-      e.F1 = &factorWS->getSpectrum(i);
-    } else if (label == "F2") {
-      e.F2 = &factorWS->getSpectrum(i);
-    }
-    // Ignore other histograms such as 'Phi' in ILL's efficiency ws.
+void PolarizationEfficiencyCor::checkWildesProperties() const {
+  checkWorkspaces();
+
+  if (!isDefault(Prop::POLARIZATION_ANALYSIS)) {
+    throw std::invalid_argument(
+        "Property PolarizationAnalysis cannot be used with the Wildes method.");
   }
-  return e;
 }
 
-/**
- * Correct a direct beam measurement for non-ideal instrument effects.
- * Only the non-analyzer, polarizer flipper off case is considered here.
- * @param inputs a set of workspaces to correct
- * @param efficiencies a set of efficiency factors
- * @return set of corrected workspaces
+//----------------------------------------------------------------------------------------------
+/** Check that the inputs for the Fredrikze method are correct and consistent.
  */
-PolarizationEfficiencyCor::WorkspaceMap
-PolarizationEfficiencyCor::directBeamCorrections(
-    const WorkspaceMap &inputs, const EfficiencyMap &efficiencies) {
-  using namespace boost::math;
-  checkInputExists(inputs.ppWS, Flippers::Off);
-  WorkspaceMap outputs;
-  outputs.ppWS = DataObjects::create<DataObjects::Workspace2D>(*inputs.ppWS);
-  const size_t nHisto = inputs.ppWS->getNumberHistograms();
-  for (size_t wsIndex = 0; wsIndex != nHisto; ++wsIndex) {
-    const auto &ppY = inputs.ppWS->y(wsIndex);
-    const auto &ppE = inputs.ppWS->e(wsIndex);
-    auto &ppYOut = outputs.ppWS->mutableY(wsIndex);
-    auto &ppEOut = outputs.ppWS->mutableE(wsIndex);
-    for (size_t binIndex = 0; binIndex < ppY.size(); ++binIndex) {
-      const auto P1 = efficiencies.P1->y()[binIndex];
-      const auto P2 = efficiencies.P2->y()[binIndex];
-      const double f = 1. - P1 - P2 + 2. * P1 * P2;
-      ppYOut[binIndex] = ppY[binIndex] / f;
-      const auto P1E = efficiencies.P1->e()[binIndex];
-      const auto P2E = efficiencies.P2->e()[binIndex];
-      const auto e1 = pow<2>(P1E * (2. * P1 - 1.) / pow<2>(f) * ppY[binIndex]);
-      const auto e2 = pow<2>(P2E * (2. * P2 - 1.) / pow<2>(f) * ppY[binIndex]);
-      const auto e3 = pow<2>(ppE[binIndex] / f);
-      const auto errorSum = std::sqrt(e1 + e2 + e3);
-      ppEOut[binIndex] = errorSum;
-    }
+void PolarizationEfficiencyCor::checkFredrikzeProperties() const {
+  checkWorkspaces();
+
+  if (!isDefault(Prop::FLIPPERS)) {
+    throw std::invalid_argument(
+        "Property Flippers cannot be used with the Fredrikze method.");
   }
-  return outputs;
 }
 
-/**
- * Correct for non-ideal instrument effects.
- * Deals with the case when the data was taken without the analyzer:
- * only the polarizer flipper is used.
- * @param inputs a set of workspaces to correct
- * @param efficiencies a set of efficiency factors
- * @return a set of corrected workspaces
+//----------------------------------------------------------------------------------------------
+/** Get the input workspaces as a list of names.
  */
-PolarizationEfficiencyCor::WorkspaceMap
-PolarizationEfficiencyCor::analyzerlessCorrections(
-    const WorkspaceMap &inputs, const EfficiencyMap &efficiencies) {
-  using namespace boost::math;
-  checkInputExists(inputs.mmWS, Flippers::On);
-  checkInputExists(inputs.ppWS, Flippers::Off);
-  WorkspaceMap outputs;
-  outputs.mmWS = DataObjects::create<DataObjects::Workspace2D>(*inputs.mmWS);
-  outputs.ppWS = DataObjects::create<DataObjects::Workspace2D>(*inputs.ppWS);
-  const size_t nHisto = inputs.mmWS->getNumberHistograms();
-  for (size_t wsIndex = 0; wsIndex != nHisto; ++wsIndex) {
-    const auto &mmY = inputs.mmWS->y(wsIndex);
-    const auto &mmE = inputs.mmWS->e(wsIndex);
-    const auto &ppY = inputs.ppWS->y(wsIndex);
-    const auto &ppE = inputs.ppWS->e(wsIndex);
-    auto &mmYOut = outputs.mmWS->mutableY(wsIndex);
-    auto &mmEOut = outputs.mmWS->mutableE(wsIndex);
-    auto &ppYOut = outputs.ppWS->mutableY(wsIndex);
-    auto &ppEOut = outputs.ppWS->mutableE(wsIndex);
-    for (size_t binIndex = 0; binIndex < mmY.size(); ++binIndex) {
-      const auto F1 = efficiencies.F1->y()[binIndex];
-      const auto P1 = efficiencies.P1->y()[binIndex];
-      Eigen::Matrix2d F1m;
-      F1m << 1., 0., (F1 - 1.) / F1, 1. / F1;
-      const double divisor = (2. * P1 - 1.);
-      const double diag = (P1 - 1.) / divisor;
-      const double off = P1 / divisor;
-      Eigen::Matrix2d P1m;
-      P1m << diag, off, off, diag;
-      const Eigen::Vector2d intensities(ppY[binIndex], mmY[binIndex]);
-      const auto PFProduct = P1m * F1m;
-      const auto corrected = PFProduct * intensities;
-      ppYOut[binIndex] = corrected[0];
-      mmYOut[binIndex] = corrected[1];
-      const auto F1E = efficiencies.F1->e()[binIndex];
-      const auto P1E = efficiencies.P1->e()[binIndex];
-      const auto elemE1 = -1. / pow<2>(F1) * F1E;
-      Eigen::Matrix2d F1Em;
-      F1Em << 0., 0., -elemE1, elemE1;
-      const auto elemE2 = 1. / pow<2>(divisor) * P1E;
-      Eigen::Matrix2d P1Em;
-      P1Em << elemE2, -elemE2, -elemE2, elemE2;
-      const Eigen::Vector2d errors(ppE[binIndex], mmE[binIndex]);
-      const auto e1 = (P1Em * F1m * intensities).array();
-      const auto e2 = (P1m * F1Em * intensities).array();
-      const auto sqPFProduct = (PFProduct.array() * PFProduct.array()).matrix();
-      const auto sqErrors = (errors.array() * errors.array()).matrix();
-      const auto e3 = (sqPFProduct * sqErrors).array();
-      const auto errorSum = (e1 * e1 + e2 * e2 + e3).sqrt();
-      ppEOut[binIndex] = errorSum[0];
-      mmEOut[binIndex] = errorSum[1];
+std::vector<std::string>
+PolarizationEfficiencyCor::getWorkspaceNameList() const {
+  std::vector<std::string> names;
+  if (!isDefault(Prop::INPUT_WORKSPACES)) {
+    names = getProperty(Prop::INPUT_WORKSPACES);
+  } else {
+    WorkspaceGroup_sptr group = getProperty(Prop::INPUT_WORKSPACE_GROUP);
+    auto const n = group->size();
+    for (size_t i = 0; i < n; ++i) {
+      auto ws = group->getItem(i);
+      auto const name = ws->getName();
+      if (name.empty()) {
+        throw std::invalid_argument(
+            "Workspace from the input workspace group is not stored in the "
+            "Analysis Data Service which is required by the Wildes method.");
+      }
+      names.push_back(name);
     }
   }
-  return outputs;
+  return names;
 }
 
-/**
- * Correct for non-ideal instrument effects.
- * Only 00 and 11 flipper configurations need to be provided;
- * the missing 01 and 10 data is solved from the assumption that
- * in the corrected data, R01 = R10 = 0.
- * @param inputs a set of workspaces to correct
- * @param efficiencies a set of efficiency factors
- * @return a set of corrected workspaces
- */
-PolarizationEfficiencyCor::WorkspaceMap
-PolarizationEfficiencyCor::twoInputCorrections(
-    const WorkspaceMap &inputs, const EfficiencyMap &efficiencies) {
-  using namespace boost::math;
-  checkInputExists(inputs.mmWS, Flippers::OnOn);
-  checkInputExists(inputs.ppWS, Flippers::OffOff);
-  WorkspaceMap fullInputs = inputs;
-  fullInputs.mpWS = DataObjects::create<DataObjects::Workspace2D>(*inputs.mmWS);
-  fullInputs.pmWS = DataObjects::create<DataObjects::Workspace2D>(*inputs.ppWS);
-  twoInputsSolve01And10(fullInputs, inputs, efficiencies);
-  return fullCorrections(fullInputs, efficiencies);
-}
-
-/**
- * Correct for non-ideal instrument effects.
- * Needs the 00 and 11 flipper configurations as well as either 01 or 10.
- * The missing intensity (01 or 10) is solved from the assumption
- * that the corrected R01 = R10.
- * @param inputs a set of workspaces to correct
- * @param efficiencies a set of efficiency factors
- * @return a set of corrected workspaces
+//----------------------------------------------------------------------------------------------
+/** Get the input workspaces as a workspace group.
  */
-PolarizationEfficiencyCor::WorkspaceMap
-PolarizationEfficiencyCor::threeInputCorrections(
-    const WorkspaceMap &inputs, const EfficiencyMap &efficiencies) {
-  WorkspaceMap fullInputs = inputs;
-  checkInputExists(inputs.mmWS, Flippers::OnOn);
-  checkInputExists(inputs.ppWS, Flippers::OffOff);
-  if (!inputs.mpWS) {
-    checkInputExists(inputs.pmWS, Flippers::OffOn);
-    threeInputsSolve10(fullInputs, efficiencies);
+API::WorkspaceGroup_sptr PolarizationEfficiencyCor::getWorkspaceGroup() const {
+  WorkspaceGroup_sptr group;
+  if (!isDefault(Prop::INPUT_WORKSPACE_GROUP)) {
+    group = getProperty(Prop::INPUT_WORKSPACE_GROUP);
   } else {
-    checkInputExists(inputs.mpWS, Flippers::OnOff);
-    threeInputsSolve01(fullInputs, efficiencies);
+    throw std::invalid_argument(
+        "Input workspaces are required to be in a workspace group.");
   }
-  return fullCorrections(fullInputs, efficiencies);
+  return group;
 }
 
-/**
- * Correct for non-ideal instrument effects.
- * Perform full polarization corrections. All flipper configurations
- * (00, 01, 10 and 11) are needed for this.
- * @param inputs a set of workspaces to correct
- * @param efficiencies a set of efficiency factors
- * @return a set of corrected workspaces
- */
-PolarizationEfficiencyCor::WorkspaceMap
-PolarizationEfficiencyCor::fullCorrections(const WorkspaceMap &inputs,
-                                           const EfficiencyMap &efficiencies) {
-  using namespace boost::math;
-  checkInputExists(inputs.mmWS, Flippers::OnOn);
-  checkInputExists(inputs.mpWS, Flippers::OnOff);
-  checkInputExists(inputs.pmWS, Flippers::OffOn);
-  checkInputExists(inputs.ppWS, Flippers::OffOff);
-  WorkspaceMap outputs;
-  outputs.mmWS = DataObjects::create<DataObjects::Workspace2D>(*inputs.mmWS);
-  outputs.mpWS = DataObjects::create<DataObjects::Workspace2D>(*inputs.mpWS);
-  outputs.pmWS = DataObjects::create<DataObjects::Workspace2D>(*inputs.pmWS);
-  outputs.ppWS = DataObjects::create<DataObjects::Workspace2D>(*inputs.ppWS);
-  const auto F1 = efficiencies.F1->y();
-  const auto F1E = efficiencies.F1->e();
-  const auto F2 = efficiencies.F2->y();
-  const auto F2E = efficiencies.F2->e();
-  const auto P1 = efficiencies.P1->y();
-  const auto P1E = efficiencies.P1->e();
-  const auto P2 = efficiencies.P2->y();
-  const auto P2E = efficiencies.P2->e();
-  const size_t nHisto = inputs.mmWS->getNumberHistograms();
-  for (size_t wsIndex = 0; wsIndex != nHisto; ++wsIndex) {
-    const auto &mmY = inputs.mmWS->y(wsIndex);
-    const auto &mmE = inputs.mmWS->e(wsIndex);
-    const auto &mpY = inputs.mpWS->y(wsIndex);
-    const auto &mpE = inputs.mpWS->e(wsIndex);
-    const auto &pmY = inputs.pmWS->y(wsIndex);
-    const auto &pmE = inputs.pmWS->e(wsIndex);
-    const auto &ppY = inputs.ppWS->y(wsIndex);
-    const auto &ppE = inputs.ppWS->e(wsIndex);
-    auto &mmYOut = outputs.mmWS->mutableY(wsIndex);
-    auto &mmEOut = outputs.mmWS->mutableE(wsIndex);
-    auto &mpYOut = outputs.mpWS->mutableY(wsIndex);
-    auto &mpEOut = outputs.mpWS->mutableE(wsIndex);
-    auto &pmYOut = outputs.pmWS->mutableY(wsIndex);
-    auto &pmEOut = outputs.pmWS->mutableE(wsIndex);
-    auto &ppYOut = outputs.ppWS->mutableY(wsIndex);
-    auto &ppEOut = outputs.ppWS->mutableE(wsIndex);
-    for (size_t binIndex = 0; binIndex < mmY.size(); ++binIndex) {
-      Eigen::Vector4d corrected;
-      Eigen::Vector4d errors;
-      fourInputsCorrectedAndErrors(corrected, errors, ppY[binIndex],
-                                   ppE[binIndex], pmY[binIndex], pmE[binIndex],
-                                   mpY[binIndex], mpE[binIndex], mmY[binIndex],
-                                   mmE[binIndex], F1[binIndex], F1E[binIndex],
-                                   F2[binIndex], F2E[binIndex], P1[binIndex],
-                                   P1E[binIndex], P2[binIndex], P2E[binIndex]);
-      ppYOut[binIndex] = corrected[0];
-      pmYOut[binIndex] = corrected[1];
-      mpYOut[binIndex] = corrected[2];
-      mmYOut[binIndex] = corrected[3];
-      ppEOut[binIndex] = errors[0];
-      pmEOut[binIndex] = errors[1];
-      mpEOut[binIndex] = errors[2];
-      mmEOut[binIndex] = errors[3];
-    }
+//----------------------------------------------------------------------------------------------
+/// Check if efficiencies workspace needs interpolation. Use inWS as for
+/// comparison.
+bool PolarizationEfficiencyCor::needInterpolation(
+    MatrixWorkspace const &efficiencies, MatrixWorkspace const &inWS) const {
+
+  if (!efficiencies.isHistogramData())
+    return true;
+  if (efficiencies.blocksize() != inWS.blocksize())
+    return true;
+
+  auto const &x = inWS.x(0);
+  for (size_t i = 0; i < efficiencies.getNumberHistograms(); ++i) {
+    if (efficiencies.x(i).rawData() != x.rawData())
+      return true;
   }
-  return outputs;
+  return false;
 }
 
-/**
- * Make a set of workspaces to correct from input properties.
- * @param flippers a vector of flipper configurations
- * @return a set of workspaces to correct
- */
-PolarizationEfficiencyCor::WorkspaceMap
-PolarizationEfficiencyCor::mapInputsToDirections(
-    const std::vector<std::string> &flippers) {
-  const std::vector<std::string> inputNames = getProperty(Prop::INPUT_WS);
-  WorkspaceMap inputs;
-  for (size_t i = 0; i < flippers.size(); ++i) {
-    auto ws =
-        (API::AnalysisDataService::Instance().retrieveWS<API::MatrixWorkspace>(
-            inputNames[i]));
-    if (!ws) {
-      throw std::runtime_error(
-          "One of the input workspaces doesn't seem to be a MatrixWorkspace.");
-    }
-    const auto &f = flippers[i];
-    if (f == Flippers::OnOn || f == Flippers::On) {
-      inputs.mmWS = ws;
-    } else if (f == Flippers::OnOff) {
-      inputs.mpWS = ws;
-    } else if (f == Flippers::OffOn) {
-      inputs.pmWS = ws;
-    } else if (f == Flippers::OffOff || f == Flippers::Off) {
-      inputs.ppWS = ws;
-    } else {
-      throw std::runtime_error(std::string{"Unknown entry in "} +
-                               Prop::FLIPPERS);
-    }
+//----------------------------------------------------------------------------------------------
+/// Convert the efficiencies to histogram
+MatrixWorkspace_sptr PolarizationEfficiencyCor::convertToHistogram(
+    API::MatrixWorkspace_sptr efficiencies) {
+  if (efficiencies->isHistogramData()) {
+    return efficiencies;
   }
-  return inputs;
+  auto alg = createChildAlgorithm("ConvertToHistogram");
+  alg->initialize();
+  alg->setProperty("InputWorkspace", efficiencies);
+  alg->setProperty("OutputWorkspace", "dummy");
+  alg->execute();
+  MatrixWorkspace_sptr result = alg->getProperty("OutputWorkspace");
+  return result;
 }
 
-/**
- * Solve in-place the 01 flipper configuration from the assumption that
- * for the corrected intensities, R01 = R10.
- * @param inputs a set of input workspaces
- * @param efficiencies a set of efficiency factors
- */
-void PolarizationEfficiencyCor::threeInputsSolve01(
-    WorkspaceMap &inputs, const EfficiencyMap &efficiencies) {
-  using namespace Mantid::DataObjects;
-  inputs.pmWS = create<Workspace2D>(*inputs.mpWS);
-  const auto &F1 = efficiencies.F1->y();
-  const auto &F2 = efficiencies.F2->y();
-  const auto &P1 = efficiencies.P1->y();
-  const auto &P2 = efficiencies.P2->y();
-  const auto nHisto = inputs.pmWS->getNumberHistograms();
-  for (size_t wsIndex = 0; wsIndex != nHisto; ++wsIndex) {
-    const auto &I00 = inputs.ppWS->y(wsIndex);
-    auto &I01 = inputs.pmWS->mutableY(wsIndex);
-    const auto &I10 = inputs.mpWS->y(wsIndex);
-    const auto &I11 = inputs.mmWS->y(wsIndex);
-    for (size_t binIndex = 0; binIndex != I00.size(); ++binIndex) {
-      const auto f1 = F1[binIndex];
-      const auto f2 = F2[binIndex];
-      const auto p1 = P1[binIndex];
-      const auto p2 = P2[binIndex];
-      const auto i00 = I00[binIndex];
-      const auto i10 = I10[binIndex];
-      const auto i11 = I11[binIndex];
-      I01[binIndex] =
-          (f1 * i00 * (-1. + 2. * p1) - (i00 - i10 + i11) * (p1 - p2) -
-           f2 * (i00 - i10) * (-1. + 2. * p2)) /
-          (-p1 + f1 * (-1. + 2. * p1) + p2);
-      // The errors are left to zero.
-    }
-  }
+//----------------------------------------------------------------------------------------------
+/// Convert the efficiencies to histogram
+MatrixWorkspace_sptr
+PolarizationEfficiencyCor::interpolate(MatrixWorkspace_sptr efficiencies,
+                                       MatrixWorkspace_sptr inWS) {
+
+  efficiencies->setDistribution(true);
+  auto alg = createChildAlgorithm("RebinToWorkspace");
+  alg->initialize();
+  alg->setProperty("WorkspaceToRebin", efficiencies);
+  alg->setProperty("WorkspaceToMatch", inWS);
+  alg->setProperty("OutputWorkspace", "dummy");
+  alg->execute();
+  MatrixWorkspace_sptr result = alg->getProperty("OutputWorkspace");
+  return result;
 }
 
-/**
- * Solve in-place the 10 flipper configuration from the assumption that
- * for the corrected intensities R01 = R10.
- * @param inputs a set of input workspaces
- * @param efficiencies a set of efficiency factors
+//----------------------------------------------------------------------------------------------
+/** Prepare and return the efficiencies.
  */
-void PolarizationEfficiencyCor::threeInputsSolve10(
-    WorkspaceMap &inputs, const EfficiencyMap &efficiencies) {
-  inputs.mpWS = DataObjects::create<DataObjects::Workspace2D>(*inputs.pmWS);
-  const auto &F1 = efficiencies.F1->y();
-  const auto &F2 = efficiencies.F2->y();
-  const auto &P1 = efficiencies.P1->y();
-  const auto &P2 = efficiencies.P2->y();
-  const auto nHisto = inputs.mpWS->getNumberHistograms();
-  for (size_t wsIndex = 0; wsIndex != nHisto; ++wsIndex) {
-    const auto &I00 = inputs.ppWS->y(wsIndex);
-    const auto &I01 = inputs.pmWS->y(wsIndex);
-    auto &I10 = inputs.mpWS->mutableY(wsIndex);
-    const auto &I11 = inputs.mmWS->y(wsIndex);
-    for (size_t binIndex = 0; binIndex != I00.size(); ++binIndex) {
-      const auto f1 = F1[binIndex];
-      const auto f2 = F2[binIndex];
-      const auto p1 = P1[binIndex];
-      const auto p2 = P2[binIndex];
-      const auto i00 = I00[binIndex];
-      const auto i01 = I01[binIndex];
-      const auto i11 = I11[binIndex];
-      I10[binIndex] =
-          (-f1 * (i00 - i01) * (-1. + 2. * p1) + (i00 - i01 + i11) * (p1 - p2) +
-           f2 * i00 * (-1. + 2. * p2)) /
-          (p1 - p2 + f2 * (-1. + 2. * p2));
-      // The errors are left to zero.
-    }
+API::MatrixWorkspace_sptr PolarizationEfficiencyCor::getEfficiencies() {
+  MatrixWorkspace_sptr inWS;
+  if (!isDefault(Prop::INPUT_WORKSPACES)) {
+    std::vector<std::string> const names = getProperty(Prop::INPUT_WORKSPACES);
+    inWS = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(
+        names.front());
+  } else {
+    WorkspaceGroup_sptr group = getProperty(Prop::INPUT_WORKSPACE_GROUP);
+    inWS = boost::dynamic_pointer_cast<MatrixWorkspace>(group->getItem(0));
   }
-}
+  MatrixWorkspace_sptr efficiencies = getProperty(Prop::EFFICIENCIES);
 
-/**
- * Solve in-place the 01 and 10 flipper configurations from the assumption that
- * for the corrected intensities R01 = R10 = 0.
- * @param fullInputs a set of output workspaces
- * @param inputs a set of input workspaces
- * @param efficiencies a set of efficiency factors
- */
-void PolarizationEfficiencyCor::twoInputsSolve01And10(
-    WorkspaceMap &fullInputs, const WorkspaceMap &inputs,
-    const EfficiencyMap &efficiencies) {
-  using namespace boost::math;
-  const auto &F1 = efficiencies.F1->y();
-  const auto &F1E = efficiencies.F1->e();
-  const auto &F2 = efficiencies.F2->y();
-  const auto &F2E = efficiencies.F2->e();
-  const auto &P1 = efficiencies.P1->y();
-  const auto &P1E = efficiencies.P1->e();
-  const auto &P2 = efficiencies.P2->y();
-  const auto &P2E = efficiencies.P2->e();
-  const auto nHisto = inputs.mmWS->getNumberHistograms();
-  for (size_t wsIndex = 0; wsIndex != nHisto; ++wsIndex) {
-    const auto &I00 = inputs.ppWS->y(wsIndex);
-    const auto &E00 = inputs.ppWS->e(wsIndex);
-    const auto &I11 = inputs.mmWS->y(wsIndex);
-    const auto &E11 = inputs.mmWS->e(wsIndex);
-    auto &I01 = fullInputs.pmWS->mutableY(wsIndex);
-    auto &E01 = fullInputs.pmWS->mutableE(wsIndex);
-    auto &I10 = fullInputs.mpWS->mutableY(wsIndex);
-    auto &E10 = fullInputs.mpWS->mutableE(wsIndex);
-    for (size_t binIndex = 0; binIndex != I00.size(); ++binIndex) {
-      const auto i00 = I00[binIndex];
-      const auto i11 = I11[binIndex];
-      const auto f1 = F1[binIndex];
-      const auto f2 = F2[binIndex];
-      const auto p1 = P1[binIndex];
-      const auto p2 = P2[binIndex];
-      const auto a = -1. + p1 + 2. * p2 - 2. * p1 * p2;
-      const auto b = -1. + 2. * p1;
-      const auto c = -1. + 2. * p2;
-      const auto d = -1. + p2;
-      // Case: 01
-      const auto divisor = f2 * p1 * a + f1 * b * (-d * p2 + f2 * (p1 + d) * c);
-      I01[binIndex] =
-          (f2 * i11 * p1 * a -
-           f1 * i00 * b * (-f2 * pow<2>(c) + pow<2>(f2 * c) + d * p2)) /
-          divisor;
-      E01[binIndex] = twoInputsErrorEstimate01(
-          i00, E00[binIndex], i11, E11[binIndex], p1, P1E[binIndex], p2,
-          P2E[binIndex], f1, F1E[binIndex], f2, F2E[binIndex]);
-      // Case: 10
-      I10[binIndex] =
-          (-pow<2>(f1) * f2 * i00 * pow<2>(b) * c + f2 * i00 * p1 * a +
-           f1 * b * (-i11 * d * p2 + f2 * i00 * b * c)) /
-          divisor;
-      E10[binIndex] = twoInputsErrorEstimate10(
-          i00, E00[binIndex], i11, E11[binIndex], p1, P1E[binIndex], p2,
-          P2E[binIndex], f1, F1E[binIndex], f2, F2E[binIndex]);
-    }
+  if (!needInterpolation(*efficiencies, *inWS)) {
+    return efficiencies;
   }
+
+  efficiencies = convertToHistogram(efficiencies);
+  efficiencies = interpolate(efficiencies, inWS);
+
+  return efficiencies;
 }
+
 } // namespace Algorithms
 } // namespace Mantid
diff --git a/Framework/Algorithms/src/ReflectometryReductionOneAuto2.cpp b/Framework/Algorithms/src/ReflectometryReductionOneAuto2.cpp
index f30e521cbc958668118733bc46f3a373e63d6498..79d0390e81d129d21d2681a5b4cdf2f23ae19655 100644
--- a/Framework/Algorithms/src/ReflectometryReductionOneAuto2.cpp
+++ b/Framework/Algorithms/src/ReflectometryReductionOneAuto2.cpp
@@ -6,8 +6,8 @@
 #include "MantidKernel/CompositeValidator.h"
 #include "MantidKernel/EnabledWhenProperty.h"
 #include "MantidKernel/ListValidator.h"
-#include "MantidKernel/make_unique.h"
 #include "MantidKernel/MandatoryValidator.h"
+#include "MantidKernel/make_unique.h"
 
 namespace Mantid {
 namespace Algorithms {
@@ -42,9 +42,9 @@ const std::string ReflectometryReductionOneAuto2::summary() const {
 }
 
 /** Validate transmission runs
-*
-* @return :: result of the validation as a map
-*/
+ *
+ * @return :: result of the validation as a map
+ */
 std::map<std::string, std::string>
 ReflectometryReductionOneAuto2::validateInputs() {
 
@@ -104,7 +104,7 @@ ReflectometryReductionOneAuto2::validateInputs() {
 }
 
 /** Initialize the algorithm's properties.
-*/
+ */
 void ReflectometryReductionOneAuto2::init() {
 
   // Input ws
@@ -190,30 +190,30 @@ void ReflectometryReductionOneAuto2::init() {
                   boost::make_shared<StringListValidator>(propOptions),
                   "Polarization analysis mode.");
   declareProperty(
-      Kernel::make_unique<ArrayProperty<double>>("CPp", Direction::Input),
+      Kernel::make_unique<ArrayProperty<double>>("Pp", Direction::Input),
       "Effective polarizing power of the polarizing system. "
       "Expressed as a ratio 0 &lt; Pp &lt; 1");
   declareProperty(
-      Kernel::make_unique<ArrayProperty<double>>("CAp", Direction::Input),
+      Kernel::make_unique<ArrayProperty<double>>("Ap", Direction::Input),
       "Effective polarizing power of the analyzing system. "
       "Expressed as a ratio 0 &lt; Ap &lt; 1");
   declareProperty(
-      Kernel::make_unique<ArrayProperty<double>>("CRho", Direction::Input),
+      Kernel::make_unique<ArrayProperty<double>>("Rho", Direction::Input),
       "Ratio of efficiencies of polarizer spin-down to polarizer "
       "spin-up. This is characteristic of the polarizer flipper. "
       "Values are constants for each term in a polynomial "
       "expression.");
   declareProperty(
-      Kernel::make_unique<ArrayProperty<double>>("CAlpha", Direction::Input),
+      Kernel::make_unique<ArrayProperty<double>>("Alpha", Direction::Input),
       "Ratio of efficiencies of analyzer spin-down to analyzer "
       "spin-up. This is characteristic of the analyzer flipper. "
       "Values are factors for each term in a polynomial "
       "expression.");
   setPropertyGroup("PolarizationAnalysis", "Polarization Corrections");
-  setPropertyGroup("CPp", "Polarization Corrections");
-  setPropertyGroup("CAp", "Polarization Corrections");
-  setPropertyGroup("CRho", "Polarization Corrections");
-  setPropertyGroup("CAlpha", "Polarization Corrections");
+  setPropertyGroup("Pp", "Polarization Corrections");
+  setPropertyGroup("Ap", "Polarization Corrections");
+  setPropertyGroup("Rho", "Polarization Corrections");
+  setPropertyGroup("Alpha", "Polarization Corrections");
 
   // Init properties for diagnostics
   initDebugProperties();
@@ -235,7 +235,7 @@ void ReflectometryReductionOneAuto2::init() {
 }
 
 /** Execute the algorithm.
-*/
+ */
 void ReflectometryReductionOneAuto2::exec() {
 
   MatrixWorkspace_sptr inputWS = getProperty("InputWorkspace");
@@ -325,14 +325,14 @@ void ReflectometryReductionOneAuto2::exec() {
 }
 
 /** Returns the detectors of interest, specified via processing instructions.
-* Note that this returns the names of the parent detectors of the first and
-* last spectrum indices in the processing instructions. It is assumed that all
-* the interim detectors have the same parent.
-*
-* @param instructions :: processing instructions defining detectors of interest
-* @param inputWS :: the input workspace
-* @return :: the names of the detectors of interest
-*/
+ * Note that this returns the names of the parent detectors of the first and
+ * last spectrum indices in the processing instructions. It is assumed that all
+ * the interim detectors have the same parent.
+ *
+ * @param instructions :: processing instructions defining detectors of interest
+ * @param inputWS :: the input workspace
+ * @return :: the names of the detectors of interest
+ */
 std::vector<std::string> ReflectometryReductionOneAuto2::getDetectorNames(
     const std::string &instructions, MatrixWorkspace_sptr inputWS) {
 
@@ -365,14 +365,14 @@ std::vector<std::string> ReflectometryReductionOneAuto2::getDetectorNames(
 }
 
 /** Correct an instrument component by shifting it vertically or
-* rotating it around the sample.
-*
-* @param instructions :: processing instructions defining the detectors of
-* interest
-* @param inputWS :: the input workspace
-* @param twoTheta :: the angle to move detectors to
-* @return :: the corrected workspace
-*/
+ * rotating it around the sample.
+ *
+ * @param instructions :: processing instructions defining the detectors of
+ * interest
+ * @param inputWS :: the input workspace
+ * @param twoTheta :: the angle to move detectors to
+ * @return :: the corrected workspace
+ */
 MatrixWorkspace_sptr ReflectometryReductionOneAuto2::correctDetectorPositions(
     const std::string &instructions, MatrixWorkspace_sptr inputWS,
     const double twoTheta) {
@@ -407,13 +407,13 @@ MatrixWorkspace_sptr ReflectometryReductionOneAuto2::correctDetectorPositions(
 }
 
 /** Calculate the theta value of the detector of interest specified via
-* processing instructions
-*
-* @param instructions :: processing instructions defining the detectors of
-* interest
-* @param inputWS :: the input workspace
-* @return :: the angle of the detector (only the first detector is considered)
-*/
+ * processing instructions
+ *
+ * @param instructions :: processing instructions defining the detectors of
+ * interest
+ * @param inputWS :: the input workspace
+ * @return :: the angle of the detector (only the first detector is considered)
+ */
 double
 ReflectometryReductionOneAuto2::calculateTheta(const std::string &instructions,
                                                MatrixWorkspace_sptr inputWS) {
@@ -438,10 +438,10 @@ ReflectometryReductionOneAuto2::calculateTheta(const std::string &instructions,
 }
 
 /** Set algorithmic correction properties
-*
-* @param alg :: ReflectometryReductionOne algorithm
-* @param instrument :: The instrument attached to the workspace
-*/
+ *
+ * @param alg :: ReflectometryReductionOne algorithm
+ * @param instrument :: The instrument attached to the workspace
+ */
 void ReflectometryReductionOneAuto2::populateAlgorithmicCorrectionProperties(
     IAlgorithm_sptr alg, Instrument_const_sptr instrument) {
 
@@ -507,12 +507,12 @@ void ReflectometryReductionOneAuto2::populateAlgorithmicCorrectionProperties(
 }
 
 /** Rebin and scale a workspace in Q.
-*
-* @param inputWS :: the workspace in Q
-* @param theta :: the angle of this run
-* @param params :: [output] rebin parameters
-* @return :: the output workspace
-*/
+ *
+ * @param inputWS :: the workspace in Q
+ * @param theta :: the angle of this run
+ * @param params :: [output] rebin parameters
+ * @return :: the output workspace
+ */
 MatrixWorkspace_sptr
 ReflectometryReductionOneAuto2::rebinAndScale(MatrixWorkspace_sptr inputWS,
                                               const double theta,
@@ -585,7 +585,7 @@ ReflectometryReductionOneAuto2::rebinAndScale(MatrixWorkspace_sptr inputWS,
 }
 
 /** Check if input workspace is a group
-*/
+ */
 bool ReflectometryReductionOneAuto2::checkGroups() {
 
   const std::string wsName = getPropertyValue("InputWorkspace");
@@ -611,7 +611,7 @@ bool ReflectometryReductionOneAuto2::checkGroups() {
  * items in the transmission group will be summed to produce a matrix workspace
  * that will be applied to each of the items in the input workspace group. See
  * documentation of this algorithm for more details.
-*/
+ */
 bool ReflectometryReductionOneAuto2::processGroups() {
   // this algorithm effectively behaves as MultiPeriodGroupAlgorithm
   m_usingBaseProcessGroups = true;
@@ -744,26 +744,34 @@ bool ReflectometryReductionOneAuto2::processGroups() {
     return true;
   }
 
-  if (!group->isMultiperiod()) {
-    g_log.warning("Polarization corrections can only be performed on "
-                  "multiperiod workspaces.");
-    setPropertyValue("OutputWorkspace", outputIvsQ);
-    setPropertyValue("OutputWorkspaceBinned", outputIvsQBinned);
-    setPropertyValue("OutputWorkspaceWavelength", outputIvsLam);
-    return true;
+  auto groupIvsLam =
+      AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>(outputIvsLam);
+  auto effAlg = createChildAlgorithm("CreatePolarizationEfficiencies");
+  effAlg->setProperty("InputWorkspace", groupIvsLam->getItem(0));
+  if (!isDefault("Pp")) {
+    effAlg->setProperty("Pp", getPropertyValue("Pp"));
+  }
+  if (!isDefault("Rho")) {
+    effAlg->setProperty("Rho", getPropertyValue("Rho"));
+  }
+  if (!isDefault("Ap")) {
+    effAlg->setProperty("Ap", getPropertyValue("Ap"));
+  }
+  if (!isDefault("Alpha")) {
+    effAlg->setProperty("Alpha", getPropertyValue("Alpha"));
   }
+  effAlg->execute();
+  MatrixWorkspace_sptr efficiencies = effAlg->getProperty("OutputWorkspace");
 
-  Algorithm_sptr polAlg = createChildAlgorithm("PolarizationCorrection");
+  Algorithm_sptr polAlg =
+      createChildAlgorithm("PolarizationCorrectionFredrikze");
   polAlg->setChild(false);
   polAlg->setRethrows(true);
   polAlg->setProperty("InputWorkspace", outputIvsLam);
   polAlg->setProperty("OutputWorkspace", outputIvsLam);
   polAlg->setProperty("PolarizationAnalysis",
                       getPropertyValue("PolarizationAnalysis"));
-  polAlg->setProperty("CPp", getPropertyValue("CPp"));
-  polAlg->setProperty("CRho", getPropertyValue("CRho"));
-  polAlg->setProperty("CAp", getPropertyValue("CAp"));
-  polAlg->setProperty("CAlpha", getPropertyValue("CAlpha"));
+  polAlg->setProperty("Efficiencies", efficiencies);
   polAlg->execute();
 
   // Now we've overwritten the IvsLam workspaces, we'll need to recalculate
@@ -793,10 +801,10 @@ bool ReflectometryReductionOneAuto2::processGroups() {
 }
 
 /**
-* Sum transmission workspaces that belong to a workspace group
-* @param transGroup : The transmission group containing the transmission runs
-* @return :: A workspace pointer containing the sum of transmission workspaces
-*/
+ * Sum transmission workspaces that belong to a workspace group
+ * @param transGroup : The transmission group containing the transmission runs
+ * @return :: A workspace pointer containing the sum of transmission workspaces
+ */
 MatrixWorkspace_sptr ReflectometryReductionOneAuto2::sumTransmissionWorkspaces(
     WorkspaceGroup_sptr &transGroup) {
 
diff --git a/Framework/Algorithms/test/PolarizationCorrectionTest.h b/Framework/Algorithms/test/PolarizationCorrectionFredrikzeTest.h
similarity index 51%
rename from Framework/Algorithms/test/PolarizationCorrectionTest.h
rename to Framework/Algorithms/test/PolarizationCorrectionFredrikzeTest.h
index 921b60eca4059822c7abb40815c407220f47ab63..0e3d0d69fe3e1dee18d09aa3cb963289b6dc11f6 100644
--- a/Framework/Algorithms/test/PolarizationCorrectionTest.h
+++ b/Framework/Algorithms/test/PolarizationCorrectionFredrikzeTest.h
@@ -1,58 +1,68 @@
-#ifndef MANTID_ALGORITHMS_POLARIZATIONCORRECTION_TEST_H_
-#define MANTID_ALGORITHMS_POLARIZATIONCORRECTION_TEST_H_
+#ifndef MANTID_ALGORITHMS_POLARIZATIONCORRECTIONFREDRIKZE_TEST_H_
+#define MANTID_ALGORITHMS_POLARIZATIONCORRECTIONFREDRIKZE_TEST_H_
 
 #include <cxxtest/TestSuite.h>
-#include "MantidAlgorithms/PolarizationCorrection.h"
+
+#include "MantidAPI/AlgorithmManager.h"
+#include "MantidAPI/AnalysisDataService.h"
 #include "MantidAPI/Axis.h"
-#include "MantidDataObjects/Workspace2D.h"
+#include "MantidAPI/WorkspaceGroup.h"
+#include "MantidAlgorithms/PolarizationCorrectionFredrikze.h"
+#include "MantidDataHandling/CreatePolarizationEfficiencies.h"
 #include "MantidDataObjects/TableWorkspace.h"
-#include <boost/make_shared.hpp>
+#include "MantidDataObjects/Workspace2D.h"
+#include "MantidKernel/OptionalBool.h"
+
 #include "MantidTestHelpers/WorkspaceCreationHelper.h"
-#include "MantidAPI/AlgorithmManager.h"
-#include "MantidAPI/WorkspaceGroup.h"
+
+#include <boost/make_shared.hpp>
 
 using namespace Mantid::API;
 using namespace Mantid::Algorithms;
+using namespace Mantid::DataHandling;
 using namespace Mantid::DataObjects;
 using namespace WorkspaceCreationHelper;
 
-class PolarizationCorrectionTest : public CxxTest::TestSuite {
+class PolarizationCorrectionFredrikzeTest : 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 PolarizationCorrectionTest *createSuite() {
-    return new PolarizationCorrectionTest();
+  static PolarizationCorrectionFredrikzeTest *createSuite() {
+    return new PolarizationCorrectionFredrikzeTest();
+  }
+  static void destroySuite(PolarizationCorrectionFredrikzeTest *suite) {
+    AnalysisDataService::Instance().clear();
+    delete suite;
   }
-  static void destroySuite(PolarizationCorrectionTest *suite) { delete suite; }
 
   void test_Init() {
-    PolarizationCorrection alg;
+    PolarizationCorrectionFredrikze alg;
     TS_ASSERT_THROWS_NOTHING(alg.initialize())
     TS_ASSERT(alg.isInitialized())
   }
 
   void test_set_wrong_workspace_type_throws() {
     MatrixWorkspace_sptr ws = boost::make_shared<Workspace2D>();
-    PolarizationCorrection alg;
+    PolarizationCorrectionFredrikze alg;
     TS_ASSERT_THROWS_NOTHING(alg.initialize());
     TS_ASSERT_THROWS(alg.setProperty("InputWorkspace", ws),
                      std::invalid_argument &);
   }
 
   void test_set_analysis_to_PA() {
-    PolarizationCorrection alg;
+    PolarizationCorrectionFredrikze alg;
     TS_ASSERT_THROWS_NOTHING(alg.initialize());
     TS_ASSERT_THROWS_NOTHING(alg.setProperty("PolarizationAnalysis", "PA"));
   }
 
   void test_set_analysis_to_PNR() {
-    PolarizationCorrection alg;
+    PolarizationCorrectionFredrikze alg;
     TS_ASSERT_THROWS_NOTHING(alg.initialize())
     TS_ASSERT_THROWS_NOTHING(alg.setProperty("PolarizationAnalysis", "PNR"));
   }
 
   void test_set_analysis_to_invalid_throws() {
-    PolarizationCorrection alg;
+    PolarizationCorrectionFredrikze alg;
     TS_ASSERT_THROWS_NOTHING(alg.initialize())
     TS_ASSERT_THROWS(alg.setProperty("PolarizationAnalysis", "_"),
                      std::invalid_argument &);
@@ -64,23 +74,44 @@ public:
     return group;
   }
 
+  MatrixWorkspace_sptr makeEfficiencies(Workspace_sptr inWS,
+                                        const std::string &rho,
+                                        const std::string &pp,
+                                        const std::string &alpha = "",
+                                        const std::string &ap = "") {
+    CreatePolarizationEfficiencies alg;
+    alg.setChild(true);
+    alg.setRethrows(true);
+    alg.initialize();
+    alg.setProperty("InputWorkspace", inWS);
+    alg.setPropertyValue("Rho", rho);
+    alg.setPropertyValue("Pp", pp);
+    if (!ap.empty()) {
+      alg.setPropertyValue("Ap", ap);
+      alg.setPropertyValue("Alpha", alpha);
+    }
+    alg.setPropertyValue("OutputWorkspace", "dummy");
+    alg.execute();
+    MatrixWorkspace_sptr outWS = alg.getProperty("OutputWorkspace");
+    return outWS;
+  }
+
   void test_throw_if_PA_and_group_is_wrong_size_throws() {
     Mantid::API::WorkspaceGroup_sptr inWS =
         boost::make_shared<WorkspaceGroup>(); // Empty group ws.
 
     // Name of the output workspace.
-    std::string outWSName("PolarizationCorrectionTest_OutputWS");
+    std::string outWSName("PolarizationCorrectionFredrikzeTest_OutputWS");
+    auto efficiencies = makeEfficiencies(create1DWorkspace(4, 1, 1), "1,1,1,1",
+                                         "1,1,1,1", "1,1,1,1", "1,1,1,1");
 
-    PolarizationCorrection alg;
+    PolarizationCorrectionFredrikze alg;
     alg.setChild(true);
     alg.setRethrows(true);
     alg.initialize();
     alg.setProperty("InputWorkspace", inWS);
     alg.setProperty("PolarizationAnalysis", "PA");
-    alg.setPropertyValue("CRho", "1,1,1,1");
-    alg.setPropertyValue("CAlpha", "1,1,1,1");
-    alg.setPropertyValue("CAp", "1,1,1,1");
-    alg.setPropertyValue("CPp", "1,1,1,1");
+    alg.setProperty("Efficiencies", efficiencies);
 
     alg.setPropertyValue("OutputWorkspace", outWSName);
     TSM_ASSERT_THROWS("Wrong number of grouped workspaces, should throw",
@@ -92,19 +123,18 @@ public:
         boost::make_shared<WorkspaceGroup>(); // Empty group ws.
 
     // Name of the output workspace.
-    std::string outWSName("PolarizationCorrectionTest_OutputWS");
+    std::string outWSName("PolarizationCorrectionFredrikzeTest_OutputWS");
+    auto efficiencies = makeEfficiencies(create1DWorkspace(4, 1, 1), "1,1,1,1",
+                                         "1,1,1,1", "1,1,1,1", "1,1,1,1");
 
-    PolarizationCorrection alg;
+    PolarizationCorrectionFredrikze alg;
     alg.setChild(true);
     alg.setRethrows(true);
     alg.initialize();
     alg.setProperty("InputWorkspace", inWS);
     alg.setProperty("PolarizationAnalysis", "PNR");
     alg.setPropertyValue("OutputWorkspace", outWSName);
-    alg.setPropertyValue("CRho", "1,1,1,1");
-    alg.setPropertyValue("CAlpha", "1,1,1,1");
-    alg.setPropertyValue("CAp", "1,1,1,1");
-    alg.setPropertyValue("CPp", "1,1,1,1");
+    alg.setProperty("Efficiencies", efficiencies);
     TSM_ASSERT_THROWS("Wrong number of grouped workspaces, should throw",
                       alg.execute(), std::invalid_argument &);
   }
@@ -118,19 +148,18 @@ public:
                                                               // table workspace
 
     // Name of the output workspace.
-    std::string outWSName("PolarizationCorrectionTest_OutputWS");
+    std::string outWSName("PolarizationCorrectionFredrikzeTest_OutputWS");
+    auto efficiencies = makeEfficiencies(create1DWorkspace(4, 1, 1), "1,1,1,1",
+                                         "1,1,1,1", "1,1,1,1", "1,1,1,1");
 
-    PolarizationCorrection alg;
+    PolarizationCorrectionFredrikze alg;
     alg.setChild(true);
     alg.setRethrows(true);
     alg.initialize();
     alg.setProperty("InputWorkspace", inWS);
     alg.setProperty("PolarizationAnalysis", "PNR");
     alg.setPropertyValue("OutputWorkspace", outWSName);
-    alg.setPropertyValue("CRho", "1,1,1,1");
-    alg.setPropertyValue("CAlpha", "1,1,1,1");
-    alg.setPropertyValue("CAp", "1,1,1,1");
-    alg.setPropertyValue("CPp", "1,1,1,1");
+    alg.setProperty("Efficiencies", efficiencies);
     TSM_ASSERT_THROWS("Wrong workspace types in group", alg.execute(),
                       std::invalid_argument &);
   }
@@ -149,18 +178,17 @@ public:
     groupWS->addWorkspace(create1DWorkspace(4, 1, 1));
     groupWS->addWorkspace(create1DWorkspace(4, 1, 1));
     groupWS->addWorkspace(create1DWorkspace(4, 1, 1));
+    auto efficiencies = makeEfficiencies(create1DWorkspace(4, 1, 1), "1,0,0,0",
+                                         "1,0,0,0", "1,0,0,0", "1,0,0,0");
 
-    PolarizationCorrection alg;
+    PolarizationCorrectionFredrikze alg;
     alg.setChild(true);
     alg.setRethrows(true);
     alg.initialize();
     alg.setProperty("InputWorkspace", groupWS);
     alg.setPropertyValue("OutputWorkspace", "dummy");
     alg.setProperty("PolarizationAnalysis", "PA");
-    alg.setPropertyValue("CRho", "1,0,0,0");
-    alg.setPropertyValue("CAlpha", "1,0,0,0");
-    alg.setPropertyValue("CAp", "1,0,0,0");
-    alg.setPropertyValue("CPp", "1,0,0,0");
+    alg.setProperty("Efficiencies", efficiencies);
     alg.execute();
     WorkspaceGroup_sptr outWS = alg.getProperty("OutputWorkspace");
 
@@ -181,20 +209,91 @@ public:
     }
   }
 
+  void setInstrument(Workspace_sptr ws, const std::string &instrument_name) {
+    auto alg = AlgorithmManager::Instance().createUnmanaged("LoadInstrument");
+    AnalysisDataService::Instance().addOrReplace("dummy", ws);
+    alg->initialize();
+    alg->setProperty("Workspace", "dummy");
+    alg->setProperty("InstrumentName", instrument_name);
+    alg->setProperty("RewriteSpectraMap", Mantid::Kernel::OptionalBool(true));
+    alg->execute();
+  }
+
+  void test_run_PA_default() {
+    auto groupWS = boost::make_shared<WorkspaceGroup>(); // Empty group ws.
+    groupWS->addWorkspace(create1DWorkspace(4, 1, 1));
+    groupWS->addWorkspace(create1DWorkspace(4, 1, 1));
+    groupWS->addWorkspace(create1DWorkspace(4, 1, 1));
+    groupWS->addWorkspace(create1DWorkspace(4, 1, 1));
+    setInstrument(groupWS, "POLREF");
+    auto efficiencies =
+        makeEfficiencies(create1DWorkspace(4, 1, 1), "1,0,0,0", "1,0,0,0");
+
+    PolarizationCorrectionFredrikze alg;
+    alg.setChild(true);
+    alg.setRethrows(true);
+    alg.initialize();
+    alg.setProperty("InputWorkspace", groupWS);
+    alg.setPropertyValue("OutputWorkspace", "dummy");
+    alg.setProperty("PolarizationAnalysis", "PA");
+    alg.setProperty("Efficiencies", efficiencies);
+    alg.execute();
+    WorkspaceGroup_sptr outWS = alg.getProperty("OutputWorkspace");
+
+    TSM_ASSERT_EQUALS("Wrong number of output workspaces", outWS->size(),
+                      groupWS->size());
+
+    for (size_t i = 0; i < outWS->size(); ++i) {
+      std::cout << "Checking equivalent workspaces at index : " << i << '\n';
+      auto checkAlg =
+          AlgorithmManager::Instance().createUnmanaged("CompareWorkspaces");
+      checkAlg->initialize();
+      checkAlg->setChild(true);
+      checkAlg->setProperty("Workspace1", groupWS->getItem(i));
+      checkAlg->setProperty("Workspace2", outWS->getItem(i));
+      checkAlg->setProperty("Tolerance", 3e-16);
+      checkAlg->execute();
+      TS_ASSERT(!checkAlg->getProperty("Result"));
+    }
+  }
+
+  void test_run_PA_default_no_instrument_parameters() {
+    auto groupWS = boost::make_shared<WorkspaceGroup>(); // Empty group ws.
+    groupWS->addWorkspace(create1DWorkspace(4, 1, 1));
+    groupWS->addWorkspace(create1DWorkspace(4, 1, 1));
+    groupWS->addWorkspace(create1DWorkspace(4, 1, 1));
+    groupWS->addWorkspace(create1DWorkspace(4, 1, 1));
+    auto efficiencies =
+        makeEfficiencies(create1DWorkspace(4, 1, 1), "1,0,0,0", "1,0,0,0");
+
+    PolarizationCorrectionFredrikze alg;
+    alg.setChild(true);
+    alg.setRethrows(true);
+    alg.initialize();
+    alg.setProperty("InputWorkspace", groupWS);
+    alg.setPropertyValue("OutputWorkspace", "dummy");
+    alg.setProperty("PolarizationAnalysis", "PA");
+    alg.setProperty("Efficiencies", efficiencies);
+    TSM_ASSERT_THROWS(
+        "Instrument doesn't have default efficiencies, should throw",
+        alg.execute(), std::invalid_argument &);
+  }
+
   void test_run_PNR_unity() {
     auto groupWS = boost::make_shared<WorkspaceGroup>(); // Empty group ws.
     groupWS->addWorkspace(create1DWorkspace(4, 1, 1));
     groupWS->addWorkspace(create1DWorkspace(4, 1, 1));
+    auto efficiencies =
+        makeEfficiencies(create1DWorkspace(4, 1, 1), "1,0,0,0", "1,0,0,0");
 
-    PolarizationCorrection alg;
+    PolarizationCorrectionFredrikze alg;
     alg.setChild(true);
     alg.setRethrows(true);
     alg.initialize();
     alg.setProperty("InputWorkspace", groupWS);
     alg.setPropertyValue("OutputWorkspace", "dummy");
     alg.setProperty("PolarizationAnalysis", "PNR");
-    alg.setPropertyValue("CRho", "1,0,0,0");
-    alg.setPropertyValue("CPp", "1,0,0,0");
+    alg.setProperty("Efficiencies", efficiencies);
     alg.execute();
     WorkspaceGroup_sptr outWS = alg.getProperty("OutputWorkspace");
 
@@ -215,4 +314,4 @@ public:
   }
 };
 
-#endif /* MANTID_ALGORITHMS_POLARIZATIONCORRECTION_TEST_H_ */
+#endif /* MANTID_ALGORITHMS_POLARIZATIONCORRECTIONFREDRIKZE_TEST_H_ */
diff --git a/Framework/Algorithms/test/PolarizationCorrectionWildesTest.h b/Framework/Algorithms/test/PolarizationCorrectionWildesTest.h
new file mode 100644
index 0000000000000000000000000000000000000000..e962c7c14767ad7feaf1ad9c46c1e816e8fbb214
--- /dev/null
+++ b/Framework/Algorithms/test/PolarizationCorrectionWildesTest.h
@@ -0,0 +1,1990 @@
+#ifndef MANTID_ALGORITHMS_POLARIZATIONCORRECTIONWILDESTEST_H_
+#define MANTID_ALGORITHMS_POLARIZATIONCORRECTIONWILDESTEST_H_
+
+#include <cxxtest/TestSuite.h>
+
+#include "MantidAlgorithms/PolarizationCorrectionWildes.h"
+
+#include "MantidAPI/AlgorithmManager.h"
+#include "MantidAPI/AnalysisDataService.h"
+#include "MantidAPI/MatrixWorkspace.h"
+#include "MantidAPI/TextAxis.h"
+#include "MantidAPI/WorkspaceFactory.h"
+#include "MantidAPI/WorkspaceGroup.h"
+#include "MantidDataObjects/Workspace2D.h"
+#include "MantidDataObjects/WorkspaceCreation.h"
+
+#include <Eigen/Dense>
+
+using Mantid::Algorithms::PolarizationCorrectionWildes;
+
+class PolarizationCorrectionWildesTest : 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 PolarizationCorrectionWildesTest *createSuite() {
+    return new PolarizationCorrectionWildesTest();
+  }
+  static void destroySuite(PolarizationCorrectionWildesTest *suite) {
+    delete suite;
+  }
+
+  void tearDown() override {
+    using namespace Mantid::API;
+    AnalysisDataService::Instance().clear();
+  }
+
+  void test_Init() {
+    PolarizationCorrectionWildes alg;
+    TS_ASSERT_THROWS_NOTHING(alg.initialize())
+    TS_ASSERT(alg.isInitialized())
+  }
+
+  void test_IdealCaseFullCorrections() {
+    using namespace Mantid::API;
+    using namespace Mantid::DataObjects;
+    using namespace Mantid::HistogramData;
+    using namespace Mantid::Kernel;
+    constexpr size_t nBins{3};
+    constexpr size_t nHist{2};
+    BinEdges edges{0.3, 0.6, 0.9, 1.2};
+    const double yVal = 2.3;
+    Counts counts{yVal, 4.2 * yVal, yVal};
+    MatrixWorkspace_sptr ws00 =
+        create<Workspace2D>(nHist, Histogram(edges, counts));
+    MatrixWorkspace_sptr ws01 = ws00->clone();
+    MatrixWorkspace_sptr ws10 = ws00->clone();
+    MatrixWorkspace_sptr ws11 = ws00->clone();
+    const std::vector<std::string> wsNames{{"ws00", "ws01", "ws10", "ws11"}};
+    const std::array<MatrixWorkspace_sptr, 4> wsList{{ws00, ws01, ws10, ws11}};
+    for (size_t i = 0; i != 4; ++i) {
+      for (size_t j = 0; j != nHist; ++j) {
+        wsList[i]->mutableY(j) *= static_cast<double>(i + 1);
+        wsList[i]->mutableE(j) *= static_cast<double>(i + 1);
+      }
+      AnalysisDataService::Instance().addOrReplace(wsNames[i], wsList[i]);
+    }
+    auto effWS = idealEfficiencies(edges);
+    PolarizationCorrectionWildes alg;
+    alg.setChild(true);
+    alg.setRethrows(true);
+    TS_ASSERT_THROWS_NOTHING(alg.initialize())
+    TS_ASSERT(alg.isInitialized())
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("InputWorkspaces", wsNames))
+    TS_ASSERT_THROWS_NOTHING(
+        alg.setPropertyValue("OutputWorkspace", m_outputWSName))
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("Efficiencies", effWS))
+    TS_ASSERT_THROWS_NOTHING(alg.execute())
+    TS_ASSERT(alg.isExecuted())
+    WorkspaceGroup_sptr outputWS = alg.getProperty("OutputWorkspace");
+    TS_ASSERT(outputWS)
+    TS_ASSERT_EQUALS(outputWS->getNumberOfEntries(), 4)
+    const std::array<std::string, 4> POL_DIRS{{"++", "+-", "-+", "--"}};
+    for (size_t i = 0; i != 4; ++i) {
+      const std::string wsName =
+          m_outputWSName + std::string("_") + POL_DIRS[i];
+      MatrixWorkspace_sptr ws = boost::dynamic_pointer_cast<MatrixWorkspace>(
+          outputWS->getItem(wsName));
+      TS_ASSERT(ws)
+      TS_ASSERT_EQUALS(ws->getNumberHistograms(), nHist)
+      for (size_t j = 0; j != nHist; ++j) {
+        const auto &xs = ws->x(j);
+        const auto &ys = ws->y(j);
+        const auto &es = ws->e(j);
+        TS_ASSERT_EQUALS(ys.size(), nBins)
+        for (size_t k = 0; k != nBins; ++k) {
+          const double y = counts[k];
+          TS_ASSERT_EQUALS(xs[k], edges[k])
+          TS_ASSERT_EQUALS(ys[k], y * static_cast<double>(i + 1))
+          TS_ASSERT_EQUALS(es[k], std::sqrt(y) * static_cast<double>(i + 1))
+        }
+      }
+    }
+  }
+
+  void test_IdealCaseThreeInputs10Missing() { idealThreeInputsTest("10"); }
+
+  void test_IdealCaseThreeInputs01Missing() { idealThreeInputsTest("01"); }
+
+  void test_IdealCaseTwoInputsWithAnalyzer() {
+    using namespace Mantid::API;
+    using namespace Mantid::DataObjects;
+    using namespace Mantid::HistogramData;
+    using namespace Mantid::Kernel;
+    constexpr size_t nBins{3};
+    constexpr size_t nHist{2};
+    BinEdges edges{0.3, 0.6, 0.9, 1.2};
+    const double yVal = 2.3;
+    Counts counts{yVal, 4.2 * yVal, yVal};
+    MatrixWorkspace_sptr ws00 =
+        create<Workspace2D>(nHist, Histogram(edges, counts));
+    MatrixWorkspace_sptr ws11 = ws00->clone();
+    const std::vector<std::string> wsNames{
+        std::initializer_list<std::string>{"ws00", "ws11"}};
+    const std::array<MatrixWorkspace_sptr, 2> wsList{{ws00, ws11}};
+    for (size_t i = 0; i != nHist; ++i) {
+      ws11->mutableY(i) *= 2.;
+      ws11->mutableE(i) *= 2.;
+    }
+    AnalysisDataService::Instance().addOrReplace(wsNames.front(),
+                                                 wsList.front());
+    AnalysisDataService::Instance().addOrReplace(wsNames.back(), wsList.back());
+    auto effWS = idealEfficiencies(edges);
+    PolarizationCorrectionWildes alg;
+    alg.setChild(true);
+    alg.setRethrows(true);
+    TS_ASSERT_THROWS_NOTHING(alg.initialize())
+    TS_ASSERT(alg.isInitialized())
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("InputWorkspaces", wsNames))
+    TS_ASSERT_THROWS_NOTHING(
+        alg.setPropertyValue("OutputWorkspace", m_outputWSName))
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("Efficiencies", effWS))
+    TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("Flippers", "00, 11"))
+    TS_ASSERT_THROWS_NOTHING(alg.execute())
+    TS_ASSERT(alg.isExecuted())
+    WorkspaceGroup_sptr outputWS = alg.getProperty("OutputWorkspace");
+    TS_ASSERT(outputWS)
+    TS_ASSERT_EQUALS(outputWS->getNumberOfEntries(), 4)
+    const std::array<std::string, 4> POL_DIRS{{"++", "+-", "-+", "--"}};
+    for (size_t i = 0; i != 4; ++i) {
+      const auto &dir = POL_DIRS[i];
+      const std::string wsName = m_outputWSName + std::string("_") + dir;
+      MatrixWorkspace_sptr ws = boost::dynamic_pointer_cast<MatrixWorkspace>(
+          outputWS->getItem(wsName));
+      TS_ASSERT(ws)
+      TS_ASSERT_EQUALS(ws->getNumberHistograms(), nHist)
+      for (size_t j = 0; j != nHist; ++j) {
+        const auto &xs = ws->x(j);
+        const auto &ys = ws->y(j);
+        const auto &es = ws->e(j);
+        TS_ASSERT_EQUALS(ys.size(), nBins)
+        for (size_t k = 0; k != nBins; ++k) {
+          const double y = counts[k];
+          const double expected = [y, &dir]() {
+            if (dir == "++") {
+              return y;
+            } else if (dir == "--") {
+              return 2. * y;
+            } else {
+              return 0.;
+            }
+          }();
+          const double expectedError = [y, &dir]() {
+            if (dir == "++") {
+              return std::sqrt(y);
+            } else if (dir == "--") {
+              return 2. * std::sqrt(y);
+            } else {
+              return 0.;
+            }
+          }();
+          TS_ASSERT_EQUALS(xs[k], edges[k])
+          TS_ASSERT_EQUALS(ys[k], expected)
+          TS_ASSERT_EQUALS(es[k], expectedError)
+        }
+      }
+    }
+  }
+
+  void test_IdealCaseTwoInputsNoAnalyzer() {
+    using namespace Mantid::API;
+    using namespace Mantid::DataObjects;
+    using namespace Mantid::HistogramData;
+    using namespace Mantid::Kernel;
+    constexpr size_t nBins{3};
+    constexpr size_t nHist{2};
+    BinEdges edges{0.3, 0.6, 0.9, 1.2};
+    const double yVal = 2.3;
+    Counts counts{yVal, 4.2 * yVal, yVal};
+    MatrixWorkspace_sptr ws00 =
+        create<Workspace2D>(nHist, Histogram(edges, counts));
+    MatrixWorkspace_sptr ws11 = ws00->clone();
+    const std::vector<std::string> wsNames{
+        std::initializer_list<std::string>{"ws00", "ws11"}};
+    const std::array<MatrixWorkspace_sptr, 2> wsList{{ws00, ws11}};
+    for (size_t i = 0; i != nHist; ++i) {
+      ws11->mutableY(i) *= 2.;
+      ws11->mutableE(i) *= 2.;
+    }
+    AnalysisDataService::Instance().addOrReplace(wsNames.front(),
+                                                 wsList.front());
+    AnalysisDataService::Instance().addOrReplace(wsNames.back(), wsList.back());
+    auto effWS = idealEfficiencies(edges);
+    PolarizationCorrectionWildes alg;
+    alg.setChild(true);
+    alg.setRethrows(true);
+    TS_ASSERT_THROWS_NOTHING(alg.initialize())
+    TS_ASSERT(alg.isInitialized())
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("InputWorkspaces", wsNames))
+    TS_ASSERT_THROWS_NOTHING(
+        alg.setPropertyValue("OutputWorkspace", m_outputWSName))
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("Efficiencies", effWS))
+    TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("Flippers", "0, 1"))
+    TS_ASSERT_THROWS_NOTHING(alg.execute())
+    TS_ASSERT(alg.isExecuted())
+    WorkspaceGroup_sptr outputWS = alg.getProperty("OutputWorkspace");
+    TS_ASSERT(outputWS)
+    TS_ASSERT_EQUALS(outputWS->getNumberOfEntries(), 2)
+    const std::array<std::string, 2> POL_DIRS{{"++", "--"}};
+    for (size_t i = 0; i != 2; ++i) {
+      const auto &dir = POL_DIRS[i];
+      const std::string wsName = m_outputWSName + std::string("_") + dir;
+      MatrixWorkspace_sptr ws = boost::dynamic_pointer_cast<MatrixWorkspace>(
+          outputWS->getItem(wsName));
+      TS_ASSERT(ws)
+      TS_ASSERT_EQUALS(ws->getNumberHistograms(), nHist)
+      for (size_t j = 0; j != nHist; ++j) {
+        const auto &xs = ws->x(j);
+        const auto &ys = ws->y(j);
+        const auto &es = ws->e(j);
+        TS_ASSERT_EQUALS(ys.size(), nBins)
+        for (size_t k = 0; k != nBins; ++k) {
+          const double y = counts[k];
+          TS_ASSERT_EQUALS(xs[k], edges[k])
+          TS_ASSERT_EQUALS(ys[k], y * static_cast<double>(i + 1))
+          TS_ASSERT_EQUALS(es[k], std::sqrt(y) * static_cast<double>(i + 1))
+        }
+      }
+    }
+  }
+
+  void test_IdealCaseDirectBeamCorrections() {
+    using namespace Mantid::API;
+    using namespace Mantid::DataObjects;
+    using namespace Mantid::HistogramData;
+    using namespace Mantid::Kernel;
+    constexpr size_t nBins{3};
+    constexpr size_t nHist{2};
+    BinEdges edges{0.3, 0.6, 0.9, 1.2};
+    const double yVal = 2.3;
+    Counts counts{yVal, 4.2 * yVal, yVal};
+    MatrixWorkspace_sptr ws00 =
+        create<Workspace2D>(nHist, Histogram(edges, counts));
+    const std::vector<std::string> wsNames{{"ws00"}};
+    AnalysisDataService::Instance().addOrReplace(wsNames.front(), ws00);
+    auto effWS = idealEfficiencies(edges);
+    PolarizationCorrectionWildes alg;
+    alg.setChild(true);
+    alg.setRethrows(true);
+    TS_ASSERT_THROWS_NOTHING(alg.initialize())
+    TS_ASSERT(alg.isInitialized())
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("InputWorkspaces", wsNames))
+    TS_ASSERT_THROWS_NOTHING(
+        alg.setPropertyValue("OutputWorkspace", m_outputWSName))
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("Efficiencies", effWS))
+    TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("Flippers", "0"))
+    TS_ASSERT_THROWS_NOTHING(alg.execute())
+    TS_ASSERT(alg.isExecuted())
+    WorkspaceGroup_sptr outputWS = alg.getProperty("OutputWorkspace");
+    TS_ASSERT(outputWS)
+    TS_ASSERT_EQUALS(outputWS->getNumberOfEntries(), 1)
+    MatrixWorkspace_sptr ws = boost::dynamic_pointer_cast<MatrixWorkspace>(
+        outputWS->getItem(m_outputWSName + std::string("_++")));
+    TS_ASSERT(ws)
+    TS_ASSERT_EQUALS(ws->getNumberHistograms(), nHist)
+    for (size_t i = 0; i != nHist; ++i) {
+      const auto &xs = ws->x(i);
+      const auto &ys = ws->y(i);
+      const auto &es = ws->e(i);
+      TS_ASSERT_EQUALS(ys.size(), nBins)
+      for (size_t j = 0; j != nBins; ++j) {
+        const double y = counts[j];
+        TS_ASSERT_EQUALS(xs[j], edges[j])
+        TS_ASSERT_EQUALS(ys[j], y)
+        TS_ASSERT_EQUALS(es[j], std::sqrt(y))
+      }
+    }
+  }
+
+  void test_FullCorrections() {
+    using namespace Mantid::API;
+    using namespace Mantid::DataObjects;
+    using namespace Mantid::HistogramData;
+    using namespace Mantid::Kernel;
+    constexpr size_t nHist{2};
+    BinEdges edges{0.3, 0.6, 0.9, 1.2};
+    const double yVal = 2.3;
+    Counts counts{yVal, yVal, yVal};
+    MatrixWorkspace_sptr ws00 =
+        create<Workspace2D>(nHist, Histogram(edges, counts));
+    MatrixWorkspace_sptr ws01 = ws00->clone();
+    MatrixWorkspace_sptr ws10 = ws00->clone();
+    MatrixWorkspace_sptr ws11 = ws00->clone();
+    const std::vector<std::string> wsNames{{"ws00", "ws01", "ws10", "ws11"}};
+    const std::array<MatrixWorkspace_sptr, 4> wsList{{ws00, ws01, ws10, ws11}};
+    for (size_t i = 0; i != 4; ++i) {
+      for (size_t j = 0; j != nHist; ++j) {
+        wsList[i]->mutableY(j) *= static_cast<double>(i + 1);
+        wsList[i]->mutableE(j) *= static_cast<double>(i + 1);
+      }
+      AnalysisDataService::Instance().addOrReplace(wsNames[i], wsList[i]);
+    }
+    auto effWS = efficiencies(edges);
+    PolarizationCorrectionWildes alg;
+    alg.setChild(true);
+    alg.setRethrows(true);
+    TS_ASSERT_THROWS_NOTHING(alg.initialize())
+    TS_ASSERT(alg.isInitialized())
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("InputWorkspaces", wsNames))
+    TS_ASSERT_THROWS_NOTHING(
+        alg.setPropertyValue("OutputWorkspace", m_outputWSName))
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("Efficiencies", effWS))
+    TS_ASSERT_THROWS_NOTHING(alg.execute())
+    TS_ASSERT(alg.isExecuted())
+    WorkspaceGroup_sptr outputWS = alg.getProperty("OutputWorkspace");
+    TS_ASSERT(outputWS)
+    TS_ASSERT_EQUALS(outputWS->getNumberOfEntries(), 4)
+    fullFourInputsResultsCheck(outputWS, ws00, ws01, ws10, ws11, effWS);
+  }
+
+  void test_ThreeInputsWithMissing01FlipperConfiguration() {
+    threeInputsTest("01");
+  }
+
+  void test_ThreeInputsWithMissing10FlipperConfiguration() {
+    threeInputsTest("10");
+  }
+
+  void test_TwoInputsWithAnalyzer() {
+    using namespace Mantid::API;
+    using namespace Mantid::DataObjects;
+    using namespace Mantid::HistogramData;
+    using namespace Mantid::Kernel;
+    constexpr size_t nHist{2};
+    constexpr size_t nBins{3};
+    BinEdges edges{0.3, 0.6, 0.9, 1.2};
+    const double yVal = 2.3;
+    Counts counts{yVal, yVal, yVal};
+    MatrixWorkspace_sptr ws00 =
+        create<Workspace2D>(nHist, Histogram(edges, counts));
+    MatrixWorkspace_sptr ws01 = nullptr;
+    MatrixWorkspace_sptr ws10 = nullptr;
+    MatrixWorkspace_sptr ws11 = ws00->clone();
+    const std::vector<std::string> wsNames{
+        std::initializer_list<std::string>{"ws00", "ws11"}};
+    const std::array<MatrixWorkspace_sptr, 2> wsList{{ws00, ws11}};
+    for (size_t i = 0; i != 2; ++i) {
+      for (size_t j = 0; j != nHist; ++j) {
+        wsList[i]->mutableY(j) *= static_cast<double>(i + 1);
+        wsList[i]->mutableE(j) *= static_cast<double>(i + 1);
+      }
+      AnalysisDataService::Instance().addOrReplace(wsNames[i], wsList[i]);
+    }
+    auto effWS = efficiencies(edges);
+    PolarizationCorrectionWildes alg;
+    alg.setChild(true);
+    alg.setRethrows(true);
+    TS_ASSERT_THROWS_NOTHING(alg.initialize())
+    TS_ASSERT(alg.isInitialized())
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("InputWorkspaces", wsNames))
+    TS_ASSERT_THROWS_NOTHING(
+        alg.setPropertyValue("OutputWorkspace", m_outputWSName))
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("Efficiencies", effWS))
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("Flippers", "00, 11"))
+    TS_ASSERT_THROWS_NOTHING(alg.execute())
+    TS_ASSERT(alg.isExecuted())
+    WorkspaceGroup_sptr outputWS = alg.getProperty("OutputWorkspace");
+    TS_ASSERT(outputWS)
+    TS_ASSERT_EQUALS(outputWS->getNumberOfEntries(), 4)
+    solveMissingIntensities(ws00, ws01, ws10, ws11, effWS);
+    using namespace Mantid::API;
+    const double F1 = effWS->y(0).front();
+    const double F1e = effWS->e(0).front();
+    const double F2 = effWS->y(1).front();
+    const double F2e = effWS->e(1).front();
+    const double P1 = effWS->y(2).front();
+    const double P1e = effWS->e(2).front();
+    const double P2 = effWS->y(3).front();
+    const double P2e = effWS->e(3).front();
+    const Eigen::Vector4d y{ws00->y(0).front(), ws01->y(0).front(),
+                            ws10->y(0).front(), ws11->y(0).front()};
+    const auto expected = correction(y, F1, F2, P1, P2);
+    const Eigen::Vector4d e{ws00->e(0).front(), ws01->e(0).front(),
+                            ws10->e(0).front(), ws11->e(0).front()};
+    const auto expectedError = error(y, e, F1, F1e, F2, F2e, P1, P1e, P2, P2e);
+    MatrixWorkspace_sptr ppWS = boost::dynamic_pointer_cast<MatrixWorkspace>(
+        outputWS->getItem(m_outputWSName + std::string("_++")));
+    MatrixWorkspace_sptr pmWS = boost::dynamic_pointer_cast<MatrixWorkspace>(
+        outputWS->getItem(m_outputWSName + std::string("_+-")));
+    MatrixWorkspace_sptr mpWS = boost::dynamic_pointer_cast<MatrixWorkspace>(
+        outputWS->getItem(m_outputWSName + std::string("_-+")));
+    MatrixWorkspace_sptr mmWS = boost::dynamic_pointer_cast<MatrixWorkspace>(
+        outputWS->getItem(m_outputWSName + std::string("_--")));
+    TS_ASSERT(ppWS)
+    TS_ASSERT(pmWS)
+    TS_ASSERT(mpWS)
+    TS_ASSERT(mmWS)
+    TS_ASSERT_EQUALS(ppWS->getNumberHistograms(), nHist)
+    TS_ASSERT_EQUALS(pmWS->getNumberHistograms(), nHist)
+    TS_ASSERT_EQUALS(mpWS->getNumberHistograms(), nHist)
+    TS_ASSERT_EQUALS(mmWS->getNumberHistograms(), nHist)
+    for (size_t j = 0; j != nHist; ++j) {
+      const auto &ppX = ppWS->x(j);
+      const auto &ppY = ppWS->y(j);
+      const auto &ppE = ppWS->e(j);
+      const auto &pmX = pmWS->x(j);
+      const auto &pmY = pmWS->y(j);
+      const auto &pmE = pmWS->e(j);
+      const auto &mpX = mpWS->x(j);
+      const auto &mpY = mpWS->y(j);
+      const auto &mpE = mpWS->e(j);
+      const auto &mmX = mmWS->x(j);
+      const auto &mmY = mmWS->y(j);
+      const auto &mmE = mmWS->e(j);
+      TS_ASSERT_EQUALS(ppY.size(), nBins)
+      TS_ASSERT_EQUALS(pmY.size(), nBins)
+      TS_ASSERT_EQUALS(mpY.size(), nBins)
+      TS_ASSERT_EQUALS(mmY.size(), nBins)
+      for (size_t k = 0; k != nBins; ++k) {
+        TS_ASSERT_EQUALS(ppX[k], edges[k])
+        TS_ASSERT_EQUALS(pmX[k], edges[k])
+        TS_ASSERT_EQUALS(mpX[k], edges[k])
+        TS_ASSERT_EQUALS(mmX[k], edges[k])
+        TS_ASSERT_DELTA(ppY[k], expected[0], 1e-12)
+        TS_ASSERT_DELTA(pmY[k], expected[1], 1e-12)
+        TS_ASSERT_DELTA(mpY[k], expected[2], 1e-12)
+        TS_ASSERT_DELTA(mmY[k], expected[3], 1e-12)
+        // This test constructs the expected missing I01 and I10 intensities
+        // slightly different from what the algorithm does: I10 is solved
+        // first and then I01 is solved using all I00, I10 and I11. This
+        // results in slightly larger errors estimates for I01 and thus for
+        // the final corrected expected intensities.
+        TS_ASSERT_DELTA(ppE[k], expectedError[0], 1e-6)
+        TS_ASSERT_LESS_THAN(ppE[k], expectedError[0])
+        TS_ASSERT_DELTA(pmE[k], expectedError[1], 1e-2)
+        TS_ASSERT_LESS_THAN(pmE[k], expectedError[1])
+        TS_ASSERT_DELTA(mpE[k], expectedError[2], 1e-7)
+        TS_ASSERT_LESS_THAN(mpE[k], expectedError[2])
+        TS_ASSERT_DELTA(mmE[k], expectedError[3], 1e-5)
+        TS_ASSERT_LESS_THAN(mmE[k], expectedError[3])
+      }
+    }
+  }
+
+  void test_TwoInputsWithoutAnalyzer() {
+    using namespace Mantid::API;
+    using namespace Mantid::DataObjects;
+    using namespace Mantid::HistogramData;
+    using namespace Mantid::Kernel;
+    constexpr size_t nHist{2};
+    constexpr size_t nBins{3};
+    BinEdges edges{0.3, 0.6, 0.9, 1.2};
+    const double yVal = 2.3;
+    Counts counts{yVal, yVal, yVal};
+    MatrixWorkspace_sptr ws00 =
+        create<Workspace2D>(nHist, Histogram(edges, counts));
+    MatrixWorkspace_sptr ws11 = ws00->clone();
+    const std::vector<std::string> wsNames{
+        std::initializer_list<std::string>{"ws00", "ws11"}};
+    const std::array<MatrixWorkspace_sptr, 2> wsList{{ws00, ws11}};
+    for (size_t i = 0; i != 2; ++i) {
+      for (size_t j = 0; j != nHist; ++j) {
+        wsList[i]->mutableY(j) *= static_cast<double>(i + 1);
+        wsList[i]->mutableE(j) *= static_cast<double>(i + 1);
+      }
+      AnalysisDataService::Instance().addOrReplace(wsNames[i], wsList[i]);
+    }
+    auto effWS = efficiencies(edges);
+    PolarizationCorrectionWildes alg;
+    alg.setChild(true);
+    alg.setRethrows(true);
+    TS_ASSERT_THROWS_NOTHING(alg.initialize())
+    TS_ASSERT(alg.isInitialized())
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("InputWorkspaces", wsNames))
+    TS_ASSERT_THROWS_NOTHING(
+        alg.setPropertyValue("OutputWorkspace", m_outputWSName))
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("Efficiencies", effWS))
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("Flippers", "0, 1"))
+    TS_ASSERT_THROWS_NOTHING(alg.execute())
+    TS_ASSERT(alg.isExecuted())
+    WorkspaceGroup_sptr outputWS = alg.getProperty("OutputWorkspace");
+    TS_ASSERT(outputWS)
+    TS_ASSERT_EQUALS(outputWS->getNumberOfEntries(), 2)
+    const double F1 = effWS->y(0).front();
+    const double F1e = effWS->e(0).front();
+    const double P1 = effWS->y(2).front();
+    const double P1e = effWS->e(2).front();
+    const Eigen::Vector2d y{ws00->y(0).front(), ws11->y(0).front()};
+    const auto expected = correctionWithoutAnalyzer(y, F1, P1);
+    const Eigen::Vector2d e{ws00->e(0).front(), ws11->e(0).front()};
+    const auto expectedError = errorWithoutAnalyzer(y, e, F1, F1e, P1, P1e);
+    MatrixWorkspace_sptr ppWS = boost::dynamic_pointer_cast<MatrixWorkspace>(
+        outputWS->getItem(m_outputWSName + std::string("_++")));
+    MatrixWorkspace_sptr mmWS = boost::dynamic_pointer_cast<MatrixWorkspace>(
+        outputWS->getItem(m_outputWSName + std::string("_--")));
+    TS_ASSERT(ppWS)
+    TS_ASSERT(mmWS)
+    TS_ASSERT_EQUALS(ppWS->getNumberHistograms(), nHist)
+    TS_ASSERT_EQUALS(mmWS->getNumberHistograms(), nHist)
+    for (size_t j = 0; j != nHist; ++j) {
+      const auto &ppX = ppWS->x(j);
+      const auto &ppY = ppWS->y(j);
+      const auto &ppE = ppWS->e(j);
+      const auto &mmX = mmWS->x(j);
+      const auto &mmY = mmWS->y(j);
+      const auto &mmE = mmWS->e(j);
+      TS_ASSERT_EQUALS(ppY.size(), nBins)
+      TS_ASSERT_EQUALS(mmY.size(), nBins)
+      for (size_t k = 0; k != nBins; ++k) {
+        TS_ASSERT_EQUALS(ppX[k], edges[k])
+        TS_ASSERT_EQUALS(mmX[k], edges[k])
+        TS_ASSERT_DELTA(ppY[k], expected[0], 1e-12)
+        TS_ASSERT_DELTA(mmY[k], expected[1], 1e-12)
+        TS_ASSERT_DELTA(ppE[k], expectedError[0], 1e-12)
+        TS_ASSERT_DELTA(mmE[k], expectedError[1], 1e-12)
+      }
+    }
+  }
+
+  void test_directBeamOnlyInput() {
+    using namespace Mantid::API;
+    using namespace Mantid::DataObjects;
+    using namespace Mantid::HistogramData;
+    using namespace Mantid::Kernel;
+    constexpr size_t nHist{2};
+    constexpr size_t nBins{3};
+    BinEdges edges{0.3, 0.6, 0.9, 1.2};
+    const double yVal = 2.3;
+    Counts counts{yVal, yVal, yVal};
+    MatrixWorkspace_sptr ws00 =
+        create<Workspace2D>(nHist, Histogram(edges, counts));
+    const std::string wsName{"ws00"};
+    AnalysisDataService::Instance().addOrReplace(wsName, ws00);
+    auto effWS = efficiencies(edges);
+    PolarizationCorrectionWildes alg;
+    alg.setChild(true);
+    alg.setRethrows(true);
+    TS_ASSERT_THROWS_NOTHING(alg.initialize())
+    TS_ASSERT(alg.isInitialized())
+    TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("InputWorkspaces", wsName))
+    TS_ASSERT_THROWS_NOTHING(
+        alg.setPropertyValue("OutputWorkspace", m_outputWSName))
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("Efficiencies", effWS))
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("Flippers", "0"))
+    TS_ASSERT_THROWS_NOTHING(alg.execute())
+    TS_ASSERT(alg.isExecuted())
+    WorkspaceGroup_sptr outputWS = alg.getProperty("OutputWorkspace");
+    TS_ASSERT(outputWS)
+    TS_ASSERT_EQUALS(outputWS->getNumberOfEntries(), 1)
+    const auto P1 = effWS->y(2).front();
+    const auto P1e = effWS->e(2).front();
+    const auto P2 = effWS->y(3).front();
+    const auto P2e = effWS->e(3).front();
+    const double y{ws00->y(0).front()};
+    const auto inverted = 1. / (1. - P2 - P1 + 2. * P1 * P2);
+    const auto expected = inverted * y;
+    const double e{ws00->e(0).front()};
+    const auto errorP1 = P1e * y * (2. * P1 - 1.) * inverted * inverted;
+    const auto errorP2 = P2e * y * (2. * P2 - 1.) * inverted * inverted;
+    const auto errorY = e * e * inverted * inverted;
+    const auto expectedError =
+        std::sqrt(errorP1 * errorP1 + errorP2 * errorP2 + errorY);
+    MatrixWorkspace_sptr ppWS = boost::dynamic_pointer_cast<MatrixWorkspace>(
+        outputWS->getItem(m_outputWSName + std::string("_++")));
+    TS_ASSERT(ppWS)
+    TS_ASSERT_EQUALS(ppWS->getNumberHistograms(), nHist)
+    for (size_t j = 0; j != nHist; ++j) {
+      const auto &ppX = ppWS->x(j);
+      const auto &ppY = ppWS->y(j);
+      const auto &ppE = ppWS->e(j);
+      TS_ASSERT_EQUALS(ppY.size(), nBins)
+      for (size_t k = 0; k != nBins; ++k) {
+        TS_ASSERT_EQUALS(ppX[k], edges[k])
+        TS_ASSERT_DELTA(ppY[k], expected, 1e-12)
+        TS_ASSERT_DELTA(ppE[k], expectedError, 1e-12)
+      }
+    }
+  }
+
+  void test_FailureWhenEfficiencyHistogramIsMissing() {
+    using namespace Mantid::API;
+    using namespace Mantid::DataObjects;
+    using namespace Mantid::HistogramData;
+    using namespace Mantid::Kernel;
+    BinEdges edges{0.3, 0.6, 0.9, 1.2};
+    Counts counts{0., 0., 0.};
+    MatrixWorkspace_sptr ws00 =
+        create<Workspace2D>(1, Histogram(edges, counts));
+    const std::string wsName{"ws00"};
+    AnalysisDataService::Instance().addOrReplace(wsName, ws00);
+    auto effWS = idealEfficiencies(edges);
+    // Rename F1 to something else.
+    auto axis = make_unique<TextAxis>(4);
+    axis->setLabel(0, "__wrong_histogram_label");
+    axis->setLabel(1, "F2");
+    axis->setLabel(2, "P1");
+    axis->setLabel(3, "P2");
+    effWS->replaceAxis(1, axis.release());
+    PolarizationCorrectionWildes alg;
+    alg.setChild(true);
+    alg.setRethrows(true);
+    TS_ASSERT_THROWS_NOTHING(alg.initialize())
+    TS_ASSERT(alg.isInitialized())
+    TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("InputWorkspaces", wsName))
+    TS_ASSERT_THROWS_NOTHING(
+        alg.setPropertyValue("OutputWorkspace", m_outputWSName))
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("Efficiencies", effWS))
+    TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("Flippers", "0"))
+    TS_ASSERT_THROWS(alg.execute(), std::runtime_error)
+    TS_ASSERT(!alg.isExecuted())
+  }
+
+  void test_FailureWhenEfficiencyXDataMismatches() {
+    using namespace Mantid::API;
+    using namespace Mantid::DataObjects;
+    using namespace Mantid::HistogramData;
+    using namespace Mantid::Kernel;
+    BinEdges edges{0.3, 0.6, 0.9, 1.2};
+    Counts counts{0., 0., 0.};
+    MatrixWorkspace_sptr ws00 =
+        create<Workspace2D>(1, Histogram(edges, counts));
+    const std::string wsName{"ws00"};
+    AnalysisDataService::Instance().addOrReplace(wsName, ws00);
+    auto effWS = idealEfficiencies(edges);
+    // Change a bin edge of one of the histograms.
+    auto &xs = effWS->mutableX(0);
+    xs[xs.size() / 2] *= 1.01;
+    PolarizationCorrectionWildes alg;
+    alg.setChild(true);
+    alg.setRethrows(true);
+    TS_ASSERT_THROWS_NOTHING(alg.initialize())
+    TS_ASSERT(alg.isInitialized())
+    TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("InputWorkspaces", wsName))
+    TS_ASSERT_THROWS_NOTHING(
+        alg.setPropertyValue("OutputWorkspace", m_outputWSName))
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("Efficiencies", effWS))
+    TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("Flippers", "0"))
+    TS_ASSERT_THROWS(alg.execute(), std::runtime_error)
+    TS_ASSERT(!alg.isExecuted())
+  }
+
+  void test_FailureWhenNumberOfHistogramsInInputWorkspacesMismatch() {
+    using namespace Mantid::API;
+    using namespace Mantid::DataObjects;
+    using namespace Mantid::HistogramData;
+    using namespace Mantid::Kernel;
+    constexpr size_t nHist{2};
+    BinEdges edges{0.3, 0.6, 0.9, 1.2};
+    Counts counts{0., 0., 0.};
+    MatrixWorkspace_sptr ws00 =
+        create<Workspace2D>(nHist, Histogram(edges, counts));
+    MatrixWorkspace_sptr ws01 = ws00->clone();
+    MatrixWorkspace_sptr ws10 =
+        create<Workspace2D>(nHist + 1, Histogram(edges, counts));
+    MatrixWorkspace_sptr ws11 = ws00->clone();
+    const std::vector<std::string> wsNames{{"ws00", "ws01", "ws10", "ws11"}};
+    const std::array<MatrixWorkspace_sptr, 4> wsList{{ws00, ws01, ws10, ws11}};
+    for (size_t i = 0; i != 4; ++i) {
+      AnalysisDataService::Instance().addOrReplace(wsNames[i], wsList[i]);
+    }
+    auto effWS = idealEfficiencies(edges);
+    PolarizationCorrectionWildes alg;
+    alg.setChild(true);
+    alg.setRethrows(true);
+    TS_ASSERT_THROWS_NOTHING(alg.initialize())
+    TS_ASSERT(alg.isInitialized())
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("InputWorkspaces", wsNames))
+    TS_ASSERT_THROWS_NOTHING(
+        alg.setPropertyValue("OutputWorkspace", m_outputWSName))
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("Efficiencies", effWS))
+    TS_ASSERT_THROWS(alg.execute(), std::runtime_error)
+    TS_ASSERT(!alg.isExecuted())
+  }
+
+  void test_FailureWhenAnInputWorkspaceIsMissing() {
+    using namespace Mantid::API;
+    using namespace Mantid::DataObjects;
+    using namespace Mantid::HistogramData;
+    using namespace Mantid::Kernel;
+    constexpr size_t nHist{2};
+    BinEdges edges{0.3, 0.6, 0.9, 1.2};
+    Counts counts{0., 0., 0.};
+    MatrixWorkspace_sptr ws00 =
+        create<Workspace2D>(nHist, Histogram(edges, counts));
+    MatrixWorkspace_sptr ws01 = ws00->clone();
+    MatrixWorkspace_sptr ws11 = ws00->clone();
+    AnalysisDataService::Instance().addOrReplace("ws00", ws00);
+    AnalysisDataService::Instance().addOrReplace("ws01", ws01);
+    AnalysisDataService::Instance().addOrReplace("ws11", ws11);
+    PolarizationCorrectionWildes alg;
+    alg.setChild(true);
+    alg.setRethrows(true);
+    TS_ASSERT_THROWS_NOTHING(alg.initialize())
+    TS_ASSERT(alg.isInitialized())
+    TS_ASSERT_THROWS(
+        alg.setPropertyValue("InputWorkspaces", "ws00, ws01, ws10, ws11"),
+        std::invalid_argument)
+  }
+
+private:
+  const std::string m_outputWSName{"output"};
+
+  Mantid::API::MatrixWorkspace_sptr
+  efficiencies(const Mantid::HistogramData::BinEdges &edges) {
+    using namespace Mantid::API;
+    using namespace Mantid::DataObjects;
+    using namespace Mantid::HistogramData;
+    using namespace Mantid::Kernel;
+    const auto nBins = edges.size() - 1;
+    constexpr size_t nHist{4};
+    Counts counts(nBins, 0.0);
+    MatrixWorkspace_sptr ws =
+        create<Workspace2D>(nHist, Histogram(edges, counts));
+    ws->mutableY(0) = 0.95;
+    ws->mutableE(0) = 0.01;
+    ws->mutableY(1) = 0.92;
+    ws->mutableE(1) = 0.02;
+    ws->mutableY(2) = 0.05;
+    ws->mutableE(2) = 0.015;
+    ws->mutableY(3) = 0.04;
+    ws->mutableE(3) = 0.03;
+    auto axis = make_unique<TextAxis>(4);
+    axis->setLabel(0, "F1");
+    axis->setLabel(1, "F2");
+    axis->setLabel(2, "P1");
+    axis->setLabel(3, "P2");
+    ws->replaceAxis(1, axis.release());
+    return ws;
+  }
+
+  Mantid::API::MatrixWorkspace_sptr
+  idealEfficiencies(const Mantid::HistogramData::BinEdges &edges) {
+    using namespace Mantid::API;
+    using namespace Mantid::DataObjects;
+    using namespace Mantid::HistogramData;
+    using namespace Mantid::Kernel;
+    const auto nBins = edges.size() - 1;
+    constexpr size_t nHist{4};
+    Counts counts(nBins, 0.0);
+    MatrixWorkspace_sptr ws =
+        create<Workspace2D>(nHist, Histogram(edges, counts));
+    ws->mutableY(0) = 1.;
+    ws->mutableY(1) = 1.;
+    auto axis = make_unique<TextAxis>(4);
+    axis->setLabel(0, "F1");
+    axis->setLabel(1, "F2");
+    axis->setLabel(2, "P1");
+    axis->setLabel(3, "P2");
+    ws->replaceAxis(1, axis.release());
+    return ws;
+  }
+
+  void idealThreeInputsTest(const std::string &missingFlipperConf) {
+    using namespace Mantid::API;
+    using namespace Mantid::DataObjects;
+    using namespace Mantid::HistogramData;
+    using namespace Mantid::Kernel;
+    constexpr size_t nBins{3};
+    constexpr size_t nHist{2};
+    BinEdges edges{0.3, 0.6, 0.9, 1.2};
+    const double yVal = 2.3;
+    Counts counts{yVal, 4.2 * yVal, yVal};
+    MatrixWorkspace_sptr ws00 =
+        create<Workspace2D>(nHist, Histogram(edges, counts));
+    MatrixWorkspace_sptr wsXX = ws00->clone();
+    MatrixWorkspace_sptr ws11 = ws00->clone();
+    const std::vector<std::string> wsNames{{"ws00", "wsXX", "ws11"}};
+    const std::array<MatrixWorkspace_sptr, 3> wsList{{ws00, wsXX, ws11}};
+    for (size_t i = 0; i != 3; ++i) {
+      for (size_t j = 0; j != nHist; ++j) {
+        wsList[i]->mutableY(j) *= static_cast<double>(i + 1);
+        wsList[i]->mutableE(j) *= static_cast<double>(i + 1);
+      }
+      AnalysisDataService::Instance().addOrReplace(wsNames[i], wsList[i]);
+    }
+    auto effWS = idealEfficiencies(edges);
+    PolarizationCorrectionWildes alg;
+    alg.setChild(true);
+    alg.setRethrows(true);
+    TS_ASSERT_THROWS_NOTHING(alg.initialize())
+    TS_ASSERT(alg.isInitialized())
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("InputWorkspaces", wsNames))
+    TS_ASSERT_THROWS_NOTHING(
+        alg.setPropertyValue("OutputWorkspace", m_outputWSName))
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("Efficiencies", effWS))
+    const std::string presentFlipperConf =
+        missingFlipperConf == "01" ? "10" : "01";
+    const std::string flipperConf = "00, " + presentFlipperConf + ", 11";
+    TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("Flippers", flipperConf))
+    TS_ASSERT_THROWS_NOTHING(alg.execute())
+    TS_ASSERT(alg.isExecuted())
+    WorkspaceGroup_sptr outputWS = alg.getProperty("OutputWorkspace");
+    TS_ASSERT(outputWS)
+    TS_ASSERT_EQUALS(outputWS->getNumberOfEntries(), 4)
+    const std::array<std::string, 4> POL_DIRS{{"++", "+-", "-+", "--"}};
+    for (size_t i = 0; i != 4; ++i) {
+      const auto &dir = POL_DIRS[i];
+      const std::string wsName = m_outputWSName + std::string("_") + dir;
+      MatrixWorkspace_sptr ws = boost::dynamic_pointer_cast<MatrixWorkspace>(
+          outputWS->getItem(wsName));
+      TS_ASSERT(ws)
+      TS_ASSERT_EQUALS(ws->getNumberHistograms(), nHist)
+      for (size_t j = 0; j != nHist; ++j) {
+        const auto &xs = ws->x(j);
+        const auto &ys = ws->y(j);
+        const auto &es = ws->e(j);
+        TS_ASSERT_EQUALS(ys.size(), nBins)
+        for (size_t k = 0; k != nBins; ++k) {
+          const double y = counts[k];
+          const double expected = [y, &dir]() {
+            if (dir == "++") {
+              return y;
+            } else if (dir == "--") {
+              return 3. * y;
+            } else {
+              return 2. * y;
+            }
+          }();
+          const double expectedError = [y, &dir, &missingFlipperConf]() {
+            if (dir == "++") {
+              return std::sqrt(y);
+            } else if (dir == "--") {
+              return 3. * std::sqrt(y);
+            } else {
+              std::string conf = std::string(dir.front() == '+' ? "0" : "1") +
+                                 std::string(dir.back() == '+' ? "0" : "1");
+              if (conf != missingFlipperConf) {
+                return 2. * std::sqrt(y);
+              } else {
+                return 0.;
+              }
+            }
+          }();
+          TS_ASSERT_EQUALS(xs[k], edges[k])
+          TS_ASSERT_EQUALS(ys[k], expected)
+          TS_ASSERT_EQUALS(es[k], expectedError)
+        }
+      }
+    }
+  }
+
+  void threeInputsTest(const std::string &missingFlipperConf) {
+    using namespace Mantid::API;
+    using namespace Mantid::DataObjects;
+    using namespace Mantid::HistogramData;
+    using namespace Mantid::Kernel;
+    constexpr size_t nHist{2};
+    BinEdges edges{0.3, 0.6, 0.9, 1.2};
+    const double yVal = 2.3;
+    Counts counts{yVal, yVal, yVal};
+    MatrixWorkspace_sptr ws00 =
+        create<Workspace2D>(nHist, Histogram(edges, counts));
+    MatrixWorkspace_sptr ws01 =
+        missingFlipperConf == "01" ? nullptr : ws00->clone();
+    MatrixWorkspace_sptr ws10 =
+        missingFlipperConf == "10" ? nullptr : ws00->clone();
+    MatrixWorkspace_sptr ws11 = ws00->clone();
+    const std::vector<std::string> wsNames{{"ws00", "wsXX", "ws11"}};
+    const std::array<MatrixWorkspace_sptr, 3> wsList{
+        {ws00, ws01 != nullptr ? ws01 : ws10, ws11}};
+    for (size_t i = 0; i != 3; ++i) {
+      for (size_t j = 0; j != nHist; ++j) {
+        wsList[i]->mutableY(j) *= static_cast<double>(i + 1);
+        wsList[i]->mutableE(j) *= static_cast<double>(i + 1);
+      }
+      AnalysisDataService::Instance().addOrReplace(wsNames[i], wsList[i]);
+    }
+    auto effWS = efficiencies(edges);
+    PolarizationCorrectionWildes alg;
+    alg.setChild(true);
+    alg.setRethrows(true);
+    TS_ASSERT_THROWS_NOTHING(alg.initialize())
+    TS_ASSERT(alg.isInitialized())
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("InputWorkspaces", wsNames))
+    TS_ASSERT_THROWS_NOTHING(
+        alg.setPropertyValue("OutputWorkspace", m_outputWSName))
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("Efficiencies", effWS))
+    const std::string presentFlipperConf =
+        missingFlipperConf == "01" ? "10" : "01";
+    const std::string flipperConf = "00, " + presentFlipperConf + ", 11";
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("Flippers", flipperConf))
+    TS_ASSERT_THROWS_NOTHING(alg.execute())
+    TS_ASSERT(alg.isExecuted())
+    WorkspaceGroup_sptr outputWS = alg.getProperty("OutputWorkspace");
+    TS_ASSERT(outputWS)
+    TS_ASSERT_EQUALS(outputWS->getNumberOfEntries(), 4)
+    solveMissingIntensity(ws00, ws01, ws10, ws11, effWS);
+    fullFourInputsResultsCheck(outputWS, ws00, ws01, ws10, ws11, effWS);
+  }
+
+  void fullFourInputsResultsCheck(Mantid::API::WorkspaceGroup_sptr &outputWS,
+                                  Mantid::API::MatrixWorkspace_sptr &ws00,
+                                  Mantid::API::MatrixWorkspace_sptr &ws01,
+                                  Mantid::API::MatrixWorkspace_sptr &ws10,
+                                  Mantid::API::MatrixWorkspace_sptr &ws11,
+                                  Mantid::API::MatrixWorkspace_sptr &effWS) {
+    using namespace Mantid::API;
+    const auto nHist = ws00->getNumberHistograms();
+    const auto nBins = ws00->y(0).size();
+    const auto edges = ws00->binEdges(0);
+    const double F1 = effWS->y(0).front();
+    const double F1e = effWS->e(0).front();
+    const double F2 = effWS->y(1).front();
+    const double F2e = effWS->e(1).front();
+    const double P1 = effWS->y(2).front();
+    const double P1e = effWS->e(2).front();
+    const double P2 = effWS->y(3).front();
+    const double P2e = effWS->e(3).front();
+    const Eigen::Vector4d y{ws00->y(0).front(), ws01->y(0).front(),
+                            ws10->y(0).front(), ws11->y(0).front()};
+    const auto expected = correction(y, F1, F2, P1, P2);
+    const Eigen::Vector4d e{ws00->e(0).front(), ws01->e(0).front(),
+                            ws10->e(0).front(), ws11->e(0).front()};
+    const auto expectedError = error(y, e, F1, F1e, F2, F2e, P1, P1e, P2, P2e);
+    MatrixWorkspace_sptr ppWS = boost::dynamic_pointer_cast<MatrixWorkspace>(
+        outputWS->getItem(m_outputWSName + std::string("_++")));
+    MatrixWorkspace_sptr pmWS = boost::dynamic_pointer_cast<MatrixWorkspace>(
+        outputWS->getItem(m_outputWSName + std::string("_+-")));
+    MatrixWorkspace_sptr mpWS = boost::dynamic_pointer_cast<MatrixWorkspace>(
+        outputWS->getItem(m_outputWSName + std::string("_-+")));
+    MatrixWorkspace_sptr mmWS = boost::dynamic_pointer_cast<MatrixWorkspace>(
+        outputWS->getItem(m_outputWSName + std::string("_--")));
+    TS_ASSERT(ppWS)
+    TS_ASSERT(pmWS)
+    TS_ASSERT(mpWS)
+    TS_ASSERT(mmWS)
+    TS_ASSERT_EQUALS(ppWS->getNumberHistograms(), nHist)
+    TS_ASSERT_EQUALS(pmWS->getNumberHistograms(), nHist)
+    TS_ASSERT_EQUALS(mpWS->getNumberHistograms(), nHist)
+    TS_ASSERT_EQUALS(mmWS->getNumberHistograms(), nHist)
+    for (size_t j = 0; j != nHist; ++j) {
+      const auto &ppX = ppWS->x(j);
+      const auto &ppY = ppWS->y(j);
+      const auto &ppE = ppWS->e(j);
+      const auto &pmX = pmWS->x(j);
+      const auto &pmY = pmWS->y(j);
+      const auto &pmE = pmWS->e(j);
+      const auto &mpX = mpWS->x(j);
+      const auto &mpY = mpWS->y(j);
+      const auto &mpE = mpWS->e(j);
+      const auto &mmX = mmWS->x(j);
+      const auto &mmY = mmWS->y(j);
+      const auto &mmE = mmWS->e(j);
+      TS_ASSERT_EQUALS(ppY.size(), nBins)
+      TS_ASSERT_EQUALS(pmY.size(), nBins)
+      TS_ASSERT_EQUALS(mpY.size(), nBins)
+      TS_ASSERT_EQUALS(mmY.size(), nBins)
+      for (size_t k = 0; k != nBins; ++k) {
+        TS_ASSERT_EQUALS(ppX[k], edges[k])
+        TS_ASSERT_EQUALS(pmX[k], edges[k])
+        TS_ASSERT_EQUALS(mpX[k], edges[k])
+        TS_ASSERT_EQUALS(mmX[k], edges[k])
+        TS_ASSERT_DELTA(ppY[k], expected[0], 1e-12)
+        TS_ASSERT_DELTA(pmY[k], expected[1], 1e-12)
+        TS_ASSERT_DELTA(mpY[k], expected[2], 1e-12)
+        TS_ASSERT_DELTA(mmY[k], expected[3], 1e-12)
+        TS_ASSERT_DELTA(ppE[k], expectedError[0], 1e-12)
+        TS_ASSERT_DELTA(pmE[k], expectedError[1], 1e-12)
+        TS_ASSERT_DELTA(mpE[k], expectedError[2], 1e-12)
+        TS_ASSERT_DELTA(mmE[k], expectedError[3], 1e-12)
+      }
+    }
+  }
+  Eigen::Matrix4d invertedF1(const double f1) {
+    Eigen::Matrix4d m;
+    m << f1, 0., 0., 0., 0., f1, 0., 0., f1 - 1., 0., 1., 0., 0., f1 - 1., 0.,
+        1.;
+    m *= 1. / f1;
+    return m;
+  }
+
+  Eigen::Matrix4d invertedF1Derivative(const double f1) {
+    Eigen::Matrix4d m;
+    m << 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., -1., 0., 0., 1., 0., -1.;
+    m *= 1. / (f1 * f1);
+    return m;
+  }
+
+  Eigen::Matrix4d invertedF2(const double f2) {
+    Eigen::Matrix4d m;
+    m << f2, 0., 0., 0., f2 - 1., 1., 0., 0., 0., 0., f2, 0., 0., 0., f2 - 1.,
+        1.;
+    m *= 1. / f2;
+    return m;
+  }
+
+  Eigen::Matrix4d invertedF2Derivative(const double f2) {
+    Eigen::Matrix4d m;
+    m << 0., 0., 0., 0., 1., -1., 0., 0., 0., 0., 0., 0., 0., 0., 1., -1.;
+    m *= 1. / (f2 * f2);
+    return m;
+  }
+
+  Eigen::Matrix4d invertedP1(const double p1) {
+    Eigen::Matrix4d m;
+    m << p1 - 1., 0., p1, 0., 0., p1 - 1., 0., p1, p1, 0., p1 - 1., 0., 0., p1,
+        0., p1 - 1.;
+    m *= 1. / (2. * p1 - 1.);
+    return m;
+  }
+
+  Eigen::Matrix4d invertedP1Derivative(const double p1) {
+    Eigen::Matrix4d m;
+    m << 1., 0., -1., 0., 0., 1., 0., -1., -1., 0., 1., 0., 0., -1., 0., 1.;
+    m *= 1. / (2. * p1 - 1.) / (2. * p1 - 1.);
+    return m;
+  }
+
+  Eigen::Matrix4d invertedP2(const double p2) {
+    Eigen::Matrix4d m;
+    m << p2 - 1., p2, 0., 0., p2, p2 - 1., 0., 0., 0., 0., p2 - 1., p2, 0., 0.,
+        p2, p2 - 1.;
+    m *= 1. / (2. * p2 - 1.);
+    return m;
+  }
+
+  Eigen::Matrix4d invertedP2Derivative(const double p2) {
+    Eigen::Matrix4d m;
+    m << 1., -1., 0., 0., -1., 1., 0., 0., 0., 0., 1., -1., 0., 0., -1., 1.;
+    m *= 1. / (2. * p2 - 1.) / (2. * p2 - 1.);
+    return m;
+  }
+
+  Eigen::Vector4d correction(const Eigen::Vector4d &y, const double f1,
+                             const double f2, const double p1,
+                             const double p2) {
+    const Eigen::Matrix4d F1 = invertedF1(f1);
+    const Eigen::Matrix4d F2 = invertedF2(f2);
+    const Eigen::Matrix4d P1 = invertedP1(p1);
+    const Eigen::Matrix4d P2 = invertedP2(p2);
+    const Eigen::Matrix4d inverted = (P2 * P1 * F2 * F1).matrix();
+    return (inverted * y).matrix();
+  }
+
+  Eigen::Vector4d error(const Eigen::Vector4d &y, const Eigen::Vector4d &e,
+                        const double f1, const double f1e, const double f2,
+                        const double f2e, const double p1, const double p1e,
+                        const double p2, const double p2e) {
+    const Eigen::Matrix4d F1 = invertedF1(f1);
+    const Eigen::Matrix4d dF1 = f1e * invertedF1Derivative(f1);
+    const Eigen::Matrix4d F2 = invertedF2(f2);
+    const Eigen::Matrix4d dF2 = f2e * invertedF2Derivative(f2);
+    const Eigen::Matrix4d P1 = invertedP1(p1);
+    const Eigen::Matrix4d dP1 = p1e * invertedP1Derivative(p1);
+    const Eigen::Matrix4d P2 = invertedP2(p2);
+    const Eigen::Matrix4d dP2 = p2e * invertedP2Derivative(p2);
+    const auto p2Error = (dP2 * P1 * F2 * F1 * y).array();
+    const auto p1Error = (P2 * dP1 * F2 * F1 * y).array();
+    const auto f2Error = (P2 * P1 * dF2 * F1 * y).array();
+    const auto f1Error = (P2 * P1 * F2 * dF1 * y).array();
+    const auto inverted = (P2 * P1 * F2 * F1).array();
+    const auto yError = ((inverted * inverted).matrix() *
+                         (e.array() * e.array()).matrix()).array();
+    return (p2Error * p2Error + p1Error * p1Error + f2Error * f2Error +
+            f1Error * f1Error + yError)
+        .sqrt()
+        .matrix();
+  }
+
+  Eigen::Vector2d correctionWithoutAnalyzer(const Eigen::Vector2d &y,
+                                            const double f1, const double p1) {
+    Eigen::Matrix2d F1;
+    F1 << f1, 0., f1 - 1., 1.;
+    F1 *= 1. / f1;
+    Eigen::Matrix2d P1;
+    P1 << p1 - 1., p1, p1, p1 - 1.;
+    P1 *= 1. / (2. * p1 - 1.);
+    const Eigen::Matrix2d inverted = (P1 * F1).matrix();
+    return static_cast<Eigen::Vector2d>(inverted * y);
+  }
+
+  Eigen::Vector2d errorWithoutAnalyzer(const Eigen::Vector2d &y,
+                                       const Eigen::Vector2d &e,
+                                       const double f1, const double f1e,
+                                       const double p1, const double p1e) {
+    Eigen::Matrix2d F1;
+    F1 << f1, 0, f1 - 1., 1.;
+    F1 *= 1. / f1;
+    Eigen::Matrix2d dF1;
+    dF1 << 0., 0., 1., -1.;
+    dF1 *= f1e / (f1 * f1);
+    Eigen::Matrix2d P1;
+    P1 << p1 - 1., p1, p1, p1 - 1.;
+    P1 *= 1. / (2. * p1 - 1.);
+    Eigen::Matrix2d dP1;
+    dP1 << 1., -1., -1., 1.;
+    dP1 *= p1e / ((2. * p1 - 1.) * (2. * p1 - 1.));
+    const auto p1Error = (dP1 * F1 * y).array();
+    const auto f1Error = (P1 * dF1 * y).array();
+    const auto inverted = (P1 * F1).array();
+    const auto yError = ((inverted * inverted).matrix() *
+                         (e.array() * e.array()).matrix()).array();
+    return (p1Error * p1Error + f1Error * f1Error + yError).sqrt().matrix();
+  }
+
+  void solveMissingIntensity(const Mantid::API::MatrixWorkspace_sptr &ppWS,
+                             Mantid::API::MatrixWorkspace_sptr &pmWS,
+                             Mantid::API::MatrixWorkspace_sptr &mpWS,
+                             const Mantid::API::MatrixWorkspace_sptr &mmWS,
+                             const Mantid::API::MatrixWorkspace_sptr &effWS) {
+    const auto &F1 = effWS->y(0);
+    const auto &F2 = effWS->y(1);
+    const auto &P1 = effWS->y(2);
+    const auto &P2 = effWS->y(3);
+    if (!pmWS) {
+      pmWS = mpWS->clone();
+      for (size_t wsIndex = 0; wsIndex != pmWS->getNumberHistograms();
+           ++wsIndex) {
+        const auto &ppY = ppWS->y(wsIndex);
+        auto &pmY = pmWS->mutableY(wsIndex);
+        auto &pmE = pmWS->mutableE(wsIndex);
+        const auto &mpY = mpWS->y(wsIndex);
+        const auto &mmY = mmWS->y(wsIndex);
+        for (size_t binIndex = 0; binIndex != mpY.size(); ++binIndex) {
+          pmY[binIndex] =
+              -(2 * ppY[binIndex] * F2[binIndex] * P2[binIndex] -
+                P2[binIndex] * mmY[binIndex] -
+                2 * mpY[binIndex] * F2[binIndex] * P2[binIndex] +
+                mpY[binIndex] * P2[binIndex] - ppY[binIndex] * P2[binIndex] +
+                P1[binIndex] * mmY[binIndex] -
+                2 * ppY[binIndex] * F1[binIndex] * P1[binIndex] +
+                ppY[binIndex] * P1[binIndex] - P1[binIndex] * mpY[binIndex] +
+                ppY[binIndex] * F1[binIndex] + mpY[binIndex] * F2[binIndex] -
+                ppY[binIndex] * F2[binIndex]) /
+              (P2[binIndex] - P1[binIndex] + 2 * F1[binIndex] * P1[binIndex] -
+               F1[binIndex]);
+          // Error propagation is not implemented in the algorithm.
+          pmE[binIndex] = 0.;
+        }
+      }
+    } else {
+      mpWS = pmWS->clone();
+      for (size_t wsIndex = 0; wsIndex != mpWS->getNumberHistograms();
+           ++wsIndex) {
+        const auto &ppY = ppWS->y(wsIndex);
+        const auto &pmY = pmWS->y(wsIndex);
+        auto &mpY = mpWS->mutableY(wsIndex);
+        auto &mpE = mpWS->mutableE(wsIndex);
+        const auto &mmY = mmWS->y(wsIndex);
+        for (size_t binIndex = 0; binIndex != mpY.size(); ++binIndex) {
+          mpY[binIndex] =
+              (-ppY[binIndex] * P2[binIndex] + P2[binIndex] * pmY[binIndex] -
+               P2[binIndex] * mmY[binIndex] +
+               2 * ppY[binIndex] * F2[binIndex] * P2[binIndex] -
+               pmY[binIndex] * P1[binIndex] + P1[binIndex] * mmY[binIndex] +
+               ppY[binIndex] * P1[binIndex] -
+               2 * ppY[binIndex] * F1[binIndex] * P1[binIndex] +
+               2 * pmY[binIndex] * F1[binIndex] * P1[binIndex] +
+               ppY[binIndex] * F1[binIndex] - ppY[binIndex] * F2[binIndex] -
+               pmY[binIndex] * F1[binIndex]) /
+              (-P2[binIndex] + 2 * F2[binIndex] * P2[binIndex] + P1[binIndex] -
+               F2[binIndex]);
+          // Error propagation is not implemented in the algorithm.
+          mpE[binIndex] = 0.;
+        }
+      }
+    }
+  }
+
+  void solveMissingIntensities(const Mantid::API::MatrixWorkspace_sptr &ppWS,
+                               Mantid::API::MatrixWorkspace_sptr &pmWS,
+                               Mantid::API::MatrixWorkspace_sptr &mpWS,
+                               const Mantid::API::MatrixWorkspace_sptr &mmWS,
+                               const Mantid::API::MatrixWorkspace_sptr &effWS) {
+    const auto &F1 = effWS->y(0);
+    const auto &F1E = effWS->e(0);
+    const auto &F2 = effWS->y(1);
+    const auto &F2E = effWS->e(1);
+    const auto &P1 = effWS->y(2);
+    const auto &P1E = effWS->e(2);
+    const auto &P2 = effWS->y(3);
+    const auto &P2E = effWS->e(3);
+    pmWS = ppWS->clone();
+    mpWS = ppWS->clone();
+    for (size_t wsIndex = 0; wsIndex != ppWS->getNumberHistograms();
+         ++wsIndex) {
+      const auto &ppY = ppWS->y(wsIndex);
+      const auto &ppE = ppWS->e(wsIndex);
+      auto &pmY = pmWS->mutableY(wsIndex);
+      auto &pmE = pmWS->mutableE(wsIndex);
+      auto &mpY = mpWS->mutableY(wsIndex);
+      auto &mpE = mpWS->mutableE(wsIndex);
+      const auto &mmY = mmWS->y(wsIndex);
+      const auto &mmE = mmWS->e(wsIndex);
+      for (size_t binIndex = 0; binIndex != mpY.size(); ++binIndex) {
+        const double P12 = P1[binIndex] * P1[binIndex];
+        const double P13 = P1[binIndex] * P12;
+        const double P14 = P1[binIndex] * P13;
+        const double P22 = P2[binIndex] * P2[binIndex];
+        const double P23 = P2[binIndex] * P22;
+        const double F12 = F1[binIndex] * F1[binIndex];
+        {
+          mpY[binIndex] =
+              -(-mmY[binIndex] * P22 * F1[binIndex] +
+                2 * F1[binIndex] * P1[binIndex] * mmY[binIndex] * P22 -
+                2 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P2[binIndex] -
+                8 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P12 *
+                    P2[binIndex] +
+                2 * ppY[binIndex] * F2[binIndex] * P12 * P2[binIndex] +
+                8 * ppY[binIndex] * F12 * F2[binIndex] * P12 * P2[binIndex] +
+                2 * ppY[binIndex] * F12 * F2[binIndex] * P2[binIndex] -
+                8 * ppY[binIndex] * F12 * F2[binIndex] * P2[binIndex] *
+                    P1[binIndex] -
+                2 * F1[binIndex] * P1[binIndex] * mmY[binIndex] * P2[binIndex] -
+                2 * ppY[binIndex] * F2[binIndex] * P1[binIndex] * P2[binIndex] +
+                8 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P1[binIndex] *
+                    P2[binIndex] +
+                mmY[binIndex] * P2[binIndex] * F1[binIndex] +
+                ppY[binIndex] * F1[binIndex] * F2[binIndex] -
+                ppY[binIndex] * F2[binIndex] * P12 +
+                4 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P12 +
+                4 * ppY[binIndex] * F12 * F2[binIndex] * P1[binIndex] -
+                4 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P1[binIndex] +
+                ppY[binIndex] * F2[binIndex] * P1[binIndex] -
+                4 * ppY[binIndex] * F12 * F2[binIndex] * P12 -
+                ppY[binIndex] * F12 * F2[binIndex]) /
+              (-F1[binIndex] * F2[binIndex] +
+               2 * F2[binIndex] * P1[binIndex] * P2[binIndex] +
+               3 * F1[binIndex] * F2[binIndex] * P1[binIndex] -
+               2 * F1[binIndex] * F2[binIndex] * P22 -
+               2 * P22 * F1[binIndex] * P1[binIndex] +
+               2 * P2[binIndex] * F1[binIndex] * P1[binIndex] +
+               3 * F1[binIndex] * F2[binIndex] * P2[binIndex] -
+               P2[binIndex] * F1[binIndex] + P22 * F1[binIndex] +
+               F2[binIndex] * P12 - 2 * F2[binIndex] * P12 * P2[binIndex] -
+               2 * F1[binIndex] * F2[binIndex] * P12 -
+               F2[binIndex] * P1[binIndex] -
+               8 * F1[binIndex] * F2[binIndex] * P1[binIndex] * P2[binIndex] +
+               4 * F1[binIndex] * F2[binIndex] * P1[binIndex] * P22 +
+               4 * F1[binIndex] * F2[binIndex] * P12 * P2[binIndex]);
+          const double dI00 =
+              -F2[binIndex] *
+              (-2 * P2[binIndex] * F1[binIndex] + 2 * P12 * P2[binIndex] +
+               8 * P2[binIndex] * F1[binIndex] * P1[binIndex] -
+               2 * P1[binIndex] * P2[binIndex] + 2 * P2[binIndex] * F12 -
+               8 * P2[binIndex] * F12 * P1[binIndex] -
+               8 * P2[binIndex] * F1[binIndex] * P12 +
+               8 * P2[binIndex] * F12 * P12 - 4 * F1[binIndex] * P1[binIndex] -
+               F12 + 4 * F12 * P1[binIndex] + P1[binIndex] + F1[binIndex] -
+               P12 + 4 * F1[binIndex] * P12 - 4 * F12 * P12) /
+              (-P2[binIndex] * F1[binIndex] +
+               3 * F1[binIndex] * F2[binIndex] * P2[binIndex] -
+               2 * P22 * F1[binIndex] * P1[binIndex] -
+               2 * F1[binIndex] * F2[binIndex] * P22 -
+               2 * F2[binIndex] * P12 * P2[binIndex] -
+               2 * F1[binIndex] * F2[binIndex] * P12 +
+               2 * P2[binIndex] * F1[binIndex] * P1[binIndex] +
+               P22 * F1[binIndex] + F2[binIndex] * P12 +
+               3 * F1[binIndex] * F2[binIndex] * P1[binIndex] +
+               2 * F2[binIndex] * P1[binIndex] * P2[binIndex] -
+               F1[binIndex] * F2[binIndex] - F2[binIndex] * P1[binIndex] -
+               8 * F1[binIndex] * F2[binIndex] * P1[binIndex] * P2[binIndex] +
+               4 * F1[binIndex] * F2[binIndex] * P1[binIndex] * P22 +
+               4 * F1[binIndex] * F2[binIndex] * P12 * P2[binIndex]);
+          const double dI11 =
+              -P2[binIndex] * F1[binIndex] *
+              (1 - 2 * P1[binIndex] - P2[binIndex] +
+               2 * P1[binIndex] * P2[binIndex]) /
+              (-P2[binIndex] * F1[binIndex] +
+               3 * F1[binIndex] * F2[binIndex] * P2[binIndex] -
+               2 * P22 * F1[binIndex] * P1[binIndex] -
+               2 * F1[binIndex] * F2[binIndex] * P22 -
+               2 * F2[binIndex] * P12 * P2[binIndex] -
+               2 * F1[binIndex] * F2[binIndex] * P12 +
+               2 * P2[binIndex] * F1[binIndex] * P1[binIndex] +
+               P22 * F1[binIndex] + F2[binIndex] * P12 +
+               3 * F1[binIndex] * F2[binIndex] * P1[binIndex] +
+               2 * F2[binIndex] * P1[binIndex] * P2[binIndex] -
+               F1[binIndex] * F2[binIndex] - F2[binIndex] * P1[binIndex] -
+               8 * F1[binIndex] * F2[binIndex] * P1[binIndex] * P2[binIndex] +
+               4 * F1[binIndex] * F2[binIndex] * P1[binIndex] * P22 +
+               4 * F1[binIndex] * F2[binIndex] * P12 * P2[binIndex]);
+          const double divisor1 =
+              (-P2[binIndex] * F1[binIndex] +
+               3 * F1[binIndex] * F2[binIndex] * P2[binIndex] -
+               2 * P22 * F1[binIndex] * P1[binIndex] -
+               2 * F1[binIndex] * F2[binIndex] * P22 -
+               2 * F2[binIndex] * P12 * P2[binIndex] -
+               2 * F1[binIndex] * F2[binIndex] * P12 +
+               2 * P2[binIndex] * F1[binIndex] * P1[binIndex] +
+               P22 * F1[binIndex] + F2[binIndex] * P12 +
+               3 * F1[binIndex] * F2[binIndex] * P1[binIndex] +
+               2 * F2[binIndex] * P1[binIndex] * P2[binIndex] -
+               F1[binIndex] * F2[binIndex] - F2[binIndex] * P1[binIndex] -
+               8 * F1[binIndex] * F2[binIndex] * P1[binIndex] * P2[binIndex] +
+               4 * F1[binIndex] * F2[binIndex] * P1[binIndex] * P22 +
+               4 * F1[binIndex] * F2[binIndex] * P12 * P2[binIndex]);
+          const double dF1 =
+              -F2[binIndex] *
+              (-P1[binIndex] * mmY[binIndex] * P2[binIndex] +
+               4 * ppY[binIndex] * F2[binIndex] * P1[binIndex] * P22 -
+               ppY[binIndex] * F2[binIndex] * P12 * P2[binIndex] -
+               10 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P12 -
+               8 * ppY[binIndex] * F2[binIndex] * P12 * P22 +
+               2 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P1[binIndex] -
+               ppY[binIndex] * F2[binIndex] * P1[binIndex] * P2[binIndex] -
+               32 * ppY[binIndex] * F12 * F2[binIndex] * P14 * P2[binIndex] +
+               32 * ppY[binIndex] * F2[binIndex] * P14 * P2[binIndex] *
+                   F1[binIndex] -
+               32 * ppY[binIndex] * F2[binIndex] * P14 * P22 * F1[binIndex] +
+               32 * ppY[binIndex] * F12 * F2[binIndex] * P14 * P22 +
+               32 * ppY[binIndex] * F12 * F2[binIndex] * P13 * P23 +
+               2 * ppY[binIndex] * F2[binIndex] * P14 +
+               4 * ppY[binIndex] * P13 * P23 - 4 * P13 * mmY[binIndex] * P23 -
+               8 * ppY[binIndex] * F2[binIndex] * P13 * P23 -
+               16 * ppY[binIndex] * P23 * F12 * P13 +
+               8 * ppY[binIndex] * F12 * F2[binIndex] * P14 -
+               8 * ppY[binIndex] * F2[binIndex] * P14 * P2[binIndex] +
+               8 * ppY[binIndex] * F2[binIndex] * P14 * P22 -
+               8 * ppY[binIndex] * F2[binIndex] * P14 * F1[binIndex] +
+               10 * ppY[binIndex] * F2[binIndex] * P13 * P2[binIndex] -
+               4 * ppY[binIndex] * F2[binIndex] * P13 * P22 +
+               16 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P13 -
+               4 * ppY[binIndex] * F2[binIndex] * P1[binIndex] * P23 +
+               12 * ppY[binIndex] * F2[binIndex] * P12 * P23 +
+               18 * ppY[binIndex] * P22 * F12 * P1[binIndex] -
+               20 * ppY[binIndex] * F12 * F2[binIndex] * P13 -
+               36 * ppY[binIndex] * P22 * F12 * P12 +
+               24 * ppY[binIndex] * P22 * F12 * P13 -
+               6 * ppY[binIndex] * P2[binIndex] * F12 * P1[binIndex] -
+               5 * ppY[binIndex] * F12 * F2[binIndex] * P2[binIndex] +
+               8 * ppY[binIndex] * F12 * F2[binIndex] * P22 -
+               8 * ppY[binIndex] * P2[binIndex] * F12 * P13 +
+               12 * ppY[binIndex] * P2[binIndex] * F12 * P12 +
+               18 * ppY[binIndex] * F12 * F2[binIndex] * P12 -
+               7 * ppY[binIndex] * F12 * F2[binIndex] * P1[binIndex] -
+               12 * ppY[binIndex] * P23 * F12 * P1[binIndex] +
+               24 * ppY[binIndex] * P23 * F12 * P12 -
+               4 * ppY[binIndex] * F12 * F2[binIndex] * P23 -
+               3 * ppY[binIndex] * P1[binIndex] * P22 +
+               ppY[binIndex] * F2[binIndex] * P12 -
+               3 * ppY[binIndex] * P12 * P2[binIndex] +
+               3 * P12 * mmY[binIndex] * P2[binIndex] -
+               9 * P12 * mmY[binIndex] * P22 + 9 * ppY[binIndex] * P12 * P22 +
+               ppY[binIndex] * P1[binIndex] * P2[binIndex] +
+               3 * P1[binIndex] * mmY[binIndex] * P22 -
+               8 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P1[binIndex] *
+                   P2[binIndex] +
+               8 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P1[binIndex] *
+                   P22 +
+               40 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P12 *
+                   P2[binIndex] -
+               40 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P12 * P22 -
+               64 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P13 *
+                   P2[binIndex] +
+               64 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P13 * P22 +
+               34 * ppY[binIndex] * F12 * F2[binIndex] * P2[binIndex] *
+                   P1[binIndex] -
+               52 * ppY[binIndex] * F12 * F2[binIndex] * P22 * P1[binIndex] -
+               84 * ppY[binIndex] * F12 * F2[binIndex] * P12 * P2[binIndex] +
+               120 * ppY[binIndex] * F12 * F2[binIndex] * P12 * P22 +
+               88 * ppY[binIndex] * F12 * F2[binIndex] * P13 * P2[binIndex] -
+               112 * ppY[binIndex] * F12 * F2[binIndex] * P13 * P22 +
+               24 * ppY[binIndex] * F12 * F2[binIndex] * P23 * P1[binIndex] -
+               48 * ppY[binIndex] * F12 * F2[binIndex] * P12 * P23 +
+               2 * ppY[binIndex] * P13 * P2[binIndex] -
+               6 * ppY[binIndex] * P13 * P22 -
+               3 * ppY[binIndex] * F2[binIndex] * P13 +
+               2 * ppY[binIndex] * P1[binIndex] * P23 -
+               6 * ppY[binIndex] * P12 * P23 +
+               ppY[binIndex] * P2[binIndex] * F12 -
+               3 * ppY[binIndex] * P22 * F12 +
+               ppY[binIndex] * F12 * F2[binIndex] +
+               2 * ppY[binIndex] * P23 * F12 -
+               2 * P13 * mmY[binIndex] * P2[binIndex] +
+               6 * P13 * mmY[binIndex] * P22 + 6 * P12 * mmY[binIndex] * P23 -
+               2 * P1[binIndex] * mmY[binIndex] * P23) /
+              (divisor1 * divisor1);
+          const double divisor2 =
+              (-P2[binIndex] * F1[binIndex] +
+               3 * F1[binIndex] * F2[binIndex] * P2[binIndex] -
+               2 * P22 * F1[binIndex] * P1[binIndex] -
+               2 * F1[binIndex] * F2[binIndex] * P22 -
+               2 * F2[binIndex] * P12 * P2[binIndex] -
+               2 * F1[binIndex] * F2[binIndex] * P12 +
+               2 * P2[binIndex] * F1[binIndex] * P1[binIndex] +
+               P22 * F1[binIndex] + F2[binIndex] * P12 +
+               3 * F1[binIndex] * F2[binIndex] * P1[binIndex] +
+               2 * F2[binIndex] * P1[binIndex] * P2[binIndex] -
+               F1[binIndex] * F2[binIndex] - F2[binIndex] * P1[binIndex] -
+               8 * F1[binIndex] * F2[binIndex] * P1[binIndex] * P2[binIndex] +
+               4 * F1[binIndex] * F2[binIndex] * P1[binIndex] * P22 +
+               4 * F1[binIndex] * F2[binIndex] * P12 * P2[binIndex]);
+          const double dF2 =
+              P2[binIndex] * F1[binIndex] *
+              (3 * P1[binIndex] * mmY[binIndex] * P2[binIndex] -
+               12 * ppY[binIndex] * P22 * F1[binIndex] * P1[binIndex] -
+               36 * ppY[binIndex] * P2[binIndex] * F1[binIndex] * P12 +
+               24 * ppY[binIndex] * P22 * F1[binIndex] * P12 +
+               18 * ppY[binIndex] * P2[binIndex] * F1[binIndex] * P1[binIndex] +
+               12 * ppY[binIndex] * F1[binIndex] * P12 +
+               24 * ppY[binIndex] * P2[binIndex] * F1[binIndex] * P13 -
+               16 * ppY[binIndex] * P22 * F1[binIndex] * P13 +
+               12 * ppY[binIndex] * P22 * F12 * P1[binIndex] -
+               24 * ppY[binIndex] * P22 * F12 * P12 +
+               16 * ppY[binIndex] * P22 * F12 * P13 -
+               18 * ppY[binIndex] * P2[binIndex] * F12 * P1[binIndex] -
+               24 * ppY[binIndex] * P2[binIndex] * F12 * P13 +
+               36 * ppY[binIndex] * P2[binIndex] * F12 * P12 -
+               19 * F1[binIndex] * P1[binIndex] * mmY[binIndex] * P2[binIndex] +
+               28 * F1[binIndex] * P12 * mmY[binIndex] * P2[binIndex] -
+               12 * F1[binIndex] * P13 * mmY[binIndex] * P2[binIndex] +
+               22 * F1[binIndex] * P1[binIndex] * mmY[binIndex] * P22 -
+               28 * F1[binIndex] * P12 * mmY[binIndex] * P22 +
+               8 * F1[binIndex] * P13 * mmY[binIndex] * P22 -
+               8 * F1[binIndex] * P1[binIndex] * mmY[binIndex] * P23 +
+               8 * F1[binIndex] * P12 * mmY[binIndex] * P23 -
+               ppY[binIndex] * F12 + 2 * ppY[binIndex] * P13 -
+               2 * P13 * mmY[binIndex] - mmY[binIndex] * F1[binIndex] +
+               2 * ppY[binIndex] * P1[binIndex] * P22 +
+               9 * ppY[binIndex] * P12 * P2[binIndex] -
+               9 * P12 * mmY[binIndex] * P2[binIndex] +
+               6 * P12 * mmY[binIndex] * P22 - 6 * ppY[binIndex] * P12 * P22 -
+               3 * ppY[binIndex] * P1[binIndex] * P2[binIndex] -
+               2 * P1[binIndex] * mmY[binIndex] * P22 -
+               6 * ppY[binIndex] * F1[binIndex] * P1[binIndex] +
+               2 * ppY[binIndex] * P22 * F1[binIndex] -
+               3 * ppY[binIndex] * P2[binIndex] * F1[binIndex] -
+               P1[binIndex] * mmY[binIndex] + ppY[binIndex] * P1[binIndex] -
+               3 * ppY[binIndex] * P12 + ppY[binIndex] * F1[binIndex] +
+               3 * P12 * mmY[binIndex] -
+               6 * ppY[binIndex] * P13 * P2[binIndex] +
+               4 * ppY[binIndex] * P13 * P22 +
+               3 * ppY[binIndex] * P2[binIndex] * F12 -
+               2 * ppY[binIndex] * P22 * F12 +
+               5 * F1[binIndex] * P1[binIndex] * mmY[binIndex] +
+               6 * ppY[binIndex] * F12 * P1[binIndex] -
+               8 * F1[binIndex] * P12 * mmY[binIndex] -
+               12 * F12 * P12 * ppY[binIndex] -
+               8 * ppY[binIndex] * F1[binIndex] * P13 +
+               6 * P13 * mmY[binIndex] * P2[binIndex] +
+               4 * F1[binIndex] * P13 * mmY[binIndex] +
+               8 * F12 * P13 * ppY[binIndex] - 4 * P13 * mmY[binIndex] * P22 -
+               5 * mmY[binIndex] * P22 * F1[binIndex] +
+               2 * mmY[binIndex] * P23 * F1[binIndex] +
+               4 * mmY[binIndex] * P2[binIndex] * F1[binIndex]) /
+              (divisor2 * divisor2);
+          const double divisor3 =
+              (-P2[binIndex] * F1[binIndex] +
+               3 * F1[binIndex] * F2[binIndex] * P2[binIndex] -
+               2 * P22 * F1[binIndex] * P1[binIndex] -
+               2 * F1[binIndex] * F2[binIndex] * P22 -
+               2 * F2[binIndex] * P12 * P2[binIndex] -
+               2 * F1[binIndex] * F2[binIndex] * P12 +
+               2 * P2[binIndex] * F1[binIndex] * P1[binIndex] +
+               P22 * F1[binIndex] + F2[binIndex] * P12 +
+               3 * F1[binIndex] * F2[binIndex] * P1[binIndex] +
+               2 * F2[binIndex] * P1[binIndex] * P2[binIndex] -
+               F1[binIndex] * F2[binIndex] - F2[binIndex] * P1[binIndex] -
+               8 * F1[binIndex] * F2[binIndex] * P1[binIndex] * P2[binIndex] +
+               4 * F1[binIndex] * F2[binIndex] * P1[binIndex] * P22 +
+               4 * F1[binIndex] * F2[binIndex] * P12 * P2[binIndex]);
+          const double dP1 =
+              -F1[binIndex] * F2[binIndex] *
+              (-2 * P1[binIndex] * mmY[binIndex] * P2[binIndex] -
+               2 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P2[binIndex] +
+               8 * ppY[binIndex] * F2[binIndex] * P1[binIndex] * P22 +
+               24 * ppY[binIndex] * P22 * F1[binIndex] * P1[binIndex] +
+               8 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P22 +
+               8 * ppY[binIndex] * P2[binIndex] * F1[binIndex] * P12 +
+               6 * ppY[binIndex] * F2[binIndex] * P12 * P2[binIndex] +
+               4 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P12 -
+               24 * ppY[binIndex] * P22 * F1[binIndex] * P12 -
+               12 * ppY[binIndex] * F2[binIndex] * P12 * P22 -
+               8 * ppY[binIndex] * P2[binIndex] * F1[binIndex] * P1[binIndex] -
+               2 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P1[binIndex] -
+               2 * ppY[binIndex] * F2[binIndex] * P1[binIndex] * P2[binIndex] +
+               ppY[binIndex] * F2[binIndex] * P2[binIndex] -
+               4 * ppY[binIndex] * F2[binIndex] * P22 -
+               8 * ppY[binIndex] * F2[binIndex] * P1[binIndex] * P23 -
+               16 * ppY[binIndex] * P23 * F1[binIndex] * P1[binIndex] -
+               8 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P23 +
+               16 * ppY[binIndex] * P23 * F1[binIndex] * P12 +
+               8 * ppY[binIndex] * F2[binIndex] * P12 * P23 -
+               24 * ppY[binIndex] * P22 * F12 * P1[binIndex] +
+               24 * ppY[binIndex] * P22 * F12 * P12 +
+               8 * ppY[binIndex] * P2[binIndex] * F12 * P1[binIndex] +
+               6 * ppY[binIndex] * F12 * F2[binIndex] * P2[binIndex] -
+               12 * ppY[binIndex] * F12 * F2[binIndex] * P22 -
+               8 * ppY[binIndex] * P2[binIndex] * F12 * P12 -
+               4 * ppY[binIndex] * F12 * F2[binIndex] * P12 +
+               4 * ppY[binIndex] * F12 * F2[binIndex] * P1[binIndex] +
+               16 * ppY[binIndex] * P23 * F12 * P1[binIndex] -
+               16 * ppY[binIndex] * P23 * F12 * P12 +
+               8 * ppY[binIndex] * F12 * F2[binIndex] * P23 +
+               4 * F1[binIndex] * P1[binIndex] * mmY[binIndex] * P2[binIndex] -
+               4 * F1[binIndex] * P12 * mmY[binIndex] * P2[binIndex] -
+               12 * F1[binIndex] * P1[binIndex] * mmY[binIndex] * P22 +
+               12 * F1[binIndex] * P12 * mmY[binIndex] * P22 +
+               8 * F1[binIndex] * P1[binIndex] * mmY[binIndex] * P23 -
+               8 * F1[binIndex] * P12 * mmY[binIndex] * P23 +
+               2 * mmY[binIndex] * P23 - 2 * ppY[binIndex] * P23 +
+               4 * ppY[binIndex] * F2[binIndex] * P23 -
+               6 * ppY[binIndex] * P1[binIndex] * P22 -
+               ppY[binIndex] * F2[binIndex] * P12 -
+               2 * ppY[binIndex] * P12 * P2[binIndex] +
+               2 * P12 * mmY[binIndex] * P2[binIndex] -
+               6 * P12 * mmY[binIndex] * P22 + 6 * ppY[binIndex] * P12 * P22 +
+               2 * ppY[binIndex] * P1[binIndex] * P2[binIndex] -
+               ppY[binIndex] * P2[binIndex] +
+               6 * P1[binIndex] * mmY[binIndex] * P22 -
+               6 * ppY[binIndex] * P22 * F1[binIndex] +
+               2 * ppY[binIndex] * P2[binIndex] * F1[binIndex] +
+               3 * ppY[binIndex] * P22 +
+               16 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P1[binIndex] *
+                   P2[binIndex] -
+               40 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P1[binIndex] *
+                   P22 -
+               24 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P12 *
+                   P2[binIndex] +
+               48 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P12 * P22 +
+               mmY[binIndex] * P2[binIndex] - 3 * mmY[binIndex] * P22 +
+               32 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P1[binIndex] *
+                   P23 -
+               32 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P12 * P23 -
+               24 * ppY[binIndex] * F12 * F2[binIndex] * P2[binIndex] *
+                   P1[binIndex] +
+               48 * ppY[binIndex] * F12 * F2[binIndex] * P22 * P1[binIndex] +
+               24 * ppY[binIndex] * F12 * F2[binIndex] * P12 * P2[binIndex] -
+               48 * ppY[binIndex] * F12 * F2[binIndex] * P12 * P22 -
+               32 * ppY[binIndex] * F12 * F2[binIndex] * P23 * P1[binIndex] +
+               32 * ppY[binIndex] * F12 * F2[binIndex] * P12 * P23 +
+               4 * ppY[binIndex] * P1[binIndex] * P23 +
+               4 * ppY[binIndex] * P23 * F1[binIndex] -
+               4 * ppY[binIndex] * P12 * P23 -
+               2 * ppY[binIndex] * P2[binIndex] * F12 +
+               6 * ppY[binIndex] * P22 * F12 -
+               ppY[binIndex] * F12 * F2[binIndex] -
+               4 * ppY[binIndex] * P23 * F12 + 4 * P12 * mmY[binIndex] * P23 -
+               4 * P1[binIndex] * mmY[binIndex] * P23 +
+               3 * mmY[binIndex] * P22 * F1[binIndex] -
+               2 * mmY[binIndex] * P23 * F1[binIndex] -
+               mmY[binIndex] * P2[binIndex] * F1[binIndex]) /
+              (divisor3 * divisor3);
+          const double divisor4 =
+              (-P2[binIndex] * F1[binIndex] +
+               3 * F1[binIndex] * F2[binIndex] * P2[binIndex] -
+               2 * P22 * F1[binIndex] * P1[binIndex] -
+               2 * F1[binIndex] * F2[binIndex] * P22 -
+               2 * F2[binIndex] * P12 * P2[binIndex] -
+               2 * F1[binIndex] * F2[binIndex] * P12 +
+               2 * P2[binIndex] * F1[binIndex] * P1[binIndex] +
+               P22 * F1[binIndex] + F2[binIndex] * P12 +
+               3 * F1[binIndex] * F2[binIndex] * P1[binIndex] +
+               2 * F2[binIndex] * P1[binIndex] * P2[binIndex] -
+               F1[binIndex] * F2[binIndex] - F2[binIndex] * P1[binIndex] -
+               8 * F1[binIndex] * F2[binIndex] * P1[binIndex] * P2[binIndex] +
+               4 * F1[binIndex] * F2[binIndex] * P1[binIndex] * P22 +
+               4 * F1[binIndex] * F2[binIndex] * P12 * P2[binIndex]);
+          const double dP2 =
+              F1[binIndex] * F2[binIndex] *
+              (-2 * P1[binIndex] * mmY[binIndex] * P2[binIndex] -
+               4 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P2[binIndex] +
+               4 * ppY[binIndex] * F2[binIndex] * P1[binIndex] * P22 +
+               12 * ppY[binIndex] * P22 * F1[binIndex] * P1[binIndex] +
+               4 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P22 +
+               24 * ppY[binIndex] * P2[binIndex] * F1[binIndex] * P12 +
+               12 * ppY[binIndex] * F2[binIndex] * P12 * P2[binIndex] +
+               12 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P12 -
+               24 * ppY[binIndex] * P22 * F1[binIndex] * P12 -
+               12 * ppY[binIndex] * F2[binIndex] * P12 * P22 -
+               12 * ppY[binIndex] * P2[binIndex] * F1[binIndex] * P1[binIndex] -
+               6 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P1[binIndex] -
+               4 * ppY[binIndex] * F2[binIndex] * P1[binIndex] * P2[binIndex] -
+               12 * ppY[binIndex] * F1[binIndex] * P12 -
+               16 * ppY[binIndex] * P2[binIndex] * F1[binIndex] * P13 +
+               16 * ppY[binIndex] * P22 * F1[binIndex] * P13 -
+               8 * ppY[binIndex] * F2[binIndex] * P13 * P2[binIndex] +
+               8 * ppY[binIndex] * F2[binIndex] * P13 * P22 -
+               8 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P13 -
+               12 * ppY[binIndex] * P22 * F12 * P1[binIndex] +
+               8 * ppY[binIndex] * F12 * F2[binIndex] * P13 +
+               24 * ppY[binIndex] * P22 * F12 * P12 -
+               16 * ppY[binIndex] * P22 * F12 * P13 +
+               12 * ppY[binIndex] * P2[binIndex] * F12 * P1[binIndex] +
+               4 * ppY[binIndex] * F12 * F2[binIndex] * P2[binIndex] -
+               4 * ppY[binIndex] * F12 * F2[binIndex] * P22 +
+               16 * ppY[binIndex] * P2[binIndex] * F12 * P13 -
+               24 * ppY[binIndex] * P2[binIndex] * F12 * P12 -
+               12 * ppY[binIndex] * F12 * F2[binIndex] * P12 +
+               6 * ppY[binIndex] * F12 * F2[binIndex] * P1[binIndex] +
+               10 * F1[binIndex] * P1[binIndex] * mmY[binIndex] * P2[binIndex] -
+               16 * F1[binIndex] * P12 * mmY[binIndex] * P2[binIndex] +
+               8 * F1[binIndex] * P13 * mmY[binIndex] * P2[binIndex] -
+               6 * F1[binIndex] * P1[binIndex] * mmY[binIndex] * P22 +
+               12 * F1[binIndex] * P12 * mmY[binIndex] * P22 -
+               8 * F1[binIndex] * P13 * mmY[binIndex] * P22 +
+               ppY[binIndex] * F12 - 2 * ppY[binIndex] * P13 +
+               2 * P13 * mmY[binIndex] + mmY[binIndex] * F1[binIndex] -
+               2 * ppY[binIndex] * P1[binIndex] * P22 +
+               ppY[binIndex] * F2[binIndex] * P1[binIndex] -
+               3 * ppY[binIndex] * F2[binIndex] * P12 -
+               6 * ppY[binIndex] * P12 * P2[binIndex] +
+               6 * P12 * mmY[binIndex] * P2[binIndex] -
+               6 * P12 * mmY[binIndex] * P22 + 6 * ppY[binIndex] * P12 * P22 +
+               2 * ppY[binIndex] * P1[binIndex] * P2[binIndex] +
+               ppY[binIndex] * F1[binIndex] * F2[binIndex] +
+               2 * P1[binIndex] * mmY[binIndex] * P22 +
+               6 * ppY[binIndex] * F1[binIndex] * P1[binIndex] -
+               2 * ppY[binIndex] * P22 * F1[binIndex] +
+               2 * ppY[binIndex] * P2[binIndex] * F1[binIndex] +
+               24 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P1[binIndex] *
+                   P2[binIndex] -
+               24 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P1[binIndex] *
+                   P22 -
+               48 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P12 *
+                   P2[binIndex] +
+               48 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P12 * P22 +
+               P1[binIndex] * mmY[binIndex] - ppY[binIndex] * P1[binIndex] +
+               3 * ppY[binIndex] * P12 - ppY[binIndex] * F1[binIndex] -
+               3 * P12 * mmY[binIndex] +
+               32 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P13 *
+                   P2[binIndex] -
+               32 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P13 * P22 -
+               24 * ppY[binIndex] * F12 * F2[binIndex] * P2[binIndex] *
+                   P1[binIndex] +
+               24 * ppY[binIndex] * F12 * F2[binIndex] * P22 * P1[binIndex] +
+               48 * ppY[binIndex] * F12 * F2[binIndex] * P12 * P2[binIndex] -
+               48 * ppY[binIndex] * F12 * F2[binIndex] * P12 * P22 -
+               32 * ppY[binIndex] * F12 * F2[binIndex] * P13 * P2[binIndex] +
+               32 * ppY[binIndex] * F12 * F2[binIndex] * P13 * P22 +
+               4 * ppY[binIndex] * P13 * P2[binIndex] -
+               4 * ppY[binIndex] * P13 * P22 +
+               2 * ppY[binIndex] * F2[binIndex] * P13 -
+               2 * ppY[binIndex] * P2[binIndex] * F12 +
+               2 * ppY[binIndex] * P22 * F12 -
+               ppY[binIndex] * F12 * F2[binIndex] -
+               5 * F1[binIndex] * P1[binIndex] * mmY[binIndex] -
+               6 * ppY[binIndex] * F12 * P1[binIndex] +
+               8 * F1[binIndex] * P12 * mmY[binIndex] +
+               12 * F12 * P12 * ppY[binIndex] +
+               8 * ppY[binIndex] * F1[binIndex] * P13 -
+               4 * P13 * mmY[binIndex] * P2[binIndex] -
+               4 * F1[binIndex] * P13 * mmY[binIndex] -
+               8 * F12 * P13 * ppY[binIndex] + 4 * P13 * mmY[binIndex] * P22 +
+               mmY[binIndex] * P22 * F1[binIndex] -
+               2 * mmY[binIndex] * P2[binIndex] * F1[binIndex]) /
+              (divisor4 * divisor4);
+          const double e1 = dI00 * ppE[binIndex];
+          const double e2 = dI11 * mmE[binIndex];
+          const double e3 = dF1 * F1E[binIndex];
+          const double e4 = dF2 * F2E[binIndex];
+          const double e5 = dP1 * P1E[binIndex];
+          const double e6 = dP2 * P2E[binIndex];
+          mpE[binIndex] = std::sqrt(e1 * e1 + e2 * e2 + e3 * e3 + e4 * e4 +
+                                    e5 * e5 + e6 * e6);
+        }
+        {
+          pmY[binIndex] =
+              -(ppY[binIndex] * P2[binIndex] * F1[binIndex] -
+                2 * ppY[binIndex] * F2[binIndex] * P1[binIndex] * P2[binIndex] -
+                2 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P2[binIndex] -
+                2 * ppY[binIndex] * P2[binIndex] * F1[binIndex] * P1[binIndex] +
+                2 * P1[binIndex] * mpY[binIndex] * F2[binIndex] * P2[binIndex] +
+                ppY[binIndex] * P1[binIndex] * P2[binIndex] -
+                P1[binIndex] * mpY[binIndex] * P2[binIndex] +
+                4 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P1[binIndex] *
+                    P2[binIndex] +
+                P1[binIndex] * mmY[binIndex] * P2[binIndex] -
+                ppY[binIndex] * F1[binIndex] +
+                2 * ppY[binIndex] * F1[binIndex] * P1[binIndex] -
+                P1[binIndex] * mmY[binIndex] -
+                P1[binIndex] * mpY[binIndex] * F2[binIndex] +
+                ppY[binIndex] * F2[binIndex] * P1[binIndex] +
+                ppY[binIndex] * F1[binIndex] * F2[binIndex] -
+                2 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P1[binIndex] +
+                P1[binIndex] * mpY[binIndex] - ppY[binIndex] * P1[binIndex]) /
+              ((-P1[binIndex] + 2 * F1[binIndex] * P1[binIndex] -
+                F1[binIndex]) *
+               (-1 + P2[binIndex]));
+          const double dI00 =
+              -(-P1[binIndex] + P1[binIndex] * P2[binIndex] +
+                F2[binIndex] * P1[binIndex] -
+                2 * F2[binIndex] * P1[binIndex] * P2[binIndex] +
+                2 * F1[binIndex] * P1[binIndex] -
+                2 * P2[binIndex] * F1[binIndex] * P1[binIndex] -
+                2 * F1[binIndex] * F2[binIndex] * P1[binIndex] +
+                4 * F1[binIndex] * F2[binIndex] * P1[binIndex] * P2[binIndex] +
+                F1[binIndex] * F2[binIndex] - F1[binIndex] +
+                P2[binIndex] * F1[binIndex] -
+                2 * F1[binIndex] * F2[binIndex] * P2[binIndex]) /
+              ((-P1[binIndex] + 2 * F1[binIndex] * P1[binIndex] -
+                F1[binIndex]) *
+               (-1 + P2[binIndex]));
+          const double dI11 =
+              -(P1[binIndex] * P2[binIndex] - P1[binIndex]) /
+              ((-P1[binIndex] + 2 * F1[binIndex] * P1[binIndex] -
+                F1[binIndex]) *
+               (-1 + P2[binIndex]));
+          const double dI10 =
+              -(P1[binIndex] - P1[binIndex] * P2[binIndex] -
+                F2[binIndex] * P1[binIndex] +
+                2 * F2[binIndex] * P1[binIndex] * P2[binIndex]) /
+              ((-P1[binIndex] + 2 * F1[binIndex] * P1[binIndex] -
+                F1[binIndex]) *
+               (-1 + P2[binIndex]));
+          const double factor1 =
+              (-P1[binIndex] + 2 * F1[binIndex] * P1[binIndex] - F1[binIndex]);
+          const double dF1 =
+              -(ppY[binIndex] * P2[binIndex] -
+                2 * ppY[binIndex] * F2[binIndex] * P2[binIndex] -
+                2 * ppY[binIndex] * P1[binIndex] * P2[binIndex] +
+                4 * ppY[binIndex] * F2[binIndex] * P1[binIndex] * P2[binIndex] -
+                ppY[binIndex] + 2 * ppY[binIndex] * P1[binIndex] +
+                ppY[binIndex] * F2[binIndex] -
+                2 * ppY[binIndex] * F2[binIndex] * P1[binIndex]) /
+                  ((-P1[binIndex] + 2 * F1[binIndex] * P1[binIndex] -
+                    F1[binIndex]) *
+                   (-1 + P2[binIndex])) +
+              (ppY[binIndex] * P2[binIndex] * F1[binIndex] -
+               2 * ppY[binIndex] * F2[binIndex] * P1[binIndex] * P2[binIndex] -
+               2 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P2[binIndex] -
+               2 * ppY[binIndex] * P2[binIndex] * F1[binIndex] * P1[binIndex] +
+               2 * P1[binIndex] * mpY[binIndex] * F2[binIndex] * P2[binIndex] +
+               ppY[binIndex] * P1[binIndex] * P2[binIndex] -
+               P1[binIndex] * mpY[binIndex] * P2[binIndex] +
+               4 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P1[binIndex] *
+                   P2[binIndex] +
+               P1[binIndex] * mmY[binIndex] * P2[binIndex] -
+               ppY[binIndex] * F1[binIndex] +
+               2 * ppY[binIndex] * F1[binIndex] * P1[binIndex] -
+               P1[binIndex] * mmY[binIndex] -
+               P1[binIndex] * mpY[binIndex] * F2[binIndex] +
+               ppY[binIndex] * F2[binIndex] * P1[binIndex] +
+               ppY[binIndex] * F1[binIndex] * F2[binIndex] -
+               2 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P1[binIndex] +
+               P1[binIndex] * mpY[binIndex] - ppY[binIndex] * P1[binIndex]) *
+                  (-1 + 2 * P1[binIndex]) /
+                  ((factor1 * factor1) * (-1 + P2[binIndex]));
+          const double dF2 =
+              -(-2 * ppY[binIndex] * P1[binIndex] * P2[binIndex] -
+                2 * ppY[binIndex] * P2[binIndex] * F1[binIndex] +
+                2 * P1[binIndex] * mpY[binIndex] * P2[binIndex] +
+                4 * ppY[binIndex] * P2[binIndex] * F1[binIndex] * P1[binIndex] -
+                P1[binIndex] * mpY[binIndex] + ppY[binIndex] * P1[binIndex] +
+                ppY[binIndex] * F1[binIndex] -
+                2 * ppY[binIndex] * F1[binIndex] * P1[binIndex]) /
+              ((-P1[binIndex] + 2 * F1[binIndex] * P1[binIndex] -
+                F1[binIndex]) *
+               (-1 + P2[binIndex]));
+          const double factor2 =
+              (-P1[binIndex] + 2 * F1[binIndex] * P1[binIndex] - F1[binIndex]);
+          const double dP1 =
+              -(-2 * ppY[binIndex] * F2[binIndex] * P2[binIndex] -
+                2 * ppY[binIndex] * P2[binIndex] * F1[binIndex] +
+                2 * mpY[binIndex] * F2[binIndex] * P2[binIndex] +
+                ppY[binIndex] * P2[binIndex] - mpY[binIndex] * P2[binIndex] +
+                4 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P2[binIndex] +
+                mmY[binIndex] * P2[binIndex] +
+                2 * ppY[binIndex] * F1[binIndex] - mmY[binIndex] -
+                mpY[binIndex] * F2[binIndex] + ppY[binIndex] * F2[binIndex] -
+                2 * ppY[binIndex] * F1[binIndex] * F2[binIndex] +
+                mpY[binIndex] - ppY[binIndex]) /
+                  ((-P1[binIndex] + 2 * F1[binIndex] * P1[binIndex] -
+                    F1[binIndex]) *
+                   (-1 + P2[binIndex])) +
+              (ppY[binIndex] * P2[binIndex] * F1[binIndex] -
+               2 * ppY[binIndex] * F2[binIndex] * P1[binIndex] * P2[binIndex] -
+               2 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P2[binIndex] -
+               2 * ppY[binIndex] * P2[binIndex] * F1[binIndex] * P1[binIndex] +
+               2 * P1[binIndex] * mpY[binIndex] * F2[binIndex] * P2[binIndex] +
+               ppY[binIndex] * P1[binIndex] * P2[binIndex] -
+               P1[binIndex] * mpY[binIndex] * P2[binIndex] +
+               4 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P1[binIndex] *
+                   P2[binIndex] +
+               P1[binIndex] * mmY[binIndex] * P2[binIndex] -
+               ppY[binIndex] * F1[binIndex] +
+               2 * ppY[binIndex] * F1[binIndex] * P1[binIndex] -
+               P1[binIndex] * mmY[binIndex] -
+               P1[binIndex] * mpY[binIndex] * F2[binIndex] +
+               ppY[binIndex] * F2[binIndex] * P1[binIndex] +
+               ppY[binIndex] * F1[binIndex] * F2[binIndex] -
+               2 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P1[binIndex] +
+               P1[binIndex] * mpY[binIndex] - ppY[binIndex] * P1[binIndex]) *
+                  (-1 + 2 * F1[binIndex]) /
+                  ((factor2 * factor2) * (-1 + P2[binIndex]));
+          const double factor3 = (-1 + P2[binIndex]);
+          const double dP2 =
+              -(ppY[binIndex] * F1[binIndex] -
+                2 * ppY[binIndex] * F2[binIndex] * P1[binIndex] -
+                2 * ppY[binIndex] * F1[binIndex] * F2[binIndex] -
+                2 * ppY[binIndex] * F1[binIndex] * P1[binIndex] +
+                2 * P1[binIndex] * mpY[binIndex] * F2[binIndex] +
+                ppY[binIndex] * P1[binIndex] - P1[binIndex] * mpY[binIndex] +
+                4 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P1[binIndex] +
+                P1[binIndex] * mmY[binIndex]) /
+                  ((-P1[binIndex] + 2 * F1[binIndex] * P1[binIndex] -
+                    F1[binIndex]) *
+                   (-1 + P2[binIndex])) +
+              (ppY[binIndex] * P2[binIndex] * F1[binIndex] -
+               2 * ppY[binIndex] * F2[binIndex] * P1[binIndex] * P2[binIndex] -
+               2 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P2[binIndex] -
+               2 * ppY[binIndex] * P2[binIndex] * F1[binIndex] * P1[binIndex] +
+               2 * P1[binIndex] * mpY[binIndex] * F2[binIndex] * P2[binIndex] +
+               ppY[binIndex] * P1[binIndex] * P2[binIndex] -
+               P1[binIndex] * mpY[binIndex] * P2[binIndex] +
+               4 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P1[binIndex] *
+                   P2[binIndex] +
+               P1[binIndex] * mmY[binIndex] * P2[binIndex] -
+               ppY[binIndex] * F1[binIndex] +
+               2 * ppY[binIndex] * F1[binIndex] * P1[binIndex] -
+               P1[binIndex] * mmY[binIndex] -
+               P1[binIndex] * mpY[binIndex] * F2[binIndex] +
+               ppY[binIndex] * F2[binIndex] * P1[binIndex] +
+               ppY[binIndex] * F1[binIndex] * F2[binIndex] -
+               2 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P1[binIndex] +
+               P1[binIndex] * mpY[binIndex] - ppY[binIndex] * P1[binIndex]) /
+                  ((-P1[binIndex] + 2 * F1[binIndex] * P1[binIndex] -
+                    F1[binIndex]) *
+                   (factor3 * factor3));
+          const double e1 = dI00 * ppE[binIndex];
+          const double e2 = dI11 * mmE[binIndex];
+          const double e3 = dI10 * mpE[binIndex];
+          const double e4 = dF1 * F1E[binIndex];
+          const double e5 = dF2 * F2E[binIndex];
+          const double e6 = dP1 * P1E[binIndex];
+          const double e7 = dP2 * P2E[binIndex];
+          pmE[binIndex] = std::sqrt(e1 * e1 + e2 * e2 + e3 * e3 + e4 * e4 +
+                                    e5 * e5 + e6 * e6 + e7 * e7);
+        }
+      }
+    }
+  }
+};
+
+class PolarizationCorrectionWildesTestPerformance : public CxxTest::TestSuite {
+public:
+  void setUp() override {
+    using namespace Mantid::API;
+    auto loadWS =
+        AlgorithmManager::Instance().createUnmanaged("LoadILLReflectometry");
+    loadWS->setChild(true);
+    loadWS->initialize();
+    loadWS->setProperty("Filename", "ILL/D17/317370.nxs");
+    loadWS->setProperty("OutputWorkspace", "output");
+    loadWS->setProperty("XUnit", "TimeOfFlight");
+    loadWS->execute();
+    m_ws00 = loadWS->getProperty("OutputWorkspace");
+    auto groupDetectors =
+        AlgorithmManager::Instance().createUnmanaged("GroupDetectors");
+    groupDetectors->setChild(true);
+    groupDetectors->initialize();
+    groupDetectors->setProperty("InputWorkspace", m_ws00);
+    groupDetectors->setProperty("OutputWorkspace", "output");
+    groupDetectors->setPropertyValue("WorkspaceIndexList", "201, 202, 203");
+    groupDetectors->execute();
+    m_ws00 = groupDetectors->getProperty("OutputWorkspace");
+    auto convertUnits =
+        AlgorithmManager::Instance().createUnmanaged("ConvertUnits");
+    convertUnits->setChild(true);
+    convertUnits->initialize();
+    convertUnits->setProperty("InputWorkspace", m_ws00);
+    convertUnits->setProperty("OutputWorkspace", "output");
+    convertUnits->setProperty("Target", "Wavelength");
+    convertUnits->execute();
+    m_ws00 = convertUnits->getProperty("OutputWorkspace");
+    auto crop = AlgorithmManager::Instance().createUnmanaged("CropWorkspace");
+    crop->setChild(true);
+    crop->initialize();
+    crop->setProperty("InputWorkspace", m_ws00);
+    crop->setProperty("OutputWorkspace", "output");
+    crop->setProperty("XMin", 0.);
+    crop->execute();
+    m_ws00 = crop->getProperty("OutputWorkspace");
+    AnalysisDataService::Instance().addOrReplace("00", m_ws00);
+    m_ws01 = m_ws00->clone();
+    AnalysisDataService::Instance().addOrReplace("01", m_ws01);
+    m_ws10 = m_ws00->clone();
+    AnalysisDataService::Instance().addOrReplace("10", m_ws10);
+    m_ws11 = m_ws00->clone();
+    AnalysisDataService::Instance().addOrReplace("11", m_ws11);
+    auto loadEff = AlgorithmManager::Instance().createUnmanaged(
+        "LoadILLPolarizationFactors");
+    loadEff->setChild(true);
+    loadEff->initialize();
+    loadEff->setProperty("Filename", "ILL/D17/PolarizationFactors.txt");
+    loadEff->setProperty("OutputWorkspace", "output");
+    loadEff->setProperty("WavelengthReference", m_ws00);
+    loadEff->execute();
+    m_effWS = loadEff->getProperty("OutputWorkspace");
+  }
+
+  void tearDown() override {
+    using namespace Mantid::API;
+    AnalysisDataService::Instance().clear();
+  }
+
+  void test_DirectBeamPerformance() {
+    using namespace Mantid::API;
+    for (int i = 0; i < 3000; ++i) {
+      PolarizationCorrectionWildes correction;
+      correction.setChild(true);
+      correction.setRethrows(true);
+      correction.initialize();
+      correction.setProperty("InputWorkspaces", "00");
+      correction.setProperty("OutputWorkspace", "output");
+      correction.setProperty("Flippers", "0");
+      correction.setProperty("Efficiencies", m_effWS);
+      TS_ASSERT_THROWS_NOTHING(correction.execute())
+    }
+  }
+
+  void test_ThreeInputsPerformanceMissing01() {
+    using namespace Mantid::API;
+    for (int i = 0; i < 3000; ++i) {
+      PolarizationCorrectionWildes correction;
+      correction.setChild(true);
+      correction.setRethrows(true);
+      correction.initialize();
+      correction.setProperty("InputWorkspaces", "00, 10, 11");
+      correction.setProperty("OutputWorkspace", "output");
+      correction.setProperty("Flippers", "00, 10, 11");
+      correction.setProperty("Efficiencies", m_effWS);
+      TS_ASSERT_THROWS_NOTHING(correction.execute())
+    }
+  }
+
+  void test_ThreeInputsPerformanceMissing10() {
+    using namespace Mantid::API;
+    for (int i = 0; i < 3000; ++i) {
+      PolarizationCorrectionWildes correction;
+      correction.setChild(true);
+      correction.setRethrows(true);
+      correction.initialize();
+      correction.setProperty("InputWorkspaces", "00, 01, 11");
+      correction.setProperty("OutputWorkspace", "output");
+      correction.setProperty("Flippers", "00, 01, 11");
+      correction.setProperty("Efficiencies", m_effWS);
+      TS_ASSERT_THROWS_NOTHING(correction.execute())
+    }
+  }
+
+  void test_TwoInputsNoAnalyzerPerformance() {
+    using namespace Mantid::API;
+    for (int i = 0; i < 3000; ++i) {
+      PolarizationCorrectionWildes correction;
+      correction.setChild(true);
+      correction.setRethrows(true);
+      correction.initialize();
+      correction.setProperty("InputWorkspaces", "00, 11");
+      correction.setProperty("OutputWorkspace", "output");
+      correction.setProperty("Flippers", "0, 1");
+      correction.setProperty("Efficiencies", m_effWS);
+      TS_ASSERT_THROWS_NOTHING(correction.execute())
+    }
+  }
+
+  void test_TwoInputsPerformance() {
+    using namespace Mantid::API;
+    for (int i = 0; i < 3000; ++i) {
+      PolarizationCorrectionWildes correction;
+      correction.setChild(true);
+      correction.setRethrows(true);
+      correction.initialize();
+      correction.setProperty("InputWorkspaces", "00, 11");
+      correction.setProperty("OutputWorkspace", "output");
+      correction.setProperty("Flippers", "00, 11");
+      correction.setProperty("Efficiencies", m_effWS);
+      TS_ASSERT_THROWS_NOTHING(correction.execute())
+    }
+  }
+
+private:
+  Mantid::API::MatrixWorkspace_sptr m_effWS;
+  Mantid::API::MatrixWorkspace_sptr m_ws00;
+  Mantid::API::MatrixWorkspace_sptr m_ws01;
+  Mantid::API::MatrixWorkspace_sptr m_ws10;
+  Mantid::API::MatrixWorkspace_sptr m_ws11;
+};
+
+#endif /* MANTID_ALGORITHMS_POLARIZATIONCORRECTIONWILDESTEST_H_ */
diff --git a/Framework/Algorithms/test/PolarizationEfficiencyCorTest.h b/Framework/Algorithms/test/PolarizationEfficiencyCorTest.h
index 08999a4f7669142c541cefce5ab2913b0f57854b..fb710a89379bc262db6590570b38e5aef29ca270 100644
--- a/Framework/Algorithms/test/PolarizationEfficiencyCorTest.h
+++ b/Framework/Algorithms/test/PolarizationEfficiencyCorTest.h
@@ -13,10 +13,19 @@
 #include "MantidAPI/WorkspaceGroup.h"
 #include "MantidDataObjects/Workspace2D.h"
 #include "MantidDataObjects/WorkspaceCreation.h"
+#include "MantidHistogramData/BinEdges.h"
+#include "MantidHistogramData/Counts.h"
+#include "MantidHistogramData/LinearGenerator.h"
+
+#include "MantidTestHelpers/WorkspaceCreationHelper.h"
 
 #include <Eigen/Dense>
 
-using Mantid::Algorithms::PolarizationEfficiencyCor;
+using namespace Mantid::API;
+using namespace Mantid::Algorithms;
+using namespace Mantid::DataObjects;
+using namespace Mantid::HistogramData;
+using namespace WorkspaceCreationHelper;
 
 class PolarizationEfficiencyCorTest : public CxxTest::TestSuite {
 public:
@@ -29,1962 +38,521 @@ public:
     delete suite;
   }
 
-  void tearDown() override {
-    using namespace Mantid::API;
-    AnalysisDataService::Instance().clear();
-  }
+  void tearDown() override { AnalysisDataService::Instance().clear(); }
 
-  void test_Init() {
+  void test_input_ws_no_inputs() {
     PolarizationEfficiencyCor alg;
-    TS_ASSERT_THROWS_NOTHING(alg.initialize())
-    TS_ASSERT(alg.isInitialized())
-  }
-
-  void test_IdealCaseFullCorrections() {
-    using namespace Mantid::API;
-    using namespace Mantid::DataObjects;
-    using namespace Mantid::HistogramData;
-    using namespace Mantid::Kernel;
-    constexpr size_t nBins{3};
-    constexpr size_t nHist{2};
-    BinEdges edges{0.3, 0.6, 0.9, 1.2};
-    const double yVal = 2.3;
-    Counts counts{yVal, 4.2 * yVal, yVal};
-    MatrixWorkspace_sptr ws00 =
-        create<Workspace2D>(nHist, Histogram(edges, counts));
-    MatrixWorkspace_sptr ws01 = ws00->clone();
-    MatrixWorkspace_sptr ws10 = ws00->clone();
-    MatrixWorkspace_sptr ws11 = ws00->clone();
-    const std::vector<std::string> wsNames{{"ws00", "ws01", "ws10", "ws11"}};
-    const std::array<MatrixWorkspace_sptr, 4> wsList{{ws00, ws01, ws10, ws11}};
-    for (size_t i = 0; i != 4; ++i) {
-      for (size_t j = 0; j != nHist; ++j) {
-        wsList[i]->mutableY(j) *= static_cast<double>(i + 1);
-        wsList[i]->mutableE(j) *= static_cast<double>(i + 1);
-      }
-      AnalysisDataService::Instance().addOrReplace(wsNames[i], wsList[i]);
-    }
-    auto effWS = idealEfficiencies(edges);
+    alg.setRethrows(true);
+    alg.initialize();
+    alg.setProperty("OutputWorkspace", "out");
+    alg.setProperty("Efficiencies", createEfficiencies("Wildes"));
+    // Error: Input workspaces are missing. Either a workspace group or a list
+    // of workspace names must be given
+    TS_ASSERT_THROWS(alg.execute(), std::invalid_argument);
+  }
+  void test_input_ws_default_group() {
     PolarizationEfficiencyCor alg;
-    alg.setChild(true);
     alg.setRethrows(true);
-    TS_ASSERT_THROWS_NOTHING(alg.initialize())
-    TS_ASSERT(alg.isInitialized())
-    TS_ASSERT_THROWS_NOTHING(alg.setProperty("InputWorkspaces", wsNames))
-    TS_ASSERT_THROWS_NOTHING(
-        alg.setPropertyValue("OutputWorkspace", m_outputWSName))
-    TS_ASSERT_THROWS_NOTHING(alg.setProperty("Efficiencies", effWS))
-    TS_ASSERT_THROWS_NOTHING(alg.execute())
-    TS_ASSERT(alg.isExecuted())
-    WorkspaceGroup_sptr outputWS = alg.getProperty("OutputWorkspace");
-    TS_ASSERT(outputWS)
-    TS_ASSERT_EQUALS(outputWS->getNumberOfEntries(), 4)
-    const std::array<std::string, 4> POL_DIRS{{"++", "+-", "-+", "--"}};
-    for (size_t i = 0; i != 4; ++i) {
-      const std::string wsName =
-          m_outputWSName + std::string("_") + POL_DIRS[i];
-      MatrixWorkspace_sptr ws = boost::dynamic_pointer_cast<MatrixWorkspace>(
-          outputWS->getItem(wsName));
-      TS_ASSERT(ws)
-      TS_ASSERT_EQUALS(ws->getNumberHistograms(), nHist)
-      for (size_t j = 0; j != nHist; ++j) {
-        const auto &xs = ws->x(j);
-        const auto &ys = ws->y(j);
-        const auto &es = ws->e(j);
-        TS_ASSERT_EQUALS(ys.size(), nBins)
-        for (size_t k = 0; k != nBins; ++k) {
-          const double y = counts[k];
-          TS_ASSERT_EQUALS(xs[k], edges[k])
-          TS_ASSERT_EQUALS(ys[k], y * static_cast<double>(i + 1))
-          TS_ASSERT_EQUALS(es[k], std::sqrt(y) * static_cast<double>(i + 1))
-        }
-      }
-    }
-  }
-
-  void test_IdealCaseThreeInputs10Missing() { idealThreeInputsTest("10"); }
-
-  void test_IdealCaseThreeInputs01Missing() { idealThreeInputsTest("01"); }
-
-  void test_IdealCaseTwoInputsWithAnalyzer() {
-    using namespace Mantid::API;
-    using namespace Mantid::DataObjects;
-    using namespace Mantid::HistogramData;
-    using namespace Mantid::Kernel;
-    constexpr size_t nBins{3};
-    constexpr size_t nHist{2};
-    BinEdges edges{0.3, 0.6, 0.9, 1.2};
-    const double yVal = 2.3;
-    Counts counts{yVal, 4.2 * yVal, yVal};
-    MatrixWorkspace_sptr ws00 =
-        create<Workspace2D>(nHist, Histogram(edges, counts));
-    MatrixWorkspace_sptr ws11 = ws00->clone();
-    const std::vector<std::string> wsNames{
-        std::initializer_list<std::string>{"ws00", "ws11"}};
-    const std::array<MatrixWorkspace_sptr, 2> wsList{{ws00, ws11}};
-    for (size_t i = 0; i != nHist; ++i) {
-      ws11->mutableY(i) *= 2.;
-      ws11->mutableE(i) *= 2.;
-    }
-    AnalysisDataService::Instance().addOrReplace(wsNames.front(),
-                                                 wsList.front());
-    AnalysisDataService::Instance().addOrReplace(wsNames.back(), wsList.back());
-    auto effWS = idealEfficiencies(edges);
+    alg.initialize();
+    alg.setProperty("OutputWorkspace", "out");
+    alg.setProperty("InputWorkspaceGroup", createWorkspaceGroup(4));
+    alg.setProperty("Efficiencies", createEfficiencies("Wildes"));
+    alg.execute();
+    WorkspaceGroup_sptr out =
+        AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>("out");
+    TS_ASSERT_EQUALS(out->size(), 4);
+  }
+  void test_input_ws_wildes_group() {
     PolarizationEfficiencyCor alg;
-    alg.setChild(true);
     alg.setRethrows(true);
-    TS_ASSERT_THROWS_NOTHING(alg.initialize())
-    TS_ASSERT(alg.isInitialized())
-    TS_ASSERT_THROWS_NOTHING(alg.setProperty("InputWorkspaces", wsNames))
-    TS_ASSERT_THROWS_NOTHING(
-        alg.setPropertyValue("OutputWorkspace", m_outputWSName))
-    TS_ASSERT_THROWS_NOTHING(alg.setProperty("Efficiencies", effWS))
-    TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("Flippers", "00, 11"))
-    TS_ASSERT_THROWS_NOTHING(alg.execute())
-    TS_ASSERT(alg.isExecuted())
-    WorkspaceGroup_sptr outputWS = alg.getProperty("OutputWorkspace");
-    TS_ASSERT(outputWS)
-    TS_ASSERT_EQUALS(outputWS->getNumberOfEntries(), 4)
-    const std::array<std::string, 4> POL_DIRS{{"++", "+-", "-+", "--"}};
-    for (size_t i = 0; i != 4; ++i) {
-      const auto &dir = POL_DIRS[i];
-      const std::string wsName = m_outputWSName + std::string("_") + dir;
-      MatrixWorkspace_sptr ws = boost::dynamic_pointer_cast<MatrixWorkspace>(
-          outputWS->getItem(wsName));
-      TS_ASSERT(ws)
-      TS_ASSERT_EQUALS(ws->getNumberHistograms(), nHist)
-      for (size_t j = 0; j != nHist; ++j) {
-        const auto &xs = ws->x(j);
-        const auto &ys = ws->y(j);
-        const auto &es = ws->e(j);
-        TS_ASSERT_EQUALS(ys.size(), nBins)
-        for (size_t k = 0; k != nBins; ++k) {
-          const double y = counts[k];
-          const double expected = [y, &dir]() {
-            if (dir == "++") {
-              return y;
-            } else if (dir == "--") {
-              return 2. * y;
-            } else {
-              return 0.;
-            }
-          }();
-          const double expectedError = [y, &dir]() {
-            if (dir == "++") {
-              return std::sqrt(y);
-            } else if (dir == "--") {
-              return 2. * std::sqrt(y);
-            } else {
-              return 0.;
-            }
-          }();
-          TS_ASSERT_EQUALS(xs[k], edges[k])
-          TS_ASSERT_EQUALS(ys[k], expected)
-          TS_ASSERT_EQUALS(es[k], expectedError)
-        }
-      }
-    }
-  }
-
-  void test_IdealCaseTwoInputsNoAnalyzer() {
-    using namespace Mantid::API;
-    using namespace Mantid::DataObjects;
-    using namespace Mantid::HistogramData;
-    using namespace Mantid::Kernel;
-    constexpr size_t nBins{3};
-    constexpr size_t nHist{2};
-    BinEdges edges{0.3, 0.6, 0.9, 1.2};
-    const double yVal = 2.3;
-    Counts counts{yVal, 4.2 * yVal, yVal};
-    MatrixWorkspace_sptr ws00 =
-        create<Workspace2D>(nHist, Histogram(edges, counts));
-    MatrixWorkspace_sptr ws11 = ws00->clone();
-    const std::vector<std::string> wsNames{
-        std::initializer_list<std::string>{"ws00", "ws11"}};
-    const std::array<MatrixWorkspace_sptr, 2> wsList{{ws00, ws11}};
-    for (size_t i = 0; i != nHist; ++i) {
-      ws11->mutableY(i) *= 2.;
-      ws11->mutableE(i) *= 2.;
-    }
-    AnalysisDataService::Instance().addOrReplace(wsNames.front(),
-                                                 wsList.front());
-    AnalysisDataService::Instance().addOrReplace(wsNames.back(), wsList.back());
-    auto effWS = idealEfficiencies(edges);
+    alg.initialize();
+    alg.setProperty("OutputWorkspace", "out");
+    alg.setProperty("InputWorkspaceGroup", createWorkspaceGroup(4));
+    alg.setProperty("CorrectionMethod", "Wildes");
+    alg.setProperty("Efficiencies", createEfficiencies("Wildes"));
+    alg.execute();
+    WorkspaceGroup_sptr out =
+        AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>("out");
+    TS_ASSERT_EQUALS(out->size(), 4);
+  }
+  void test_input_ws_fredrikze_group() {
     PolarizationEfficiencyCor alg;
-    alg.setChild(true);
     alg.setRethrows(true);
-    TS_ASSERT_THROWS_NOTHING(alg.initialize())
-    TS_ASSERT(alg.isInitialized())
-    TS_ASSERT_THROWS_NOTHING(alg.setProperty("InputWorkspaces", wsNames))
-    TS_ASSERT_THROWS_NOTHING(
-        alg.setPropertyValue("OutputWorkspace", m_outputWSName))
-    TS_ASSERT_THROWS_NOTHING(alg.setProperty("Efficiencies", effWS))
-    TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("Flippers", "0, 1"))
-    TS_ASSERT_THROWS_NOTHING(alg.execute())
-    TS_ASSERT(alg.isExecuted())
-    WorkspaceGroup_sptr outputWS = alg.getProperty("OutputWorkspace");
-    TS_ASSERT(outputWS)
-    TS_ASSERT_EQUALS(outputWS->getNumberOfEntries(), 2)
-    const std::array<std::string, 2> POL_DIRS{{"++", "--"}};
-    for (size_t i = 0; i != 2; ++i) {
-      const auto &dir = POL_DIRS[i];
-      const std::string wsName = m_outputWSName + std::string("_") + dir;
-      MatrixWorkspace_sptr ws = boost::dynamic_pointer_cast<MatrixWorkspace>(
-          outputWS->getItem(wsName));
-      TS_ASSERT(ws)
-      TS_ASSERT_EQUALS(ws->getNumberHistograms(), nHist)
-      for (size_t j = 0; j != nHist; ++j) {
-        const auto &xs = ws->x(j);
-        const auto &ys = ws->y(j);
-        const auto &es = ws->e(j);
-        TS_ASSERT_EQUALS(ys.size(), nBins)
-        for (size_t k = 0; k != nBins; ++k) {
-          const double y = counts[k];
-          TS_ASSERT_EQUALS(xs[k], edges[k])
-          TS_ASSERT_EQUALS(ys[k], y * static_cast<double>(i + 1))
-          TS_ASSERT_EQUALS(es[k], std::sqrt(y) * static_cast<double>(i + 1))
-        }
-      }
-    }
-  }
-
-  void test_IdealCaseDirectBeamCorrections() {
-    using namespace Mantid::API;
-    using namespace Mantid::DataObjects;
-    using namespace Mantid::HistogramData;
-    using namespace Mantid::Kernel;
-    constexpr size_t nBins{3};
-    constexpr size_t nHist{2};
-    BinEdges edges{0.3, 0.6, 0.9, 1.2};
-    const double yVal = 2.3;
-    Counts counts{yVal, 4.2 * yVal, yVal};
-    MatrixWorkspace_sptr ws00 =
-        create<Workspace2D>(nHist, Histogram(edges, counts));
-    const std::vector<std::string> wsNames{{"ws00"}};
-    AnalysisDataService::Instance().addOrReplace(wsNames.front(), ws00);
-    auto effWS = idealEfficiencies(edges);
+    alg.initialize();
+    alg.setProperty("OutputWorkspace", "out");
+    alg.setProperty("InputWorkspaceGroup", createWorkspaceGroup(4));
+    alg.setProperty("CorrectionMethod", "Fredrikze");
+    alg.setProperty("Efficiencies", createEfficiencies("Fredrikze"));
+    alg.execute();
+    WorkspaceGroup_sptr out =
+        AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>("out");
+    TS_ASSERT_EQUALS(out->size(), 4);
+  }
+  void test_input_ws_wildes_wrong_input_size() {
     PolarizationEfficiencyCor alg;
-    alg.setChild(true);
     alg.setRethrows(true);
-    TS_ASSERT_THROWS_NOTHING(alg.initialize())
-    TS_ASSERT(alg.isInitialized())
-    TS_ASSERT_THROWS_NOTHING(alg.setProperty("InputWorkspaces", wsNames))
-    TS_ASSERT_THROWS_NOTHING(
-        alg.setPropertyValue("OutputWorkspace", m_outputWSName))
-    TS_ASSERT_THROWS_NOTHING(alg.setProperty("Efficiencies", effWS))
-    TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("Flippers", "0"))
-    TS_ASSERT_THROWS_NOTHING(alg.execute())
-    TS_ASSERT(alg.isExecuted())
-    WorkspaceGroup_sptr outputWS = alg.getProperty("OutputWorkspace");
-    TS_ASSERT(outputWS)
-    TS_ASSERT_EQUALS(outputWS->getNumberOfEntries(), 1)
-    MatrixWorkspace_sptr ws = boost::dynamic_pointer_cast<MatrixWorkspace>(
-        outputWS->getItem(m_outputWSName + std::string("_++")));
-    TS_ASSERT(ws)
-    TS_ASSERT_EQUALS(ws->getNumberHistograms(), nHist)
-    for (size_t i = 0; i != nHist; ++i) {
-      const auto &xs = ws->x(i);
-      const auto &ys = ws->y(i);
-      const auto &es = ws->e(i);
-      TS_ASSERT_EQUALS(ys.size(), nBins)
-      for (size_t j = 0; j != nBins; ++j) {
-        const double y = counts[j];
-        TS_ASSERT_EQUALS(xs[j], edges[j])
-        TS_ASSERT_EQUALS(ys[j], y)
-        TS_ASSERT_EQUALS(es[j], std::sqrt(y))
-      }
-    }
-  }
-
-  void test_FullCorrections() {
-    using namespace Mantid::API;
-    using namespace Mantid::DataObjects;
-    using namespace Mantid::HistogramData;
-    using namespace Mantid::Kernel;
-    constexpr size_t nHist{2};
-    BinEdges edges{0.3, 0.6, 0.9, 1.2};
-    const double yVal = 2.3;
-    Counts counts{yVal, yVal, yVal};
-    MatrixWorkspace_sptr ws00 =
-        create<Workspace2D>(nHist, Histogram(edges, counts));
-    MatrixWorkspace_sptr ws01 = ws00->clone();
-    MatrixWorkspace_sptr ws10 = ws00->clone();
-    MatrixWorkspace_sptr ws11 = ws00->clone();
-    const std::vector<std::string> wsNames{{"ws00", "ws01", "ws10", "ws11"}};
-    const std::array<MatrixWorkspace_sptr, 4> wsList{{ws00, ws01, ws10, ws11}};
-    for (size_t i = 0; i != 4; ++i) {
-      for (size_t j = 0; j != nHist; ++j) {
-        wsList[i]->mutableY(j) *= static_cast<double>(i + 1);
-        wsList[i]->mutableE(j) *= static_cast<double>(i + 1);
-      }
-      AnalysisDataService::Instance().addOrReplace(wsNames[i], wsList[i]);
-    }
-    auto effWS = efficiencies(edges);
+    alg.initialize();
+    alg.setProperty("OutputWorkspace", "out");
+    alg.setProperty("InputWorkspaceGroup", createWorkspaceGroup(2));
+    alg.setProperty("CorrectionMethod", "Wildes");
+    alg.setProperty("Efficiencies", createEfficiencies("Wildes"));
+    // Error: Some invalid Properties found
+    TS_ASSERT_THROWS(alg.execute(), std::runtime_error);
+  }
+  void test_input_ws_fredrikze_wrong_input_size() {
     PolarizationEfficiencyCor alg;
-    alg.setChild(true);
     alg.setRethrows(true);
-    TS_ASSERT_THROWS_NOTHING(alg.initialize())
-    TS_ASSERT(alg.isInitialized())
-    TS_ASSERT_THROWS_NOTHING(alg.setProperty("InputWorkspaces", wsNames))
-    TS_ASSERT_THROWS_NOTHING(
-        alg.setPropertyValue("OutputWorkspace", m_outputWSName))
-    TS_ASSERT_THROWS_NOTHING(alg.setProperty("Efficiencies", effWS))
-    TS_ASSERT_THROWS_NOTHING(alg.execute())
-    TS_ASSERT(alg.isExecuted())
-    WorkspaceGroup_sptr outputWS = alg.getProperty("OutputWorkspace");
-    TS_ASSERT(outputWS)
-    TS_ASSERT_EQUALS(outputWS->getNumberOfEntries(), 4)
-    fullFourInputsResultsCheck(outputWS, ws00, ws01, ws10, ws11, effWS);
-  }
-
-  void test_ThreeInputsWithMissing01FlipperConfiguration() {
-    threeInputsTest("01");
-  }
-
-  void test_ThreeInputsWithMissing10FlipperConfiguration() {
-    threeInputsTest("10");
-  }
-
-  void test_TwoInputsWithAnalyzer() {
-    using namespace Mantid::API;
-    using namespace Mantid::DataObjects;
-    using namespace Mantid::HistogramData;
-    using namespace Mantid::Kernel;
-    constexpr size_t nHist{2};
-    constexpr size_t nBins{3};
-    BinEdges edges{0.3, 0.6, 0.9, 1.2};
-    const double yVal = 2.3;
-    Counts counts{yVal, yVal, yVal};
-    MatrixWorkspace_sptr ws00 =
-        create<Workspace2D>(nHist, Histogram(edges, counts));
-    MatrixWorkspace_sptr ws01 = nullptr;
-    MatrixWorkspace_sptr ws10 = nullptr;
-    MatrixWorkspace_sptr ws11 = ws00->clone();
-    const std::vector<std::string> wsNames{
-        std::initializer_list<std::string>{"ws00", "ws11"}};
-    const std::array<MatrixWorkspace_sptr, 2> wsList{{ws00, ws11}};
-    for (size_t i = 0; i != 2; ++i) {
-      for (size_t j = 0; j != nHist; ++j) {
-        wsList[i]->mutableY(j) *= static_cast<double>(i + 1);
-        wsList[i]->mutableE(j) *= static_cast<double>(i + 1);
-      }
-      AnalysisDataService::Instance().addOrReplace(wsNames[i], wsList[i]);
-    }
-    auto effWS = efficiencies(edges);
+    alg.initialize();
+    alg.setProperty("OutputWorkspace", "out");
+    alg.setProperty("InputWorkspaceGroup", createWorkspaceGroup(2));
+    alg.setProperty("CorrectionMethod", "Fredrikze");
+    alg.setProperty("Efficiencies", createEfficiencies("Fredrikze"));
+    // Error: For PA analysis, input group must have 4 periods
+    TS_ASSERT_THROWS(alg.execute(), std::invalid_argument);
+  }
+  void test_input_ws_wildes_list() {
     PolarizationEfficiencyCor alg;
-    alg.setChild(true);
     alg.setRethrows(true);
-    TS_ASSERT_THROWS_NOTHING(alg.initialize())
-    TS_ASSERT(alg.isInitialized())
-    TS_ASSERT_THROWS_NOTHING(alg.setProperty("InputWorkspaces", wsNames))
-    TS_ASSERT_THROWS_NOTHING(
-        alg.setPropertyValue("OutputWorkspace", m_outputWSName))
-    TS_ASSERT_THROWS_NOTHING(alg.setProperty("Efficiencies", effWS))
-    TS_ASSERT_THROWS_NOTHING(alg.setProperty("Flippers", "00, 11"))
-    TS_ASSERT_THROWS_NOTHING(alg.execute())
-    TS_ASSERT(alg.isExecuted())
-    WorkspaceGroup_sptr outputWS = alg.getProperty("OutputWorkspace");
-    TS_ASSERT(outputWS)
-    TS_ASSERT_EQUALS(outputWS->getNumberOfEntries(), 4)
-    solveMissingIntensities(ws00, ws01, ws10, ws11, effWS);
-    using namespace Mantid::API;
-    const double F1 = effWS->y(0).front();
-    const double F1e = effWS->e(0).front();
-    const double F2 = effWS->y(1).front();
-    const double F2e = effWS->e(1).front();
-    const double P1 = effWS->y(2).front();
-    const double P1e = effWS->e(2).front();
-    const double P2 = effWS->y(3).front();
-    const double P2e = effWS->e(3).front();
-    const Eigen::Vector4d y{ws00->y(0).front(), ws01->y(0).front(),
-                            ws10->y(0).front(), ws11->y(0).front()};
-    const auto expected = correction(y, F1, F2, P1, P2);
-    const Eigen::Vector4d e{ws00->e(0).front(), ws01->e(0).front(),
-                            ws10->e(0).front(), ws11->e(0).front()};
-    const auto expectedError = error(y, e, F1, F1e, F2, F2e, P1, P1e, P2, P2e);
-    MatrixWorkspace_sptr ppWS = boost::dynamic_pointer_cast<MatrixWorkspace>(
-        outputWS->getItem(m_outputWSName + std::string("_++")));
-    MatrixWorkspace_sptr pmWS = boost::dynamic_pointer_cast<MatrixWorkspace>(
-        outputWS->getItem(m_outputWSName + std::string("_+-")));
-    MatrixWorkspace_sptr mpWS = boost::dynamic_pointer_cast<MatrixWorkspace>(
-        outputWS->getItem(m_outputWSName + std::string("_-+")));
-    MatrixWorkspace_sptr mmWS = boost::dynamic_pointer_cast<MatrixWorkspace>(
-        outputWS->getItem(m_outputWSName + std::string("_--")));
-    TS_ASSERT(ppWS)
-    TS_ASSERT(pmWS)
-    TS_ASSERT(mpWS)
-    TS_ASSERT(mmWS)
-    TS_ASSERT_EQUALS(ppWS->getNumberHistograms(), nHist)
-    TS_ASSERT_EQUALS(pmWS->getNumberHistograms(), nHist)
-    TS_ASSERT_EQUALS(mpWS->getNumberHistograms(), nHist)
-    TS_ASSERT_EQUALS(mmWS->getNumberHistograms(), nHist)
-    for (size_t j = 0; j != nHist; ++j) {
-      const auto &ppX = ppWS->x(j);
-      const auto &ppY = ppWS->y(j);
-      const auto &ppE = ppWS->e(j);
-      const auto &pmX = pmWS->x(j);
-      const auto &pmY = pmWS->y(j);
-      const auto &pmE = pmWS->e(j);
-      const auto &mpX = mpWS->x(j);
-      const auto &mpY = mpWS->y(j);
-      const auto &mpE = mpWS->e(j);
-      const auto &mmX = mmWS->x(j);
-      const auto &mmY = mmWS->y(j);
-      const auto &mmE = mmWS->e(j);
-      TS_ASSERT_EQUALS(ppY.size(), nBins)
-      TS_ASSERT_EQUALS(pmY.size(), nBins)
-      TS_ASSERT_EQUALS(mpY.size(), nBins)
-      TS_ASSERT_EQUALS(mmY.size(), nBins)
-      for (size_t k = 0; k != nBins; ++k) {
-        TS_ASSERT_EQUALS(ppX[k], edges[k])
-        TS_ASSERT_EQUALS(pmX[k], edges[k])
-        TS_ASSERT_EQUALS(mpX[k], edges[k])
-        TS_ASSERT_EQUALS(mmX[k], edges[k])
-        TS_ASSERT_DELTA(ppY[k], expected[0], 1e-12)
-        TS_ASSERT_DELTA(pmY[k], expected[1], 1e-12)
-        TS_ASSERT_DELTA(mpY[k], expected[2], 1e-12)
-        TS_ASSERT_DELTA(mmY[k], expected[3], 1e-12)
-        // This test constructs the expected missing I01 and I10 intensities
-        // slightly different from what the algorithm does: I10 is solved
-        // first and then I01 is solved using all I00, I10 and I11. This
-        // results in slightly larger errors estimates for I01 and thus for
-        // the final corrected expected intensities.
-        TS_ASSERT_DELTA(ppE[k], expectedError[0], 1e-6)
-        TS_ASSERT_LESS_THAN(ppE[k], expectedError[0])
-        TS_ASSERT_DELTA(pmE[k], expectedError[1], 1e-2)
-        TS_ASSERT_LESS_THAN(pmE[k], expectedError[1])
-        TS_ASSERT_DELTA(mpE[k], expectedError[2], 1e-7)
-        TS_ASSERT_LESS_THAN(mpE[k], expectedError[2])
-        TS_ASSERT_DELTA(mmE[k], expectedError[3], 1e-5)
-        TS_ASSERT_LESS_THAN(mmE[k], expectedError[3])
-      }
-    }
-  }
-
-  void test_TwoInputsWithoutAnalyzer() {
-    using namespace Mantid::API;
-    using namespace Mantid::DataObjects;
-    using namespace Mantid::HistogramData;
-    using namespace Mantid::Kernel;
-    constexpr size_t nHist{2};
-    constexpr size_t nBins{3};
-    BinEdges edges{0.3, 0.6, 0.9, 1.2};
-    const double yVal = 2.3;
-    Counts counts{yVal, yVal, yVal};
-    MatrixWorkspace_sptr ws00 =
-        create<Workspace2D>(nHist, Histogram(edges, counts));
-    MatrixWorkspace_sptr ws11 = ws00->clone();
-    const std::vector<std::string> wsNames{
-        std::initializer_list<std::string>{"ws00", "ws11"}};
-    const std::array<MatrixWorkspace_sptr, 2> wsList{{ws00, ws11}};
-    for (size_t i = 0; i != 2; ++i) {
-      for (size_t j = 0; j != nHist; ++j) {
-        wsList[i]->mutableY(j) *= static_cast<double>(i + 1);
-        wsList[i]->mutableE(j) *= static_cast<double>(i + 1);
-      }
-      AnalysisDataService::Instance().addOrReplace(wsNames[i], wsList[i]);
-    }
-    auto effWS = efficiencies(edges);
+    alg.initialize();
+    alg.setProperty("OutputWorkspace", "out");
+    alg.setProperty("InputWorkspaces", createWorkspacesInADS(4));
+    alg.setProperty("CorrectionMethod", "Wildes");
+    alg.setProperty("Efficiencies", createEfficiencies("Wildes"));
+    alg.execute();
+    WorkspaceGroup_sptr out =
+        AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>("out");
+    TS_ASSERT_EQUALS(out->size(), 4);
+  }
+  void test_input_ws_frederikze_needs_group() {
     PolarizationEfficiencyCor alg;
-    alg.setChild(true);
     alg.setRethrows(true);
-    TS_ASSERT_THROWS_NOTHING(alg.initialize())
-    TS_ASSERT(alg.isInitialized())
-    TS_ASSERT_THROWS_NOTHING(alg.setProperty("InputWorkspaces", wsNames))
-    TS_ASSERT_THROWS_NOTHING(
-        alg.setPropertyValue("OutputWorkspace", m_outputWSName))
-    TS_ASSERT_THROWS_NOTHING(alg.setProperty("Efficiencies", effWS))
-    TS_ASSERT_THROWS_NOTHING(alg.setProperty("Flippers", "0, 1"))
-    TS_ASSERT_THROWS_NOTHING(alg.execute())
-    TS_ASSERT(alg.isExecuted())
-    WorkspaceGroup_sptr outputWS = alg.getProperty("OutputWorkspace");
-    TS_ASSERT(outputWS)
-    TS_ASSERT_EQUALS(outputWS->getNumberOfEntries(), 2)
-    const double F1 = effWS->y(0).front();
-    const double F1e = effWS->e(0).front();
-    const double P1 = effWS->y(2).front();
-    const double P1e = effWS->e(2).front();
-    const Eigen::Vector2d y{ws00->y(0).front(), ws11->y(0).front()};
-    const auto expected = correctionWithoutAnalyzer(y, F1, P1);
-    const Eigen::Vector2d e{ws00->e(0).front(), ws11->e(0).front()};
-    const auto expectedError = errorWithoutAnalyzer(y, e, F1, F1e, P1, P1e);
-    MatrixWorkspace_sptr ppWS = boost::dynamic_pointer_cast<MatrixWorkspace>(
-        outputWS->getItem(m_outputWSName + std::string("_++")));
-    MatrixWorkspace_sptr mmWS = boost::dynamic_pointer_cast<MatrixWorkspace>(
-        outputWS->getItem(m_outputWSName + std::string("_--")));
-    TS_ASSERT(ppWS)
-    TS_ASSERT(mmWS)
-    TS_ASSERT_EQUALS(ppWS->getNumberHistograms(), nHist)
-    TS_ASSERT_EQUALS(mmWS->getNumberHistograms(), nHist)
-    for (size_t j = 0; j != nHist; ++j) {
-      const auto &ppX = ppWS->x(j);
-      const auto &ppY = ppWS->y(j);
-      const auto &ppE = ppWS->e(j);
-      const auto &mmX = mmWS->x(j);
-      const auto &mmY = mmWS->y(j);
-      const auto &mmE = mmWS->e(j);
-      TS_ASSERT_EQUALS(ppY.size(), nBins)
-      TS_ASSERT_EQUALS(mmY.size(), nBins)
-      for (size_t k = 0; k != nBins; ++k) {
-        TS_ASSERT_EQUALS(ppX[k], edges[k])
-        TS_ASSERT_EQUALS(mmX[k], edges[k])
-        TS_ASSERT_DELTA(ppY[k], expected[0], 1e-12)
-        TS_ASSERT_DELTA(mmY[k], expected[1], 1e-12)
-        TS_ASSERT_DELTA(ppE[k], expectedError[0], 1e-12)
-        TS_ASSERT_DELTA(mmE[k], expectedError[1], 1e-12)
-      }
-    }
-  }
-
-  void test_directBeamOnlyInput() {
-    using namespace Mantid::API;
-    using namespace Mantid::DataObjects;
-    using namespace Mantid::HistogramData;
-    using namespace Mantid::Kernel;
-    constexpr size_t nHist{2};
-    constexpr size_t nBins{3};
-    BinEdges edges{0.3, 0.6, 0.9, 1.2};
-    const double yVal = 2.3;
-    Counts counts{yVal, yVal, yVal};
-    MatrixWorkspace_sptr ws00 =
-        create<Workspace2D>(nHist, Histogram(edges, counts));
-    const std::string wsName{"ws00"};
-    AnalysisDataService::Instance().addOrReplace(wsName, ws00);
-    auto effWS = efficiencies(edges);
+    alg.initialize();
+    alg.setProperty("OutputWorkspace", "out");
+    alg.setProperty("InputWorkspaces", createWorkspacesInADS(4));
+    alg.setProperty("CorrectionMethod", "Fredrikze");
+    alg.setProperty("Efficiencies", createEfficiencies("Fredrikze"));
+    // Error: Input workspaces are required to be in a workspace group
+    TS_ASSERT_THROWS(alg.execute(), std::invalid_argument);
+  }
+  void test_input_ws_cannot_be_both() {
     PolarizationEfficiencyCor alg;
-    alg.setChild(true);
     alg.setRethrows(true);
-    TS_ASSERT_THROWS_NOTHING(alg.initialize())
-    TS_ASSERT(alg.isInitialized())
-    TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("InputWorkspaces", wsName))
-    TS_ASSERT_THROWS_NOTHING(
-        alg.setPropertyValue("OutputWorkspace", m_outputWSName))
-    TS_ASSERT_THROWS_NOTHING(alg.setProperty("Efficiencies", effWS))
-    TS_ASSERT_THROWS_NOTHING(alg.setProperty("Flippers", "0"))
-    TS_ASSERT_THROWS_NOTHING(alg.execute())
-    TS_ASSERT(alg.isExecuted())
-    WorkspaceGroup_sptr outputWS = alg.getProperty("OutputWorkspace");
-    TS_ASSERT(outputWS)
-    TS_ASSERT_EQUALS(outputWS->getNumberOfEntries(), 1)
-    const auto P1 = effWS->y(2).front();
-    const auto P1e = effWS->e(2).front();
-    const auto P2 = effWS->y(3).front();
-    const auto P2e = effWS->e(3).front();
-    const double y{ws00->y(0).front()};
-    const auto inverted = 1. / (1. - P2 - P1 + 2. * P1 * P2);
-    const auto expected = inverted * y;
-    const double e{ws00->e(0).front()};
-    const auto errorP1 = P1e * y * (2. * P1 - 1.) * inverted * inverted;
-    const auto errorP2 = P2e * y * (2. * P2 - 1.) * inverted * inverted;
-    const auto errorY = e * e * inverted * inverted;
-    const auto expectedError =
-        std::sqrt(errorP1 * errorP1 + errorP2 * errorP2 + errorY);
-    MatrixWorkspace_sptr ppWS = boost::dynamic_pointer_cast<MatrixWorkspace>(
-        outputWS->getItem(m_outputWSName + std::string("_++")));
-    TS_ASSERT(ppWS)
-    TS_ASSERT_EQUALS(ppWS->getNumberHistograms(), nHist)
-    for (size_t j = 0; j != nHist; ++j) {
-      const auto &ppX = ppWS->x(j);
-      const auto &ppY = ppWS->y(j);
-      const auto &ppE = ppWS->e(j);
-      TS_ASSERT_EQUALS(ppY.size(), nBins)
-      for (size_t k = 0; k != nBins; ++k) {
-        TS_ASSERT_EQUALS(ppX[k], edges[k])
-        TS_ASSERT_DELTA(ppY[k], expected, 1e-12)
-        TS_ASSERT_DELTA(ppE[k], expectedError, 1e-12)
-      }
-    }
-  }
-
-  void test_FailureWhenEfficiencyHistogramIsMissing() {
-    using namespace Mantid::API;
-    using namespace Mantid::DataObjects;
-    using namespace Mantid::HistogramData;
-    using namespace Mantid::Kernel;
-    BinEdges edges{0.3, 0.6, 0.9, 1.2};
-    Counts counts{0., 0., 0.};
-    MatrixWorkspace_sptr ws00 =
-        create<Workspace2D>(1, Histogram(edges, counts));
-    const std::string wsName{"ws00"};
-    AnalysisDataService::Instance().addOrReplace(wsName, ws00);
-    auto effWS = idealEfficiencies(edges);
-    // Rename F1 to something else.
-    auto axis = make_unique<TextAxis>(4);
-    axis->setLabel(0, "__wrong_histogram_label");
-    axis->setLabel(1, "F2");
-    axis->setLabel(2, "P1");
-    axis->setLabel(3, "P2");
-    effWS->replaceAxis(1, axis.release());
+    alg.initialize();
+    alg.setProperty("OutputWorkspace", "out");
+    alg.setProperty("InputWorkspaceGroup", createWorkspaceGroup(4));
+    alg.setProperty("InputWorkspaces", createWorkspacesInADS(4));
+    alg.setProperty("Efficiencies", createEfficiencies("Wildes"));
+    // Error: Input workspaces must be given either as a workspace group or a
+    // list of names
+    TS_ASSERT_THROWS(alg.execute(), std::invalid_argument);
+  }
+  void test_input_ws_wildes_wrong_size() {
     PolarizationEfficiencyCor alg;
-    alg.setChild(true);
     alg.setRethrows(true);
-    TS_ASSERT_THROWS_NOTHING(alg.initialize())
-    TS_ASSERT(alg.isInitialized())
-    TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("InputWorkspaces", wsName))
-    TS_ASSERT_THROWS_NOTHING(
-        alg.setPropertyValue("OutputWorkspace", m_outputWSName))
-    TS_ASSERT_THROWS_NOTHING(alg.setProperty("Efficiencies", effWS))
-    TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("Flippers", "0"))
-    TS_ASSERT_THROWS(alg.execute(), std::runtime_error)
-    TS_ASSERT(!alg.isExecuted())
+    alg.initialize();
+    alg.setProperty("OutputWorkspace", "out");
+    alg.setProperty("InputWorkspaces", createWorkspacesInADS(2));
+    alg.setProperty("CorrectionMethod", "Wildes");
+    alg.setProperty("Efficiencies", createEfficiencies("Wildes"));
+    // Error: Some invalid Properties found
+    TS_ASSERT_THROWS(alg.execute(), std::runtime_error);
   }
 
-  void test_FailureWhenEfficiencyXDataMismatches() {
-    using namespace Mantid::API;
-    using namespace Mantid::DataObjects;
-    using namespace Mantid::HistogramData;
-    using namespace Mantid::Kernel;
-    BinEdges edges{0.3, 0.6, 0.9, 1.2};
-    Counts counts{0., 0., 0.};
-    MatrixWorkspace_sptr ws00 =
-        create<Workspace2D>(1, Histogram(edges, counts));
-    const std::string wsName{"ws00"};
-    AnalysisDataService::Instance().addOrReplace(wsName, ws00);
-    auto effWS = idealEfficiencies(edges);
-    // Change a bin edge of one of the histograms.
-    auto &xs = effWS->mutableX(0);
-    xs[xs.size() / 2] *= 1.01;
+  void test_efficiencies_fredrikze_wrong_efficiencies() {
     PolarizationEfficiencyCor alg;
-    alg.setChild(true);
     alg.setRethrows(true);
-    TS_ASSERT_THROWS_NOTHING(alg.initialize())
-    TS_ASSERT(alg.isInitialized())
-    TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("InputWorkspaces", wsName))
-    TS_ASSERT_THROWS_NOTHING(
-        alg.setPropertyValue("OutputWorkspace", m_outputWSName))
-    TS_ASSERT_THROWS_NOTHING(alg.setProperty("Efficiencies", effWS))
-    TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("Flippers", "0"))
-    TS_ASSERT_THROWS(alg.execute(), std::runtime_error)
-    TS_ASSERT(!alg.isExecuted())
-  }
-
-  void test_FailureWhenNumberOfHistogramsInInputWorkspacesMismatch() {
-    using namespace Mantid::API;
-    using namespace Mantid::DataObjects;
-    using namespace Mantid::HistogramData;
-    using namespace Mantid::Kernel;
-    constexpr size_t nHist{2};
-    BinEdges edges{0.3, 0.6, 0.9, 1.2};
-    Counts counts{0., 0., 0.};
-    MatrixWorkspace_sptr ws00 =
-        create<Workspace2D>(nHist, Histogram(edges, counts));
-    MatrixWorkspace_sptr ws01 = ws00->clone();
-    MatrixWorkspace_sptr ws10 =
-        create<Workspace2D>(nHist + 1, Histogram(edges, counts));
-    MatrixWorkspace_sptr ws11 = ws00->clone();
-    const std::vector<std::string> wsNames{{"ws00", "ws01", "ws10", "ws11"}};
-    const std::array<MatrixWorkspace_sptr, 4> wsList{{ws00, ws01, ws10, ws11}};
-    for (size_t i = 0; i != 4; ++i) {
-      AnalysisDataService::Instance().addOrReplace(wsNames[i], wsList[i]);
-    }
-    auto effWS = idealEfficiencies(edges);
+    alg.initialize();
+    alg.setProperty("OutputWorkspace", "out");
+    alg.setProperty("InputWorkspaceGroup", createWorkspaceGroup(4));
+    alg.setProperty("CorrectionMethod", "Fredrikze");
+    alg.setProperty("Efficiencies", createEfficiencies("Wildes"));
+    // Error: Efficiencey property not found: Rho;
+    TS_ASSERT_THROWS(alg.execute(), std::invalid_argument);
+  }
+  void test_efficiencies_wildes_wrong_efficiencies() {
     PolarizationEfficiencyCor alg;
-    alg.setChild(true);
     alg.setRethrows(true);
-    TS_ASSERT_THROWS_NOTHING(alg.initialize())
-    TS_ASSERT(alg.isInitialized())
-    TS_ASSERT_THROWS_NOTHING(alg.setProperty("InputWorkspaces", wsNames))
-    TS_ASSERT_THROWS_NOTHING(
-        alg.setPropertyValue("OutputWorkspace", m_outputWSName))
-    TS_ASSERT_THROWS_NOTHING(alg.setProperty("Efficiencies", effWS))
-    TS_ASSERT_THROWS(alg.execute(), std::runtime_error)
-    TS_ASSERT(!alg.isExecuted())
-  }
-
-  void test_FailureWhenAnInputWorkspaceIsMissing() {
-    using namespace Mantid::API;
-    using namespace Mantid::DataObjects;
-    using namespace Mantid::HistogramData;
-    using namespace Mantid::Kernel;
-    constexpr size_t nHist{2};
-    BinEdges edges{0.3, 0.6, 0.9, 1.2};
-    Counts counts{0., 0., 0.};
-    MatrixWorkspace_sptr ws00 =
-        create<Workspace2D>(nHist, Histogram(edges, counts));
-    MatrixWorkspace_sptr ws01 = ws00->clone();
-    MatrixWorkspace_sptr ws11 = ws00->clone();
-    AnalysisDataService::Instance().addOrReplace("ws00", ws00);
-    AnalysisDataService::Instance().addOrReplace("ws01", ws01);
-    AnalysisDataService::Instance().addOrReplace("ws11", ws11);
+    alg.initialize();
+    alg.setProperty("OutputWorkspace", "out");
+    alg.setProperty("InputWorkspaces", createWorkspacesInADS(4));
+    alg.setProperty("CorrectionMethod", "Wildes");
+    alg.setProperty("Efficiencies", createEfficiencies("Fredrikze"));
+    // Error: Some invalid Properties found
+    TS_ASSERT_THROWS(alg.execute(), std::runtime_error);
+  }
+  void test_flippers_full() {
     PolarizationEfficiencyCor alg;
-    alg.setChild(true);
     alg.setRethrows(true);
-    TS_ASSERT_THROWS_NOTHING(alg.initialize())
-    TS_ASSERT(alg.isInitialized())
-    TS_ASSERT_THROWS(
-        alg.setPropertyValue("InputWorkspaces", "ws00, ws01, ws10, ws11"),
-        std::invalid_argument)
-  }
-
-private:
-  const std::string m_outputWSName{"output"};
-
-  Mantid::API::MatrixWorkspace_sptr
-  efficiencies(const Mantid::HistogramData::BinEdges &edges) {
-    using namespace Mantid::API;
-    using namespace Mantid::DataObjects;
-    using namespace Mantid::HistogramData;
-    using namespace Mantid::Kernel;
-    const auto nBins = edges.size() - 1;
-    constexpr size_t nHist{4};
-    Counts counts(nBins, 0.0);
-    MatrixWorkspace_sptr ws =
-        create<Workspace2D>(nHist, Histogram(edges, counts));
-    ws->mutableY(0) = 0.95;
-    ws->mutableE(0) = 0.01;
-    ws->mutableY(1) = 0.92;
-    ws->mutableE(1) = 0.02;
-    ws->mutableY(2) = 0.05;
-    ws->mutableE(2) = 0.015;
-    ws->mutableY(3) = 0.04;
-    ws->mutableE(3) = 0.03;
-    auto axis = make_unique<TextAxis>(4);
-    axis->setLabel(0, "F1");
-    axis->setLabel(1, "F2");
-    axis->setLabel(2, "P1");
-    axis->setLabel(3, "P2");
-    ws->replaceAxis(1, axis.release());
-    return ws;
-  }
-
-  Mantid::API::MatrixWorkspace_sptr
-  idealEfficiencies(const Mantid::HistogramData::BinEdges &edges) {
-    using namespace Mantid::API;
-    using namespace Mantid::DataObjects;
-    using namespace Mantid::HistogramData;
-    using namespace Mantid::Kernel;
-    const auto nBins = edges.size() - 1;
-    constexpr size_t nHist{4};
-    Counts counts(nBins, 0.0);
-    MatrixWorkspace_sptr ws =
-        create<Workspace2D>(nHist, Histogram(edges, counts));
-    ws->mutableY(0) = 1.;
-    ws->mutableY(1) = 1.;
-    auto axis = make_unique<TextAxis>(4);
-    axis->setLabel(0, "F1");
-    axis->setLabel(1, "F2");
-    axis->setLabel(2, "P1");
-    axis->setLabel(3, "P2");
-    ws->replaceAxis(1, axis.release());
-    return ws;
-  }
-
-  void idealThreeInputsTest(const std::string &missingFlipperConf) {
-    using namespace Mantid::API;
-    using namespace Mantid::DataObjects;
-    using namespace Mantid::HistogramData;
-    using namespace Mantid::Kernel;
-    constexpr size_t nBins{3};
-    constexpr size_t nHist{2};
-    BinEdges edges{0.3, 0.6, 0.9, 1.2};
-    const double yVal = 2.3;
-    Counts counts{yVal, 4.2 * yVal, yVal};
-    MatrixWorkspace_sptr ws00 =
-        create<Workspace2D>(nHist, Histogram(edges, counts));
-    MatrixWorkspace_sptr wsXX = ws00->clone();
-    MatrixWorkspace_sptr ws11 = ws00->clone();
-    const std::vector<std::string> wsNames{{"ws00", "wsXX", "ws11"}};
-    const std::array<MatrixWorkspace_sptr, 3> wsList{{ws00, wsXX, ws11}};
-    for (size_t i = 0; i != 3; ++i) {
-      for (size_t j = 0; j != nHist; ++j) {
-        wsList[i]->mutableY(j) *= static_cast<double>(i + 1);
-        wsList[i]->mutableE(j) *= static_cast<double>(i + 1);
-      }
-      AnalysisDataService::Instance().addOrReplace(wsNames[i], wsList[i]);
-    }
-    auto effWS = idealEfficiencies(edges);
+    alg.initialize();
+    alg.setProperty("OutputWorkspace", "out");
+    alg.setProperty("InputWorkspaces", createWorkspacesInADS(4));
+    alg.setProperty("CorrectionMethod", "Wildes");
+    alg.setProperty("Efficiencies", createEfficiencies("Wildes"));
+    alg.setProperty("Flippers", "00, 01, 10, 11");
+    alg.execute();
+    WorkspaceGroup_sptr out =
+        AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>("out");
+    TS_ASSERT_EQUALS(out->size(), 4);
+  }
+  void test_flippers_missing_01() {
     PolarizationEfficiencyCor alg;
-    alg.setChild(true);
     alg.setRethrows(true);
-    TS_ASSERT_THROWS_NOTHING(alg.initialize())
-    TS_ASSERT(alg.isInitialized())
-    TS_ASSERT_THROWS_NOTHING(alg.setProperty("InputWorkspaces", wsNames))
-    TS_ASSERT_THROWS_NOTHING(
-        alg.setPropertyValue("OutputWorkspace", m_outputWSName))
-    TS_ASSERT_THROWS_NOTHING(alg.setProperty("Efficiencies", effWS))
-    const std::string presentFlipperConf =
-        missingFlipperConf == "01" ? "10" : "01";
-    const std::string flipperConf = "00, " + presentFlipperConf + ", 11";
-    TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("Flippers", flipperConf))
-    TS_ASSERT_THROWS_NOTHING(alg.execute())
-    TS_ASSERT(alg.isExecuted())
-    WorkspaceGroup_sptr outputWS = alg.getProperty("OutputWorkspace");
-    TS_ASSERT(outputWS)
-    TS_ASSERT_EQUALS(outputWS->getNumberOfEntries(), 4)
-    const std::array<std::string, 4> POL_DIRS{{"++", "+-", "-+", "--"}};
-    for (size_t i = 0; i != 4; ++i) {
-      const auto &dir = POL_DIRS[i];
-      const std::string wsName = m_outputWSName + std::string("_") + dir;
-      MatrixWorkspace_sptr ws = boost::dynamic_pointer_cast<MatrixWorkspace>(
-          outputWS->getItem(wsName));
-      TS_ASSERT(ws)
-      TS_ASSERT_EQUALS(ws->getNumberHistograms(), nHist)
-      for (size_t j = 0; j != nHist; ++j) {
-        const auto &xs = ws->x(j);
-        const auto &ys = ws->y(j);
-        const auto &es = ws->e(j);
-        TS_ASSERT_EQUALS(ys.size(), nBins)
-        for (size_t k = 0; k != nBins; ++k) {
-          const double y = counts[k];
-          const double expected = [y, &dir]() {
-            if (dir == "++") {
-              return y;
-            } else if (dir == "--") {
-              return 3. * y;
-            } else {
-              return 2. * y;
-            }
-          }();
-          const double expectedError = [y, &dir, &missingFlipperConf]() {
-            if (dir == "++") {
-              return std::sqrt(y);
-            } else if (dir == "--") {
-              return 3. * std::sqrt(y);
-            } else {
-              std::string conf = std::string(dir.front() == '+' ? "0" : "1") +
-                                 std::string(dir.back() == '+' ? "0" : "1");
-              if (conf != missingFlipperConf) {
-                return 2. * std::sqrt(y);
-              } else {
-                return 0.;
-              }
-            }
-          }();
-          TS_ASSERT_EQUALS(xs[k], edges[k])
-          TS_ASSERT_EQUALS(ys[k], expected)
-          TS_ASSERT_EQUALS(es[k], expectedError)
-        }
-      }
-    }
-  }
-
-  void threeInputsTest(const std::string &missingFlipperConf) {
-    using namespace Mantid::API;
-    using namespace Mantid::DataObjects;
-    using namespace Mantid::HistogramData;
-    using namespace Mantid::Kernel;
-    constexpr size_t nHist{2};
-    BinEdges edges{0.3, 0.6, 0.9, 1.2};
-    const double yVal = 2.3;
-    Counts counts{yVal, yVal, yVal};
-    MatrixWorkspace_sptr ws00 =
-        create<Workspace2D>(nHist, Histogram(edges, counts));
-    MatrixWorkspace_sptr ws01 =
-        missingFlipperConf == "01" ? nullptr : ws00->clone();
-    MatrixWorkspace_sptr ws10 =
-        missingFlipperConf == "10" ? nullptr : ws00->clone();
-    MatrixWorkspace_sptr ws11 = ws00->clone();
-    const std::vector<std::string> wsNames{{"ws00", "wsXX", "ws11"}};
-    const std::array<MatrixWorkspace_sptr, 3> wsList{
-        {ws00, ws01 != nullptr ? ws01 : ws10, ws11}};
-    for (size_t i = 0; i != 3; ++i) {
-      for (size_t j = 0; j != nHist; ++j) {
-        wsList[i]->mutableY(j) *= static_cast<double>(i + 1);
-        wsList[i]->mutableE(j) *= static_cast<double>(i + 1);
-      }
-      AnalysisDataService::Instance().addOrReplace(wsNames[i], wsList[i]);
-    }
-    auto effWS = efficiencies(edges);
+    alg.initialize();
+    alg.setProperty("OutputWorkspace", "out");
+    alg.setProperty("InputWorkspaces", createWorkspacesInADS(3));
+    alg.setProperty("CorrectionMethod", "Wildes");
+    alg.setProperty("Efficiencies", createEfficiencies("Wildes"));
+    alg.setProperty("Flippers", "00, 10, 11");
+    alg.execute();
+    WorkspaceGroup_sptr out =
+        AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>("out");
+    TS_ASSERT_EQUALS(out->size(), 4);
+  }
+  void test_flippers_missing_10() {
+    PolarizationEfficiencyCor alg;
+    alg.setRethrows(true);
+    alg.initialize();
+    alg.setProperty("OutputWorkspace", "out");
+    alg.setProperty("InputWorkspaces", createWorkspacesInADS(3));
+    alg.setProperty("CorrectionMethod", "Wildes");
+    alg.setProperty("Efficiencies", createEfficiencies("Wildes"));
+    alg.setProperty("Flippers", "00, 01, 11");
+    alg.execute();
+    WorkspaceGroup_sptr out =
+        AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>("out");
+    TS_ASSERT_EQUALS(out->size(), 4);
+  }
+  void test_flippers_missing_0110() {
+    PolarizationEfficiencyCor alg;
+    alg.setRethrows(true);
+    alg.initialize();
+    alg.setProperty("OutputWorkspace", "out");
+    alg.setProperty("InputWorkspaces", createWorkspacesInADS(2));
+    alg.setProperty("CorrectionMethod", "Wildes");
+    alg.setProperty("Efficiencies", createEfficiencies("Wildes"));
+    alg.setProperty("Flippers", "00, 11");
+    alg.execute();
+    WorkspaceGroup_sptr out =
+        AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>("out");
+    TS_ASSERT_EQUALS(out->size(), 4);
+  }
+  void test_flippers_no_analyser() {
+    PolarizationEfficiencyCor alg;
+    alg.setRethrows(true);
+    alg.initialize();
+    alg.setProperty("OutputWorkspace", "out");
+    alg.setProperty("InputWorkspaces", createWorkspacesInADS(2));
+    alg.setProperty("CorrectionMethod", "Wildes");
+    alg.setProperty("Efficiencies", createEfficiencies("Wildes"));
+    alg.setProperty("Flippers", "0, 1");
+    alg.execute();
+    WorkspaceGroup_sptr out =
+        AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>("out");
+    TS_ASSERT_EQUALS(out->size(), 2);
+  }
+  void test_flippers_direct_beam() {
+    PolarizationEfficiencyCor alg;
+    alg.setRethrows(true);
+    alg.initialize();
+    alg.setProperty("OutputWorkspace", "out");
+    alg.setProperty("InputWorkspaces", createWorkspacesInADS(1));
+    alg.setProperty("CorrectionMethod", "Wildes");
+    alg.setProperty("Efficiencies", createEfficiencies("Wildes"));
+    alg.setProperty("Flippers", "0");
+    alg.execute();
+    WorkspaceGroup_sptr out =
+        AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>("out");
+    TS_ASSERT_EQUALS(out->size(), 1);
+  }
+  void test_flippers_wrong_flippers() {
     PolarizationEfficiencyCor alg;
-    alg.setChild(true);
     alg.setRethrows(true);
-    TS_ASSERT_THROWS_NOTHING(alg.initialize())
-    TS_ASSERT(alg.isInitialized())
-    TS_ASSERT_THROWS_NOTHING(alg.setProperty("InputWorkspaces", wsNames))
-    TS_ASSERT_THROWS_NOTHING(
-        alg.setPropertyValue("OutputWorkspace", m_outputWSName))
-    TS_ASSERT_THROWS_NOTHING(alg.setProperty("Efficiencies", effWS))
-    const std::string presentFlipperConf =
-        missingFlipperConf == "01" ? "10" : "01";
-    const std::string flipperConf = "00, " + presentFlipperConf + ", 11";
-    TS_ASSERT_THROWS_NOTHING(alg.setProperty("Flippers", flipperConf))
-    TS_ASSERT_THROWS_NOTHING(alg.execute())
-    TS_ASSERT(alg.isExecuted())
-    WorkspaceGroup_sptr outputWS = alg.getProperty("OutputWorkspace");
-    TS_ASSERT(outputWS)
-    TS_ASSERT_EQUALS(outputWS->getNumberOfEntries(), 4)
-    solveMissingIntensity(ws00, ws01, ws10, ws11, effWS);
-    fullFourInputsResultsCheck(outputWS, ws00, ws01, ws10, ws11, effWS);
+    alg.initialize();
+    alg.setProperty("OutputWorkspace", "out");
+    alg.setProperty("InputWorkspaces", createWorkspacesInADS(4));
+    alg.setProperty("CorrectionMethod", "Wildes");
+    alg.setProperty("Efficiencies", createEfficiencies("Wildes"));
+    alg.setProperty("Flippers", "00, 10, 11");
+    // Error: Some invalid Properties found
+    TS_ASSERT_THROWS(alg.execute(), std::runtime_error);
+  }
+  void test_flippers_wildes_no_pnr() {
+    PolarizationEfficiencyCor alg;
+    alg.setRethrows(true);
+    alg.initialize();
+    alg.setProperty("OutputWorkspace", "out");
+    alg.setProperty("InputWorkspaces", createWorkspacesInADS(4));
+    alg.setProperty("CorrectionMethod", "Wildes");
+    alg.setProperty("Efficiencies", createEfficiencies("Wildes"));
+    alg.setProperty("PolarizationAnalysis", "PNR");
+    // Error: Property PolarizationAnalysis canot be used with the Wildes
+    // method
+    TS_ASSERT_THROWS(alg.execute(), std::invalid_argument);
+  }
+  void test_flippers_wildes_no_pa() {
+    PolarizationEfficiencyCor alg;
+    alg.setRethrows(true);
+    alg.initialize();
+    alg.setProperty("OutputWorkspace", "out");
+    alg.setProperty("InputWorkspaces", createWorkspacesInADS(4));
+    alg.setProperty("CorrectionMethod", "Wildes");
+    alg.setProperty("Efficiencies", createEfficiencies("Wildes"));
+    alg.setProperty("PolarizationAnalysis", "PA");
+    // Error: Property PolarizationAnalysis canot be used with the Wildes
+    // method
+    TS_ASSERT_THROWS(alg.execute(), std::invalid_argument);
+  }
+  void test_polarization_analysis_pnr() {
+    PolarizationEfficiencyCor alg;
+    alg.setRethrows(true);
+    alg.initialize();
+    alg.setProperty("OutputWorkspace", "out");
+    alg.setProperty("InputWorkspaceGroup", createWorkspaceGroup(2));
+    alg.setProperty("CorrectionMethod", "Fredrikze");
+    alg.setProperty("Efficiencies", createEfficiencies("Fredrikze"));
+    alg.setProperty("PolarizationAnalysis", "PNR");
+    alg.execute();
+    WorkspaceGroup_sptr out =
+        AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>("out");
+    TS_ASSERT_EQUALS(out->size(), 2);
+  }
+  void test_polarization_analysis_pa() {
+    PolarizationEfficiencyCor alg;
+    alg.setRethrows(true);
+    alg.initialize();
+    alg.setProperty("OutputWorkspace", "out");
+    alg.setProperty("InputWorkspaceGroup", createWorkspaceGroup(4));
+    alg.setProperty("CorrectionMethod", "Fredrikze");
+    alg.setProperty("Efficiencies", createEfficiencies("Fredrikze"));
+    alg.setProperty("PolarizationAnalysis", "PA");
+    alg.execute();
+    WorkspaceGroup_sptr out =
+        AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>("out");
+    TS_ASSERT_EQUALS(out->size(), 4);
+  }
+  void test_polarization_analysis_wrong_group_size() {
+    PolarizationEfficiencyCor alg;
+    alg.setRethrows(true);
+    alg.initialize();
+    alg.setProperty("OutputWorkspace", "out");
+    alg.setProperty("InputWorkspaceGroup", createWorkspaceGroup(4));
+    alg.setProperty("CorrectionMethod", "Fredrikze");
+    alg.setProperty("Efficiencies", createEfficiencies("Fredrikze"));
+    alg.setProperty("PolarizationAnalysis", "PNR");
+    // Error: For PNR analysis, input group must have 2 periods
+    TS_ASSERT_THROWS(alg.execute(), std::invalid_argument);
+  }
+  void test_polarization_analysis_no_flippers() {
+    PolarizationEfficiencyCor alg;
+    alg.setRethrows(true);
+    alg.initialize();
+    alg.setProperty("OutputWorkspace", "out");
+    alg.setProperty("InputWorkspaceGroup", createWorkspaceGroup(4));
+    alg.setProperty("CorrectionMethod", "Fredrikze");
+    alg.setProperty("Efficiencies", createEfficiencies("Fredrikze"));
+    alg.setProperty("Flippers", "00, 01, 10, 11");
+    // Error: Property Flippers canot be used with the Fredrikze method
+    TS_ASSERT_THROWS(alg.execute(), std::invalid_argument);
   }
 
-  void fullFourInputsResultsCheck(Mantid::API::WorkspaceGroup_sptr &outputWS,
-                                  Mantid::API::MatrixWorkspace_sptr &ws00,
-                                  Mantid::API::MatrixWorkspace_sptr &ws01,
-                                  Mantid::API::MatrixWorkspace_sptr &ws10,
-                                  Mantid::API::MatrixWorkspace_sptr &ws11,
-                                  Mantid::API::MatrixWorkspace_sptr &effWS) {
-    using namespace Mantid::API;
-    const auto nHist = ws00->getNumberHistograms();
-    const auto nBins = ws00->y(0).size();
-    const auto edges = ws00->binEdges(0);
-    const double F1 = effWS->y(0).front();
-    const double F1e = effWS->e(0).front();
-    const double F2 = effWS->y(1).front();
-    const double F2e = effWS->e(1).front();
-    const double P1 = effWS->y(2).front();
-    const double P1e = effWS->e(2).front();
-    const double P2 = effWS->y(3).front();
-    const double P2e = effWS->e(3).front();
-    const Eigen::Vector4d y{ws00->y(0).front(), ws01->y(0).front(),
-                            ws10->y(0).front(), ws11->y(0).front()};
-    const auto expected = correction(y, F1, F2, P1, P2);
-    const Eigen::Vector4d e{ws00->e(0).front(), ws01->e(0).front(),
-                            ws10->e(0).front(), ws11->e(0).front()};
-    const auto expectedError = error(y, e, F1, F1e, F2, F2e, P1, P1e, P2, P2e);
-    MatrixWorkspace_sptr ppWS = boost::dynamic_pointer_cast<MatrixWorkspace>(
-        outputWS->getItem(m_outputWSName + std::string("_++")));
-    MatrixWorkspace_sptr pmWS = boost::dynamic_pointer_cast<MatrixWorkspace>(
-        outputWS->getItem(m_outputWSName + std::string("_+-")));
-    MatrixWorkspace_sptr mpWS = boost::dynamic_pointer_cast<MatrixWorkspace>(
-        outputWS->getItem(m_outputWSName + std::string("_-+")));
-    MatrixWorkspace_sptr mmWS = boost::dynamic_pointer_cast<MatrixWorkspace>(
-        outputWS->getItem(m_outputWSName + std::string("_--")));
-    TS_ASSERT(ppWS)
-    TS_ASSERT(pmWS)
-    TS_ASSERT(mpWS)
-    TS_ASSERT(mmWS)
-    TS_ASSERT_EQUALS(ppWS->getNumberHistograms(), nHist)
-    TS_ASSERT_EQUALS(pmWS->getNumberHistograms(), nHist)
-    TS_ASSERT_EQUALS(mpWS->getNumberHistograms(), nHist)
-    TS_ASSERT_EQUALS(mmWS->getNumberHistograms(), nHist)
-    for (size_t j = 0; j != nHist; ++j) {
-      const auto &ppX = ppWS->x(j);
-      const auto &ppY = ppWS->y(j);
-      const auto &ppE = ppWS->e(j);
-      const auto &pmX = pmWS->x(j);
-      const auto &pmY = pmWS->y(j);
-      const auto &pmE = pmWS->e(j);
-      const auto &mpX = mpWS->x(j);
-      const auto &mpY = mpWS->y(j);
-      const auto &mpE = mpWS->e(j);
-      const auto &mmX = mmWS->x(j);
-      const auto &mmY = mmWS->y(j);
-      const auto &mmE = mmWS->e(j);
-      TS_ASSERT_EQUALS(ppY.size(), nBins)
-      TS_ASSERT_EQUALS(pmY.size(), nBins)
-      TS_ASSERT_EQUALS(mpY.size(), nBins)
-      TS_ASSERT_EQUALS(mmY.size(), nBins)
-      for (size_t k = 0; k != nBins; ++k) {
-        TS_ASSERT_EQUALS(ppX[k], edges[k])
-        TS_ASSERT_EQUALS(pmX[k], edges[k])
-        TS_ASSERT_EQUALS(mpX[k], edges[k])
-        TS_ASSERT_EQUALS(mmX[k], edges[k])
-        TS_ASSERT_DELTA(ppY[k], expected[0], 1e-12)
-        TS_ASSERT_DELTA(pmY[k], expected[1], 1e-12)
-        TS_ASSERT_DELTA(mpY[k], expected[2], 1e-12)
-        TS_ASSERT_DELTA(mmY[k], expected[3], 1e-12)
-        TS_ASSERT_DELTA(ppE[k], expectedError[0], 1e-12)
-        TS_ASSERT_DELTA(pmE[k], expectedError[1], 1e-12)
-        TS_ASSERT_DELTA(mpE[k], expectedError[2], 1e-12)
-        TS_ASSERT_DELTA(mmE[k], expectedError[3], 1e-12)
-      }
+  void test_histo() {
+    PolarizationEfficiencyCor alg;
+    alg.setRethrows(true);
+    alg.initialize();
+    alg.setProperty("OutputWorkspace", "out");
+    alg.setProperty("InputWorkspaces", createWorkspacesInADS(4));
+    alg.setProperty("CorrectionMethod", "Wildes");
+    alg.setProperty("Efficiencies", createEfficiencies("histo"));
+    alg.execute();
+    WorkspaceGroup_sptr out =
+        AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>("out");
+    TS_ASSERT_EQUALS(out->size(), 4);
+  }
+
+  void test_points() {
+    PolarizationEfficiencyCor alg;
+    auto const inputs = createWorkspacesInADS(4);
+    alg.setRethrows(true);
+    alg.initialize();
+    alg.setProperty("OutputWorkspace", "out");
+    alg.setProperty("InputWorkspaces", inputs);
+    alg.setProperty("CorrectionMethod", "Wildes");
+    alg.setProperty("Efficiencies", createEfficiencies("points"));
+    alg.execute();
+    WorkspaceGroup_sptr out =
+        AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>("out");
+    TS_ASSERT_EQUALS(out->size(), 4);
+
+    for (size_t i = 0; i < out->size(); ++i) {
+      auto ws = AnalysisDataService::Instance().retrieve(inputs[i]);
+      auto checkAlg =
+          AlgorithmManager::Instance().createUnmanaged("CompareWorkspaces");
+      checkAlg->initialize();
+      checkAlg->setChild(true);
+      checkAlg->setProperty("Workspace1", ws);
+      checkAlg->setProperty("Workspace2", out->getItem(i));
+      checkAlg->setProperty("Tolerance", 3e-16);
+      checkAlg->execute();
+      TS_ASSERT(checkAlg->getProperty("Result"));
     }
   }
-  Eigen::Matrix4d invertedF1(const double f1) {
-    Eigen::Matrix4d m;
-    m << f1, 0., 0., 0., 0., f1, 0., 0., f1 - 1., 0., 1., 0., 0., f1 - 1., 0.,
-        1.;
-    m *= 1. / f1;
-    return m;
-  }
-
-  Eigen::Matrix4d invertedF1Derivative(const double f1) {
-    Eigen::Matrix4d m;
-    m << 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., -1., 0., 0., 1., 0., -1.;
-    m *= 1. / (f1 * f1);
-    return m;
-  }
-
-  Eigen::Matrix4d invertedF2(const double f2) {
-    Eigen::Matrix4d m;
-    m << f2, 0., 0., 0., f2 - 1., 1., 0., 0., 0., 0., f2, 0., 0., 0., f2 - 1.,
-        1.;
-    m *= 1. / f2;
-    return m;
-  }
-
-  Eigen::Matrix4d invertedF2Derivative(const double f2) {
-    Eigen::Matrix4d m;
-    m << 0., 0., 0., 0., 1., -1., 0., 0., 0., 0., 0., 0., 0., 0., 1., -1.;
-    m *= 1. / (f2 * f2);
-    return m;
-  }
-
-  Eigen::Matrix4d invertedP1(const double p1) {
-    Eigen::Matrix4d m;
-    m << p1 - 1., 0., p1, 0., 0., p1 - 1., 0., p1, p1, 0., p1 - 1., 0., 0., p1,
-        0., p1 - 1.;
-    m *= 1. / (2. * p1 - 1.);
-    return m;
-  }
 
-  Eigen::Matrix4d invertedP1Derivative(const double p1) {
-    Eigen::Matrix4d m;
-    m << 1., 0., -1., 0., 0., 1., 0., -1., -1., 0., 1., 0., 0., -1., 0., 1.;
-    m *= 1. / (2. * p1 - 1.) / (2. * p1 - 1.);
-    return m;
-  }
-
-  Eigen::Matrix4d invertedP2(const double p2) {
-    Eigen::Matrix4d m;
-    m << p2 - 1., p2, 0., 0., p2, p2 - 1., 0., 0., 0., 0., p2 - 1., p2, 0., 0.,
-        p2, p2 - 1.;
-    m *= 1. / (2. * p2 - 1.);
-    return m;
-  }
-
-  Eigen::Matrix4d invertedP2Derivative(const double p2) {
-    Eigen::Matrix4d m;
-    m << 1., -1., 0., 0., -1., 1., 0., 0., 0., 0., 1., -1., 0., 0., -1., 1.;
-    m *= 1. / (2. * p2 - 1.) / (2. * p2 - 1.);
-    return m;
-  }
-
-  Eigen::Vector4d correction(const Eigen::Vector4d &y, const double f1,
-                             const double f2, const double p1,
-                             const double p2) {
-    const Eigen::Matrix4d F1 = invertedF1(f1);
-    const Eigen::Matrix4d F2 = invertedF2(f2);
-    const Eigen::Matrix4d P1 = invertedP1(p1);
-    const Eigen::Matrix4d P2 = invertedP2(p2);
-    const Eigen::Matrix4d inverted = (P2 * P1 * F2 * F1).matrix();
-    return (inverted * y).matrix();
-  }
-
-  Eigen::Vector4d error(const Eigen::Vector4d &y, const Eigen::Vector4d &e,
-                        const double f1, const double f1e, const double f2,
-                        const double f2e, const double p1, const double p1e,
-                        const double p2, const double p2e) {
-    const Eigen::Matrix4d F1 = invertedF1(f1);
-    const Eigen::Matrix4d dF1 = f1e * invertedF1Derivative(f1);
-    const Eigen::Matrix4d F2 = invertedF2(f2);
-    const Eigen::Matrix4d dF2 = f2e * invertedF2Derivative(f2);
-    const Eigen::Matrix4d P1 = invertedP1(p1);
-    const Eigen::Matrix4d dP1 = p1e * invertedP1Derivative(p1);
-    const Eigen::Matrix4d P2 = invertedP2(p2);
-    const Eigen::Matrix4d dP2 = p2e * invertedP2Derivative(p2);
-    const auto p2Error = (dP2 * P1 * F2 * F1 * y).array();
-    const auto p1Error = (P2 * dP1 * F2 * F1 * y).array();
-    const auto f2Error = (P2 * P1 * dF2 * F1 * y).array();
-    const auto f1Error = (P2 * P1 * F2 * dF1 * y).array();
-    const auto inverted = (P2 * P1 * F2 * F1).array();
-    const auto yError = ((inverted * inverted).matrix() *
-                         (e.array() * e.array()).matrix()).array();
-    return (p2Error * p2Error + p1Error * p1Error + f2Error * f2Error +
-            f1Error * f1Error + yError)
-        .sqrt()
-        .matrix();
-  }
-
-  Eigen::Vector2d correctionWithoutAnalyzer(const Eigen::Vector2d &y,
-                                            const double f1, const double p1) {
-    Eigen::Matrix2d F1;
-    F1 << f1, 0., f1 - 1., 1.;
-    F1 *= 1. / f1;
-    Eigen::Matrix2d P1;
-    P1 << p1 - 1., p1, p1, p1 - 1.;
-    P1 *= 1. / (2. * p1 - 1.);
-    const Eigen::Matrix2d inverted = (P1 * F1).matrix();
-    return static_cast<Eigen::Vector2d>(inverted * y);
-  }
-
-  Eigen::Vector2d errorWithoutAnalyzer(const Eigen::Vector2d &y,
-                                       const Eigen::Vector2d &e,
-                                       const double f1, const double f1e,
-                                       const double p1, const double p1e) {
-    Eigen::Matrix2d F1;
-    F1 << f1, 0, f1 - 1., 1.;
-    F1 *= 1. / f1;
-    Eigen::Matrix2d dF1;
-    dF1 << 0., 0., 1., -1.;
-    dF1 *= f1e / (f1 * f1);
-    Eigen::Matrix2d P1;
-    P1 << p1 - 1., p1, p1, p1 - 1.;
-    P1 *= 1. / (2. * p1 - 1.);
-    Eigen::Matrix2d dP1;
-    dP1 << 1., -1., -1., 1.;
-    dP1 *= p1e / ((2. * p1 - 1.) * (2. * p1 - 1.));
-    const auto p1Error = (dP1 * F1 * y).array();
-    const auto f1Error = (P1 * dF1 * y).array();
-    const auto inverted = (P1 * F1).array();
-    const auto yError = ((inverted * inverted).matrix() *
-                         (e.array() * e.array()).matrix()).array();
-    return (p1Error * p1Error + f1Error * f1Error + yError).sqrt().matrix();
-  }
-
-  void solveMissingIntensity(const Mantid::API::MatrixWorkspace_sptr &ppWS,
-                             Mantid::API::MatrixWorkspace_sptr &pmWS,
-                             Mantid::API::MatrixWorkspace_sptr &mpWS,
-                             const Mantid::API::MatrixWorkspace_sptr &mmWS,
-                             const Mantid::API::MatrixWorkspace_sptr &effWS) {
-    const auto &F1 = effWS->y(0);
-    const auto &F2 = effWS->y(1);
-    const auto &P1 = effWS->y(2);
-    const auto &P2 = effWS->y(3);
-    if (!pmWS) {
-      pmWS = mpWS->clone();
-      for (size_t wsIndex = 0; wsIndex != pmWS->getNumberHistograms();
-           ++wsIndex) {
-        const auto &ppY = ppWS->y(wsIndex);
-        auto &pmY = pmWS->mutableY(wsIndex);
-        auto &pmE = pmWS->mutableE(wsIndex);
-        const auto &mpY = mpWS->y(wsIndex);
-        const auto &mmY = mmWS->y(wsIndex);
-        for (size_t binIndex = 0; binIndex != mpY.size(); ++binIndex) {
-          pmY[binIndex] =
-              -(2 * ppY[binIndex] * F2[binIndex] * P2[binIndex] -
-                P2[binIndex] * mmY[binIndex] -
-                2 * mpY[binIndex] * F2[binIndex] * P2[binIndex] +
-                mpY[binIndex] * P2[binIndex] - ppY[binIndex] * P2[binIndex] +
-                P1[binIndex] * mmY[binIndex] -
-                2 * ppY[binIndex] * F1[binIndex] * P1[binIndex] +
-                ppY[binIndex] * P1[binIndex] - P1[binIndex] * mpY[binIndex] +
-                ppY[binIndex] * F1[binIndex] + mpY[binIndex] * F2[binIndex] -
-                ppY[binIndex] * F2[binIndex]) /
-              (P2[binIndex] - P1[binIndex] + 2 * F1[binIndex] * P1[binIndex] -
-               F1[binIndex]);
-          // Error propagation is not implemented in the algorithm.
-          pmE[binIndex] = 0.;
-        }
-      }
-    } else {
-      mpWS = pmWS->clone();
-      for (size_t wsIndex = 0; wsIndex != mpWS->getNumberHistograms();
-           ++wsIndex) {
-        const auto &ppY = ppWS->y(wsIndex);
-        const auto &pmY = pmWS->y(wsIndex);
-        auto &mpY = mpWS->mutableY(wsIndex);
-        auto &mpE = mpWS->mutableE(wsIndex);
-        const auto &mmY = mmWS->y(wsIndex);
-        for (size_t binIndex = 0; binIndex != mpY.size(); ++binIndex) {
-          mpY[binIndex] =
-              (-ppY[binIndex] * P2[binIndex] + P2[binIndex] * pmY[binIndex] -
-               P2[binIndex] * mmY[binIndex] +
-               2 * ppY[binIndex] * F2[binIndex] * P2[binIndex] -
-               pmY[binIndex] * P1[binIndex] + P1[binIndex] * mmY[binIndex] +
-               ppY[binIndex] * P1[binIndex] -
-               2 * ppY[binIndex] * F1[binIndex] * P1[binIndex] +
-               2 * pmY[binIndex] * F1[binIndex] * P1[binIndex] +
-               ppY[binIndex] * F1[binIndex] - ppY[binIndex] * F2[binIndex] -
-               pmY[binIndex] * F1[binIndex]) /
-              (-P2[binIndex] + 2 * F2[binIndex] * P2[binIndex] + P1[binIndex] -
-               F2[binIndex]);
-          // Error propagation is not implemented in the algorithm.
-          mpE[binIndex] = 0.;
-        }
-      }
+  void test_points_short() {
+    PolarizationEfficiencyCor alg;
+    auto const inputs = createWorkspacesInADS(4);
+    alg.setRethrows(true);
+    alg.initialize();
+    alg.setProperty("OutputWorkspace", "out");
+    alg.setProperty("InputWorkspaces", inputs);
+    alg.setProperty("CorrectionMethod", "Wildes");
+    alg.setProperty("Efficiencies", createEfficiencies("points-short"));
+    alg.execute();
+    WorkspaceGroup_sptr out =
+        AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>("out");
+    TS_ASSERT_EQUALS(out->size(), 4);
+
+    for (size_t i = 0; i < out->size(); ++i) {
+      auto ws = AnalysisDataService::Instance().retrieve(inputs[i]);
+      auto checkAlg =
+          AlgorithmManager::Instance().createUnmanaged("CompareWorkspaces");
+      checkAlg->initialize();
+      checkAlg->setChild(true);
+      checkAlg->setProperty("Workspace1", ws);
+      checkAlg->setProperty("Workspace2", out->getItem(i));
+      checkAlg->setProperty("Tolerance", 3e-16);
+      checkAlg->execute();
+      TS_ASSERT(checkAlg->getProperty("Result"));
     }
   }
 
-  void solveMissingIntensities(const Mantid::API::MatrixWorkspace_sptr &ppWS,
-                               Mantid::API::MatrixWorkspace_sptr &pmWS,
-                               Mantid::API::MatrixWorkspace_sptr &mpWS,
-                               const Mantid::API::MatrixWorkspace_sptr &mmWS,
-                               const Mantid::API::MatrixWorkspace_sptr &effWS) {
-    const auto &F1 = effWS->y(0);
-    const auto &F1E = effWS->e(0);
-    const auto &F2 = effWS->y(1);
-    const auto &F2E = effWS->e(1);
-    const auto &P1 = effWS->y(2);
-    const auto &P1E = effWS->e(2);
-    const auto &P2 = effWS->y(3);
-    const auto &P2E = effWS->e(3);
-    pmWS = ppWS->clone();
-    mpWS = ppWS->clone();
-    for (size_t wsIndex = 0; wsIndex != ppWS->getNumberHistograms();
-         ++wsIndex) {
-      const auto &ppY = ppWS->y(wsIndex);
-      const auto &ppE = ppWS->e(wsIndex);
-      auto &pmY = pmWS->mutableY(wsIndex);
-      auto &pmE = pmWS->mutableE(wsIndex);
-      auto &mpY = mpWS->mutableY(wsIndex);
-      auto &mpE = mpWS->mutableE(wsIndex);
-      const auto &mmY = mmWS->y(wsIndex);
-      const auto &mmE = mmWS->e(wsIndex);
-      for (size_t binIndex = 0; binIndex != mpY.size(); ++binIndex) {
-        const double P12 = P1[binIndex] * P1[binIndex];
-        const double P13 = P1[binIndex] * P12;
-        const double P14 = P1[binIndex] * P13;
-        const double P22 = P2[binIndex] * P2[binIndex];
-        const double P23 = P2[binIndex] * P22;
-        const double F12 = F1[binIndex] * F1[binIndex];
-        {
-          mpY[binIndex] =
-              -(-mmY[binIndex] * P22 * F1[binIndex] +
-                2 * F1[binIndex] * P1[binIndex] * mmY[binIndex] * P22 -
-                2 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P2[binIndex] -
-                8 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P12 *
-                    P2[binIndex] +
-                2 * ppY[binIndex] * F2[binIndex] * P12 * P2[binIndex] +
-                8 * ppY[binIndex] * F12 * F2[binIndex] * P12 * P2[binIndex] +
-                2 * ppY[binIndex] * F12 * F2[binIndex] * P2[binIndex] -
-                8 * ppY[binIndex] * F12 * F2[binIndex] * P2[binIndex] *
-                    P1[binIndex] -
-                2 * F1[binIndex] * P1[binIndex] * mmY[binIndex] * P2[binIndex] -
-                2 * ppY[binIndex] * F2[binIndex] * P1[binIndex] * P2[binIndex] +
-                8 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P1[binIndex] *
-                    P2[binIndex] +
-                mmY[binIndex] * P2[binIndex] * F1[binIndex] +
-                ppY[binIndex] * F1[binIndex] * F2[binIndex] -
-                ppY[binIndex] * F2[binIndex] * P12 +
-                4 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P12 +
-                4 * ppY[binIndex] * F12 * F2[binIndex] * P1[binIndex] -
-                4 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P1[binIndex] +
-                ppY[binIndex] * F2[binIndex] * P1[binIndex] -
-                4 * ppY[binIndex] * F12 * F2[binIndex] * P12 -
-                ppY[binIndex] * F12 * F2[binIndex]) /
-              (-F1[binIndex] * F2[binIndex] +
-               2 * F2[binIndex] * P1[binIndex] * P2[binIndex] +
-               3 * F1[binIndex] * F2[binIndex] * P1[binIndex] -
-               2 * F1[binIndex] * F2[binIndex] * P22 -
-               2 * P22 * F1[binIndex] * P1[binIndex] +
-               2 * P2[binIndex] * F1[binIndex] * P1[binIndex] +
-               3 * F1[binIndex] * F2[binIndex] * P2[binIndex] -
-               P2[binIndex] * F1[binIndex] + P22 * F1[binIndex] +
-               F2[binIndex] * P12 - 2 * F2[binIndex] * P12 * P2[binIndex] -
-               2 * F1[binIndex] * F2[binIndex] * P12 -
-               F2[binIndex] * P1[binIndex] -
-               8 * F1[binIndex] * F2[binIndex] * P1[binIndex] * P2[binIndex] +
-               4 * F1[binIndex] * F2[binIndex] * P1[binIndex] * P22 +
-               4 * F1[binIndex] * F2[binIndex] * P12 * P2[binIndex]);
-          const double dI00 =
-              -F2[binIndex] *
-              (-2 * P2[binIndex] * F1[binIndex] + 2 * P12 * P2[binIndex] +
-               8 * P2[binIndex] * F1[binIndex] * P1[binIndex] -
-               2 * P1[binIndex] * P2[binIndex] + 2 * P2[binIndex] * F12 -
-               8 * P2[binIndex] * F12 * P1[binIndex] -
-               8 * P2[binIndex] * F1[binIndex] * P12 +
-               8 * P2[binIndex] * F12 * P12 - 4 * F1[binIndex] * P1[binIndex] -
-               F12 + 4 * F12 * P1[binIndex] + P1[binIndex] + F1[binIndex] -
-               P12 + 4 * F1[binIndex] * P12 - 4 * F12 * P12) /
-              (-P2[binIndex] * F1[binIndex] +
-               3 * F1[binIndex] * F2[binIndex] * P2[binIndex] -
-               2 * P22 * F1[binIndex] * P1[binIndex] -
-               2 * F1[binIndex] * F2[binIndex] * P22 -
-               2 * F2[binIndex] * P12 * P2[binIndex] -
-               2 * F1[binIndex] * F2[binIndex] * P12 +
-               2 * P2[binIndex] * F1[binIndex] * P1[binIndex] +
-               P22 * F1[binIndex] + F2[binIndex] * P12 +
-               3 * F1[binIndex] * F2[binIndex] * P1[binIndex] +
-               2 * F2[binIndex] * P1[binIndex] * P2[binIndex] -
-               F1[binIndex] * F2[binIndex] - F2[binIndex] * P1[binIndex] -
-               8 * F1[binIndex] * F2[binIndex] * P1[binIndex] * P2[binIndex] +
-               4 * F1[binIndex] * F2[binIndex] * P1[binIndex] * P22 +
-               4 * F1[binIndex] * F2[binIndex] * P12 * P2[binIndex]);
-          const double dI11 =
-              -P2[binIndex] * F1[binIndex] *
-              (1 - 2 * P1[binIndex] - P2[binIndex] +
-               2 * P1[binIndex] * P2[binIndex]) /
-              (-P2[binIndex] * F1[binIndex] +
-               3 * F1[binIndex] * F2[binIndex] * P2[binIndex] -
-               2 * P22 * F1[binIndex] * P1[binIndex] -
-               2 * F1[binIndex] * F2[binIndex] * P22 -
-               2 * F2[binIndex] * P12 * P2[binIndex] -
-               2 * F1[binIndex] * F2[binIndex] * P12 +
-               2 * P2[binIndex] * F1[binIndex] * P1[binIndex] +
-               P22 * F1[binIndex] + F2[binIndex] * P12 +
-               3 * F1[binIndex] * F2[binIndex] * P1[binIndex] +
-               2 * F2[binIndex] * P1[binIndex] * P2[binIndex] -
-               F1[binIndex] * F2[binIndex] - F2[binIndex] * P1[binIndex] -
-               8 * F1[binIndex] * F2[binIndex] * P1[binIndex] * P2[binIndex] +
-               4 * F1[binIndex] * F2[binIndex] * P1[binIndex] * P22 +
-               4 * F1[binIndex] * F2[binIndex] * P12 * P2[binIndex]);
-          const double divisor1 =
-              (-P2[binIndex] * F1[binIndex] +
-               3 * F1[binIndex] * F2[binIndex] * P2[binIndex] -
-               2 * P22 * F1[binIndex] * P1[binIndex] -
-               2 * F1[binIndex] * F2[binIndex] * P22 -
-               2 * F2[binIndex] * P12 * P2[binIndex] -
-               2 * F1[binIndex] * F2[binIndex] * P12 +
-               2 * P2[binIndex] * F1[binIndex] * P1[binIndex] +
-               P22 * F1[binIndex] + F2[binIndex] * P12 +
-               3 * F1[binIndex] * F2[binIndex] * P1[binIndex] +
-               2 * F2[binIndex] * P1[binIndex] * P2[binIndex] -
-               F1[binIndex] * F2[binIndex] - F2[binIndex] * P1[binIndex] -
-               8 * F1[binIndex] * F2[binIndex] * P1[binIndex] * P2[binIndex] +
-               4 * F1[binIndex] * F2[binIndex] * P1[binIndex] * P22 +
-               4 * F1[binIndex] * F2[binIndex] * P12 * P2[binIndex]);
-          const double dF1 =
-              -F2[binIndex] *
-              (-P1[binIndex] * mmY[binIndex] * P2[binIndex] +
-               4 * ppY[binIndex] * F2[binIndex] * P1[binIndex] * P22 -
-               ppY[binIndex] * F2[binIndex] * P12 * P2[binIndex] -
-               10 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P12 -
-               8 * ppY[binIndex] * F2[binIndex] * P12 * P22 +
-               2 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P1[binIndex] -
-               ppY[binIndex] * F2[binIndex] * P1[binIndex] * P2[binIndex] -
-               32 * ppY[binIndex] * F12 * F2[binIndex] * P14 * P2[binIndex] +
-               32 * ppY[binIndex] * F2[binIndex] * P14 * P2[binIndex] *
-                   F1[binIndex] -
-               32 * ppY[binIndex] * F2[binIndex] * P14 * P22 * F1[binIndex] +
-               32 * ppY[binIndex] * F12 * F2[binIndex] * P14 * P22 +
-               32 * ppY[binIndex] * F12 * F2[binIndex] * P13 * P23 +
-               2 * ppY[binIndex] * F2[binIndex] * P14 +
-               4 * ppY[binIndex] * P13 * P23 - 4 * P13 * mmY[binIndex] * P23 -
-               8 * ppY[binIndex] * F2[binIndex] * P13 * P23 -
-               16 * ppY[binIndex] * P23 * F12 * P13 +
-               8 * ppY[binIndex] * F12 * F2[binIndex] * P14 -
-               8 * ppY[binIndex] * F2[binIndex] * P14 * P2[binIndex] +
-               8 * ppY[binIndex] * F2[binIndex] * P14 * P22 -
-               8 * ppY[binIndex] * F2[binIndex] * P14 * F1[binIndex] +
-               10 * ppY[binIndex] * F2[binIndex] * P13 * P2[binIndex] -
-               4 * ppY[binIndex] * F2[binIndex] * P13 * P22 +
-               16 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P13 -
-               4 * ppY[binIndex] * F2[binIndex] * P1[binIndex] * P23 +
-               12 * ppY[binIndex] * F2[binIndex] * P12 * P23 +
-               18 * ppY[binIndex] * P22 * F12 * P1[binIndex] -
-               20 * ppY[binIndex] * F12 * F2[binIndex] * P13 -
-               36 * ppY[binIndex] * P22 * F12 * P12 +
-               24 * ppY[binIndex] * P22 * F12 * P13 -
-               6 * ppY[binIndex] * P2[binIndex] * F12 * P1[binIndex] -
-               5 * ppY[binIndex] * F12 * F2[binIndex] * P2[binIndex] +
-               8 * ppY[binIndex] * F12 * F2[binIndex] * P22 -
-               8 * ppY[binIndex] * P2[binIndex] * F12 * P13 +
-               12 * ppY[binIndex] * P2[binIndex] * F12 * P12 +
-               18 * ppY[binIndex] * F12 * F2[binIndex] * P12 -
-               7 * ppY[binIndex] * F12 * F2[binIndex] * P1[binIndex] -
-               12 * ppY[binIndex] * P23 * F12 * P1[binIndex] +
-               24 * ppY[binIndex] * P23 * F12 * P12 -
-               4 * ppY[binIndex] * F12 * F2[binIndex] * P23 -
-               3 * ppY[binIndex] * P1[binIndex] * P22 +
-               ppY[binIndex] * F2[binIndex] * P12 -
-               3 * ppY[binIndex] * P12 * P2[binIndex] +
-               3 * P12 * mmY[binIndex] * P2[binIndex] -
-               9 * P12 * mmY[binIndex] * P22 + 9 * ppY[binIndex] * P12 * P22 +
-               ppY[binIndex] * P1[binIndex] * P2[binIndex] +
-               3 * P1[binIndex] * mmY[binIndex] * P22 -
-               8 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P1[binIndex] *
-                   P2[binIndex] +
-               8 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P1[binIndex] *
-                   P22 +
-               40 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P12 *
-                   P2[binIndex] -
-               40 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P12 * P22 -
-               64 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P13 *
-                   P2[binIndex] +
-               64 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P13 * P22 +
-               34 * ppY[binIndex] * F12 * F2[binIndex] * P2[binIndex] *
-                   P1[binIndex] -
-               52 * ppY[binIndex] * F12 * F2[binIndex] * P22 * P1[binIndex] -
-               84 * ppY[binIndex] * F12 * F2[binIndex] * P12 * P2[binIndex] +
-               120 * ppY[binIndex] * F12 * F2[binIndex] * P12 * P22 +
-               88 * ppY[binIndex] * F12 * F2[binIndex] * P13 * P2[binIndex] -
-               112 * ppY[binIndex] * F12 * F2[binIndex] * P13 * P22 +
-               24 * ppY[binIndex] * F12 * F2[binIndex] * P23 * P1[binIndex] -
-               48 * ppY[binIndex] * F12 * F2[binIndex] * P12 * P23 +
-               2 * ppY[binIndex] * P13 * P2[binIndex] -
-               6 * ppY[binIndex] * P13 * P22 -
-               3 * ppY[binIndex] * F2[binIndex] * P13 +
-               2 * ppY[binIndex] * P1[binIndex] * P23 -
-               6 * ppY[binIndex] * P12 * P23 +
-               ppY[binIndex] * P2[binIndex] * F12 -
-               3 * ppY[binIndex] * P22 * F12 +
-               ppY[binIndex] * F12 * F2[binIndex] +
-               2 * ppY[binIndex] * P23 * F12 -
-               2 * P13 * mmY[binIndex] * P2[binIndex] +
-               6 * P13 * mmY[binIndex] * P22 + 6 * P12 * mmY[binIndex] * P23 -
-               2 * P1[binIndex] * mmY[binIndex] * P23) /
-              (divisor1 * divisor1);
-          const double divisor2 =
-              (-P2[binIndex] * F1[binIndex] +
-               3 * F1[binIndex] * F2[binIndex] * P2[binIndex] -
-               2 * P22 * F1[binIndex] * P1[binIndex] -
-               2 * F1[binIndex] * F2[binIndex] * P22 -
-               2 * F2[binIndex] * P12 * P2[binIndex] -
-               2 * F1[binIndex] * F2[binIndex] * P12 +
-               2 * P2[binIndex] * F1[binIndex] * P1[binIndex] +
-               P22 * F1[binIndex] + F2[binIndex] * P12 +
-               3 * F1[binIndex] * F2[binIndex] * P1[binIndex] +
-               2 * F2[binIndex] * P1[binIndex] * P2[binIndex] -
-               F1[binIndex] * F2[binIndex] - F2[binIndex] * P1[binIndex] -
-               8 * F1[binIndex] * F2[binIndex] * P1[binIndex] * P2[binIndex] +
-               4 * F1[binIndex] * F2[binIndex] * P1[binIndex] * P22 +
-               4 * F1[binIndex] * F2[binIndex] * P12 * P2[binIndex]);
-          const double dF2 =
-              P2[binIndex] * F1[binIndex] *
-              (3 * P1[binIndex] * mmY[binIndex] * P2[binIndex] -
-               12 * ppY[binIndex] * P22 * F1[binIndex] * P1[binIndex] -
-               36 * ppY[binIndex] * P2[binIndex] * F1[binIndex] * P12 +
-               24 * ppY[binIndex] * P22 * F1[binIndex] * P12 +
-               18 * ppY[binIndex] * P2[binIndex] * F1[binIndex] * P1[binIndex] +
-               12 * ppY[binIndex] * F1[binIndex] * P12 +
-               24 * ppY[binIndex] * P2[binIndex] * F1[binIndex] * P13 -
-               16 * ppY[binIndex] * P22 * F1[binIndex] * P13 +
-               12 * ppY[binIndex] * P22 * F12 * P1[binIndex] -
-               24 * ppY[binIndex] * P22 * F12 * P12 +
-               16 * ppY[binIndex] * P22 * F12 * P13 -
-               18 * ppY[binIndex] * P2[binIndex] * F12 * P1[binIndex] -
-               24 * ppY[binIndex] * P2[binIndex] * F12 * P13 +
-               36 * ppY[binIndex] * P2[binIndex] * F12 * P12 -
-               19 * F1[binIndex] * P1[binIndex] * mmY[binIndex] * P2[binIndex] +
-               28 * F1[binIndex] * P12 * mmY[binIndex] * P2[binIndex] -
-               12 * F1[binIndex] * P13 * mmY[binIndex] * P2[binIndex] +
-               22 * F1[binIndex] * P1[binIndex] * mmY[binIndex] * P22 -
-               28 * F1[binIndex] * P12 * mmY[binIndex] * P22 +
-               8 * F1[binIndex] * P13 * mmY[binIndex] * P22 -
-               8 * F1[binIndex] * P1[binIndex] * mmY[binIndex] * P23 +
-               8 * F1[binIndex] * P12 * mmY[binIndex] * P23 -
-               ppY[binIndex] * F12 + 2 * ppY[binIndex] * P13 -
-               2 * P13 * mmY[binIndex] - mmY[binIndex] * F1[binIndex] +
-               2 * ppY[binIndex] * P1[binIndex] * P22 +
-               9 * ppY[binIndex] * P12 * P2[binIndex] -
-               9 * P12 * mmY[binIndex] * P2[binIndex] +
-               6 * P12 * mmY[binIndex] * P22 - 6 * ppY[binIndex] * P12 * P22 -
-               3 * ppY[binIndex] * P1[binIndex] * P2[binIndex] -
-               2 * P1[binIndex] * mmY[binIndex] * P22 -
-               6 * ppY[binIndex] * F1[binIndex] * P1[binIndex] +
-               2 * ppY[binIndex] * P22 * F1[binIndex] -
-               3 * ppY[binIndex] * P2[binIndex] * F1[binIndex] -
-               P1[binIndex] * mmY[binIndex] + ppY[binIndex] * P1[binIndex] -
-               3 * ppY[binIndex] * P12 + ppY[binIndex] * F1[binIndex] +
-               3 * P12 * mmY[binIndex] -
-               6 * ppY[binIndex] * P13 * P2[binIndex] +
-               4 * ppY[binIndex] * P13 * P22 +
-               3 * ppY[binIndex] * P2[binIndex] * F12 -
-               2 * ppY[binIndex] * P22 * F12 +
-               5 * F1[binIndex] * P1[binIndex] * mmY[binIndex] +
-               6 * ppY[binIndex] * F12 * P1[binIndex] -
-               8 * F1[binIndex] * P12 * mmY[binIndex] -
-               12 * F12 * P12 * ppY[binIndex] -
-               8 * ppY[binIndex] * F1[binIndex] * P13 +
-               6 * P13 * mmY[binIndex] * P2[binIndex] +
-               4 * F1[binIndex] * P13 * mmY[binIndex] +
-               8 * F12 * P13 * ppY[binIndex] - 4 * P13 * mmY[binIndex] * P22 -
-               5 * mmY[binIndex] * P22 * F1[binIndex] +
-               2 * mmY[binIndex] * P23 * F1[binIndex] +
-               4 * mmY[binIndex] * P2[binIndex] * F1[binIndex]) /
-              (divisor2 * divisor2);
-          const double divisor3 =
-              (-P2[binIndex] * F1[binIndex] +
-               3 * F1[binIndex] * F2[binIndex] * P2[binIndex] -
-               2 * P22 * F1[binIndex] * P1[binIndex] -
-               2 * F1[binIndex] * F2[binIndex] * P22 -
-               2 * F2[binIndex] * P12 * P2[binIndex] -
-               2 * F1[binIndex] * F2[binIndex] * P12 +
-               2 * P2[binIndex] * F1[binIndex] * P1[binIndex] +
-               P22 * F1[binIndex] + F2[binIndex] * P12 +
-               3 * F1[binIndex] * F2[binIndex] * P1[binIndex] +
-               2 * F2[binIndex] * P1[binIndex] * P2[binIndex] -
-               F1[binIndex] * F2[binIndex] - F2[binIndex] * P1[binIndex] -
-               8 * F1[binIndex] * F2[binIndex] * P1[binIndex] * P2[binIndex] +
-               4 * F1[binIndex] * F2[binIndex] * P1[binIndex] * P22 +
-               4 * F1[binIndex] * F2[binIndex] * P12 * P2[binIndex]);
-          const double dP1 =
-              -F1[binIndex] * F2[binIndex] *
-              (-2 * P1[binIndex] * mmY[binIndex] * P2[binIndex] -
-               2 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P2[binIndex] +
-               8 * ppY[binIndex] * F2[binIndex] * P1[binIndex] * P22 +
-               24 * ppY[binIndex] * P22 * F1[binIndex] * P1[binIndex] +
-               8 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P22 +
-               8 * ppY[binIndex] * P2[binIndex] * F1[binIndex] * P12 +
-               6 * ppY[binIndex] * F2[binIndex] * P12 * P2[binIndex] +
-               4 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P12 -
-               24 * ppY[binIndex] * P22 * F1[binIndex] * P12 -
-               12 * ppY[binIndex] * F2[binIndex] * P12 * P22 -
-               8 * ppY[binIndex] * P2[binIndex] * F1[binIndex] * P1[binIndex] -
-               2 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P1[binIndex] -
-               2 * ppY[binIndex] * F2[binIndex] * P1[binIndex] * P2[binIndex] +
-               ppY[binIndex] * F2[binIndex] * P2[binIndex] -
-               4 * ppY[binIndex] * F2[binIndex] * P22 -
-               8 * ppY[binIndex] * F2[binIndex] * P1[binIndex] * P23 -
-               16 * ppY[binIndex] * P23 * F1[binIndex] * P1[binIndex] -
-               8 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P23 +
-               16 * ppY[binIndex] * P23 * F1[binIndex] * P12 +
-               8 * ppY[binIndex] * F2[binIndex] * P12 * P23 -
-               24 * ppY[binIndex] * P22 * F12 * P1[binIndex] +
-               24 * ppY[binIndex] * P22 * F12 * P12 +
-               8 * ppY[binIndex] * P2[binIndex] * F12 * P1[binIndex] +
-               6 * ppY[binIndex] * F12 * F2[binIndex] * P2[binIndex] -
-               12 * ppY[binIndex] * F12 * F2[binIndex] * P22 -
-               8 * ppY[binIndex] * P2[binIndex] * F12 * P12 -
-               4 * ppY[binIndex] * F12 * F2[binIndex] * P12 +
-               4 * ppY[binIndex] * F12 * F2[binIndex] * P1[binIndex] +
-               16 * ppY[binIndex] * P23 * F12 * P1[binIndex] -
-               16 * ppY[binIndex] * P23 * F12 * P12 +
-               8 * ppY[binIndex] * F12 * F2[binIndex] * P23 +
-               4 * F1[binIndex] * P1[binIndex] * mmY[binIndex] * P2[binIndex] -
-               4 * F1[binIndex] * P12 * mmY[binIndex] * P2[binIndex] -
-               12 * F1[binIndex] * P1[binIndex] * mmY[binIndex] * P22 +
-               12 * F1[binIndex] * P12 * mmY[binIndex] * P22 +
-               8 * F1[binIndex] * P1[binIndex] * mmY[binIndex] * P23 -
-               8 * F1[binIndex] * P12 * mmY[binIndex] * P23 +
-               2 * mmY[binIndex] * P23 - 2 * ppY[binIndex] * P23 +
-               4 * ppY[binIndex] * F2[binIndex] * P23 -
-               6 * ppY[binIndex] * P1[binIndex] * P22 -
-               ppY[binIndex] * F2[binIndex] * P12 -
-               2 * ppY[binIndex] * P12 * P2[binIndex] +
-               2 * P12 * mmY[binIndex] * P2[binIndex] -
-               6 * P12 * mmY[binIndex] * P22 + 6 * ppY[binIndex] * P12 * P22 +
-               2 * ppY[binIndex] * P1[binIndex] * P2[binIndex] -
-               ppY[binIndex] * P2[binIndex] +
-               6 * P1[binIndex] * mmY[binIndex] * P22 -
-               6 * ppY[binIndex] * P22 * F1[binIndex] +
-               2 * ppY[binIndex] * P2[binIndex] * F1[binIndex] +
-               3 * ppY[binIndex] * P22 +
-               16 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P1[binIndex] *
-                   P2[binIndex] -
-               40 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P1[binIndex] *
-                   P22 -
-               24 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P12 *
-                   P2[binIndex] +
-               48 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P12 * P22 +
-               mmY[binIndex] * P2[binIndex] - 3 * mmY[binIndex] * P22 +
-               32 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P1[binIndex] *
-                   P23 -
-               32 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P12 * P23 -
-               24 * ppY[binIndex] * F12 * F2[binIndex] * P2[binIndex] *
-                   P1[binIndex] +
-               48 * ppY[binIndex] * F12 * F2[binIndex] * P22 * P1[binIndex] +
-               24 * ppY[binIndex] * F12 * F2[binIndex] * P12 * P2[binIndex] -
-               48 * ppY[binIndex] * F12 * F2[binIndex] * P12 * P22 -
-               32 * ppY[binIndex] * F12 * F2[binIndex] * P23 * P1[binIndex] +
-               32 * ppY[binIndex] * F12 * F2[binIndex] * P12 * P23 +
-               4 * ppY[binIndex] * P1[binIndex] * P23 +
-               4 * ppY[binIndex] * P23 * F1[binIndex] -
-               4 * ppY[binIndex] * P12 * P23 -
-               2 * ppY[binIndex] * P2[binIndex] * F12 +
-               6 * ppY[binIndex] * P22 * F12 -
-               ppY[binIndex] * F12 * F2[binIndex] -
-               4 * ppY[binIndex] * P23 * F12 + 4 * P12 * mmY[binIndex] * P23 -
-               4 * P1[binIndex] * mmY[binIndex] * P23 +
-               3 * mmY[binIndex] * P22 * F1[binIndex] -
-               2 * mmY[binIndex] * P23 * F1[binIndex] -
-               mmY[binIndex] * P2[binIndex] * F1[binIndex]) /
-              (divisor3 * divisor3);
-          const double divisor4 =
-              (-P2[binIndex] * F1[binIndex] +
-               3 * F1[binIndex] * F2[binIndex] * P2[binIndex] -
-               2 * P22 * F1[binIndex] * P1[binIndex] -
-               2 * F1[binIndex] * F2[binIndex] * P22 -
-               2 * F2[binIndex] * P12 * P2[binIndex] -
-               2 * F1[binIndex] * F2[binIndex] * P12 +
-               2 * P2[binIndex] * F1[binIndex] * P1[binIndex] +
-               P22 * F1[binIndex] + F2[binIndex] * P12 +
-               3 * F1[binIndex] * F2[binIndex] * P1[binIndex] +
-               2 * F2[binIndex] * P1[binIndex] * P2[binIndex] -
-               F1[binIndex] * F2[binIndex] - F2[binIndex] * P1[binIndex] -
-               8 * F1[binIndex] * F2[binIndex] * P1[binIndex] * P2[binIndex] +
-               4 * F1[binIndex] * F2[binIndex] * P1[binIndex] * P22 +
-               4 * F1[binIndex] * F2[binIndex] * P12 * P2[binIndex]);
-          const double dP2 =
-              F1[binIndex] * F2[binIndex] *
-              (-2 * P1[binIndex] * mmY[binIndex] * P2[binIndex] -
-               4 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P2[binIndex] +
-               4 * ppY[binIndex] * F2[binIndex] * P1[binIndex] * P22 +
-               12 * ppY[binIndex] * P22 * F1[binIndex] * P1[binIndex] +
-               4 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P22 +
-               24 * ppY[binIndex] * P2[binIndex] * F1[binIndex] * P12 +
-               12 * ppY[binIndex] * F2[binIndex] * P12 * P2[binIndex] +
-               12 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P12 -
-               24 * ppY[binIndex] * P22 * F1[binIndex] * P12 -
-               12 * ppY[binIndex] * F2[binIndex] * P12 * P22 -
-               12 * ppY[binIndex] * P2[binIndex] * F1[binIndex] * P1[binIndex] -
-               6 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P1[binIndex] -
-               4 * ppY[binIndex] * F2[binIndex] * P1[binIndex] * P2[binIndex] -
-               12 * ppY[binIndex] * F1[binIndex] * P12 -
-               16 * ppY[binIndex] * P2[binIndex] * F1[binIndex] * P13 +
-               16 * ppY[binIndex] * P22 * F1[binIndex] * P13 -
-               8 * ppY[binIndex] * F2[binIndex] * P13 * P2[binIndex] +
-               8 * ppY[binIndex] * F2[binIndex] * P13 * P22 -
-               8 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P13 -
-               12 * ppY[binIndex] * P22 * F12 * P1[binIndex] +
-               8 * ppY[binIndex] * F12 * F2[binIndex] * P13 +
-               24 * ppY[binIndex] * P22 * F12 * P12 -
-               16 * ppY[binIndex] * P22 * F12 * P13 +
-               12 * ppY[binIndex] * P2[binIndex] * F12 * P1[binIndex] +
-               4 * ppY[binIndex] * F12 * F2[binIndex] * P2[binIndex] -
-               4 * ppY[binIndex] * F12 * F2[binIndex] * P22 +
-               16 * ppY[binIndex] * P2[binIndex] * F12 * P13 -
-               24 * ppY[binIndex] * P2[binIndex] * F12 * P12 -
-               12 * ppY[binIndex] * F12 * F2[binIndex] * P12 +
-               6 * ppY[binIndex] * F12 * F2[binIndex] * P1[binIndex] +
-               10 * F1[binIndex] * P1[binIndex] * mmY[binIndex] * P2[binIndex] -
-               16 * F1[binIndex] * P12 * mmY[binIndex] * P2[binIndex] +
-               8 * F1[binIndex] * P13 * mmY[binIndex] * P2[binIndex] -
-               6 * F1[binIndex] * P1[binIndex] * mmY[binIndex] * P22 +
-               12 * F1[binIndex] * P12 * mmY[binIndex] * P22 -
-               8 * F1[binIndex] * P13 * mmY[binIndex] * P22 +
-               ppY[binIndex] * F12 - 2 * ppY[binIndex] * P13 +
-               2 * P13 * mmY[binIndex] + mmY[binIndex] * F1[binIndex] -
-               2 * ppY[binIndex] * P1[binIndex] * P22 +
-               ppY[binIndex] * F2[binIndex] * P1[binIndex] -
-               3 * ppY[binIndex] * F2[binIndex] * P12 -
-               6 * ppY[binIndex] * P12 * P2[binIndex] +
-               6 * P12 * mmY[binIndex] * P2[binIndex] -
-               6 * P12 * mmY[binIndex] * P22 + 6 * ppY[binIndex] * P12 * P22 +
-               2 * ppY[binIndex] * P1[binIndex] * P2[binIndex] +
-               ppY[binIndex] * F1[binIndex] * F2[binIndex] +
-               2 * P1[binIndex] * mmY[binIndex] * P22 +
-               6 * ppY[binIndex] * F1[binIndex] * P1[binIndex] -
-               2 * ppY[binIndex] * P22 * F1[binIndex] +
-               2 * ppY[binIndex] * P2[binIndex] * F1[binIndex] +
-               24 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P1[binIndex] *
-                   P2[binIndex] -
-               24 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P1[binIndex] *
-                   P22 -
-               48 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P12 *
-                   P2[binIndex] +
-               48 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P12 * P22 +
-               P1[binIndex] * mmY[binIndex] - ppY[binIndex] * P1[binIndex] +
-               3 * ppY[binIndex] * P12 - ppY[binIndex] * F1[binIndex] -
-               3 * P12 * mmY[binIndex] +
-               32 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P13 *
-                   P2[binIndex] -
-               32 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P13 * P22 -
-               24 * ppY[binIndex] * F12 * F2[binIndex] * P2[binIndex] *
-                   P1[binIndex] +
-               24 * ppY[binIndex] * F12 * F2[binIndex] * P22 * P1[binIndex] +
-               48 * ppY[binIndex] * F12 * F2[binIndex] * P12 * P2[binIndex] -
-               48 * ppY[binIndex] * F12 * F2[binIndex] * P12 * P22 -
-               32 * ppY[binIndex] * F12 * F2[binIndex] * P13 * P2[binIndex] +
-               32 * ppY[binIndex] * F12 * F2[binIndex] * P13 * P22 +
-               4 * ppY[binIndex] * P13 * P2[binIndex] -
-               4 * ppY[binIndex] * P13 * P22 +
-               2 * ppY[binIndex] * F2[binIndex] * P13 -
-               2 * ppY[binIndex] * P2[binIndex] * F12 +
-               2 * ppY[binIndex] * P22 * F12 -
-               ppY[binIndex] * F12 * F2[binIndex] -
-               5 * F1[binIndex] * P1[binIndex] * mmY[binIndex] -
-               6 * ppY[binIndex] * F12 * P1[binIndex] +
-               8 * F1[binIndex] * P12 * mmY[binIndex] +
-               12 * F12 * P12 * ppY[binIndex] +
-               8 * ppY[binIndex] * F1[binIndex] * P13 -
-               4 * P13 * mmY[binIndex] * P2[binIndex] -
-               4 * F1[binIndex] * P13 * mmY[binIndex] -
-               8 * F12 * P13 * ppY[binIndex] + 4 * P13 * mmY[binIndex] * P22 +
-               mmY[binIndex] * P22 * F1[binIndex] -
-               2 * mmY[binIndex] * P2[binIndex] * F1[binIndex]) /
-              (divisor4 * divisor4);
-          const double e1 = dI00 * ppE[binIndex];
-          const double e2 = dI11 * mmE[binIndex];
-          const double e3 = dF1 * F1E[binIndex];
-          const double e4 = dF2 * F2E[binIndex];
-          const double e5 = dP1 * P1E[binIndex];
-          const double e6 = dP2 * P2E[binIndex];
-          mpE[binIndex] = std::sqrt(e1 * e1 + e2 * e2 + e3 * e3 + e4 * e4 +
-                                    e5 * e5 + e6 * e6);
-        }
-        {
-          pmY[binIndex] =
-              -(ppY[binIndex] * P2[binIndex] * F1[binIndex] -
-                2 * ppY[binIndex] * F2[binIndex] * P1[binIndex] * P2[binIndex] -
-                2 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P2[binIndex] -
-                2 * ppY[binIndex] * P2[binIndex] * F1[binIndex] * P1[binIndex] +
-                2 * P1[binIndex] * mpY[binIndex] * F2[binIndex] * P2[binIndex] +
-                ppY[binIndex] * P1[binIndex] * P2[binIndex] -
-                P1[binIndex] * mpY[binIndex] * P2[binIndex] +
-                4 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P1[binIndex] *
-                    P2[binIndex] +
-                P1[binIndex] * mmY[binIndex] * P2[binIndex] -
-                ppY[binIndex] * F1[binIndex] +
-                2 * ppY[binIndex] * F1[binIndex] * P1[binIndex] -
-                P1[binIndex] * mmY[binIndex] -
-                P1[binIndex] * mpY[binIndex] * F2[binIndex] +
-                ppY[binIndex] * F2[binIndex] * P1[binIndex] +
-                ppY[binIndex] * F1[binIndex] * F2[binIndex] -
-                2 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P1[binIndex] +
-                P1[binIndex] * mpY[binIndex] - ppY[binIndex] * P1[binIndex]) /
-              ((-P1[binIndex] + 2 * F1[binIndex] * P1[binIndex] -
-                F1[binIndex]) *
-               (-1 + P2[binIndex]));
-          const double dI00 =
-              -(-P1[binIndex] + P1[binIndex] * P2[binIndex] +
-                F2[binIndex] * P1[binIndex] -
-                2 * F2[binIndex] * P1[binIndex] * P2[binIndex] +
-                2 * F1[binIndex] * P1[binIndex] -
-                2 * P2[binIndex] * F1[binIndex] * P1[binIndex] -
-                2 * F1[binIndex] * F2[binIndex] * P1[binIndex] +
-                4 * F1[binIndex] * F2[binIndex] * P1[binIndex] * P2[binIndex] +
-                F1[binIndex] * F2[binIndex] - F1[binIndex] +
-                P2[binIndex] * F1[binIndex] -
-                2 * F1[binIndex] * F2[binIndex] * P2[binIndex]) /
-              ((-P1[binIndex] + 2 * F1[binIndex] * P1[binIndex] -
-                F1[binIndex]) *
-               (-1 + P2[binIndex]));
-          const double dI11 =
-              -(P1[binIndex] * P2[binIndex] - P1[binIndex]) /
-              ((-P1[binIndex] + 2 * F1[binIndex] * P1[binIndex] -
-                F1[binIndex]) *
-               (-1 + P2[binIndex]));
-          const double dI10 =
-              -(P1[binIndex] - P1[binIndex] * P2[binIndex] -
-                F2[binIndex] * P1[binIndex] +
-                2 * F2[binIndex] * P1[binIndex] * P2[binIndex]) /
-              ((-P1[binIndex] + 2 * F1[binIndex] * P1[binIndex] -
-                F1[binIndex]) *
-               (-1 + P2[binIndex]));
-          const double factor1 =
-              (-P1[binIndex] + 2 * F1[binIndex] * P1[binIndex] - F1[binIndex]);
-          const double dF1 =
-              -(ppY[binIndex] * P2[binIndex] -
-                2 * ppY[binIndex] * F2[binIndex] * P2[binIndex] -
-                2 * ppY[binIndex] * P1[binIndex] * P2[binIndex] +
-                4 * ppY[binIndex] * F2[binIndex] * P1[binIndex] * P2[binIndex] -
-                ppY[binIndex] + 2 * ppY[binIndex] * P1[binIndex] +
-                ppY[binIndex] * F2[binIndex] -
-                2 * ppY[binIndex] * F2[binIndex] * P1[binIndex]) /
-                  ((-P1[binIndex] + 2 * F1[binIndex] * P1[binIndex] -
-                    F1[binIndex]) *
-                   (-1 + P2[binIndex])) +
-              (ppY[binIndex] * P2[binIndex] * F1[binIndex] -
-               2 * ppY[binIndex] * F2[binIndex] * P1[binIndex] * P2[binIndex] -
-               2 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P2[binIndex] -
-               2 * ppY[binIndex] * P2[binIndex] * F1[binIndex] * P1[binIndex] +
-               2 * P1[binIndex] * mpY[binIndex] * F2[binIndex] * P2[binIndex] +
-               ppY[binIndex] * P1[binIndex] * P2[binIndex] -
-               P1[binIndex] * mpY[binIndex] * P2[binIndex] +
-               4 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P1[binIndex] *
-                   P2[binIndex] +
-               P1[binIndex] * mmY[binIndex] * P2[binIndex] -
-               ppY[binIndex] * F1[binIndex] +
-               2 * ppY[binIndex] * F1[binIndex] * P1[binIndex] -
-               P1[binIndex] * mmY[binIndex] -
-               P1[binIndex] * mpY[binIndex] * F2[binIndex] +
-               ppY[binIndex] * F2[binIndex] * P1[binIndex] +
-               ppY[binIndex] * F1[binIndex] * F2[binIndex] -
-               2 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P1[binIndex] +
-               P1[binIndex] * mpY[binIndex] - ppY[binIndex] * P1[binIndex]) *
-                  (-1 + 2 * P1[binIndex]) /
-                  ((factor1 * factor1) * (-1 + P2[binIndex]));
-          const double dF2 =
-              -(-2 * ppY[binIndex] * P1[binIndex] * P2[binIndex] -
-                2 * ppY[binIndex] * P2[binIndex] * F1[binIndex] +
-                2 * P1[binIndex] * mpY[binIndex] * P2[binIndex] +
-                4 * ppY[binIndex] * P2[binIndex] * F1[binIndex] * P1[binIndex] -
-                P1[binIndex] * mpY[binIndex] + ppY[binIndex] * P1[binIndex] +
-                ppY[binIndex] * F1[binIndex] -
-                2 * ppY[binIndex] * F1[binIndex] * P1[binIndex]) /
-              ((-P1[binIndex] + 2 * F1[binIndex] * P1[binIndex] -
-                F1[binIndex]) *
-               (-1 + P2[binIndex]));
-          const double factor2 =
-              (-P1[binIndex] + 2 * F1[binIndex] * P1[binIndex] - F1[binIndex]);
-          const double dP1 =
-              -(-2 * ppY[binIndex] * F2[binIndex] * P2[binIndex] -
-                2 * ppY[binIndex] * P2[binIndex] * F1[binIndex] +
-                2 * mpY[binIndex] * F2[binIndex] * P2[binIndex] +
-                ppY[binIndex] * P2[binIndex] - mpY[binIndex] * P2[binIndex] +
-                4 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P2[binIndex] +
-                mmY[binIndex] * P2[binIndex] +
-                2 * ppY[binIndex] * F1[binIndex] - mmY[binIndex] -
-                mpY[binIndex] * F2[binIndex] + ppY[binIndex] * F2[binIndex] -
-                2 * ppY[binIndex] * F1[binIndex] * F2[binIndex] +
-                mpY[binIndex] - ppY[binIndex]) /
-                  ((-P1[binIndex] + 2 * F1[binIndex] * P1[binIndex] -
-                    F1[binIndex]) *
-                   (-1 + P2[binIndex])) +
-              (ppY[binIndex] * P2[binIndex] * F1[binIndex] -
-               2 * ppY[binIndex] * F2[binIndex] * P1[binIndex] * P2[binIndex] -
-               2 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P2[binIndex] -
-               2 * ppY[binIndex] * P2[binIndex] * F1[binIndex] * P1[binIndex] +
-               2 * P1[binIndex] * mpY[binIndex] * F2[binIndex] * P2[binIndex] +
-               ppY[binIndex] * P1[binIndex] * P2[binIndex] -
-               P1[binIndex] * mpY[binIndex] * P2[binIndex] +
-               4 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P1[binIndex] *
-                   P2[binIndex] +
-               P1[binIndex] * mmY[binIndex] * P2[binIndex] -
-               ppY[binIndex] * F1[binIndex] +
-               2 * ppY[binIndex] * F1[binIndex] * P1[binIndex] -
-               P1[binIndex] * mmY[binIndex] -
-               P1[binIndex] * mpY[binIndex] * F2[binIndex] +
-               ppY[binIndex] * F2[binIndex] * P1[binIndex] +
-               ppY[binIndex] * F1[binIndex] * F2[binIndex] -
-               2 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P1[binIndex] +
-               P1[binIndex] * mpY[binIndex] - ppY[binIndex] * P1[binIndex]) *
-                  (-1 + 2 * F1[binIndex]) /
-                  ((factor2 * factor2) * (-1 + P2[binIndex]));
-          const double factor3 = (-1 + P2[binIndex]);
-          const double dP2 =
-              -(ppY[binIndex] * F1[binIndex] -
-                2 * ppY[binIndex] * F2[binIndex] * P1[binIndex] -
-                2 * ppY[binIndex] * F1[binIndex] * F2[binIndex] -
-                2 * ppY[binIndex] * F1[binIndex] * P1[binIndex] +
-                2 * P1[binIndex] * mpY[binIndex] * F2[binIndex] +
-                ppY[binIndex] * P1[binIndex] - P1[binIndex] * mpY[binIndex] +
-                4 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P1[binIndex] +
-                P1[binIndex] * mmY[binIndex]) /
-                  ((-P1[binIndex] + 2 * F1[binIndex] * P1[binIndex] -
-                    F1[binIndex]) *
-                   (-1 + P2[binIndex])) +
-              (ppY[binIndex] * P2[binIndex] * F1[binIndex] -
-               2 * ppY[binIndex] * F2[binIndex] * P1[binIndex] * P2[binIndex] -
-               2 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P2[binIndex] -
-               2 * ppY[binIndex] * P2[binIndex] * F1[binIndex] * P1[binIndex] +
-               2 * P1[binIndex] * mpY[binIndex] * F2[binIndex] * P2[binIndex] +
-               ppY[binIndex] * P1[binIndex] * P2[binIndex] -
-               P1[binIndex] * mpY[binIndex] * P2[binIndex] +
-               4 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P1[binIndex] *
-                   P2[binIndex] +
-               P1[binIndex] * mmY[binIndex] * P2[binIndex] -
-               ppY[binIndex] * F1[binIndex] +
-               2 * ppY[binIndex] * F1[binIndex] * P1[binIndex] -
-               P1[binIndex] * mmY[binIndex] -
-               P1[binIndex] * mpY[binIndex] * F2[binIndex] +
-               ppY[binIndex] * F2[binIndex] * P1[binIndex] +
-               ppY[binIndex] * F1[binIndex] * F2[binIndex] -
-               2 * ppY[binIndex] * F1[binIndex] * F2[binIndex] * P1[binIndex] +
-               P1[binIndex] * mpY[binIndex] - ppY[binIndex] * P1[binIndex]) /
-                  ((-P1[binIndex] + 2 * F1[binIndex] * P1[binIndex] -
-                    F1[binIndex]) *
-                   (factor3 * factor3));
-          const double e1 = dI00 * ppE[binIndex];
-          const double e2 = dI11 * mmE[binIndex];
-          const double e3 = dI10 * mpE[binIndex];
-          const double e4 = dF1 * F1E[binIndex];
-          const double e5 = dF2 * F2E[binIndex];
-          const double e6 = dP1 * P1E[binIndex];
-          const double e7 = dP2 * P2E[binIndex];
-          pmE[binIndex] = std::sqrt(e1 * e1 + e2 * e2 + e3 * e3 + e4 * e4 +
-                                    e5 * e5 + e6 * e6 + e7 * e7);
-        }
-      }
+private:
+  std::vector<MatrixWorkspace_sptr> createWorkspaces(int n) {
+    std::vector<MatrixWorkspace_sptr> workspaces;
+    for (int i = 0; i < n; ++i) {
+      auto ws = create1DWorkspaceConstant(5, 2.0, 1.0, true);
+      workspaces.push_back(ws);
     }
+    return workspaces;
   }
-};
 
-class PolarizationEfficiencyCorTestPerformance : public CxxTest::TestSuite {
-public:
-  void setUp() override {
-    using namespace Mantid::API;
-    auto loadWS =
-        AlgorithmManager::Instance().createUnmanaged("LoadILLReflectometry");
-    loadWS->setChild(true);
-    loadWS->initialize();
-    loadWS->setProperty("Filename", "ILL/D17/317370.nxs");
-    loadWS->setProperty("OutputWorkspace", "output");
-    loadWS->setProperty("XUnit", "TimeOfFlight");
-    loadWS->execute();
-    m_ws00 = loadWS->getProperty("OutputWorkspace");
-    auto groupDetectors =
-        AlgorithmManager::Instance().createUnmanaged("GroupDetectors");
-    groupDetectors->setChild(true);
-    groupDetectors->initialize();
-    groupDetectors->setProperty("InputWorkspace", m_ws00);
-    groupDetectors->setProperty("OutputWorkspace", "output");
-    groupDetectors->setPropertyValue("WorkspaceIndexList", "201, 202, 203");
-    groupDetectors->execute();
-    m_ws00 = groupDetectors->getProperty("OutputWorkspace");
-    auto convertUnits =
-        AlgorithmManager::Instance().createUnmanaged("ConvertUnits");
-    convertUnits->setChild(true);
-    convertUnits->initialize();
-    convertUnits->setProperty("InputWorkspace", m_ws00);
-    convertUnits->setProperty("OutputWorkspace", "output");
-    convertUnits->setProperty("Target", "Wavelength");
-    convertUnits->execute();
-    m_ws00 = convertUnits->getProperty("OutputWorkspace");
-    auto crop = AlgorithmManager::Instance().createUnmanaged("CropWorkspace");
-    crop->setChild(true);
-    crop->initialize();
-    crop->setProperty("InputWorkspace", m_ws00);
-    crop->setProperty("OutputWorkspace", "output");
-    crop->setProperty("XMin", 0.);
-    crop->execute();
-    m_ws00 = crop->getProperty("OutputWorkspace");
-    AnalysisDataService::Instance().addOrReplace("00", m_ws00);
-    m_ws01 = m_ws00->clone();
-    AnalysisDataService::Instance().addOrReplace("01", m_ws01);
-    m_ws10 = m_ws00->clone();
-    AnalysisDataService::Instance().addOrReplace("10", m_ws10);
-    m_ws11 = m_ws00->clone();
-    AnalysisDataService::Instance().addOrReplace("11", m_ws11);
-    auto loadEff = AlgorithmManager::Instance().createUnmanaged(
-        "LoadILLPolarizationFactors");
-    loadEff->setChild(true);
-    loadEff->initialize();
-    loadEff->setProperty("Filename", "ILL/D17/PolarizationFactors.txt");
-    loadEff->setProperty("OutputWorkspace", "output");
-    loadEff->setProperty("WavelengthReference", m_ws00);
-    loadEff->execute();
-    m_effWS = loadEff->getProperty("OutputWorkspace");
-  }
-
-  void tearDown() override {
-    using namespace Mantid::API;
-    AnalysisDataService::Instance().clear();
-  }
-
-  void test_DirectBeamPerformance() {
-    using namespace Mantid::API;
-    for (int i = 0; i < 3000; ++i) {
-      PolarizationEfficiencyCor correction;
-      correction.setChild(true);
-      correction.setRethrows(true);
-      correction.initialize();
-      correction.setProperty("InputWorkspaces", "00");
-      correction.setProperty("OutputWorkspace", "output");
-      correction.setProperty("Flippers", "0");
-      correction.setProperty("Efficiencies", m_effWS);
-      TS_ASSERT_THROWS_NOTHING(correction.execute())
+  WorkspaceGroup_sptr createWorkspaceGroup(int n) {
+    auto group = boost::make_shared<WorkspaceGroup>();
+    auto workspaces = createWorkspaces(n);
+    for (auto &ws : workspaces) {
+      ws->getAxis(0)->setUnit("Wavelength");
+      group->addWorkspace(ws);
     }
-  }
-
-  void test_ThreeInputsPerformanceMissing01() {
-    using namespace Mantid::API;
-    for (int i = 0; i < 3000; ++i) {
-      PolarizationEfficiencyCor correction;
-      correction.setChild(true);
-      correction.setRethrows(true);
-      correction.initialize();
-      correction.setProperty("InputWorkspaces", "00, 10, 11");
-      correction.setProperty("OutputWorkspace", "output");
-      correction.setProperty("Flippers", "00, 10, 11");
-      correction.setProperty("Efficiencies", m_effWS);
-      TS_ASSERT_THROWS_NOTHING(correction.execute())
+    AnalysisDataService::Instance().addOrReplace("WS_GROUP_1", group);
+    return group;
+  }
+
+  std::vector<std::string> createWorkspacesInADS(int n) {
+    std::vector<std::string> names;
+    auto workspaces = createWorkspaces(n);
+    size_t i = 0;
+    for (auto &ws : workspaces) {
+      names.push_back("ws_" + std::to_string(i));
+      AnalysisDataService::Instance().addOrReplace(names.back(), ws);
+      ++i;
     }
-  }
-
-  void test_ThreeInputsPerformanceMissing10() {
-    using namespace Mantid::API;
-    for (int i = 0; i < 3000; ++i) {
-      PolarizationEfficiencyCor correction;
-      correction.setChild(true);
-      correction.setRethrows(true);
-      correction.initialize();
-      correction.setProperty("InputWorkspaces", "00, 01, 11");
-      correction.setProperty("OutputWorkspace", "output");
-      correction.setProperty("Flippers", "00, 01, 11");
-      correction.setProperty("Efficiencies", m_effWS);
-      TS_ASSERT_THROWS_NOTHING(correction.execute())
+    return names;
+  }
+
+  MatrixWorkspace_sptr createEfficiencies(std::string const &kind) {
+    static std::map<std::string, std::vector<std::string>> const labels = {
+        {"Wildes", {"P1", "P2", "F1", "F2"}},
+        {"Fredrikze", {"Pp", "Ap", "Rho", "Alpha"}}};
+    if (kind == "Wildes" || kind == "Fredrikze") {
+      auto inWS = createWorkspaces(1)[0];
+      MatrixWorkspace_sptr ws = WorkspaceFactory::Instance().create(inWS, 4);
+      ws->getAxis(0)->setUnit("Wavelength");
+      auto axis1 = new TextAxis(4);
+      ws->replaceAxis(1, axis1);
+      auto const &current_labels = labels.at(kind);
+      for (size_t i = 0; i < ws->getNumberHistograms(); ++i) {
+        axis1->setLabel(i, current_labels[i]);
+      }
+      return ws;
+    } else if (kind == "histo") {
+      auto ws1 = createHistoWS(10, 0, 10);
+      auto ws2 = createHistoWS(10, 0, 10);
+      auto ws3 = createHistoWS(10, 0, 10);
+      auto ws4 = createHistoWS(10, 0, 10);
+
+      auto alg = AlgorithmFactory::Instance().create(
+          "JoinISISPolarizationEfficiencies", -1);
+      alg->initialize();
+      alg->setChild(true);
+      alg->setRethrows(true);
+      alg->setProperty("P1", ws1);
+      alg->setProperty("P2", ws2);
+      alg->setProperty("F1", ws3);
+      alg->setProperty("F2", ws4);
+      alg->setPropertyValue("OutputWorkspace", "dummy");
+      alg->execute();
+      MatrixWorkspace_sptr outWS = alg->getProperty("OutputWorkspace");
+      return outWS;
+    } else if (kind == "points") {
+      auto ws1 = createPointWS(10, 0, 10);
+      auto ws2 = createPointWS(10, 0, 10);
+      auto ws3 = createPointWS(10, 0, 10);
+      auto ws4 = createPointWS(10, 0, 10);
+
+      auto alg = AlgorithmFactory::Instance().create(
+          "JoinISISPolarizationEfficiencies", -1);
+      alg->initialize();
+      alg->setChild(true);
+      alg->setRethrows(true);
+      alg->setProperty("P1", ws1);
+      alg->setProperty("P2", ws2);
+      alg->setProperty("F1", ws3);
+      alg->setProperty("F2", ws4);
+      alg->setPropertyValue("OutputWorkspace", "dummy");
+      alg->execute();
+      MatrixWorkspace_sptr outWS = alg->getProperty("OutputWorkspace");
+      return outWS;
+    } else if (kind == "points-short") {
+      auto ws1 = createPointWS(4, 0, 10);
+      auto ws2 = createPointWS(4, 0, 10);
+      auto ws3 = createPointWS(4, 0, 10);
+      auto ws4 = createPointWS(4, 0, 10);
+
+      auto alg = AlgorithmFactory::Instance().create(
+          "JoinISISPolarizationEfficiencies", -1);
+      alg->initialize();
+      alg->setChild(true);
+      alg->setRethrows(true);
+      alg->setProperty("P1", ws1);
+      alg->setProperty("P2", ws2);
+      alg->setProperty("F1", ws3);
+      alg->setProperty("F2", ws4);
+      alg->setPropertyValue("OutputWorkspace", "dummy");
+      alg->execute();
+      MatrixWorkspace_sptr outWS = alg->getProperty("OutputWorkspace");
+      return outWS;
     }
+    throw std::logic_error("Unknown efficeincy test kind");
   }
 
-  void test_TwoInputsNoAnalyzerPerformance() {
-    using namespace Mantid::API;
-    for (int i = 0; i < 3000; ++i) {
-      PolarizationEfficiencyCor correction;
-      correction.setChild(true);
-      correction.setRethrows(true);
-      correction.initialize();
-      correction.setProperty("InputWorkspaces", "00, 11");
-      correction.setProperty("OutputWorkspace", "output");
-      correction.setProperty("Flippers", "0, 1");
-      correction.setProperty("Efficiencies", m_effWS);
-      TS_ASSERT_THROWS_NOTHING(correction.execute())
-    }
+  MatrixWorkspace_sptr createHistoWS(size_t size, double startX,
+                                     double endX) const {
+    double const dX = (endX - startX) / double(size);
+    BinEdges xVals(size + 1, LinearGenerator(startX, dX));
+    Counts yVals(size, 1.0);
+    auto retVal = boost::make_shared<Workspace2D>();
+    retVal->initialize(1, Histogram(xVals, yVals));
+    return retVal;
   }
 
-  void test_TwoInputsPerformance() {
-    using namespace Mantid::API;
-    for (int i = 0; i < 3000; ++i) {
-      PolarizationEfficiencyCor correction;
-      correction.setChild(true);
-      correction.setRethrows(true);
-      correction.initialize();
-      correction.setProperty("InputWorkspaces", "00, 11");
-      correction.setProperty("OutputWorkspace", "output");
-      correction.setProperty("Flippers", "00, 11");
-      correction.setProperty("Efficiencies", m_effWS);
-      TS_ASSERT_THROWS_NOTHING(correction.execute())
-    }
+  MatrixWorkspace_sptr createPointWS(size_t size, double startX,
+                                     double endX) const {
+    double const dX = (endX - startX) / double(size - 1);
+    Points xVals(size, LinearGenerator(startX, dX));
+    Counts yVals(size, 1.0);
+    auto retVal = boost::make_shared<Workspace2D>();
+    retVal->initialize(1, Histogram(xVals, yVals));
+    return retVal;
   }
-
-private:
-  Mantid::API::MatrixWorkspace_sptr m_effWS;
-  Mantid::API::MatrixWorkspace_sptr m_ws00;
-  Mantid::API::MatrixWorkspace_sptr m_ws01;
-  Mantid::API::MatrixWorkspace_sptr m_ws10;
-  Mantid::API::MatrixWorkspace_sptr m_ws11;
 };
 
 #endif /* MANTID_ALGORITHMS_POLARIZATIONEFFICIENCYCORTEST_H_ */
diff --git a/Framework/Algorithms/test/ReflectometryReductionOneAuto2Test.h b/Framework/Algorithms/test/ReflectometryReductionOneAuto2Test.h
index 328fd8d98ea89de92988c67e1981416f07747db4..8179b8eac358dc690d3d564f5817b339555586a3 100644
--- a/Framework/Algorithms/test/ReflectometryReductionOneAuto2Test.h
+++ b/Framework/Algorithms/test/ReflectometryReductionOneAuto2Test.h
@@ -564,6 +564,88 @@ public:
     TS_ASSERT_DELTA(outQ->x(0)[0], 0.3353, 0.0001);
     TS_ASSERT_DELTA(outQ->x(0)[7], 0.5962, 0.0001);
   }
+
+  void test_polarization_correction() {
+
+    MatrixWorkspace_sptr first = m_TOF->clone();
+    MatrixWorkspace_sptr second = m_TOF->clone();
+    MatrixWorkspace_sptr third = m_TOF->clone();
+    MatrixWorkspace_sptr fourth = m_TOF->clone();
+
+    WorkspaceGroup_sptr inputWSGroup = boost::make_shared<WorkspaceGroup>();
+    inputWSGroup->addWorkspace(first);
+    inputWSGroup->addWorkspace(second);
+    inputWSGroup->addWorkspace(third);
+    inputWSGroup->addWorkspace(fourth);
+    WorkspaceGroup_sptr transWSGroup = boost::make_shared<WorkspaceGroup>();
+    transWSGroup->addWorkspace(first);
+    transWSGroup->addWorkspace(second);
+    transWSGroup->addWorkspace(third);
+    transWSGroup->addWorkspace(fourth);
+    AnalysisDataService::Instance().addOrReplace("input", inputWSGroup);
+    AnalysisDataService::Instance().addOrReplace("trans", transWSGroup);
+
+    ReflectometryReductionOneAuto2 alg;
+    alg.initialize();
+    alg.setPropertyValue("InputWorkspace", "input");
+    alg.setPropertyValue("FirstTransmissionRun", "trans");
+    alg.setProperty("WavelengthMin", 1.5);
+    alg.setProperty("WavelengthMax", 15.0);
+    alg.setProperty("ProcessingInstructions", "2");
+    alg.setProperty("MomentumTransferStep", 0.04);
+    alg.setProperty("PolarizationAnalysis", "PA");
+    alg.setProperty("Pp", "1,1,2");
+    alg.setProperty("Ap", "1,1,2");
+    alg.setProperty("Rho", "1,1");
+    alg.setProperty("Alpha", "1");
+    alg.setPropertyValue("OutputWorkspace", "IvsQ");
+    alg.setPropertyValue("OutputWorkspaceBinned", "IvsQ_binned");
+    alg.setPropertyValue("OutputWorkspaceWavelength", "IvsLam");
+    alg.execute();
+    auto outQGroup =
+        AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>("IvsQ");
+    auto outLamGroup =
+        AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>("IvsLam");
+
+    TS_ASSERT(outQGroup);
+    TS_ASSERT(outLamGroup);
+
+    if (!outQGroup || !outLamGroup)
+      return;
+
+    TS_ASSERT_EQUALS(outQGroup->size(), 4);
+    TS_ASSERT_EQUALS(outLamGroup->size(), 4);
+
+    {
+      auto outQ =
+          boost::dynamic_pointer_cast<MatrixWorkspace>(outQGroup->getItem(0));
+      TS_ASSERT_EQUALS(outQ->getNumberHistograms(), 1);
+      TS_ASSERT_EQUALS(outQ->blocksize(), 14);
+      // X range in outQ
+      TS_ASSERT_DELTA(outQ->x(0)[0], 0.3353, 0.0001);
+      TS_ASSERT_DELTA(outQ->x(0)[7], 0.5962, 0.0001);
+      auto outLam =
+          boost::dynamic_pointer_cast<MatrixWorkspace>(outLamGroup->getItem(0));
+      // X range in outLam
+      TS_ASSERT_DELTA(outLam->x(0)[0], 1.7924, 0.0001);
+      TS_ASSERT_DELTA(outLam->x(0)[7], 8.0658, 0.0001);
+    }
+
+    {
+      auto outQ =
+          boost::dynamic_pointer_cast<MatrixWorkspace>(outQGroup->getItem(1));
+      TS_ASSERT_EQUALS(outQ->getNumberHistograms(), 1);
+      TS_ASSERT_EQUALS(outQ->blocksize(), 14);
+      // X range in outQ
+      TS_ASSERT_DELTA(outQ->x(0)[0], 0.3353, 0.0001);
+      TS_ASSERT_DELTA(outQ->x(0)[7], 0.5962, 0.0001);
+      auto outLam =
+          boost::dynamic_pointer_cast<MatrixWorkspace>(outLamGroup->getItem(1));
+      // X range in outLam
+      TS_ASSERT_DELTA(outLam->x(0)[0], 1.7924, 0.0001);
+      TS_ASSERT_DELTA(outLam->x(0)[7], 8.0658, 0.0001);
+    }
+  }
 };
 
 #endif /* MANTID_ALGORITHMS_REFLECTOMETRYREDUCTIONONEAUTO2TEST_H_ */
diff --git a/Framework/DataHandling/CMakeLists.txt b/Framework/DataHandling/CMakeLists.txt
index ac72a225b3cb983663e85098436aabeaebe43f9f..220c1e62f1facd25ab13c450db3d99f91e1a1663 100644
--- a/Framework/DataHandling/CMakeLists.txt
+++ b/Framework/DataHandling/CMakeLists.txt
@@ -7,6 +7,8 @@ set ( SRC_FILES
 	src/CreateChopperModel.cpp
 	src/CreateChunkingFromInstrument.cpp
 	src/CreateModeratorModel.cpp
+	src/CreatePolarizationEfficiencies.cpp
+	src/CreatePolarizationEfficienciesBase.cpp
 	src/CreateSampleShape.cpp
 	src/CreateSimulationWorkspace.cpp
 	src/DataBlock.cpp
@@ -29,6 +31,7 @@ set ( SRC_FILES
 	src/H5Util.cpp
 	src/ISISDataArchive.cpp
 	src/ISISRunLogs.cpp
+	src/JoinISISPolarizationEfficiencies.cpp
 	src/Load.cpp
 	src/LoadANSTOHelper.cpp
 	src/LoadAscii.cpp
@@ -60,6 +63,7 @@ set ( SRC_FILES
 	src/LoadILLSANS.cpp
 	src/LoadILLTOF2.cpp
 	src/LoadISISNexus2.cpp
+	src/LoadISISPolarizationEfficiencies.cpp
 	src/LoadInstrument.cpp
 	src/LoadInstrumentFromNexus.cpp
 	src/LoadInstrumentFromRaw.cpp
@@ -190,6 +194,8 @@ set ( INC_FILES
 	inc/MantidDataHandling/CreateChopperModel.h
 	inc/MantidDataHandling/CreateChunkingFromInstrument.h
 	inc/MantidDataHandling/CreateModeratorModel.h
+	inc/MantidDataHandling/CreatePolarizationEfficiencies.h
+	inc/MantidDataHandling/CreatePolarizationEfficienciesBase.h
 	inc/MantidDataHandling/CreateSampleShape.h
 	inc/MantidDataHandling/CreateSimulationWorkspace.h
 	inc/MantidDataHandling/DataBlock.h
@@ -212,6 +218,7 @@ set ( INC_FILES
 	inc/MantidDataHandling/H5Util.h
 	inc/MantidDataHandling/ISISDataArchive.h
 	inc/MantidDataHandling/ISISRunLogs.h
+	inc/MantidDataHandling/JoinISISPolarizationEfficiencies.h
 	inc/MantidDataHandling/Load.h
 	inc/MantidDataHandling/LoadANSTOHelper.h
 	inc/MantidDataHandling/LoadAscii.h
@@ -243,6 +250,7 @@ set ( INC_FILES
 	inc/MantidDataHandling/LoadILLSANS.h
 	inc/MantidDataHandling/LoadILLTOF2.h
 	inc/MantidDataHandling/LoadISISNexus2.h
+	inc/MantidDataHandling/LoadISISPolarizationEfficiencies.h
 	inc/MantidDataHandling/LoadInstrument.h
 	inc/MantidDataHandling/LoadInstrumentFromNexus.h
 	inc/MantidDataHandling/LoadInstrumentFromRaw.h
@@ -372,6 +380,7 @@ set ( TEST_FILES
 	CreateChopperModelTest.h
 	CreateChunkingFromInstrumentTest.h
 	CreateModeratorModelTest.h
+	CreatePolarizationEfficienciesTest.h
 	CreateSampleShapeTest.h
 	CreateSimulationWorkspaceTest.h
 	DataBlockCompositeTest.h
@@ -393,6 +402,7 @@ set ( TEST_FILES
 	H5UtilTest.h
 	ISISDataArchiveTest.h
 	InstrumentRayTracerTest.h
+	JoinISISPolarizationEfficienciesTest.h
 	LoadAscii2Test.h
 	LoadAsciiTest.h
 	LoadBBYTest.h
@@ -419,6 +429,7 @@ set ( TEST_FILES
 	LoadILLSANSTest.h
 	LoadILLTOF2Test.h
 	LoadISISNexusTest.h
+	LoadISISPolarizationEfficienciesTest.h
 	LoadInstrumentFromNexusTest.h
 	LoadInstrumentFromRawTest.h
 	LoadInstrumentTest.h
diff --git a/Framework/DataHandling/inc/MantidDataHandling/CreatePolarizationEfficiencies.h b/Framework/DataHandling/inc/MantidDataHandling/CreatePolarizationEfficiencies.h
new file mode 100644
index 0000000000000000000000000000000000000000..866107fb77eeab024bb62d0cb44d198f1adae191
--- /dev/null
+++ b/Framework/DataHandling/inc/MantidDataHandling/CreatePolarizationEfficiencies.h
@@ -0,0 +1,50 @@
+#ifndef MANTID_DATAHANDLING_CREATEPOLARIZATIONEFFICIENCIES_H_
+#define MANTID_DATAHANDLING_CREATEPOLARIZATIONEFFICIENCIES_H_
+
+#include "MantidKernel/System.h"
+#include "MantidDataHandling/CreatePolarizationEfficienciesBase.h"
+
+namespace Mantid {
+namespace DataHandling {
+
+/** CreatePolarizationEfficiencies
+
+ Copyright &copy; 2014 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge
+ National Laboratory & European Spallation Source
+
+ This file is part of Mantid.
+
+ Mantid is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ Mantid is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+ File change history is stored at: <https://github.com/mantidproject/mantid>
+ Code Documentation is available at: <http://doxygen.mantidproject.org>
+ */
+class DLLExport CreatePolarizationEfficiencies
+    : public CreatePolarizationEfficienciesBase {
+public:
+  const std::string name() const override;
+  int version() const override;
+  const std::string summary() const override;
+  const std::vector<std::string> seeAlso() const override;
+
+private:
+  void init() override;
+  API::MatrixWorkspace_sptr
+  createEfficiencies(std::vector<std::string> const &labels) override;
+};
+
+} // namespace DataHandling
+} // namespace Mantid
+
+#endif /* MANTID_DATAHANDLING_CREATEPOLARIZATIONEFFICIENCIES_H_ */
diff --git a/Framework/DataHandling/inc/MantidDataHandling/CreatePolarizationEfficienciesBase.h b/Framework/DataHandling/inc/MantidDataHandling/CreatePolarizationEfficienciesBase.h
new file mode 100644
index 0000000000000000000000000000000000000000..946505d59fa86c0e767c975f294f46d45e70e8b0
--- /dev/null
+++ b/Framework/DataHandling/inc/MantidDataHandling/CreatePolarizationEfficienciesBase.h
@@ -0,0 +1,71 @@
+#ifndef MANTID_DATAHANDLING_CREATEPOLARIZATIONEFFICIENCIESBASE_H_
+#define MANTID_DATAHANDLING_CREATEPOLARIZATIONEFFICIENCIESBASE_H_
+
+#include "MantidKernel/System.h"
+#include "MantidAPI/Algorithm.h"
+#include "MantidAPI/MatrixWorkspace_fwd.h"
+#include <boost/shared_ptr.hpp>
+#include <boost/optional.hpp>
+
+namespace Mantid {
+namespace DataHandling {
+
+/** CreatePolarizationEfficienciesBase - the base class for algorithms
+ that create polarization efficiency workspaces:
+
+   - CreatePolarizationEfficiencies
+   - JoinISISPolarizationEfficiencies
+   - LoadISISPolarizationEfficiencies
+
+ Copyright &copy; 2014 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge
+ National Laboratory & European Spallation Source
+
+ This file is part of Mantid.
+
+ Mantid is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ Mantid is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+ File change history is stored at: <https://github.com/mantidproject/mantid>
+ Code Documentation is available at: <http://doxygen.mantidproject.org>
+ */
+class DLLExport CreatePolarizationEfficienciesBase : public API::Algorithm {
+public:
+  const std::string category() const override;
+
+protected:
+  void initOutputWorkspace();
+  std::vector<std::string>
+  getNonDefaultProperties(std::vector<std::string> const &props) const;
+
+  /// Names of the efficiency properties
+  static std::string const Pp;
+  static std::string const Ap;
+  static std::string const Rho;
+  static std::string const Alpha;
+  static std::string const P1;
+  static std::string const P2;
+  static std::string const F1;
+  static std::string const F2;
+
+private:
+  void exec() override;
+  /// Create the output workspace with efficiencies
+  /// @param labels :: Names of the efficiencies to create
+  virtual API::MatrixWorkspace_sptr
+  createEfficiencies(std::vector<std::string> const &labels) = 0;
+};
+
+} // namespace DataHandling
+} // namespace Mantid
+
+#endif /* MANTID_DATAHANDLING_CREATEPOLARIZATIONEFFICIENCIESBASE_H_ */
diff --git a/Framework/DataHandling/inc/MantidDataHandling/JoinISISPolarizationEfficiencies.h b/Framework/DataHandling/inc/MantidDataHandling/JoinISISPolarizationEfficiencies.h
new file mode 100644
index 0000000000000000000000000000000000000000..1c154187cee55be1e2d2132654d167364cdac419
--- /dev/null
+++ b/Framework/DataHandling/inc/MantidDataHandling/JoinISISPolarizationEfficiencies.h
@@ -0,0 +1,62 @@
+#ifndef MANTID_DATAHANDLING_JOINISISPOLARIZATIONEFFICIENCIES_H_
+#define MANTID_DATAHANDLING_JOINISISPOLARIZATIONEFFICIENCIES_H_
+
+#include "MantidDataHandling/CreatePolarizationEfficienciesBase.h"
+#include "MantidDataHandling/DllConfig.h"
+
+namespace Mantid {
+namespace DataHandling {
+
+/** JoinISISPolarizationEfficiencies : Joins reflectometry polarization
+  efficiency correction factors to form a single matrix workspace.
+
+  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_DATAHANDLING_DLL JoinISISPolarizationEfficiencies
+    : public CreatePolarizationEfficienciesBase {
+public:
+  const std::string name() const override;
+  int version() const override;
+  const std::string summary() const override;
+  const std::vector<std::string> seeAlso() const override;
+
+private:
+  void init() override;
+  API::MatrixWorkspace_sptr
+  createEfficiencies(std::vector<std::string> const &props) override;
+  API::MatrixWorkspace_sptr
+  createEfficiencies(std::vector<std::string> const &labels,
+                     std::vector<API::MatrixWorkspace_sptr> const &workspaces);
+  std::vector<API::MatrixWorkspace_sptr> interpolateWorkspaces(
+      std::vector<API::MatrixWorkspace_sptr> const &workspaces);
+  API::MatrixWorkspace_sptr
+  interpolatePointDataWorkspace(API::MatrixWorkspace_sptr ws,
+                                size_t const maxSize);
+  API::MatrixWorkspace_sptr
+  interpolateHistogramWorkspace(API::MatrixWorkspace_sptr ws,
+                                size_t const maxSize);
+};
+
+} // namespace DataHandling
+} // namespace Mantid
+
+#endif /* MANTID_DATAHANDLING_JOINISISPOLARIZATIONEFFICIENCIES_H_ */
diff --git a/Framework/DataHandling/inc/MantidDataHandling/LoadISISPolarizationEfficiencies.h b/Framework/DataHandling/inc/MantidDataHandling/LoadISISPolarizationEfficiencies.h
new file mode 100644
index 0000000000000000000000000000000000000000..e341b5bacbabe575f650a5ad55db9922b84aced6
--- /dev/null
+++ b/Framework/DataHandling/inc/MantidDataHandling/LoadISISPolarizationEfficiencies.h
@@ -0,0 +1,51 @@
+#ifndef MANTID_DATAHANDLING_LOADISISPOLARIZATIONEFFICIENCIES_H_
+#define MANTID_DATAHANDLING_LOADISISPOLARIZATIONEFFICIENCIES_H_
+
+#include "MantidDataHandling/CreatePolarizationEfficienciesBase.h"
+#include "MantidDataHandling/DllConfig.h"
+
+namespace Mantid {
+namespace DataHandling {
+
+/** LoadISISPolarizationEfficiencies : Load reflectometry polarization
+  efficiency correction factors from disk.
+
+  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_DATAHANDLING_DLL LoadISISPolarizationEfficiencies
+    : public CreatePolarizationEfficienciesBase {
+public:
+  const std::string name() const override;
+  int version() const override;
+  const std::string summary() const override;
+  const std::vector<std::string> seeAlso() const override;
+
+private:
+  void init() override;
+  API::MatrixWorkspace_sptr
+  createEfficiencies(std::vector<std::string> const &props) override;
+};
+
+} // namespace DataHandling
+} // namespace Mantid
+
+#endif /* MANTID_DATAHANDLING_LOADISISPOLARIZATIONEFFICIENCIES_H_ */
diff --git a/Framework/DataHandling/src/CreatePolarizationEfficiencies.cpp b/Framework/DataHandling/src/CreatePolarizationEfficiencies.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a6cce278dc695fc9a896e75773376b0c60fedbfe
--- /dev/null
+++ b/Framework/DataHandling/src/CreatePolarizationEfficiencies.cpp
@@ -0,0 +1,142 @@
+#include "MantidDataHandling/CreatePolarizationEfficiencies.h"
+#include "MantidAPI/AnalysisDataService.h"
+#include "MantidAPI/TextAxis.h"
+#include "MantidAPI/WorkspaceFactory.h"
+#include "MantidAPI/WorkspaceHistory.h"
+#include "MantidDataObjects/WorkspaceSingleValue.h"
+#include "MantidKernel/ArrayProperty.h"
+#include "MantidKernel/ListValidator.h"
+#include "MantidKernel/Unit.h"
+#include "MantidGeometry/Instrument.h"
+
+#include <boost/shared_ptr.hpp>
+
+#include <algorithm>
+
+using namespace Mantid::API;
+using namespace Mantid::Kernel;
+using namespace Mantid::Geometry;
+
+namespace {
+
+double calculatePolynomial(std::vector<double> const &coefficients, double x) {
+  double polynomial = coefficients[0];
+  double xPow = 1.0;
+  // Build up the polynomial in ascending powers of x
+  for (size_t i = 1; i < coefficients.size(); ++i) {
+    xPow *= x;
+    polynomial += coefficients[i] * xPow;
+  }
+  return polynomial;
+}
+
+} // namespace
+
+namespace Mantid {
+namespace DataHandling {
+
+DECLARE_ALGORITHM(CreatePolarizationEfficiencies)
+
+const std::string CreatePolarizationEfficiencies::name() const {
+  return "CreatePolarizationEfficiencies";
+}
+
+int CreatePolarizationEfficiencies::version() const { return 1; }
+
+const std::string CreatePolarizationEfficiencies::summary() const {
+  return "Converts polynomial factors to histograms with polarization "
+         "efficiencies.";
+}
+
+const std::vector<std::string> CreatePolarizationEfficiencies::seeAlso() const {
+  return {"JoinISISPolarizationEfficiencies",
+          "LoadISISPolarizationEfficiencies", "PolarizationEfficiencyCor"};
+}
+
+void CreatePolarizationEfficiencies::init() {
+  declareProperty(make_unique<WorkspaceProperty<Mantid::API::MatrixWorkspace>>(
+                      "InputWorkspace", "", Direction::Input),
+                  "An input workspace to use the x-values from.");
+
+  declareProperty(
+      Kernel::make_unique<ArrayProperty<double>>(Pp, Direction::Input),
+      "Effective polarizing power of the polarizing system. "
+      "Expressed as a ratio 0 < Pp < 1");
+
+  declareProperty(
+      Kernel::make_unique<ArrayProperty<double>>(Ap, Direction::Input),
+      "Effective polarizing power of the analyzing system. "
+      "Expressed as a ratio 0 < Ap < 1");
+
+  declareProperty(
+      Kernel::make_unique<ArrayProperty<double>>(Rho, Direction::Input),
+      "Ratio of efficiencies of polarizer spin-down to polarizer "
+      "spin-up. This is characteristic of the polarizer flipper. "
+      "Values are constants for each term in a polynomial "
+      "expression.");
+
+  declareProperty(
+      Kernel::make_unique<ArrayProperty<double>>(Alpha, Direction::Input),
+      "Ratio of efficiencies of analyzer spin-down to analyzer "
+      "spin-up. This is characteristic of the analyzer flipper. "
+      "Values are factors for each term in a polynomial "
+      "expression.");
+
+  declareProperty(
+      Kernel::make_unique<ArrayProperty<double>>(P1, Direction::Input),
+      "Polarizer efficiency.");
+
+  declareProperty(
+      Kernel::make_unique<ArrayProperty<double>>(P2, Direction::Input),
+      "Analyzer efficiency.");
+
+  declareProperty(
+      Kernel::make_unique<ArrayProperty<double>>(F1, Direction::Input),
+      "Polarizer flipper efficiency.");
+
+  declareProperty(
+      Kernel::make_unique<ArrayProperty<double>>(F2, Direction::Input),
+      "Analyzer flipper efficiency.");
+
+  initOutputWorkspace();
+}
+
+/// Create the efficiencies workspace given names of input properties.
+/// @param labels :: Names of efficiencies which to include in the output
+/// workspace.
+MatrixWorkspace_sptr CreatePolarizationEfficiencies::createEfficiencies(
+    std::vector<std::string> const &labels) {
+
+  std::vector<std::vector<double>> polynomialCoefficients;
+
+  for (auto const &label : labels) {
+    polynomialCoefficients.emplace_back<std::vector<double>>(
+        getProperty(label));
+  }
+
+  MatrixWorkspace_sptr inWS = getProperty("InputWorkspace");
+  auto sharedInX = inWS->sharedX(0);
+
+  MatrixWorkspace_sptr outWS = WorkspaceFactory::Instance().create(
+      inWS, labels.size(), sharedInX->size(), inWS->blocksize());
+  auto axis1 = new TextAxis(labels.size());
+  outWS->replaceAxis(1, axis1);
+  outWS->getAxis(0)->setUnit(inWS->getAxis(0)->unit()->unitID());
+
+  auto const x = inWS->points(0);
+  std::vector<double> y(x.size());
+  for (size_t i = 0; i < labels.size(); ++i) {
+    outWS->setSharedX(i, sharedInX);
+    auto const &coefficients = polynomialCoefficients[i];
+    std::transform(x.begin(), x.end(), y.begin(), [&coefficients](double v) {
+      return calculatePolynomial(coefficients, v);
+    });
+    outWS->mutableY(i) = y;
+    axis1->setLabel(i, labels[i]);
+  }
+
+  return outWS;
+}
+
+} // namespace Algorithms
+} // namespace Mantid
diff --git a/Framework/DataHandling/src/CreatePolarizationEfficienciesBase.cpp b/Framework/DataHandling/src/CreatePolarizationEfficienciesBase.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..7a3747f42a619cabf1533d87ecda9813b636c812
--- /dev/null
+++ b/Framework/DataHandling/src/CreatePolarizationEfficienciesBase.cpp
@@ -0,0 +1,81 @@
+#include "MantidDataHandling/CreatePolarizationEfficienciesBase.h"
+#include "MantidAPI/AnalysisDataService.h"
+#include "MantidAPI/TextAxis.h"
+#include "MantidAPI/WorkspaceFactory.h"
+#include "MantidAPI/WorkspaceHistory.h"
+#include "MantidDataObjects/WorkspaceSingleValue.h"
+#include "MantidKernel/ArrayProperty.h"
+#include "MantidKernel/ListValidator.h"
+#include "MantidKernel/Unit.h"
+#include "MantidGeometry/Instrument.h"
+
+#include <boost/shared_ptr.hpp>
+
+#include <algorithm>
+
+using namespace Mantid::API;
+using namespace Mantid::Kernel;
+using namespace Mantid::Geometry;
+
+namespace Mantid {
+namespace DataHandling {
+
+std::string const CreatePolarizationEfficienciesBase::Pp("Pp");
+std::string const CreatePolarizationEfficienciesBase::Ap("Ap");
+std::string const CreatePolarizationEfficienciesBase::Rho("Rho");
+std::string const CreatePolarizationEfficienciesBase::Alpha("Alpha");
+std::string const CreatePolarizationEfficienciesBase::P1("P1");
+std::string const CreatePolarizationEfficienciesBase::P2("P2");
+std::string const CreatePolarizationEfficienciesBase::F1("F1");
+std::string const CreatePolarizationEfficienciesBase::F2("F2");
+
+const std::string CreatePolarizationEfficienciesBase::category() const {
+  return "Reflectometry";
+}
+
+void CreatePolarizationEfficienciesBase::initOutputWorkspace() {
+  declareProperty(make_unique<WorkspaceProperty<Mantid::API::MatrixWorkspace>>(
+                      "OutputWorkspace", "", Direction::Output),
+                  "An output workspace.");
+}
+
+void CreatePolarizationEfficienciesBase::exec() {
+  auto const labelsFredrikze = getNonDefaultProperties({Pp, Ap, Rho, Alpha});
+  auto const labelsWildes = getNonDefaultProperties({P1, P2, F1, F2});
+
+  if (labelsFredrikze.empty() && labelsWildes.empty()) {
+    throw std::invalid_argument(
+        "At least one of the efficiencies must be set.");
+  }
+
+  if (!labelsFredrikze.empty() && !labelsWildes.empty()) {
+    throw std::invalid_argument(
+        "Efficiencies belonging to different methods cannot mix.");
+  }
+
+  MatrixWorkspace_sptr efficiencies;
+  if (!labelsFredrikze.empty()) {
+    efficiencies = createEfficiencies(labelsFredrikze);
+  } else {
+    efficiencies = createEfficiencies(labelsWildes);
+  }
+
+  setProperty("OutputWorkspace", efficiencies);
+}
+
+/// Get names of non-default properties out of a list of names
+/// @param labels :: Names of properties to check.
+std::vector<std::string>
+CreatePolarizationEfficienciesBase::getNonDefaultProperties(
+    std::vector<std::string> const &labels) const {
+  std::vector<std::string> outputLabels;
+  for (auto const &label : labels) {
+    if (!isDefault(label)) {
+      outputLabels.emplace_back(label);
+    }
+  }
+  return outputLabels;
+}
+
+} // namespace Algorithms
+} // namespace Mantid
diff --git a/Framework/DataHandling/src/JoinISISPolarizationEfficiencies.cpp b/Framework/DataHandling/src/JoinISISPolarizationEfficiencies.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..96b5825b8ae470e1c0ca5b10db48045bf14e324b
--- /dev/null
+++ b/Framework/DataHandling/src/JoinISISPolarizationEfficiencies.cpp
@@ -0,0 +1,234 @@
+#include "MantidDataHandling/JoinISISPolarizationEfficiencies.h"
+
+#include "MantidAPI/FileProperty.h"
+#include "MantidAPI/TextAxis.h"
+#include "MantidAPI/WorkspaceFactory.h"
+#include "MantidDataObjects/Workspace2D.h"
+#include "MantidDataObjects/WorkspaceCreation.h"
+#include "MantidHistogramData/Histogram.h"
+#include "MantidHistogramData/Interpolate.h"
+#include "MantidHistogramData/LinearGenerator.h"
+#include "MantidKernel/make_unique.h"
+#include <limits>
+
+using namespace Mantid::API;
+using namespace Mantid::DataObjects;
+using namespace Mantid::HistogramData;
+using namespace Mantid::Kernel;
+
+namespace Mantid {
+namespace DataHandling {
+
+// Register the algorithm into the AlgorithmFactory
+DECLARE_ALGORITHM(JoinISISPolarizationEfficiencies)
+
+//----------------------------------------------------------------------------------------------
+
+/// Algorithms name for identification. @see Algorithm::name
+const std::string JoinISISPolarizationEfficiencies::name() const {
+  return "JoinISISPolarizationEfficiencies";
+}
+
+/// Algorithm's version for identification. @see Algorithm::version
+int JoinISISPolarizationEfficiencies::version() const { return 1; }
+
+/// Algorithm's summary for use in the GUI and help. @see Algorithm::summary
+const std::string JoinISISPolarizationEfficiencies::summary() const {
+  return "Joins workspaces containing ISIS reflectometry polarization "
+         "efficiency factors into a single workspace ready to be used with "
+         "PolarizationEfficiencyCor.";
+}
+
+const std::vector<std::string>
+JoinISISPolarizationEfficiencies::seeAlso() const {
+  return {"CreatePolarizationEfficiencies", "LoadISISPolarizationEfficiencies",
+          "PolarizationEfficiencyCor"};
+}
+
+//----------------------------------------------------------------------------------------------
+/** Initialize the algorithm's properties.
+ */
+void JoinISISPolarizationEfficiencies::init() {
+
+  declareProperty(
+      Kernel::make_unique<WorkspaceProperty<MatrixWorkspace>>(
+          Pp, "", Kernel::Direction::Input, PropertyMode::Optional),
+      "A matrix workspaces containing the Pp polarization efficiency.");
+
+  declareProperty(
+      Kernel::make_unique<WorkspaceProperty<MatrixWorkspace>>(
+          Ap, "", Kernel::Direction::Input, PropertyMode::Optional),
+      "A matrix workspaces containing the Ap polarization efficiency.");
+
+  declareProperty(
+      Kernel::make_unique<WorkspaceProperty<MatrixWorkspace>>(
+          Rho, "", Kernel::Direction::Input, PropertyMode::Optional),
+      "A matrix workspaces containing the Rho polarization efficiency.");
+
+  declareProperty(
+      Kernel::make_unique<WorkspaceProperty<MatrixWorkspace>>(
+          Alpha, "", Kernel::Direction::Input, PropertyMode::Optional),
+      "A matrix workspaces containing the Alpha polarization efficiency.");
+
+  declareProperty(
+      Kernel::make_unique<WorkspaceProperty<MatrixWorkspace>>(
+          P1, "", Kernel::Direction::Input, PropertyMode::Optional),
+      "A matrix workspaces containing the P1 polarization efficiency.");
+
+  declareProperty(
+      Kernel::make_unique<WorkspaceProperty<MatrixWorkspace>>(
+          P2, "", Kernel::Direction::Input, PropertyMode::Optional),
+      "A matrix workspaces containing the P2 polarization efficiency.");
+
+  declareProperty(
+      Kernel::make_unique<WorkspaceProperty<MatrixWorkspace>>(
+          F1, "", Kernel::Direction::Input, PropertyMode::Optional),
+      "A matrix workspaces containing the F1 polarization efficiency.");
+
+  declareProperty(
+      Kernel::make_unique<WorkspaceProperty<MatrixWorkspace>>(
+          F2, "", Kernel::Direction::Input, PropertyMode::Optional),
+      "A matrix workspaces containing the F2 polarization efficiency.");
+
+  initOutputWorkspace();
+}
+
+/// Load efficientcies from files and put them into a single workspace.
+/// @param props :: Names of properties containg names of files to load.
+MatrixWorkspace_sptr JoinISISPolarizationEfficiencies::createEfficiencies(
+    std::vector<std::string> const &props) {
+  std::vector<MatrixWorkspace_sptr> workspaces;
+  for (auto const &propName : props) {
+    MatrixWorkspace_sptr ws = getProperty(propName);
+    if (ws->getNumberHistograms() != 1) {
+      throw std::runtime_error(
+          "Loaded workspace must contain a single histogram. Found " +
+          std::to_string(ws->getNumberHistograms()));
+    }
+    workspaces.push_back(ws);
+  }
+
+  return createEfficiencies(props, workspaces);
+}
+
+/// Create the efficiency workspace by combining single spectra workspaces into
+/// one.
+/// @param labels :: Axis labels for each workspace.
+/// @param workspaces :: Workspaces to put together.
+MatrixWorkspace_sptr JoinISISPolarizationEfficiencies::createEfficiencies(
+    std::vector<std::string> const &labels,
+    std::vector<MatrixWorkspace_sptr> const &workspaces) {
+  auto interpolatedWorkspaces = interpolateWorkspaces(workspaces);
+
+  auto const &inWS = interpolatedWorkspaces.front();
+  MatrixWorkspace_sptr outWS = DataObjects::create<Workspace2D>(
+      *inWS, labels.size(), inWS->histogram(0));
+  auto axis1 = new TextAxis(labels.size());
+  outWS->replaceAxis(1, axis1);
+  outWS->getAxis(0)->setUnit("Wavelength");
+
+  for (size_t i = 0; i < interpolatedWorkspaces.size(); ++i) {
+    auto &ws = interpolatedWorkspaces[i];
+    outWS->mutableX(i) = ws->x(0);
+    outWS->mutableY(i) = ws->y(0);
+    outWS->mutableE(i) = ws->e(0);
+    axis1->setLabel(i, labels[i]);
+  }
+
+  return outWS;
+}
+
+/// Interpolate the workspaces so that all have the same blocksize.
+/// @param workspaces :: The workspaces to interpolate.
+/// @return A list of interpolated workspaces.
+std::vector<MatrixWorkspace_sptr>
+JoinISISPolarizationEfficiencies::interpolateWorkspaces(
+    std::vector<MatrixWorkspace_sptr> const &workspaces) {
+  size_t minSize(std::numeric_limits<size_t>::max());
+  size_t maxSize(0);
+  bool thereAreHistograms = false;
+  bool allAreHistograms = true;
+
+  // Find out if the workspaces need to be interpolated.
+  for (auto const &ws : workspaces) {
+    auto size = ws->blocksize();
+    if (size < minSize) {
+      minSize = size;
+    }
+    if (size > maxSize) {
+      maxSize = size;
+    }
+    thereAreHistograms = thereAreHistograms || ws->isHistogramData();
+    allAreHistograms = allAreHistograms && ws->isHistogramData();
+  }
+
+  if (thereAreHistograms != allAreHistograms) {
+    throw std::invalid_argument("Cannot mix histograms and point data.");
+  }
+
+  // All same size, same type - nothing to do
+  if (minSize == maxSize) {
+    return workspaces;
+  }
+
+  // Interpolate those that need interpolating
+  std::vector<MatrixWorkspace_sptr> interpolatedWorkspaces;
+  for (auto const &ws : workspaces) {
+    if (ws->blocksize() < maxSize) {
+      if (allAreHistograms) {
+        interpolatedWorkspaces.push_back(
+            interpolateHistogramWorkspace(ws, maxSize));
+      } else {
+        interpolatedWorkspaces.push_back(
+            interpolatePointDataWorkspace(ws, maxSize));
+      }
+    } else {
+      interpolatedWorkspaces.push_back(ws);
+    }
+  }
+
+  return interpolatedWorkspaces;
+}
+
+MatrixWorkspace_sptr
+JoinISISPolarizationEfficiencies::interpolatePointDataWorkspace(
+    MatrixWorkspace_sptr ws, size_t const maxSize) {
+  auto const &x = ws->x(0);
+  auto const startX = x.front();
+  auto const endX = x.back();
+  Counts yVals(maxSize, 0.0);
+  auto const dX = (endX - startX) / double(maxSize - 1);
+  Points xVals(maxSize, LinearGenerator(startX, dX));
+  auto newHisto = Histogram(xVals, yVals);
+  interpolateLinearInplace(ws->histogram(0), newHisto);
+  auto interpolatedWS = boost::make_shared<Workspace2D>();
+  interpolatedWS->initialize(1, newHisto);
+  assert(interpolatedWS->y(0).size() == maxSize);
+  return interpolatedWS;
+}
+
+MatrixWorkspace_sptr
+JoinISISPolarizationEfficiencies::interpolateHistogramWorkspace(
+    MatrixWorkspace_sptr ws, size_t const maxSize) {
+  ws->setDistribution(true);
+  auto const &x = ws->x(0);
+  auto const dX = (x.back() - x.front()) / double(maxSize);
+  std::vector<double> params(2 * maxSize + 1);
+  for (size_t i = 0; i < maxSize; ++i) {
+    params[2 * i] = x.front() + dX * double(i);
+    params[2 * i + 1] = dX;
+  }
+  params.back() = x.back();
+  auto alg = createChildAlgorithm("InterpolatingRebin");
+  alg->setProperty("InputWorkspace", ws);
+  alg->setProperty("Params", params);
+  alg->setProperty("OutputWorkspace", "dummy");
+  alg->execute();
+  MatrixWorkspace_sptr interpolatedWS = alg->getProperty("OutputWorkspace");
+  assert(interpolatedWS->y(0).size() == maxSize);
+  assert(interpolatedWS->x(0).size() == maxSize + 1);
+  return interpolatedWS;
+}
+
+} // namespace DataHandling
+} // namespace Mantid
diff --git a/Framework/DataHandling/src/LoadAscii2.cpp b/Framework/DataHandling/src/LoadAscii2.cpp
index 16742656887350eaeb14eddd395f522e0d55ef66..304cab3f647a97e8cf6b7883a7d8fabe09faa0cc 100644
--- a/Framework/DataHandling/src/LoadAscii2.cpp
+++ b/Framework/DataHandling/src/LoadAscii2.cpp
@@ -107,16 +107,20 @@ API::Workspace_sptr LoadAscii2::readData(std::ifstream &file) {
   try {
     localWorkspace = WorkspaceFactory::Instance().create(
         "Workspace2D", numSpectra, m_lastBins, m_lastBins);
-  } catch (std::exception &) {
-    throw std::runtime_error("Failed to create a Workspace2D from the "
-                             "data found in this file");
+  } catch (std::exception &e) {
+    std::ostringstream msg;
+    msg << "Failed to create a Workspace2D from the data found in this file. "
+           "Error: " << e.what();
+    throw std::runtime_error(msg.str());
   }
 
   try {
     writeToWorkspace(localWorkspace, numSpectra);
-  } catch (std::exception &) {
-    throw std::runtime_error("Failed to write read data into the "
-                             "output Workspace2D");
+  } catch (std::exception &e) {
+    std::ostringstream msg;
+    msg << "Failed to write read data into the output Workspace2D. Error: "
+        << e.what();
+    throw std::runtime_error(msg.str());
   }
   delete m_curSpectra;
   return localWorkspace;
diff --git a/Framework/DataHandling/src/LoadISISPolarizationEfficiencies.cpp b/Framework/DataHandling/src/LoadISISPolarizationEfficiencies.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..0d5e0b494693b8def90e49b702ebf410d93f0c34
--- /dev/null
+++ b/Framework/DataHandling/src/LoadISISPolarizationEfficiencies.cpp
@@ -0,0 +1,123 @@
+#include "MantidDataHandling/LoadISISPolarizationEfficiencies.h"
+
+#include "MantidAPI/FileProperty.h"
+#include "MantidAPI/TextAxis.h"
+#include "MantidAPI/WorkspaceFactory.h"
+#include "MantidDataObjects/Workspace2D.h"
+#include "MantidDataObjects/WorkspaceCreation.h"
+#include "MantidHistogramData/Histogram.h"
+#include "MantidHistogramData/Interpolate.h"
+#include "MantidKernel/make_unique.h"
+#include <limits>
+
+namespace Mantid {
+namespace DataHandling {
+
+using namespace Mantid::Kernel;
+using namespace Mantid::API;
+
+// Register the algorithm into the AlgorithmFactory
+DECLARE_ALGORITHM(LoadISISPolarizationEfficiencies)
+
+//----------------------------------------------------------------------------------------------
+
+/// Algorithms name for identification. @see Algorithm::name
+const std::string LoadISISPolarizationEfficiencies::name() const {
+  return "LoadISISPolarizationEfficiencies";
+}
+
+/// Algorithm's version for identification. @see Algorithm::version
+int LoadISISPolarizationEfficiencies::version() const { return 1; }
+
+/// Algorithm's summary for use in the GUI and help. @see Algorithm::summary
+const std::string LoadISISPolarizationEfficiencies::summary() const {
+  return "Loads ISIS reflectometry polarization efficiency factors from files: "
+         "one factor per file.";
+}
+
+const std::vector<std::string>
+LoadISISPolarizationEfficiencies::seeAlso() const {
+  return {"CreatePolarizationEfficiencies", "JoinISISPolarizationEfficiencies",
+          "PolarizationEfficiencyCor"};
+}
+
+//----------------------------------------------------------------------------------------------
+/** Initialize the algorithm's properties.
+ */
+void LoadISISPolarizationEfficiencies::init() {
+  declareProperty(Kernel::make_unique<API::FileProperty>(
+                      Pp, "", API::FileProperty::OptionalLoad),
+                  "Path to the file containing the Pp polarization efficiency "
+                  "in XYE columns.");
+
+  declareProperty(Kernel::make_unique<API::FileProperty>(
+                      Ap, "", API::FileProperty::OptionalLoad),
+                  "Path to the file containing the Ap polarization efficiency "
+                  "in XYE columns.");
+
+  declareProperty(Kernel::make_unique<API::FileProperty>(
+                      Rho, "", API::FileProperty::OptionalLoad),
+                  "Path to the file containing the Rho polarization efficiency "
+                  "in XYE columns.");
+
+  declareProperty(
+      Kernel::make_unique<API::FileProperty>(Alpha, "",
+                                             API::FileProperty::OptionalLoad),
+      "Path to the file containing the Alpha polarization efficiency "
+      "in XYE columns.");
+
+  declareProperty(Kernel::make_unique<API::FileProperty>(
+                      P1, "", API::FileProperty::OptionalLoad),
+                  "Path to the file containing the P1 polarization efficiency "
+                  "in XYE columns.");
+
+  declareProperty(Kernel::make_unique<API::FileProperty>(
+                      P2, "", API::FileProperty::OptionalLoad),
+                  "Path to the file containing the P2 polarization efficiency "
+                  "in XYE columns.");
+
+  declareProperty(Kernel::make_unique<API::FileProperty>(
+                      F1, "", API::FileProperty::OptionalLoad),
+                  "Path to the file containing the F1 polarization efficiency "
+                  "in XYE columns.");
+
+  declareProperty(Kernel::make_unique<API::FileProperty>(
+                      F2, "", API::FileProperty::OptionalLoad),
+                  "Path to the file containing the F2 polarization efficiency "
+                  "in XYE columns.");
+
+  initOutputWorkspace();
+}
+
+/// Load efficiencies from files and put them into a single workspace.
+/// @param props :: Names of properties containg names of files to load.
+MatrixWorkspace_sptr LoadISISPolarizationEfficiencies::createEfficiencies(
+    std::vector<std::string> const &props) {
+
+  auto alg = createChildAlgorithm("JoinISISPolarizationEfficiencies");
+  alg->initialize();
+  for (auto const &propName : props) {
+    auto loader = createChildAlgorithm("Load");
+    loader->initialize();
+    loader->setPropertyValue("Filename", getPropertyValue(propName));
+    loader->execute();
+    Workspace_sptr output = loader->getProperty("OutputWorkspace");
+    auto ws = boost::dynamic_pointer_cast<MatrixWorkspace>(output);
+    if (!ws) {
+      throw std::invalid_argument("File " + propName +
+                                  " cannot be loaded into a MatrixWorkspace.");
+    }
+    if (ws->getNumberHistograms() != 1) {
+      throw std::runtime_error(
+          "Loaded workspace must contain a single histogram. Found " +
+          std::to_string(ws->getNumberHistograms()));
+    }
+    alg->setProperty(propName, ws);
+  }
+  alg->execute();
+  MatrixWorkspace_sptr outWS = alg->getProperty("OutputWorkspace");
+  return outWS;
+}
+
+} // namespace DataHandling
+} // namespace Mantid
diff --git a/Framework/DataHandling/test/CreatePolarizationEfficienciesTest.h b/Framework/DataHandling/test/CreatePolarizationEfficienciesTest.h
new file mode 100644
index 0000000000000000000000000000000000000000..d7ba71c5edb28413e11b6cf790da3573b1e24401
--- /dev/null
+++ b/Framework/DataHandling/test/CreatePolarizationEfficienciesTest.h
@@ -0,0 +1,321 @@
+#ifndef MANTID_ALGORITHMS_CREATEPOLARIZATIONEFFICIENCIES_TEST_H_
+#define MANTID_ALGORITHMS_CREATEPOLARIZATIONEFFICIENCIES_TEST_H_
+
+#include <cxxtest/TestSuite.h>
+#include "MantidDataHandling/CreatePolarizationEfficiencies.h"
+#include "MantidAPI/Axis.h"
+#include "MantidKernel/Unit.h"
+#include "MantidDataObjects/Workspace2D.h"
+#include "MantidHistogramData/LinearGenerator.h"
+#include "MantidTestHelpers/WorkspaceCreationHelper.h"
+
+#include <boost/make_shared.hpp>
+
+using namespace Mantid::API;
+using namespace Mantid::DataHandling;
+using namespace Mantid::DataObjects;
+using namespace Mantid::HistogramData;
+using namespace WorkspaceCreationHelper;
+
+class CreatePolarizationEfficienciesTest : 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 CreatePolarizationEfficienciesTest *createSuite() {
+    return new CreatePolarizationEfficienciesTest();
+  }
+  static void destroySuite(CreatePolarizationEfficienciesTest *suite) {
+    delete suite;
+  }
+
+  void test_init() {
+    CreatePolarizationEfficiencies alg;
+    TS_ASSERT_THROWS_NOTHING(alg.initialize())
+    TS_ASSERT(alg.isInitialized())
+  }
+
+  void test_no_input() {
+    auto inWS = createPointWS();
+    CreatePolarizationEfficiencies alg;
+    alg.setChild(true);
+    alg.setRethrows(true);
+    alg.initialize();
+    alg.setProperty("InputWorkspace", inWS);
+    alg.setPropertyValue("OutputWorkspace", "dummy");
+    TS_ASSERT_THROWS(alg.execute(), std::invalid_argument);
+  }
+
+  void test_mixed_input() {
+    auto inWS = createHistoWS();
+
+    CreatePolarizationEfficiencies alg;
+    alg.setChild(true);
+    alg.setRethrows(true);
+    alg.initialize();
+    alg.setProperty("InputWorkspace", inWS);
+    alg.setPropertyValue("OutputWorkspace", "dummy");
+    alg.setPropertyValue("Pp", "1,0,0,0");
+    alg.setPropertyValue("Ap", "0,1,0,0");
+    alg.setPropertyValue("F1", "0,0,1,0");
+    alg.setPropertyValue("F2", "0,0,0,1");
+    TS_ASSERT_THROWS(alg.execute(), std::invalid_argument);
+  }
+
+  void test_histo() {
+    auto inWS = createHistoWS();
+
+    CreatePolarizationEfficiencies alg;
+    alg.setChild(true);
+    alg.setRethrows(true);
+    alg.initialize();
+    alg.setProperty("InputWorkspace", inWS);
+    alg.setPropertyValue("OutputWorkspace", "dummy");
+    alg.setPropertyValue("Pp", "1,0,0,0");
+    alg.setPropertyValue("Ap", "0,1,0,0");
+    alg.setPropertyValue("Rho", "0,0,1,0");
+    alg.setPropertyValue("Alpha", "0,0,0,1");
+    alg.execute();
+    MatrixWorkspace_sptr outWS = alg.getProperty("OutputWorkspace");
+
+    TS_ASSERT(outWS);
+    TS_ASSERT_EQUALS(outWS->getNumberHistograms(), 4);
+
+    TS_ASSERT_EQUALS(outWS->getAxis(0)->unit()->caption(), "Wavelength");
+
+    auto axis1 = outWS->getAxis(1);
+    TS_ASSERT_EQUALS(axis1->label(0), "Pp");
+    TS_ASSERT_EQUALS(axis1->label(1), "Ap");
+    TS_ASSERT_EQUALS(axis1->label(2), "Rho");
+    TS_ASSERT_EQUALS(axis1->label(3), "Alpha");
+
+    TS_ASSERT_DELTA(outWS->readY(0)[0], 1.0, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(0)[1], 1.0, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(0)[2], 1.0, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(0)[3], 1.0, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(0)[4], 1.0, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(0)[5], 1.0, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(0)[6], 1.0, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(0)[7], 1.0, 1e-15);
+
+    TS_ASSERT_DELTA(outWS->readY(1)[0], 0.25, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(1)[1], 0.75, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(1)[2], 1.25, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(1)[3], 1.75, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(1)[4], 2.25, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(1)[5], 2.75, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(1)[6], 3.25, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(1)[7], 3.75, 1e-15);
+
+    TS_ASSERT_DELTA(outWS->readY(2)[0], 0.0625, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(2)[1], 0.5625, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(2)[2], 1.5625, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(2)[3], 3.0625, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(2)[4], 5.0625, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(2)[5], 7.5625, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(2)[6], 10.5625, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(2)[7], 14.0625, 1e-15);
+
+    TS_ASSERT_DELTA(outWS->readY(3)[0], 0.015625, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(3)[1], 0.421875, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(3)[2], 1.953125, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(3)[3], 5.359375, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(3)[4], 11.390625, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(3)[5], 20.796875, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(3)[6], 34.328125, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(3)[7], 52.734375, 1e-15);
+  }
+
+  void test_histo_partial() {
+    auto inWS = createHistoWS();
+
+    CreatePolarizationEfficiencies alg;
+    alg.setChild(true);
+    alg.setRethrows(true);
+    alg.initialize();
+    alg.setProperty("InputWorkspace", inWS);
+    alg.setPropertyValue("OutputWorkspace", "dummy");
+    alg.setPropertyValue("Pp", "1,0,0,0");
+    alg.setPropertyValue("Rho", "0,0,1,0");
+    alg.execute();
+    MatrixWorkspace_sptr outWS = alg.getProperty("OutputWorkspace");
+
+    TS_ASSERT(outWS);
+    TS_ASSERT_EQUALS(outWS->getNumberHistograms(), 2);
+    TS_ASSERT_EQUALS(outWS->getAxis(0)->unit()->caption(), "Wavelength");
+
+    auto axis1 = outWS->getAxis(1);
+    TS_ASSERT_EQUALS(axis1->label(0), "Pp");
+    TS_ASSERT_EQUALS(axis1->label(1), "Rho");
+
+    TS_ASSERT_DELTA(outWS->readY(0)[0], 1.0, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(0)[1], 1.0, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(0)[2], 1.0, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(0)[3], 1.0, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(0)[4], 1.0, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(0)[5], 1.0, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(0)[6], 1.0, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(0)[7], 1.0, 1e-15);
+
+    TS_ASSERT_DELTA(outWS->readY(1)[0], 0.0625, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(1)[1], 0.5625, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(1)[2], 1.5625, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(1)[3], 3.0625, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(1)[4], 5.0625, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(1)[5], 7.5625, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(1)[6], 10.5625, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(1)[7], 14.0625, 1e-15);
+  }
+
+  void test_points() {
+    auto inWS = createPointWS();
+
+    CreatePolarizationEfficiencies alg;
+    alg.setChild(true);
+    alg.setRethrows(true);
+    alg.initialize();
+    alg.setProperty("InputWorkspace", inWS);
+    alg.setPropertyValue("OutputWorkspace", "dummy");
+    alg.setPropertyValue("Pp", "1,0,0,0");
+    alg.setPropertyValue("Ap", "0,1,0,0");
+    alg.setPropertyValue("Rho", "0,0,1,0");
+    alg.setPropertyValue("Alpha", "0,0,0,1");
+    alg.execute();
+    MatrixWorkspace_sptr outWS = alg.getProperty("OutputWorkspace");
+    TS_ASSERT_EQUALS(outWS->getAxis(0)->unit()->caption(), "Wavelength");
+
+    TS_ASSERT(outWS);
+    TS_ASSERT_EQUALS(outWS->getNumberHistograms(), 4);
+
+    auto axis1 = outWS->getAxis(1);
+    TS_ASSERT_EQUALS(axis1->label(0), "Pp");
+    TS_ASSERT_EQUALS(axis1->label(1), "Ap");
+    TS_ASSERT_EQUALS(axis1->label(2), "Rho");
+    TS_ASSERT_EQUALS(axis1->label(3), "Alpha");
+
+    TS_ASSERT_DELTA(outWS->readY(0)[0], 1.0, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(0)[1], 1.0, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(0)[2], 1.0, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(0)[3], 1.0, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(0)[4], 1.0, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(0)[5], 1.0, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(0)[6], 1.0, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(0)[7], 1.0, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(0)[8], 1.0, 1e-15);
+
+    TS_ASSERT_DELTA(outWS->readY(1)[0], 0.0, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(1)[1], 0.5, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(1)[2], 1.0, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(1)[3], 1.5, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(1)[4], 2.0, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(1)[5], 2.5, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(1)[6], 3.0, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(1)[7], 3.5, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(1)[8], 4.0, 1e-15);
+
+    TS_ASSERT_DELTA(outWS->readY(2)[0], 0.0, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(2)[1], 0.25, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(2)[2], 1.0, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(2)[3], 2.25, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(2)[4], 4.0, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(2)[5], 6.25, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(2)[6], 9.0, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(2)[7], 12.25, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(2)[8], 16.0, 1e-15);
+
+    TS_ASSERT_DELTA(outWS->readY(3)[0], 0.0, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(3)[1], 0.125, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(3)[2], 1.0, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(3)[3], 3.375, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(3)[4], 8.0, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(3)[5], 15.625, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(3)[6], 27.0, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(3)[7], 42.875, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(3)[8], 64.0, 1e-15);
+  }
+
+  void test_histo_wildes() {
+    auto inWS = createHistoWS();
+
+    CreatePolarizationEfficiencies alg;
+    alg.setChild(true);
+    alg.setRethrows(true);
+    alg.initialize();
+    alg.setProperty("InputWorkspace", inWS);
+    alg.setPropertyValue("OutputWorkspace", "dummy");
+    alg.setPropertyValue("P1", "1,0,0,0");
+    alg.setPropertyValue("P2", "0,1,0,0");
+    alg.setPropertyValue("F1", "0,0,1,0");
+    alg.setPropertyValue("F2", "0,0,0,1");
+    alg.execute();
+    MatrixWorkspace_sptr outWS = alg.getProperty("OutputWorkspace");
+
+    TS_ASSERT(outWS);
+    TS_ASSERT_EQUALS(outWS->getNumberHistograms(), 4);
+    TS_ASSERT_EQUALS(outWS->getAxis(0)->unit()->caption(), "Wavelength");
+
+    auto axis1 = outWS->getAxis(1);
+    TS_ASSERT_EQUALS(axis1->label(0), "P1");
+    TS_ASSERT_EQUALS(axis1->label(1), "P2");
+    TS_ASSERT_EQUALS(axis1->label(2), "F1");
+    TS_ASSERT_EQUALS(axis1->label(3), "F2");
+
+    TS_ASSERT_DELTA(outWS->readY(0)[0], 1.0, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(0)[1], 1.0, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(0)[2], 1.0, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(0)[3], 1.0, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(0)[4], 1.0, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(0)[5], 1.0, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(0)[6], 1.0, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(0)[7], 1.0, 1e-15);
+
+    TS_ASSERT_DELTA(outWS->readY(1)[0], 0.25, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(1)[1], 0.75, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(1)[2], 1.25, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(1)[3], 1.75, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(1)[4], 2.25, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(1)[5], 2.75, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(1)[6], 3.25, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(1)[7], 3.75, 1e-15);
+
+    TS_ASSERT_DELTA(outWS->readY(2)[0], 0.0625, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(2)[1], 0.5625, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(2)[2], 1.5625, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(2)[3], 3.0625, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(2)[4], 5.0625, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(2)[5], 7.5625, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(2)[6], 10.5625, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(2)[7], 14.0625, 1e-15);
+
+    TS_ASSERT_DELTA(outWS->readY(3)[0], 0.015625, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(3)[1], 0.421875, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(3)[2], 1.953125, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(3)[3], 5.359375, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(3)[4], 11.390625, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(3)[5], 20.796875, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(3)[6], 34.328125, 1e-15);
+    TS_ASSERT_DELTA(outWS->readY(3)[7], 52.734375, 1e-15);
+  }
+
+private:
+  Workspace2D_sptr createHistoWS() {
+    size_t const size = 8;
+    BinEdges xVals(size + 1, LinearGenerator(0, 0.5));
+    Counts yVals(size, 0);
+    auto retVal = boost::make_shared<Workspace2D>();
+    retVal->initialize(1, Histogram(xVals, yVals));
+    retVal->getAxis(0)->setUnit("Wavelength");
+    return retVal;
+  }
+
+  Workspace2D_sptr createPointWS() {
+    size_t const size = 9;
+    Points xVals(size, LinearGenerator(0, 0.5));
+    Counts yVals(size, 0);
+    auto retVal = boost::make_shared<Workspace2D>();
+    retVal->initialize(1, Histogram(xVals, yVals));
+    retVal->getAxis(0)->setUnit("Wavelength");
+    return retVal;
+  }
+};
+
+#endif /* MANTID_ALGORITHMS_CREATEPOLARIZATIONEFFICIENCIES_TEST_H_ */
diff --git a/Framework/DataHandling/test/JoinISISPolarizationEfficienciesTest.h b/Framework/DataHandling/test/JoinISISPolarizationEfficienciesTest.h
new file mode 100644
index 0000000000000000000000000000000000000000..02d3e7711970f541261a48902e9cc4f0bc80172f
--- /dev/null
+++ b/Framework/DataHandling/test/JoinISISPolarizationEfficienciesTest.h
@@ -0,0 +1,596 @@
+#ifndef MANTID_DATAHANDLING_JOINISISPOLARIZATIONEFFICIENCIESTEST_H_
+#define MANTID_DATAHANDLING_JOINISISPOLARIZATIONEFFICIENCIESTEST_H_
+
+#include <cxxtest/TestSuite.h>
+
+#include "MantidDataHandling/JoinISISPolarizationEfficiencies.h"
+
+#include "MantidAPI/Axis.h"
+#include "MantidAPI/MatrixWorkspace.h"
+#include "MantidDataObjects/Workspace2D.h"
+#include "MantidDataObjects/WorkspaceCreation.h"
+#include "MantidHistogramData/BinEdges.h"
+#include "MantidHistogramData/Counts.h"
+#include "MantidHistogramData/LinearGenerator.h"
+#include "MantidKernel/Unit.h"
+
+#include <array>
+#include <numeric>
+
+using Mantid::DataHandling::JoinISISPolarizationEfficiencies;
+using namespace Mantid::API;
+using namespace Mantid::DataObjects;
+using namespace Mantid::HistogramData;
+
+class JoinISISPolarizationEfficienciesTest : 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 JoinISISPolarizationEfficienciesTest *createSuite() {
+    return new JoinISISPolarizationEfficienciesTest();
+  }
+  static void destroySuite(JoinISISPolarizationEfficienciesTest *suite) {
+    delete suite;
+  }
+
+  void test_initialization() {
+    JoinISISPolarizationEfficiencies alg;
+    alg.setRethrows(true);
+    TS_ASSERT_THROWS_NOTHING(alg.initialize())
+    TS_ASSERT(alg.isInitialized())
+  }
+
+  void test_no_input() {
+    JoinISISPolarizationEfficiencies alg;
+    alg.initialize();
+    alg.setChild(true);
+    alg.setRethrows(true);
+    alg.setPropertyValue("OutputWorkspace", "dummy");
+    // Error: At least one of the efficiency file names must be set.
+    TS_ASSERT_THROWS(alg.execute(), std::invalid_argument);
+  }
+
+  void test_mixed_input() {
+    auto ws1 = createHistoWS(10, 0, 10);
+    auto ws2 = createHistoWS(10, 0, 10);
+    auto ws3 = createHistoWS(10, 0, 10);
+    auto ws4 = createHistoWS(10, 0, 10);
+
+    JoinISISPolarizationEfficiencies alg;
+    alg.initialize();
+    alg.setChild(true);
+    alg.setRethrows(true);
+    alg.setProperty("Pp", ws1);
+    alg.setProperty("Ap", ws2);
+    alg.setProperty("P1", ws3);
+    alg.setProperty("P2", ws4);
+    alg.setPropertyValue("OutputWorkspace", "dummy");
+    // Error: Efficiencies belonging to different methods cannot mix.
+    TS_ASSERT_THROWS(alg.execute(), std::invalid_argument);
+  }
+
+  void test_fredrikze() {
+    auto ws1 = createHistoWS(10, 0, 10);
+    auto ws2 = createHistoWS(10, 0, 10);
+    auto ws3 = createHistoWS(10, 0, 10);
+    auto ws4 = createHistoWS(10, 0, 10);
+
+    JoinISISPolarizationEfficiencies alg;
+    alg.initialize();
+    alg.setChild(true);
+    alg.setRethrows(true);
+    alg.setProperty("Pp", ws1);
+    alg.setProperty("Ap", ws2);
+    alg.setProperty("Rho", ws3);
+    alg.setProperty("Alpha", ws4);
+    alg.setPropertyValue("OutputWorkspace", "dummy");
+    alg.execute();
+    MatrixWorkspace_sptr outWS = alg.getProperty("OutputWorkspace");
+    TS_ASSERT(outWS);
+    TS_ASSERT_EQUALS(outWS->getNumberHistograms(), 4);
+    TS_ASSERT_EQUALS(outWS->blocksize(), 10);
+    TS_ASSERT_EQUALS(outWS->getAxis(0)->unit()->caption(), "Wavelength");
+
+    auto axis1 = outWS->getAxis(1);
+    TS_ASSERT_EQUALS(axis1->label(0), "Pp");
+    TS_ASSERT_EQUALS(axis1->label(1), "Ap");
+    TS_ASSERT_EQUALS(axis1->label(2), "Rho");
+    TS_ASSERT_EQUALS(axis1->label(3), "Alpha");
+
+    TS_ASSERT(outWS->isHistogramData());
+
+    {
+      auto const &x = outWS->x(0);
+      auto const &y = outWS->y(0);
+      TS_ASSERT_EQUALS(x.size(), 11);
+      TS_ASSERT_EQUALS(y.size(), 10);
+      TS_ASSERT_EQUALS(x.front(), 0);
+      TS_ASSERT_EQUALS(x.back(), 10);
+      TS_ASSERT_EQUALS(y.front(), 1);
+      TS_ASSERT_EQUALS(y.back(), 1);
+    }
+
+    {
+      auto const &x = outWS->x(1);
+      auto const &y = outWS->y(1);
+      TS_ASSERT_EQUALS(x.size(), 11);
+      TS_ASSERT_EQUALS(y.size(), 10);
+      TS_ASSERT_EQUALS(x.front(), 0);
+      TS_ASSERT_EQUALS(x.back(), 10);
+      TS_ASSERT_EQUALS(y.front(), 1);
+      TS_ASSERT_EQUALS(y.back(), 1);
+    }
+
+    {
+      auto const &x = outWS->x(2);
+      auto const &y = outWS->y(2);
+      TS_ASSERT_EQUALS(x.size(), 11);
+      TS_ASSERT_EQUALS(y.size(), 10);
+      TS_ASSERT_EQUALS(x.front(), 0);
+      TS_ASSERT_EQUALS(x.back(), 10);
+      TS_ASSERT_EQUALS(y.front(), 1);
+      TS_ASSERT_EQUALS(y.back(), 1);
+    }
+
+    {
+      auto const &x = outWS->x(3);
+      auto const &y = outWS->y(3);
+      TS_ASSERT_EQUALS(x.size(), 11);
+      TS_ASSERT_EQUALS(y.size(), 10);
+      TS_ASSERT_EQUALS(x.front(), 0);
+      TS_ASSERT_EQUALS(x.back(), 10);
+      TS_ASSERT_EQUALS(y.front(), 1);
+      TS_ASSERT_EQUALS(y.back(), 1);
+    }
+  }
+
+  void test_wildes() {
+    auto ws1 = createHistoWS(10, 0, 10);
+    auto ws2 = createHistoWS(10, 0, 10);
+    auto ws3 = createHistoWS(10, 0, 10);
+    auto ws4 = createHistoWS(10, 0, 10);
+
+    JoinISISPolarizationEfficiencies alg;
+    alg.initialize();
+    alg.setChild(true);
+    alg.setRethrows(true);
+    alg.setProperty("P1", ws1);
+    alg.setProperty("P2", ws2);
+    alg.setProperty("F1", ws3);
+    alg.setProperty("F2", ws4);
+    alg.setPropertyValue("OutputWorkspace", "dummy");
+    alg.execute();
+    MatrixWorkspace_sptr outWS = alg.getProperty("OutputWorkspace");
+    TS_ASSERT(outWS);
+    TS_ASSERT_EQUALS(outWS->getNumberHistograms(), 4);
+    TS_ASSERT_EQUALS(outWS->blocksize(), 10);
+    TS_ASSERT_EQUALS(outWS->getAxis(0)->unit()->caption(), "Wavelength");
+
+    auto axis1 = outWS->getAxis(1);
+    TS_ASSERT_EQUALS(axis1->label(0), "P1");
+    TS_ASSERT_EQUALS(axis1->label(1), "P2");
+    TS_ASSERT_EQUALS(axis1->label(2), "F1");
+    TS_ASSERT_EQUALS(axis1->label(3), "F2");
+
+    TS_ASSERT(outWS->isHistogramData());
+  }
+
+  void test_wildes_points() {
+    auto ws1 = createPointWS(10, 0, 10);
+    auto ws2 = createPointWS(10, 0, 10);
+    auto ws3 = createPointWS(10, 0, 10);
+    auto ws4 = createPointWS(10, 0, 10);
+
+    JoinISISPolarizationEfficiencies alg;
+    alg.initialize();
+    alg.setChild(true);
+    alg.setRethrows(true);
+    alg.setProperty("P1", ws1);
+    alg.setProperty("P2", ws2);
+    alg.setProperty("F1", ws3);
+    alg.setProperty("F2", ws4);
+    alg.setPropertyValue("OutputWorkspace", "dummy");
+    alg.execute();
+    MatrixWorkspace_sptr outWS = alg.getProperty("OutputWorkspace");
+    TS_ASSERT(outWS);
+    TS_ASSERT_EQUALS(outWS->getNumberHistograms(), 4);
+    TS_ASSERT_EQUALS(outWS->blocksize(), 10);
+    TS_ASSERT_EQUALS(outWS->getAxis(0)->unit()->caption(), "Wavelength");
+
+    auto axis1 = outWS->getAxis(1);
+    TS_ASSERT_EQUALS(axis1->label(0), "P1");
+    TS_ASSERT_EQUALS(axis1->label(1), "P2");
+    TS_ASSERT_EQUALS(axis1->label(2), "F1");
+    TS_ASSERT_EQUALS(axis1->label(3), "F2");
+
+    TS_ASSERT(!outWS->isHistogramData());
+
+    {
+      auto const &x = outWS->x(0);
+      auto const &y = outWS->y(0);
+      TS_ASSERT_EQUALS(x.size(), 10);
+      TS_ASSERT_EQUALS(y.size(), 10);
+      TS_ASSERT_EQUALS(x.front(), 0);
+      TS_ASSERT_EQUALS(x.back(), 10);
+      TS_ASSERT_EQUALS(y.front(), 1);
+      TS_ASSERT_EQUALS(y.back(), 1);
+      auto sum = std::accumulate(y.begin(), y.end(), 0.0);
+      TS_ASSERT_DELTA(sum, 10.0, 1e-14);
+    }
+
+    {
+      auto const &x = outWS->x(1);
+      auto const &y = outWS->y(1);
+      TS_ASSERT_EQUALS(x.size(), 10);
+      TS_ASSERT_EQUALS(y.size(), 10);
+      TS_ASSERT_EQUALS(x.front(), 0);
+      TS_ASSERT_EQUALS(x.back(), 10);
+      TS_ASSERT_EQUALS(y.front(), 1);
+      TS_ASSERT_EQUALS(y.back(), 1);
+      auto sum = std::accumulate(y.begin(), y.end(), 0.0);
+      TS_ASSERT_DELTA(sum, 10.0, 1e-14);
+    }
+
+    {
+      auto const &x = outWS->x(2);
+      auto const &y = outWS->y(2);
+      TS_ASSERT_EQUALS(x.size(), 10);
+      TS_ASSERT_EQUALS(y.size(), 10);
+      TS_ASSERT_EQUALS(x.front(), 0);
+      TS_ASSERT_EQUALS(x.back(), 10);
+      TS_ASSERT_EQUALS(y.front(), 1);
+      TS_ASSERT_EQUALS(y.back(), 1);
+      auto sum = std::accumulate(y.begin(), y.end(), 0.0);
+      TS_ASSERT_DELTA(sum, 10.0, 1e-14);
+    }
+
+    {
+      auto const &x = outWS->x(3);
+      auto const &y = outWS->y(3);
+      TS_ASSERT_EQUALS(x.size(), 10);
+      TS_ASSERT_EQUALS(y.size(), 10);
+      TS_ASSERT_EQUALS(x.front(), 0);
+      TS_ASSERT_EQUALS(x.back(), 10);
+      TS_ASSERT_EQUALS(y.front(), 1);
+      TS_ASSERT_EQUALS(y.back(), 1);
+      auto sum = std::accumulate(y.begin(), y.end(), 0.0);
+      TS_ASSERT_DELTA(sum, 10.0, 1e-14);
+    }
+  }
+
+  void test_histo_3_out_of_4() {
+    auto ws1 = createHistoWS(10, 0, 10);
+    auto ws2 = createHistoWS(10, 0, 10);
+    auto ws3 = createHistoWS(10, 0, 10);
+
+    JoinISISPolarizationEfficiencies alg;
+    alg.initialize();
+    alg.setChild(true);
+    alg.setRethrows(true);
+    alg.setProperty("P1", ws1);
+    alg.setProperty("P2", ws2);
+    alg.setProperty("F1", ws3);
+    alg.setPropertyValue("OutputWorkspace", "dummy");
+    alg.execute();
+    MatrixWorkspace_sptr outWS = alg.getProperty("OutputWorkspace");
+    TS_ASSERT(outWS);
+    TS_ASSERT_EQUALS(outWS->getNumberHistograms(), 3);
+    TS_ASSERT_EQUALS(outWS->blocksize(), 10);
+    TS_ASSERT_EQUALS(outWS->getAxis(0)->unit()->caption(), "Wavelength");
+
+    auto axis1 = outWS->getAxis(1);
+    TS_ASSERT_EQUALS(axis1->label(0), "P1");
+    TS_ASSERT_EQUALS(axis1->label(1), "P2");
+    TS_ASSERT_EQUALS(axis1->label(2), "F1");
+  }
+
+  void test_histo_2_out_of_4() {
+    auto ws1 = createHistoWS(10, 0, 10);
+    auto ws2 = createHistoWS(10, 0, 10);
+
+    JoinISISPolarizationEfficiencies alg;
+    alg.initialize();
+    alg.setChild(true);
+    alg.setRethrows(true);
+    alg.setProperty("P1", ws1);
+    alg.setProperty("F1", ws2);
+    alg.setPropertyValue("OutputWorkspace", "dummy");
+    alg.execute();
+    MatrixWorkspace_sptr outWS = alg.getProperty("OutputWorkspace");
+    TS_ASSERT(outWS);
+    TS_ASSERT_EQUALS(outWS->getNumberHistograms(), 2);
+    TS_ASSERT_EQUALS(outWS->blocksize(), 10);
+    TS_ASSERT_EQUALS(outWS->getAxis(0)->unit()->caption(), "Wavelength");
+
+    auto axis1 = outWS->getAxis(1);
+    TS_ASSERT_EQUALS(axis1->label(0), "P1");
+    TS_ASSERT_EQUALS(axis1->label(1), "F1");
+  }
+
+  void test_histo_1_out_of_4() {
+    auto ws1 = createHistoWS(10, 0, 10);
+
+    JoinISISPolarizationEfficiencies alg;
+    alg.initialize();
+    alg.setChild(true);
+    alg.setRethrows(true);
+    alg.setProperty("F2", ws1);
+    alg.setPropertyValue("OutputWorkspace", "dummy");
+    alg.execute();
+    MatrixWorkspace_sptr outWS = alg.getProperty("OutputWorkspace");
+    TS_ASSERT(outWS);
+    TS_ASSERT_EQUALS(outWS->getNumberHistograms(), 1);
+    TS_ASSERT_EQUALS(outWS->blocksize(), 10);
+    TS_ASSERT_EQUALS(outWS->getAxis(0)->unit()->caption(), "Wavelength");
+
+    auto axis1 = outWS->getAxis(1);
+    TS_ASSERT_EQUALS(axis1->label(0), "F2");
+  }
+
+  void test_mixed_histo_points() {
+    auto ws1 = createHistoWS(10, 0, 10);
+    auto ws2 = createPointWS(10, 0, 10);
+    auto ws3 = createHistoWS(10, 0, 10);
+    auto ws4 = createHistoWS(10, 0, 10);
+
+    JoinISISPolarizationEfficiencies alg;
+    alg.initialize();
+    alg.setChild(true);
+    alg.setRethrows(true);
+    alg.setProperty("P1", ws1);
+    alg.setProperty("P2", ws2);
+    alg.setProperty("F1", ws3);
+    alg.setProperty("F2", ws4);
+    alg.setPropertyValue("OutputWorkspace", "dummy");
+    // Error: Cannot mix histograms and point data.
+    TS_ASSERT_THROWS(alg.execute(), std::invalid_argument);
+  }
+
+  void test_ragged() {
+    auto ws1 = createHistoWS(10, 0, 10);
+    auto ws2 = createHistoWS(10, 1, 10);
+    auto ws3 = createHistoWS(10, 2, 3);
+    auto ws4 = createHistoWS(10, 11, 20);
+
+    JoinISISPolarizationEfficiencies alg;
+    alg.initialize();
+    alg.setChild(true);
+    alg.setRethrows(true);
+    alg.setProperty("Pp", ws1);
+    alg.setProperty("Ap", ws2);
+    alg.setProperty("Rho", ws3);
+    alg.setProperty("Alpha", ws4);
+    alg.setPropertyValue("OutputWorkspace", "dummy");
+    alg.execute();
+    MatrixWorkspace_sptr outWS = alg.getProperty("OutputWorkspace");
+    TS_ASSERT(outWS);
+    TS_ASSERT_EQUALS(outWS->getNumberHistograms(), 4);
+    TS_ASSERT_EQUALS(outWS->blocksize(), 10);
+    TS_ASSERT_EQUALS(outWS->getAxis(0)->unit()->caption(), "Wavelength");
+
+    auto axis1 = outWS->getAxis(1);
+    TS_ASSERT_EQUALS(axis1->label(0), "Pp");
+    TS_ASSERT_EQUALS(axis1->label(1), "Ap");
+    TS_ASSERT_EQUALS(axis1->label(2), "Rho");
+    TS_ASSERT_EQUALS(axis1->label(3), "Alpha");
+
+    TS_ASSERT(outWS->isHistogramData());
+
+    {
+      auto const &x = outWS->x(0);
+      auto const &y = outWS->y(0);
+      TS_ASSERT_EQUALS(x.size(), 11);
+      TS_ASSERT_EQUALS(y.size(), 10);
+      TS_ASSERT_EQUALS(x.front(), 0);
+      TS_ASSERT_EQUALS(x.back(), 10);
+      TS_ASSERT_EQUALS(y.front(), 1);
+      TS_ASSERT_EQUALS(y.back(), 1);
+    }
+
+    {
+      auto const &x = outWS->x(1);
+      auto const &y = outWS->y(1);
+      TS_ASSERT_EQUALS(x.size(), 11);
+      TS_ASSERT_EQUALS(y.size(), 10);
+      TS_ASSERT_EQUALS(x.front(), 1);
+      TS_ASSERT_EQUALS(x.back(), 10);
+      TS_ASSERT_EQUALS(y.front(), 1);
+      TS_ASSERT_EQUALS(y.back(), 1);
+    }
+
+    {
+      auto const &x = outWS->x(2);
+      auto const &y = outWS->y(2);
+      TS_ASSERT_EQUALS(x.size(), 11);
+      TS_ASSERT_EQUALS(y.size(), 10);
+      TS_ASSERT_EQUALS(x.front(), 2);
+      TS_ASSERT_EQUALS(x.back(), 3);
+      TS_ASSERT_EQUALS(y.front(), 1);
+      TS_ASSERT_EQUALS(y.back(), 1);
+    }
+
+    {
+      auto const &x = outWS->x(3);
+      auto const &y = outWS->y(3);
+      TS_ASSERT_EQUALS(x.size(), 11);
+      TS_ASSERT_EQUALS(y.size(), 10);
+      TS_ASSERT_EQUALS(x.front(), 11);
+      TS_ASSERT_EQUALS(x.back(), 20);
+      TS_ASSERT_EQUALS(y.front(), 1);
+      TS_ASSERT_EQUALS(y.back(), 1);
+    }
+  }
+
+  void test_histo_ragged_diff_sizes() {
+    auto ws1 = createHistoWS(10, 0, 10);
+    auto ws2 = createHistoWS(9, 1, 10);
+    auto ws3 = createHistoWS(11, 2, 3);
+    auto ws4 = createHistoWS(10, 11, 20);
+
+    JoinISISPolarizationEfficiencies alg;
+    alg.initialize();
+    alg.setChild(true);
+    alg.setRethrows(true);
+    alg.setProperty("Pp", ws1);
+    alg.setProperty("Ap", ws2);
+    alg.setProperty("Rho", ws3);
+    alg.setProperty("Alpha", ws4);
+    alg.setPropertyValue("OutputWorkspace", "dummy");
+    alg.execute();
+    MatrixWorkspace_sptr outWS = alg.getProperty("OutputWorkspace");
+    TS_ASSERT(outWS);
+    TS_ASSERT_EQUALS(outWS->getNumberHistograms(), 4);
+    TS_ASSERT_EQUALS(outWS->blocksize(), 11);
+    TS_ASSERT_EQUALS(outWS->getAxis(0)->unit()->caption(), "Wavelength");
+
+    auto axis1 = outWS->getAxis(1);
+    TS_ASSERT_EQUALS(axis1->label(0), "Pp");
+    TS_ASSERT_EQUALS(axis1->label(1), "Ap");
+    TS_ASSERT_EQUALS(axis1->label(2), "Rho");
+    TS_ASSERT_EQUALS(axis1->label(3), "Alpha");
+
+    TS_ASSERT(outWS->isHistogramData());
+
+    {
+      auto const &x = outWS->x(0);
+      auto const &y = outWS->y(0);
+      TS_ASSERT_EQUALS(x.size(), 12);
+      TS_ASSERT_EQUALS(y.size(), 11);
+      TS_ASSERT_DELTA(x.front(), 0., 1e-15);
+      TS_ASSERT_DELTA(x.back(), 10, 1e-15);
+      TS_ASSERT_DELTA(y.front(), 1., 1e-15);
+      TS_ASSERT_DELTA(y.back(), 1., 1e-15);
+    }
+
+    {
+      auto const &x = outWS->x(1);
+      auto const &y = outWS->y(1);
+      TS_ASSERT_EQUALS(x.size(), 12);
+      TS_ASSERT_EQUALS(y.size(), 11);
+      TS_ASSERT_DELTA(x.front(), 1., 1e-15);
+      TS_ASSERT_DELTA(x.back(), 10, 1e-15);
+      TS_ASSERT_DELTA(y.front(), 1., 1e-15);
+      TS_ASSERT_DELTA(y.back(), 1., 1e-15);
+    }
+
+    {
+      auto const &x = outWS->x(2);
+      auto const &y = outWS->y(2);
+      TS_ASSERT_EQUALS(x.size(), 12);
+      TS_ASSERT_EQUALS(y.size(), 11);
+      TS_ASSERT_DELTA(x.front(), 2.0, 1e-9);
+      TS_ASSERT_DELTA(x.back(), 3.0, 1e-9);
+      TS_ASSERT_EQUALS(y.front(), 1);
+      TS_ASSERT_EQUALS(y.back(), 1);
+    }
+
+    {
+      auto const &x = outWS->x(3);
+      auto const &y = outWS->y(3);
+      TS_ASSERT_EQUALS(x.size(), 12);
+      TS_ASSERT_EQUALS(y.size(), 11);
+      TS_ASSERT_DELTA(x.front(), 11.0, 1e-15);
+      TS_ASSERT_DELTA(x.back(), 20.0, 1e-15);
+      TS_ASSERT_DELTA(y.front(), 1., 1e-15);
+      TS_ASSERT_DELTA(y.back(), 1., 1e-15);
+    }
+  }
+
+  void test_points_ragged_diff_sizes() {
+    auto ws1 = createPointWS(10, 0, 10);
+    auto ws2 = createPointWS(9, 1, 10);
+    auto ws3 = createPointWS(11, 2, 3);
+    auto ws4 = createPointWS(10, 11, 20);
+
+    JoinISISPolarizationEfficiencies alg;
+    alg.initialize();
+    alg.setChild(true);
+    alg.setRethrows(true);
+    alg.setProperty("Pp", ws1);
+    alg.setProperty("Ap", ws2);
+    alg.setProperty("Rho", ws3);
+    alg.setProperty("Alpha", ws4);
+    alg.setPropertyValue("OutputWorkspace", "dummy");
+    alg.execute();
+    MatrixWorkspace_sptr outWS = alg.getProperty("OutputWorkspace");
+    TS_ASSERT(outWS);
+    TS_ASSERT_EQUALS(outWS->getNumberHistograms(), 4);
+    TS_ASSERT_EQUALS(outWS->blocksize(), 11);
+    TS_ASSERT_EQUALS(outWS->getAxis(0)->unit()->caption(), "Wavelength");
+
+    auto axis1 = outWS->getAxis(1);
+    TS_ASSERT_EQUALS(axis1->label(0), "Pp");
+    TS_ASSERT_EQUALS(axis1->label(1), "Ap");
+    TS_ASSERT_EQUALS(axis1->label(2), "Rho");
+    TS_ASSERT_EQUALS(axis1->label(3), "Alpha");
+
+    TS_ASSERT(!outWS->isHistogramData());
+
+    {
+      auto const &x = outWS->x(0);
+      auto const &y = outWS->y(0);
+      TS_ASSERT_EQUALS(x.size(), 11);
+      TS_ASSERT_EQUALS(y.size(), 11);
+      TS_ASSERT_DELTA(x.front(), 0, 1e-5);
+      TS_ASSERT_DELTA(x.back(), 10.0, 1e-15);
+      TS_ASSERT_DELTA(y.front(), 1.0, 1e-15);
+      TS_ASSERT_DELTA(y.back(), 1.0, 1e-15);
+    }
+
+    {
+      auto const &x = outWS->x(1);
+      auto const &y = outWS->y(1);
+      TS_ASSERT_EQUALS(x.size(), 11);
+      TS_ASSERT_EQUALS(y.size(), 11);
+      TS_ASSERT_DELTA(x.front(), 1.0, 1e-15);
+      TS_ASSERT_DELTA(x.back(), 10.0, 1e-15);
+      TS_ASSERT_DELTA(y.front(), 1.0, 1e-15);
+      TS_ASSERT_DELTA(y.back(), 1.0, 1e-15);
+    }
+
+    {
+      auto const &x = outWS->x(2);
+      auto const &y = outWS->y(2);
+      TS_ASSERT_EQUALS(x.size(), 11);
+      TS_ASSERT_EQUALS(y.size(), 11);
+      TS_ASSERT_EQUALS(x.front(), 2);
+      TS_ASSERT_EQUALS(x.back(), 3);
+      TS_ASSERT_EQUALS(y.front(), 1);
+      TS_ASSERT_EQUALS(y.back(), 1);
+    }
+
+    {
+      auto const &x = outWS->x(3);
+      auto const &y = outWS->y(3);
+      TS_ASSERT_EQUALS(x.size(), 11);
+      TS_ASSERT_EQUALS(y.size(), 11);
+      TS_ASSERT_DELTA(x.front(), 11.0, 1e-15);
+      TS_ASSERT_DELTA(x.back(), 20.0, 1e-15);
+      TS_ASSERT_DELTA(y.front(), 1.0, 1e-15);
+      TS_ASSERT_DELTA(y.back(), 1.0, 1e-15);
+    }
+  }
+
+private:
+  MatrixWorkspace_sptr createHistoWS(size_t size, double startX,
+                                     double endX) const {
+    double const dX = (endX - startX) / double(size);
+    BinEdges xVals(size + 1, LinearGenerator(startX, dX));
+    Counts yVals(size, 1.0);
+    auto retVal = boost::make_shared<Workspace2D>();
+    retVal->initialize(1, Histogram(xVals, yVals));
+    return retVal;
+  }
+
+  MatrixWorkspace_sptr createPointWS(size_t size, double startX,
+                                     double endX) const {
+    double const dX = (endX - startX) / double(size - 1);
+    Points xVals(size, LinearGenerator(startX, dX));
+    Counts yVals(size, 1.0);
+    auto retVal = boost::make_shared<Workspace2D>();
+    retVal->initialize(1, Histogram(xVals, yVals));
+    return retVal;
+  }
+};
+
+#endif /* MANTID_DATAHANDLING_JOINISISPOLARIZATIONEFFICIENCIESTEST_H_ */
diff --git a/Framework/DataHandling/test/LoadISISPolarizationEfficienciesTest.h b/Framework/DataHandling/test/LoadISISPolarizationEfficienciesTest.h
new file mode 100644
index 0000000000000000000000000000000000000000..ba3a4e47860ac9411c1e7a041f7b40a093401853
--- /dev/null
+++ b/Framework/DataHandling/test/LoadISISPolarizationEfficienciesTest.h
@@ -0,0 +1,163 @@
+#ifndef MANTID_DATAHANDLING_LOADISISPOLARIZATIONEFFICIENCIESTEST_H_
+#define MANTID_DATAHANDLING_LOADISISPOLARIZATIONEFFICIENCIESTEST_H_
+
+#include <cxxtest/TestSuite.h>
+
+#include "MantidDataHandling/LoadISISPolarizationEfficiencies.h"
+
+#include "MantidAPI/Axis.h"
+#include "MantidAPI/MatrixWorkspace.h"
+#include "MantidDataObjects/Workspace2D.h"
+#include "MantidDataObjects/WorkspaceCreation.h"
+#include "MantidHistogramData/BinEdges.h"
+#include "MantidHistogramData/Counts.h"
+#include "MantidHistogramData/LinearGenerator.h"
+#include "MantidKernel/Unit.h"
+#include "MantidTestHelpers/ScopedFileHelper.h"
+
+#include <array>
+#include <fstream>
+
+using Mantid::DataHandling::LoadISISPolarizationEfficiencies;
+using namespace Mantid::API;
+using namespace Mantid::DataObjects;
+using namespace Mantid::HistogramData;
+using ScopedFileHelper::ScopedFile;
+
+class LoadISISPolarizationEfficienciesTest : 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 LoadISISPolarizationEfficienciesTest *createSuite() {
+    return new LoadISISPolarizationEfficienciesTest();
+  }
+  static void destroySuite(LoadISISPolarizationEfficienciesTest *suite) {
+    delete suite;
+  }
+
+  void test_initialization() {
+    LoadISISPolarizationEfficiencies alg;
+    alg.setRethrows(true);
+    TS_ASSERT_THROWS_NOTHING(alg.initialize())
+    TS_ASSERT(alg.isInitialized())
+  }
+
+  void test_load() {
+    ScopedFile f1(m_data1, "Efficiency1.txt");
+
+    LoadISISPolarizationEfficiencies alg;
+    alg.setChild(true);
+    alg.setRethrows(true);
+    alg.initialize();
+    alg.setProperty("P1", f1.getFileName());
+    alg.setProperty("P2", f1.getFileName());
+    alg.setProperty("OutputWorkspace", "dummy");
+    alg.execute();
+    MatrixWorkspace_sptr outWS = alg.getProperty("OutputWorkspace");
+    TS_ASSERT(outWS);
+    TS_ASSERT_EQUALS(outWS->getNumberHistograms(), 2);
+    TS_ASSERT_EQUALS(outWS->blocksize(), 5);
+    TS_ASSERT_EQUALS(outWS->getAxis(0)->unit()->caption(), "Wavelength");
+
+    auto axis1 = outWS->getAxis(1);
+    TS_ASSERT_EQUALS(axis1->label(0), "P1");
+    TS_ASSERT_EQUALS(axis1->label(1), "P2");
+
+    TS_ASSERT(!outWS->isHistogramData());
+
+    {
+      auto const &x = outWS->x(0);
+      auto const &y = outWS->y(0);
+      TS_ASSERT_EQUALS(x.size(), 5);
+      TS_ASSERT_EQUALS(y.size(), 5);
+      TS_ASSERT_DELTA(x.front(), 1.1, 1e-15);
+      TS_ASSERT_DELTA(x.back(), 5.5, 1e-15);
+      TS_ASSERT_DELTA(y.front(), 1., 1e-15);
+      TS_ASSERT_DELTA(y.back(), 1., 1e-15);
+    }
+
+    {
+      auto const &x = outWS->x(1);
+      auto const &y = outWS->y(1);
+      TS_ASSERT_EQUALS(x.size(), 5);
+      TS_ASSERT_EQUALS(y.size(), 5);
+      TS_ASSERT_DELTA(x.front(), 1.1, 1e-15);
+      TS_ASSERT_DELTA(x.back(), 5.5, 1e-15);
+      TS_ASSERT_DELTA(y.front(), 1., 1e-15);
+      TS_ASSERT_DELTA(y.back(), 1., 1e-15);
+    }
+  }
+
+  void test_load_diff_sizes() {
+    ScopedFile f1(m_data1, "Efficiency2.txt");
+
+    LoadISISPolarizationEfficiencies alg;
+    alg.setChild(true);
+    alg.setRethrows(true);
+    alg.initialize();
+    alg.setProperty("P1", f1.getFileName());
+    alg.setProperty("P2", f1.getFileName());
+    alg.setProperty("OutputWorkspace", "dummy");
+    alg.execute();
+    MatrixWorkspace_sptr outWS = alg.getProperty("OutputWorkspace");
+    TS_ASSERT(outWS);
+    TS_ASSERT_EQUALS(outWS->getNumberHistograms(), 2);
+    TS_ASSERT_EQUALS(outWS->blocksize(), 5);
+    TS_ASSERT_EQUALS(outWS->getAxis(0)->unit()->caption(), "Wavelength");
+
+    auto axis1 = outWS->getAxis(1);
+    TS_ASSERT_EQUALS(axis1->label(0), "P1");
+    TS_ASSERT_EQUALS(axis1->label(1), "P2");
+
+    TS_ASSERT(!outWS->isHistogramData());
+
+    {
+      auto const &x = outWS->x(0);
+      auto const &y = outWS->y(0);
+      TS_ASSERT_EQUALS(x.size(), 5);
+      TS_ASSERT_EQUALS(y.size(), 5);
+      TS_ASSERT_DELTA(x.front(), 1.1, 1e-15);
+      TS_ASSERT_DELTA(x.back(), 5.5, 1e-15);
+      TS_ASSERT_DELTA(y.front(), 1., 1e-15);
+      TS_ASSERT_DELTA(y.back(), 1., 1e-15);
+    }
+
+    {
+      auto const &x = outWS->x(1);
+      auto const &y = outWS->y(1);
+      TS_ASSERT_EQUALS(x.size(), 5);
+      TS_ASSERT_EQUALS(y.size(), 5);
+      TS_ASSERT_DELTA(x.front(), 1.1, 1e-15);
+      // TS_ASSERT_DELTA(x.back(), 4.5, 1e-15);
+      TS_ASSERT_DELTA(y.front(), 1., 1e-15);
+      TS_ASSERT_DELTA(y.back(), 1., 1e-15);
+    }
+  }
+
+  void test_diff_methods() {
+    ScopedFile f1(m_data1, "Efficiency3.txt");
+
+    LoadISISPolarizationEfficiencies alg;
+    alg.setChild(true);
+    alg.setRethrows(true);
+    alg.initialize();
+    alg.setProperty("P1", f1.getFileName());
+    alg.setProperty("Pp", f1.getFileName());
+    alg.setProperty("OutputWorkspace", "dummy");
+    TS_ASSERT_THROWS(alg.execute(), std::invalid_argument);
+  }
+
+private:
+  std::string const m_data1{"\n1.10000,1.000000,0.322961\n"
+                            "2.20000,1.000000,0.0217908\n"
+                            "3.30000,1.000000,0.00993287\n"
+                            "4.50000,1.000000,0.00668106\n"
+                            "5.50000,1.000000,0.0053833\n"};
+
+  std::string const m_data2{"\n1.10000,1.000000,0.322961\n"
+                            "2.20000,1.000000,0.0217908\n"
+                            "3.30000,1.000000,0.00993287\n"
+                            "4.50000,1.000000,0.00668106\n"};
+};
+
+#endif /* MANTID_DATAHANDLING_LOADISISPOLARIZATIONEFFICIENCIESTEST_H_ */
diff --git a/Framework/HistogramData/src/Interpolate.cpp b/Framework/HistogramData/src/Interpolate.cpp
index 8a0daace69abb8619fe9753c8826f51358b61382..51c8735cdf3577fca9f88ee701045dfd00851246 100644
--- a/Framework/HistogramData/src/Interpolate.cpp
+++ b/Framework/HistogramData/src/Interpolate.cpp
@@ -250,7 +250,8 @@ void interpolateLinearInplace(Histogram &inOut, const size_t stepSize) {
  */
 void interpolateLinearInplace(const Histogram &input, Histogram &output) {
   sanityCheck(input, output, minSizeForLinearInterpolation());
-  const auto &points = input.points().rawData();
+  const auto inputPoints = input.points();
+  const auto &points = inputPoints.rawData();
   const auto &y = input.y().rawData();
   const auto &interpPoints = output.points();
   auto &newY = output.mutableY();
diff --git a/docs/source/algorithms/CreatePolarizationEfficiencies-v1.rst b/docs/source/algorithms/CreatePolarizationEfficiencies-v1.rst
new file mode 100644
index 0000000000000000000000000000000000000000..5a085962f61b5684bdeafeeadc53034cd5fed487
--- /dev/null
+++ b/docs/source/algorithms/CreatePolarizationEfficiencies-v1.rst
@@ -0,0 +1,43 @@
+
+.. algorithm::
+
+.. summary::
+
+.. relatedalgorithms::
+
+.. properties::
+
+Description
+-----------
+
+Creates a workspace in which the spectra contain the polarization efficiencies calculated from polynomial coefficients
+on the x-values of the input workspace.
+
+
+Usage
+-----
+
+**Example**
+
+.. testcode:: Example
+
+    ws = CreateWorkspace([0, 1, 2, 3, 4], [0, 0, 0, 0, 0])
+    eff = CreatePolarizationEfficiencies(ws, Pp=[0, 1, 2, 3], Ap=[1, 2, 3], Rho=[3, 2, 1], Alpha=[4, 3, 2, 1])
+    print(eff.getAxis(1).label(0))
+    print(eff.getAxis(1).label(1))
+    print(eff.getAxis(1).label(2))
+    print(eff.getAxis(1).label(3))
+
+
+Output:
+
+.. testoutput:: Example
+
+    Pp
+    Ap
+    Rho
+    Alpha
+
+.. categories::
+
+.. sourcelink::
diff --git a/docs/source/algorithms/JoinISISPolarizationEfficiencies-v1.rst b/docs/source/algorithms/JoinISISPolarizationEfficiencies-v1.rst
new file mode 100644
index 0000000000000000000000000000000000000000..478a4a2603eba2df3f97ff90240bc59f13ce90ed
--- /dev/null
+++ b/docs/source/algorithms/JoinISISPolarizationEfficiencies-v1.rst
@@ -0,0 +1,45 @@
+.. algorithm::
+
+.. summary::
+
+.. relatedalgorithms::
+
+.. properties::
+
+Description
+-----------
+
+The inputs to this algorithm are single-spectra workspaces containing polarization efficiencies. They are combined and interpolated if
+neccessary to form a valid matrix workspace. The spectra of the output workspace are labeled with the names of the corresponding
+input properties.
+
+
+Usage
+-----
+
+.. testcode:: Example
+    
+    # Create input workspaces which can have different sizes
+    ws1 = CreateWorkspace([1, 2, 3], [1, 1])
+    ws2 = CreateWorkspace([2, 3, 4, 5], [1, 1, 1])
+
+    # Combine them in a single workspace
+    efficiencies = JoinISISPolarizationEfficiencies(Pp=ws1, Ap=ws2)
+    print('Number of spectra = {}'.format(efficiencies.getNumberHistograms()))
+    print('Number of bins    = {}'.format(efficiencies.blocksize()))
+    print('Label of first  spectrum: {}'.format(efficiencies.getAxis(1).label(0)))
+    print('Label of second spectrum: {}'.format(efficiencies.getAxis(1).label(1)))
+
+Output:
+
+.. testoutput:: Example 
+
+    Number of spectra = 2
+    Number of bins    = 3
+    Label of first  spectrum: Pp
+    Label of second spectrum: Ap
+
+
+.. categories::
+
+.. sourcelink::
diff --git a/docs/source/algorithms/LoadISISPolarizationEfficiencies-v1.rst b/docs/source/algorithms/LoadISISPolarizationEfficiencies-v1.rst
new file mode 100644
index 0000000000000000000000000000000000000000..842706ed7fb49202bde5b734cf7a96050f61ccb6
--- /dev/null
+++ b/docs/source/algorithms/LoadISISPolarizationEfficiencies-v1.rst
@@ -0,0 +1,18 @@
+.. algorithm::
+
+.. summary::
+
+.. relatedalgorithms::
+
+.. properties::
+
+Description
+-----------
+
+This algorithm is similar to :ref:`algm-JoinISISPolarizationEfficiencies` only the input efficiencies are taken from files
+instead of workspaces.
+
+
+.. categories::
+
+.. sourcelink::
diff --git a/docs/source/algorithms/PolarizationCorrection-v1.rst b/docs/source/algorithms/PolarizationCorrectionFredrikze-v1.rst
similarity index 99%
rename from docs/source/algorithms/PolarizationCorrection-v1.rst
rename to docs/source/algorithms/PolarizationCorrectionFredrikze-v1.rst
index c42f2de3d7fec485a9e788ea88186a38b37e00d4..8ed2fae2876cf497903f56d09707bb6312fbcddf 100644
--- a/docs/source/algorithms/PolarizationCorrection-v1.rst
+++ b/docs/source/algorithms/PolarizationCorrectionFredrikze-v1.rst
@@ -9,6 +9,7 @@
 Description
 -----------
 
+
 Performs wavelength polarization correction on a TOF reflectometer spectrometer.
 
 Algorithm is based on the the paper Fredrikze, H, et al. "Calibration of a polarized neutron reflectometer" Physica B 297 (2001).
diff --git a/docs/source/algorithms/PolarizationCorrectionWildes-v1.rst b/docs/source/algorithms/PolarizationCorrectionWildes-v1.rst
new file mode 100644
index 0000000000000000000000000000000000000000..3d6d7b431fc16c0769dcbc521cba71838d6c752a
--- /dev/null
+++ b/docs/source/algorithms/PolarizationCorrectionWildes-v1.rst
@@ -0,0 +1,159 @@
+
+.. algorithm::
+
+.. summary::
+
+.. properties::
+
+Description
+-----------
+
+
+This algorithm corrects for non-ideal instrument component efficiencies in a polarization analysis experiment by following the procedure and conventions introduced by Wildes [#WILDES]_. In the full polarization analysis case it solves the corrected count rates :math:`\Sigma^{++}`, :math:`\Sigma^{+-}`, :math:`\Sigma^{-+}` and :math:`\Sigma^{--}` from the equation
+
+.. math::
+   \begin{bmatrix}
+   \Sigma^{++} \\
+   \Sigma^{+-} \\
+   \Sigma^{-+} \\
+   \Sigma^{--}
+   \end{bmatrix}
+   = \bm{M}
+   \begin{bmatrix}
+   I^{00} \\
+   I^{01} \\
+   I^{10} \\
+   I^{11}
+   \end{bmatrix},
+
+where :math:`I^{jk}` are the experimental count rates for flipper configuration :math:`jk` and :math:`\bm{M}` is the four-by-four correction matrix as defined by equations (4) in [#WILDES]_.
+
+Flipper configurations
+######################
+
+*InputWorkspaces* is a list containing one to four workspace names (X unit: wavelength) corresponding to the instrument configurations given as *Flippers*. Supported configurations are:
+
+:literal:`'00, 01, 10, 11'`
+   Full polarization corrections. Four input workspaces are required. They should be in the input group in the following order: both flippers off, analyzer flipper on, polarizer flipper on, both flippers on.
+
+:literal:`'00, 01, 11'` and :literal:`'00, 10, 11'`
+   Polarization corrections with the assumption that the corrected count rates :math:`\Sigma^{+-} = \Sigma^{-+}`. In this case the intensity of the missing flipper configuration (01 or 10) can be solved from the other intensities. Workspaces in the input group should be in the following order: both flippers off, one flipper on, both flippers on.
+
+:literal:`'00, 11'`
+   Polarization corrections with the assumption that the corrected count rates :math:`\Sigma^{+-} = \Sigma^{-+} = 0`. In this case the intensities of the missing flipper configurations (01 and 11) can be solved from the other intensities. Workspaces in the input group should be in the following order: both flippers off, both flippers on.
+
+:literal:`'0, 1'`
+   Polarization corrections when no analyzer has been used. Workspaces in the input group should be in the following order: polarizer flipper off, polarizer flipper on.
+
+:literal:`'0'`
+   Polarization corrections for a direct beam measurement in a reflectometry experiment.
+
+Output
+######
+
+The algorithm's output is a group workspace containing the corrected workspaces. The names of each corrected workspace is prefixed by :literal:`_++`, :literal:`_+-`, :literal:`_-+` or :literal:`_--` depending on which :math:`\Sigma^{mn}` they correspond to.
+
+Efficiency factors
+##################
+
+The *Efficiencies* input property expects to get a workspace with the following properties:
+
+* Contains four histograms, each labeled by their vertical axis as :literal:`P1`, :literal:`P2`, :literal:`F1`, :literal:`F2`. Other histograms (if present) are ignored.
+* The Y values of each histogram should be the corresponding efficiencies as functions of wavelength as defined in [#WILDES]_.
+* The wavelength values (X values) should be the same is in the input workspaces.
+
+.. note::
+   Users at ILL can load a conforming efficiency workspace from disk by :ref:`algm-LoadILLPolarizationFactors`.
+
+Error propagation
+#################
+
+.. note::
+   Errors are calculated as per Wildes [#WILDES]_, except for the numerically solved intensity in :literal:`'00, 01, 11'` and :literal:`'00, 10, 11'` flipper configurations in which case the uncertainties of :math:`\Sigma^{+-}` or :math:`\Sigma^{-+}` are set to zero.
+
+Usage
+-----
+
+.. include:: ../usagedata-note.txt
+
+**Example - PolarizationEfficiencyCor**
+
+.. testcode:: PolarizationEfficiencyCorExample
+
+   LoadILLReflectometry(
+       Filename='ILL/D17/317370.nxs',
+       OutputWorkspace='direct_beam',
+       OutputBeamPosition='direct_beam_position',
+       XUnit='TimeOfFlight')
+   LoadILLReflectometry(
+       Filename='ILL/D17/317370.nxs',
+       OutputWorkspace='reflected_beam',
+       DirectBeamPosition='direct_beam_position',
+       XUnit='TimeOfFlight')
+   # Sum pixels containing the reflected intensity
+   GroupDetectors(
+       InputWorkspace='reflected_beam',
+       OutputWorkspace='reflected_beam',
+       WorkspaceIndexList=[199, 200, 201, 202, 203, 204, 205])
+   ConvertUnits(
+       InputWorkspace='reflected_beam',
+       OutputWorkspace='reflected_beam',
+       Target='Wavelength',
+       EMode='Elastic')
+   # There are some unphysical wavelengths
+   CropWorkspace(
+       InputWorkspace='reflected_beam',
+       OutputWorkspace='reflected_beam',
+       XMin=0.)
+   # Fake two flipper configurations 
+   RenameWorkspace(
+       InputWorkspace='reflected_beam',
+       OutputWorkspace='up'
+   )
+   CloneWorkspace(
+       InputWorkspace='up',
+       OutputWorkspace='down'
+   )
+   Scale(
+       InputWorkspace='down',
+       OutputWorkspace='down',
+       Factor=0.1
+   )
+   LoadILLPolarizationFactors(
+       Filename='ILL/D17/PolarizationFactors.txt',
+       OutputWorkspace='efficiencies',
+       WavelengthReference='up')
+   PolarizationEfficiencyCor(
+       InputWorkspaces='up, down',
+       OutputWorkspace='corrected',
+       Efficiencies='efficiencies',
+       Flippers='00, 11')
+   
+   orig = mtd['up']
+   corr = mtd['corrected_++']
+   index = orig.binIndexOf(15.)
+   ratio_up = corr.readY(0)[index] / orig.readY(0)[index]
+   print("Ratio of corrected and original 'up' intensity at 15A: {:.4}".format(ratio_up))
+   orig = mtd['down']
+   corr = mtd['corrected_--']
+   index = orig.binIndexOf(15.)
+   ratio_down = corr.readY(0)[index] / orig.readY(0)[index]
+   print("Ratio of corrected and original 'down' intensity at 15A: {:.4}".format(ratio_down))
+
+Output:
+
+.. testoutput:: PolarizationEfficiencyCorExample
+
+   Ratio of corrected and original 'up' intensity at 15A: 1.038
+   Ratio of corrected and original 'down' intensity at 15A: 1.062
+
+References
+----------
+
+.. [#WILDES] A. R. Wildes, *Neutron News*, **17** 17 (2006)
+             `doi: 10.1080/10448630600668738 <https://doi.org/10.1080/10448630600668738>`_
+
+.. categories::
+
+.. sourcelink::
+
diff --git a/docs/source/algorithms/PolarizationEfficiencyCor-v1.rst b/docs/source/algorithms/PolarizationEfficiencyCor-v1.rst
index a34480a2307b1035f6ee503f4b5b352f272d11bd..69145706df83f57fa86cda91088239b8c5fbcd61 100644
--- a/docs/source/algorithms/PolarizationEfficiencyCor-v1.rst
+++ b/docs/source/algorithms/PolarizationEfficiencyCor-v1.rst
@@ -1,4 +1,3 @@
-
 .. algorithm::
 
 .. summary::
@@ -10,151 +9,16 @@
 Description
 -----------
 
-This algorithm corrects for non-ideal instrument component efficiencies in a polarization analysis experiment by following the procedure and conventions introduced by Wildes [#WILDES]_. In the full polarization analysis case it solves the corrected count rates :math:`\Sigma^{++}`, :math:`\Sigma^{+-}`, :math:`\Sigma^{-+}` and :math:`\Sigma^{--}` from the equation
-
-.. math::
-   \begin{bmatrix}
-   \Sigma^{++} \\
-   \Sigma^{+-} \\
-   \Sigma^{-+} \\
-   \Sigma^{--}
-   \end{bmatrix}
-   = \bm{M}
-   \begin{bmatrix}
-   I^{00} \\
-   I^{01} \\
-   I^{10} \\
-   I^{11}
-   \end{bmatrix},
-
-where :math:`I^{jk}` are the experimental count rates for flipper configuration :math:`jk` and :math:`\bm{M}` is the four-by-four correction matrix as defined by equations (4) in [#WILDES]_.
-
-Flipper configurations
-######################
-
-*InputWorkspaces* is a list containing one to four workspace names (X unit: wavelength) corresponding to the instrument configurations given as *Flippers*. Supported configurations are:
-
-:literal:`'00, 01, 10, 11'`
-   Full polarization corrections. Four input workspaces are required. They should be in the input group in the following order: both flippers off, polarizer flipper on, analyzer flipper on, both flippers on.
-
-:literal:`'00, 01, 11'` and :literal:`'00, 10, 11'`
-   Polarization corrections with the assumption that the corrected count rates :math:`\Sigma^{+-} = \Sigma^{-+}`. In this case the intensity of the missing flipper configuration (01 or 10) can be solved from the other intensities. Workspaces in the input group should be in the following order: both flippers off, one flipper on, both flippers on.
-
-:literal:`'00, 11'`
-   Polarization corrections with the assumption that the corrected count rates :math:`\Sigma^{+-} = \Sigma^{-+} = 0`. In this case the intensities of the missing flipper configurations (01 and 11) can be solved from the other intensities. Workspaces in the input group should be in the following order: both flippers off, both flippers on.
-
-:literal:`'0, 1'`
-   Polarization corrections when no analyzer has been used. Workspaces in the input group should be in the following order: polarizer flipper off, polarizer flipper on.
-
-:literal:`'0'`
-   Polarization corrections for a direct beam measurement in a reflectometry experiment.
-
-Output
-######
-
-The algorithm's output is a group workspace containing the corrected workspaces. The names of each corrected workspace is prefixed by :literal:`_++`, :literal:`_+-`, :literal:`_-+` or :literal:`_--` depending on which :math:`\Sigma^{mn}` they correspond to.
-
-Efficiency factors
-##################
-
-The *Efficiencies* input property expects to get a workspace with the following properties:
+This is a wrapper around the algorithms
+:ref:`algm-PolarizationCorrectionWildes` and :ref:`algm-PolarizationCorrectionFredrikze`. Use `CorrectionMethod` property
+to select between the two. The default is Wildes.
 
-* Contains four histograms, each labeled by their vertical axis as :literal:`P1`, :literal:`P2`, :literal:`F1`, :literal:`F2`. Other histograms (if present) are ignored.
-* The Y values of each histogram should be the corresponding efficiencies as functions of wavelength as defined in [#WILDES]_.
-* The wavelength values (X values) should be the same is in the input workspaces.
+The input workspaces can be passed in either via `InputWorkspaces` or
+`InputWorkspaceGroup` property but not both. An attempt to set both properties will result in an error.
 
-.. note::
-   Users at ILL can load a conforming efficiency workspace from disk by :ref:`algm-LoadILLPolarizationFactors`.
-
-Error propagation
-#################
-
-.. note::
-   Errors are calculated as per Wildes [#WILDES]_, except for the numerically solved intensity in :literal:`'00, 01, 11'` and :literal:`'00, 10, 11'` flipper configurations in which case the uncertainties of :math:`\Sigma^{+-}` or :math:`\Sigma^{-+}` are set to zero.
-
-Usage
------
-
-.. include:: ../usagedata-note.txt
-
-**Example - PolarizationEfficiencyCor**
-
-.. testcode:: PolarizationEfficiencyCorExample
-
-   LoadILLReflectometry(
-       Filename='ILL/D17/317370.nxs',
-       OutputWorkspace='direct_beam',
-       OutputBeamPosition='direct_beam_position',
-       XUnit='TimeOfFlight')
-   LoadILLReflectometry(
-       Filename='ILL/D17/317370.nxs',
-       OutputWorkspace='reflected_beam',
-       DirectBeamPosition='direct_beam_position',
-       XUnit='TimeOfFlight')
-   # Sum pixels containing the reflected intensity
-   GroupDetectors(
-       InputWorkspace='reflected_beam',
-       OutputWorkspace='reflected_beam',
-       WorkspaceIndexList=[199, 200, 201, 202, 203, 204, 205])
-   ConvertUnits(
-       InputWorkspace='reflected_beam',
-       OutputWorkspace='reflected_beam',
-       Target='Wavelength',
-       EMode='Elastic')
-   # There are some unphysical wavelengths
-   CropWorkspace(
-       InputWorkspace='reflected_beam',
-       OutputWorkspace='reflected_beam',
-       XMin=0.)
-   # Fake two flipper configurations 
-   RenameWorkspace(
-       InputWorkspace='reflected_beam',
-       OutputWorkspace='up'
-   )
-   CloneWorkspace(
-       InputWorkspace='up',
-       OutputWorkspace='down'
-   )
-   Scale(
-       InputWorkspace='down',
-       OutputWorkspace='down',
-       Factor=0.1
-   )
-   LoadILLPolarizationFactors(
-       Filename='ILL/D17/PolarizationFactors.txt',
-       OutputWorkspace='efficiencies',
-       WavelengthReference='up')
-   PolarizationEfficiencyCor(
-       InputWorkspaces='up, down',
-       OutputWorkspace='corrected',
-       Efficiencies='efficiencies',
-       Flippers='00, 11')
-   
-   orig = mtd['up']
-   corr = mtd['corrected_++']
-   index = orig.binIndexOf(15.)
-   ratio_up = corr.readY(0)[index] / orig.readY(0)[index]
-   print("Ratio of corrected and original 'up' intensity at 15A: {:.4}".format(ratio_up))
-   orig = mtd['down']
-   corr = mtd['corrected_--']
-   index = orig.binIndexOf(15.)
-   ratio_down = corr.readY(0)[index] / orig.readY(0)[index]
-   print("Ratio of corrected and original 'down' intensity at 15A: {:.4}".format(ratio_down))
-
-Output:
-
-.. testoutput:: PolarizationEfficiencyCorExample
-
-   Ratio of corrected and original 'up' intensity at 15A: 1.038
-   Ratio of corrected and original 'down' intensity at 15A: 1.062
-
-References
-----------
-
-.. [#WILDES] A. R. Wildes, *Neutron News*, **17** 17 (2006)
-             `doi: 10.1080/10448630600668738 <https://doi.org/10.1080/10448630600668738>`_
+The default values for the `Flippers` and `PolarizationAnalysis` properties are empty strings and correspond to the actual
+defaults of the child algorithms: `00, 01, 10, 11` for Wildes and `PA` for Fredrikze.
 
 .. categories::
 
 .. sourcelink::
-
diff --git a/docs/source/algorithms/ReflectometryReductionOneAuto-v2.rst b/docs/source/algorithms/ReflectometryReductionOneAuto-v2.rst
index 4258f0d63cb608753b0818403fce8e1ca991567d..0156eaeb847e33df16fd1fd792e02c90b3c2a387 100644
--- a/docs/source/algorithms/ReflectometryReductionOneAuto-v2.rst
+++ b/docs/source/algorithms/ReflectometryReductionOneAuto-v2.rst
@@ -106,7 +106,7 @@ Polarization Analysis On
 If :literal:`PolarizationAnalysis` is set to :literal:`PA` or :literal:`PNR`
 the reduction continues and polarization corrections will be applied to
 the output workspace in wavelength. The algorithm will use the properties :literal:`PolarizationAnalysis`,
-:literal:`CPp`, :literal:`CAp`, :literal:`CRho` and :literal:`CAlpha` to run :ref:`algm-PolarizationCorrection`.
+:literal:`Pp`, :literal:`Ap`, :literal:`Rho` and :literal:`Alpha` to run :ref:`algm-PolarizationCorrectionFredrikze`.
 The result will be a new workspace in wavelength, which will override the previous one, that will
 be used as input to :ref:`algm-ReflectometryReductionOne` to calculate the new output workspaces in Q, which
 in turn will override the existing workspaces in Q. Note that if transmission runs are provided in the form of workspace
diff --git a/docs/source/interfaces/ISIS Reflectometry.rst b/docs/source/interfaces/ISIS Reflectometry.rst
index 59adf74a69c70886419c5d9382cfceea8c759c60..bd8bfe4b1aecec8ce2faa5b932c1cb14c762b5d1 100644
--- a/docs/source/interfaces/ISIS Reflectometry.rst	
+++ b/docs/source/interfaces/ISIS Reflectometry.rst	
@@ -1,5 +1,6 @@
 .. _interface-isis-refl:
 
+
 ============================
 ISIS Reflectometry Interface
 ============================
diff --git a/docs/source/release/v3.13.0/reflectometry.rst b/docs/source/release/v3.13.0/reflectometry.rst
index c3c757687314402d038c6eae4e35573c7574b747..72d1b5f7f5cc48b82dcb3f14e75d2ee0568665e3 100644
--- a/docs/source/release/v3.13.0/reflectometry.rst
+++ b/docs/source/release/v3.13.0/reflectometry.rst
@@ -30,16 +30,23 @@ Algorithms
 ----------
 
 * Removed version 1 of ``ReflectometryReductionOne`` and ``ReflectometryReductionOneAuto``.
+* Renamed algorithms ``PolarizationCorrection`` to ``PolarizationCorrectionFredrikze`` and ``PolarizationEfficiencyCor`` to ``PolarizationCorrectionWildes``.
 
 New features
 ############
 
-- Algorithms for reflectometry reduction at ILL have been added. These handle the basic reduction in SumInLambda mode. Included algorithms:
+* Added algorithm ``PolarizationEfficiencyCor`` which calls ``PolarizationCorrectionFredrikze`` or ``PolarizationCorrectionWildes`` depending on chosen ``Method`` property.
+* Added algorithms that help create a matrix workspace with polarization efficiencies ready to be used with ``PolarizationEfficiencyCor``
+
+  - ``CreatePolarizationEfficiencies`` creates efficiencies from polynomial coefficients
+  - ``JoinISISPolarizationEfficiencies`` joins individual efficiencies into one matrix workspace
+  - ``LoadISISPolarizationEfficiencies`` loads efficiencies form files
+* Algorithms for reflectometry reduction at ILL have been added. These handle the basic reduction in SumInLambda mode. Included algorithms:
     - :ref:`algm-ReflectometryILLPreprocess`
     - :ref:`algm-ReflectometryILLSumForeground`
     - :ref:`algm-ReflectometryILLPolarizationCor`
     - :ref:`algm-ReflectometryILLConvertToQ`
-- A new algorithm :ref:`algm-ReflectometryMomentumTransfer` provides conversion to momentum transfer and :math:`Q_{z}` resolution calculation for relfectivity workspaces.
+* A new algorithm :ref:`algm-ReflectometryMomentumTransfer` provides conversion to momentum transfer and :math:`Q_{z}` resolution calculation for relfectivity workspaces.
 
 Improvements
 ############
diff --git a/qt/scientific_interfaces/ISISReflectometry/ExperimentOptionDefaults.cpp b/qt/scientific_interfaces/ISISReflectometry/ExperimentOptionDefaults.cpp
index 584e9374506005b6990cbe31a216ceead5bf28d3..1f2547d15594ab9cf31d57dc3bf4ddd54c164058 100644
--- a/qt/scientific_interfaces/ISISReflectometry/ExperimentOptionDefaults.cpp
+++ b/qt/scientific_interfaces/ISISReflectometry/ExperimentOptionDefaults.cpp
@@ -25,8 +25,8 @@ std::ostream &operator<<(std::ostream &os,
                          ExperimentOptionDefaults const &defaults) {
   os << "ExperimentOptionDefaults: { AnalysisMode: '" << defaults.AnalysisMode
      << ", \nPolarizationAnalysis: '" << defaults.PolarizationAnalysis
-     << "',\nCRho: '" << defaults.CRho << "',\nCAlpha: '" << defaults.CAlpha
-     << "',\nCAp: '" << defaults.CAp << "', \nCPp: '" << defaults.CPp
+     << "',\nRho: '" << defaults.CRho << "',\nAlpha: '" << defaults.CAlpha
+     << "',\nAp: '" << defaults.CAp << "', \nPp: '" << defaults.CPp
      << "',\nSummationType: '" << defaults.SummationType
      << "', \nReductionType: '" << defaults.ReductionType;
   if (defaults.TransRunStartOverlap)
diff --git a/qt/scientific_interfaces/ISISReflectometry/QtReflSettingsView.cpp b/qt/scientific_interfaces/ISISReflectometry/QtReflSettingsView.cpp
index e318d9eb0f150c46862b03ce0ea25a40b762a846..8ccad3eb878ce849cd0ae2eb26385a414dbc9c2b 100644
--- a/qt/scientific_interfaces/ISISReflectometry/QtReflSettingsView.cpp
+++ b/qt/scientific_interfaces/ISISReflectometry/QtReflSettingsView.cpp
@@ -148,10 +148,10 @@ void QtReflSettingsView::registerExperimentSettingsWidgets(
   registerSettingWidget(*m_ui.startOverlapEdit, "StartOverlap", alg);
   registerSettingWidget(*m_ui.endOverlapEdit, "EndOverlap", alg);
   registerSettingWidget(*m_ui.polCorrComboBox, "PolarizationAnalysis", alg);
-  registerSettingWidget(*m_ui.CRhoEdit, "CRho", alg);
-  registerSettingWidget(*m_ui.CAlphaEdit, "CAlpha", alg);
-  registerSettingWidget(*m_ui.CApEdit, "CAp", alg);
-  registerSettingWidget(*m_ui.CPpEdit, "CPp", alg);
+  registerSettingWidget(*m_ui.CRhoEdit, "Rho", alg);
+  registerSettingWidget(*m_ui.CAlphaEdit, "Alpha", alg);
+  registerSettingWidget(*m_ui.CApEdit, "Ap", alg);
+  registerSettingWidget(*m_ui.CPpEdit, "Pp", alg);
   registerSettingWidget(stitchOptionsLineEdit(), "Params", alg);
 }
 
diff --git a/qt/scientific_interfaces/ISISReflectometry/ReflSettingsPresenter.cpp b/qt/scientific_interfaces/ISISReflectometry/ReflSettingsPresenter.cpp
index bf42ae1a721e00361965d8d25acc6cc92ad6216c..ba36bd8ceaf261a29c0a1fddb92d4125a6c9e64b 100644
--- a/qt/scientific_interfaces/ISISReflectometry/ReflSettingsPresenter.cpp
+++ b/qt/scientific_interfaces/ISISReflectometry/ReflSettingsPresenter.cpp
@@ -213,10 +213,10 @@ OptionsQMap ReflSettingsPresenter::getReductionOptions() const {
 
   if (m_view->experimentSettingsEnabled()) {
     addIfNotEmpty(options, "AnalysisMode", m_view->getAnalysisMode());
-    addIfNotEmpty(options, "CRho", m_view->getCRho());
-    addIfNotEmpty(options, "CAlpha", m_view->getCAlpha());
-    addIfNotEmpty(options, "CAp", m_view->getCAp());
-    addIfNotEmpty(options, "CPp", m_view->getCPp());
+    addIfNotEmpty(options, "Rho", m_view->getCRho());
+    addIfNotEmpty(options, "Alpha", m_view->getCAlpha());
+    addIfNotEmpty(options, "Ap", m_view->getCAp());
+    addIfNotEmpty(options, "Pp", m_view->getCPp());
     addIfNotEmpty(options, "PolarizationAnalysis",
                   m_view->getPolarisationCorrections());
     addIfNotEmpty(options, "StartOverlap", m_view->getStartOverlap());
diff --git a/qt/scientific_interfaces/test/ReflSettingsPresenterTest.h b/qt/scientific_interfaces/test/ReflSettingsPresenterTest.h
index 493ce7187a897fdf0bebee911c692f4ceb5eb7c3..2a62575dc4370038139fb528a895526dca021a90 100644
--- a/qt/scientific_interfaces/test/ReflSettingsPresenterTest.h
+++ b/qt/scientific_interfaces/test/ReflSettingsPresenterTest.h
@@ -204,10 +204,10 @@ public:
 
     auto options = presenter.getReductionOptions();
     TS_ASSERT_EQUALS(variantToString(options["PolarizationAnalysis"]), "PNR");
-    TS_ASSERT_EQUALS(variantToString(options["CRho"]), "2.5,0.4,1.1");
-    TS_ASSERT_EQUALS(variantToString(options["CAlpha"]), "0.6,0.9,1.2");
-    TS_ASSERT_EQUALS(variantToString(options["CAp"]), "100.0,17.0,44.0");
-    TS_ASSERT_EQUALS(variantToString(options["CPp"]), "0.54,0.33,1.81");
+    TS_ASSERT_EQUALS(variantToString(options["Rho"]), "2.5,0.4,1.1");
+    TS_ASSERT_EQUALS(variantToString(options["Alpha"]), "0.6,0.9,1.2");
+    TS_ASSERT_EQUALS(variantToString(options["Ap"]), "100.0,17.0,44.0");
+    TS_ASSERT_EQUALS(variantToString(options["Pp"]), "0.54,0.33,1.81");
 
     TS_ASSERT(Mock::VerifyAndClearExpectations(&mockView));
   }