/** Execute the algorithm.
 */
void PolarizationCorrection::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 propName = loadableProperties.begin();
            propName != loadableProperties.end(); ++propName) {
        Property *prop = getProperty(propName->first);

        if (!prop)
            continue;

        if (prop->isDefault()) {
            auto vals = instrument->getStringParameter(propName->second);
            if (vals.empty())
                throw std::runtime_error(
                    "Cannot find value for " + propName->first +
                    " in parameter file. Please specify this property manually.");
            prop->setValue(vals[0]);
        }
    }

    WorkspaceGroup_sptr outWS;
    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()) {
        if (nWorkspaces != 2) {
            throw std::invalid_argument(
                "For PNR analysis, input group must have 2 periods.");
        }
        outWS = execPNR(inWS);
        g_log.notice("PNR polarization correction");
    }
    this->setProperty("OutputWorkspace", outWS);
}
/** 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;
  }
}