diff --git a/Framework/API/inc/MantidAPI/MatrixWorkspace.h b/Framework/API/inc/MantidAPI/MatrixWorkspace.h index 9377027226e6eeb8ce4a2879b76a77dd72a66904..3fb7b0b087b41bd8f0f7ad1f52f261f34f946adf 100644 --- a/Framework/API/inc/MantidAPI/MatrixWorkspace.h +++ b/Framework/API/inc/MantidAPI/MatrixWorkspace.h @@ -414,7 +414,7 @@ public: /// to point-like) virtual bool isHistogramData() const; - /// Returns true if the workspace contains has common X bins + /// Returns true if the workspace contains common X bins virtual bool isCommonBins() const; std::string YUnit() const; diff --git a/Framework/Algorithms/CMakeLists.txt b/Framework/Algorithms/CMakeLists.txt index 6514e828c709ee4ed3f41a3a853f1362a53525d9..d513840a134f95c5ba095507bba5e1b684539c14 100644 --- a/Framework/Algorithms/CMakeLists.txt +++ b/Framework/Algorithms/CMakeLists.txt @@ -182,6 +182,7 @@ set ( SRC_FILES src/MaskBinsIf.cpp src/MaskDetectorsIf.cpp src/MaskInstrument.cpp + src/MaskNonOverlappingBins.cpp src/MatrixWorkspaceAccess.cpp src/Max.cpp src/MaxEnt.cpp @@ -517,6 +518,7 @@ set ( INC_FILES inc/MantidAlgorithms/MaskBinsIf.h inc/MantidAlgorithms/MaskDetectorsIf.h inc/MantidAlgorithms/MaskInstrument.h + inc/MantidAlgorithms/MaskNonOverlappingBins.h inc/MantidAlgorithms/MatrixWorkspaceAccess.h inc/MantidAlgorithms/Max.h inc/MantidAlgorithms/MaxEnt.h @@ -862,6 +864,7 @@ set ( TEST_FILES MaskBinsTest.h MaskDetectorsIfTest.h MaskInstrumentTest.h + MaskNonOverlappingBinsTest.h MaxEnt/MaxentCalculatorTest.h MaxEnt/MaxentEntropyNegativeValuesTest.h MaxEnt/MaxentEntropyPositiveValuesTest.h diff --git a/Framework/Algorithms/inc/MantidAlgorithms/MaskBins.h b/Framework/Algorithms/inc/MantidAlgorithms/MaskBins.h index 0fac7baa6c67c836c169310ce588ebd682c714c8..67ad013469b1b174c24e474a5791dfbb54bdd414 100644 --- a/Framework/Algorithms/inc/MantidAlgorithms/MaskBins.h +++ b/Framework/Algorithms/inc/MantidAlgorithms/MaskBins.h @@ -50,7 +50,7 @@ public: /// Algorithm's version int version() const override { return (1); } const std::vector<std::string> seeAlso() const override { - return {"MaskBinsFromTable"}; + return {"MaskBinsIf, MaskBinsFromTable, MaskNonOverlappingBins"}; } /// Algorithm's category for identification const std::string category() const override { return "Transforms\\Masking"; } diff --git a/Framework/Algorithms/inc/MantidAlgorithms/MaskNonOverlappingBins.h b/Framework/Algorithms/inc/MantidAlgorithms/MaskNonOverlappingBins.h new file mode 100644 index 0000000000000000000000000000000000000000..f53383a50d4011a90aba82974cd5a82c688ccb8e --- /dev/null +++ b/Framework/Algorithms/inc/MantidAlgorithms/MaskNonOverlappingBins.h @@ -0,0 +1,46 @@ +// 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_MASKNONOVERLAPPINGBINS_H_ +#define MANTID_ALGORITHMS_MASKNONOVERLAPPINGBINS_H_ + +#include "MantidAPI/Algorithm.h" +#include "MantidAlgorithms/DllConfig.h" + +namespace Mantid { +namespace Algorithms { + +/** MaskNonOverlappingBins : Compares the X ranges of two workspace and + * masks the non-overlapping bins in the first workspace. + */ +class MANTID_ALGORITHMS_DLL MaskNonOverlappingBins : public API::Algorithm { +public: + std::string const name() const override; + int version() const override; + std::string const category() const override; + std::string const summary() const override; + std::vector<std::string> const seeAlso() const override; + +private: + void init() override; + void exec() override; + std::map<std::string, std::string> validateInputs() override; + void checkXSorting(API::MatrixWorkspace const &inputWS, + API::MatrixWorkspace const &comparisonWS); + bool isCommonBins(API::MatrixWorkspace const &inputWS, + API::MatrixWorkspace const &comparisonWS); + void processRagged(API::MatrixWorkspace const &inputWS, + API::MatrixWorkspace const &comparisonWS, + API::MatrixWorkspace &outputWS); + void processNonRagged(API::MatrixWorkspace const &inputWS, + API::MatrixWorkspace const &comparisonWS, + API::MatrixWorkspace &outputWS); +}; + +} // namespace Algorithms +} // namespace Mantid + +#endif /* MANTID_ALGORITHMS_MASKNONOVERLAPPINGBINS_H_ */ diff --git a/Framework/Algorithms/src/MaskNonOverlappingBins.cpp b/Framework/Algorithms/src/MaskNonOverlappingBins.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d16050832f195ee10aff7c525054974f9249dbf1 --- /dev/null +++ b/Framework/Algorithms/src/MaskNonOverlappingBins.cpp @@ -0,0 +1,256 @@ +// 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 + +#include "MantidAlgorithms/MaskNonOverlappingBins.h" + +#include "MantidAPI/Axis.h" +#include "MantidAPI/MatrixWorkspace.h" +#include "MantidKernel/ListValidator.h" +#include "MantidKernel/MultiThreaded.h" +#include "MantidKernel/Unit.h" + +namespace { +/// Constants for the algorithm's property names. +namespace Prop { +std::string const CHECK_SORTING{"CheckSortedX"}; +std::string const COMPARISON_WS{"ComparisonWorkspace"}; +std::string const INPUT_WS{"InputWorkspace"}; +std::string const MASK_PARTIAL{"MaskPartiallyOverlapping"}; +std::string const OUTPUT_WS{"OutputWorkspace"}; +std::string const RAGGEDNESS{"RaggedInputs"}; +} // namespace Prop +/// Constants for the RaggedInputs property. +namespace Raggedness { +std::string const CHECK{"Check"}; +std::string const RAGGED{"Ragged"}; +std::string const NONRAGGED{"Common Bins"}; +} // namespace Raggedness + +/// Return true if X data is sorted in ascending order. +bool isXSorted(Mantid::API::MatrixWorkspace const &ws) { + int unsorted{0}; + PARALLEL_FOR_IF(Mantid::Kernel::threadSafe(ws)) + for (int64_t i = 0; static_cast<size_t>(i) < ws.getNumberHistograms(); ++i) { + auto const &Xs = ws.x(static_cast<size_t>(i)); + if (!std::is_sorted(Xs.cbegin(), Xs.cend())) { + PARALLEL_ATOMIC + ++unsorted; + } + } + return unsorted == 0; +} + +/// Holds limiting bin indices for masking +struct BinIndices { + size_t frontEndIndex; ///< Mask from 0 to this index. + size_t backBeginIndex; ///< Mask from this index to size. +}; + +/// Return the proper masking limits for non-overlapping bins. +BinIndices maskingLimits(Mantid::API::MatrixWorkspace const &ws, + Mantid::API::MatrixWorkspace const &comparisonWS, + bool const maskPartial, size_t const histogramIndex) { + auto const &Xs = ws.x(histogramIndex); + auto const &comparisonXs = comparisonWS.x(histogramIndex); + // At the moment we only support increasing X. + auto const startX = comparisonXs.front(); + auto const endX = comparisonXs.back(); + // There is no Y corresponding to the last bin edge, + // therefore iterate only to cend() - 1. + auto frontEnd = std::lower_bound(Xs.cbegin(), Xs.cend() - 1, startX); + if (!maskPartial && frontEnd != Xs.cbegin() && *frontEnd != startX) { + --frontEnd; + } + auto backBegin = std::lower_bound(frontEnd, Xs.cend() - 1, endX); + if (maskPartial && backBegin != Xs.cbegin() && *backBegin > endX) { + --backBegin; + } + BinIndices limits; + limits.frontEndIndex = + static_cast<size_t>(std::distance(Xs.cbegin(), frontEnd)); + limits.backBeginIndex = + static_cast<size_t>(std::distance(Xs.cbegin(), backBegin)); + return limits; +} + +/// Mask the start and end of histogram at histogram index. +void maskBinsWithinLimits(Mantid::API::MatrixWorkspace &ws, + size_t const histogramIndex, + BinIndices const &limits) { + auto const xSize = ws.x(histogramIndex).size(); + for (size_t binIndex = 0; binIndex < limits.frontEndIndex; ++binIndex) { + ws.flagMasked(histogramIndex, binIndex); + } + for (size_t binIndex = limits.backBeginIndex; binIndex < xSize - 1; + ++binIndex) { + ws.flagMasked(histogramIndex, binIndex); + } +} +} // namespace + +namespace Mantid { +namespace Algorithms { +DECLARE_ALGORITHM(MaskNonOverlappingBins) + +/// Algorithms name for identification. @see Algorithm::name +std::string const MaskNonOverlappingBins::name() const { + return "MaskNonOverlappingBins"; +} + +/// Algorithm's version for identification. @see Algorithm::version +int MaskNonOverlappingBins::version() const { return 1; } + +/// Algorithm's category for identification. @see Algorithm::category +std::string const MaskNonOverlappingBins::category() const { + return "Transforms\\Masking"; +} + +/// Algorithm's summary for use in the GUI and help. @see Algorithm::summary +std::string const MaskNonOverlappingBins::summary() const { + return "Marks bins in InputWorkspace which are out of the X range of the " + "second workspace."; +} + +/// Return a list of the names of related algorithms. +std::vector<std::string> const MaskNonOverlappingBins::seeAlso() const { + return {"MaskBins", "MaskBinsIf"}; +} + +/** Initialize the algorithm's properties. + */ +void MaskNonOverlappingBins::init() { + declareProperty(Kernel::make_unique<API::WorkspaceProperty<>>( + Prop::INPUT_WS, "", Kernel::Direction::Input), + "A workspace to mask."); + declareProperty(Kernel::make_unique<API::WorkspaceProperty<>>( + Prop::OUTPUT_WS, "", Kernel::Direction::Output), + "The masked workspace."); + declareProperty(Kernel::make_unique<API::WorkspaceProperty<>>( + Prop::COMPARISON_WS, "", Kernel::Direction::Input), + "A workspace to compare the InputWorkspace's binning to."); + declareProperty(Prop::MASK_PARTIAL, false, + "If true, mask also bins that overlap only partially."); + std::vector<std::string> const options{Raggedness::CHECK, Raggedness::RAGGED, + Raggedness::NONRAGGED}; + auto raggednessOptions = + boost::make_shared<Kernel::ListValidator<std::string>>(options); + declareProperty(Prop::RAGGEDNESS, Raggedness::CHECK, raggednessOptions, + "Choose whether the input workspaces have common bins, are " + "ragged, or if the algorithm should check."); + declareProperty( + Prop::CHECK_SORTING, true, + "If true, the algorithm ensures that both workspaces have X sorted in " + "ascending order."); +} + +/// Returns a map from property name to message in case of invalid values. +std::map<std::string, std::string> MaskNonOverlappingBins::validateInputs() { + std::map<std::string, std::string> issues; + API::MatrixWorkspace_const_sptr inputWS = getProperty(Prop::INPUT_WS); + API::MatrixWorkspace_const_sptr comparisonWS = + getProperty(Prop::COMPARISON_WS); + if (inputWS->getNumberHistograms() != comparisonWS->getNumberHistograms()) { + issues[Prop::COMPARISON_WS] = + "The number of histogams mismatches with " + Prop::INPUT_WS; + } + if (!inputWS->isHistogramData()) { + issues[Prop::INPUT_WS] = + "The workspace contains point data, not histograms."; + } + if (!comparisonWS->isHistogramData()) { + issues[Prop::COMPARISON_WS] = + "The workspace contains point data, not histograms."; + } + auto const inputAxis = inputWS->getAxis(0); + auto const comparisonAxis = comparisonWS->getAxis(0); + if (inputAxis && comparisonAxis) { + if (*(inputAxis->unit()) != *(comparisonAxis->unit())) { + issues[Prop::COMPARISON_WS] = + "X units do not match with " + Prop::INPUT_WS; + } + } + return issues; +} + +/** Execute the algorithm. + */ +void MaskNonOverlappingBins::exec() { + API::MatrixWorkspace_sptr inputWS = getProperty(Prop::INPUT_WS); + API::MatrixWorkspace_sptr outputWS = getProperty(Prop::OUTPUT_WS); + if (inputWS != outputWS) { + outputWS = inputWS->clone(); + } + API::MatrixWorkspace_const_sptr comparisonWS = + getProperty(Prop::COMPARISON_WS); + checkXSorting(*inputWS, *comparisonWS); + if (isCommonBins(*inputWS, *comparisonWS)) { + processNonRagged(*inputWS, *comparisonWS, *outputWS); + } else { + processRagged(*inputWS, *comparisonWS, *outputWS); + } + setProperty(Prop::OUTPUT_WS, outputWS); +} + +/// Throw if the workspaces don't have sorted X. +void MaskNonOverlappingBins::checkXSorting( + API::MatrixWorkspace const &inputWS, + API::MatrixWorkspace const &comparisonWS) { + bool const checkSorting = getProperty(Prop::CHECK_SORTING); + if (checkSorting) { + if (!isXSorted(inputWS)) { + throw std::invalid_argument(Prop::INPUT_WS + " has unsorted X."); + } + if (!isXSorted(comparisonWS)) { + throw std::invalid_argument(Prop::COMPARISON_WS + " has unsorted X."); + } + } +} + +/// Return true if the workspaces should be considered as having common bins. +bool MaskNonOverlappingBins::isCommonBins( + API::MatrixWorkspace const &inputWS, + API::MatrixWorkspace const &comparisonWS) { + std::string const choice = getProperty(Prop::RAGGEDNESS); + if (choice == Raggedness::CHECK) { + return inputWS.isCommonBins() && comparisonWS.isCommonBins(); + } else { + return choice == Raggedness::NONRAGGED; + } +} + +/// Mask all types of workspaces, ragged or nonragged. +void MaskNonOverlappingBins::processRagged( + API::MatrixWorkspace const &inputWS, + API::MatrixWorkspace const &comparisonWS, API::MatrixWorkspace &outputWS) { + bool const maskPartial = getProperty(Prop::MASK_PARTIAL); + auto const nHist = inputWS.getNumberHistograms(); + API::Progress progress(this, 0., 1., nHist); + // Tried to parallelize this loop but the performance test showed + // regression. Hence no PARALLEL_FOR_IF. + for (size_t histogramIndex = 0; histogramIndex < nHist; ++histogramIndex) { + auto const limits = + maskingLimits(inputWS, comparisonWS, maskPartial, histogramIndex); + maskBinsWithinLimits(outputWS, histogramIndex, limits); + progress.report("Masking nonoverlapping bins"); + } +} + +/// Mask only workspace with same X in all histograms. +void MaskNonOverlappingBins::processNonRagged( + API::MatrixWorkspace const &inputWS, + API::MatrixWorkspace const &comparisonWS, API::MatrixWorkspace &outputWS) { + bool const maskPartial = getProperty(Prop::MASK_PARTIAL); + auto const nHist = inputWS.getNumberHistograms(); + API::Progress progress(this, 0., 1., nHist); + auto const limits = maskingLimits(inputWS, comparisonWS, maskPartial, 0); + for (size_t histogramIndex = 0; histogramIndex < nHist; ++histogramIndex) { + maskBinsWithinLimits(outputWS, histogramIndex, limits); + progress.report("Masking nonoverlapping bins"); + } +} + +} // namespace Algorithms +} // namespace Mantid diff --git a/Framework/Algorithms/test/MaskNonOverlappingBinsTest.h b/Framework/Algorithms/test/MaskNonOverlappingBinsTest.h new file mode 100644 index 0000000000000000000000000000000000000000..ed8ec214c3cf6dea099d3b2220eaafc992522fee --- /dev/null +++ b/Framework/Algorithms/test/MaskNonOverlappingBinsTest.h @@ -0,0 +1,208 @@ +// 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_MaskNonOverlappingBinsTEST_H_ +#define MANTID_ALGORITHMS_MaskNonOverlappingBinsTEST_H_ + +#include <cxxtest/TestSuite.h> + +#include "MantidAlgorithms/MaskNonOverlappingBins.h" +#include "MantidDataObjects/Workspace2D.h" +#include "MantidDataObjects/WorkspaceCreation.h" +#include "MantidHistogramData/BinEdges.h" +#include "MantidHistogramData/Counts.h" +#include "MantidHistogramData/LinearGenerator.h" + +#include <array> + +using namespace Mantid; + +class MaskNonOverlappingBinsTest : public CxxTest::TestSuite { +public: + // This pair of boilerplate methods prevent the suite being created statically + // This means the constructor isn't called when running other tests + static MaskNonOverlappingBinsTest *createSuite() { + return new MaskNonOverlappingBinsTest(); + } + static void destroySuite(MaskNonOverlappingBinsTest *suite) { delete suite; } + + void test_init() { + Algorithms::MaskNonOverlappingBins alg; + TS_ASSERT_THROWS_NOTHING(alg.initialize()) + TS_ASSERT(alg.isInitialized()) + } + + void test_maskBegin() { + HistogramData::BinEdges comparison{-1.1, -0.1}; + auto const expected = API::MatrixWorkspace::MaskList{{1, 1.}, {2, 1.}}; + runTestWithAlwaysSameExpectedOutcome(std::move(comparison), expected); + } + + void test_maskCentre() { + HistogramData::BinEdges comparison{-0.1, 0.9}; + auto const expected = API::MatrixWorkspace::MaskList{{0, 1.}, {2, 1.}}; + runTestWithAlwaysSameExpectedOutcome(std::move(comparison), expected); + } + + void test_maskEnd() { + HistogramData::BinEdges comparison{0.9, 1.8}; + auto const expected = API::MatrixWorkspace::MaskList{{0, 1.}, {1, 1.}}; + runTestWithAlwaysSameExpectedOutcome(std::move(comparison), expected); + } + + void test_maskAll() { + HistogramData::BinEdges comparison{-13., -1.1}; + auto const expected = + API::MatrixWorkspace::MaskList{{0, 1.}, {1, 1.}, {2, 1.}}; + runTestWithAlwaysSameExpectedOutcome(std::move(comparison), expected); + comparison = {1.8, 13.}; + runTestWithAlwaysSameExpectedOutcome(std::move(comparison), expected); + } + + void test_partialOverlapMasking() { + HistogramData::BinEdges const comparison{0., 0.1}; + auto expected = API::MatrixWorkspace::MaskList{{0, 1.}, {1, 1.}, {2, 1.}}; + runTestWithMatchingBins(comparison, expected, true); + expected = {{0, 1.}, {2, 1.}}; + runTestWithMatchingBins(comparison, expected, false); + } + + void test_maskNone() { + HistogramData::BinEdges const comparison{-13., 13.}; + auto const expected = API::MatrixWorkspace::MaskList(); + runTestWithAlwaysSameExpectedOutcome(comparison, expected); + } + + void test_unsortedXThrows() { + API::MatrixWorkspace_sptr inputWS = + makeWorkspace(HistogramData::BinEdges{-1.1, -0.1, 0.2, 1.8}); + inputWS->mutableX(0)[2] = -0.9; + API::MatrixWorkspace_sptr comparisonWS = + makeWorkspace(HistogramData::BinEdges{-1.1, 1.8}); + Algorithms::MaskNonOverlappingBins alg; + alg.setChild(true); + alg.setRethrows(true); + TS_ASSERT_THROWS_NOTHING(alg.initialize()) + TS_ASSERT(alg.isInitialized()) + TS_ASSERT_THROWS_NOTHING(alg.setProperty("InputWorkspace", inputWS)) + TS_ASSERT_THROWS_NOTHING( + alg.setPropertyValue("OutputWorkspace", "_unused_for_child")) + TS_ASSERT_THROWS_NOTHING( + alg.setProperty("ComparisonWorkspace", comparisonWS)) + TS_ASSERT_THROWS_EQUALS(alg.execute(), std::invalid_argument const &e, + e.what(), + std::string("InputWorkspace has unsorted X.")) + TS_ASSERT(!alg.isExecuted()) + } + +private: + template <typename BinEdges> + static API::MatrixWorkspace_sptr makeWorkspace(BinEdges &&binEdges) { + HistogramData::BinEdges edges(std::forward<BinEdges>(binEdges)); + HistogramData::Counts counts(edges.size() - 1, 2); + return DataObjects::create<DataObjects::Workspace2D>( + 1, HistogramData::Histogram(edges, counts)); + } + + static void runTestWithAlwaysSameExpectedOutcome( + HistogramData::BinEdges comparisonBinEdges, + API::MatrixWorkspace::MaskList const &expected) { + runTestWithMatchingBins(comparisonBinEdges, expected, true); + runTestWithMatchingBins(std::move(comparisonBinEdges), expected, false); + } + + template <typename BinEdges> + static void + runTestWithMatchingBins(BinEdges &&comparisonBinEdges, + API::MatrixWorkspace::MaskList const &expected, + bool const maskPartial) { + API::MatrixWorkspace_sptr inputWS = + makeWorkspace(HistogramData::BinEdges{-1.1, -0.1, 0.9, 1.8}); + API::MatrixWorkspace_sptr comparisonWS = + makeWorkspace(std::forward<BinEdges>(comparisonBinEdges)); + std::array<std::string, 3> raggedOptions{ + {"Check", "Ragged", "Common Bins"}}; + for (auto const &raggedness : raggedOptions) { + Algorithms::MaskNonOverlappingBins alg; + alg.setChild(true); + alg.setRethrows(true); + TS_ASSERT_THROWS_NOTHING(alg.initialize()) + TS_ASSERT(alg.isInitialized()) + TS_ASSERT_THROWS_NOTHING(alg.setProperty("InputWorkspace", inputWS)) + TS_ASSERT_THROWS_NOTHING( + alg.setPropertyValue("OutputWorkspace", "_unused_for_child")) + TS_ASSERT_THROWS_NOTHING( + alg.setProperty("ComparisonWorkspace", comparisonWS)) + TS_ASSERT_THROWS_NOTHING( + alg.setProperty("MaskPartiallyOverlapping", maskPartial)) + TS_ASSERT_THROWS_NOTHING(alg.setProperty("RaggedInputs", raggedness)) + TS_ASSERT_THROWS_NOTHING(alg.execute()) + TS_ASSERT(alg.isExecuted()) + API::MatrixWorkspace_sptr outputWS = alg.getProperty("OutputWorkspace"); + TS_ASSERT(outputWS); + TS_ASSERT_EQUALS(outputWS->getNumberHistograms(), 1) + if (!expected.empty()) { + auto const mask = outputWS->maskedBins(0); + TS_ASSERT_EQUALS(mask, expected) + } else { + TS_ASSERT(!outputWS->hasMaskedBins(0)) + } + } + } +}; + +class MaskNonOverlappingBinsTestPerformance : public CxxTest::TestSuite { +public: + // This pair of boilerplate methods prevent the suite being created statically + // This means the constructor isn't called when running other tests + static MaskNonOverlappingBinsTestPerformance *createSuite() { + return new MaskNonOverlappingBinsTestPerformance(); + } + static void destroySuite(MaskNonOverlappingBinsTestPerformance *suite) { + delete suite; + } + + void setUp() override { + HistogramData::BinEdges edges(1000, + HistogramData::LinearGenerator(-100., 23.)); + HistogramData::Counts counts(edges.size() - 1, 2); + m_ws = DataObjects::create<DataObjects::Workspace2D>( + 10000, HistogramData::Histogram(edges, counts)); + edges = + HistogramData::BinEdges(200, HistogramData::LinearGenerator(-10., 2.3)); + counts = HistogramData::Counts(edges.size() - 1, 2); + m_compWS = DataObjects::create<DataObjects::Workspace2D>( + 10000, HistogramData::Histogram(edges, counts)); + m_alg.initialize(); + m_alg.setChild(true); + m_alg.setRethrows(true); + m_alg.setProperty("InputWorkspace", m_ws); + m_alg.setPropertyValue("OutputWorkspace", "_unused_for_child"); + m_alg.setProperty("ComparisonWorkspace", m_compWS); + m_alg.setProperty("MaskPartiallyOverlapping", true); + } + + void test_default() { TS_ASSERT_THROWS_NOTHING(m_alg.execute()) } + + void test_nonragged() { + m_alg.setProperty("CheckSortedX", false); + m_alg.setProperty("RaggedInputs", "Common Bins"); + TS_ASSERT_THROWS_NOTHING(m_alg.execute()) + } + + void test_ragged() { + m_alg.setProperty("CheckSortedX", false); + m_alg.setProperty("RaggedInputs", "Ragged"); + TS_ASSERT_THROWS_NOTHING(m_alg.execute()) + } + +private: + API::MatrixWorkspace_sptr m_ws; + API::MatrixWorkspace_sptr m_compWS; + Algorithms::MaskNonOverlappingBins m_alg; +}; + +#endif /* MANTID_ALGORITHMS_MaskNonOverlappingBinsTEST_H_ */ diff --git a/docs/source/algorithms/MaskNonOverlappingBins-v1.rst b/docs/source/algorithms/MaskNonOverlappingBins-v1.rst new file mode 100644 index 0000000000000000000000000000000000000000..28337edfd11d6627558e95988975aad18fb0c26d --- /dev/null +++ b/docs/source/algorithms/MaskNonOverlappingBins-v1.rst @@ -0,0 +1,48 @@ + +.. algorithm:: + +.. summary:: + +.. relatedalgorithms:: + +.. properties:: + +Description +----------- + +This algorithm masks the bins in ``InputWorkspace`` which lie in :math:`X` range that is not covered by ``ComparisonWorkspace``. The ``MaskPartiallyOverlapping`` flag affect the behavior with regards to bins which are partially covered by ``ComparisonWorkspace``. The algorithm works only with the X data sorted in ascending order. + +The algorithm currently applies the default masking weight to the bins which does not clear the data. + +Optimizations +############# + +Some small optimizations are possible via ``CheckSortedX`` and ``RaggedInputs``. Make sure the input workspaces fill the expectations before using these properties! + +- If there is no doubt that X data in ``InputWorkspace`` and ``ComparisonWorkspace`` is sorted, the checking for ascending X can be skipped by setting ``CheckSortedX`` to ``False``. +- If ``RaggedInputs`` is set to ``'Check'`` (the default), the algorithm will check if both ``InputWorkspace`` and ``ComparisonWorkspace`` are :ref:`ragged workspaces <Ragged_Workspace>` and choose the processing method accordingly. The test can be skipped by setting ``RaggedInputs`` to ``'Ragged'`` or ``'Common Bins'`` which forces a specific processing method. + +Usage +----- + +**Example - MaskNonOverlappingBins** + +.. testcode:: MaskNonOverlappingBinsExample + + bigWS = CreateSampleWorkspace(XMin=0, XMax=20000) + smallWS = CreateSampleWorkspace(XMin=9000, XMax=11000) + masked = MaskNonOverlappingBins(bigWS, smallWS) + print('It is not (yet) possible to access the bin masking information in Python.') + print('Please check that the correct bins are grayed out in the data view.') + +Output: + +.. testoutput:: MaskNonOverlappingBinsExample + + It is not (yet) possible to access the bin masking information in Python. + Please check that the correct bins are grayed out in the data view. + +.. categories:: + +.. sourcelink:: + diff --git a/docs/source/release/v3.14.0/framework.rst b/docs/source/release/v3.14.0/framework.rst index 31971ef23f9b1ddc24980dba41f1b95425e1038b..be679ff13a52f091ce2e44d8210e656c564fb51c 100644 --- a/docs/source/release/v3.14.0/framework.rst +++ b/docs/source/release/v3.14.0/framework.rst @@ -42,6 +42,7 @@ New Algorithms - :ref:`CalculateDynamicRange <algm-CalculateDynamicRange>` will calculate the Q range of a SANS workspace. - :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. +- :ref:`MaskNonOverlappingBins <algm-MaskNonOverlappingBins>` masks the bins that do not overlap with another workspace. Improvements ############