Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
IntegratePeaksCWSDTest.h 17.29 KiB
#ifndef MANTID_MDAGORITHMS_INTEGRATEPEAKSCWSDTEST_H_
#define MANTID_MDAGORITHMS_INTEGRATEPEAKSCWSDTEST_H_

#include "MantidAPI/AnalysisDataService.h"
#include "MantidAPI/IMDEventWorkspace.h"
#include "MantidAPI/Run.h"
#include "MantidMDAlgorithms/IntegratePeaksCWSD.h"
#include "MantidTestHelpers/ComponentCreationHelper.h"
#include "MantidKernel/V3D.h"
#include "MantidDataObjects/MDEventFactory.h"
#include "MantidGeometry/MDGeometry/QSample.h"
#include "MantidDataObjects/MDEventInserter.h"

#include <cxxtest/TestSuite.h>

#include <Poco/File.h>

using Mantid::API::AnalysisDataService;
using Mantid::Geometry::MDHistoDimension;
using namespace Mantid::API;
using namespace Mantid::DataObjects;
using namespace Mantid::Geometry;
using namespace Mantid::Kernel;
using namespace Mantid::MDAlgorithms;
using Mantid::Kernel::V3D;

namespace {
/** Add a list of MDEvents around Q = (1, 2, 3)
* @brief createMDWorkspace
*/
IMDEventWorkspace_sptr
createMDWorkspace(const std::vector<Mantid::Kernel::V3D> &vec_event_qsample,
                  const std::vector<double> &vec_event_signal,
                  const std::vector<int> &vec_event_det,
                  const std::vector<int> &vec_event_run) {
  // Check the inputs
  TS_ASSERT_EQUALS(vec_event_qsample.size(), vec_event_signal.size());
  TS_ASSERT_EQUALS(vec_event_qsample.size(), vec_event_det.size());
  TS_ASSERT_EQUALS(vec_event_qsample.size(), vec_event_run.size());

  // Create MDEVENTWorkspace
  // Create workspace in Q_sample with dimenion as 3
  size_t nDimension = 3;
  IMDEventWorkspace_sptr mdws =
      MDEventFactory::CreateMDWorkspace(nDimension, "MDEvent");

  // Extract Dimensions and add to the output workspace.
  std::vector<std::string> vec_ID(3);
  vec_ID[0] = "Q_sample_x";
  vec_ID[1] = "Q_sample_y";
  vec_ID[2] = "Q_sample_z";
  std::vector<std::string> dimensionNames(3);
  dimensionNames[0] = "Q_sample_x";
  dimensionNames[1] = "Q_sample_y";
  dimensionNames[2] = "Q_sample_z";

  Mantid::Kernel::SpecialCoordinateSystem coordinateSystem =
      Mantid::Kernel::QSample;

  // Add dimensions
  std::vector<double> m_extentMins(3);
  std::vector<double> m_extentMaxs(3);
  std::vector<size_t> m_numBins(3, 100);
  for (size_t i = 0; i < 3; ++i) {
    m_extentMins[i] = 2;
    m_extentMaxs[i] = 4;
  }

  // Get MDFrame of Qsample
  Mantid::Geometry::QSample frame;

  for (size_t i = 0; i < nDimension; ++i) {
    std::string id = vec_ID[i];
    std::string name = dimensionNames[i];
    mdws->addDimension(Mantid::Geometry::MDHistoDimension_sptr(
        new Mantid::Geometry::MDHistoDimension(
            id, name, frame, static_cast<Mantid::coord_t>(m_extentMins[i]),
            static_cast<Mantid::coord_t>(m_extentMaxs[i]), m_numBins[i])));
  }

  // Set coordinate system
  mdws->setCoordinateSystem(coordinateSystem);

  // Creates a new instance of the MDEventInserter to output workspace
  MDEventWorkspace<MDEvent<3>, 3>::sptr mdws_mdevt_3 =
      boost::dynamic_pointer_cast<MDEventWorkspace<MDEvent<3>, 3>>(mdws);
  MDEventInserter<MDEventWorkspace<MDEvent<3>, 3>::sptr> inserter(mdws_mdevt_3);

  // Go though each spectrum to conver to MDEvent
  for (size_t iq = 0; iq < vec_event_qsample.size(); ++iq) {
    Mantid::Kernel::V3D qsample = vec_event_qsample[iq];
    std::vector<Mantid::coord_t> millerindex(3);
    millerindex[0] = static_cast<Mantid::coord_t>(qsample.X());
    millerindex[1] = static_cast<Mantid::coord_t>(qsample.Y());
    millerindex[2] = static_cast<Mantid::coord_t>(qsample.Z());

    double signal = vec_event_signal[iq];
    double error = std::sqrt(signal);
    uint16_t runnumber = static_cast<uint16_t>(vec_event_run[iq]);
    Mantid::detid_t detid = vec_event_det[iq];

    // Insert
    inserter.insertMDEvent(
        static_cast<float>(signal), static_cast<float>(error * error),
        static_cast<uint16_t>(runnumber), detid, millerindex.data());
  }

  // Set up run information
  ExperimentInfo_sptr exp_info = boost::make_shared<ExperimentInfo>();
  exp_info->mutableRun().addProperty("run_number", 121);
  exp_info->mutableRun().addProperty("monitor", 3021);

  // add instrument
  Instrument_sptr inst1 =
      ComponentCreationHelper::createTestInstrumentRectangular2(1, 10);
  inst1->setName("SillyInstrument1");
  exp_info->setInstrument(inst1);
  mdws->addExperimentInfo(exp_info);

  ExperimentInfo_sptr exp_info2 = boost::make_shared<ExperimentInfo>();
  exp_info2->mutableRun().addProperty("run_number", 144);
  exp_info2->mutableRun().addProperty("monitor", 1022);
  // add instrument
  Instrument_sptr inst2 =
      ComponentCreationHelper::createTestInstrumentRectangular2(1, 11);
  inst1->setName("SillyInstrument2");
  exp_info2->setInstrument(inst2);

  mdws->addExperimentInfo(exp_info2);

  return mdws;
}

/** Add a peak at Q = (1, 2, 3)
* @brief buildPW
* @return
*/
PeaksWorkspace_sptr
buildPeakWorkspace(std::vector<int> vec_run_number,
                   std::vector<Mantid::Kernel::V3D> vec_q_sample) {
  // create instrument
  Instrument_sptr inst =
      ComponentCreationHelper::createTestInstrumentRectangular2(1, 10);
  inst->setName("SillyInstrument");

  // create PeaksWorkspace with property
  auto pw = PeaksWorkspace_sptr(new PeaksWorkspace);
  pw->setInstrument(inst);
  std::string val = "value";
  pw->mutableRun().addProperty("TestProp", val);
  std::string val_mon = "3012";
  pw->mutableRun().addProperty("monitor", val_mon);

  // add peaks
  size_t num_peaks = vec_run_number.size();
  TS_ASSERT_EQUALS(num_peaks, vec_q_sample.size());

  for (size_t i_peak = 0; i_peak < num_peaks; ++i_peak) {
    Peak p(inst, 1, 3.0);
    Mantid::Kernel::V3D qsample = vec_q_sample[i_peak];
    p.setQSampleFrame(qsample, 0.37);
    p.setRunNumber(vec_run_number[i_peak]);
    pw->addPeak(p);
  }
  return pw;
}

/** Create MDEventsWorkspace containing data of 1 run
* @brief createMDEvents1Run
* @param vec_qsample
* @param vec_signal
* @param vec_detid
* @param vec_runnumber
*/
void createMDEvents1Run(std::vector<Mantid::Kernel::V3D> &vec_qsample,
                        std::vector<double> &vec_signal,
                        std::vector<Mantid::detid_t> &vec_detid,
                        std::vector<int> &vec_runnumber) {

  double q_x0 = 1.0;
  double q_y0 = 2.0;
  double q_z0 = 3.0;
  double d_q = 0.1;
  Mantid::Kernel::V3D origin(0, 0, 0);

  Mantid::detid_t detid = 1000;
  for (size_t i = 0; i < 8; ++i) {
    double q_x = static_cast<double>(i) * d_q + q_x0;
    for (size_t j = 0; j < 8; ++j) {
      double q_y = static_cast<double>(j) * d_q + q_y0;
      for (size_t k = 0; k < 8; ++k) {
        double q_z = static_cast<double>(k) * d_q + q_z0;
        Mantid::Kernel::V3D qsample(q_x, q_y, q_z);
        double signal = qsample.distance(origin) * 1000;

        vec_qsample.push_back(qsample);
        vec_signal.push_back(signal);
        vec_detid.push_back(detid);
        vec_runnumber.push_back(121);

        ++detid;
      }
    }
  }

  return;
}

/** Create MDEventsWorkspace containing data of 2 runs
* @brief createMDEvents2Run
* @param vec_qsample
* @param vec_signal
* @param vec_detid
* @param vec_runnumber
*/
void createMDEvents2Run(std::vector<Mantid::Kernel::V3D> &vec_qsample,
                        std::vector<double> &vec_signal,
                        std::vector<Mantid::detid_t> &vec_detid,
                        std::vector<int> &vec_runnumber) {

  double q_x0 = -0.4;
  double q_y0 = -0.4;
  double q_z0 = -0.4;
  double d_q = 0.1;
  Mantid::Kernel::V3D origin(0, 0, 0);

  Mantid::detid_t detid = 1000;
  for (size_t i = 0; i < 8; ++i) {
    double q_x = static_cast<double>(i) * d_q + q_x0;
    for (size_t j = 0; j < 8; ++j) {
      double q_y = static_cast<double>(j) * d_q + q_y0;
      for (size_t k = 0; k < 8; ++k) {
        double q_z = static_cast<double>(k) * d_q + q_z0;
        Mantid::Kernel::V3D qsample(q_x, q_y, q_z);
        double signal = qsample.distance(origin) * 1000;

        vec_qsample.push_back(qsample);
        vec_signal.push_back(signal);
        vec_detid.push_back(detid);
        vec_runnumber.push_back(121);

        ++detid;
      }
    }
  }

  // Add 2nd run
  q_x0 = -0.3;
  q_y0 = -0.3;
  q_z0 = -0.3;
  d_q = 0.1;

  detid = 1000;
  for (size_t i = 0; i < 8; ++i) {
    double q_x = static_cast<double>(i) * d_q + q_x0;
    for (size_t j = 0; j < 8; ++j) {
      double q_y = static_cast<double>(j) * d_q + q_y0;
      for (size_t k = 0; k < 8; ++k) {
        double q_z = static_cast<double>(k) * d_q + q_z0;
        Mantid::Kernel::V3D qsample(q_x, q_y, q_z);
        double signal = qsample.distance(origin) * 100;

        vec_qsample.push_back(qsample);
        vec_signal.push_back(signal);
        vec_detid.push_back(detid);
        vec_runnumber.push_back(144);

        ++detid;
      }
    }
  }

  return;
}
}

