Skip to content
Snippets Groups Projects
MaskBinsIf.cpp 4.56 KiB
Newer Older
// 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/MaskBinsIf.h"
#include "MantidAPI/MatrixWorkspace.h"
#include "MantidAPI/NumericAxis.h"
#include "MantidAPI/Progress.h"
#include "MantidAPI/SpectraAxis.h"
#include "MantidHistogramData/HistogramIterator.h"
#include "MantidKernel/MultiThreaded.h"

#include <muParser.h>

namespace {

/**
 * @brief Makes a new instance of the muparser
 * @param y : count
 * @param e : error
 * @param x : bin center
 * @param dx : bin center error
 * @param s : spectrum axis value
 * @param criterion : expression
 * @return muparser
 */
mu::Parser makeParser(double &y, double &e, double &x, double &dx, double &s,
                      const std::string &criterion) {
  mu::Parser muParser;
  muParser.DefineVar("y", &y);
  muParser.DefineVar("e", &e);
  muParser.DefineVar("x", &x);
  muParser.DefineVar("dx", &dx);
  muParser.DefineVar("s", &s);
  muParser.SetExpr(criterion);
  return muParser;
}
namespace Mantid {
namespace Algorithms {
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.");
  declareProperty(Kernel::make_unique<WorkspaceProperty<MatrixWorkspace>>(
                      "OutputWorkspace", "", Direction::Output),
                  "An output workspace.");
}

//----------------------------------------------------------------------------------------------
/** Validate the inputs.
 */
std::map<std::string, std::string> MaskBinsIf::validateInputs() {
  std::map<std::string, std::string> issues;
  double y = 0., e = 0., x = 0., dx = 0., s = 0.;
  mu::Parser parser = makeParser(y, e, x, dx, s, getPropertyValue("Criterion"));
  try {
    parser.Eval();
  } catch (mu::Parser::exception_type &e) {
    issues["Criterion"] = "Invalid expression given: " + e.GetMsg();
  }
  return issues;
}

//----------------------------------------------------------------------------------------------
/** 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;
  if (!spectrumOrNumeric) {
    throw std::runtime_error(
        "Vertical axis must be NumericAxis or SpectraAxis");
  }
  const int64_t numberHistograms =
      static_cast<int64_t>(outputWorkspace->getNumberHistograms());
  auto progress = make_unique<Progress>(this, 0., 1., numberHistograms);
  PARALLEL_FOR_IF(Mantid::Kernel::threadSafe(*outputWorkspace))
  for (int64_t index = 0; index < numberHistograms; ++index) {
    PARALLEL_START_INTERUPT_REGION
    double y, e, x, dx;
    double s = spectrumOrNumeric ? spectrumAxis->getValue(index) : 0.;
    mu::Parser parser = makeParser(y, e, x, dx, s, criterion);
    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();
      dx = hasDx ? it->centerError() : 0.;
      if (parser.Eval() != 0.) {
        outputWorkspace->maskBin(index, bin);
    PARALLEL_END_INTERUPT_REGION
  }
  PARALLEL_CHECK_INTERUPT_REGION
  setProperty("OutputWorkspace", outputWorkspace);
}

} // namespace Algorithms
} // namespace Mantid