diff --git a/Framework/Algorithms/CMakeLists.txt b/Framework/Algorithms/CMakeLists.txt index d7c643cdd072ce4de5db4cbe7a9bfbbf3e7a9a29..61aaea9e61e00160e4b5d40db73f1cc6c8b4bdeb 100644 --- a/Framework/Algorithms/CMakeLists.txt +++ b/Framework/Algorithms/CMakeLists.txt @@ -18,12 +18,12 @@ set ( SRC_FILES src/Bin2DPowderDiffraction.cpp src/BinaryOperateMasks.cpp src/BinaryOperation.cpp + src/CalculateCarpenterSampleCorrection.cpp src/CalculateCountRate.cpp src/CalculateDIFC.cpp src/CalculateEfficiency.cpp src/CalculateFlatBackground.cpp src/CalculateIqt.cpp - src/CalculateCarpenterSampleCorrection.cpp src/CalculatePolynomialBackground.cpp src/CalculateSlits.cpp src/CalculateTransmission.cpp @@ -177,6 +177,7 @@ set ( SRC_FILES src/MagFormFactorCorrection.cpp src/MaskBins.cpp src/MaskBinsFromTable.cpp + src/MaskBinsIf.cpp src/MaskDetectorsIf.cpp src/MaskInstrument.cpp src/MatrixWorkspaceAccess.cpp @@ -348,12 +349,12 @@ set ( INC_FILES inc/MantidAlgorithms/BinaryOperateMasks.h inc/MantidAlgorithms/BinaryOperation.h inc/MantidAlgorithms/BoostOptionalToAlgorithmProperty.h + inc/MantidAlgorithms/CalculateCarpenterSampleCorrection.h inc/MantidAlgorithms/CalculateCountRate.h inc/MantidAlgorithms/CalculateDIFC.h inc/MantidAlgorithms/CalculateEfficiency.h inc/MantidAlgorithms/CalculateFlatBackground.h inc/MantidAlgorithms/CalculateIqt.h - inc/MantidAlgorithms/CalculateCarpenterSampleCorrection.h inc/MantidAlgorithms/CalculatePolynomialBackground.h inc/MantidAlgorithms/CalculateSlits.h inc/MantidAlgorithms/CalculateTransmission.h @@ -508,6 +509,7 @@ set ( INC_FILES inc/MantidAlgorithms/MagFormFactorCorrection.h inc/MantidAlgorithms/MaskBins.h inc/MantidAlgorithms/MaskBinsFromTable.h + inc/MantidAlgorithms/MaskBinsIf.h inc/MantidAlgorithms/MaskDetectorsIf.h inc/MantidAlgorithms/MaskInstrument.h inc/MantidAlgorithms/MatrixWorkspaceAccess.h @@ -847,6 +849,7 @@ set ( TEST_FILES MCInteractionVolumeTest.h MagFormFactorCorrectionTest.h MaskBinsFromTableTest.h + MaskBinsIfTest.h MaskBinsTest.h MaskDetectorsIfTest.h MaskInstrumentTest.h diff --git a/Framework/Algorithms/inc/MantidAlgorithms/MaskBinsIf.h b/Framework/Algorithms/inc/MantidAlgorithms/MaskBinsIf.h new file mode 100644 index 0000000000000000000000000000000000000000..6b6518af15981b53c4d7eb31d6e581fa9629f571 --- /dev/null +++ b/Framework/Algorithms/inc/MantidAlgorithms/MaskBinsIf.h @@ -0,0 +1,38 @@ +// Mantid Repository : https://github.com/mantidproject/mantid +// +// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI, +// NScD Oak Ridge National Laboratory, European Spallation Source +// & Institut Laue - Langevin +// SPDX - License - Identifier: GPL - 3.0 + +#ifndef MANTID_ALGORITHMS_MASKBINSIF_H_ +#define MANTID_ALGORITHMS_MASKBINSIF_H_ + +#include "MantidAlgorithms/DllConfig.h" +#include "MantidAPI/Algorithm.h" + +namespace Mantid { +namespace Algorithms { + +/** MaskBinsIf : Masks bins based on muparser expression +*/ +class MANTID_ALGORITHMS_DLL MaskBinsIf : public API::Algorithm { +public: + const std::string name() const override { return "MaskBinsIf"; } + int version() const override { return 1; } + const std::string category() const override { return "Transforms\\Masking"; } + const std::string summary() const override { + return "Masks bins based on muparser expression"; + } + const std::vector<std::string> seeAlso() const override { + return {"MaskBins"}; + } + +private: + void init() override; + void exec() override; +}; + +} // namespace Algorithms +} // namespace Mantid + +#endif /* MANTID_ALGORITHMS_MASKBINSIF_H_ */ diff --git a/Framework/Algorithms/src/MaskBinsIf.cpp b/Framework/Algorithms/src/MaskBinsIf.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a8de35d07b31540575ec15577f17adbd3e175d7d --- /dev/null +++ b/Framework/Algorithms/src/MaskBinsIf.cpp @@ -0,0 +1,94 @@ +#include "MantidAlgorithms/MaskBinsIf.h" +#include "MantidAPI/MatrixWorkspace.h" +#include "MantidAPI/NumericAxis.h" +#include "MantidAPI/SpectraAxis.h" +#include "MantidHistogramData/HistogramIterator.h" +#include "MantidKernel/MultiThreaded.h" + +#include <muParser.h> + +namespace Mantid { +namespace Algorithms { +// Mantid Repository : https://github.com/mantidproject/mantid +// +// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI, +// NScD Oak Ridge National Laboratory, European Spallation Source +// & Institut Laue - Langevin +// SPDX - License - Identifier: GPL - 3.0 + +using namespace API; +using namespace Kernel; + +// Register the algorithm into the AlgorithmFactory +DECLARE_ALGORITHM(MaskBinsIf) + +//---------------------------------------------------------------------------------------------- +/** Initialize the algorithm's properties. + */ +void MaskBinsIf::init() { + declareProperty(Kernel::make_unique<WorkspaceProperty<MatrixWorkspace>>( + "InputWorkspace", "", Direction::Input), + "An input workspace."); + declareProperty("Criterion", "", + "Masking criterion as a muparser expression; y: bin count, " + "e: bin error, x: bin center, dx: bin center error, s: " + "spectrum axis value, i: workspace index."); + declareProperty(Kernel::make_unique<WorkspaceProperty<MatrixWorkspace>>( + "OutputWorkspace", "", Direction::Output), + "An output workspace."); +} + +//---------------------------------------------------------------------------------------------- +/** Execute the algorithm. + */ +void MaskBinsIf::exec() { + const std::string criterion = getPropertyValue("Criterion"); + MatrixWorkspace_const_sptr inputWorkspace = getProperty("InputWorkspace"); + MatrixWorkspace_sptr outputWorkspace = getProperty("OutputWorkspace"); + if (inputWorkspace != outputWorkspace) { + outputWorkspace = inputWorkspace->clone(); + } + const auto spectrumAxis = outputWorkspace->getAxis(1); + const auto numeric = dynamic_cast<NumericAxis *>(spectrumAxis); + const auto spectrum = dynamic_cast<SpectraAxis *>(spectrumAxis); + const bool spectrumOrNumeric = numeric || spectrum; + PARALLEL_FOR_IF(Mantid::Kernel::threadSafe(*outputWorkspace)) + for (size_t index = 0; index < outputWorkspace->getNumberHistograms(); + ++index) { + PARALLEL_START_INTERUPT_REGION + double y, e, x, dx, s, i; + dx = 0.; + s = 0.; + i = index; + mu::Parser muParser; + muParser.DefineVar("y", &y); + muParser.DefineVar("e", &e); + muParser.DefineVar("x", &x); + muParser.DefineVar("dx", &dx); + muParser.DefineVar("s", &s); + muParser.DefineVar("i", &i); + muParser.SetExpr(criterion); + if (spectrumOrNumeric) { + s = spectrumAxis->getValue(index); + } + const auto &spectrum = outputWorkspace->histogram(index); + const bool hasDx = outputWorkspace->hasDx(index); + for (auto it = spectrum.begin(); it != spectrum.end(); ++it) { + const auto bin = std::distance(spectrum.begin(), it); + y = it->counts(); + x = it->center(); + e = it->countStandardDeviation(); + if (hasDx) { + dx = it->centerError(); + } + if (muParser.Eval() != 0.) { + outputWorkspace->maskBin(index, bin); + } + } + PARALLEL_END_INTERUPT_REGION + } + PARALLEL_CHECK_INTERUPT_REGION + setProperty("OutputWorkspace", outputWorkspace); +} + +} // namespace Algorithms +} // namespace Mantid diff --git a/Framework/Algorithms/test/MaskBinsIfTest.h b/Framework/Algorithms/test/MaskBinsIfTest.h new file mode 100644 index 0000000000000000000000000000000000000000..ec15af25de3a32cda02af71f734fa774e1849db8 --- /dev/null +++ b/Framework/Algorithms/test/MaskBinsIfTest.h @@ -0,0 +1,136 @@ +// Mantid Repository : https://github.com/mantidproject/mantid +// +// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI, +// NScD Oak Ridge National Laboratory, European Spallation Source +// & Institut Laue - Langevin +// SPDX - License - Identifier: GPL - 3.0 + +#ifndef MANTID_ALGORITHMS_MASKBINSIFTEST_H_ +#define MANTID_ALGORITHMS_MASKBINSIFTEST_H_ + +#include <cxxtest/TestSuite.h> + +#include "MantidAPI/FrameworkManager.h" +#include "MantidAPI/MatrixWorkspace.h" +#include "MantidAlgorithms/CreateSampleWorkspace.h" +#include "MantidAlgorithms/CreateWorkspace.h" +#include "MantidAlgorithms/MaskBinsIf.h" + +using Mantid::Algorithms::CreateSampleWorkspace; +using Mantid::Algorithms::CreateWorkspace; +using Mantid::Algorithms::MaskBinsIf; +using Mantid::API::MatrixWorkspace_sptr; + +class MaskBinsIfTest : public CxxTest::TestSuite { +private: + MatrixWorkspace_sptr createWorkspace() { + CreateWorkspace creator; + creator.initialize(); + creator.setChild(true); + creator.setAlwaysStoreInADS(false); + const std::vector<double> x = {1.1, 2.5, 3.2, 4.5, 6.7, 8.9, + 10.3, 12.4, 13.9, 14.1, 15.3, 16.8}; + const std::vector<double> y = {7, 23, 54, 34, 23, 64, + 34, 23, 58, 63, 34, 25}; + const std::vector<double> e = {3.2, 2.1, 8.4, 3.5, 6.3, 4.7, + 4.9, 3.6, 4.1, 6.7, 5.1, 3.2}; + const std::vector<double> dx = {0.1, 0.2, 0.4, 0.7, 0.9, 1.3, + 1.5, 1.7, 1.9, 1.2, 4.5, 2.3}; + const std::vector<std::string> spectrumAxis = {"3", "7", "11", "17"}; + creator.setProperty("DataX", x); + creator.setProperty("DataY", y); + creator.setProperty("DataE", e); + creator.setProperty("Dx", dx); + creator.setProperty("NSpec", 4); + creator.setProperty("VerticalAxisValues", spectrumAxis); + creator.setProperty("VerticalAxisUnit", "Label"); + creator.setProperty("OutputWorkspace", "__unused"); + creator.execute(); + MatrixWorkspace_sptr ws = creator.getProperty("OutputWorkspace"); + return ws; + } + +public: + // This pair of boilerplate methods prevent the suite being created statically + // This means the constructor isn't called when running other tests + static MaskBinsIfTest *createSuite() { return new MaskBinsIfTest(); } + static void destroySuite(MaskBinsIfTest *suite) { delete suite; } + + void test_init() { + MaskBinsIf alg; + TS_ASSERT_THROWS_NOTHING(alg.initialize()) + TS_ASSERT(alg.isInitialized()) + } + + void test_exec() { + MaskBinsIf alg; + alg.setChild(true); + alg.setRethrows(true); + alg.setAlwaysStoreInADS(false); + TS_ASSERT_THROWS_NOTHING(alg.initialize()) + TS_ASSERT(alg.isInitialized()) + const auto inputWS = createWorkspace(); + TS_ASSERT_THROWS_NOTHING(alg.setProperty("InputWorkspace", inputWS)); + TS_ASSERT_THROWS_NOTHING( + alg.setPropertyValue("OutputWorkspace", "__unused_for_child")); + const std::string criterion = "y>50 || e>6 || s<5 || i>2 || dx>1.6"; + TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("Criterion", criterion)); + TS_ASSERT_THROWS_NOTHING(alg.execute()); + TS_ASSERT(alg.isExecuted()); + Mantid::API::MatrixWorkspace_sptr outputWS = + alg.getProperty("OutputWorkspace"); + TS_ASSERT(outputWS); + const auto maskedBins1 = outputWS->maskedBins(0); + TS_ASSERT(maskedBins1.find(0) != maskedBins1.end()); + TS_ASSERT(maskedBins1.find(1) != maskedBins1.end()); + TS_ASSERT(maskedBins1.find(2) != maskedBins1.end()); + const auto maskedBins2 = outputWS->maskedBins(1); + TS_ASSERT(maskedBins2.find(0) == maskedBins2.end()); + TS_ASSERT(maskedBins2.find(1) != maskedBins2.end()); + TS_ASSERT(maskedBins2.find(2) != maskedBins2.end()); + const auto maskedBins3 = outputWS->maskedBins(2); + TS_ASSERT(maskedBins3.find(0) == maskedBins3.end()); + TS_ASSERT(maskedBins3.find(1) != maskedBins3.end()); + TS_ASSERT(maskedBins3.find(2) != maskedBins3.end()); + const auto maskedBins4 = outputWS->maskedBins(3); + TS_ASSERT(maskedBins4.find(0) != maskedBins4.end()); + TS_ASSERT(maskedBins4.find(1) != maskedBins4.end()); + TS_ASSERT(maskedBins4.find(2) != maskedBins4.end()); + } +}; + +class MaskBinsIfTestPerformance : public CxxTest::TestSuite { +public: + static MaskBinsIfTestPerformance *createSuite() { + return new MaskBinsIfTestPerformance(); + } + static void destroySuite(MaskBinsIfTestPerformance *suite) { delete suite; } + + void setUp() override { + Mantid::API::FrameworkManager::Instance(); + CreateSampleWorkspace creator; + creator.initialize(); + creator.setChild(true); + creator.setAlwaysStoreInADS(false); + creator.setProperty("BankPixelWidth", 100); + creator.setProperty("NumBanks", 20); + creator.setProperty("BinWidth", 200.); + creator.setProperty("Random", true); + creator.setPropertyValue("OutputWorkspace", "__unused"); + creator.execute(); + Mantid::API::MatrixWorkspace_sptr ws = + creator.getProperty("OutputWorkspace"); + m_alg.initialize(); + m_alg.setChild(true); + m_alg.setAlwaysStoreInADS(false); + m_alg.setProperty("InputWorkspace", ws); + m_alg.setPropertyValue("Criterion", "y>100 || y<1"); + m_alg.setProperty("OutputWorkspace", "__out"); + } + + void test_performance() { m_alg.execute(); } + +private: + MaskBinsIf m_alg; +}; + +#endif /* MANTID_ALGORITHMS_MASKBINSIFTEST_H_ */ diff --git a/Framework/HistogramData/inc/MantidHistogramData/HistogramItem.h b/Framework/HistogramData/inc/MantidHistogramData/HistogramItem.h index ca47f52f5ca8c6481cc99308f78352482a87b7a3..d0da03dbd438c9f4e012304315306a9c996309b9 100644 --- a/Framework/HistogramData/inc/MantidHistogramData/HistogramItem.h +++ b/Framework/HistogramData/inc/MantidHistogramData/HistogramItem.h @@ -45,6 +45,11 @@ public: } } + double centerError() const { + const auto &dx = m_histogram.dx(); + return dx[m_index]; + } + double binWidth() const { const auto &x = m_histogram.x(); if (xModeIsPoints()) { diff --git a/docs/source/algorithms/MaskBinsIf-v1.rst b/docs/source/algorithms/MaskBinsIf-v1.rst new file mode 100644 index 0000000000000000000000000000000000000000..a1437f59a3a0d0672da9f8c9a005641e268f18e0 --- /dev/null +++ b/docs/source/algorithms/MaskBinsIf-v1.rst @@ -0,0 +1,35 @@ + +.. algorithm:: + +.. summary:: + +.. relatedalgorithms:: + +.. properties:: + +Description +----------- + +This algorithm masks bins according to the criteria specified as a `muparser <http://beltoforion.de/article.php?a=muparser>`_ expression. +The variables entering the criteria are reserved as follows: + +- y : count in a bin +- x : the bin center +- e : the error on the count +- dx : the error on the bin center +- i : the workspace index +- s : the value of spectrum axis, in case of SpectraAxis or NumericAxis. + +Usage +----- + +**Example - MaskBinsIf** + +.. code-block:: python + + CreateSampleWorkspace(BankPixelWidth=100, NumBanks=1, OutputWorkspace='out') + MaskBinsIf(InputWorkspace='out', Criterion='i >10 && i<20 && x>1000 && x<2000', OutputWorkspace='out') + +.. categories:: + +.. sourcelink:: diff --git a/docs/source/release/v3.14.0/framework.rst b/docs/source/release/v3.14.0/framework.rst index e0071118a39f0ba7d61c51143537a4fd532c857f..9e732a85e52e13c45a1e5a9c2e48610a184323ca 100644 --- a/docs/source/release/v3.14.0/framework.rst +++ b/docs/source/release/v3.14.0/framework.rst @@ -40,6 +40,7 @@ New Algorithms ############## - :ref:`MatchSpectra <algm-MatchSpectra>` is an algorithm that calculates factors to match all spectra to a reference spectrum. +- :ref:`MaskBinsIf <algm-MaskBinsIf>` is an algorithm to mask bins according to criteria specified as a muparser expression. Improvements ############