class IntegratePeaksCWSDTest : public CxxTest::TestSuite {
public:
  static IntegratePeaksCWSDTest *createSuite() {
    return new IntegratePeaksCWSDTest();
  }

  static void destroySuite(IntegratePeaksCWSDTest *suite) { delete suite; }

  //-------------------------------------------------------------------------------
  /** Test initialize of the algorithm
   */
  void test_Init() {
    IntegratePeaksCWSD alg;
    TS_ASSERT_THROWS_NOTHING(alg.initialize())
    TS_ASSERT(alg.isInitialized())
  }

  //-------------------------------------------------------------------------------
  /** Test integrate MDEventWorkspace with 1 run
   */
  void test_singleRun() {
    // Initialize algorithm and set up
    IntegratePeaksCWSD alg;
    alg.initialize();
    TS_ASSERT(alg.isInitialized())

    // Create workspaces to test
    std::vector<Mantid::Kernel::V3D> vec_qsample;
    std::vector<double> vec_signal;
    std::vector<int> vec_detid;
    std::vector<int> vec_runnumbers;
    createMDEvents1Run(vec_qsample, vec_signal, vec_detid, vec_runnumbers);

    IMDEventWorkspace_sptr inputws =
        createMDWorkspace(vec_qsample, vec_signal, vec_detid, vec_runnumbers);
    AnalysisDataService::Instance().addOrReplace("TestMDWS", inputws);

    std::vector<int> runnumberlist;
    runnumberlist.push_back(vec_runnumbers[0]);
    Mantid::Kernel::V3D peakcenter(1.4, 2.4, 3.4);
    std::vector<Mantid::Kernel::V3D> peakcenterlist;
    peakcenterlist.push_back(peakcenter);
    PeaksWorkspace_sptr peakws =
        buildPeakWorkspace(runnumberlist, peakcenterlist);
    AnalysisDataService::Instance().addOrReplace("TestPeaksWS", peakws);

    alg.setProperty("InputWorkspace", inputws);
    alg.setProperty("PeaksWorkspace", peakws);
    alg.setProperty("OutputWorkspace", "IntegratedPeakWS");
    alg.setProperty("PeakRadius", 0.3);
    alg.setProperty("MergePeaks", true);
    alg.setProperty("NormalizeByMonitor", true);
    alg.setProperty("NormalizeByTime", false);

    alg.execute();
    TS_ASSERT(alg.isExecuted())
    // check result
    PeaksWorkspace_sptr outws = boost::dynamic_pointer_cast<PeaksWorkspace>(
        AnalysisDataService::Instance().retrieve("IntegratedPeakWS"));
    TS_ASSERT(outws)
    TS_ASSERT_EQUALS(outws->getNumberPeaks(), 1)

    Peak peak = outws->getPeak(0);
    TS_ASSERT(peak.getIntensity() > 0)

    // clean the workspaces
    AnalysisDataService::Instance().remove("TestPeaksWS");
    AnalysisDataService::Instance().remove("TestMDWS");
    AnalysisDataService::Instance().remove("IntegratedPeakWS");
  }

