Skip to content

Commit

Permalink
Refs #9445. Cleaned up PoldiInstrumentAdapter.
Browse files Browse the repository at this point in the history
Added unit tests for chopper speed extraction functors.
  • Loading branch information
Michael Wedel committed Jun 25, 2014
1 parent c1aec4c commit 6767d05
Show file tree
Hide file tree
Showing 4 changed files with 274 additions and 17 deletions.
1 change: 1 addition & 0 deletions Code/Mantid/Framework/SINQ/CMakeLists.txt
Expand Up @@ -101,6 +101,7 @@ set ( TEST_FILES
PoldiDetectorFactoryTest.h
PoldiDetectorTest.h
PoldiFitPeaks1DTest.h
PoldiInstrumentAdapterTest.h
PoldiPeakCollectionTest.h
PoldiPeakSearchTest.h
PoldiPeakTest.h
Expand Down
Expand Up @@ -5,6 +5,9 @@
#include "MantidSINQ/DllConfig.h"
#include "MantidGeometry/Instrument.h"
#include "MantidAPI/ExperimentInfo.h"
#include "MantidAPI/MatrixWorkspace.h"

#include <map>

#include "MantidSINQ/PoldiUtilities/PoldiAbstractDetector.h"
#include "MantidSINQ/PoldiUtilities/PoldiAbstractChopper.h"
Expand Down Expand Up @@ -36,9 +39,53 @@ namespace Poldi
Code Documentation is available at: <http://doxygen.mantidproject.org>
*/

class AbstractDoubleValueExtractor
{
public:
AbstractDoubleValueExtractor(std::string doubleValueKey) :
m_doubleValueKey(doubleValueKey)
{ }

virtual ~AbstractDoubleValueExtractor() { }

virtual double operator()(const API::Run &runInformation) const = 0;

protected:
std::string m_doubleValueKey;
};

typedef boost::shared_ptr<AbstractDoubleValueExtractor> AbstractDoubleValueExtractor_sptr;

class NumberDoubleValueExtractor : public AbstractDoubleValueExtractor
{
public:
NumberDoubleValueExtractor(std::string doubleValueKey) :
AbstractDoubleValueExtractor(doubleValueKey)
{ }
virtual ~NumberDoubleValueExtractor() { }

virtual double operator()(const API::Run &runInformation) const {
return runInformation.getPropertyValueAsType<double>(m_doubleValueKey);
}
};

class VectorDoubleValueExtractor : public AbstractDoubleValueExtractor
{
public:
VectorDoubleValueExtractor(std::string doubleValueKey) :
AbstractDoubleValueExtractor(doubleValueKey)
{ }
virtual ~VectorDoubleValueExtractor() { }

virtual double operator()(const API::Run &runInformation) const {
return runInformation.getPropertyValueAsType<std::vector<double> >(m_doubleValueKey).front();
}
};

class MANTID_SINQ_DLL PoldiInstrumentAdapter
{
public:
PoldiInstrumentAdapter(API::MatrixWorkspace_const_sptr matrixWorkspace);
PoldiInstrumentAdapter(Geometry::Instrument_const_sptr mantidInstrument, const API::Run &runInformation);
virtual ~PoldiInstrumentAdapter();

Expand All @@ -49,13 +96,21 @@ class MANTID_SINQ_DLL PoldiInstrumentAdapter
protected:
PoldiInstrumentAdapter() { }

void initializeFromInstrumentAndRun(Geometry::Instrument_const_sptr mantidInstrument, const API::Run &runInformation);

void setDetector(Geometry::Instrument_const_sptr mantidInstrument);
void setChopper(Geometry::Instrument_const_sptr mantidInstrument, const API::Run &runInformation);
void setSpectrum(Geometry::Instrument_const_sptr mantidInstrument);

double getChopperSpeedFromRun(const API::Run &runInformation);
AbstractDoubleValueExtractor_sptr getExtractorForProperty(Kernel::Property *chopperSpeedProperty);

PoldiAbstractChopper_sptr m_chopper;
PoldiAbstractDetector_sptr m_detector;
PoldiSourceSpectrum_sptr m_spectrum;

static const std::string m_chopperSpeedPropertyName;
static std::map<std::string, AbstractDoubleValueExtractor_sptr> m_extractors;
};

typedef boost::shared_ptr<PoldiInstrumentAdapter> PoldiInstrumentAdapter_sptr;
Expand Down
Expand Up @@ -4,36 +4,44 @@
#include "MantidSINQ/PoldiUtilities/PoldiChopperFactory.h"
#include "MantidSINQ/PoldiUtilities/PoldiSourceSpectrum.h"

#include "boost/assign.hpp"

namespace Mantid
{
namespace Poldi
{
using namespace Mantid::Geometry;
using namespace Mantid::API;

/** Constructor with required arguments
// Initializing static variables for DoubleValueExtractors
const std::string PoldiInstrumentAdapter::m_chopperSpeedPropertyName = "chopperspeed";

std::map<std::string, AbstractDoubleValueExtractor_sptr> PoldiInstrumentAdapter::m_extractors =
boost::assign::map_list_of
("dbl list", AbstractDoubleValueExtractor_sptr(new VectorDoubleValueExtractor(PoldiInstrumentAdapter::m_chopperSpeedPropertyName)))
("number", AbstractDoubleValueExtractor_sptr(new NumberDoubleValueExtractor(PoldiInstrumentAdapter::m_chopperSpeedPropertyName)));

/** Constructor with workspace argument
*
* With the Instrument and Run data provided to the constructor, the resulting POLDI utility objects are
* created. Currently this is a detector, a chopper and the neutron source spectrum.
* When a NULL-instrument pointer is passed in, or the chopperspeed-property is not present in the
* experiment log, std::runtime_error is thrown.
* This constructor directly takes a matrix workspace and extracts instrument and run information.
*
* @param matrixWorkspace :: Workspace with a valid POLDI instrument and run information
*/
PoldiInstrumentAdapter::PoldiInstrumentAdapter(API::MatrixWorkspace_const_sptr matrixWorkspace)
{
initializeFromInstrumentAndRun(matrixWorkspace->getInstrument(), matrixWorkspace->run());
}

/** Constructor with instrument and run information arguments
*
* This constructor internall calls PoldiInstrumentAdapter::initializeFromInstrumentAndRun.
*
* @param mantidInstrument :: Const shared pointer to Mantid::Geometry::Instrument
* @param runInformation :: Const Reference to Mantid::API::Run object
*/
PoldiInstrumentAdapter::PoldiInstrumentAdapter(Instrument_const_sptr mantidInstrument, const Run &runInformation)
{
if(!mantidInstrument) {
throw std::runtime_error("Can not construct POLDI classes from invalid instrument. Aborting.");
}

if(!runInformation.hasProperty("chopperspeed")) {
throw(std::runtime_error("Can not construct instrument without 'chopperspeed' property in log. Aborting."));
}

setDetector(mantidInstrument);
setChopper(mantidInstrument, runInformation);
setSpectrum(mantidInstrument);
initializeFromInstrumentAndRun(mantidInstrument, runInformation);
}

PoldiInstrumentAdapter::~PoldiInstrumentAdapter()
Expand Down Expand Up @@ -67,6 +75,27 @@ PoldiSourceSpectrum_sptr PoldiInstrumentAdapter::spectrum() const
return m_spectrum;
}

/** Initializes object from POLDI instrument definition and run information
*
* With the Instrument and Run data provided in the arguments, the resulting POLDI utility objects are
* created. Currently this is a detector, a chopper and the neutron source spectrum.
* When a NULL-instrument pointer is passed in, or the chopperspeed-property is not present in the
* experiment log, std::runtime_error is thrown.
*
* @param mantidInstrument :: Const shared pointer to Mantid::Geometry::Instrument
* @param runInformation :: Const Reference to Mantid::API::Run object
*/
void PoldiInstrumentAdapter::initializeFromInstrumentAndRun(Instrument_const_sptr mantidInstrument, const Run &runInformation)
{
if(!mantidInstrument) {
throw std::runtime_error("Can not construct POLDI classes from invalid instrument. Aborting.");
}

setDetector(mantidInstrument);
setChopper(mantidInstrument, runInformation);
setSpectrum(mantidInstrument);
}

/** Constructs a detector and stores it
*
* A PoldiAbstractDetector is constructed through PoldiDetectorFactory. Currently, the He3-detector
Expand All @@ -92,14 +121,60 @@ void PoldiInstrumentAdapter::setDetector(Instrument_const_sptr mantidInstrument)
*/
void PoldiInstrumentAdapter::setChopper(Instrument_const_sptr mantidInstrument, const Run &runInformation)
{
double chopperSpeed = runInformation.getPropertyValueAsType<std::vector<double> >("chopperspeed").front();
double chopperSpeed = getChopperSpeedFromRun(runInformation);

PoldiChopperFactory chopperFactory;
m_chopper = PoldiAbstractChopper_sptr(chopperFactory.createChopper(std::string("default-chopper")));
m_chopper->loadConfiguration(mantidInstrument);
m_chopper->setRotationSpeed(chopperSpeed);
}

/**
* Extracts the chopper speed from run information
*
* This method tries to extract the chopper rotation speed from the run information, using
* an appropriate functor of type AbstractDoubleValueExtractor.
*
* @param runInformation :: Run information that contains a "chopperspeed" property
* @return Chopper speed as stored in run information
*/
double PoldiInstrumentAdapter::getChopperSpeedFromRun(const Run &runInformation)
{
if(!runInformation.hasProperty(m_chopperSpeedPropertyName)) {
throw std::runtime_error("Cannot construct instrument without " + m_chopperSpeedPropertyName + "property in log. Aborting.");
}

Kernel::Property *chopperSpeedProperty = runInformation.getProperty(m_chopperSpeedPropertyName);

AbstractDoubleValueExtractor_sptr extractor = getExtractorForProperty(chopperSpeedProperty);

if(!extractor) {
throw std::invalid_argument("Cannot extract chopper speed from run information.");
}

return (*extractor)(runInformation);
}

/**
* Returns appropriate extractor for supplied property
*
* This method checks the property's type and gets the appropriate functor to extract the value.
* If a null pointer is supplied, the method throws an std::runtime_error exception.
*
* @param chopperSpeedProperty :: Property containing the chopper speed
* @return Functor of type AbstractDoubleValueExtractor
*/
AbstractDoubleValueExtractor_sptr PoldiInstrumentAdapter::getExtractorForProperty(Kernel::Property *chopperSpeedProperty)
{
if(!chopperSpeedProperty) {
throw std::invalid_argument("Cannot process null-Property.");
}

std::string propertyType = chopperSpeedProperty->type();

return m_extractors[propertyType];
}

/** Constructs a spectrum and stores it
*
* This method constructs a PoldiSourceSpectrum object with the spectrum data provided
Expand Down
126 changes: 126 additions & 0 deletions Code/Mantid/Framework/SINQ/test/PoldiInstrumentAdapterTest.h
@@ -0,0 +1,126 @@
#ifndef MANTID_SINQ_POLDIINSTRUMENTADAPTERTEST_H_
#define MANTID_SINQ_POLDIINSTRUMENTADAPTERTEST_H_

#include <cxxtest/TestSuite.h>
#include <gtest/gtest.h>
#include <gmock/gmock.h>

#include "MantidSINQ/PoldiUtilities/PoldiInstrumentAdapter.h"
#include "MantidSINQ/PoldiUtilities/PoldiMockInstrumentHelpers.h"

#include "MantidAPI/Run.h"
#include "MantidKernel/PropertyWithValue.h"

using namespace Mantid::Poldi;
using namespace Mantid::API;
using namespace Mantid::Kernel;

class PoldiInstrumentAdapterTest : public CxxTest::TestSuite
{
public:
// This pair of boilerplate methods prevent the suite being created statically
// This means the constructor isn't called when running other tests
static PoldiInstrumentAdapterTest *createSuite() { return new PoldiInstrumentAdapterTest(); }
static void destroySuite( PoldiInstrumentAdapterTest *suite ) { delete suite; }

PoldiInstrumentAdapterTest()
{
// special properties for testing AbstractDoubleValueExtractor
m_run.addProperty<double>("chopperspeed_double", 10000.0);

std::vector<double> chopperSpeed(1, 10000.0);
m_run.addProperty<std::vector<double> >("chopperspeed_vector", chopperSpeed);

// add string property, for which there is no extractor
m_stringRun.addProperty<std::string>(PoldiInstrumentAdapter::m_chopperSpeedPropertyName, "10000.0");

// run with correct chopperspeed property
m_correctRun.addProperty<double>(PoldiInstrumentAdapter::m_chopperSpeedPropertyName, 10000.0);
}

void testVectorDoubleValueExtractor()
{
// Extract vector value with vector value extractor - this should work.
AbstractDoubleValueExtractor_sptr extractorGood(new VectorDoubleValueExtractor("chopperspeed_vector"));
TS_ASSERT_THROWS_NOTHING((*extractorGood)(const_cast<const Run &>(m_run)));

// this should not work, because it's a "number" property (see constructor above)
AbstractDoubleValueExtractor_sptr extractorBad(new VectorDoubleValueExtractor("chopperspeed_double"));
TS_ASSERT_THROWS((*extractorBad)(const_cast<const Run &>(m_run)), std::invalid_argument);

// check that the value comes out correctly
TS_ASSERT_EQUALS((*extractorGood)(const_cast<const Run &>(m_run)), 10000.0);
}

void testNumberDoubleValueExtractor()
{
// Same as above test
AbstractDoubleValueExtractor_sptr extractorGood(new NumberDoubleValueExtractor("chopperspeed_double"));
TS_ASSERT_THROWS_NOTHING((*extractorGood)(const_cast<const Run &>(m_run)));

AbstractDoubleValueExtractor_sptr extractorBad(new NumberDoubleValueExtractor("chopperspeed_vector"));
TS_ASSERT_THROWS((*extractorBad)(const_cast<const Run &>(m_run)), std::invalid_argument);

// check that the value comes out correctly
TS_ASSERT_EQUALS((*extractorGood)(const_cast<const Run &>(m_run)), 10000.0);
}

void testGetChopperSpeedFromRun() {
TestablePoldiInstrumentAdapter instrumentAdapter;

// Throws, because "chopperspeed" is missing
TS_ASSERT_THROWS(instrumentAdapter.getChopperSpeedFromRun(m_run), std::runtime_error);

// Throws, because there is no extractor for supplied type
TS_ASSERT_THROWS(instrumentAdapter.getChopperSpeedFromRun(m_stringRun), std::invalid_argument);

// Should be ok.
TS_ASSERT_THROWS_NOTHING(instrumentAdapter.getChopperSpeedFromRun(m_correctRun));
TS_ASSERT_EQUALS(instrumentAdapter.getChopperSpeedFromRun(m_correctRun), 10000.0);
}

void testGetExtractorForProperty() {
TestablePoldiInstrumentAdapter instrumentAdapter;

// Throw on null-pointer
TS_ASSERT_THROWS(instrumentAdapter.getExtractorForProperty(0), std::invalid_argument);
TS_ASSERT_THROWS_NOTHING(instrumentAdapter.getExtractorForProperty(m_run.getProperty("chopperspeed_double")));

// Check that the correct extractor is retrieved
AbstractDoubleValueExtractor_sptr extractor = instrumentAdapter.getExtractorForProperty(m_run.getProperty("chopperspeed_double"));
TS_ASSERT(extractor);

TS_ASSERT(boost::dynamic_pointer_cast<NumberDoubleValueExtractor>(extractor));
TS_ASSERT(!boost::dynamic_pointer_cast<VectorDoubleValueExtractor>(extractor));

// Check that the correct extractor is retrieved
extractor = instrumentAdapter.getExtractorForProperty(m_run.getProperty("chopperspeed_vector"));
TS_ASSERT(extractor);

TS_ASSERT(boost::dynamic_pointer_cast<VectorDoubleValueExtractor>(extractor));
TS_ASSERT(!boost::dynamic_pointer_cast<NumberDoubleValueExtractor>(extractor));

// unregistered property type - invalid extractor
extractor = instrumentAdapter.getExtractorForProperty(m_stringRun.getProperty(PoldiInstrumentAdapter::m_chopperSpeedPropertyName));
TS_ASSERT(!extractor);
}

private:
boost::shared_ptr<ConfiguredHeliumDetector> m_detector;
boost::shared_ptr<MockChopper> m_chopper;
PoldiSourceSpectrum_sptr m_spectrum;

Run m_run;
Run m_correctRun;
Run m_stringRun;

class TestablePoldiInstrumentAdapter : public PoldiInstrumentAdapter
{
friend class PoldiInstrumentAdapterTest;
public:
TestablePoldiInstrumentAdapter() : PoldiInstrumentAdapter() { }
~TestablePoldiInstrumentAdapter() { }
};
};

#endif // MANTID_SINQ_POLDIINSTRUMENTADAPTERTEST_H_

0 comments on commit 6767d05

Please sign in to comment.