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..ecfe4df24e09 --- /dev/null +++ b/Framework/Algorithms/inc/MantidAlgorithms/PolarizationCorrections/PolarizerEfficiency.h @@ -0,0 +1,46 @@ +// 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 +#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 convertToHistIfNecessary(const MatrixWorkspace_sptr ws); + void saveToFile(MatrixWorkspace_sptr const &workspace, std::string const &filePathStr); +}; + +} // 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..cd8f640c09c1 --- /dev/null +++ b/Framework/Algorithms/src/PolarizationCorrections/PolarizerEfficiency.cpp @@ -0,0 +1,188 @@ +// 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/Axis.h" +#include "MantidAPI/FileProperty.h" +#include "MantidAPI/HistogramValidator.h" +#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" +#include "MantidKernel/Unit.h" + +#include +#include + +namespace Mantid::Algorithms { +// Register the algorithm into the algorithm factory +DECLARE_ALGORITHM(PolarizerEfficiency) + +using namespace Kernel; +using namespace API; + +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"; +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), + "Input group workspace to use for polarization calculation"); + const auto &wavelengthValidator = std::make_shared("Wavelength"); + 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, 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."); +} + +/** + * 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 WorkspaceGroup_sptr inputWorkspace = getProperty(PropertyNames::INPUT_WORKSPACE); + if (inputWorkspace == nullptr) { + errorList[PropertyNames::INPUT_WORKSPACE] = "The input workspace is not a workspace group."; + return errorList; + } + + if (inputWorkspace->size() != 4) { + errorList[PropertyNames::INPUT_WORKSPACE] = + "The input group workspace must have four periods corresponding to the four spin configurations."; + } 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."; + } + } + } + + // 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; +} + +/** + * Explicitly calls validateInputs and throws runtime error in case + * of issues in the input properties. + */ +void PolarizerEfficiency::validateGroupInput() { + const auto &results = validateInputs(); + if (results.size() > 0) { + const auto &result = results.cbegin(); + 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)); + 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); + + 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"); + + const auto &effPolarizer = (t00Ws - t01Ws) / (4 * (2 * effCell - 1) * (t00Ws + t01Ws)) + 0.5; + + 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. + if (filePath.extension() != FILE_EXTENSION) { + filePath.replace_extension(FILE_EXTENSION); + } + 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) { + if (ws->isHistogramData() && ws->isDistribution()) + return ws; + + MatrixWorkspace_sptr wsClone = 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 new file mode 100644 index 000000000000..a8a8ee954f2f --- /dev/null +++ b/Framework/Algorithms/test/PolarizationCorrections/PolarizerEfficiencyTest.h @@ -0,0 +1,263 @@ +// 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 "MantidKernel/ConfigService.h" + +#include +#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"); + m_defaultSaveDirectory = Kernel::ConfigService::Instance().getString("defaultsave.directory"); + } + + void tearDown() override { + AnalysisDataService::Instance().clear(); + Kernel::ConfigService::Instance().setString("defaultsave.directory", m_defaultSaveDirectory); + } + + 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(); + TS_ASSERT_THROWS(polariserEfficiency->setProperty("InputWorkspace", ws1), const std::invalid_argument &); + } + + 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(); + polariserEfficiency->setProperty("InputWorkspace", wsGrp); + TS_ASSERT_THROWS(polariserEfficiency->execute(), const std::runtime_error &); + } + + 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, tAnti1, tPara1}); + + 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 7/12 + for (const double &y : calculatedPolariserEfficiency->dataY(0)) { + TS_ASSERT_DELTA(7.0 / 12.0, 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 + 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); + } + } + + /// 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) { + 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->setProperty("Distribution", true); + 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); + result->setYUnit(""); + result->setDistribution(true); + return result; + } + + IAlgorithm_sptr createPolarizerEfficiencyAlgorithm(WorkspaceGroup_sptr inputGrp = nullptr, + const bool setOutputWs = true) { + 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); + if (setOutputWs) { + 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..0837808b8309 --- /dev/null +++ b/docs/source/algorithms/PolarizerEfficiency-v1.rst @@ -0,0 +1,55 @@ + +.. 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``. + +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})} + +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}}{4(2\epsilon_{cell} - 1)(T_{00} + T_{01})} + +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.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.1))',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.0 Å 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