  //-------------------------------------------------------------------------------
  /** Test integrate MDEventWorkspace with multiple runs and multiple peaks
   *  in a given PeaksWorkspace
   */
  void test_multipleRun() {
    // Create workspaces to test
    std::vector<Mantid::Kernel::V3D> vec_qsample;
    std::vector<double> vec_signal;
    std::vector<int> vec_detid;
    std::vector<int> vec_runnumbers;
    createMDEvents2Run(vec_qsample, vec_signal, vec_detid, vec_runnumbers);

    IMDEventWorkspace_sptr inputws =
        createMDWorkspace(vec_qsample, vec_signal, vec_detid, vec_runnumbers);
    AnalysisDataService::Instance().addOrReplace("TestMDWS2", inputws);
    TS_ASSERT(AnalysisDataService::Instance().doesExist("TestMDWS2"));

    std::vector<int> runnumberlist;
    runnumberlist.push_back(vec_runnumbers.front());
    runnumberlist.push_back(vec_runnumbers.back());
    Mantid::Kernel::V3D peakcenter(3, 3, 3);
    std::vector<Mantid::Kernel::V3D> peakcenterlist;
    peakcenterlist.push_back(peakcenter);
    peakcenterlist.push_back(peakcenter);
    PeaksWorkspace_sptr peakws =
        buildPeakWorkspace(runnumberlist, peakcenterlist);
    AnalysisDataService::Instance().addOrReplace("TestPeaksWS", peakws);

    // Initialize algorithm and set up
    IntegratePeaksCWSD alg;
    alg.initialize();
    TS_ASSERT(alg.isInitialized())

    alg.setPropertyValue("InputWorkspace", "TestMDWS2");
    alg.setPropertyValue("PeaksWorkspace", "TestPeaksWS");
    alg.setProperty("OutputWorkspace", "IntegratedPeakWS");
    alg.setProperty("PeakRadius", 0.2);
    alg.setProperty("MergePeaks", false);
    alg.setProperty("NormalizeByMonitor", false);
    alg.setProperty("NormalizeByTime", false);

    alg.execute();
    TS_ASSERT(alg.isExecuted())

    // check
    PeaksWorkspace_sptr outws = boost::dynamic_pointer_cast<PeaksWorkspace>(
        AnalysisDataService::Instance().retrieve("IntegratedPeakWS"));
    TS_ASSERT(outws)
    TS_ASSERT_EQUALS(outws->getNumberPeaks(), 2)

    // clean the workspaces
    AnalysisDataService::Instance().remove("TestMDWS2");
    AnalysisDataService::Instance().remove("TesetPeaksWS");
    AnalysisDataService::Instance().remove("IntegratedPeakWS");
  }

