Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
ConvertToMDComponentsTest.h 13.03 KiB
#ifndef MANTID_MDALGORITHM_CONVERT2MD_COMPONENTS_TEST_H
#define MANTID_MDALGORITHM_CONVERT2MD_COMPONENTS_TEST_H
// tests for different parts of ConvertToMD exec functions

#include "MantidAPI/FrameworkManager.h"
#include "MantidAPI/SpectrumInfo.h"
#include "MantidGeometry/Instrument/Goniometer.h"
#include "MantidMDAlgorithms/ConvertToMD.h"
#include "MantidMDAlgorithms/MDWSTransform.h"
#include "MantidTestHelpers/ComponentCreationHelper.h"
#include "MantidTestHelpers/MDEventsTestHelper.h"
#include "MantidTestHelpers/WorkspaceCreationHelper.h"

#include <cxxtest/TestSuite.h>

using namespace Mantid;
using namespace Mantid::Kernel;
using namespace Mantid::API;
using namespace Mantid::DataObjects;
using namespace Mantid::MDAlgorithms;

class Convert2MDComponentsTestHelper : public ConvertToMD {
public:
  TableWorkspace_const_sptr
  preprocessDetectorsPositions(Mantid::API::MatrixWorkspace_const_sptr InWS2D,
                               const std::string dEModeRequested = "Direct",
                               bool updateMasks = true) {
    std::string OutWSName(this->getProperty("PreprocDetectorsWS"));
    return ConvertToMD::preprocessDetectorsPositions(InWS2D, dEModeRequested,
                                                     updateMasks, OutWSName);
  }
  void setSourceWS(Mantid::API::MatrixWorkspace_sptr InWS2D) {
    this->m_InWS2D = InWS2D;
    // and create the class, which will deal with the target workspace
    if (!this->m_OutWSWrapper)
      this->m_OutWSWrapper = boost::shared_ptr<MDAlgorithms::MDEventWSWrapper>(
          new MDAlgorithms::MDEventWSWrapper());
  }
  Convert2MDComponentsTestHelper() { ConvertToMD::initialize(); }
  bool buildTargetWSDescription(API::IMDEventWorkspace_sptr spws,
                                const std::string &Q_mod_req,
                                const std::string &dEModeRequested,
                                const std::vector<std::string> &other_dim_names,
                                const std::string &QFrame,
                                const std::string &convert_to_,
                                MDAlgorithms::MDWSDescription &targWSDescr) {
    std::vector<double> dimMin = this->getProperty("MinValues");
    std::vector<double> dimMax = this->getProperty("MaxValues");
    return ConvertToMD::buildTargetWSDescription(
        spws, Q_mod_req, dEModeRequested, other_dim_names, dimMin, dimMax,
        QFrame, convert_to_, targWSDescr);
  }
  void copyMetaData(API::IMDEventWorkspace_sptr mdEventWS) const {
    ConvertToMD::copyMetaData(mdEventWS);
  }
  void addExperimentInfo(API::IMDEventWorkspace_sptr mdEventWS,
                         MDAlgorithms::MDWSDescription &targWSDescr) const {
    ConvertToMD::addExperimentInfo(mdEventWS, targWSDescr);
  };

  API::IMDEventWorkspace_sptr createNewMDWorkspace(
      const MDAlgorithms::MDWSDescription &NewMDWSDescription) {
    return ConvertToMD::createNewMDWorkspace(NewMDWSDescription, false, "");
  }
};

//
class ConvertToMDComponentsTest : public CxxTest::TestSuite {
  std::unique_ptr<Convert2MDComponentsTestHelper> pAlg;
  Mantid::API::MatrixWorkspace_sptr ws2D;

public:
  static ConvertToMDComponentsTest *createSuite() {
    return new ConvertToMDComponentsTest();
  }
  static void destroySuite(ConvertToMDComponentsTest *suite) { delete suite; }

