From b31b9eb599a750bb70a04401cc1574dc813bee22 Mon Sep 17 00:00:00 2001 From: James Clarke Date: Fri, 15 Mar 2024 11:32:24 +0000 Subject: [PATCH 01/14] Add algorithm, tests, and docs Calculate polarizer efficiency using a group workspace with 4 runs for the 4 spin combinations, plus the efficiency of the analyser cell, calculated previously. --- Framework/Algorithms/CMakeLists.txt | 3 + .../PolarizerEfficiency.h | 49 ++++ .../PolarizerEfficiency.cpp | 186 +++++++++++++++ .../PolarizerEfficiencyTest.h | 215 ++++++++++++++++++ .../algorithms/PolarizerEfficiency-v1.rst | 54 +++++ .../v6.10.0/SANS/New_features/36139.rst | 1 + 6 files changed, 508 insertions(+) create mode 100644 Framework/Algorithms/inc/MantidAlgorithms/PolarizationCorrections/PolarizerEfficiency.h create mode 100644 Framework/Algorithms/src/PolarizationCorrections/PolarizerEfficiency.cpp create mode 100644 Framework/Algorithms/test/PolarizationCorrections/PolarizerEfficiencyTest.h create mode 100644 docs/source/algorithms/PolarizerEfficiency-v1.rst create mode 100644 docs/source/release/v6.10.0/SANS/New_features/36139.rst diff --git a/Framework/Algorithms/CMakeLists.txt b/Framework/Algorithms/CMakeLists.txt index fca615eb15e4..07ddb68c1505 100644 --- a/Framework/Algorithms/CMakeLists.txt +++ b/Framework/Algorithms/CMakeLists.txt @@ -240,6 +240,7 @@ set(SRC_FILES src/PolarizationCorrections/HeliumAnalyserEfficiency.cpp src/PolarizationCorrections/PolarizationCorrectionsHelpers.cpp src/PolarizationCorrections/SpinStateValidator.cpp + src/PolarizationCorrections/PolarizerEfficiency.cpp src/PolarizationCorrectionFredrikze.cpp src/PolarizationCorrectionWildes.cpp src/PolarizationEfficiencyCor.cpp @@ -598,6 +599,7 @@ set(INC_FILES inc/MantidAlgorithms/PolarizationCorrections/PolarizationCorrectionsHelpers.h inc/MantidAlgorithms/PolarizationCorrections/SpinStateValidator.h inc/MantidAlgorithms/PolarizationCorrections/FlipperEfficiency.h + inc/MantidAlgorithms/PolarizationCorrections/PolarizerEfficiency.h inc/MantidAlgorithms/PolarizationCorrectionFredrikze.h inc/MantidAlgorithms/PolarizationCorrectionWildes.h inc/MantidAlgorithms/PolarizationEfficiencyCor.h @@ -949,6 +951,7 @@ set(TEST_FILES PolarizationCorrections/PolarizationCorrectionsHelpersTest.h PolarizationCorrections/SpinStateValidatorTest.h PolarizationCorrections/FlipperEfficiencyTest.h + PolarizationCorrections/PolarizerEfficiencyTest.h PolarizationCorrectionFredrikzeTest.h PolarizationCorrectionWildesTest.h PolarizationEfficiencyCorTest.h diff --git a/Framework/Algorithms/inc/MantidAlgorithms/PolarizationCorrections/PolarizerEfficiency.h b/Framework/Algorithms/inc/MantidAlgorithms/PolarizationCorrections/PolarizerEfficiency.h new file mode 100644 index 000000000000..2fe33b5e3fc8 --- /dev/null +++ b/Framework/Algorithms/inc/MantidAlgorithms/PolarizationCorrections/PolarizerEfficiency.h @@ -0,0 +1,49 @@ +// Mantid Repository : https://github.com/mantidproject/mantid +// +// Copyright © 2024 ISIS Rutherford Appleton Laboratory UKRI, +// NScD Oak Ridge National Laboratory, European Spallation Source, +// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS +// SPDX - License - Identifier: GPL - 3.0 + + +#pragma once + +#include "MantidAPI/Algorithm.h" +#include "MantidAPI/MatrixWorkspace.h" +#include "MantidAPI/WorkspaceGroup.h" +#include "MantidAlgorithms/DllConfig.h" +#include + +namespace Mantid { +namespace Algorithms { +using namespace API; + +class MANTID_ALGORITHMS_DLL PolarizerEfficiency final : public API::Algorithm { +public: + /// Algorithm's name for identification overriding a virtual method + const std::string name() const override { return "PolarizerEfficiency"; } + /// Summary of algorithms purpose + const std::string summary() const override { return "Calculates the efficiency of a polarizer."; } + /// Algorithm's version for identification overriding a virtual method + int version() const override { return 1; } + /// Algorithm's category for identification overriding a virtual method + const std::string category() const override { return "SANS\\PolarizationCorrections"; } + /// Check that input params are valid + std::map validateInputs() override; + +private: + // Implement abstract Algorithm methods + void init() override; + void exec() override; + bool processGroups() override; + void validateGroupInput(); + void calculatePolarizerEfficiency(); + MatrixWorkspace_sptr workspaceForSpinConfig(WorkspaceGroup_sptr group, + const std::vector &spinConfigOrder, + const std::string &spinConfig); + void scaleWorkspace(MatrixWorkspace_sptr ws, const double factor) { runScaleAlgorithm(ws, factor, true); } + void addOffsetToWorkspace(MatrixWorkspace_sptr ws, const double offset) { runScaleAlgorithm(ws, offset, false); } + void runScaleAlgorithm(MatrixWorkspace_sptr ws, const double factor, const bool isMultiply); +}; + +} // namespace Algorithms +} // namespace Mantid \ No newline at end of file diff --git a/Framework/Algorithms/src/PolarizationCorrections/PolarizerEfficiency.cpp b/Framework/Algorithms/src/PolarizationCorrections/PolarizerEfficiency.cpp new file mode 100644 index 000000000000..2ff38ca9da07 --- /dev/null +++ b/Framework/Algorithms/src/PolarizationCorrections/PolarizerEfficiency.cpp @@ -0,0 +1,186 @@ +// Mantid Repository : https://github.com/mantidproject/mantid +// +// Copyright © 2024 ISIS Rutherford Appleton Laboratory UKRI, +// NScD Oak Ridge National Laboratory, European Spallation Source, +// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS +// SPDX - License - Identifier: GPL - 3.0 + + +#include "MantidAlgorithms/PolarizationCorrections/PolarizerEfficiency.h" +#include "MantidAPI/AnalysisDataService.h" +#include "MantidAPI/HistogramValidator.h" +#include "MantidAPI/ITableWorkspace.h" +#include "MantidAPI/MatrixWorkspace.h" +#include "MantidAPI/WorkspaceUnitValidator.h" +#include "MantidKernel/BoundedValidator.h" +#include "MantidKernel/CompositeValidator.h" +#include "MantidKernel/ListValidator.h" + +#include + +namespace Mantid::Algorithms { +// Register the algorithm into the algorithm factory +DECLARE_ALGORITHM(PolarizerEfficiency) + +using namespace Kernel; +using namespace API; + +namespace SpinConfigurations { +static const std::string UP_UP = "11"; +static const std::string UP_DOWN = "10"; +static const std::string DOWN_UP = "01"; +static const std::string DOWN_DOWN = "00"; +} // namespace SpinConfigurations + +namespace PropertyNames { +static const std::string INPUT_WORKSPACE = "InputWorkspace"; +static const std::string ANALYSER_EFFICIENCY = "AnalyserEfficiency"; +static const std::string SPIN_STATES = "SpinStates"; +static const std::string OUTPUT_WORKSPACE = "OutputWorkspace"; +} // namespace PropertyNames + +void PolarizerEfficiency::init() { + // Declare required input parameters for algorithm and do some validation here + auto validator = std::make_shared(); + validator->add("Wavelength"); + validator->add(); + declareProperty( + std::make_unique>(PropertyNames::INPUT_WORKSPACE, "", Direction::Input, validator), + "Input group workspace to use for polarization calculation"); + declareProperty(std::make_unique>(PropertyNames::ANALYSER_EFFICIENCY, "", + Direction::Input, validator), + "Analyser efficiency as a function of wavelength"); + declareProperty( + std::make_unique>(PropertyNames::OUTPUT_WORKSPACE, "", Direction::Output), + "Polarizer efficiency as a function of wavelength"); + + std::vector initialSpinConfig{{SpinConfigurations::UP_UP, SpinConfigurations::UP_DOWN, + SpinConfigurations::DOWN_UP, SpinConfigurations::DOWN_DOWN}}; + std::sort(initialSpinConfig.begin(), initialSpinConfig.end()); + std::vector allowedSpinConfigs; + allowedSpinConfigs.push_back(boost::algorithm::join(initialSpinConfig, ",")); + while (std::next_permutation(initialSpinConfig.begin(), initialSpinConfig.end())) { + allowedSpinConfigs.push_back(boost::algorithm::join(initialSpinConfig, ",")); + } + // "Order of individual spin states in the input group workspace, e.g. \"01,11,00,10\"" + declareProperty( + PropertyNames::SPIN_STATES, + boost::algorithm::join(std::vector{{SpinConfigurations::UP_UP, SpinConfigurations::DOWN_UP, + SpinConfigurations::DOWN_DOWN, SpinConfigurations::UP_DOWN}}, + ","), + std::make_shared>(allowedSpinConfigs)); +} + +/** + * Tests that the inputs are all valid + * @return A map containing the incorrect workspace + * properties and an error message + */ +std::map PolarizerEfficiency::validateInputs() { + std::map errorList; + const std::string inputWorkspaceName = getProperty(PropertyNames::INPUT_WORKSPACE); + if (!AnalysisDataService::Instance().doesExist(inputWorkspaceName)) { + errorList[PropertyNames::INPUT_WORKSPACE] = "The workspace " + inputWorkspaceName + " does not exist in the ADS."; + return errorList; + } + + const auto ws = AnalysisDataService::Instance().retrieve(inputWorkspaceName); + if (!ws->isGroup()) { + errorList[PropertyNames::INPUT_WORKSPACE] = "The input workspace is not a group workspace."; + } else { + const auto wsGroup = std::dynamic_pointer_cast(ws); + if (wsGroup->size() != 4) { + errorList[PropertyNames::INPUT_WORKSPACE] = + "The input group workspace must have four periods corresponding to the four spin configurations."; + } + } + + return errorList; +} + +/** + * Explicitly calls validateInputs and throws runtime error in case + * of issues in the input properties. + */ +void PolarizerEfficiency::validateGroupInput() { + const auto results = validateInputs(); + for (const auto &result : results) { + throw std::runtime_error("Issue in " + result.first + " property: " + result.second); + } +} + +bool PolarizerEfficiency::processGroups() { + validateGroupInput(); + calculatePolarizerEfficiency(); + return true; +} + +void PolarizerEfficiency::exec() { calculatePolarizerEfficiency(); } + +void PolarizerEfficiency::calculatePolarizerEfficiency() { + // First we extract the individual workspaces corresponding to each spin configuration from the group workspace + const auto groupWorkspace = + AnalysisDataService::Instance().retrieveWS(getProperty(PropertyNames::INPUT_WORKSPACE)); + std::string spinConfigurationInput = getProperty(PropertyNames::SPIN_STATES); + std::vector spinConfigurations; + boost::split(spinConfigurations, spinConfigurationInput, boost::is_any_of(",")); + + const auto t01Ws = workspaceForSpinConfig(groupWorkspace, spinConfigurations, SpinConfigurations::DOWN_UP); + const auto t00Ws = workspaceForSpinConfig(groupWorkspace, spinConfigurations, SpinConfigurations::DOWN_DOWN); + + const MatrixWorkspace_sptr effCell = + AnalysisDataService::Instance().retrieveWS(getProperty(PropertyNames::ANALYSER_EFFICIENCY)); + + // The efficiency is given by 0.5 + (T_00 - T_01) / (8 * e_cell - 4) + + auto minus = createChildAlgorithm("Minus"); + minus->initialize(); + minus->setProperty("LHSWorkspace", t00Ws); + minus->setProperty("RHSWorkspace", t01Ws); + minus->setProperty("OutputWorkspace", "numerator"); + minus->execute(); + MatrixWorkspace_sptr numerator = minus->getProperty("OutputWorkspace"); + + // To divide workspaces they need to have matching bins + auto rebinToWorkspace = createChildAlgorithm("RebinToWorkspace"); + rebinToWorkspace->initialize(); + rebinToWorkspace->setProperty("WorkspaceToRebin", effCell); + rebinToWorkspace->setProperty("WorkspaceToMatch", numerator); + rebinToWorkspace->setProperty("OutputWorkspace", "effCellRebinned"); + rebinToWorkspace->execute(); + MatrixWorkspace_sptr denominator = rebinToWorkspace->getProperty("OutputWorkspace"); + + scaleWorkspace(denominator, 8); + addOffsetToWorkspace(denominator, -4); + + auto divide = createChildAlgorithm("Divide"); + divide->initialize(); + divide->setProperty("LHSWorkspace", numerator); + divide->setProperty("RHSWorkspace", denominator); + divide->setProperty("OutputWorkspace", "effPolarizer"); + divide->execute(); + MatrixWorkspace_sptr effPolarizer = divide->getProperty("OutputWorkspace"); + + addOffsetToWorkspace(effPolarizer, 0.5); + + setProperty(PropertyNames::OUTPUT_WORKSPACE, effPolarizer); +} + +void PolarizerEfficiency::runScaleAlgorithm(MatrixWorkspace_sptr ws, const double factor, const bool isMultiply) { + auto scale = createChildAlgorithm("Scale"); + scale->initialize(); + scale->setProperty("InputWorkspace", ws); + scale->setProperty("OutputWorkspace", ws); + scale->setProperty("Factor", factor); + const std::string operation = isMultiply ? "Multiply" : "Add"; + scale->setProperty("Operation", operation); + scale->execute(); +} + +MatrixWorkspace_sptr PolarizerEfficiency::workspaceForSpinConfig(WorkspaceGroup_sptr group, + const std::vector &spinConfigOrder, + const std::string &spinConfig) { + const auto wsIndex = + std::find(spinConfigOrder.cbegin(), spinConfigOrder.cend(), spinConfig) - spinConfigOrder.cbegin(); + return std::dynamic_pointer_cast(group->getItem(wsIndex)); +} +} // namespace Mantid::Algorithms \ No newline at end of file diff --git a/Framework/Algorithms/test/PolarizationCorrections/PolarizerEfficiencyTest.h b/Framework/Algorithms/test/PolarizationCorrections/PolarizerEfficiencyTest.h new file mode 100644 index 000000000000..c7d9c8c6788d --- /dev/null +++ b/Framework/Algorithms/test/PolarizationCorrections/PolarizerEfficiencyTest.h @@ -0,0 +1,215 @@ +// Mantid Repository : https://github.com/mantidproject/mantid +// +// Copyright © 2024 ISIS Rutherford Appleton Laboratory UKRI, +// NScD Oak Ridge National Laboratory, European Spallation Source, +// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS +// SPDX - License - Identifier: GPL - 3.0 + + +#pragma once + +#include "MantidAPI/AlgorithmManager.h" +#include "MantidAPI/AnalysisDataService.h" +#include "MantidAlgorithms/PolarizationCorrections/PolarizerEfficiency.h" + +#include + +using namespace Mantid; +using namespace Mantid::Algorithms; +using namespace Mantid::API; + +class PolarizerEfficiencyTest : public CxxTest::TestSuite { +public: + void setUp() override { + // Use an analyser efficiency of 1 to make test calculations simpler + generateFunctionDefinedWorkspace(ANALYSER_EFFICIENCY_WS_NAME, "1 + x*0"); + } + + void tearDown() override { AnalysisDataService::Instance().clear(); } + + void testName() { + PolarizerEfficiency alg; + TS_ASSERT_EQUALS(alg.name(), "PolarizerEfficiency"); + } + + void testInit() { + PolarizerEfficiency alg; + alg.initialize(); + TS_ASSERT(alg.isInitialized()); + } + + void testNonGroupWorkspaceInput() { + // Should accept a group workspace containing four workspaces, corresponding to the four spin configurations + std::vector x{1, 2, 3, 4, 5}; + std::vector y{1, 4, 9, 16, 25}; + + MatrixWorkspace_sptr ws1 = generateWorkspace("ws1", x, y); + + auto polariserEfficiency = AlgorithmManager::Instance().create("PolarizerEfficiency"); + polariserEfficiency->initialize(); + polariserEfficiency->setProperty("InputWorkspace", ws1->getName()); + TS_ASSERT_THROWS(polariserEfficiency->execute(), const std::runtime_error &); + } + + void testGroupWorkspaceWithWrongSize() { + // Should accept a group workspace containing four workspaces, corresponding to the four spin configurations + std::vector x{1, 2, 3, 4, 5}; + std::vector y{1, 4, 9, 16, 25}; + + MatrixWorkspace_sptr ws1 = generateWorkspace("ws1", x, y); + MatrixWorkspace_sptr ws2 = generateWorkspace("ws2", x, y); + WorkspaceGroup_sptr groupWs = groupWorkspaces("grp", std::vector{ws1, ws2}); + auto polariserEfficiency = createPolarizerEfficiencyAlgorithm(groupWs); + TS_ASSERT_THROWS(polariserEfficiency->execute(), const std::runtime_error &); + } + + void testOutput() { + auto polariserEfficiency = createPolarizerEfficiencyAlgorithm(); + polariserEfficiency->execute(); + + const auto workspaces = AnalysisDataService::Instance().getObjectNames(); + ASSERT_TRUE(std::find(workspaces.cbegin(), workspaces.cend(), "psm") != workspaces.cend()); + } + + void testSpinConfigurations() { + auto polariserEfficiency = AlgorithmManager::Instance().create("PolarizerEfficiency"); + TS_ASSERT_THROWS(polariserEfficiency->setProperty("SpinStates", "bad"), std::invalid_argument &); + TS_ASSERT_THROWS(polariserEfficiency->setProperty("SpinStates", "10,01"), std::invalid_argument &); + TS_ASSERT_THROWS(polariserEfficiency->setProperty("SpinStates", "00,00,11,11"), std::invalid_argument &); + TS_ASSERT_THROWS(polariserEfficiency->setProperty("SpinStates", "02,20,22,00"), std::invalid_argument &); + } + + void testNonWavelengthInput() { + // The units of the input workspace should be wavelength + auto wsGrp = createExampleGroupWorkspace("wsGrp", "TOF"); + auto polariserEfficiency = AlgorithmManager::Instance().create("PolarizerEfficiency"); + polariserEfficiency->initialize(); + TS_ASSERT_THROWS(polariserEfficiency->setProperty("InputWorkspace", wsGrp->getName()), std::invalid_argument &); + } + + void testExampleCalculation() { + auto tPara = generateFunctionDefinedWorkspace("T_para", "4 + x*0"); + auto tPara1 = generateFunctionDefinedWorkspace("T_para1", "4 + x*0"); + auto tAnti = generateFunctionDefinedWorkspace("T_anti", "2 + x*0"); + auto tAnti1 = generateFunctionDefinedWorkspace("T_anti1", "2 * x*0"); + + auto grpWs = groupWorkspaces("grpWs", {tPara, tAnti, tPara1, tAnti1}); + + auto polariserEfficiency = createPolarizerEfficiencyAlgorithm(grpWs); + polariserEfficiency->execute(); + MatrixWorkspace_sptr calculatedPolariserEfficiency = AnalysisDataService::Instance().retrieveWS( + polariserEfficiency->getProperty("OutputWorkspace")); + + // The T_para and T_anti curves are 4 and 2 (constant wrt wavelength) respectively, and the analyser + // efficiency is 1 for all wavelengths, which should give us a polarizer efficiency of 1 + for (const double &y : calculatedPolariserEfficiency->dataY(0)) { + TS_ASSERT_DELTA(1, y, 1e-8); + } + } + + void testErrors() { + auto polarizerEfficiency = createPolarizerEfficiencyAlgorithm(); + polarizerEfficiency->execute(); + MatrixWorkspace_sptr eff = AnalysisDataService::Instance().retrieveWS( + polarizerEfficiency->getProperty("OutputWorkspace")); + const auto errors = eff->dataE(0); + // Skip the first error because with this toy data it'll be NaN + for (size_t i = 1; i < errors.size(); ++i) { + TS_ASSERT_DELTA(353.55339059327378, errors[i], 1e-8); + } + } + +private: + const std::string ANALYSER_EFFICIENCY_WS_NAME = "effAnalyser"; + + WorkspaceGroup_sptr createExampleGroupWorkspace(const std::string &name, const std::string &xUnit = "Wavelength", + const size_t numBins = 5) { + std::vector x(numBins); + std::vector y(numBins); + std::vector e(numBins); + for (size_t i = 0; i < numBins; ++i) { + x[i] = static_cast(i) + 1.0; + y[i] = x[i] * x[i]; + e[i] = 1000; + } + std::vector wsVec(4); + for (size_t i = 0; i < 4; ++i) { + wsVec[i] = generateWorkspace("ws" + std::to_string(i), x, y, e, xUnit); + } + return groupWorkspaces(name, wsVec); + } + + MatrixWorkspace_sptr generateWorkspace(const std::string &name, const std::vector &x, + const std::vector &y, const std::string &xUnit = "Wavelength") { + auto e = std::vector(x.size()); + for (size_t i = 0; i < e.size(); ++i) { + e[i] = 0; + } + return generateWorkspace(name, x, y, e, xUnit); + } + + MatrixWorkspace_sptr generateWorkspace(const std::string &name, const std::vector &x, + const std::vector &y, const std::vector &e, + const std::string &xUnit = "Wavelength") { + auto createWorkspace = AlgorithmManager::Instance().create("CreateWorkspace"); + createWorkspace->initialize(); + createWorkspace->setProperty("DataX", x); + createWorkspace->setProperty("DataY", y); + createWorkspace->setProperty("DataE", e); + createWorkspace->setProperty("UnitX", xUnit); + createWorkspace->setProperty("OutputWorkspace", name); + createWorkspace->execute(); + + auto convertToHistogram = AlgorithmManager::Instance().create("ConvertToHistogram"); + convertToHistogram->initialize(); + convertToHistogram->setProperty("InputWorkspace", name); + convertToHistogram->setProperty("OutputWorkspace", name); + convertToHistogram->execute(); + + MatrixWorkspace_sptr ws = AnalysisDataService::Instance().retrieveWS(name); + return ws; + } + + WorkspaceGroup_sptr groupWorkspaces(const std::string &name, const std::vector &wsToGroup) { + auto groupWorkspace = AlgorithmManager::Instance().create("GroupWorkspaces"); + groupWorkspace->initialize(); + std::vector wsToGroupNames(wsToGroup.size()); + std::transform(wsToGroup.cbegin(), wsToGroup.cend(), wsToGroupNames.begin(), + [](MatrixWorkspace_sptr w) { return w->getName(); }); + groupWorkspace->setProperty("InputWorkspaces", wsToGroupNames); + groupWorkspace->setProperty("OutputWorkspace", name); + groupWorkspace->execute(); + WorkspaceGroup_sptr group = AnalysisDataService::Instance().retrieveWS(name); + return group; + } + + MatrixWorkspace_sptr generateFunctionDefinedWorkspace(const std::string &name, const std::string &func) { + auto createSampleWorkspace = AlgorithmManager::Instance().create("CreateSampleWorkspace"); + createSampleWorkspace->initialize(); + createSampleWorkspace->setProperty("WorkspaceType", "Histogram"); + createSampleWorkspace->setProperty("OutputWorkspace", name); + createSampleWorkspace->setProperty("Function", "User Defined"); + createSampleWorkspace->setProperty("UserDefinedFunction", "name=UserFunction,Formula=" + func); + createSampleWorkspace->setProperty("XUnit", "Wavelength"); + createSampleWorkspace->setProperty("XMin", "1"); + createSampleWorkspace->setProperty("XMax", "8"); + createSampleWorkspace->setProperty("BinWidth", "1"); + createSampleWorkspace->setProperty("NumBanks", 1); + createSampleWorkspace->setProperty("BankPixelWidth", 1); + createSampleWorkspace->execute(); + + MatrixWorkspace_sptr result = AnalysisDataService::Instance().retrieveWS(name); + return result; + } + + IAlgorithm_sptr createPolarizerEfficiencyAlgorithm(WorkspaceGroup_sptr inputGrp = nullptr) { + if (inputGrp == nullptr) { + inputGrp = createExampleGroupWorkspace("wsGrp"); + } + auto polarizerEfficiency = AlgorithmManager::Instance().create("PolarizerEfficiency"); + polarizerEfficiency->initialize(); + polarizerEfficiency->setProperty("InputWorkspace", inputGrp->getName()); + polarizerEfficiency->setProperty("AnalyserEfficiency", ANALYSER_EFFICIENCY_WS_NAME); + polarizerEfficiency->setProperty("OutputWorkspace", "psm"); + return polarizerEfficiency; + } +}; \ No newline at end of file diff --git a/docs/source/algorithms/PolarizerEfficiency-v1.rst b/docs/source/algorithms/PolarizerEfficiency-v1.rst new file mode 100644 index 000000000000..d6ae36fb77b3 --- /dev/null +++ b/docs/source/algorithms/PolarizerEfficiency-v1.rst @@ -0,0 +1,54 @@ + +.. algorithm:: + +.. summary:: + +.. relatedalgorithms:: + +.. properties:: + +Description +----------- + +Calculates how the efficiency of a polarizer varies with wavelength. The +ordering of the workspaces in ``InputWorkspace`` is taken from the ``SpinStates`` parameter, and the analyser +efficiency, :math:`\epsilon_{cell}`, is given by ``AnalyserEfficiency``. + +The polarization of the polarizer, :math:`P_{SM}`, is given by + +.. math:: + P_{SM} = \frac{T_{00} - T_{01}}{2P_{cell}} + +Since the efficiency, :math:`\epsilon_{SM}`, is given by :math:`\frac{1 + P_{SM}}{2}`, we have that + +.. math:: + \epsilon_{SM} = \frac{1}{2} + \frac{T_{00} - T_{01}}{8\epsilon_{cell} - 4} + +Usage +----- + +**Example - Calculate Polarizer Efficiency** + +.. testcode:: PolarizerEfficiencyExample + + wsPara = CreateSampleWorkspace('Histogram', Function='User Defined', UserDefinedFunction='name=UserFunction,Formula=0.5*exp(-0.0733*12*x*(1-0.9))',XUnit='Wavelength', xMin='1',XMax='8', BinWidth='1') + wsPara1 = CloneWorkspace(wsPara) + wsAnti = CreateSampleWorkspace('Histogram', Function='User Defined', UserDefinedFunction='name=UserFunction,Formula=0.5*exp(-0.0733*12*x*(1+0.9))',XUnit='Wavelength', xMin='1',XMax='8', BinWidth='1') + wsAnti1 = CloneWorkspace(wsAnti) + + grp = GroupWorkspaces([wsPara,wsAnti,wsPara1,wsAnti1]) + eCell = CreateSampleWorkspace('Histogram', Function='User Defined', UserDefinedFunction='name=UserFunction,Formula=(1 + tanh(0.0733 * 12 * x * 0.2))/2',XUnit='Wavelength', xMin='1',XMax='16', BinWidth='1') + + psm = PolarizerEfficiency(grp, eCell) + print("Polarizer efficiency at a wavelength of " + str(mtd['psm'].dataX(0)[3]) + " Å is " + str(mtd['psm'].dataY(0)[3])) + +Output: + +.. testoutput:: PolarizerEfficiencyExample + :options: +ELLIPSIS +NORMALIZE_WHITESPACE + + Polarizer efficiency at a wavelength of 4.5 Å is ... + +.. categories:: + +.. sourcelink:: diff --git a/docs/source/release/v6.10.0/SANS/New_features/36139.rst b/docs/source/release/v6.10.0/SANS/New_features/36139.rst new file mode 100644 index 000000000000..2655a9eda9c4 --- /dev/null +++ b/docs/source/release/v6.10.0/SANS/New_features/36139.rst @@ -0,0 +1 @@ +- Added algorithm for calculating the efficiency of a polariser. \ No newline at end of file From 36fa2b75fe4bc79f1539d64bc3fc382073e17a57 Mon Sep 17 00:00:00 2001 From: James Clarke Date: Thu, 18 Apr 2024 08:31:02 +0100 Subject: [PATCH 02/14] Fix doc test --- docs/source/algorithms/PolarizerEfficiency-v1.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/algorithms/PolarizerEfficiency-v1.rst b/docs/source/algorithms/PolarizerEfficiency-v1.rst index d6ae36fb77b3..f1ddec0b08c2 100644 --- a/docs/source/algorithms/PolarizerEfficiency-v1.rst +++ b/docs/source/algorithms/PolarizerEfficiency-v1.rst @@ -47,7 +47,7 @@ Output: .. testoutput:: PolarizerEfficiencyExample :options: +ELLIPSIS +NORMALIZE_WHITESPACE - Polarizer efficiency at a wavelength of 4.5 Å is ... + Polarizer efficiency at a wavelength of 4.0 Å is ... .. categories:: From 8d8bc85478ff39e4721a8df345731007f47758a2 Mon Sep 17 00:00:00 2001 From: James Clarke Date: Wed, 24 Apr 2024 17:09:00 +0100 Subject: [PATCH 03/14] Update to use new formula for efficiency --- .../PolarizerEfficiency.h | 27 +++- .../PolarizerEfficiency.cpp | 139 +++++++++--------- .../PolarizerEfficiencyTest.h | 17 ++- .../algorithms/PolarizerEfficiency-v1.rst | 8 +- 4 files changed, 103 insertions(+), 88 deletions(-) diff --git a/Framework/Algorithms/inc/MantidAlgorithms/PolarizationCorrections/PolarizerEfficiency.h b/Framework/Algorithms/inc/MantidAlgorithms/PolarizationCorrections/PolarizerEfficiency.h index 2fe33b5e3fc8..8f87c4b2e1fb 100644 --- a/Framework/Algorithms/inc/MantidAlgorithms/PolarizationCorrections/PolarizerEfficiency.h +++ b/Framework/Algorithms/inc/MantidAlgorithms/PolarizationCorrections/PolarizerEfficiency.h @@ -12,6 +12,7 @@ #include "MantidAPI/WorkspaceGroup.h" #include "MantidAlgorithms/DllConfig.h" #include +#include namespace Mantid { namespace Algorithms { @@ -37,12 +38,26 @@ class MANTID_ALGORITHMS_DLL PolarizerEfficiency final : public API::Algorithm { bool processGroups() override; void validateGroupInput(); void calculatePolarizerEfficiency(); - MatrixWorkspace_sptr workspaceForSpinConfig(WorkspaceGroup_sptr group, - const std::vector &spinConfigOrder, - const std::string &spinConfig); - void scaleWorkspace(MatrixWorkspace_sptr ws, const double factor) { runScaleAlgorithm(ws, factor, true); } - void addOffsetToWorkspace(MatrixWorkspace_sptr ws, const double offset) { runScaleAlgorithm(ws, offset, false); } - void runScaleAlgorithm(MatrixWorkspace_sptr ws, const double factor, const bool isMultiply); + void scaleWorkspace(MatrixWorkspace_sptr ws, const double factor); + MatrixWorkspace_sptr addTwoWorkspaces(MatrixWorkspace_sptr a, MatrixWorkspace_sptr b, + MatrixWorkspace_sptr output = nullptr) { + return runMathsAlgorithm("Plus", a, b, output); + } + MatrixWorkspace_sptr subtractTwoWorkspaces(MatrixWorkspace_sptr lhs, MatrixWorkspace_sptr rhs, + MatrixWorkspace_sptr output = nullptr) { + return runMathsAlgorithm("Minus", lhs, rhs, output); + } + MatrixWorkspace_sptr multiplyWorkspaces(MatrixWorkspace_sptr a, MatrixWorkspace_sptr b, + MatrixWorkspace_sptr output = nullptr) { + return runMathsAlgorithm("Multiply", a, b, output); + } + MatrixWorkspace_sptr divideWorkspaces(MatrixWorkspace_sptr numerator, MatrixWorkspace_sptr denominator, + MatrixWorkspace_sptr output = nullptr) { + return runMathsAlgorithm("Divide", numerator, denominator, output); + } + MatrixWorkspace_sptr runMathsAlgorithm(std::string algName, MatrixWorkspace_sptr lhs, MatrixWorkspace_sptr rhs, + MatrixWorkspace_sptr output); + MatrixWorkspace_sptr convertToHistIfNecessary(const MatrixWorkspace_sptr ws); }; } // namespace Algorithms diff --git a/Framework/Algorithms/src/PolarizationCorrections/PolarizerEfficiency.cpp b/Framework/Algorithms/src/PolarizationCorrections/PolarizerEfficiency.cpp index 2ff38ca9da07..e9782712a10b 100644 --- a/Framework/Algorithms/src/PolarizationCorrections/PolarizerEfficiency.cpp +++ b/Framework/Algorithms/src/PolarizationCorrections/PolarizerEfficiency.cpp @@ -11,6 +11,8 @@ #include "MantidAPI/ITableWorkspace.h" #include "MantidAPI/MatrixWorkspace.h" #include "MantidAPI/WorkspaceUnitValidator.h" +#include "MantidAlgorithms/PolarizationCorrections/PolarizationCorrectionsHelpers.h" +#include "MantidAlgorithms/PolarizationCorrections/SpinStateValidator.h" #include "MantidKernel/BoundedValidator.h" #include "MantidKernel/CompositeValidator.h" #include "MantidKernel/ListValidator.h" @@ -24,13 +26,6 @@ DECLARE_ALGORITHM(PolarizerEfficiency) using namespace Kernel; using namespace API; -namespace SpinConfigurations { -static const std::string UP_UP = "11"; -static const std::string UP_DOWN = "10"; -static const std::string DOWN_UP = "01"; -static const std::string DOWN_DOWN = "00"; -} // namespace SpinConfigurations - namespace PropertyNames { static const std::string INPUT_WORKSPACE = "InputWorkspace"; static const std::string ANALYSER_EFFICIENCY = "AnalyserEfficiency"; @@ -46,28 +41,18 @@ void PolarizerEfficiency::init() { declareProperty( std::make_unique>(PropertyNames::INPUT_WORKSPACE, "", Direction::Input, validator), "Input group workspace to use for polarization calculation"); + auto wavelengthValidator = std::make_shared("Wavelength"); declareProperty(std::make_unique>(PropertyNames::ANALYSER_EFFICIENCY, "", - Direction::Input, validator), + Direction::Input, wavelengthValidator), "Analyser efficiency as a function of wavelength"); declareProperty( std::make_unique>(PropertyNames::OUTPUT_WORKSPACE, "", Direction::Output), "Polarizer efficiency as a function of wavelength"); - std::vector initialSpinConfig{{SpinConfigurations::UP_UP, SpinConfigurations::UP_DOWN, - SpinConfigurations::DOWN_UP, SpinConfigurations::DOWN_DOWN}}; - std::sort(initialSpinConfig.begin(), initialSpinConfig.end()); - std::vector allowedSpinConfigs; - allowedSpinConfigs.push_back(boost::algorithm::join(initialSpinConfig, ",")); - while (std::next_permutation(initialSpinConfig.begin(), initialSpinConfig.end())) { - allowedSpinConfigs.push_back(boost::algorithm::join(initialSpinConfig, ",")); - } - // "Order of individual spin states in the input group workspace, e.g. \"01,11,00,10\"" - declareProperty( - PropertyNames::SPIN_STATES, - boost::algorithm::join(std::vector{{SpinConfigurations::UP_UP, SpinConfigurations::DOWN_UP, - SpinConfigurations::DOWN_DOWN, SpinConfigurations::UP_DOWN}}, - ","), - std::make_shared>(allowedSpinConfigs)); + auto spinValidator = std::make_shared(std::unordered_set{4}); + std::string initialSpinConfig = "11,10,01,00"; + declareProperty(PropertyNames::SPIN_STATES, initialSpinConfig, spinValidator, + "Order of individual spin states in the input group workspace, e.g. \"01,11,00,10\""); } /** @@ -121,66 +106,76 @@ void PolarizerEfficiency::calculatePolarizerEfficiency() { const auto groupWorkspace = AnalysisDataService::Instance().retrieveWS(getProperty(PropertyNames::INPUT_WORKSPACE)); std::string spinConfigurationInput = getProperty(PropertyNames::SPIN_STATES); - std::vector spinConfigurations; - boost::split(spinConfigurations, spinConfigurationInput, boost::is_any_of(",")); - - const auto t01Ws = workspaceForSpinConfig(groupWorkspace, spinConfigurations, SpinConfigurations::DOWN_UP); - const auto t00Ws = workspaceForSpinConfig(groupWorkspace, spinConfigurations, SpinConfigurations::DOWN_DOWN); - - const MatrixWorkspace_sptr effCell = - AnalysisDataService::Instance().retrieveWS(getProperty(PropertyNames::ANALYSER_EFFICIENCY)); - - // The efficiency is given by 0.5 + (T_00 - T_01) / (8 * e_cell - 4) - - auto minus = createChildAlgorithm("Minus"); - minus->initialize(); - minus->setProperty("LHSWorkspace", t00Ws); - minus->setProperty("RHSWorkspace", t01Ws); - minus->setProperty("OutputWorkspace", "numerator"); - minus->execute(); - MatrixWorkspace_sptr numerator = minus->getProperty("OutputWorkspace"); - - // To divide workspaces they need to have matching bins - auto rebinToWorkspace = createChildAlgorithm("RebinToWorkspace"); - rebinToWorkspace->initialize(); - rebinToWorkspace->setProperty("WorkspaceToRebin", effCell); - rebinToWorkspace->setProperty("WorkspaceToMatch", numerator); - rebinToWorkspace->setProperty("OutputWorkspace", "effCellRebinned"); - rebinToWorkspace->execute(); - MatrixWorkspace_sptr denominator = rebinToWorkspace->getProperty("OutputWorkspace"); - - scaleWorkspace(denominator, 8); - addOffsetToWorkspace(denominator, -4); - - auto divide = createChildAlgorithm("Divide"); - divide->initialize(); - divide->setProperty("LHSWorkspace", numerator); - divide->setProperty("RHSWorkspace", denominator); - divide->setProperty("OutputWorkspace", "effPolarizer"); - divide->execute(); - MatrixWorkspace_sptr effPolarizer = divide->getProperty("OutputWorkspace"); - - addOffsetToWorkspace(effPolarizer, 0.5); + const auto t01Ws = PolarizationCorrectionsHelpers::workspaceForSpinState(groupWorkspace, spinConfigurationInput, + SpinStateValidator::ZERO_ONE); + const auto t00Ws = PolarizationCorrectionsHelpers::workspaceForSpinState(groupWorkspace, spinConfigurationInput, + SpinStateValidator::ZERO_ZERO); + + auto effCell = convertToHistIfNecessary( + AnalysisDataService::Instance().retrieveWS(getProperty(PropertyNames::ANALYSER_EFFICIENCY))); + + auto rebin = createChildAlgorithm("RebinToWorkspace"); + rebin->initialize(); + rebin->setProperty("WorkspaceToRebin", effCell); + rebin->setProperty("WorkspaceToMatch", t00Ws); + rebin->setProperty("OutputWorkspace", "rebinToWorkspace"); + rebin->execute(); + effCell = rebin->getProperty("OutputWorkspace"); + + // The efficiency is given by (e_cell * (T00 + T01) - T01) / ((2 * e_cell - 1) * (T00 + T01)) + + auto sumT = addTwoWorkspaces(t00Ws, t01Ws); + auto eCellTimesSum = multiplyWorkspaces(effCell, sumT); + auto numerator = subtractTwoWorkspaces(eCellTimesSum, t01Ws); + scaleWorkspace(eCellTimesSum, 2); + auto denominator = subtractTwoWorkspaces(eCellTimesSum, sumT); + auto effPolarizer = divideWorkspaces(numerator, denominator); setProperty(PropertyNames::OUTPUT_WORKSPACE, effPolarizer); } -void PolarizerEfficiency::runScaleAlgorithm(MatrixWorkspace_sptr ws, const double factor, const bool isMultiply) { +void PolarizerEfficiency::scaleWorkspace(MatrixWorkspace_sptr ws, const double factor) { auto scale = createChildAlgorithm("Scale"); scale->initialize(); scale->setProperty("InputWorkspace", ws); scale->setProperty("OutputWorkspace", ws); scale->setProperty("Factor", factor); - const std::string operation = isMultiply ? "Multiply" : "Add"; - scale->setProperty("Operation", operation); + scale->setProperty("Operation", "Multiply"); scale->execute(); } -MatrixWorkspace_sptr PolarizerEfficiency::workspaceForSpinConfig(WorkspaceGroup_sptr group, - const std::vector &spinConfigOrder, - const std::string &spinConfig) { - const auto wsIndex = - std::find(spinConfigOrder.cbegin(), spinConfigOrder.cend(), spinConfig) - spinConfigOrder.cbegin(); - return std::dynamic_pointer_cast(group->getItem(wsIndex)); +MatrixWorkspace_sptr PolarizerEfficiency::runMathsAlgorithm(std::string algName, MatrixWorkspace_sptr lhs, + MatrixWorkspace_sptr rhs, + MatrixWorkspace_sptr output = nullptr) { + auto alg = createChildAlgorithm(algName); + alg->initialize(); + alg->setProperty("LHSWorkspace", lhs); + alg->setProperty("RHSWorkspace", rhs); + if (output) { + alg->setProperty("OutputWorkspace", output); + } else { + alg->setProperty("OutputWorkspace", "algOutput"); + } + alg->execute(); + return alg->getProperty("OutputWorkspace"); } + +MatrixWorkspace_sptr PolarizerEfficiency::convertToHistIfNecessary(const MatrixWorkspace_sptr ws) { + if (ws->isHistogramData() && ws->isDistribution()) + return ws; + + MatrixWorkspace_sptr wsClone = std::move(ws->clone()); + wsClone->setDistribution(true); + + if (wsClone->isHistogramData()) + return wsClone; + + auto convertToHistogram = createChildAlgorithm("ConvertToHistogram"); + convertToHistogram->initialize(); + convertToHistogram->setProperty("InputWorkspace", wsClone); + convertToHistogram->setProperty("OutputWorkspace", wsClone); + convertToHistogram->execute(); + return convertToHistogram->getProperty("OutputWorkspace"); +} + } // namespace Mantid::Algorithms \ No newline at end of file diff --git a/Framework/Algorithms/test/PolarizationCorrections/PolarizerEfficiencyTest.h b/Framework/Algorithms/test/PolarizationCorrections/PolarizerEfficiencyTest.h index c7d9c8c6788d..02beac0966b2 100644 --- a/Framework/Algorithms/test/PolarizationCorrections/PolarizerEfficiencyTest.h +++ b/Framework/Algorithms/test/PolarizationCorrections/PolarizerEfficiencyTest.h @@ -90,9 +90,9 @@ class PolarizerEfficiencyTest : public CxxTest::TestSuite { auto tPara = generateFunctionDefinedWorkspace("T_para", "4 + x*0"); auto tPara1 = generateFunctionDefinedWorkspace("T_para1", "4 + x*0"); auto tAnti = generateFunctionDefinedWorkspace("T_anti", "2 + x*0"); - auto tAnti1 = generateFunctionDefinedWorkspace("T_anti1", "2 * x*0"); + auto tAnti1 = generateFunctionDefinedWorkspace("T_anti1", "2 + x*0"); - auto grpWs = groupWorkspaces("grpWs", {tPara, tAnti, tPara1, tAnti1}); + auto grpWs = groupWorkspaces("grpWs", {tPara, tAnti, tAnti1, tPara1}); auto polariserEfficiency = createPolarizerEfficiencyAlgorithm(grpWs); polariserEfficiency->execute(); @@ -100,9 +100,9 @@ class PolarizerEfficiencyTest : public CxxTest::TestSuite { polariserEfficiency->getProperty("OutputWorkspace")); // The T_para and T_anti curves are 4 and 2 (constant wrt wavelength) respectively, and the analyser - // efficiency is 1 for all wavelengths, which should give us a polarizer efficiency of 1 + // efficiency is 1 for all wavelengths, which should give us a polarizer efficiency of 2/3 for (const double &y : calculatedPolariserEfficiency->dataY(0)) { - TS_ASSERT_DELTA(1, y, 1e-8); + TS_ASSERT_DELTA(2.0 / 3.0, y, 1e-8); } } @@ -113,8 +113,10 @@ class PolarizerEfficiencyTest : public CxxTest::TestSuite { polarizerEfficiency->getProperty("OutputWorkspace")); const auto errors = eff->dataE(0); // Skip the first error because with this toy data it'll be NaN - for (size_t i = 1; i < errors.size(); ++i) { - TS_ASSERT_DELTA(353.55339059327378, errors[i], 1e-8); + const std::vector expectedErrors{293.15439618057928, 130.29700166149377, 73.301389823113183, + 46.925472826600263}; + for (size_t i = 0; i < expectedErrors.size(); ++i) { + TS_ASSERT_DELTA(expectedErrors[i], errors[i + 1], 1e-7); } } @@ -157,6 +159,7 @@ class PolarizerEfficiencyTest : public CxxTest::TestSuite { createWorkspace->setProperty("DataE", e); createWorkspace->setProperty("UnitX", xUnit); createWorkspace->setProperty("OutputWorkspace", name); + createWorkspace->setProperty("Distribution", true); createWorkspace->execute(); auto convertToHistogram = AlgorithmManager::Instance().create("ConvertToHistogram"); @@ -198,6 +201,8 @@ class PolarizerEfficiencyTest : public CxxTest::TestSuite { createSampleWorkspace->execute(); MatrixWorkspace_sptr result = AnalysisDataService::Instance().retrieveWS(name); + result->setYUnit(""); + result->setDistribution(true); return result; } diff --git a/docs/source/algorithms/PolarizerEfficiency-v1.rst b/docs/source/algorithms/PolarizerEfficiency-v1.rst index f1ddec0b08c2..a8190cd45ff7 100644 --- a/docs/source/algorithms/PolarizerEfficiency-v1.rst +++ b/docs/source/algorithms/PolarizerEfficiency-v1.rst @@ -17,12 +17,12 @@ efficiency, :math:`\epsilon_{cell}`, is given by ``AnalyserEfficiency``. The polarization of the polarizer, :math:`P_{SM}`, is given by .. math:: - P_{SM} = \frac{T_{00} - T_{01}}{2P_{cell}} + P_{SM} = \frac{T_{00} - T_{01}}{P_{cell}(T_{00} + T_{01})} Since the efficiency, :math:`\epsilon_{SM}`, is given by :math:`\frac{1 + P_{SM}}{2}`, we have that .. math:: - \epsilon_{SM} = \frac{1}{2} + \frac{T_{00} - T_{01}}{8\epsilon_{cell} - 4} + \epsilon_{SM} = \frac{\epsilon_{cell}(T_{00} + T_{01}) - T_{01}}{(2\epsilon_{cell} - 1)(T_{00} + T_{01})} Usage ----- @@ -31,9 +31,9 @@ Usage .. testcode:: PolarizerEfficiencyExample - wsPara = CreateSampleWorkspace('Histogram', Function='User Defined', UserDefinedFunction='name=UserFunction,Formula=0.5*exp(-0.0733*12*x*(1-0.9))',XUnit='Wavelength', xMin='1',XMax='8', BinWidth='1') + wsPara = CreateSampleWorkspace('Histogram', Function='User Defined', UserDefinedFunction='name=UserFunction,Formula=0.5*exp(-0.0733*12*x*(1-0.1))',XUnit='Wavelength', xMin='1',XMax='8', BinWidth='1') wsPara1 = CloneWorkspace(wsPara) - wsAnti = CreateSampleWorkspace('Histogram', Function='User Defined', UserDefinedFunction='name=UserFunction,Formula=0.5*exp(-0.0733*12*x*(1+0.9))',XUnit='Wavelength', xMin='1',XMax='8', BinWidth='1') + wsAnti = CreateSampleWorkspace('Histogram', Function='User Defined', UserDefinedFunction='name=UserFunction,Formula=0.5*exp(-0.0733*12*x*(1+0.1))',XUnit='Wavelength', xMin='1',XMax='8', BinWidth='1') wsAnti1 = CloneWorkspace(wsAnti) grp = GroupWorkspaces([wsPara,wsAnti,wsPara1,wsAnti1]) From 65db887e3c68fb31d436bc40d719372e586dc8f1 Mon Sep 17 00:00:00 2001 From: James Clarke Date: Thu, 25 Apr 2024 15:12:19 +0100 Subject: [PATCH 04/14] Pre-emptive attack on Coverity --- .../PolarizationCorrections/PolarizerEfficiency.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Framework/Algorithms/src/PolarizationCorrections/PolarizerEfficiency.cpp b/Framework/Algorithms/src/PolarizationCorrections/PolarizerEfficiency.cpp index e9782712a10b..b30e8fbce77e 100644 --- a/Framework/Algorithms/src/PolarizationCorrections/PolarizerEfficiency.cpp +++ b/Framework/Algorithms/src/PolarizationCorrections/PolarizerEfficiency.cpp @@ -50,8 +50,7 @@ void PolarizerEfficiency::init() { "Polarizer efficiency as a function of wavelength"); auto spinValidator = std::make_shared(std::unordered_set{4}); - std::string initialSpinConfig = "11,10,01,00"; - declareProperty(PropertyNames::SPIN_STATES, initialSpinConfig, spinValidator, + 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\""); } @@ -88,8 +87,9 @@ std::map PolarizerEfficiency::validateInputs() { */ void PolarizerEfficiency::validateGroupInput() { const auto results = validateInputs(); - for (const auto &result : results) { - throw std::runtime_error("Issue in " + result.first + " property: " + result.second); + if (results.size() > 0) { + const auto result = results.cbegin(); + throw std::runtime_error("Issue in " + result->first + " property: " + result->second); } } @@ -130,7 +130,7 @@ void PolarizerEfficiency::calculatePolarizerEfficiency() { auto numerator = subtractTwoWorkspaces(eCellTimesSum, t01Ws); scaleWorkspace(eCellTimesSum, 2); auto denominator = subtractTwoWorkspaces(eCellTimesSum, sumT); - auto effPolarizer = divideWorkspaces(numerator, denominator); + auto effPolarizer = divideWorkspaces(std::move(numerator), std::move(denominator)); setProperty(PropertyNames::OUTPUT_WORKSPACE, effPolarizer); } From 909639d715083716c7c8b3f1432543cbc07e1614 Mon Sep 17 00:00:00 2001 From: James Clarke Date: Wed, 1 May 2024 14:14:03 +0100 Subject: [PATCH 05/14] Tidy up code Missing const in a few places, deleted unneeded methods and used the operator overloads instead. --- .../PolarizerEfficiency.h | 19 ----- .../PolarizerEfficiency.cpp | 72 ++++++------------- 2 files changed, 23 insertions(+), 68 deletions(-) diff --git a/Framework/Algorithms/inc/MantidAlgorithms/PolarizationCorrections/PolarizerEfficiency.h b/Framework/Algorithms/inc/MantidAlgorithms/PolarizationCorrections/PolarizerEfficiency.h index 8f87c4b2e1fb..9bd8d65e2f8b 100644 --- a/Framework/Algorithms/inc/MantidAlgorithms/PolarizationCorrections/PolarizerEfficiency.h +++ b/Framework/Algorithms/inc/MantidAlgorithms/PolarizationCorrections/PolarizerEfficiency.h @@ -38,25 +38,6 @@ class MANTID_ALGORITHMS_DLL PolarizerEfficiency final : public API::Algorithm { bool processGroups() override; void validateGroupInput(); void calculatePolarizerEfficiency(); - void scaleWorkspace(MatrixWorkspace_sptr ws, const double factor); - MatrixWorkspace_sptr addTwoWorkspaces(MatrixWorkspace_sptr a, MatrixWorkspace_sptr b, - MatrixWorkspace_sptr output = nullptr) { - return runMathsAlgorithm("Plus", a, b, output); - } - MatrixWorkspace_sptr subtractTwoWorkspaces(MatrixWorkspace_sptr lhs, MatrixWorkspace_sptr rhs, - MatrixWorkspace_sptr output = nullptr) { - return runMathsAlgorithm("Minus", lhs, rhs, output); - } - MatrixWorkspace_sptr multiplyWorkspaces(MatrixWorkspace_sptr a, MatrixWorkspace_sptr b, - MatrixWorkspace_sptr output = nullptr) { - return runMathsAlgorithm("Multiply", a, b, output); - } - MatrixWorkspace_sptr divideWorkspaces(MatrixWorkspace_sptr numerator, MatrixWorkspace_sptr denominator, - MatrixWorkspace_sptr output = nullptr) { - return runMathsAlgorithm("Divide", numerator, denominator, output); - } - MatrixWorkspace_sptr runMathsAlgorithm(std::string algName, MatrixWorkspace_sptr lhs, MatrixWorkspace_sptr rhs, - MatrixWorkspace_sptr output); MatrixWorkspace_sptr convertToHistIfNecessary(const MatrixWorkspace_sptr ws); }; diff --git a/Framework/Algorithms/src/PolarizationCorrections/PolarizerEfficiency.cpp b/Framework/Algorithms/src/PolarizationCorrections/PolarizerEfficiency.cpp index b30e8fbce77e..5742bc0e269f 100644 --- a/Framework/Algorithms/src/PolarizationCorrections/PolarizerEfficiency.cpp +++ b/Framework/Algorithms/src/PolarizationCorrections/PolarizerEfficiency.cpp @@ -35,13 +35,13 @@ static const std::string OUTPUT_WORKSPACE = "OutputWorkspace"; void PolarizerEfficiency::init() { // Declare required input parameters for algorithm and do some validation here - auto validator = std::make_shared(); + auto &validator = std::make_shared(); validator->add("Wavelength"); validator->add(); declareProperty( std::make_unique>(PropertyNames::INPUT_WORKSPACE, "", Direction::Input, validator), "Input group workspace to use for polarization calculation"); - auto wavelengthValidator = std::make_shared("Wavelength"); + const auto &wavelengthValidator = std::make_shared("Wavelength"); declareProperty(std::make_unique>(PropertyNames::ANALYSER_EFFICIENCY, "", Direction::Input, wavelengthValidator), "Analyser efficiency as a function of wavelength"); @@ -49,7 +49,7 @@ void PolarizerEfficiency::init() { std::make_unique>(PropertyNames::OUTPUT_WORKSPACE, "", Direction::Output), "Polarizer efficiency as a function of wavelength"); - auto spinValidator = std::make_shared(std::unordered_set{4}); + const 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\""); } @@ -67,11 +67,11 @@ std::map PolarizerEfficiency::validateInputs() { return errorList; } - const auto ws = AnalysisDataService::Instance().retrieve(inputWorkspaceName); + const auto &ws = AnalysisDataService::Instance().retrieve(inputWorkspaceName); if (!ws->isGroup()) { errorList[PropertyNames::INPUT_WORKSPACE] = "The input workspace is not a group workspace."; } else { - const auto wsGroup = std::dynamic_pointer_cast(ws); + const auto &wsGroup = std::dynamic_pointer_cast(ws); if (wsGroup->size() != 4) { errorList[PropertyNames::INPUT_WORKSPACE] = "The input group workspace must have four periods corresponding to the four spin configurations."; @@ -86,9 +86,9 @@ std::map PolarizerEfficiency::validateInputs() { * of issues in the input properties. */ void PolarizerEfficiency::validateGroupInput() { - const auto results = validateInputs(); + const auto &results = validateInputs(); if (results.size() > 0) { - const auto result = results.cbegin(); + const auto &result = results.cbegin(); throw std::runtime_error("Issue in " + result->first + " property: " + result->second); } } @@ -103,19 +103,19 @@ void PolarizerEfficiency::exec() { calculatePolarizerEfficiency(); } void PolarizerEfficiency::calculatePolarizerEfficiency() { // First we extract the individual workspaces corresponding to each spin configuration from the group workspace - const auto groupWorkspace = + const auto &groupWorkspace = AnalysisDataService::Instance().retrieveWS(getProperty(PropertyNames::INPUT_WORKSPACE)); - std::string spinConfigurationInput = getProperty(PropertyNames::SPIN_STATES); + const std::string spinConfigurationInput = getProperty(PropertyNames::SPIN_STATES); - const auto t01Ws = PolarizationCorrectionsHelpers::workspaceForSpinState(groupWorkspace, spinConfigurationInput, - SpinStateValidator::ZERO_ONE); - const auto t00Ws = PolarizationCorrectionsHelpers::workspaceForSpinState(groupWorkspace, spinConfigurationInput, - SpinStateValidator::ZERO_ZERO); + const auto &t01Ws = PolarizationCorrectionsHelpers::workspaceForSpinState(groupWorkspace, spinConfigurationInput, + SpinStateValidator::ZERO_ONE); + const auto &t00Ws = PolarizationCorrectionsHelpers::workspaceForSpinState(groupWorkspace, spinConfigurationInput, + SpinStateValidator::ZERO_ZERO); - auto effCell = convertToHistIfNecessary( + auto &effCell = convertToHistIfNecessary( AnalysisDataService::Instance().retrieveWS(getProperty(PropertyNames::ANALYSER_EFFICIENCY))); - auto rebin = createChildAlgorithm("RebinToWorkspace"); + auto &rebin = createChildAlgorithm("RebinToWorkspace"); rebin->initialize(); rebin->setProperty("WorkspaceToRebin", effCell); rebin->setProperty("WorkspaceToMatch", t00Ws); @@ -125,52 +125,26 @@ void PolarizerEfficiency::calculatePolarizerEfficiency() { // The efficiency is given by (e_cell * (T00 + T01) - T01) / ((2 * e_cell - 1) * (T00 + T01)) - auto sumT = addTwoWorkspaces(t00Ws, t01Ws); - auto eCellTimesSum = multiplyWorkspaces(effCell, sumT); - auto numerator = subtractTwoWorkspaces(eCellTimesSum, t01Ws); - scaleWorkspace(eCellTimesSum, 2); - auto denominator = subtractTwoWorkspaces(eCellTimesSum, sumT); - auto effPolarizer = divideWorkspaces(std::move(numerator), std::move(denominator)); + const auto &sumT = t00Ws + t01Ws; + auto &eCellTimesSum = effCell * sumT; + const auto &numerator = eCellTimesSum - t01Ws; + eCellTimesSum *= 2; + const auto &denominator = eCellTimesSum - sumT; + const auto &effPolarizer = numerator / denominator; setProperty(PropertyNames::OUTPUT_WORKSPACE, effPolarizer); } -void PolarizerEfficiency::scaleWorkspace(MatrixWorkspace_sptr ws, const double factor) { - auto scale = createChildAlgorithm("Scale"); - scale->initialize(); - scale->setProperty("InputWorkspace", ws); - scale->setProperty("OutputWorkspace", ws); - scale->setProperty("Factor", factor); - scale->setProperty("Operation", "Multiply"); - scale->execute(); -} - -MatrixWorkspace_sptr PolarizerEfficiency::runMathsAlgorithm(std::string algName, MatrixWorkspace_sptr lhs, - MatrixWorkspace_sptr rhs, - MatrixWorkspace_sptr output = nullptr) { - auto alg = createChildAlgorithm(algName); - alg->initialize(); - alg->setProperty("LHSWorkspace", lhs); - alg->setProperty("RHSWorkspace", rhs); - if (output) { - alg->setProperty("OutputWorkspace", output); - } else { - alg->setProperty("OutputWorkspace", "algOutput"); - } - alg->execute(); - return alg->getProperty("OutputWorkspace"); -} - MatrixWorkspace_sptr PolarizerEfficiency::convertToHistIfNecessary(const MatrixWorkspace_sptr ws) { if (ws->isHistogramData() && ws->isDistribution()) return ws; - MatrixWorkspace_sptr wsClone = std::move(ws->clone()); + MatrixWorkspace_sptr wsClone = ws->clone(); wsClone->setDistribution(true); if (wsClone->isHistogramData()) return wsClone; - auto convertToHistogram = createChildAlgorithm("ConvertToHistogram"); + auto &convertToHistogram = createChildAlgorithm("ConvertToHistogram"); convertToHistogram->initialize(); convertToHistogram->setProperty("InputWorkspace", wsClone); convertToHistogram->setProperty("OutputWorkspace", wsClone); From 11e1794714724a36253dd1844ddd7b0baec7a712 Mon Sep 17 00:00:00 2001 From: James Clarke Date: Wed, 1 May 2024 16:28:26 +0100 Subject: [PATCH 06/14] Update formula for polarizer efficiency Includes updating expected test results --- .../PolarizerEfficiency.cpp | 9 +--- .../PolarizerEfficiencyTest.h | 50 +++++++++---------- 2 files changed, 26 insertions(+), 33 deletions(-) diff --git a/Framework/Algorithms/src/PolarizationCorrections/PolarizerEfficiency.cpp b/Framework/Algorithms/src/PolarizationCorrections/PolarizerEfficiency.cpp index 5742bc0e269f..0d988bc0bce9 100644 --- a/Framework/Algorithms/src/PolarizationCorrections/PolarizerEfficiency.cpp +++ b/Framework/Algorithms/src/PolarizationCorrections/PolarizerEfficiency.cpp @@ -123,14 +123,7 @@ void PolarizerEfficiency::calculatePolarizerEfficiency() { rebin->execute(); effCell = rebin->getProperty("OutputWorkspace"); - // The efficiency is given by (e_cell * (T00 + T01) - T01) / ((2 * e_cell - 1) * (T00 + T01)) - - const auto &sumT = t00Ws + t01Ws; - auto &eCellTimesSum = effCell * sumT; - const auto &numerator = eCellTimesSum - t01Ws; - eCellTimesSum *= 2; - const auto &denominator = eCellTimesSum - sumT; - const auto &effPolarizer = numerator / denominator; + const auto &effPolarizer = (t00Ws - t01Ws) / (4 * (2 * effCell - 1) * (t00Ws + t01Ws)) + 0.5; setProperty(PropertyNames::OUTPUT_WORKSPACE, effPolarizer); } diff --git a/Framework/Algorithms/test/PolarizationCorrections/PolarizerEfficiencyTest.h b/Framework/Algorithms/test/PolarizationCorrections/PolarizerEfficiencyTest.h index 02beac0966b2..fdf68aa40d6a 100644 --- a/Framework/Algorithms/test/PolarizationCorrections/PolarizerEfficiencyTest.h +++ b/Framework/Algorithms/test/PolarizationCorrections/PolarizerEfficiencyTest.h @@ -44,7 +44,7 @@ class PolarizerEfficiencyTest : public CxxTest::TestSuite { MatrixWorkspace_sptr ws1 = generateWorkspace("ws1", x, y); - auto polariserEfficiency = AlgorithmManager::Instance().create("PolarizerEfficiency"); + auto &polariserEfficiency = AlgorithmManager::Instance().create("PolarizerEfficiency"); polariserEfficiency->initialize(); polariserEfficiency->setProperty("InputWorkspace", ws1->getName()); TS_ASSERT_THROWS(polariserEfficiency->execute(), const std::runtime_error &); @@ -58,20 +58,20 @@ class PolarizerEfficiencyTest : public CxxTest::TestSuite { MatrixWorkspace_sptr ws1 = generateWorkspace("ws1", x, y); MatrixWorkspace_sptr ws2 = generateWorkspace("ws2", x, y); WorkspaceGroup_sptr groupWs = groupWorkspaces("grp", std::vector{ws1, ws2}); - auto polariserEfficiency = createPolarizerEfficiencyAlgorithm(groupWs); + auto &polariserEfficiency = createPolarizerEfficiencyAlgorithm(groupWs); TS_ASSERT_THROWS(polariserEfficiency->execute(), const std::runtime_error &); } void testOutput() { - auto polariserEfficiency = createPolarizerEfficiencyAlgorithm(); + auto &polariserEfficiency = createPolarizerEfficiencyAlgorithm(); polariserEfficiency->execute(); - const auto workspaces = AnalysisDataService::Instance().getObjectNames(); + const auto &workspaces = AnalysisDataService::Instance().getObjectNames(); ASSERT_TRUE(std::find(workspaces.cbegin(), workspaces.cend(), "psm") != workspaces.cend()); } void testSpinConfigurations() { - auto polariserEfficiency = AlgorithmManager::Instance().create("PolarizerEfficiency"); + auto &polariserEfficiency = AlgorithmManager::Instance().create("PolarizerEfficiency"); TS_ASSERT_THROWS(polariserEfficiency->setProperty("SpinStates", "bad"), std::invalid_argument &); TS_ASSERT_THROWS(polariserEfficiency->setProperty("SpinStates", "10,01"), std::invalid_argument &); TS_ASSERT_THROWS(polariserEfficiency->setProperty("SpinStates", "00,00,11,11"), std::invalid_argument &); @@ -80,41 +80,41 @@ class PolarizerEfficiencyTest : public CxxTest::TestSuite { void testNonWavelengthInput() { // The units of the input workspace should be wavelength - auto wsGrp = createExampleGroupWorkspace("wsGrp", "TOF"); - auto polariserEfficiency = AlgorithmManager::Instance().create("PolarizerEfficiency"); + auto &wsGrp = createExampleGroupWorkspace("wsGrp", "TOF"); + auto &polariserEfficiency = AlgorithmManager::Instance().create("PolarizerEfficiency"); polariserEfficiency->initialize(); TS_ASSERT_THROWS(polariserEfficiency->setProperty("InputWorkspace", wsGrp->getName()), std::invalid_argument &); } void testExampleCalculation() { - auto tPara = generateFunctionDefinedWorkspace("T_para", "4 + x*0"); - auto tPara1 = generateFunctionDefinedWorkspace("T_para1", "4 + x*0"); - auto tAnti = generateFunctionDefinedWorkspace("T_anti", "2 + x*0"); - auto tAnti1 = generateFunctionDefinedWorkspace("T_anti1", "2 + x*0"); + auto &tPara = generateFunctionDefinedWorkspace("T_para", "4 + x*0"); + auto &tPara1 = generateFunctionDefinedWorkspace("T_para1", "4 + x*0"); + auto &tAnti = generateFunctionDefinedWorkspace("T_anti", "2 + x*0"); + auto &tAnti1 = generateFunctionDefinedWorkspace("T_anti1", "2 + x*0"); - auto grpWs = groupWorkspaces("grpWs", {tPara, tAnti, tAnti1, tPara1}); + auto &grpWs = groupWorkspaces("grpWs", {tPara, tAnti, tAnti1, tPara1}); - auto polariserEfficiency = createPolarizerEfficiencyAlgorithm(grpWs); + auto &polariserEfficiency = createPolarizerEfficiencyAlgorithm(grpWs); polariserEfficiency->execute(); MatrixWorkspace_sptr calculatedPolariserEfficiency = AnalysisDataService::Instance().retrieveWS( polariserEfficiency->getProperty("OutputWorkspace")); // The T_para and T_anti curves are 4 and 2 (constant wrt wavelength) respectively, and the analyser - // efficiency is 1 for all wavelengths, which should give us a polarizer efficiency of 2/3 + // efficiency is 1 for all wavelengths, which should give us a polarizer efficiency of 7/12 for (const double &y : calculatedPolariserEfficiency->dataY(0)) { - TS_ASSERT_DELTA(2.0 / 3.0, y, 1e-8); + TS_ASSERT_DELTA(7.0 / 12.0, y, 1e-8); } } void testErrors() { - auto polarizerEfficiency = createPolarizerEfficiencyAlgorithm(); + auto &polarizerEfficiency = createPolarizerEfficiencyAlgorithm(); polarizerEfficiency->execute(); MatrixWorkspace_sptr eff = AnalysisDataService::Instance().retrieveWS( polarizerEfficiency->getProperty("OutputWorkspace")); - const auto errors = eff->dataE(0); + const auto &errors = eff->dataE(0); // Skip the first error because with this toy data it'll be NaN - const std::vector expectedErrors{293.15439618057928, 130.29700166149377, 73.301389823113183, - 46.925472826600263}; + const std::vector expectedErrors{44.194173824159222, 19.641855032959654, 11.048543456039805, + 7.0710678118654755}; for (size_t i = 0; i < expectedErrors.size(); ++i) { TS_ASSERT_DELTA(expectedErrors[i], errors[i + 1], 1e-7); } @@ -142,7 +142,7 @@ class PolarizerEfficiencyTest : public CxxTest::TestSuite { MatrixWorkspace_sptr generateWorkspace(const std::string &name, const std::vector &x, const std::vector &y, const std::string &xUnit = "Wavelength") { - auto e = std::vector(x.size()); + auto &e = std::vector(x.size()); for (size_t i = 0; i < e.size(); ++i) { e[i] = 0; } @@ -152,7 +152,7 @@ class PolarizerEfficiencyTest : public CxxTest::TestSuite { MatrixWorkspace_sptr generateWorkspace(const std::string &name, const std::vector &x, const std::vector &y, const std::vector &e, const std::string &xUnit = "Wavelength") { - auto createWorkspace = AlgorithmManager::Instance().create("CreateWorkspace"); + auto &createWorkspace = AlgorithmManager::Instance().create("CreateWorkspace"); createWorkspace->initialize(); createWorkspace->setProperty("DataX", x); createWorkspace->setProperty("DataY", y); @@ -162,7 +162,7 @@ class PolarizerEfficiencyTest : public CxxTest::TestSuite { createWorkspace->setProperty("Distribution", true); createWorkspace->execute(); - auto convertToHistogram = AlgorithmManager::Instance().create("ConvertToHistogram"); + auto &convertToHistogram = AlgorithmManager::Instance().create("ConvertToHistogram"); convertToHistogram->initialize(); convertToHistogram->setProperty("InputWorkspace", name); convertToHistogram->setProperty("OutputWorkspace", name); @@ -173,7 +173,7 @@ class PolarizerEfficiencyTest : public CxxTest::TestSuite { } WorkspaceGroup_sptr groupWorkspaces(const std::string &name, const std::vector &wsToGroup) { - auto groupWorkspace = AlgorithmManager::Instance().create("GroupWorkspaces"); + auto &groupWorkspace = AlgorithmManager::Instance().create("GroupWorkspaces"); groupWorkspace->initialize(); std::vector wsToGroupNames(wsToGroup.size()); std::transform(wsToGroup.cbegin(), wsToGroup.cend(), wsToGroupNames.begin(), @@ -186,7 +186,7 @@ class PolarizerEfficiencyTest : public CxxTest::TestSuite { } MatrixWorkspace_sptr generateFunctionDefinedWorkspace(const std::string &name, const std::string &func) { - auto createSampleWorkspace = AlgorithmManager::Instance().create("CreateSampleWorkspace"); + auto &createSampleWorkspace = AlgorithmManager::Instance().create("CreateSampleWorkspace"); createSampleWorkspace->initialize(); createSampleWorkspace->setProperty("WorkspaceType", "Histogram"); createSampleWorkspace->setProperty("OutputWorkspace", name); @@ -210,7 +210,7 @@ class PolarizerEfficiencyTest : public CxxTest::TestSuite { if (inputGrp == nullptr) { inputGrp = createExampleGroupWorkspace("wsGrp"); } - auto polarizerEfficiency = AlgorithmManager::Instance().create("PolarizerEfficiency"); + auto &polarizerEfficiency = AlgorithmManager::Instance().create("PolarizerEfficiency"); polarizerEfficiency->initialize(); polarizerEfficiency->setProperty("InputWorkspace", inputGrp->getName()); polarizerEfficiency->setProperty("AnalyserEfficiency", ANALYSER_EFFICIENCY_WS_NAME); From 5096c966ddf76df9f114edbd4f7cd6422eb6020c Mon Sep 17 00:00:00 2001 From: James Clarke Date: Wed, 1 May 2024 16:39:11 +0100 Subject: [PATCH 07/14] Fix cppcheck --- .../PolarizerEfficiency.cpp | 8 ++-- .../PolarizerEfficiencyTest.h | 38 +++++++++---------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/Framework/Algorithms/src/PolarizationCorrections/PolarizerEfficiency.cpp b/Framework/Algorithms/src/PolarizationCorrections/PolarizerEfficiency.cpp index 0d988bc0bce9..146bc14a98be 100644 --- a/Framework/Algorithms/src/PolarizationCorrections/PolarizerEfficiency.cpp +++ b/Framework/Algorithms/src/PolarizationCorrections/PolarizerEfficiency.cpp @@ -35,7 +35,7 @@ static const std::string OUTPUT_WORKSPACE = "OutputWorkspace"; void PolarizerEfficiency::init() { // Declare required input parameters for algorithm and do some validation here - auto &validator = std::make_shared(); + auto validator = std::make_shared(); validator->add("Wavelength"); validator->add(); declareProperty( @@ -112,10 +112,10 @@ void PolarizerEfficiency::calculatePolarizerEfficiency() { const auto &t00Ws = PolarizationCorrectionsHelpers::workspaceForSpinState(groupWorkspace, spinConfigurationInput, SpinStateValidator::ZERO_ZERO); - auto &effCell = convertToHistIfNecessary( + auto effCell = convertToHistIfNecessary( AnalysisDataService::Instance().retrieveWS(getProperty(PropertyNames::ANALYSER_EFFICIENCY))); - auto &rebin = createChildAlgorithm("RebinToWorkspace"); + auto rebin = createChildAlgorithm("RebinToWorkspace"); rebin->initialize(); rebin->setProperty("WorkspaceToRebin", effCell); rebin->setProperty("WorkspaceToMatch", t00Ws); @@ -137,7 +137,7 @@ MatrixWorkspace_sptr PolarizerEfficiency::convertToHistIfNecessary(const MatrixW if (wsClone->isHistogramData()) return wsClone; - auto &convertToHistogram = createChildAlgorithm("ConvertToHistogram"); + auto convertToHistogram = createChildAlgorithm("ConvertToHistogram"); convertToHistogram->initialize(); convertToHistogram->setProperty("InputWorkspace", wsClone); convertToHistogram->setProperty("OutputWorkspace", wsClone); diff --git a/Framework/Algorithms/test/PolarizationCorrections/PolarizerEfficiencyTest.h b/Framework/Algorithms/test/PolarizationCorrections/PolarizerEfficiencyTest.h index fdf68aa40d6a..0ecdda1bfbe1 100644 --- a/Framework/Algorithms/test/PolarizationCorrections/PolarizerEfficiencyTest.h +++ b/Framework/Algorithms/test/PolarizationCorrections/PolarizerEfficiencyTest.h @@ -44,7 +44,7 @@ class PolarizerEfficiencyTest : public CxxTest::TestSuite { MatrixWorkspace_sptr ws1 = generateWorkspace("ws1", x, y); - auto &polariserEfficiency = AlgorithmManager::Instance().create("PolarizerEfficiency"); + auto polariserEfficiency = AlgorithmManager::Instance().create("PolarizerEfficiency"); polariserEfficiency->initialize(); polariserEfficiency->setProperty("InputWorkspace", ws1->getName()); TS_ASSERT_THROWS(polariserEfficiency->execute(), const std::runtime_error &); @@ -58,12 +58,12 @@ class PolarizerEfficiencyTest : public CxxTest::TestSuite { MatrixWorkspace_sptr ws1 = generateWorkspace("ws1", x, y); MatrixWorkspace_sptr ws2 = generateWorkspace("ws2", x, y); WorkspaceGroup_sptr groupWs = groupWorkspaces("grp", std::vector{ws1, ws2}); - auto &polariserEfficiency = createPolarizerEfficiencyAlgorithm(groupWs); + auto polariserEfficiency = createPolarizerEfficiencyAlgorithm(groupWs); TS_ASSERT_THROWS(polariserEfficiency->execute(), const std::runtime_error &); } void testOutput() { - auto &polariserEfficiency = createPolarizerEfficiencyAlgorithm(); + auto polariserEfficiency = createPolarizerEfficiencyAlgorithm(); polariserEfficiency->execute(); const auto &workspaces = AnalysisDataService::Instance().getObjectNames(); @@ -71,7 +71,7 @@ class PolarizerEfficiencyTest : public CxxTest::TestSuite { } void testSpinConfigurations() { - auto &polariserEfficiency = AlgorithmManager::Instance().create("PolarizerEfficiency"); + auto polariserEfficiency = AlgorithmManager::Instance().create("PolarizerEfficiency"); TS_ASSERT_THROWS(polariserEfficiency->setProperty("SpinStates", "bad"), std::invalid_argument &); TS_ASSERT_THROWS(polariserEfficiency->setProperty("SpinStates", "10,01"), std::invalid_argument &); TS_ASSERT_THROWS(polariserEfficiency->setProperty("SpinStates", "00,00,11,11"), std::invalid_argument &); @@ -80,21 +80,21 @@ class PolarizerEfficiencyTest : public CxxTest::TestSuite { void testNonWavelengthInput() { // The units of the input workspace should be wavelength - auto &wsGrp = createExampleGroupWorkspace("wsGrp", "TOF"); - auto &polariserEfficiency = AlgorithmManager::Instance().create("PolarizerEfficiency"); + auto wsGrp = createExampleGroupWorkspace("wsGrp", "TOF"); + auto polariserEfficiency = AlgorithmManager::Instance().create("PolarizerEfficiency"); polariserEfficiency->initialize(); TS_ASSERT_THROWS(polariserEfficiency->setProperty("InputWorkspace", wsGrp->getName()), std::invalid_argument &); } void testExampleCalculation() { - auto &tPara = generateFunctionDefinedWorkspace("T_para", "4 + x*0"); - auto &tPara1 = generateFunctionDefinedWorkspace("T_para1", "4 + x*0"); - auto &tAnti = generateFunctionDefinedWorkspace("T_anti", "2 + x*0"); - auto &tAnti1 = generateFunctionDefinedWorkspace("T_anti1", "2 + x*0"); + auto tPara = generateFunctionDefinedWorkspace("T_para", "4 + x*0"); + auto tPara1 = generateFunctionDefinedWorkspace("T_para1", "4 + x*0"); + auto tAnti = generateFunctionDefinedWorkspace("T_anti", "2 + x*0"); + auto tAnti1 = generateFunctionDefinedWorkspace("T_anti1", "2 + x*0"); - auto &grpWs = groupWorkspaces("grpWs", {tPara, tAnti, tAnti1, tPara1}); + auto grpWs = groupWorkspaces("grpWs", {tPara, tAnti, tAnti1, tPara1}); - auto &polariserEfficiency = createPolarizerEfficiencyAlgorithm(grpWs); + auto polariserEfficiency = createPolarizerEfficiencyAlgorithm(grpWs); polariserEfficiency->execute(); MatrixWorkspace_sptr calculatedPolariserEfficiency = AnalysisDataService::Instance().retrieveWS( polariserEfficiency->getProperty("OutputWorkspace")); @@ -107,7 +107,7 @@ class PolarizerEfficiencyTest : public CxxTest::TestSuite { } void testErrors() { - auto &polarizerEfficiency = createPolarizerEfficiencyAlgorithm(); + auto polarizerEfficiency = createPolarizerEfficiencyAlgorithm(); polarizerEfficiency->execute(); MatrixWorkspace_sptr eff = AnalysisDataService::Instance().retrieveWS( polarizerEfficiency->getProperty("OutputWorkspace")); @@ -142,7 +142,7 @@ class PolarizerEfficiencyTest : public CxxTest::TestSuite { MatrixWorkspace_sptr generateWorkspace(const std::string &name, const std::vector &x, const std::vector &y, const std::string &xUnit = "Wavelength") { - auto &e = std::vector(x.size()); + auto e = std::vector(x.size()); for (size_t i = 0; i < e.size(); ++i) { e[i] = 0; } @@ -152,7 +152,7 @@ class PolarizerEfficiencyTest : public CxxTest::TestSuite { MatrixWorkspace_sptr generateWorkspace(const std::string &name, const std::vector &x, const std::vector &y, const std::vector &e, const std::string &xUnit = "Wavelength") { - auto &createWorkspace = AlgorithmManager::Instance().create("CreateWorkspace"); + auto createWorkspace = AlgorithmManager::Instance().create("CreateWorkspace"); createWorkspace->initialize(); createWorkspace->setProperty("DataX", x); createWorkspace->setProperty("DataY", y); @@ -162,7 +162,7 @@ class PolarizerEfficiencyTest : public CxxTest::TestSuite { createWorkspace->setProperty("Distribution", true); createWorkspace->execute(); - auto &convertToHistogram = AlgorithmManager::Instance().create("ConvertToHistogram"); + auto convertToHistogram = AlgorithmManager::Instance().create("ConvertToHistogram"); convertToHistogram->initialize(); convertToHistogram->setProperty("InputWorkspace", name); convertToHistogram->setProperty("OutputWorkspace", name); @@ -173,7 +173,7 @@ class PolarizerEfficiencyTest : public CxxTest::TestSuite { } WorkspaceGroup_sptr groupWorkspaces(const std::string &name, const std::vector &wsToGroup) { - auto &groupWorkspace = AlgorithmManager::Instance().create("GroupWorkspaces"); + auto groupWorkspace = AlgorithmManager::Instance().create("GroupWorkspaces"); groupWorkspace->initialize(); std::vector wsToGroupNames(wsToGroup.size()); std::transform(wsToGroup.cbegin(), wsToGroup.cend(), wsToGroupNames.begin(), @@ -186,7 +186,7 @@ class PolarizerEfficiencyTest : public CxxTest::TestSuite { } MatrixWorkspace_sptr generateFunctionDefinedWorkspace(const std::string &name, const std::string &func) { - auto &createSampleWorkspace = AlgorithmManager::Instance().create("CreateSampleWorkspace"); + auto createSampleWorkspace = AlgorithmManager::Instance().create("CreateSampleWorkspace"); createSampleWorkspace->initialize(); createSampleWorkspace->setProperty("WorkspaceType", "Histogram"); createSampleWorkspace->setProperty("OutputWorkspace", name); @@ -210,7 +210,7 @@ class PolarizerEfficiencyTest : public CxxTest::TestSuite { if (inputGrp == nullptr) { inputGrp = createExampleGroupWorkspace("wsGrp"); } - auto &polarizerEfficiency = AlgorithmManager::Instance().create("PolarizerEfficiency"); + auto polarizerEfficiency = AlgorithmManager::Instance().create("PolarizerEfficiency"); polarizerEfficiency->initialize(); polarizerEfficiency->setProperty("InputWorkspace", inputGrp->getName()); polarizerEfficiency->setProperty("AnalyserEfficiency", ANALYSER_EFFICIENCY_WS_NAME); From d4001368c83d9a7ce7f22d3f9ea661694443caad Mon Sep 17 00:00:00 2001 From: James Clarke Date: Wed, 1 May 2024 16:47:33 +0100 Subject: [PATCH 08/14] Update equations in docs --- docs/source/algorithms/PolarizerEfficiency-v1.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/algorithms/PolarizerEfficiency-v1.rst b/docs/source/algorithms/PolarizerEfficiency-v1.rst index a8190cd45ff7..7da2f84674a7 100644 --- a/docs/source/algorithms/PolarizerEfficiency-v1.rst +++ b/docs/source/algorithms/PolarizerEfficiency-v1.rst @@ -17,12 +17,12 @@ efficiency, :math:`\epsilon_{cell}`, is given by ``AnalyserEfficiency``. The polarization of the polarizer, :math:`P_{SM}`, is given by .. math:: - P_{SM} = \frac{T_{00} - T_{01}}{P_{cell}(T_{00} + T_{01})} + P_{SM} = \frac{T_{00} - T_{01}}{2P_{cell}(T_{00} + T_{01})} Since the efficiency, :math:`\epsilon_{SM}`, is given by :math:`\frac{1 + P_{SM}}{2}`, we have that .. math:: - \epsilon_{SM} = \frac{\epsilon_{cell}(T_{00} + T_{01}) - T_{01}}{(2\epsilon_{cell} - 1)(T_{00} + T_{01})} + \epsilon_{SM} = \frac{1}{2} + \frac{T_{00} - T_{01}}{4(2\epsilon_{cell} - 1)(T_{00} + T_{01})} Usage ----- From 9db3f69cfb1abd22774536bd43cc55707bf23aad Mon Sep 17 00:00:00 2001 From: James Clarke Date: Thu, 2 May 2024 16:31:23 +0100 Subject: [PATCH 09/14] Add option to save to file You can now either have an output workspace, or save to a file, or both. --- .../PolarizerEfficiency.h | 1 + .../PolarizerEfficiency.cpp | 45 +++++++++++++++-- .../PolarizerEfficiencyTest.h | 49 +++++++++++++++++-- 3 files changed, 88 insertions(+), 7 deletions(-) diff --git a/Framework/Algorithms/inc/MantidAlgorithms/PolarizationCorrections/PolarizerEfficiency.h b/Framework/Algorithms/inc/MantidAlgorithms/PolarizationCorrections/PolarizerEfficiency.h index 9bd8d65e2f8b..ecfe4df24e09 100644 --- a/Framework/Algorithms/inc/MantidAlgorithms/PolarizationCorrections/PolarizerEfficiency.h +++ b/Framework/Algorithms/inc/MantidAlgorithms/PolarizationCorrections/PolarizerEfficiency.h @@ -39,6 +39,7 @@ class MANTID_ALGORITHMS_DLL PolarizerEfficiency final : public API::Algorithm { void validateGroupInput(); void calculatePolarizerEfficiency(); MatrixWorkspace_sptr convertToHistIfNecessary(const MatrixWorkspace_sptr ws); + void saveToFile(MatrixWorkspace_sptr const &workspace, std::string const &filePathStr); }; } // namespace Algorithms diff --git a/Framework/Algorithms/src/PolarizationCorrections/PolarizerEfficiency.cpp b/Framework/Algorithms/src/PolarizationCorrections/PolarizerEfficiency.cpp index 146bc14a98be..abc54169cb79 100644 --- a/Framework/Algorithms/src/PolarizationCorrections/PolarizerEfficiency.cpp +++ b/Framework/Algorithms/src/PolarizationCorrections/PolarizerEfficiency.cpp @@ -7,6 +7,7 @@ #include "MantidAlgorithms/PolarizationCorrections/PolarizerEfficiency.h" #include "MantidAPI/AnalysisDataService.h" +#include "MantidAPI/FileProperty.h" #include "MantidAPI/HistogramValidator.h" #include "MantidAPI/ITableWorkspace.h" #include "MantidAPI/MatrixWorkspace.h" @@ -18,6 +19,7 @@ #include "MantidKernel/ListValidator.h" #include +#include namespace Mantid::Algorithms { // Register the algorithm into the algorithm factory @@ -31,6 +33,7 @@ static const std::string INPUT_WORKSPACE = "InputWorkspace"; static const std::string ANALYSER_EFFICIENCY = "AnalyserEfficiency"; static const std::string SPIN_STATES = "SpinStates"; static const std::string OUTPUT_WORKSPACE = "OutputWorkspace"; +static const std::string OUTPUT_FILE_PATH = "OutputFilePath"; } // namespace PropertyNames void PolarizerEfficiency::init() { @@ -45,13 +48,16 @@ void PolarizerEfficiency::init() { declareProperty(std::make_unique>(PropertyNames::ANALYSER_EFFICIENCY, "", Direction::Input, wavelengthValidator), "Analyser efficiency as a function of wavelength"); - declareProperty( - std::make_unique>(PropertyNames::OUTPUT_WORKSPACE, "", Direction::Output), - "Polarizer efficiency as a function of wavelength"); + declareProperty(std::make_unique>(PropertyNames::OUTPUT_WORKSPACE, "", + Direction::Output, PropertyMode::Optional), + "Polarizer efficiency as a function of wavelength"); const 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\""); + + declareProperty(std::make_unique(PropertyNames::OUTPUT_FILE_PATH, "", FileProperty::OptionalSave), + "File name or path for the output to be saved to."); } /** @@ -78,6 +84,14 @@ std::map PolarizerEfficiency::validateInputs() { } } + // Check outputs. + auto const &outputWs = getPropertyValue(PropertyNames::OUTPUT_WORKSPACE); + auto const &outputFile = getPropertyValue(PropertyNames::OUTPUT_FILE_PATH); + if (outputWs.empty() && outputFile.empty()) { + errorList[PropertyNames::OUTPUT_FILE_PATH] = "Either an output workspace or output file must be provided."; + errorList[PropertyNames::OUTPUT_WORKSPACE] = "Either an output workspace or output file must be provided."; + } + return errorList; } @@ -124,7 +138,30 @@ void PolarizerEfficiency::calculatePolarizerEfficiency() { effCell = rebin->getProperty("OutputWorkspace"); const auto &effPolarizer = (t00Ws - t01Ws) / (4 * (2 * effCell - 1) * (t00Ws + t01Ws)) + 0.5; - setProperty(PropertyNames::OUTPUT_WORKSPACE, effPolarizer); + + auto const &filename = getPropertyValue(PropertyNames::OUTPUT_FILE_PATH); + if (!filename.empty()) { + saveToFile(effPolarizer, filename); + } + + auto const &outputWsName = getPropertyValue(PropertyNames::OUTPUT_WORKSPACE); + if (!outputWsName.empty()) { + setProperty(PropertyNames::OUTPUT_WORKSPACE, effPolarizer); + } +} + +void PolarizerEfficiency::saveToFile(MatrixWorkspace_sptr const &workspace, std::string const &filePathStr) { + std::filesystem::path filePath = filePathStr; + // Add the nexus extension if it's not been applied already. + const std::string fileExtension = ".nxs"; + if (filePath.extension() != fileExtension) { + filePath.replace_extension(fileExtension); + } + auto saveAlg = createChildAlgorithm("SaveNexus"); + saveAlg->initialize(); + saveAlg->setProperty("Filename", filePath.string()); + saveAlg->setProperty("InputWorkspace", workspace); + saveAlg->execute(); } MatrixWorkspace_sptr PolarizerEfficiency::convertToHistIfNecessary(const MatrixWorkspace_sptr ws) { diff --git a/Framework/Algorithms/test/PolarizationCorrections/PolarizerEfficiencyTest.h b/Framework/Algorithms/test/PolarizationCorrections/PolarizerEfficiencyTest.h index 0ecdda1bfbe1..ba7331a1e225 100644 --- a/Framework/Algorithms/test/PolarizationCorrections/PolarizerEfficiencyTest.h +++ b/Framework/Algorithms/test/PolarizationCorrections/PolarizerEfficiencyTest.h @@ -10,8 +10,10 @@ #include "MantidAPI/AlgorithmManager.h" #include "MantidAPI/AnalysisDataService.h" #include "MantidAlgorithms/PolarizationCorrections/PolarizerEfficiency.h" +#include "MantidKernel/ConfigService.h" #include +#include using namespace Mantid; using namespace Mantid::Algorithms; @@ -22,9 +24,13 @@ class PolarizerEfficiencyTest : public CxxTest::TestSuite { void setUp() override { // Use an analyser efficiency of 1 to make test calculations simpler generateFunctionDefinedWorkspace(ANALYSER_EFFICIENCY_WS_NAME, "1 + x*0"); + m_defaultSaveDirectory = Kernel::ConfigService::Instance().getString("defaultsave.directory"); } - void tearDown() override { AnalysisDataService::Instance().clear(); } + void tearDown() override { + AnalysisDataService::Instance().clear(); + Kernel::ConfigService::Instance().setString("defaultsave.directory", m_defaultSaveDirectory); + } void testName() { PolarizerEfficiency alg; @@ -120,8 +126,42 @@ class PolarizerEfficiencyTest : public CxxTest::TestSuite { } } + /// Saving Tests + + void testSavingAbsolute() { + auto const temp_filename = std::filesystem::temp_directory_path() /= "something.nxs"; + auto polarizerEfficiency = createPolarizerEfficiencyAlgorithm(createExampleGroupWorkspace("wsGrp"), false); + polarizerEfficiency->setPropertyValue("OutputFilePath", temp_filename.string()); + polarizerEfficiency->execute(); + TS_ASSERT(std::filesystem::exists(temp_filename)) + std::filesystem::remove(temp_filename); + } + + void testSavingRelative() { + auto tempDir = std::filesystem::temp_directory_path(); + Kernel::ConfigService::Instance().setString("defaultsave.directory", tempDir.string()); + std::string const &filename = "something.nxs"; + auto polarizerEfficiency = createPolarizerEfficiencyAlgorithm(); + polarizerEfficiency->setPropertyValue("OutputFilePath", filename); + polarizerEfficiency->execute(); + auto savedPath = tempDir /= filename; + TS_ASSERT(std::filesystem::exists(savedPath)) + std::filesystem::remove(savedPath); + } + + void testSavingNoExt() { + auto const temp_filename = std::filesystem::temp_directory_path() /= "something"; + auto polarizerEfficiency = createPolarizerEfficiencyAlgorithm(); + polarizerEfficiency->setPropertyValue("OutputFilePath", temp_filename.string()); + polarizerEfficiency->execute(); + auto savedPath = temp_filename.string() + ".nxs"; + TS_ASSERT(std::filesystem::exists(savedPath)) + std::filesystem::remove(savedPath); + } + private: const std::string ANALYSER_EFFICIENCY_WS_NAME = "effAnalyser"; + std::string m_defaultSaveDirectory; WorkspaceGroup_sptr createExampleGroupWorkspace(const std::string &name, const std::string &xUnit = "Wavelength", const size_t numBins = 5) { @@ -206,7 +246,8 @@ class PolarizerEfficiencyTest : public CxxTest::TestSuite { return result; } - IAlgorithm_sptr createPolarizerEfficiencyAlgorithm(WorkspaceGroup_sptr inputGrp = nullptr) { + IAlgorithm_sptr createPolarizerEfficiencyAlgorithm(WorkspaceGroup_sptr inputGrp = nullptr, + const bool setOutputWs = true) { if (inputGrp == nullptr) { inputGrp = createExampleGroupWorkspace("wsGrp"); } @@ -214,7 +255,9 @@ class PolarizerEfficiencyTest : public CxxTest::TestSuite { polarizerEfficiency->initialize(); polarizerEfficiency->setProperty("InputWorkspace", inputGrp->getName()); polarizerEfficiency->setProperty("AnalyserEfficiency", ANALYSER_EFFICIENCY_WS_NAME); - polarizerEfficiency->setProperty("OutputWorkspace", "psm"); + if (setOutputWs) { + polarizerEfficiency->setProperty("OutputWorkspace", "psm"); + } return polarizerEfficiency; } }; \ No newline at end of file From bab74fa86305b665addd32c2cdd36bb1f51ce07a Mon Sep 17 00:00:00 2001 From: James Clarke <139879523+jclarkeSTFC@users.noreply.github.com> Date: Fri, 3 May 2024 14:24:25 +0100 Subject: [PATCH 10/14] Specify input is a workspace group Co-authored-by: Caila Finn <47181718+cailafinn@users.noreply.github.com> --- .../src/PolarizationCorrections/PolarizerEfficiency.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Framework/Algorithms/src/PolarizationCorrections/PolarizerEfficiency.cpp b/Framework/Algorithms/src/PolarizationCorrections/PolarizerEfficiency.cpp index abc54169cb79..5d0c584a5e82 100644 --- a/Framework/Algorithms/src/PolarizationCorrections/PolarizerEfficiency.cpp +++ b/Framework/Algorithms/src/PolarizationCorrections/PolarizerEfficiency.cpp @@ -42,7 +42,7 @@ void PolarizerEfficiency::init() { validator->add("Wavelength"); validator->add(); declareProperty( - std::make_unique>(PropertyNames::INPUT_WORKSPACE, "", Direction::Input, validator), + std::make_unique>(PropertyNames::INPUT_WORKSPACE, "", Direction::Input, validator), "Input group workspace to use for polarization calculation"); const auto &wavelengthValidator = std::make_shared("Wavelength"); declareProperty(std::make_unique>(PropertyNames::ANALYSER_EFFICIENCY, "", From 48c6cfd3aee6538fdd16e2444058a866f44acfc7 Mon Sep 17 00:00:00 2001 From: James Clarke <139879523+jclarkeSTFC@users.noreply.github.com> Date: Fri, 3 May 2024 14:25:30 +0100 Subject: [PATCH 11/14] Input may not be in the ADS Co-authored-by: Caila Finn <47181718+cailafinn@users.noreply.github.com> --- .../src/PolarizationCorrections/PolarizerEfficiency.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Framework/Algorithms/src/PolarizationCorrections/PolarizerEfficiency.cpp b/Framework/Algorithms/src/PolarizationCorrections/PolarizerEfficiency.cpp index 5d0c584a5e82..c4b1ff85db56 100644 --- a/Framework/Algorithms/src/PolarizationCorrections/PolarizerEfficiency.cpp +++ b/Framework/Algorithms/src/PolarizationCorrections/PolarizerEfficiency.cpp @@ -67,9 +67,9 @@ void PolarizerEfficiency::init() { */ std::map PolarizerEfficiency::validateInputs() { std::map errorList; - const std::string inputWorkspaceName = getProperty(PropertyNames::INPUT_WORKSPACE); - if (!AnalysisDataService::Instance().doesExist(inputWorkspaceName)) { - errorList[PropertyNames::INPUT_WORKSPACE] = "The workspace " + inputWorkspaceName + " does not exist in the ADS."; + const WorkspaceGroup_sptr inputWorkspace = getProperty(PropertyNames::INPUT_WORKSPACE); + if (inputWorkspace == nullptr) { + errorList[PropertyNames::INPUT_WORKSPACE] = "The input workspace is not a workspace group." return errorList; } From 153d06d1d49b1a254f48d47806d1ccd7b8e7fe49 Mon Sep 17 00:00:00 2001 From: James Clarke Date: Fri, 3 May 2024 16:00:59 +0100 Subject: [PATCH 12/14] Remove validator on input workspace This validator does not work when the type is specified explicitly as being a WorkspaceGroup, so instead we'll have to to check for wavelength in validateInputs(). --- .../PolarizerEfficiency.cpp | 28 +++++++++---------- .../PolarizerEfficiencyTest.h | 6 ++-- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/Framework/Algorithms/src/PolarizationCorrections/PolarizerEfficiency.cpp b/Framework/Algorithms/src/PolarizationCorrections/PolarizerEfficiency.cpp index c4b1ff85db56..7c6e8a596b1d 100644 --- a/Framework/Algorithms/src/PolarizationCorrections/PolarizerEfficiency.cpp +++ b/Framework/Algorithms/src/PolarizationCorrections/PolarizerEfficiency.cpp @@ -7,6 +7,7 @@ #include "MantidAlgorithms/PolarizationCorrections/PolarizerEfficiency.h" #include "MantidAPI/AnalysisDataService.h" +#include "MantidAPI/Axis.h" #include "MantidAPI/FileProperty.h" #include "MantidAPI/HistogramValidator.h" #include "MantidAPI/ITableWorkspace.h" @@ -17,6 +18,7 @@ #include "MantidKernel/BoundedValidator.h" #include "MantidKernel/CompositeValidator.h" #include "MantidKernel/ListValidator.h" +#include "MantidKernel/Unit.h" #include #include @@ -37,12 +39,8 @@ static const std::string OUTPUT_FILE_PATH = "OutputFilePath"; } // namespace PropertyNames void PolarizerEfficiency::init() { - // Declare required input parameters for algorithm and do some validation here - auto validator = std::make_shared(); - validator->add("Wavelength"); - validator->add(); declareProperty( - std::make_unique>(PropertyNames::INPUT_WORKSPACE, "", Direction::Input, validator), + std::make_unique>(PropertyNames::INPUT_WORKSPACE, "", Direction::Input), "Input group workspace to use for polarization calculation"); const auto &wavelengthValidator = std::make_shared("Wavelength"); declareProperty(std::make_unique>(PropertyNames::ANALYSER_EFFICIENCY, "", @@ -69,18 +67,20 @@ std::map PolarizerEfficiency::validateInputs() { std::map errorList; const WorkspaceGroup_sptr inputWorkspace = getProperty(PropertyNames::INPUT_WORKSPACE); if (inputWorkspace == nullptr) { - errorList[PropertyNames::INPUT_WORKSPACE] = "The input workspace is not a workspace group." + errorList[PropertyNames::INPUT_WORKSPACE] = "The input workspace is not a workspace group."; return errorList; } - const auto &ws = AnalysisDataService::Instance().retrieve(inputWorkspaceName); - if (!ws->isGroup()) { - errorList[PropertyNames::INPUT_WORKSPACE] = "The input workspace is not a group workspace."; - } else { - const auto &wsGroup = std::dynamic_pointer_cast(ws); - if (wsGroup->size() != 4) { - errorList[PropertyNames::INPUT_WORKSPACE] = - "The input group workspace must have four periods corresponding to the four spin configurations."; + if (inputWorkspace->size() != 4) { + errorList[PropertyNames::INPUT_WORKSPACE] = + "The input group workspace must have four periods corresponding to the four spin configurations."; + } + + for (size_t i = 0; i < inputWorkspace->size(); ++i) { + const MatrixWorkspace_sptr stateWs = std::dynamic_pointer_cast(inputWorkspace->getItem(i)); + Unit_const_sptr unit = stateWs->getAxis(0)->unit(); + if (unit->unitID() != "Wavelength") { + errorList[PropertyNames::INPUT_WORKSPACE] = "All input workspaces must be in units of Wavelength."; } } diff --git a/Framework/Algorithms/test/PolarizationCorrections/PolarizerEfficiencyTest.h b/Framework/Algorithms/test/PolarizationCorrections/PolarizerEfficiencyTest.h index ba7331a1e225..a8a8ee954f2f 100644 --- a/Framework/Algorithms/test/PolarizationCorrections/PolarizerEfficiencyTest.h +++ b/Framework/Algorithms/test/PolarizationCorrections/PolarizerEfficiencyTest.h @@ -52,8 +52,7 @@ class PolarizerEfficiencyTest : public CxxTest::TestSuite { auto polariserEfficiency = AlgorithmManager::Instance().create("PolarizerEfficiency"); polariserEfficiency->initialize(); - polariserEfficiency->setProperty("InputWorkspace", ws1->getName()); - TS_ASSERT_THROWS(polariserEfficiency->execute(), const std::runtime_error &); + TS_ASSERT_THROWS(polariserEfficiency->setProperty("InputWorkspace", ws1), const std::invalid_argument &); } void testGroupWorkspaceWithWrongSize() { @@ -89,7 +88,8 @@ class PolarizerEfficiencyTest : public CxxTest::TestSuite { auto wsGrp = createExampleGroupWorkspace("wsGrp", "TOF"); auto polariserEfficiency = AlgorithmManager::Instance().create("PolarizerEfficiency"); polariserEfficiency->initialize(); - TS_ASSERT_THROWS(polariserEfficiency->setProperty("InputWorkspace", wsGrp->getName()), std::invalid_argument &); + polariserEfficiency->setProperty("InputWorkspace", wsGrp); + TS_ASSERT_THROWS(polariserEfficiency->execute(), const std::runtime_error &); } void testExampleCalculation() { From 387fd4ec6f29feaece7f59f57dc5b3b0397a53ef Mon Sep 17 00:00:00 2001 From: Rachel Baust Date: Thu, 9 May 2024 11:30:55 +0100 Subject: [PATCH 13/14] Add note about rebinning to documentation --- docs/source/algorithms/PolarizerEfficiency-v1.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/source/algorithms/PolarizerEfficiency-v1.rst b/docs/source/algorithms/PolarizerEfficiency-v1.rst index 7da2f84674a7..0837808b8309 100644 --- a/docs/source/algorithms/PolarizerEfficiency-v1.rst +++ b/docs/source/algorithms/PolarizerEfficiency-v1.rst @@ -14,7 +14,8 @@ Calculates how the efficiency of a polarizer varies with wavelength. The ordering of the workspaces in ``InputWorkspace`` is taken from the ``SpinStates`` parameter, and the analyser efficiency, :math:`\epsilon_{cell}`, is given by ``AnalyserEfficiency``. -The polarization of the polarizer, :math:`P_{SM}`, is given by +First the ``AnalyserEfficiency`` workspace is rebinned to match the binning of the input workspace that corresponds to the "00" spin state. +Having done this, the polarization of the polarizer, :math:`P_{SM}`, is given by .. math:: P_{SM} = \frac{T_{00} - T_{01}}{2P_{cell}(T_{00} + T_{01})} From 19babc8a044181343129992d670bc79065cdbff1 Mon Sep 17 00:00:00 2001 From: Rachel Baust Date: Thu, 9 May 2024 13:27:47 +0100 Subject: [PATCH 14/14] Minor refactoring --- .../PolarizerEfficiency.cpp | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/Framework/Algorithms/src/PolarizationCorrections/PolarizerEfficiency.cpp b/Framework/Algorithms/src/PolarizationCorrections/PolarizerEfficiency.cpp index 7c6e8a596b1d..cd8f640c09c1 100644 --- a/Framework/Algorithms/src/PolarizationCorrections/PolarizerEfficiency.cpp +++ b/Framework/Algorithms/src/PolarizationCorrections/PolarizerEfficiency.cpp @@ -38,6 +38,10 @@ static const std::string OUTPUT_WORKSPACE = "OutputWorkspace"; static const std::string OUTPUT_FILE_PATH = "OutputFilePath"; } // namespace PropertyNames +namespace { +static const std::string FILE_EXTENSION = ".nxs"; +} // unnamed namespace + void PolarizerEfficiency::init() { declareProperty( std::make_unique>(PropertyNames::INPUT_WORKSPACE, "", Direction::Input), @@ -74,13 +78,13 @@ std::map PolarizerEfficiency::validateInputs() { if (inputWorkspace->size() != 4) { errorList[PropertyNames::INPUT_WORKSPACE] = "The input group workspace must have four periods corresponding to the four spin configurations."; - } - - for (size_t i = 0; i < inputWorkspace->size(); ++i) { - const MatrixWorkspace_sptr stateWs = std::dynamic_pointer_cast(inputWorkspace->getItem(i)); - Unit_const_sptr unit = stateWs->getAxis(0)->unit(); - if (unit->unitID() != "Wavelength") { - errorList[PropertyNames::INPUT_WORKSPACE] = "All input workspaces must be in units of Wavelength."; + } else { + for (size_t i = 0; i < inputWorkspace->size(); ++i) { + const MatrixWorkspace_sptr stateWs = std::dynamic_pointer_cast(inputWorkspace->getItem(i)); + Unit_const_sptr unit = stateWs->getAxis(0)->unit(); + if (unit->unitID() != "Wavelength") { + errorList[PropertyNames::INPUT_WORKSPACE] = "All input workspaces must be in units of Wavelength."; + } } } @@ -153,9 +157,8 @@ void PolarizerEfficiency::calculatePolarizerEfficiency() { void PolarizerEfficiency::saveToFile(MatrixWorkspace_sptr const &workspace, std::string const &filePathStr) { std::filesystem::path filePath = filePathStr; // Add the nexus extension if it's not been applied already. - const std::string fileExtension = ".nxs"; - if (filePath.extension() != fileExtension) { - filePath.replace_extension(fileExtension); + if (filePath.extension() != FILE_EXTENSION) { + filePath.replace_extension(FILE_EXTENSION); } auto saveAlg = createChildAlgorithm("SaveNexus"); saveAlg->initialize();