  //-------------------------------------------------------------------------------
  /** Test integrate MDEventWorkspace with multiple runs without PeaksWorkspace
   *  but with a given peak center
   */
  void test_multipleRun1Peak() {
    // Create MDEventWorkspace for testing
    std::vector<Mantid::Kernel::V3D> vec_qsample;
    std::vector<double> vec_signal;
    std::vector<int> vec_detid;
    std::vector<int> vec_runnumbers;
    createMDEvents2Run(vec_qsample, vec_signal, vec_detid, vec_runnumbers);

    IMDEventWorkspace_sptr inputws =
        createMDWorkspace(vec_qsample, vec_signal, vec_detid, vec_runnumbers);
    AnalysisDataService::Instance().addOrReplace("TestMDWS2", inputws);
    TS_ASSERT(AnalysisDataService::Instance().doesExist("TestMDWS2"));
    // Initialize algorithm and set up
    IntegratePeaksCWSD alg;
    alg.initialize();
    TS_ASSERT(alg.isInitialized())

    alg.setProperty("InputWorkspace", inputws);
    // alg.setProperty("PeaksWorkspace", peakws);
    alg.setProperty("OutputWorkspace", "IntegratedPeakWS");
    alg.setProperty("PeakRadius", 0.2);
    alg.setPropertyValue("PeakCentre", "3, 3, 3");
    alg.setProperty("MergePeaks", true);
    alg.setProperty("NormalizeByMonitor", true);
    alg.setProperty("NormalizeByTime", false);

    alg.execute();
    TS_ASSERT(alg.isExecuted());

    // check result
    bool doesexit =
        AnalysisDataService::Instance().doesExist("IntegratedPeakWS");
    TS_ASSERT(doesexit);
    PeaksWorkspace_sptr outws = boost::dynamic_pointer_cast<PeaksWorkspace>(
        AnalysisDataService::Instance().retrieve("IntegratedPeakWS"));
    TS_ASSERT(outws);

    TS_ASSERT_EQUALS(outws->getNumberPeaks(), 2)

    Peak peak1 = outws->getPeak(0);
    Peak peak2 = outws->getPeak(1);
    TS_ASSERT_DELTA(peak1.getIntensity(), peak2.getIntensity(), 0.000001);
  }
};

