Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
SetUncertaintiesTest.h 10.74 KiB
// 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 & CSNS, Institute of High Energy Physics, CAS
// SPDX - License - Identifier: GPL - 3.0 +
#pragma once

#include <cxxtest/TestSuite.h>

#include "MantidAlgorithms/SetUncertainties.h"
#include "MantidTestHelpers/WorkspaceCreationHelper.h"

using namespace Mantid::Algorithms;
using namespace Mantid::Kernel;
using namespace Mantid;

class SetUncertaintiesTest : public CxxTest::TestSuite {
public:
  void test_Init() {
    SetUncertainties alg;
    TS_ASSERT_THROWS_NOTHING(alg.initialize());
    TS_ASSERT(alg.isInitialized());
  }

  /**
   * Create and execute the algorithm in the specified mode.
   * @param mode The name of the SetError property SetUncertainties
   * @return The name that the output workspace will be registered as.
   */
  API::MatrixWorkspace_sptr runAlg(const std::string &mode) {
    // random data mostly works
    auto inWksp = WorkspaceCreationHelper::create1DWorkspaceRand(30, true);
    // Ensure first elements of random workspace are zero so test don't
    // pass randomly
    auto &E = inWksp->mutableE(0);
    E[0] = 0.;
    auto &Y = inWksp->mutableY(0);
    Y[1] = 0.; // stress sqrtOrOne

    std::string outWSname = "SetUncertainties_" + mode;

    SetUncertainties alg;
    TS_ASSERT_THROWS_NOTHING(alg.initialize());
    alg.setProperty("InputWorkspace", inWksp);
    alg.setProperty("SetError", mode);
    alg.setProperty("OutputWorkspace", outWSname);
    TS_ASSERT_THROWS_NOTHING(alg.execute());
    TS_ASSERT(alg.isExecuted());

    const auto outWS =
        API::AnalysisDataService::Instance().retrieveWS<API::MatrixWorkspace>(
            outWSname);
    TS_ASSERT(bool(outWS)); // non-null pointer
    return outWS;
  }

  /**
   * Create and execute the algorithm in the specified mode.
   * @param mode The name of the SetError property SetUncertainties
   * @return The name that the output workspace will be registered as.
   */
  API::MatrixWorkspace_sptr runAlgInPlace(const std::string &mode) {
    // random data mostly works
    auto inWksp = WorkspaceCreationHelper::create1DWorkspaceRand(30, true);
    // Ensure first elements of random workspace are zero so test don't
    // pass randomly
    auto &E = inWksp->mutableE(0);
    E[0] = 0.;
    auto &Y = inWksp->mutableY(0);
    Y[1] = 0.; // stress sqrtOrOne

    std::string outWSname = "SetUncertainties_" + mode;
    WorkspaceCreationHelper::storeWS(outWSname, inWksp);
    SetUncertainties alg;
    TS_ASSERT_THROWS_NOTHING(alg.initialize());
    alg.setProperty("InputWorkspace", inWksp);
    alg.setProperty("SetError", mode);
    alg.setProperty("OutputWorkspace", outWSname);
    TS_ASSERT_THROWS_NOTHING(alg.execute());
    TS_ASSERT(alg.isExecuted());

    const auto outWS =
        API::AnalysisDataService::Instance().retrieveWS<API::MatrixWorkspace>(
            outWSname);
    TS_ASSERT(bool(outWS)); // non-null pointer
    return outWS;
  }

  API::MatrixWorkspace_sptr
  runAlgCustom(const double toSet, const double toReplace,
               const double errorVal, const int precision, const int position) {

    const std::string mode = "custom";
    std::string outWSname = "SetUncertainties_" + mode;

    auto inWksp =
        WorkspaceCreationHelper::create1DWorkspaceConstant(10, 1, 0., true);
    // Set random element to value to replace
    auto &E = inWksp->mutableE(0);
    E[position] = double(errorVal);

    SetUncertainties alg;
    TS_ASSERT_THROWS_NOTHING(alg.initialize());
    alg.setProperty("InputWorkspace", inWksp);
    alg.setProperty("SetError", mode);
    alg.setProperty("OutputWorkspace", outWSname);
    alg.setProperty("SetErrorTo", toSet);
    alg.setProperty("ifEqualTo", toReplace);
    alg.setProperty("precision", precision);
    TS_ASSERT_THROWS_NOTHING(alg.execute());
    TS_ASSERT(alg.isExecuted());

    const auto outWS =
        API::AnalysisDataService::Instance().retrieveWS<API::MatrixWorkspace>(
            outWSname);
    TS_ASSERT(bool(outWS)); // non-null pointer
    return outWS;
  }

