diff --git a/Framework/Algorithms/inc/MantidAlgorithms/PolarizationCorrectionWildes.h b/Framework/Algorithms/inc/MantidAlgorithms/PolarizationCorrectionWildes.h index 50b691f9064f..8178b7bb7617 100644 --- a/Framework/Algorithms/inc/MantidAlgorithms/PolarizationCorrectionWildes.h +++ b/Framework/Algorithms/inc/MantidAlgorithms/PolarizationCorrectionWildes.h @@ -65,6 +65,9 @@ class MANTID_ALGORITHMS_DLL PolarizationCorrectionWildes final : public API::Alg 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 addSpinStateOutput(std::vector &names, const std::string &spinStateOrder, + const std::string &baseName, const API::MatrixWorkspace_sptr &ws, + const std::string &spinState); }; } // namespace Algorithms } // namespace Mantid diff --git a/Framework/Algorithms/inc/MantidAlgorithms/PolarizationCorrections/PolarizationCorrectionsHelpers.h b/Framework/Algorithms/inc/MantidAlgorithms/PolarizationCorrections/PolarizationCorrectionsHelpers.h index 0b4aaef0120c..d1cc91dd227b 100644 --- a/Framework/Algorithms/inc/MantidAlgorithms/PolarizationCorrections/PolarizationCorrectionsHelpers.h +++ b/Framework/Algorithms/inc/MantidAlgorithms/PolarizationCorrections/PolarizationCorrectionsHelpers.h @@ -21,4 +21,32 @@ MANTID_ALGORITHMS_DLL std::optional indexOfWorkspaceForSpinState(const s std::string targetSpinState); MANTID_ALGORITHMS_DLL std::vector splitSpinStateString(const std::string &spinStates); } // namespace PolarizationCorrectionsHelpers + +namespace FlipperConfigurations { +auto constexpr OFF_ON = "01"; +auto constexpr ON_OFF = "10"; +auto constexpr OFF_OFF = "00"; +auto constexpr ON_ON = "11"; +auto constexpr OFF = "0"; +auto constexpr ON = "1"; +} // namespace FlipperConfigurations + +namespace SpinStateConfigurationsFredrikze { +auto constexpr PARA_ANTI = "pa"; +auto constexpr ANTI_PARA = "ap"; +auto constexpr PARA_PARA = "pp"; +auto constexpr ANTI_ANTI = "aa"; +auto constexpr PARA = "p"; +auto constexpr ANTI = "a"; +} // namespace SpinStateConfigurationsFredrikze + +namespace SpinStateConfigurationsWildes { +auto constexpr MINUS_PLUS = "-+"; +auto constexpr PLUS_MINUS = "+-"; +auto constexpr MINUS_MINUS = "--"; +auto constexpr PLUS_PLUS = "++"; +auto constexpr MINUS = "-"; +auto constexpr PLUS = "+"; +} // namespace SpinStateConfigurationsWildes + } // namespace Mantid::Algorithms \ No newline at end of file diff --git a/Framework/Algorithms/inc/MantidAlgorithms/PolarizationCorrections/SpinStateValidator.h b/Framework/Algorithms/inc/MantidAlgorithms/PolarizationCorrections/SpinStateValidator.h index 064d9e09b7cb..2e597aa33ec2 100644 --- a/Framework/Algorithms/inc/MantidAlgorithms/PolarizationCorrections/SpinStateValidator.h +++ b/Framework/Algorithms/inc/MantidAlgorithms/PolarizationCorrections/SpinStateValidator.h @@ -24,16 +24,10 @@ particular ordering. */ class MANTID_ALGORITHMS_DLL SpinStateValidator : public Kernel::TypedValidator { public: - SpinStateValidator(std::unordered_set allowedNumbersOfSpins, const bool acceptSingleStates = false); + SpinStateValidator(std::unordered_set allowedNumbersOfSpins, const bool acceptSingleStates = false, + const char paraIndicator = '0', const char antiIndicator = '1', const bool optional = false); Kernel::IValidator_sptr clone() const override; - static const std::string ZERO_ONE; - static const std::string ONE_ZERO; - static const std::string ZERO_ZERO; - static const std::string ONE_ONE; - static const std::string ZERO; - static const std::string ONE; - static bool anyOfIsInSet(const std::vector &anyOf, const std::unordered_set &set); static bool setContains(const std::unordered_set &set, const std::string &s) { return set.find(s) != set.cend(); @@ -42,6 +36,11 @@ class MANTID_ALGORITHMS_DLL SpinStateValidator : public Kernel::TypedValidator m_allowedNumbersOfSpins = {1, 2, 3, 4}; + const std::unordered_set getAllowedPairStates() const; + const std::unordered_set getAllowedSingleStates() const; bool m_acceptSingleStates = false; + const std::string m_para; + const std::string m_anti; + bool m_optional = false; }; -} // namespace Mantid::Algorithms \ No newline at end of file +} // namespace Mantid::Algorithms diff --git a/Framework/Algorithms/inc/MantidAlgorithms/PolarizationEfficiencyCor.h b/Framework/Algorithms/inc/MantidAlgorithms/PolarizationEfficiencyCor.h index ab57d514f613..7744d6f5fd33 100644 --- a/Framework/Algorithms/inc/MantidAlgorithms/PolarizationEfficiencyCor.h +++ b/Framework/Algorithms/inc/MantidAlgorithms/PolarizationEfficiencyCor.h @@ -22,7 +22,9 @@ class MANTID_ALGORITHMS_DLL PolarizationEfficiencyCor final : public API::Algori public: const std::string name() const override; int version() const override; - const std::vector seeAlso() const override { return {"PolarizationCorrectionFredrikze"}; } + const std::vector seeAlso() const override { + return {"PolarizationCorrectionWildes", "PolarizationCorrectionFredrikze"}; + } const std::string category() const override; const std::string summary() const override; diff --git a/Framework/Algorithms/src/PolarizationCorrectionWildes.cpp b/Framework/Algorithms/src/PolarizationCorrectionWildes.cpp index 054ddf75929d..20ea1f7f1f0a 100644 --- a/Framework/Algorithms/src/PolarizationCorrectionWildes.cpp +++ b/Framework/Algorithms/src/PolarizationCorrectionWildes.cpp @@ -25,22 +25,12 @@ namespace { /// Property names. namespace Prop { static const std::string FLIPPERS{"Flippers"}; +static const std::string SPIN_STATES{"SpinStates"}; 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 { -using namespace Mantid::Algorithms; -static const std::string Off{SpinStateValidator::ZERO}; -static const std::string OffOff{SpinStateValidator::ZERO_ZERO}; -static const std::string OffOn{SpinStateValidator::ZERO_ONE}; -static const std::string On{SpinStateValidator::ONE}; -static const std::string OnOff{SpinStateValidator::ONE_ZERO}; -static const std::string OnOn{SpinStateValidator::ONE_ONE}; -} // namespace Flippers - /** * Throw if given ws is nullptr. * @param ws a workspace to check @@ -313,8 +303,9 @@ const std::string PolarizationCorrectionWildes::summary() const { "and analyzer efficiencies."; } +/// Algorithm's related algorithms. @see Algorithm::seeAlso const std::vector PolarizationCorrectionWildes::seeAlso() const { - return {"PolarizationEfficienciesWildes"}; + return {"PolarizationEfficiencyCor", "PolarizationEfficienciesWildes"}; } /** @@ -337,10 +328,14 @@ void PolarizationCorrectionWildes::init() { std::make_unique>(Prop::OUTPUT_WS, "", Kernel::Direction::Output), "A group of polarization efficiency corrected workspaces."); - const auto spinStateValidator = std::make_shared(std::unordered_set{1, 2, 3, 4}, true); + const auto flipperConfigValidator = std::make_shared(std::unordered_set{1, 2, 3, 4}, true); declareProperty(Prop::FLIPPERS, - Flippers::OffOff + ", " + Flippers::OffOn + ", " + Flippers::OnOff + ", " + Flippers::OnOn, - spinStateValidator, "Flipper configurations of the input workspaces."); + std::string(FlipperConfigurations::OFF_OFF) + ", " + FlipperConfigurations::OFF_ON + ", " + + FlipperConfigurations::ON_OFF + ", " + FlipperConfigurations::ON_ON, + flipperConfigValidator, "Flipper configurations of the input workspaces."); + const auto spinStateValidator = + std::make_shared(std::unordered_set{0, 2, 4}, false, '+', '-', true); + declareProperty(Prop::SPIN_STATES, "", spinStateValidator, "The order of the spin states in the output workspace."); declareProperty( std::make_unique>(Prop::EFFICIENCIES, "", Kernel::Direction::Input), "A workspace containing the efficiency factors P1, P2, F1 and F2 as " @@ -410,12 +405,28 @@ std::map PolarizationCorrectionWildes::validateInputs( } } const std::vector inputs = getProperty(Prop::INPUT_WS); - const std::string flipperProperty = getProperty(Prop::FLIPPERS); - const auto flipperCount = PolarizationCorrectionsHelpers::splitSpinStateString(flipperProperty).size(); + const auto flipperConfig = PolarizationCorrectionsHelpers::splitSpinStateString(getPropertyValue(Prop::FLIPPERS)); + const auto flipperCount = flipperConfig.size(); if (inputs.size() != flipperCount) { issues[Prop::FLIPPERS] = "The number of flipper configurations (" + std::to_string(flipperCount) + ") does not match the number of input workspaces (" + std::to_string(inputs.size()) + ")"; } + // SpinStates checks. + const auto spinStates = PolarizationCorrectionsHelpers::splitSpinStateString(getPropertyValue(Prop::SPIN_STATES)); + if (inputs.size() == 1 && !spinStates.empty()) { + issues[Prop::SPIN_STATES] = "Output workspace order cannot be set for direct beam calculations."; + } else if (!spinStates.empty()) { + if (flipperConfig.front().size() == 1 && spinStates.size() != 2) { + issues[Prop::SPIN_STATES] = + "Incorrect number of workspaces in output configuration: " + std::to_string(spinStates.size()) + + ". Only two output workspaces are produced when an analyzer is not used."; + } + if (flipperConfig.front().size() == 2 && spinStates.size() != 4) { + issues[Prop::SPIN_STATES] = + "Incorrect number of workspaces in output configuration: " + std::to_string(spinStates.size()) + + ". Four output workspaces are produced by the corrections."; + } + } return issues; } @@ -438,16 +449,16 @@ void PolarizationCorrectionWildes::checkConsistentNumberHistograms(const Workspa } }; if (inputs.mmWS) { - checkNHist(inputs.mmWS, Flippers::OnOn); + checkNHist(inputs.mmWS, FlipperConfigurations::ON_ON); } if (inputs.mpWS) { - checkNHist(inputs.mpWS, Flippers::OnOff); + checkNHist(inputs.mpWS, FlipperConfigurations::ON_OFF); } if (inputs.pmWS) { - checkNHist(inputs.pmWS, Flippers::OffOn); + checkNHist(inputs.pmWS, FlipperConfigurations::OFF_ON); } if (inputs.ppWS) { - checkNHist(inputs.ppWS, Flippers::OffOff); + checkNHist(inputs.ppWS, FlipperConfigurations::OFF_OFF); } } @@ -484,16 +495,16 @@ void PolarizationCorrectionWildes::checkConsistentX(const WorkspaceMap &inputs, } }; if (inputs.mmWS) { - checkWS(inputs.mmWS, Flippers::OnOn); + checkWS(inputs.mmWS, FlipperConfigurations::ON_ON); } if (inputs.mpWS) { - checkWS(inputs.mpWS, Flippers::OnOff); + checkWS(inputs.mpWS, FlipperConfigurations::ON_OFF); } if (inputs.pmWS) { - checkWS(inputs.pmWS, Flippers::OffOn); + checkWS(inputs.pmWS, FlipperConfigurations::OFF_ON); } if (inputs.ppWS) { - checkWS(inputs.ppWS, Flippers::OffOff); + checkWS(inputs.ppWS, FlipperConfigurations::OFF_OFF); } } @@ -505,24 +516,26 @@ void PolarizationCorrectionWildes::checkConsistentX(const WorkspaceMap &inputs, * @return a group workspace */ API::WorkspaceGroup_sptr PolarizationCorrectionWildes::groupOutput(const WorkspaceMap &outputs) { - const std::string outWSName = getProperty(Prop::OUTPUT_WS); + const auto &outWSName = getPropertyValue(Prop::OUTPUT_WS); + auto spinStateOrder = getPropertyValue(Prop::SPIN_STATES); std::vector names; + if (!spinStateOrder.empty()) { + names.resize(PolarizationCorrectionsHelpers::splitSpinStateString(spinStateOrder).size()); + } + if (outputs.ppWS) { - names.emplace_back(outWSName + "_++"); - API::AnalysisDataService::Instance().addOrReplace(names.back(), outputs.ppWS); + addSpinStateOutput(names, spinStateOrder, outWSName, outputs.ppWS, SpinStateConfigurationsWildes::PLUS_PLUS); } if (outputs.pmWS) { - names.emplace_back(outWSName + "_+-"); - API::AnalysisDataService::Instance().addOrReplace(names.back(), outputs.pmWS); + addSpinStateOutput(names, spinStateOrder, outWSName, outputs.pmWS, SpinStateConfigurationsWildes::PLUS_MINUS); } if (outputs.mpWS) { - names.emplace_back(outWSName + "_-+"); - API::AnalysisDataService::Instance().addOrReplace(names.back(), outputs.mpWS); + addSpinStateOutput(names, spinStateOrder, outWSName, outputs.mpWS, SpinStateConfigurationsWildes::MINUS_PLUS); } if (outputs.mmWS) { - names.emplace_back(outWSName + "_--"); - API::AnalysisDataService::Instance().addOrReplace(names.back(), outputs.mmWS); + addSpinStateOutput(names, spinStateOrder, outWSName, outputs.mmWS, SpinStateConfigurationsWildes::MINUS_MINUS); } + auto group = createChildAlgorithm("GroupWorkspaces"); group->initialize(); group->setProperty("InputWorkspaces", names); @@ -532,6 +545,34 @@ API::WorkspaceGroup_sptr PolarizationCorrectionWildes::groupOutput(const Workspa return outWS; } +/** + * Add an output name in the correct position in the vector and to the ADS. + * @param names A list of the names of the workspaces the algorithm has generated. + * @param spinStateOrder The order the output should be in. + * @param baseName The base name for the output workspaces ("BASENAME_SPINSTATE" e.g "OUTNAME_+-") + * @param ws The workspace to add to the vector and ADS. + * @param spinState The spin state the workspace represents. + */ +void PolarizationCorrectionWildes::addSpinStateOutput(std::vector &names, + const std::string &spinStateOrder, const std::string &baseName, + const API::MatrixWorkspace_sptr &ws, + const std::string &spinState) { + if (spinStateOrder.empty()) { + names.emplace_back(baseName + "_" + spinState); + API::AnalysisDataService::Instance().addOrReplace(names.back(), ws); + } else { + const auto &maybeIndex = PolarizationCorrectionsHelpers::indexOfWorkspaceForSpinState( + PolarizationCorrectionsHelpers::splitSpinStateString(spinStateOrder), spinState); + if (!maybeIndex.has_value()) { + throw std::invalid_argument("Required spin state (" + spinState + ") not found in spin state order (" + + spinStateOrder + ")."); + } + const auto index = maybeIndex.value(); + names[index] = baseName + "_" + spinState; + API::AnalysisDataService::Instance().addOrReplace(names[index], ws); + } +} + /** * Make a convenience access object to the efficiency factors. * @return an EfficiencyMap object @@ -566,7 +607,7 @@ PolarizationCorrectionWildes::EfficiencyMap PolarizationCorrectionWildes::effici PolarizationCorrectionWildes::WorkspaceMap PolarizationCorrectionWildes::directBeamCorrections(const WorkspaceMap &inputs, const EfficiencyMap &efficiencies) { using namespace boost::math; - checkInputExists(inputs.ppWS, Flippers::Off); + checkInputExists(inputs.ppWS, FlipperConfigurations::OFF); WorkspaceMap outputs; outputs.ppWS = createWorkspaceWithHistory(inputs.ppWS); const size_t nHisto = inputs.ppWS->getNumberHistograms(); @@ -603,8 +644,8 @@ PolarizationCorrectionWildes::directBeamCorrections(const WorkspaceMap &inputs, PolarizationCorrectionWildes::WorkspaceMap PolarizationCorrectionWildes::analyzerlessCorrections(const WorkspaceMap &inputs, const EfficiencyMap &efficiencies) { using namespace boost::math; - checkInputExists(inputs.mmWS, Flippers::On); - checkInputExists(inputs.ppWS, Flippers::Off); + checkInputExists(inputs.mmWS, FlipperConfigurations::ON); + checkInputExists(inputs.ppWS, FlipperConfigurations::OFF); WorkspaceMap outputs; outputs.mmWS = createWorkspaceWithHistory(inputs.mmWS); outputs.ppWS = createWorkspaceWithHistory(inputs.ppWS); @@ -667,8 +708,8 @@ PolarizationCorrectionWildes::analyzerlessCorrections(const WorkspaceMap &inputs PolarizationCorrectionWildes::WorkspaceMap PolarizationCorrectionWildes::twoInputCorrections(const WorkspaceMap &inputs, const EfficiencyMap &efficiencies) { using namespace boost::math; - checkInputExists(inputs.mmWS, Flippers::OnOn); - checkInputExists(inputs.ppWS, Flippers::OffOff); + checkInputExists(inputs.mmWS, FlipperConfigurations::ON_ON); + checkInputExists(inputs.ppWS, FlipperConfigurations::OFF_OFF); WorkspaceMap fullInputs = inputs; fullInputs.mpWS = createWorkspaceWithHistory(inputs.mmWS); fullInputs.pmWS = createWorkspaceWithHistory(inputs.ppWS); @@ -688,13 +729,13 @@ PolarizationCorrectionWildes::twoInputCorrections(const WorkspaceMap &inputs, co PolarizationCorrectionWildes::WorkspaceMap PolarizationCorrectionWildes::threeInputCorrections(const WorkspaceMap &inputs, const EfficiencyMap &efficiencies) { WorkspaceMap fullInputs = inputs; - checkInputExists(inputs.mmWS, Flippers::OnOn); - checkInputExists(inputs.ppWS, Flippers::OffOff); + checkInputExists(inputs.mmWS, FlipperConfigurations::ON_ON); + checkInputExists(inputs.ppWS, FlipperConfigurations::OFF_OFF); if (!inputs.mpWS) { - checkInputExists(inputs.pmWS, Flippers::OffOn); + checkInputExists(inputs.pmWS, FlipperConfigurations::OFF_ON); threeInputsSolve10(fullInputs, efficiencies); } else { - checkInputExists(inputs.mpWS, Flippers::OnOff); + checkInputExists(inputs.mpWS, FlipperConfigurations::ON_OFF); threeInputsSolve01(fullInputs, efficiencies); } return fullCorrections(fullInputs, efficiencies); @@ -711,10 +752,10 @@ PolarizationCorrectionWildes::threeInputCorrections(const WorkspaceMap &inputs, 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); + checkInputExists(inputs.mmWS, FlipperConfigurations::ON_ON); + checkInputExists(inputs.mpWS, FlipperConfigurations::ON_OFF); + checkInputExists(inputs.pmWS, FlipperConfigurations::OFF_ON); + checkInputExists(inputs.ppWS, FlipperConfigurations::OFF_OFF); WorkspaceMap outputs; outputs.mmWS = createWorkspaceWithHistory(inputs.mmWS); outputs.mpWS = createWorkspaceWithHistory(inputs.mpWS); @@ -781,13 +822,13 @@ PolarizationCorrectionWildes::mapInputsToDirections(const std::vector(std::unordered_set{4}); declareProperty(PropNames::SPIN_STATES, INITIAL_SPIN, spinValidator, - "Order of individual spin states in the input group workspace, e.g. \"01,11,00,10\""); + "Order of individual flipper configurations in the input group workspace, e.g. \"01,11,00,10\""); declareProperty(std::make_unique>(PropNames::OUTPUT_WS, "", Direction::Output, PropertyMode::Optional), "Workspace containing the wavelength-dependent efficiency for the flipper."); @@ -129,10 +129,10 @@ void FlipperEfficiency::exec() { MatrixWorkspace_sptr FlipperEfficiency::calculateEfficiency(WorkspaceGroup_sptr const &groupWs) { auto const &spinConfig = getPropertyValue(PropNames::SPIN_STATES); - auto const &t11Ws = workspaceForSpinState(groupWs, spinConfig, SpinStateValidator::ONE_ONE); - auto const &t10Ws = workspaceForSpinState(groupWs, spinConfig, SpinStateValidator::ONE_ZERO); - auto const &t01Ws = workspaceForSpinState(groupWs, spinConfig, SpinStateValidator::ZERO_ONE); - auto const &t00Ws = workspaceForSpinState(groupWs, spinConfig, SpinStateValidator::ZERO_ZERO); + auto const &t11Ws = workspaceForSpinState(groupWs, spinConfig, FlipperConfigurations::ON_ON); + auto const &t10Ws = workspaceForSpinState(groupWs, spinConfig, FlipperConfigurations::ON_OFF); + auto const &t01Ws = workspaceForSpinState(groupWs, spinConfig, FlipperConfigurations::OFF_ON); + auto const &t00Ws = workspaceForSpinState(groupWs, spinConfig, FlipperConfigurations::OFF_OFF); auto const &numerator = (t11Ws * t00Ws) - (t10Ws * t01Ws); auto const &denominator = (t11Ws + t10Ws) * (t00Ws - t01Ws); diff --git a/Framework/Algorithms/src/PolarizationCorrections/HeliumAnalyserEfficiency.cpp b/Framework/Algorithms/src/PolarizationCorrections/HeliumAnalyserEfficiency.cpp index 844a2f514e2d..aebe4f5f8e58 100644 --- a/Framework/Algorithms/src/PolarizationCorrections/HeliumAnalyserEfficiency.cpp +++ b/Framework/Algorithms/src/PolarizationCorrections/HeliumAnalyserEfficiency.cpp @@ -57,7 +57,7 @@ void HeliumAnalyserEfficiency::init() { auto spinValidator = std::make_shared(std::unordered_set{4}); declareProperty(PropertyNames::SPIN_STATES, "11,10,01,00", spinValidator, - "Order of individual spin states in the input group workspace, e.g. \"01,11,00,10\""); + "Order of individual flipper configurations in the input group workspace, e.g. \"01,11,00,10\""); auto mustBePositive = std::make_shared>(); mustBePositive->setLower(0); @@ -149,13 +149,13 @@ void HeliumAnalyserEfficiency::calculateAnalyserEfficiency() { const std::string spinConfigurationInput = getProperty(PropertyNames::SPIN_STATES); const auto t11Ws = PolarizationCorrectionsHelpers::workspaceForSpinState(groupWorkspace, spinConfigurationInput, - SpinStateValidator::ONE_ONE); + FlipperConfigurations::ON_ON); const auto t10Ws = PolarizationCorrectionsHelpers::workspaceForSpinState(groupWorkspace, spinConfigurationInput, - SpinStateValidator::ONE_ZERO); + FlipperConfigurations::ON_OFF); const auto t01Ws = PolarizationCorrectionsHelpers::workspaceForSpinState(groupWorkspace, spinConfigurationInput, - SpinStateValidator::ZERO_ONE); + FlipperConfigurations::OFF_ON); const auto t00Ws = PolarizationCorrectionsHelpers::workspaceForSpinState(groupWorkspace, spinConfigurationInput, - SpinStateValidator::ZERO_ZERO); + FlipperConfigurations::OFF_OFF); // T_NSF = T11 + T00 (NSF = not spin flipped) MatrixWorkspace_sptr tnsfWs = addTwoWorkspaces(t11Ws, t00Ws); diff --git a/Framework/Algorithms/src/PolarizationCorrections/PolarizationEfficienciesWildes.cpp b/Framework/Algorithms/src/PolarizationCorrections/PolarizationEfficienciesWildes.cpp index 750ad089ee3a..545ed520245c 100644 --- a/Framework/Algorithms/src/PolarizationCorrections/PolarizationEfficienciesWildes.cpp +++ b/Framework/Algorithms/src/PolarizationCorrections/PolarizationEfficienciesWildes.cpp @@ -271,10 +271,10 @@ void PolarizationEfficienciesWildes::calculateFlipperEfficienciesAndPhi() { // Calculate the polarizing and analysing flipper efficiencies const WorkspaceGroup_sptr nonMagWsGrp = getProperty(PropNames::INPUT_NON_MAG_WS); const auto &flipperConfig = getPropertyValue(PropNames::FLIPPERS); - const auto &ws00 = workspaceForSpinState(nonMagWsGrp, flipperConfig, SpinStateValidator::ZERO_ZERO); - const auto &ws01 = workspaceForSpinState(nonMagWsGrp, flipperConfig, SpinStateValidator::ZERO_ONE); - const auto &ws10 = workspaceForSpinState(nonMagWsGrp, flipperConfig, SpinStateValidator::ONE_ZERO); - const auto &ws11 = workspaceForSpinState(nonMagWsGrp, flipperConfig, SpinStateValidator::ONE_ONE); + const auto &ws00 = workspaceForSpinState(nonMagWsGrp, flipperConfig, FlipperConfigurations::OFF_OFF); + const auto &ws01 = workspaceForSpinState(nonMagWsGrp, flipperConfig, FlipperConfigurations::OFF_ON); + const auto &ws10 = workspaceForSpinState(nonMagWsGrp, flipperConfig, FlipperConfigurations::ON_OFF); + const auto &ws11 = workspaceForSpinState(nonMagWsGrp, flipperConfig, FlipperConfigurations::ON_ON); const auto numerator = ws00 - ws01 - ws10 + ws11; @@ -290,10 +290,10 @@ void PolarizationEfficienciesWildes::calculateFlipperEfficienciesAndPhi() { MatrixWorkspace_sptr PolarizationEfficienciesWildes::calculateTPMOFromPhi(const WorkspaceGroup_sptr &magWsGrp) { const auto &flipperConfig = getPropertyValue(PropNames::FLIPPERS); - const auto &ws00 = workspaceForSpinState(magWsGrp, flipperConfig, SpinStateValidator::ZERO_ZERO); - const auto &ws01 = workspaceForSpinState(magWsGrp, flipperConfig, SpinStateValidator::ZERO_ONE); - const auto &ws10 = workspaceForSpinState(magWsGrp, flipperConfig, SpinStateValidator::ONE_ZERO); - const auto &ws11 = workspaceForSpinState(magWsGrp, flipperConfig, SpinStateValidator::ONE_ONE); + const auto &ws00 = workspaceForSpinState(magWsGrp, flipperConfig, FlipperConfigurations::OFF_OFF); + const auto &ws01 = workspaceForSpinState(magWsGrp, flipperConfig, FlipperConfigurations::OFF_ON); + const auto &ws10 = workspaceForSpinState(magWsGrp, flipperConfig, FlipperConfigurations::ON_OFF); + const auto &ws11 = workspaceForSpinState(magWsGrp, flipperConfig, FlipperConfigurations::ON_ON); // We use the flipper efficiency to multiply the mag ws counts, but the resulting workspace will have lost the Y unit // and distribution information. We need to put these back otherwise the rest of the calculation fails when it tries diff --git a/Framework/Algorithms/src/PolarizationCorrections/PolarizerEfficiency.cpp b/Framework/Algorithms/src/PolarizationCorrections/PolarizerEfficiency.cpp index 7f0077a94c10..b66d8b59ec49 100644 --- a/Framework/Algorithms/src/PolarizationCorrections/PolarizerEfficiency.cpp +++ b/Framework/Algorithms/src/PolarizationCorrections/PolarizerEfficiency.cpp @@ -25,6 +25,7 @@ DECLARE_ALGORITHM(PolarizerEfficiency) using namespace Kernel; using namespace API; +using namespace FlipperConfigurations; namespace PropertyNames { static const std::string INPUT_WORKSPACE = "InputWorkspace"; @@ -126,9 +127,9 @@ std::map PolarizerEfficiency::validateInputs() { ") does not match the number of spin states provided (" + std::to_string(spinStates.size()) + ")."; } const auto &t01WsIndex = - PolarizationCorrectionsHelpers::indexOfWorkspaceForSpinState(spinStates, SpinStateValidator::ZERO_ONE); + PolarizationCorrectionsHelpers::indexOfWorkspaceForSpinState(spinStates, FlipperConfigurations::OFF_ON); const auto &t00WsIndex = - PolarizationCorrectionsHelpers::indexOfWorkspaceForSpinState(spinStates, SpinStateValidator::ZERO_ZERO); + PolarizationCorrectionsHelpers::indexOfWorkspaceForSpinState(spinStates, FlipperConfigurations::OFF_OFF); if (!t01WsIndex.has_value() || !t00WsIndex.has_value()) { errorList[PropertyNames::SPIN_STATES] = "The required spin configurations (00, 01) could not be found in the given SpinStates."; @@ -161,9 +162,9 @@ void PolarizerEfficiency::calculatePolarizerEfficiency() { const auto spinConfigurationInput = getPropertyValue(PropertyNames::SPIN_STATES); const auto &t01Ws = PolarizationCorrectionsHelpers::workspaceForSpinState(groupWorkspace, spinConfigurationInput, - SpinStateValidator::ZERO_ONE); + FlipperConfigurations::OFF_ON); const auto &t00Ws = PolarizationCorrectionsHelpers::workspaceForSpinState(groupWorkspace, spinConfigurationInput, - SpinStateValidator::ZERO_ZERO); + FlipperConfigurations::OFF_OFF); const MatrixWorkspace_sptr effCell = getProperty(PropertyNames::ANALYSER_EFFICIENCY); diff --git a/Framework/Algorithms/src/PolarizationCorrections/SpinStateValidator.cpp b/Framework/Algorithms/src/PolarizationCorrections/SpinStateValidator.cpp index 820399afea4e..8b0156997da1 100644 --- a/Framework/Algorithms/src/PolarizationCorrections/SpinStateValidator.cpp +++ b/Framework/Algorithms/src/PolarizationCorrections/SpinStateValidator.cpp @@ -11,32 +11,26 @@ namespace Mantid::Algorithms { -const std::string SpinStateValidator::ZERO_ONE = "01"; -const std::string SpinStateValidator::ONE_ZERO = "10"; -const std::string SpinStateValidator::ZERO_ZERO = "00"; -const std::string SpinStateValidator::ONE_ONE = "11"; -const std::string SpinStateValidator::ZERO = "0"; -const std::string SpinStateValidator::ONE = "1"; - -namespace SpinStateStrings { -static const std::unordered_set ALLOWED_PAIR_SPIN_STATES{ - SpinStateValidator::ZERO_ZERO, SpinStateValidator::ZERO_ONE, SpinStateValidator::ONE_ZERO, - SpinStateValidator::ONE_ONE}; -static const std::unordered_set ALLOWED_SINGLE_SPIN_STATES{SpinStateValidator::ZERO, - SpinStateValidator::ONE}; -} // namespace SpinStateStrings - -SpinStateValidator::SpinStateValidator(std::unordered_set allowedNumbersOfSpins, const bool acceptSingleStates) +SpinStateValidator::SpinStateValidator(std::unordered_set allowedNumbersOfSpins, const bool acceptSingleStates, + const char paraIndicator, const char antiIndicator, const bool optional) : TypedValidator(), m_allowedNumbersOfSpins(std::move(allowedNumbersOfSpins)), - m_acceptSingleStates(acceptSingleStates) {} + m_acceptSingleStates(acceptSingleStates), m_para(std::string(1, paraIndicator)), + m_anti(std::string(1, antiIndicator)), m_optional(optional) {} Kernel::IValidator_sptr SpinStateValidator::clone() const { return std::make_shared(m_allowedNumbersOfSpins, m_acceptSingleStates); } std::string SpinStateValidator::checkValidity(const std::string &input) const { - if (input.empty()) - return "Enter a spin state string, it should be a comma-separated list of spin states, e.g. 01, 11, 10, 00"; + if (input.empty()) { + if (m_optional) { + return ""; + } + return "Enter a spin state string, it should be a comma-separated list, e.g. " + m_para + m_anti + ", " + m_anti + + m_anti + ", " + m_anti + m_para + ", " + m_para + m_para + "."; + } + const auto &allowedPairs = getAllowedPairStates(); + const auto &allowedSingles = getAllowedSingleStates(); std::vector spinStates = PolarizationCorrectionsHelpers::splitSpinStateString(input); @@ -45,22 +39,22 @@ std::string SpinStateValidator::checkValidity(const std::string &input) const { return "The number of spin states specified is not an allowed value"; // First check that the spin states are valid entries - if (std::any_of(spinStates.cbegin(), spinStates.cend(), [this](std::string s) { - const bool isPair = setContains(SpinStateStrings::ALLOWED_PAIR_SPIN_STATES, s); - const bool isSingle = m_acceptSingleStates && setContains(SpinStateStrings::ALLOWED_SINGLE_SPIN_STATES, s); + if (std::any_of(spinStates.cbegin(), spinStates.cend(), [&](std::string s) { + const bool isPair = setContains(allowedPairs, s); + const bool isSingle = m_acceptSingleStates && setContains(allowedSingles, s); return !isPair && !isSingle; })) { return m_acceptSingleStates - ? "The spin states must either be one or two digits, with each being either a zero or one" - : "The spin states must consist of two digits, either a zero or a one."; + ? "The spin states must either be one or two characters, with each being either a " + m_para + " or " + + m_anti + "." + : "The spin states must consist of two characters, either a " + m_para + " or a " + m_anti + "."; } // Single digits can't mix with pairs if (m_acceptSingleStates) { - bool containsAnySingles = - SpinStateValidator::anyOfIsInSet(spinStates, SpinStateStrings::ALLOWED_SINGLE_SPIN_STATES); + bool containsAnySingles = SpinStateValidator::anyOfIsInSet(spinStates, allowedSingles); - bool containsAnyPairs = SpinStateValidator::anyOfIsInSet(spinStates, SpinStateStrings::ALLOWED_PAIR_SPIN_STATES); + bool containsAnyPairs = SpinStateValidator::anyOfIsInSet(spinStates, allowedPairs); if (!(containsAnyPairs ^ containsAnySingles)) { return "Single and paired spin states cannot be mixed"; } @@ -80,4 +74,11 @@ bool SpinStateValidator::anyOfIsInSet(const std::vector &anyOf, const std::unordered_set &set) { return std::any_of(anyOf.cbegin(), anyOf.cend(), [&set](const std::string &s) { return setContains(set, s); }); } -} // namespace Mantid::Algorithms \ No newline at end of file + +const std::unordered_set SpinStateValidator::getAllowedPairStates() const { + return {m_para + m_para, m_para + m_anti, m_anti + m_para, m_anti + m_anti}; +} + +const std::unordered_set SpinStateValidator::getAllowedSingleStates() const { return {m_para, m_anti}; } + +} // namespace Mantid::Algorithms diff --git a/Framework/Algorithms/src/PolarizationEfficiencyCor.cpp b/Framework/Algorithms/src/PolarizationEfficiencyCor.cpp index 0d5f6c28c840..14105edb533c 100644 --- a/Framework/Algorithms/src/PolarizationEfficiencyCor.cpp +++ b/Framework/Algorithms/src/PolarizationEfficiencyCor.cpp @@ -5,6 +5,8 @@ // Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS // SPDX - License - Identifier: GPL - 3.0 + #include "MantidAlgorithms/PolarizationEfficiencyCor.h" +#include "MantidAlgorithms/PolarizationCorrections/PolarizationCorrectionsHelpers.h" +#include "MantidAlgorithms/PolarizationCorrections/SpinStateValidator.h" #include "MantidAPI/ADSValidator.h" #include "MantidAPI/Axis.h" @@ -24,6 +26,7 @@ namespace { /// Property names. namespace Prop { static const std::string FLIPPERS{"Flippers"}; +static const std::string SPIN_STATES{"SpinStates"}; static const std::string POLARIZATION_ANALYSIS{"PolarizationAnalysis"}; static const std::string EFFICIENCIES{"Efficiencies"}; static const std::string INPUT_WORKSPACES{"InputWorkspaces"}; @@ -32,16 +35,6 @@ static const std::string OUTPUT_WORKSPACES{"OutputWorkspace"}; static const std::string CORRECTION_METHOD{"CorrectionMethod"}; } // 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 - namespace CorrectionMethod { static const std::string WILDES{"Wildes"}; static const std::string FREDRIKZE{"Fredrikze"}; @@ -99,16 +92,24 @@ void PolarizationEfficiencyCor::init() { "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 = 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::string full = std::string(FlipperConfigurations::OFF_OFF) + ", " + FlipperConfigurations::OFF_ON + ", " + + FlipperConfigurations::ON_OFF + ", " + FlipperConfigurations::ON_ON; + const std::string missing01 = std::string(FlipperConfigurations::OFF_OFF) + ", " + FlipperConfigurations::ON_OFF + + ", " + FlipperConfigurations::ON_ON; + const std::string missing10 = std::string(FlipperConfigurations::OFF_OFF) + ", " + FlipperConfigurations::OFF_ON + + ", " + FlipperConfigurations::ON_ON; + const std::string missing0110 = std::string(FlipperConfigurations::OFF_OFF) + ", " + FlipperConfigurations::ON_ON; + const std::string noAnalyzer = std::string(FlipperConfigurations::OFF) + ", " + FlipperConfigurations::ON; + const std::string directBeam = std::string(FlipperConfigurations::OFF); const std::vector setups{{"", full, missing01, missing10, missing0110, noAnalyzer, directBeam}}; declareProperty(Prop::FLIPPERS, "", std::make_shared>(setups), "Flipper configurations of the input workspaces (Wildes method only)"); + const auto spinStateValidator = + std::make_shared(std::unordered_set{0, 2, 4}, true, '+', '-', true); + declareProperty(Prop::SPIN_STATES, "", spinStateValidator, + "The order of the spin states in the output workspace. (Wildes method only)."); + std::vector propOptions{"", "PA", "PNR"}; declareProperty("PolarizationAnalysis", "", std::make_shared(propOptions), "What Polarization mode will be used?\n" @@ -146,6 +147,9 @@ void PolarizationEfficiencyCor::execWildes() { if (!isDefault(Prop::FLIPPERS)) { alg->setPropertyValue("Flippers", getPropertyValue(Prop::FLIPPERS)); } + if (!isDefault(Prop::SPIN_STATES)) { + alg->setPropertyValue("SpinStates", getPropertyValue(Prop::SPIN_STATES)); + } auto out = getPropertyValue(Prop::OUTPUT_WORKSPACES); alg->setPropertyValue("OutputWorkspace", out); alg->execute(); @@ -206,6 +210,9 @@ void PolarizationEfficiencyCor::checkFredrikzeProperties() const { if (!isDefault(Prop::FLIPPERS)) { throw std::invalid_argument("Property Flippers cannot be used with the Fredrikze method."); } + if (!isDefault(Prop::SPIN_STATES)) { + throw std::invalid_argument("Property SpinStates cannot be used with the Fredrikze method."); + } } //---------------------------------------------------------------------------------------------- diff --git a/Framework/Algorithms/test/PolarizationCorrectionWildesTest.h b/Framework/Algorithms/test/PolarizationCorrectionWildesTest.h index e9ade57d974d..440561fb1e8b 100644 --- a/Framework/Algorithms/test/PolarizationCorrectionWildesTest.h +++ b/Framework/Algorithms/test/PolarizationCorrectionWildesTest.h @@ -51,12 +51,20 @@ class PolarizationCorrectionWildesTest : public CxxTest::TestSuite { runIdealCaseFullCorrections("11,00,10,01", {"++", "+-", "-+", "--"}); } + void test_IdealCaseFullCorrectionsReorderedOutputs() { + runIdealCaseFullCorrections("00,11,10,01", {"--", "++", "-+", "+-"}, true); + } + void test_IdealCaseThreeInputs10Missing() { idealThreeInputsTest("10", "00,01,11", {"++", "+-", "-+", "--"}); } void test_IdealCaseThreeInputs10MissingReorderedInput() { idealThreeInputsTest("10", "01,00,11", {"++", "+-", "-+", "--"}); } + void test_IdealCaseThreeInputs10MissingReorderedOutput() { + idealThreeInputsTest("10", "01,00,11", {"--", "+-", "-+", "++"}, true); + } + void test_IdealCaseThreeInputs01Missing() { idealThreeInputsTest("01", "00,10,11", {"++", "+-", "-+", "--"}); } void test_IdealCaseThreeInputs01MissingReorderedInput() { @@ -327,7 +335,7 @@ class PolarizationCorrectionWildesTest : public CxxTest::TestSuite { axis->setLabel(2, "P1"); axis->setLabel(3, "P2"); effWS->replaceAxis(1, std::move(axis)); - runCorrectionWildes(wsName, effWS, "0", false); + runCorrectionWildes(wsName, effWS, "0", "", false); } void test_FailureWhenEfficiencyXDataMismatches() { @@ -340,7 +348,7 @@ class PolarizationCorrectionWildesTest : public CxxTest::TestSuite { // Change a bin edge of one of the histograms. auto &xs = effWS->mutableX(0); xs[xs.size() / 2] *= 1.01; - runCorrectionWildes(wsName, effWS, "0", false); + runCorrectionWildes(wsName, effWS, "0", "", false); } void test_FailureWhenNumberOfHistogramsInInputWorkspacesMismatch() { @@ -357,7 +365,7 @@ class PolarizationCorrectionWildesTest : public CxxTest::TestSuite { AnalysisDataService::Instance().addOrReplace(wsNames[i], wsList[i]); } auto effWS = idealEfficiencies(edges); - runCorrectionWildes(wsNames, effWS, "", false); + runCorrectionWildes(wsNames, effWS, "", "", false); } void test_FailureWhenAnInputWorkspaceIsMissing() { @@ -431,13 +439,15 @@ class PolarizationCorrectionWildesTest : public CxxTest::TestSuite { Mantid::API::WorkspaceGroup_sptr runCorrectionWildes(const std::string &inputWorkspace, Mantid::API::MatrixWorkspace_sptr effWs, const std::string &flippers = "", + const std::string &spinStates = "", const bool expectedToWork = true) { - return runCorrectionWildes(std::vector{inputWorkspace}, effWs, flippers, expectedToWork); + return runCorrectionWildes(std::vector{inputWorkspace}, effWs, flippers, spinStates, expectedToWork); } Mantid::API::WorkspaceGroup_sptr runCorrectionWildes(const std::vector &inputWorkspaces, Mantid::API::MatrixWorkspace_sptr effWs, const std::string &flippers = "", + const std::string &spinStates = "", const bool expectedToWork = true) { PolarizationCorrectionWildes alg; alg.setChild(true); @@ -455,6 +465,9 @@ class PolarizationCorrectionWildesTest : public CxxTest::TestSuite { if (!flippers.empty()) { alg.setProperty("Flippers", flippers); } + if (!spinStates.empty()) { + alg.setProperty("SpinStates", spinStates); + } TS_ASSERT_THROWS_NOTHING(alg.setProperty("Efficiencies", effWs)) if (expectedToWork) { TS_ASSERT_THROWS_NOTHING(alg.execute()) @@ -555,7 +568,8 @@ class PolarizationCorrectionWildesTest : public CxxTest::TestSuite { void idealCaseFullCorrectionsTest(const Mantid::HistogramData::BinEdges &edges, const Mantid::API::MatrixWorkspace_sptr &effWS, const std::array &outputSpinStates, - const std::string &flipperConfig = "00,01,10,11") { + const std::string &flipperConfig = "00,01,10,11", + const std::string &spinStates = "") { constexpr size_t nBins{3}; constexpr size_t nHist{2}; const double yVal = 2.3; @@ -570,24 +584,31 @@ class PolarizationCorrectionWildesTest : public CxxTest::TestSuite { setupWorkspaceData(wsNames, wsList, nHist); // Re-order the input workspace names to match the input flipper configuration - auto const &flipperConfigVec = splitSpinStateString(flipperConfig); + const auto &flipperConfigVec = splitSpinStateString(flipperConfig); wsNames[indexOfWorkspaceForSpinState(flipperConfigVec, "00").value()] = ws00->getName(); wsNames[indexOfWorkspaceForSpinState(flipperConfigVec, "01").value()] = ws01->getName(); wsNames[indexOfWorkspaceForSpinState(flipperConfigVec, "10").value()] = ws10->getName(); wsNames[indexOfWorkspaceForSpinState(flipperConfigVec, "11").value()] = ws11->getName(); - WorkspaceGroup_sptr outputWS = runCorrectionWildes(wsNames, effWS, flipperConfig); + WorkspaceGroup_sptr outputWS = runCorrectionWildes(wsNames, effWS, flipperConfig, spinStates); auto pols = std::vector(4); std::transform(outputSpinStates.cbegin(), outputSpinStates.cend(), pols.begin(), [](const std::string &s) { return "_" + s; }); - compareCorrectionResults( - outputWS, pols, nHist, nBins, edges, counts, - [](size_t wsIndex, double c) { return c * static_cast(wsIndex + 1); }, - [](size_t wsIndex, double c) { return std::sqrt(c) * static_cast(wsIndex + 1); }); + if (!spinStates.empty()) { + compareCorrectionResults( + outputWS, pols, nHist, nBins, edges, counts, + [&](size_t wsIndex, double c) { return c * static_cast(getPolIndex(pols[wsIndex]) + 1); }, + [&](size_t wsIndex, double c) { return std::sqrt(c) * static_cast(getPolIndex(pols[wsIndex]) + 1); }); + } else { + compareCorrectionResults( + outputWS, pols, nHist, nBins, edges, counts, + [](size_t wsIndex, double c) { return c * static_cast(wsIndex + 1); }, + [](size_t wsIndex, double c) { return std::sqrt(c) * static_cast(wsIndex + 1); }); + } } void idealThreeInputsTest(const std::string &missingFlipperConf, const std::string &flipperConfig, - const std::vector &ouputWsOrder) { + const std::vector &outputWsOrder, const bool useSpinStates = false) { constexpr size_t nBins{3}; constexpr size_t nHist{2}; BinEdges edges{0.3, 0.6, 0.9, 1.2}; @@ -603,17 +624,22 @@ class PolarizationCorrectionWildesTest : public CxxTest::TestSuite { setupWorkspaceData(wsNames, wsList, nHist); // Re-order the input workspace names to match the input flipper configuration - auto const &flipperConfigVec = splitSpinStateString(flipperConfig); + const auto &flipperConfigVec = splitSpinStateString(flipperConfig); wsNames[indexOfWorkspaceForSpinState(flipperConfigVec, "00").value()] = ws00->getName(); wsNames[indexOfWorkspaceForSpinState(flipperConfigVec, presentFlipperConf).value()] = wsXX->getName(); wsNames[indexOfWorkspaceForSpinState(flipperConfigVec, "11").value()] = ws11->getName(); + std::string spinStates = ""; + if (useSpinStates) { + spinStates = outputWsOrder[0] + "," + outputWsOrder[1] + "," + outputWsOrder[2] + "," + outputWsOrder[3]; + } + auto effWS = idealEfficiencies(edges); - WorkspaceGroup_sptr outputWS = runCorrectionWildes(wsNames, effWS, flipperConfig); + WorkspaceGroup_sptr outputWS = runCorrectionWildes(wsNames, effWS, flipperConfig, spinStates); TS_ASSERT_EQUALS(outputWS->getNumberOfEntries(), 4) for (size_t i = 0; i != 4; ++i) { - const auto &dir = ouputWsOrder[i]; + const auto &dir = outputWsOrder[i]; const std::string wsName = m_outputWSName + std::string("_") + dir; MatrixWorkspace_sptr ws = std::dynamic_pointer_cast(outputWS->getItem(wsName)); TS_ASSERT(ws) @@ -1318,10 +1344,24 @@ class PolarizationCorrectionWildesTest : public CxxTest::TestSuite { } } - void runIdealCaseFullCorrections(const std::string &flipperConfig, const std::array &outputOrder) { + void runIdealCaseFullCorrections(const std::string &flipperConfig, const std::array &outputOrder, + const bool useSpinStates = false) { BinEdges edges{0.3, 0.6, 0.9, 1.2}; auto effWS = idealEfficiencies(edges); - idealCaseFullCorrectionsTest(edges, effWS, outputOrder, flipperConfig); + std::string spinStates = ""; + if (useSpinStates) { + spinStates = outputOrder[0] + "," + outputOrder[1] + "," + outputOrder[2] + "," + outputOrder[3]; + } + idealCaseFullCorrectionsTest(edges, effWS, outputOrder, flipperConfig, spinStates); + } + + size_t getPolIndex(const std::string &pol) { + static const std::unordered_map polMap = {{"_++", 0}, {"_+-", 1}, {"_-+", 2}, {"_--", 3}}; + const auto it = polMap.find(pol); + if (it != polMap.end()) { + return it->second; + } + throw std::invalid_argument("Unknown polarization string: " + pol); } }; diff --git a/Framework/Algorithms/test/PolarizationCorrections/SpinStateValidatorTest.h b/Framework/Algorithms/test/PolarizationCorrections/SpinStateValidatorTest.h index e92f0f5901f9..23f74cc6899c 100644 --- a/Framework/Algorithms/test/PolarizationCorrections/SpinStateValidatorTest.h +++ b/Framework/Algorithms/test/PolarizationCorrections/SpinStateValidatorTest.h @@ -28,6 +28,18 @@ class SpinStateValidatorTest : public CxxTest::TestSuite { checkAllInputs(validator, correctInputs, true); } + void testSpinStateSinglePairCorrectInputs() { + auto validator = std::make_shared(std::unordered_set{1}, false, '+', '-'); + auto correctInputs = std::vector{"-+", "--", "+-", "++", " -+", " -- ", "++ "}; + checkAllInputs(validator, correctInputs, true); + } + + void testSpinStateSingleDigitCorrectInputs() { + auto validator = std::make_shared(std::unordered_set{1}, true, '+', '-'); + auto correctInputs = std::vector{"-+", "--", "+-", "++", " -+", " -- ", "++ ", "-", "+"}; + checkAllInputs(validator, correctInputs, true); + } + void testSingleIncorrectInputs() { auto validator = std::make_shared(std::unordered_set{1}); auto incorrectInputs = std::vector{"0 1", "2", "01,10", "!", "001", "", " "}; @@ -46,6 +58,12 @@ class SpinStateValidatorTest : public CxxTest::TestSuite { checkAllInputs(validator, duplicates, false); } + void testSpinStateDuplicateEntry() { + auto validator = std::make_shared(std::unordered_set{2, 3}, false, false); + auto duplicates = std::vector{"-+, -+", "++,+-,++", "--,--"}; + checkAllInputs(validator, duplicates, false); + } + void testDuplicateEntryWithSingleDigit() { auto validator = std::make_shared(std::unordered_set{2, 3}, true); auto duplicates = std::vector{"01, 01", "11,10,11", "00,00", "1,1,0", "0,1,0", "1,1"}; @@ -58,12 +76,24 @@ class SpinStateValidatorTest : public CxxTest::TestSuite { checkAllInputs(validator, correctInputs, true); } + void testSpinStateMultipleStatesCorrectInputs() { + auto validator = std::make_shared(std::unordered_set{2, 3, 4}, false, '+', '-'); + auto correctInputs = std::vector{"-+, ++", "--,+-,++", "++,+-, --,-+", "--, +- "}; + checkAllInputs(validator, correctInputs, true); + } + void testTwoSingleDigitCorrectInputs() { auto validator = std::make_shared(std::unordered_set{2}, true); auto correctInputs = std::vector{"0, 1", "1,0"}; checkAllInputs(validator, correctInputs, true); } + void testSpinStateMixedWithFlipperConfig() { + auto validator = std::make_shared(std::unordered_set{2, 3, 4}, false, '+', '-'); + auto invalidInputs = std::vector{"-+, 0+", "--,+-,11", "++,01, --,-+", "00, 1- "}; + checkAllInputs(validator, invalidInputs, false); + } + void testAllFourSpinStateCombos() { auto validator = std::make_shared(std::unordered_set{4}); auto correctInputs = std::vector(); diff --git a/docs/source/algorithms/PolarizationCorrectionWildes-v1.rst b/docs/source/algorithms/PolarizationCorrectionWildes-v1.rst index b987d4872f62..927b197c3a76 100644 --- a/docs/source/algorithms/PolarizationCorrectionWildes-v1.rst +++ b/docs/source/algorithms/PolarizationCorrectionWildes-v1.rst @@ -20,7 +20,9 @@ This algorithm corrects for non-ideal instrument component efficiencies in a pol \Sigma^{-+} \\ \Sigma^{--} \end{bmatrix} - = \bm{M} + = \begin{bmatrix} + M + \end{bmatrix} \begin{bmatrix} I^{00} \\ I^{01} \\ @@ -28,7 +30,8 @@ This algorithm corrects for non-ideal instrument component efficiencies in a pol 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]_. +where :math:`I^{jk}` are the experimental count rates for flipper configuration :math:`jk` and +:math:`\begin{bmatrix}M\end{bmatrix}` is the four-by-four correction matrix as defined by equations (4) in [#WILDES]_. Flipper configurations ###################### @@ -50,10 +53,32 @@ Flipper configurations :literal:`'0'` Polarization corrections for a direct beam measurement in a reflectometry experiment. +Spin States +########### + +The order of the workspaces in the output group workspace can be defined by setting the values in the *SpinStates* +property. Supported configurations are: + +:literal:`''` + Default behaviour. The output workspace group will be in the order :literal:`'++, +-, -+, --'` for all outputs. In + instances where not all outputs are produced, the order is maintained with the missing workspaces omitted (e.g. + :literal:`'++, --'`). + +:literal:`'++, --, +-, --'` + For polarization corrections where both an analyzer and polarizer are used. The order of the states in the string + will be the same as the order of the workspaces in the *OutputWorkspace* group. Only allowed if flipper + configuration accounts for both flippers (contains two digits). + +:literal:`'--, ++'` + For polarization corrections when no analyzer has been used. Only allowed if the flipper configuration is also + setup this way (e.g. :literal:`'1, 0'`). + +*Note:* Output order cannot be set for direct beam measurements as there is only a single workspace in the output. + 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. +The algorithm's output is a group workspace containing the corrected workspaces. The names of each corrected workspace is suffixed by :literal:`_++`, :literal:`_+-`, :literal:`_-+` or :literal:`_--` depending on which :math:`\Sigma^{mn}` they correspond to. Efficiency factors ################## diff --git a/docs/source/algorithms/PolarizationEfficiencyCor-v1.rst b/docs/source/algorithms/PolarizationEfficiencyCor-v1.rst index 69145706df83..53496838e1db 100644 --- a/docs/source/algorithms/PolarizationEfficiencyCor-v1.rst +++ b/docs/source/algorithms/PolarizationEfficiencyCor-v1.rst @@ -16,8 +16,9 @@ to select between the two. The default is Wildes. 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. -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. +The default values for the ``Flippers``, ``SpinStates`` 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:: diff --git a/docs/source/release/v6.11.0/Framework/Algorithms/New_features/35067.rst b/docs/source/release/v6.11.0/Framework/Algorithms/New_features/35067.rst new file mode 100644 index 000000000000..c45e67fea172 --- /dev/null +++ b/docs/source/release/v6.11.0/Framework/Algorithms/New_features/35067.rst @@ -0,0 +1,2 @@ +- A new ``SpinStates`` property has been added to :ref:`algm-PolarizationCorrectionWildes` and + :ref:`algm-PolarizationEfficiencyCor` to allow the order of the workspaces in the output Workspace Group to be set. \ No newline at end of file