class IntegratePeaksCWSDTestPerformance : public CxxTest::TestSuite {
public:
  static IntegratePeaksCWSDTestPerformance *createSuite() {
    return new IntegratePeaksCWSDTestPerformance();
  }
  static void destroySuite(IntegratePeaksCWSDTestPerformance *suite) {
    delete suite;
  }

  void setUp() override {
    createMDEvents2Run(vec_qsample, vec_signal, vec_detid, vec_runnumbers);

    inputws =
        createMDWorkspace(vec_qsample, vec_signal, vec_detid, vec_runnumbers);
    AnalysisDataService::Instance().addOrReplace("TestMDWS2", inputws);

    runnumberlist.push_back(vec_runnumbers.front());
    runnumberlist.push_back(vec_runnumbers.back());
    Mantid::Kernel::V3D peakcenter(3, 3, 3);
    std::vector<Mantid::Kernel::V3D> peakcenterlist;
    peakcenterlist.push_back(peakcenter);
    peakcenterlist.push_back(peakcenter);
    peakws = buildPeakWorkspace(runnumberlist, peakcenterlist);
    AnalysisDataService::Instance().addOrReplace("TestPeaksWS", peakws);

    MaskWorkspace_sptr maskws(new MaskWorkspace());
    maskws->initialize(99, 1, 1);
    for (size_t i = 0; i < maskws->getNumberHistograms(); i++) {
      maskws->mutableY(i)[0] = 1;
    }
    const auto &inst = inputws->getExperimentInfo(0)->getInstrument();
    maskws->setInstrument(inst);
    AnalysisDataService::Instance().addOrReplace("InMaskWS", maskws);

    alg.initialize();
    alg.setPropertyValue("InputWorkspace", "TestMDWS2");
    alg.setPropertyValue("PeaksWorkspace", "TestPeaksWS");
    alg.setProperty("OutputWorkspace", "IntegratedPeakWS");
    alg.setProperty("MaskWorkspace", "InMaskWS");
    alg.setProperty("PeakRadius", 0.2);
    alg.setProperty("MergePeaks", false);
    alg.setProperty("NormalizeByMonitor", false);
    alg.setProperty("NormalizeByTime", false);
  }

  void tearDown() override { AnalysisDataService::Instance().clear(); }

  void testIntegratePeaksCWSDPerformance() {
    TS_ASSERT_THROWS_NOTHING(alg.execute());
  }

private:
  IntegratePeaksCWSD alg;
  IMDEventWorkspace_sptr inputws;
  PeaksWorkspace_sptr peakws;

  std::vector<Mantid::Kernel::V3D> vec_qsample;
  std::vector<double> vec_signal;
  std::vector<int> vec_detid;
  std::vector<int> vec_runnumbers;
  std::vector<int> runnumberlist;
};

#endif /* MANTID_MDEVENTS_INTEGRATEPEAKSCWSDTEST_H_ */