Skip to content
Snippets Groups Projects
MatrixWorkspaceTest.h 67.7 KiB
Newer Older
    TS_ASSERT_THROWS_NOTHING(
        value = ws.getSignalAtCoord(coord_bottom_left, VolumeNormalization));
    TS_ASSERT_EQUALS(1.0, value);
  }

  void test_setMDMasking() {
    TSM_ASSERT_THROWS("Characterisation test. This is not implemented.",
                      ws.setMDMasking(NULL), std::runtime_error);
  void test_clearMDMasking() {
    TSM_ASSERT_THROWS("Characterisation test. This is not implemented.",
                      ws.clearMDMasking(), std::runtime_error);
  void test_getSpecialCoordinateSystem_default() {
    TSM_ASSERT_EQUALS("Should default to no special coordinate system.",
                      Mantid::Kernel::None, ws.getSpecialCoordinateSystem());
  void test_getFirstPulseTime_getLastPulseTime() {
    WorkspaceTester ws;
    auto proton_charge = new TimeSeriesProperty<double>("proton_charge");
    DateAndTime startTime("2013-04-21T10:40:00");
    proton_charge->addValue(startTime, 1.0E-7);
    proton_charge->addValue(startTime + 1.0, 2.0E-7);
    proton_charge->addValue(startTime + 2.0, 3.0E-7);
    proton_charge->addValue(startTime + 3.0, 4.0E-7);
    ws.mutableRun().addLogData(proton_charge);

    TS_ASSERT_EQUALS(ws.getFirstPulseTime(), startTime);
    TS_ASSERT_EQUALS(ws.getLastPulseTime(), startTime + 3.0);
  void test_getFirstPulseTime_getLastPulseTime_SNS1990bug() {
    WorkspaceTester ws;
    auto proton_charge = new TimeSeriesProperty<double>("proton_charge");
    DateAndTime startTime("1990-12-31T23:59:00");
    proton_charge->addValue(startTime, 1.0E-7);
    proton_charge->addValue(startTime + 1.0, 2.0E-7);
    ws.mutableRun().addLogData(proton_charge);

    // If fewer than 100 entries (unlikely to happen in reality), you just get
    // back the last one
    TS_ASSERT_EQUALS(ws.getFirstPulseTime(), startTime + 1.0);
    for (int i = 2; i < 62; ++i) {
      proton_charge->addValue(startTime + static_cast<double>(i), 1.0E-7);
    TS_ASSERT_EQUALS(ws.getFirstPulseTime(),
                     DateAndTime("1991-01-01T00:00:00"));
  void
  test_getFirstPulseTime_getLastPulseTime_throws_if_protoncharge_missing_or_empty() {
    WorkspaceTester ws;
    TS_ASSERT_THROWS(ws.getFirstPulseTime(), std::runtime_error);
    TS_ASSERT_THROWS(ws.getLastPulseTime(), std::runtime_error);
    ws.mutableRun().addLogData(new TimeSeriesProperty<double>("proton_charge"));
    TS_ASSERT_THROWS(ws.getFirstPulseTime(), std::runtime_error);
    TS_ASSERT_THROWS(ws.getLastPulseTime(), std::runtime_error);
  void
  test_getFirstPulseTime_getLastPulseTime_throws_if_protoncharge_wrong_type() {
    WorkspaceTester ws;
    auto proton_charge = new TimeSeriesProperty<int>("proton_charge");
    proton_charge->addValue("2013-04-21T10:19:10", 1);
    proton_charge->addValue("2013-04-21T10:19:12", 2);
    ws.mutableRun().addLogData(proton_charge);
    TS_ASSERT_THROWS(ws.getFirstPulseTime(), std::invalid_argument);
    TS_ASSERT_THROWS(ws.getLastPulseTime(), std::invalid_argument);
    ws.mutableRun().addProperty(
        new PropertyWithValue<double>("proton_charge", 99.0), true);
    TS_ASSERT_THROWS(ws.getFirstPulseTime(), std::invalid_argument);
    TS_ASSERT_THROWS(ws.getLastPulseTime(), std::invalid_argument);
  void test_getXMinMax() {
    double xmin, xmax;
    ws->getXMinMax(xmin, xmax);
    TS_ASSERT_EQUALS(xmin, 1.0);
    TS_ASSERT_EQUALS(xmax, 1.0);
    TS_ASSERT_EQUALS(ws->getXMin(), 1.0);
    TS_ASSERT_EQUALS(ws->getXMax(), 1.0);
  }

  void test_monitorWorkspace() {
    auto ws = boost::make_shared<WorkspaceTester>();
    TSM_ASSERT("There should be no monitor workspace by default",
               !ws->monitorWorkspace())
    auto ws2 = boost::make_shared<WorkspaceTester>();
    ws->setMonitorWorkspace(ws2);
    TSM_ASSERT_EQUALS("Monitor workspace not successfully set",
                      ws->monitorWorkspace(), ws2)

    ws->setMonitorWorkspace(boost::shared_ptr<MatrixWorkspace>());
    TSM_ASSERT("Monitor workspace not successfully reset",
               !ws->monitorWorkspace())
  void test_getXIndex() {
    WorkspaceTester ws;
    auto &X = ws.dataX(0);
    X[0] = 1.0;
    X[1] = 2.0;
    X[2] = 3.0;
    X[3] = 4.0;

    auto ip = ws.getXIndex(0, 0.0, true);
    TS_ASSERT_EQUALS(ip.first, 0);
    TS_ASSERT_DELTA(ip.second, 0.0, 1e-15);
    ip = ws.getXIndex(0, 0.0, false);
    TS_ASSERT_EQUALS(ip.first, 4);
    TS_ASSERT_DELTA(ip.second, 0.0, 1e-15);
    ip = ws.getXIndex(0, 1.0, true);
    TS_ASSERT_EQUALS(ip.first, 0);
    TS_ASSERT_DELTA(ip.second, 0.0, 1e-15);
    ip = ws.getXIndex(0, 1.0, false);
    TS_ASSERT_EQUALS(ip.first, 4);
    TS_ASSERT_DELTA(ip.second, 0.0, 1e-15);
    ip = ws.getXIndex(0, 5.0, true);
    TS_ASSERT_EQUALS(ip.first, 4);
    TS_ASSERT_DELTA(ip.second, 0.0, 1e-15);
    ip = ws.getXIndex(0, 5.0, false);
    TS_ASSERT_EQUALS(ip.first, 3);
    TS_ASSERT_DELTA(ip.second, 0.0, 1e-15);
    ip = ws.getXIndex(0, 4.0, true);
    TS_ASSERT_EQUALS(ip.first, 4);
    TS_ASSERT_DELTA(ip.second, 0.0, 1e-15);
    ip = ws.getXIndex(0, 4.0, false);
    TS_ASSERT_EQUALS(ip.first, 3);
    TS_ASSERT_DELTA(ip.second, 0.0, 1e-15);
    ip = ws.getXIndex(0, 5.0, true, 5);
    TS_ASSERT_EQUALS(ip.first, 4);
    TS_ASSERT_DELTA(ip.second, 0.0, 1e-15);
    ip = ws.getXIndex(0, 5.0, false, 5);
    TS_ASSERT_EQUALS(ip.first, 4);
    TS_ASSERT_DELTA(ip.second, 0.0, 1e-15);
    ip = ws.getXIndex(0, 3.0, true, 5);
    TS_ASSERT_EQUALS(ip.first, 4);
    TS_ASSERT_DELTA(ip.second, 0.0, 1e-15);
    ip = ws.getXIndex(0, 3.0, false, 5);
    TS_ASSERT_EQUALS(ip.first, 4);
    TS_ASSERT_DELTA(ip.second, 0.0, 1e-15);
    ip = ws.getXIndex(0, 4.0, true, 5);
    TS_ASSERT_EQUALS(ip.first, 4);
    TS_ASSERT_DELTA(ip.second, 0.0, 1e-15);
    ip = ws.getXIndex(0, 4.0, false, 5);
    TS_ASSERT_EQUALS(ip.first, 4);
    TS_ASSERT_DELTA(ip.second, 0.0, 1e-15);
    ip = ws.getXIndex(0, 4.0, true, 4);
    TS_ASSERT_EQUALS(ip.first, 4);
    TS_ASSERT_DELTA(ip.second, 0.0, 1e-15);
    ip = ws.getXIndex(0, 4.0, false, 4);
    TS_ASSERT_EQUALS(ip.first, 4);
    TS_ASSERT_DELTA(ip.second, 0.0, 1e-15);
    ip = ws.getXIndex(0, 4.0, true, 3);
    TS_ASSERT_EQUALS(ip.first, 4);
    TS_ASSERT_DELTA(ip.second, 0.0, 1e-15);
    ip = ws.getXIndex(0, 4.0, false, 3);
    TS_ASSERT_EQUALS(ip.first, 3);
    TS_ASSERT_DELTA(ip.second, 0.0, 1e-15);
    ip = ws.getXIndex(0, 4.0, true);
    TS_ASSERT_EQUALS(ip.first, 4);
    TS_ASSERT_DELTA(ip.second, 0.0, 1e-15);
    ip = ws.getXIndex(0, 4.0, false);
    TS_ASSERT_EQUALS(ip.first, 3);
    TS_ASSERT_DELTA(ip.second, 0.0, 1e-15);
    ip = ws.getXIndex(0, 2.0, true, 3);
    TS_ASSERT_EQUALS(ip.first, 4);
    TS_ASSERT_DELTA(ip.second, 0.0, 1e-15);
    ip = ws.getXIndex(0, 2.0, false, 3);
    TS_ASSERT_EQUALS(ip.first, 3);
    TS_ASSERT_DELTA(ip.second, 0.0, 1e-15);
    ip = ws.getXIndex(0, 1.0, true, 3);
    TS_ASSERT_EQUALS(ip.first, 4);
    TS_ASSERT_DELTA(ip.second, 0.0, 1e-15);
    ip = ws.getXIndex(0, 1.0, false, 3);
    TS_ASSERT_EQUALS(ip.first, 3);
    TS_ASSERT_DELTA(ip.second, 0.0, 1e-15);
    ip = ws.getXIndex(0, 2.1, true);
    TS_ASSERT_EQUALS(ip.first, 1);
    TS_ASSERT_DELTA(ip.second, 0.1, 1e-15);
    ip = ws.getXIndex(0, 2.1, false);
    TS_ASSERT_EQUALS(ip.first, 2);
    TS_ASSERT_DELTA(ip.second, 0.9, 1e-15);
  void test_getImage_0_width() {
    auto &X = ws.dataX(0);
    X[0] = 1.0;
    X[1] = 2.0;
    const size_t start = 0;
    const size_t stop = 8;
    TS_ASSERT_THROWS(ws.getImageY(start, stop, width), std::runtime_error);
    TS_ASSERT_THROWS_NOTHING(ws.getImageY(start, stop, width));
  void test_getImage_wrong_start() {
    auto &X = ws.dataX(0);
    X[0] = 1.0;
    X[1] = 2.0;
    size_t stop = 8;
    TS_ASSERT_THROWS(ws.getImageY(start, stop, width), std::runtime_error);
    TS_ASSERT_THROWS(ws.getImageY(start, stop, width), std::runtime_error);
    TS_ASSERT_THROWS_NOTHING(ws.getImageY(start, stop, width));
  void test_getImage_wrong_stop() {
    auto &X = ws.dataX(0);
    X[0] = 1.0;
    X[1] = 2.0;
    size_t stop = 18;
    TS_ASSERT_THROWS(ws.getImageY(start, stop, width), std::runtime_error);
    TS_ASSERT_THROWS(ws.getImageY(start, stop, width), std::runtime_error);
    TS_ASSERT_THROWS_NOTHING(ws.getImageY(start, stop, width));
  void test_getImage_empty_set() {
    auto &X = ws.dataX(0);
    X[0] = 1.0;
    X[1] = 2.0;
    size_t stop = 0;
    TS_ASSERT_THROWS(ws.getImageY(start, stop, width), std::runtime_error);
    TS_ASSERT_THROWS_NOTHING(ws.getImageY(start, stop, width));
  void test_getImage_non_rectangular() {
    auto &X = ws.dataX(0);
    X[0] = 1.0;
    X[1] = 2.0;
    size_t stop = 7;
    TS_ASSERT_THROWS(ws.getImageY(start, stop, width), std::runtime_error);
  void test_getImage_wrong_indexStart() {
    auto &X = ws.dataX(0);
    X[0] = 1.0;
    X[1] = 2.0;
    const size_t start = 0;
    const size_t stop = 8;
    const size_t width = 3;
    double startX = 3;
    double endX = 4;
    TS_ASSERT_THROWS(ws.getImageY(start, stop, width, startX, endX),
                     std::runtime_error);
    TS_ASSERT_THROWS(wsh.getImageY(start, stop, width, startX, endX),
                     std::runtime_error);
  void test_getImage_wrong_indexEnd() {
    auto &X = ws.dataX(0);
    X[0] = 1.0;
    X[1] = 2.0;
    const size_t start = 0;
    const size_t stop = 8;
    const size_t width = 3;
    double startX = 1.0;
    double endX = 0.0;
    TS_ASSERT_THROWS(ws.getImageY(start, stop, width, startX, endX),
                     std::runtime_error);
    auto &X1 = ws.dataX(0);
    X1[0] = 1.0;
    X1[1] = 2.0;
    startX = 1.0;
    endX = 0.0;
    TS_ASSERT_THROWS(wsh.getImageY(start, stop, width, startX, endX),
                     std::runtime_error);
  void test_getImage_single_bin_histo() {
    auto &X = ws.dataX(0);
    X[0] = 1.0;
    X[1] = 2.0;
    for (size_t i = 0; i < ws.getNumberHistograms(); ++i) {
      ws.dataY(i)[0] = static_cast<double>(i + 1);
    const size_t stop = 8;
    const size_t width = 3;
    double startX = 0;
    double endX = 3;
    Mantid::API::MantidImage_sptr image;
    TS_ASSERT_THROWS_NOTHING(
        image = ws.getImageY(start, stop, width, startX, endX));
    if (!image)
      return;
    TS_ASSERT_EQUALS(image->size(), 3);
    TS_ASSERT_EQUALS((*image)[0].size(), 3);
    TS_ASSERT_EQUALS((*image)[1].size(), 3);
    TS_ASSERT_EQUALS((*image)[2].size(), 3);

    TS_ASSERT_EQUALS((*image)[0][0], 1);
    TS_ASSERT_EQUALS((*image)[0][1], 2);
    TS_ASSERT_EQUALS((*image)[0][2], 3);
    TS_ASSERT_EQUALS((*image)[1][0], 4);
    TS_ASSERT_EQUALS((*image)[1][1], 5);
    TS_ASSERT_EQUALS((*image)[1][2], 6);
    TS_ASSERT_EQUALS((*image)[2][0], 7);
    TS_ASSERT_EQUALS((*image)[2][1], 8);
    TS_ASSERT_EQUALS((*image)[2][2], 9);
  }

  void test_getImage_single_bin_points() {
    auto &X = ws.dataX(0);
    X[0] = 1.0;
    for (size_t i = 0; i < ws.getNumberHistograms(); ++i) {
      ws.dataY(i)[0] = static_cast<double>(i + 1);
    const size_t stop = 8;
    const size_t width = 3;
    double startX = 1;
    double endX = 1;
    Mantid::API::MantidImage_sptr image;
    TS_ASSERT_THROWS_NOTHING(
        image = ws.getImageY(start, stop, width, startX, endX));
    if (!image)
      return;
    TS_ASSERT_EQUALS(image->size(), 3);
    TS_ASSERT_EQUALS((*image)[0].size(), 3);
    TS_ASSERT_EQUALS((*image)[1].size(), 3);
    TS_ASSERT_EQUALS((*image)[2].size(), 3);

    TS_ASSERT_EQUALS((*image)[0][0], 1);
    TS_ASSERT_EQUALS((*image)[0][1], 2);
    TS_ASSERT_EQUALS((*image)[0][2], 3);
    TS_ASSERT_EQUALS((*image)[1][0], 4);
    TS_ASSERT_EQUALS((*image)[1][1], 5);
    TS_ASSERT_EQUALS((*image)[1][2], 6);
    TS_ASSERT_EQUALS((*image)[2][0], 7);
    TS_ASSERT_EQUALS((*image)[2][1], 8);
    TS_ASSERT_EQUALS((*image)[2][2], 9);
  }

  void test_getImage_multi_bin_histo() {
    auto &X = ws.dataX(0);
    X[0] = 1.0;
    X[1] = 2.0;
    X[2] = 3.0;
    X[3] = 4.0;
    for (size_t i = 0; i < ws.getNumberHistograms(); ++i) {
      ws.dataY(i)[0] = static_cast<double>(i + 1);
      ws.dataY(i)[1] = static_cast<double>(i + 2);
      ws.dataY(i)[2] = static_cast<double>(i + 3);
    const size_t stop = 8;
    const size_t width = 3;
    Mantid::API::MantidImage_sptr image;
    TS_ASSERT_THROWS_NOTHING(image = ws.getImageY(start, stop, width));
    if (!image)
      return;
    TS_ASSERT_EQUALS(image->size(), 3);
    TS_ASSERT_EQUALS((*image)[0].size(), 3);
    TS_ASSERT_EQUALS((*image)[1].size(), 3);
    TS_ASSERT_EQUALS((*image)[2].size(), 3);

    TS_ASSERT_EQUALS((*image)[0][0], 6);
    TS_ASSERT_EQUALS((*image)[0][1], 9);
    TS_ASSERT_EQUALS((*image)[0][2], 12);
    TS_ASSERT_EQUALS((*image)[1][0], 15);
    TS_ASSERT_EQUALS((*image)[1][1], 18);
    TS_ASSERT_EQUALS((*image)[1][2], 21);
    TS_ASSERT_EQUALS((*image)[2][0], 24);
    TS_ASSERT_EQUALS((*image)[2][1], 27);
    TS_ASSERT_EQUALS((*image)[2][2], 30);
  }

  void test_getImage_multi_bin_points() {
    auto &X = ws.dataX(0);
    X[0] = 1.0;
    X[1] = 2.0;
    X[2] = 3.0;
    for (size_t i = 0; i < ws.getNumberHistograms(); ++i) {
      ws.dataY(i)[0] = static_cast<double>(i + 1);
      ws.dataY(i)[1] = static_cast<double>(i + 2);
      ws.dataY(i)[2] = static_cast<double>(i + 3);
    const size_t stop = 8;
    const size_t width = 3;
    Mantid::API::MantidImage_sptr image;
    TS_ASSERT_THROWS_NOTHING(image = ws.getImageY(start, stop, width));
    if (!image)
      return;
    TS_ASSERT_EQUALS(image->size(), 3);
    TS_ASSERT_EQUALS((*image)[0].size(), 3);
    TS_ASSERT_EQUALS((*image)[1].size(), 3);
    TS_ASSERT_EQUALS((*image)[2].size(), 3);

    TS_ASSERT_EQUALS((*image)[0][0], 6);
    TS_ASSERT_EQUALS((*image)[0][1], 9);
    TS_ASSERT_EQUALS((*image)[0][2], 12);
    TS_ASSERT_EQUALS((*image)[1][0], 15);
    TS_ASSERT_EQUALS((*image)[1][1], 18);
    TS_ASSERT_EQUALS((*image)[1][2], 21);
    TS_ASSERT_EQUALS((*image)[2][0], 24);
    TS_ASSERT_EQUALS((*image)[2][1], 27);
    TS_ASSERT_EQUALS((*image)[2][2], 30);
  }

  void test_setImage_too_large() {
    auto image = createImage(2, 3);
    WorkspaceTester ws;
    TS_ASSERT_THROWS(ws.setImageY(*image), std::runtime_error);
  void test_setImage_not_single_bin() {
    auto image = createImage(2, 3);
    WorkspaceTester ws;
    TS_ASSERT_THROWS(ws.setImageY(*image), std::runtime_error);
  void test_setImageY() {
    auto image = createImage(2, 3);
    WorkspaceTester ws;
    TS_ASSERT_THROWS_NOTHING(ws.setImageY(*image));
    TS_ASSERT_EQUALS(ws.readY(0)[0], 1);
    TS_ASSERT_EQUALS(ws.readY(1)[0], 2);
    TS_ASSERT_EQUALS(ws.readY(2)[0], 3);
    TS_ASSERT_EQUALS(ws.readY(3)[0], 4);
    TS_ASSERT_EQUALS(ws.readY(4)[0], 5);
    TS_ASSERT_EQUALS(ws.readY(5)[0], 6);
  }

  void test_setImageE() {
    auto image = createImage(2, 3);
    WorkspaceTester ws;
    TS_ASSERT_THROWS_NOTHING(ws.setImageE(*image));
    TS_ASSERT_EQUALS(ws.readE(0)[0], 1);
    TS_ASSERT_EQUALS(ws.readE(1)[0], 2);
    TS_ASSERT_EQUALS(ws.readE(2)[0], 3);
    TS_ASSERT_EQUALS(ws.readE(3)[0], 4);
    TS_ASSERT_EQUALS(ws.readE(4)[0], 5);
    TS_ASSERT_EQUALS(ws.readE(5)[0], 6);
  }

  void test_setImageY_start() {
    auto image = createImage(2, 3);
    WorkspaceTester ws;
    TS_ASSERT_THROWS_NOTHING(ws.setImageY(*image, 3));
    TS_ASSERT_EQUALS(ws.readY(3)[0], 1);
    TS_ASSERT_EQUALS(ws.readY(4)[0], 2);
    TS_ASSERT_EQUALS(ws.readY(5)[0], 3);
    TS_ASSERT_EQUALS(ws.readY(6)[0], 4);
    TS_ASSERT_EQUALS(ws.readY(7)[0], 5);
    TS_ASSERT_EQUALS(ws.readY(8)[0], 6);
  }

  void test_setImageE_start() {
    auto image = createImage(2, 3);
    WorkspaceTester ws;
    TS_ASSERT_THROWS_NOTHING(ws.setImageE(*image, 2));
    TS_ASSERT_EQUALS(ws.readE(2)[0], 1);
    TS_ASSERT_EQUALS(ws.readE(3)[0], 2);
    TS_ASSERT_EQUALS(ws.readE(4)[0], 3);
    TS_ASSERT_EQUALS(ws.readE(5)[0], 4);
    TS_ASSERT_EQUALS(ws.readE(6)[0], 5);
    TS_ASSERT_EQUALS(ws.readE(7)[0], 6);
  * Test declaring an input workspace and retrieving as const_sptr or sptr
  */
  void testGetProperty_const_sptr() {
    const std::string wsName = "InputWorkspace";
Hahn, Steven's avatar
Hahn, Steven committed
    MatrixWorkspace_sptr wsInput = boost::make_shared<WorkspaceTester>();
    PropertyManagerHelper manager;
    manager.declareProperty(wsName, wsInput, Direction::Input);

    // Check property can be obtained as const_sptr or sptr
    MatrixWorkspace_const_sptr wsConst;
    MatrixWorkspace_sptr wsNonConst;
    TS_ASSERT_THROWS_NOTHING(
        wsConst = manager.getValue<MatrixWorkspace_const_sptr>(wsName));
    TS_ASSERT(wsConst != NULL);
    TS_ASSERT_THROWS_NOTHING(
        wsNonConst = manager.getValue<MatrixWorkspace_sptr>(wsName));
    TS_ASSERT(wsNonConst != NULL);
    TS_ASSERT_EQUALS(wsConst, wsNonConst);

    // Check TypedValue can be cast to const_sptr or to sptr
    PropertyManagerHelper::TypedValue val(manager, wsName);
    MatrixWorkspace_const_sptr wsCastConst;
    MatrixWorkspace_sptr wsCastNonConst;
    TS_ASSERT_THROWS_NOTHING(wsCastConst = (MatrixWorkspace_const_sptr)val);
    TS_ASSERT(wsCastConst != NULL);
    TS_ASSERT_THROWS_NOTHING(wsCastNonConst = (MatrixWorkspace_sptr)val);
    TS_ASSERT(wsCastNonConst != NULL);
    TS_ASSERT_EQUALS(wsCastConst, wsCastNonConst);
  }

  void test_x_uncertainty_can_be_set() {
    // Arrange
    WorkspaceTester ws;
    const size_t numspec = 4;
    const size_t j = 3;
    const size_t k = j;
    ws.initialize(numspec, j, k);
    double values[3] = {10, 11, 17};
    size_t workspaceIndexWithDx[3] = {0, 1, 2};
    Mantid::MantidVec dxSpec0(j, values[0]);
    auto dxSpec1 =
        Kernel::make_cow<Mantid::HistogramData::HistogramDx>(j, values[1]);
    auto dxSpec2 = boost::make_shared<Mantid::HistogramData::HistogramDx>(
        Mantid::MantidVec(j, values[2]));
    // Act
    for (size_t spec = 0; spec < numspec; ++spec) {
      TSM_ASSERT("Should not have any x resolution values", !ws.hasDx(spec));
    }
    ws.dataDx(workspaceIndexWithDx[0]) = dxSpec0;
    ws.setSharedDx(workspaceIndexWithDx[1], dxSpec1);
    ws.setSharedDx(workspaceIndexWithDx[2], dxSpec2);
    auto compareValue =
        [&values](double data, size_t index) { return data == values[index]; };
    for (auto &index : workspaceIndexWithDx) {
      TSM_ASSERT("Should have x resolution values", ws.hasDx(index));
      TSM_ASSERT_EQUALS("Should have a length of 3", ws.dataDx(index).size(),
      auto compareValueForSpecificWorkspaceIndex =
          std::bind(compareValue, std::placeholders::_1, index);
      auto &dataDx = ws.dataDx(index);
      TSM_ASSERT("dataDx should allow access to the spectrum",
                 std::all_of(std::begin(dataDx), std::end(dataDx),
                             compareValueForSpecificWorkspaceIndex));
      auto &readDx = ws.readDx(index);
      TSM_ASSERT("readDx should allow access to the spectrum",
                 std::all_of(std::begin(readDx), std::end(readDx),
                             compareValueForSpecificWorkspaceIndex));
      auto refDx = ws.sharedDx(index);
      TSM_ASSERT("readDx should allow access to the spectrum",
                 std::all_of(std::begin(*refDx), std::end(*refDx),
                             compareValueForSpecificWorkspaceIndex));

    TSM_ASSERT("Should not have any x resolution values", !ws.hasDx(3));
  void test_scanning() {
    // Set up 2 workspaces to be merged
    auto ws1 = makeWorkspaceWithDetectors(1, 1);
    auto ws2 = makeWorkspaceWithDetectors(1, 1);
    auto &detInfo1 = ws1->mutableDetectorInfo();
    auto &detInfo2 = ws2->mutableDetectorInfo();
    detInfo1.setPosition(0, {1, 0, 0});
    detInfo2.setPosition(0, {2, 0, 0});
    detInfo1.setScanInterval(0, {10, 20});
    detInfo2.setScanInterval(0, {20, 30});

    // Merge
    auto merged = WorkspaceFactory::Instance().create(ws1, 2);
    auto &detInfo = merged->mutableDetectorInfo();
    detInfo.merge(detInfo2);

    // Setting IndexInfo without spectrum definitions will set up a 1:1 mapping
    // such that each spectrum corresponds to 1 time index of a detector.
    merged->setIndexInfo(IndexInfo(merged->getNumberHistograms()));

    const auto &specInfo = merged->spectrumInfo();
    TS_ASSERT(specInfo.hasDetectors(0));
    TS_ASSERT(specInfo.hasDetectors(1));
    // This is the order we get currently from the default mapping, but it is
    // not guaranteed by the interface and might change.
    TS_ASSERT_EQUALS(specInfo.position(0), V3D(1, 0, 0));
    TS_ASSERT_EQUALS(specInfo.position(1), V3D(2, 0, 0));

    TS_ASSERT_THROWS_NOTHING(specInfo.detector(0));
    const auto &det = specInfo.detector(0);
    // Failing legacy methods (use DetectorInfo/SpectrumInfo instead):
    TS_ASSERT_THROWS(det.getPos(), std::runtime_error);
    TS_ASSERT_THROWS(det.getRelativePos(), std::runtime_error);
    TS_ASSERT_THROWS(det.getRotation(), std::runtime_error);
    TS_ASSERT_THROWS(det.getRelativeRot(), std::runtime_error);
    TS_ASSERT_THROWS(det.getPhi(), std::runtime_error);
    // Failing methods, currently without replacement:
    TS_ASSERT_THROWS(det.solidAngle(V3D(0, 0, 0)), std::runtime_error);
    BoundingBox bb;
    TS_ASSERT_THROWS(det.getBoundingBox(bb), std::runtime_error);
    // Moving parent not possible since non-detector components do not have time
    // indices and thus DetectorInfo cannot tell which set of detector positions
    // to adjust.

    auto &compInfo = merged->mutableComponentInfo();

    // Try to move the parent
    TS_ASSERT_THROWS(compInfo.setPosition(compInfo.parent(compInfo.indexOf(
                                              det.getComponentID())),
                                          V3D(1, 2, 3)),
    // Try to rotate the parent
    TS_ASSERT_THROWS(compInfo.setRotation(compInfo.parent(compInfo.indexOf(
                                              det.getComponentID())),
                                          Quat(1, 2, 3, 4)),
  void test_legacy_setting_spectrum_numbers_with_MPI() {
    ParallelTestHelpers::runParallel(
        run_legacy_setting_spectrum_numbers_with_MPI);
  }

  Mantid::API::MantidImage_sptr createImage(const size_t width,
                                            const size_t height) {
    auto image =
        boost::make_shared<Mantid::API::MantidImage>(height, MantidVec(width));
    double startingValue = 1.0;
    for (auto &row : *image) {
      std::iota(row.begin(), row.end(), startingValue);
      startingValue += static_cast<double>(width);
  /**
   * Create a test workspace. Can be histo or points depending on x/yLength.
   * @param nVectors :: [input] Number of vectors
   * @param xLength :: [input] Length of X vector
   * @param yLength :: [input] Length of Y, E vectors
   * @returns :: workspace
   */
  WorkspaceTester createTestWorkspace(size_t nVectors, size_t xLength,
                                      size_t yLength) {
    WorkspaceTester ws;
    ws.initialize(nVectors, xLength, yLength);
    // X data
    std::vector<double> xData(xLength);
    std::iota(xData.begin(), xData.end(), 0.0);

    // Y data
    const auto yCounts = [&yLength](size_t wi) {
      std::vector<double> v(yLength);
      std::iota(v.begin(), v.end(), static_cast<double>(wi) * 10.0);
      return v;
    };

    // E data
    const auto errors = [&yLength](size_t wi) {
      std::vector<double> v(yLength);
      std::generate(v.begin(), v.end(), [&wi]() {
        return std::sqrt(static_cast<double>(wi) * 10.0);
      });
      return v;
    };

    for (size_t wi = 0; wi < nVectors; ++wi) {
      if (xLength == yLength) {
        ws.setPoints(wi, xData);
      } else if (xLength == yLength + 1) {
        ws.setBinEdges(wi, xData);
      } else {
        throw std::invalid_argument(
            "yLength must either be equal to xLength or xLength - 1");
      }
      ws.setCounts(wi, yCounts(wi));
      ws.setCountStandardDeviations(wi, errors(wi));
    }
    return ws;
  }

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

  MatrixWorkspaceTestPerformance() : m_workspace() {
    using namespace Mantid::Geometry;

    size_t numberOfHistograms = 10000;
    size_t numberOfBins = 1;
    m_workspace.initialize(numberOfHistograms, numberOfBins + 1, numberOfBins);
    bool includeMonitors = false;
    bool startYNegative = true;
    const std::string instrumentName("SimpleFakeInstrument");
    InstrumentCreationHelper::addFullInstrumentToWorkspace(
        m_workspace, includeMonitors, startYNegative, instrumentName);

    Mantid::Kernel::V3D sourcePos(0, 0, 0);
    Mantid::Kernel::V3D samplePos(0, 0, 1);
    Mantid::Kernel::V3D trolley1Pos(0, 0, 3);
    Mantid::Kernel::V3D trolley2Pos(0, 0, 6);
    m_paramMap = boost::make_shared<Mantid::Geometry::ParameterMap>();

    auto baseInstrument = ComponentCreationHelper::sansInstrument(
        sourcePos, samplePos, trolley1Pos, trolley2Pos);

    auto sansInstrument =
        boost::make_shared<Instrument>(baseInstrument, m_paramMap);
    // See component creation helper for instrument definition
    m_sansBank = sansInstrument->getComponentByName("Bank1");
Owen Arnold's avatar
Owen Arnold committed
    numberOfHistograms = sansInstrument->getNumberDetectors();
    m_workspaceSans.initialize(numberOfHistograms, numberOfBins + 1,
                               numberOfBins);
    m_workspaceSans.setInstrument(sansInstrument);
    m_workspaceSans.getAxis(0)->setUnit("TOF");
    m_workspaceSans.rebuildSpectraMapping();
    m_zRotation =
        Mantid::Kernel::Quat(180, V3D(0, 0, 1)); // rotate 180 degrees around z
    m_pos = Mantid::Kernel::V3D(1, 1, 1);
  }
  /// This test is equivalent to GeometryInfoFactoryTestPerformance, see there.
  void test_typical() {
    auto instrument = m_workspace.getInstrument();
    auto source = instrument->getSource();
    auto sample = instrument->getSample();
    auto L1 = source->getDistance(*sample);
    double result = 0.0;
    for (size_t i = 0; i < 10000; ++i) {
      auto detector = m_workspace.getDetector(i);
      result += L1;
      result += detector->getDistance(*sample);
      result += m_workspace.detectorTwoTheta(*detector);
    // We are computing and using the result to fool the optimizer.
    TS_ASSERT_DELTA(result, 5214709.740869, 1e-6);
  }

  void test_calculateL2() {

    /*
     * Simulate the L2 calculation performed via the Workspace/Instrument
     * interface.
     */
    auto instrument = m_workspaceSans.getInstrument();
    auto sample = instrument->getSample();
    double l2 = 0;
    for (size_t i = 0; i < m_workspaceSans.getNumberHistograms(); ++i) {
      auto detector = m_workspaceSans.getDetector(i);
      l2 += detector->getDistance(*sample);
    }
    // Prevent optimization
    TS_ASSERT(l2 > 0);
  }

  void test_calculateL2_x10() {

    /*
     * Simulate the L2 calculation performed via the Workspace/Instrument
     * interface. Repeat several times to benchmark any caching/optmisation that
     * might be taken place in parameter maps.
     */
    auto instrument = m_workspaceSans.getInstrument();
    auto sample = instrument->getSample();
    double l2 = 0;
    int count = 0;
    while (count < 10) {
      for (size_t i = 0; i < m_workspaceSans.getNumberHistograms(); ++i) {
        auto detector = m_workspaceSans.getDetector(i);
        l2 += detector->getDistance(*sample);
      }
      ++count;
    }
    // Prevent optimization
    TS_ASSERT(l2 > 0);
  }

Owen Arnold's avatar
Owen Arnold committed
   * Rotate a bank in the workspace and read the positions out again. Very
   * typical.
  void test_rotate_bank_and_read_positions_x10() {

    using namespace Mantid::Geometry;
    using namespace Mantid::Kernel;

    int count = 0;
    // Repeated execution to improve statistics and for comparison purposes with
    // future updates
    while (count < 10) {
Owen Arnold's avatar
Owen Arnold committed
      // Rotate the bank
      auto &compInfo = m_workspaceSans.mutableComponentInfo();
      compInfo.setRotation(compInfo.indexOf(m_sansBank->getComponentID()),
                           m_zRotation);
Owen Arnold's avatar
Owen Arnold committed

      V3D pos;
      for (size_t i = 1; i < m_workspaceSans.getNumberHistograms(); ++i) {
        pos += m_workspaceSans.getDetector(i)->getPos();
      }
      ++count;
Owen Arnold's avatar
Owen Arnold committed
   * Move a bank in the workspace and read the positions out again. Very
   * typical.
  void test_move_bank_and_read_positions_x10() {

    using namespace Mantid::Geometry;
    using namespace Mantid::Kernel;

    int count = 0;
    // Repeated execution to improve statistics and for comparison purposes with
    // future updates
    while (count < 10) {
Owen Arnold's avatar
Owen Arnold committed
      // move the bank
      auto &compInfo = m_workspaceSans.mutableComponentInfo();
      compInfo.setPosition(compInfo.indexOf(m_sansBank->getComponentID()),
                           m_pos);
Owen Arnold's avatar
Owen Arnold committed

      V3D pos;
      for (size_t i = 1; i < m_workspaceSans.getNumberHistograms(); ++i) {
        pos += m_workspaceSans.getDetector(i)->getPos();
      }
      ++count;
  // As test_rotate_bank_and_read_positions_x10 but based on SpectrumInfo.
  void test_rotate_bank_and_read_positions_SpectrumInfo_x10() {
    int count = 0;
    while (count < 10) {
      // Rotate the bank
      auto &compInfo = m_workspaceSans.mutableComponentInfo();
      compInfo.setRotation(compInfo.indexOf(m_sansBank->getComponentID()),
                           m_zRotation);

      V3D pos;
      const auto &spectrumInfo = m_workspaceSans.spectrumInfo();
      for (size_t i = 1; i < m_workspaceSans.getNumberHistograms(); ++i) {
        pos += spectrumInfo.position(i);
      }
      ++count;
    }
  }

  // As test_move_bank_and_read_positions_x10 but based on SpectrumInfo.
  void test_move_bank_and_read_positions_SpectrumInfo_x10() {
    int count = 0;
    while (count < 10) {
      // move the bank
      auto &compInfo = m_workspaceSans.mutableComponentInfo();
      compInfo.setPosition(compInfo.indexOf(m_sansBank->getComponentID()),
                           m_pos);

      V3D pos;
      const auto &spectrumInfo = m_workspaceSans.spectrumInfo();
      for (size_t i = 1; i < m_workspaceSans.getNumberHistograms(); ++i) {
        pos += spectrumInfo.position(i);
      }
      ++count;
    }
  }

private:
  WorkspaceTester m_workspace;
  WorkspaceTester m_workspaceSans;
  Mantid::Kernel::Quat m_zRotation;
  Mantid::Kernel::V3D m_pos;
  Mantid::Geometry::IComponent_const_sptr m_sansBank;
  boost::shared_ptr<Mantid::Geometry::ParameterMap> m_paramMap;
#endif /*WORKSPACETEST_H_*/