Skip to content
Snippets Groups Projects
CachedExperimentInfoTest.h 9.61 KiB
Newer Older
#ifndef OBSERVATIONTEST_H_
#define OBSERVATIONTEST_H_

#include "MantidMDAlgorithms/Quantification/CachedExperimentInfo.h"
#include "MantidKernel/DeltaEMode.h"
#include "MantidGeometry/Crystal/OrientedLattice.h"
#include "MantidGeometry/Instrument/ReferenceFrame.h"
#include "MantidAPI/Run.h"
#include "MantidAPI/Sample.h"

#include "MantidTestHelpers/ComponentCreationHelper.h"
#include <cxxtest/TestSuite.h>
#include <boost/make_shared.hpp>

using Mantid::MDAlgorithms::CachedExperimentInfo;
using Mantid::Kernel::DeltaEMode;
using Mantid::Kernel::V3D;

class CachedExperimentInfoTest : public CxxTest::TestSuite {
  enum TestObjectType {
    NoChopper,
    WithChopper,
    NoAperture,
    WithAperture,
    NoDetShape,
    WithDetShape
  };
  // This pair of boilerplate methods prevent the suite being created statically
  // This means the constructor isn't called when running other tests
  static CachedExperimentInfoTest *createSuite() {
    return new CachedExperimentInfoTest();
  static void destroySuite(CachedExperimentInfoTest *suite) { delete suite; }
  CachedExperimentInfoTest()
      : m_test_ei(12.1), m_test_ef(15.5), m_sourcePos(0.0, 0.0, -10.0),
        m_chopperPos(0, 0, -3.), m_aperturePos(0., 0., -8.) {}

  void test_trying_to_construct_object_with_unknown_id_throws_exception() {
    // createEmptyExptInfo();
    auto expt = boost::make_shared<Mantid::API::ExperimentInfo>();
    TS_ASSERT_THROWS(CachedExperimentInfo(*expt, 1000), std::out_of_range);
  void test_trying_to_construct_object_with_no_chopper_throws() {
    TS_ASSERT_THROWS(createTestCachedExperimentInfo(NoChopper),
                     std::invalid_argument);
  void test_trying_to_construct_object_with_no_aperature_throws() {
    TS_ASSERT_THROWS(createTestCachedExperimentInfo(WithChopper, NoAperture),
                     std::invalid_argument);
  void test_trying_to_construct_object_with_no_det_shape_throws() {
    TS_ASSERT_THROWS(createTestCachedExperimentInfo(WithChopper, WithAperture,
                                                    DeltaEMode::Direct,
                                                    V3D(1, 1, 1), NoDetShape),
  void test_efixed_returns_Ei_for_direct_mode() {
    boost::shared_ptr<CachedExperimentInfo> event =
        createTestCachedExperimentInfo(WithChopper, WithAperture,
                                       DeltaEMode::Direct);
    TS_ASSERT_EQUALS(event->getEFixed(), m_test_ei);
  }

  void test_efixed_returns_EFixed_for_indirect_mode() {
    boost::shared_ptr<CachedExperimentInfo> event =
        createTestCachedExperimentInfo(WithChopper, WithAperture,
                                       DeltaEMode::Indirect);
    TS_ASSERT_EQUALS(event->getEFixed(), m_test_ef);
  }

  void test_theta_angle_from_beam_is_correct() {
    boost::shared_ptr<CachedExperimentInfo> event =
        createTestCachedExperimentInfo();
    TS_ASSERT_DELTA(event->twoTheta(), 0.440510663, 1e-09);
  }

  void test_phi_angle_from_beam_is_correct() {
    boost::shared_ptr<CachedExperimentInfo> event =
        createTestCachedExperimentInfo();
    TS_ASSERT_DELTA(event->phi(), M_PI / 4., 1e-09);
  void test_sample_to_detector_distance_gives_expected_results() {
    boost::shared_ptr<CachedExperimentInfo> event =
        createTestCachedExperimentInfo();

    TS_ASSERT_DELTA(event->sampleToDetectorDistance(), std::sqrt(11.), 1e-12);
  }

  void test_moderator_to_first_chopper_distance_gives_expected_result() {
    boost::shared_ptr<CachedExperimentInfo> event =
        createTestCachedExperimentInfo(WithChopper);
    const double expectedDistance = m_chopperPos.distance(m_sourcePos);

    TS_ASSERT_DELTA(event->moderatorToFirstChopperDistance(), expectedDistance,
                    1e-12);
  void test_first_chopper_to_sample_distance_gives_expected_result() {
    boost::shared_ptr<CachedExperimentInfo> event =
        createTestCachedExperimentInfo(WithChopper);
    const double expectedDistance = m_chopperPos.distance(V3D());

    TS_ASSERT_DELTA(event->firstChopperToSampleDistance(), expectedDistance,
                    1e-12);
  void test_first_aperture_to_first_chopper_distance_gives_expected_result() {
    boost::shared_ptr<CachedExperimentInfo> event =
        createTestCachedExperimentInfo(WithChopper, WithAperture);
    const double expectedDistance = m_chopperPos.distance(m_aperturePos);
    TS_ASSERT_DELTA(event->firstApertureToFirstChopperDistance(),
                    expectedDistance, 1e-12);
  void test_aperture_size_is_expected() {
    boost::shared_ptr<CachedExperimentInfo> event =
        createTestCachedExperimentInfo(WithChopper, WithAperture);
    const double expectedWidth(0.08), expectedHeight(0.05);

    std::pair<double, double> apSize = event->apertureSize();
    TS_ASSERT_DELTA(apSize.first, expectedWidth, 1e-4);
    TS_ASSERT_DELTA(apSize.second, expectedHeight, 1e-4);
  void test_sample_widths_are_expected() {
    boost::shared_ptr<CachedExperimentInfo> event =
        createTestCachedExperimentInfo(WithChopper, WithAperture);
    const Mantid::Kernel::V3D &sampleWidths = event->sampleCuboid();
    TS_ASSERT_DELTA(sampleWidths.X(), 0.2, 1e-5);
    TS_ASSERT_DELTA(sampleWidths.Y(), 0.4, 1e-5);
    TS_ASSERT_DELTA(sampleWidths.Z(), 0.6, 1e-5);
  void test_detector_volume_gives_expected_pos() {
    boost::shared_ptr<CachedExperimentInfo> event =
        createTestCachedExperimentInfo(WithChopper, WithAperture,
                                       DeltaEMode::Direct, V3D(1, 1, 1));
    Mantid::Kernel::V3D volume;
    TS_ASSERT_THROWS_NOTHING(volume = event->detectorVolume());
    TS_ASSERT_DELTA(volume[0], 0.0240, 1e-6);
    TS_ASSERT_DELTA(volume[1], 0.0100, 1e-6);
    TS_ASSERT_DELTA(volume[2], 0.0240, 1e-6);
  void test_labToDetTransformation_Yields_Expected_Matrix() {
    boost::shared_ptr<CachedExperimentInfo> event =
        createTestCachedExperimentInfo(WithChopper, WithAperture,
                                       DeltaEMode::Direct, V3D(1, 1, 1));
    const double sintheta = std::sqrt(2. / 3.);
    const double costheta = 1. / std::sqrt(3.);
    const double sinphi = 0.5 * M_SQRT2;
    const double cosphi = 0.5 * M_SQRT2;
    double expectedMatrix[3][3] = {{costheta * cosphi, -sinphi, costheta},
                                   {costheta * cosphi, cosphi, costheta},
                                   {-sintheta, 0.0, costheta}};

    Mantid::Kernel::DblMatrix labToDet = event->labToDetectorTransform();
    for (int i = 0; i < 3; ++i) {
      for (int j = 0; j < 3; ++j) {
        std::ostringstream os;
        os << "Mismatch at row=" << i << ", col=" << j;
        TSM_ASSERT_DELTA(os.str(), labToDet[i][j], expectedMatrix[i][j], 1e-12);
      }
    }
  }

private:
  void createEmptyExptInfo() {
    m_expt = boost::make_shared<Mantid::API::ExperimentInfo>();
  boost::shared_ptr<CachedExperimentInfo> createTestCachedExperimentInfo(
      const TestObjectType addChopper = WithChopper,
      const TestObjectType addAperture = WithAperture,
      const DeltaEMode::Type emode = DeltaEMode::Direct,
      const V3D &detPos = V3D(1, 1, 3),
      const TestObjectType addDetShape = WithDetShape) {
    using namespace Mantid::API;
    using namespace Mantid::Geometry;

    Instrument_sptr instrument(new Instrument("test-inst"));
    instrument->setReferenceFrame(boost::make_shared<ReferenceFrame>(
        Mantid::Geometry::Y, Mantid::Geometry::Z, Mantid::Geometry::Right,
        "frame"));
    Detector *det1 = new Detector("det1", g_test_id, instrument.get());
    if (addDetShape == WithDetShape) {
      auto shape = ComponentCreationHelper::createCappedCylinder(
          0.012, 0.01, detPos, V3D(0, 1, 0), "cyl");
      det1->setShape(shape);
    }
    instrument->add(det1);
    det1->setPos(detPos);
    instrument->markAsDetector(det1);

    ObjComponent *source = new ObjComponent("source");
    source->setPos(m_sourcePos);
    instrument->add(source);
    instrument->markAsSource(source);

    ObjComponent *samplePos = new ObjComponent("samplePos");
    instrument->add(samplePos);
    instrument->markAsSamplePos(samplePos);
    auto sampleShape = ComponentCreationHelper::createCuboid(0.1, 0.2, 0.3);
    m_expt->mutableSample().setShape(sampleShape);
    if (addChopper == WithChopper) {
      ObjComponent *chopper = new ObjComponent("firstChopperPos");
      chopper->setPos(m_chopperPos);
      instrument->add(chopper);
      instrument->markAsChopperPoint(chopper);
    }

    if (addAperture == WithAperture) {
      ObjComponent *aperture = new ObjComponent("aperture");
      aperture->setPos(m_aperturePos);
      auto shape = ComponentCreationHelper::createCuboid(0.04, 0.025, 0.05);
    m_expt->mutableRun().addProperty("deltaE-mode",
                                     DeltaEMode::asString(emode));
    Mantid::Geometry::OrientedLattice latt(5.57, 5.51, 12.298);
    m_expt->mutableSample().setOrientedLattice(&latt);
    if (emode == DeltaEMode::Direct) // Direct
      m_expt->mutableRun().addProperty("Ei", m_test_ei);
    } else if (emode == DeltaEMode::Indirect) // Indirect
      m_expt->instrumentParameters().addDouble(det1, "EFixed", m_test_ef);
    } else {
    return boost::make_shared<CachedExperimentInfo>(
        *m_expt, static_cast<Mantid::detid_t>(g_test_id));
  }

  enum { g_test_id = 1 };
  const double m_test_ei;
  const double m_test_ef;
  const V3D m_sourcePos;
  const V3D m_chopperPos;
  const V3D m_aperturePos;

  Mantid::API::ExperimentInfo_sptr m_expt;