  void testPreprocDetLogic() {
    Mantid::API::MatrixWorkspace_sptr ws2Dp =
        AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(
            "testWSProcessed");
    // if workspace name is specified, it has been preprocessed and added to
    // analysis data service:

    pAlg->setPropertyValue("PreprocDetectorsWS", "PreprDetWS");
    auto TableWS = pAlg->preprocessDetectorsPositions(ws2Dp);
    auto TableWSs = AnalysisDataService::Instance().retrieveWS<TableWorkspace>(
        "PreprDetWS");
    TS_ASSERT_EQUALS(TableWS.get(), TableWSs.get());
    // does not calculate ws second time:
    auto TableWS2 = pAlg->preprocessDetectorsPositions(ws2Dp);
    TS_ASSERT_EQUALS(TableWS2.get(), TableWSs.get());

    // but now it does calculate a new workspace
    pAlg->setPropertyValue("PreprocDetectorsWS", "-");
    auto TableWS3 = pAlg->preprocessDetectorsPositions(ws2Dp);
    TS_ASSERT(TableWSs.get() != TableWS3.get());

    TS_ASSERT_EQUALS(
        "",
        TableWS3->getName()); // if WS isn't in the ADS it doesn't have a name
    TSM_ASSERT("Should not add service WS to the data service",
               !AnalysisDataService::Instance().doesExist("ServiceTableWS"));

    // now it does not calculates new workspace and takes old from data service
    pAlg->setPropertyValue("PreprocDetectorsWS", "PreprDetWS");
    auto TableWS4 = pAlg->preprocessDetectorsPositions(ws2Dp);
    TS_ASSERT_EQUALS(TableWS4.get(), TableWSs.get());

    // and now it does not take old and calculated new
    pAlg->setPropertyValue("PreprocDetectorsWS", "PreprDetWS2");
    auto TableWS5 = pAlg->preprocessDetectorsPositions(ws2Dp);
    TS_ASSERT(TableWS5.get() != TableWS4.get());

    // workspace with different number of detectors calculated into different
    // workspace, replacing the previous one into dataservice
    Mantid::API::MatrixWorkspace_sptr ws2DNew = WorkspaceCreationHelper::
        createProcessedWorkspaceWithCylComplexInstrument(9, 10, true);
    // this is the problems with alg, as ws has to be added to data service to
    // be avail to algorithm.
    pAlg->setSourceWS(ws2DNew);

    // Ei is not defined
    TSM_ASSERT_THROWS("WS has to have input energy for indirect methods",
                      pAlg->preprocessDetectorsPositions(ws2DNew),
                      std::invalid_argument);
    ws2DNew->mutableRun().addProperty("Ei", 130., "meV", true);

    auto TableWS6 = pAlg->preprocessDetectorsPositions(ws2DNew);
    TS_ASSERT(TableWS6.get() != TableWS5.get());
    TS_ASSERT_EQUALS(9, TableWS6->rowCount());
    TS_ASSERT_EQUALS(4, TableWS5->rowCount());

    // Trow on  running the test again if the workspace does not have energy
    // attached.
    ws2DNew->mutableRun().removeProperty("Ei");
    TSM_ASSERT_THROWS("WS has to have input energy for indirect methods "
                      "despite the table workspace is already calculated",
                      pAlg->preprocessDetectorsPositions(ws2DNew),
                      std::invalid_argument);
  }
  void testUpdateMasksSkipped() {
    Mantid::API::MatrixWorkspace_sptr ws2Dp =
        AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(
            "testWSProcessed");

    auto clVs = Mantid::API::FrameworkManager::Instance().createAlgorithm(
        "CloneWorkspace");
    TS_ASSERT(clVs);
    if (!clVs)
      return;

    clVs->initialize();
    clVs->setProperty("InputWorkspace", ws2Dp);
    clVs->setProperty("OutputWorkspace", "InWSCopy");
    clVs->execute();

    Mantid::API::MatrixWorkspace_sptr ws2DCopy =
        AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("InWSCopy");
    // if workspace name is specified, it has been preprocessed and added to
    // analysis data service:

    pAlg->setPropertyValue("PreprocDetectorsWS", "PreprDetWS");
    // the workspace has t
    auto TableWS =
        pAlg->preprocessDetectorsPositions(ws2DCopy, "Direct", false);

    auto &maskCol = TableWS->getColVector<int>("detMask");
    for (size_t i = 0; i < maskCol.size(); i++) {
      TS_ASSERT_EQUALS(0, maskCol[i]);
    }
    // now mask a detector and check if masks are updated;
    maskAllDetectors("InWSCopy");
    // skip recalculating the detectors masks so the workspace should stay the
    // same (untouched return from DS)
    auto TableWS1 =
        pAlg->preprocessDetectorsPositions(ws2DCopy, "Direct", false);

    TS_ASSERT(TableWS.get() == TableWS1.get());
    for (size_t i = 0; i < maskCol.size(); i++) {
      TS_ASSERT_EQUALS(0, maskCol[i]);
    }
    AnalysisDataService::Instance().remove("InWSCopy");
  }

  void testUpdateMasksWorked() {
    Mantid::API::MatrixWorkspace_sptr ws2Dp =
        AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(
            "testWSProcessed");
    // if workspace name is specified, it has been preprocessed and added to
    // analysis data service:

    pAlg->setPropertyValue("PreprocDetectorsWS", "PreprDetWS");
    // the workspace has t
    auto TableWS = pAlg->preprocessDetectorsPositions(ws2Dp);

    auto &maskCol = TableWS->getColVector<int>("detMask");
    for (size_t i = 0; i < maskCol.size(); i++) {
      TS_ASSERT_EQUALS(0, maskCol[i]);
    }
    // now mask a detector and check if masks are updated;
    maskAllDetectors("testWSProcessed");
    // recalculate the detectors masks but the workspace should stay the same
    auto TableWS1 = pAlg->preprocessDetectorsPositions(ws2Dp);

    TS_ASSERT(TableWS.get() == TableWS1.get());
    for (size_t i = 0; i < maskCol.size(); i++) {
      TS_ASSERT_EQUALS(1, maskCol[i]);
    }
  }