  void test_zero() {
    const auto outWS = runAlg("zero");

    const auto &E = outWS->e(0);
    for (const auto item : E) {
      TS_ASSERT_EQUALS(item, 0.);
    }

    API::AnalysisDataService::Instance().remove(outWS->getName());
  }

  void test_zero_in_place() {
    const auto outWS = runAlgInPlace("zero");

    const auto &E = outWS->e(0);
    for (const auto item : E) {
      TS_ASSERT_EQUALS(item, 0.);
    }

    API::AnalysisDataService::Instance().remove(outWS->getName());
  }

  void test_sqrt() {
    const auto outWS = runAlg("sqrt");

    const auto &E = outWS->e(0);
    const auto &Y = outWS->y(0);
    for (size_t i = 0; i < E.size(); ++i) {
      TS_ASSERT_DELTA(Y[i], E[i] * E[i], .001);
    }

    API::AnalysisDataService::Instance().remove(outWS->getName());
  }

  void test_sqrt_in_place() {
    const auto outWS = runAlgInPlace("sqrt");

    const auto &E = outWS->e(0);
    const auto &Y = outWS->y(0);
    for (size_t i = 0; i < E.size(); ++i) {
      TS_ASSERT_DELTA(Y[i], E[i] * E[i], .001);
    }

    API::AnalysisDataService::Instance().remove(outWS->getName());
  }

  void test_oneIfZero() {
    const auto outWS = runAlg("oneIfZero");

    const auto &E = outWS->e(0);
    for (const auto item : E) {
      TS_ASSERT(item > 0.);
    }
    API::AnalysisDataService::Instance().remove(outWS->getName());
  }

  void test_oneIfZero_in_place() {
    const auto outWS = runAlgInPlace("oneIfZero");

    const auto &E = outWS->e(0);
    for (const auto item : E) {
      TS_ASSERT(item > 0.);
    }
    API::AnalysisDataService::Instance().remove(outWS->getName());
  }

  void test_sqrtOrOne() {
    const auto outWS = runAlg("sqrtOrOne");

    const auto &E = outWS->e(0);
    const auto &Y = outWS->y(0);
    for (size_t i = 0; i < E.size(); ++i) {
      if (Y[i] == 0.) {
        TS_ASSERT_EQUALS(E[i], 1.);
      } else {
        TS_ASSERT_DELTA(Y[i], E[i] * E[i], .001);
      }
    }
    API::AnalysisDataService::Instance().remove(outWS->getName());
  }

  void test_sqrtOrOne_in_place() {
    const auto outWS = runAlgInPlace("sqrtOrOne");

    const auto &E = outWS->e(0);
    const auto &Y = outWS->y(0);
    for (size_t i = 0; i < E.size(); ++i) {
      if (Y[i] == 0.) {
        TS_ASSERT_EQUALS(E[i], 1.);
      } else {
        TS_ASSERT_DELTA(Y[i], E[i] * E[i], .001);
      }
    }
    API::AnalysisDataService::Instance().remove(outWS->getName());
  }

  void test_setCustomWithinToleranceRange() {
    const double toSet = 3;
    const double toReplace = 0.5;
    const double errorVal = 0.500999;
    const int precision = 3;
    const unsigned position = rand() % 10;

    const auto outWS =
        runAlgCustom(toSet, toReplace, errorVal, precision, position);

    const auto &E = outWS->e(0);
    for (size_t i = 0; i < E.size(); ++i) {
      if (i == position) {
        // Error should have been replaced with chosen value
        TS_ASSERT_EQUALS(E[i], toSet);
      } else {
        // Other values remain unchanged
        TS_ASSERT_EQUALS(E[i], 0.)
      }
    }
    API::AnalysisDataService::Instance().remove(outWS->getName());
  }

  void test_setCustomAboveToleranceRange() {
    const double toSet = 3;
    const double toReplace = 0.5;
    const double errorVal = 0.501;
    const int precision = 3;
    const unsigned position = rand() % 10;

    const auto outWS =
        runAlgCustom(toSet, toReplace, errorVal, precision, position);

    const auto &E = outWS->e(0);
    for (size_t i = 0; i < E.size(); ++i) {
      // Errors should be unchanged
      if (i == position) {
        TS_ASSERT_EQUALS(E[i], errorVal);
      } else {
        TS_ASSERT_EQUALS(E[i], 0.)
      }
    }
    API::AnalysisDataService::Instance().remove(outWS->getName());
  }

  void test_setCustomBelowToleranceRange() {
    const double toSet = 3;
    const double toReplace = 0.5;
    const double errorVal = 0.49999;
    const int precision = 1;
    const unsigned position = rand() % 10;

    const auto outWS =
        runAlgCustom(toSet, toReplace, errorVal, precision, position);

    const auto &E = outWS->e(0);
    for (size_t i = 0; i < E.size(); ++i) {
      // Errors should be unchanged
      if (i == position) {
        TS_ASSERT_EQUALS(E[i], errorVal);
      } else {
        TS_ASSERT_EQUALS(E[i], 0.)
      }
    }
    API::AnalysisDataService::Instance().remove(outWS->getName());
  }

  /**
   * Create and execute the algorithm in the specified mode.
   * @param mode The name of the SetError property SetUncertainties
   * @return The name that the output workspace will be registered as.
   */
  void test_EventWorkspacePlace() {
    // random data mostly works
    auto inWksp =
        WorkspaceCreationHelper::createEventWorkspaceWithFullInstrument2(10,
                                                                         10);
    std::string outWSname = "SetUncertainties_oneIfZero";
    WorkspaceCreationHelper::storeWS(outWSname, inWksp);
    SetUncertainties alg;
    TS_ASSERT_THROWS_NOTHING(alg.initialize());
    alg.setProperty("InputWorkspace", inWksp);
    alg.setProperty("SetError", "oneIfZero");
    alg.setProperty("OutputWorkspace", outWSname);
    TS_ASSERT_THROWS_NOTHING(alg.execute());
    TS_ASSERT(alg.isExecuted());

    const auto outWS =
        API::AnalysisDataService::Instance().retrieveWS<API::MatrixWorkspace>(
            outWSname);
    TS_ASSERT(bool(outWS)); // non-null pointer

    const auto &E = outWS->e(0);
    const auto &Y = outWS->y(0);
    for (size_t i = 0; i < E.size(); ++i) {
      if (Y[i] == 0.) {
        TS_ASSERT_EQUALS(E[i], 1.);
      } else {
        TS_ASSERT_DELTA(Y[i], E[i] * E[i], .001);
      }
    }
  }
};

class SetUncertaintiesTestPerformance : public CxxTest::TestSuite {
public:
  void setUp() override {
    algZero.initialize();
    algCalc.initialize();

    // This size controls the test time - and aims for
    // 0.1-0.2 seconds for the algorithm execution time
    constexpr size_t wsSize(1000000);

    // random data mostly works
    inputWs = WorkspaceCreationHelper::create1DWorkspaceRand(wsSize, true);
    algZero.setProperty("InputWorkspace", inputWs);
    algZero.setProperty("SetError", "zero");
    algZero.setProperty("OutputWorkspace", wsName);

    algCalc.setProperty("InputWorkspace", inputWs);
    algCalc.setProperty("SetError", "zero");
    algCalc.setProperty("OutputWorkspace", wsName);

    algZero.setRethrows(true);
    algCalc.setRethrows(true);
  }

  void testSetUncertaintiesPerformance() {
    // First run zeroing all errors
    TS_ASSERT_THROWS_NOTHING(algZero.execute());
    TS_ASSERT_THROWS_NOTHING(algCalc.execute());
  }
private:
  SetUncertainties algZero;
  SetUncertainties algCalc;
  boost::shared_ptr<Mantid::DataObjects::Workspace2D> inputWs;
  const std::string wsName = "outputWs";
};