  void testCalcDECol() {

    auto TableWS7 = pAlg->preprocessDetectorsPositions(
        ws2D, Kernel::DeltaEMode::asString(Kernel::DeltaEMode::Indirect));

    TS_ASSERT_EQUALS(4, TableWS7->rowCount());

    float *pDataArray = TableWS7->getColDataArray<float>("eFixed");
    TS_ASSERT(pDataArray);
    if (!pDataArray)
      return;

    for (size_t i = 0; i < TableWS7->rowCount(); i++) {
      TS_ASSERT_DELTA(13.f, *(pDataArray + i), 1.e-6);
    }
  }

  void testAddExperimentInfo() {
    Mantid::API::MatrixWorkspace_sptr ws2Dp =
        AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(
            "testWSProcessed");

    API::IMDEventWorkspace_sptr spws;
    // create testing part of the algorithm
    Convert2MDComponentsTestHelper subAlgo;
    // set source workspace as it would be used by the algorithm itself;
    subAlgo.setSourceWS(ws2Dp);
    // and min-max values (they are still needed by the algorithm)
    subAlgo.setPropertyValue("MinValues", "-10");
    subAlgo.setPropertyValue("MaxValues", "10");

    bool createNewTargetWs(false);
    std::vector<std::string> Q_modes =
        MDAlgorithms::MDTransfFactory::Instance().getKeys();
    std::string dE_mode =
        Kernel::DeltaEMode().asString(Kernel::DeltaEMode::Elastic);
    MDWSTransform QScl;
    std::vector<std::string> QScales = QScl.getQScalings();
    std::vector<std::string> Frames = QScl.getTargetFrames();

    MDAlgorithms::MDWSDescription targWSDescr;
    TS_ASSERT_THROWS_NOTHING(
        createNewTargetWs = subAlgo.buildTargetWSDescription(
            spws, Q_modes[0], dE_mode, std::vector<std::string>(),
            Frames[CnvrtToMD::AutoSelect], QScales[CnvrtToMD::NoScaling],
            targWSDescr));

    TSM_ASSERT(
        "as spws is null pointer, this should request creating new workspace ",
        createNewTargetWs)

    TS_ASSERT_THROWS_NOTHING(spws = subAlgo.createNewMDWorkspace(targWSDescr));
    TS_ASSERT(spws);
    if (!spws)
      return;

    // copy the experiment info and get the unique number, that identifies the
    // run, the source workspace came from.
    TS_ASSERT_THROWS_NOTHING(subAlgo.addExperimentInfo(spws, targWSDescr));

    uint16_t runIndex(1000);
    TS_ASSERT_THROWS_NOTHING(
        runIndex = targWSDescr.getPropertyValueAsType<uint16_t>("RUN_INDEX"));
    TS_ASSERT_EQUALS(0, runIndex);

    // target workspace has W-matrix, which should be unit matrix
    TS_ASSERT(spws->getExperimentInfo(0)->run().hasProperty("W_MATRIX"));
    // it also has transformation matrix
    TS_ASSERT(spws->getExperimentInfo(0)->run().hasProperty("RUBW_MATRIX"));

    if (!spws->getExperimentInfo(0)->run().hasProperty("W_MATRIX"))
      return;

    Kernel::DblMatrix UnitMatr(3, 3, true);
    std::vector<double> libWMatr;

    TS_ASSERT_THROWS_NOTHING(
        libWMatr =
            spws->getExperimentInfo(0)
                ->run()
                .getPropertyValueAsType<std::vector<double>>("W_MATRIX"));

    Kernel::DblMatrix wMatr(libWMatr);
    TSM_ASSERT("We have not set up anything so it should be unit matrix",
               wMatr.equals(UnitMatr));
  }
  void xestCopyMetadata() {
    // this test should be enabled in some form
    // TS_ASSERT_THROWS_NOTHING(subAlgo.copyMetaData(spws));
  }

  ConvertToMDComponentsTest() {
    pAlg = Mantid::Kernel::make_unique<Convert2MDComponentsTestHelper>();
    ws2D = WorkspaceCreationHelper::
        createProcessedWorkspaceWithCylComplexInstrument(4, 10, true);
    // rotate the crystal by twenty degrees back;
    ws2D->mutableRun().mutableGoniometer().setRotationAngle(0, 20);
    // add workspace energy
    ws2D->mutableRun().addProperty("eFixed", 13., "meV", true);

    AnalysisDataService::Instance().addOrReplace("testWSProcessed", ws2D);

    Mantid::API::FrameworkManager::Instance();
  }
  ~ConvertToMDComponentsTest() override {
    AnalysisDataService::Instance().remove("testWSProcessed");
  }

  void maskAllDetectors(const std::string &wsName) {
    auto inputWS = boost::dynamic_pointer_cast<API::MatrixWorkspace>(
        API::AnalysisDataService::Instance().retrieve(wsName));
    const size_t nRows = inputWS->getNumberHistograms();
    auto &spectrumInfo = inputWS->mutableSpectrumInfo();
    for (size_t i = 0; i < nRows; i++) {
      if (!spectrumInfo.hasDetectors(i) || spectrumInfo.isMonitor(i))
        continue;
      inputWS->getSpectrum(i).clearData();
      spectrumInfo.setMasked(i, true);
    }
  }
};
#endif