Skip to content

Commit

Permalink
Merge pull request #18890 from mantidproject/18722_specular_reflectio…
Browse files Browse the repository at this point in the history
…n_rotate_detectors

Add CorrectionType property to SpecularReflectionPositionCorrect
  • Loading branch information
SimonHeybrock committed Feb 27, 2017
2 parents 2473ce9 + 7709b03 commit 1a69ca2
Show file tree
Hide file tree
Showing 15 changed files with 298 additions and 98 deletions.
21 changes: 20 additions & 1 deletion Framework/Algorithms/src/ReflectometryReductionOneAuto2.cpp
Expand Up @@ -3,8 +3,10 @@
#include "MantidAPI/WorkspaceGroup.h"
#include "MantidAlgorithms/BoostOptionalToAlgorithmProperty.h"
#include "MantidKernel/ArrayProperty.h"
#include "MantidKernel/CompositeValidator.h"
#include "MantidKernel/ListValidator.h"
#include "MantidKernel/make_unique.h"
#include "MantidKernel/MandatoryValidator.h"

namespace Mantid {
namespace Algorithms {
Expand Down Expand Up @@ -130,6 +132,20 @@ void ReflectometryReductionOneAuto2::init() {
declareProperty("ThetaIn", Mantid::EMPTY_DBL(), "Angle in degrees",
Direction::Input);

// Detector position correction type
const std::vector<std::string> correctionType{"VerticalShift",
"RotateAroundSample"};
auto correctionTypeValidator = boost::make_shared<CompositeValidator>();
correctionTypeValidator->add(
boost::make_shared<MandatoryValidator<std::string>>());
correctionTypeValidator->add(
boost::make_shared<StringListValidator>(correctionType));
declareProperty(
"DetectorCorrectionType", correctionType[0], correctionTypeValidator,
"Whether detectors should be shifted vertically or rotated around the "
"sample position.",
Direction::Input);

// Wavelength limits
declareProperty("WavelengthMin", Mantid::EMPTY_DBL(),
"Wavelength Min in angstroms", Direction::Input);
Expand Down Expand Up @@ -304,7 +320,8 @@ std::vector<std::string> ReflectometryReductionOneAuto2::getDetectorNames(
return detectors;
}

/** Correct an instrument component vertically.
/** Correct an instrument component by shifting it vertically or
* rotating it around the sample.
*
* @param instructions :: processing instructions defining the detectors of
* interest
Expand All @@ -326,6 +343,7 @@ MatrixWorkspace_sptr ReflectometryReductionOneAuto2::correctDetectorPositions(
detectorsOfInterest.end());

const double theta = getProperty("ThetaIn");
const std::string correctionType = getProperty("DetectorCorrectionType");

MatrixWorkspace_sptr corrected = inputWS;

Expand All @@ -334,6 +352,7 @@ MatrixWorkspace_sptr ReflectometryReductionOneAuto2::correctDetectorPositions(
createChildAlgorithm("SpecularReflectionPositionCorrect");
alg->setProperty("InputWorkspace", corrected);
alg->setProperty("TwoTheta", theta * 2);
alg->setProperty("DetectorCorrectionType", correctionType);
alg->setProperty("DetectorComponentName", detector);
alg->execute();
corrected = alg->getProperty("OutputWorkspace");
Expand Down
52 changes: 46 additions & 6 deletions Framework/Algorithms/src/SpecularReflectionPositionCorrect2.cpp
Expand Up @@ -4,6 +4,7 @@
#include "MantidGeometry/Instrument/ReferenceFrame.h"
#include "MantidKernel/BoundedValidator.h"
#include "MantidKernel/CompositeValidator.h"
#include "MantidKernel/ListValidator.h"
#include "MantidKernel/MandatoryValidator.h"

using namespace Mantid::API;
Expand All @@ -24,7 +25,7 @@ const std::string SpecularReflectionPositionCorrect2::name() const {

/// Algorithm's summary. @see Algorithm::summary
const std::string SpecularReflectionPositionCorrect2::summary() const {
return "Corrects a detector component vertically based on TwoTheta.";
return "Corrects a detector component's position based on TwoTheta.";
}

/// Algorithm's version for identification. @see Algorithm::version
Expand Down Expand Up @@ -55,6 +56,19 @@ void SpecularReflectionPositionCorrect2::init() {
thetaValidator, Direction::Input),
"Angle used to correct the detector component.");

const std::vector<std::string> correctionType{"VerticalShift",
"RotateAroundSample"};
auto correctionTypeValidator = boost::make_shared<CompositeValidator>();
correctionTypeValidator->add(
boost::make_shared<MandatoryValidator<std::string>>());
correctionTypeValidator->add(
boost::make_shared<StringListValidator>(correctionType));
declareProperty(
"DetectorCorrectionType", correctionType[0], correctionTypeValidator,
"Whether detectors should be shifted vertically or rotated around the "
"sample position.",
Direction::Input);

declareProperty(
Mantid::Kernel::make_unique<PropertyWithValue<std::string>>(
"DetectorComponentName", "",
Expand Down Expand Up @@ -126,6 +140,9 @@ void SpecularReflectionPositionCorrect2::exec() {
IComponent_const_sptr sample = inst->getComponentByName(sampleName);
const V3D samplePosition = sample->getPos();

// Type of movement (vertical shift or rotation around the sample)
const std::string correctionType = getProperty("DetectorCorrectionType");

// Sample-to-detector
const V3D sampleToDetector = detectorPosition - samplePosition;
// Reference frame
Expand All @@ -134,19 +151,42 @@ void SpecularReflectionPositionCorrect2::exec() {
auto horizontalAxis = referenceFrame->pointingHorizontalAxis();
auto upAxis = referenceFrame->pointingUpAxis();

// We just recalculate beam offset.
const double beamOffset =
// Get the offset from the sample in the beam direction
double beamOffset = 0.0;
const double beamOffsetOld =
sampleToDetector.scalar_prod(referenceFrame->vecPointingAlongBeam());
// We only correct vertical position

if (correctionType == "VerticalShift") {
// Only shifting vertically, so the beam offset remains the same
beamOffset = beamOffsetOld;
} else if (correctionType == "RotateAroundSample") {
// The radius for the rotation is the distance from the sample to
// the detector in the Beam-Vertical plane
const double upOffsetOld =
sampleToDetector.scalar_prod(referenceFrame->vecPointingUp());
const double radius =
std::sqrt(beamOffsetOld * beamOffsetOld + upOffsetOld * upOffsetOld);
beamOffset = radius * std::cos(twoThetaInRad);
} else {
// Shouldn't get here unless there's been a coding error
std::ostringstream message;
message << "Invalid correction type '" << correctionType;
throw std::runtime_error(message.str());
}

// Calculate the offset in the vertical direction, and the total
// offset in the beam direction
const double upOffset = (beamOffset * std::tan(twoThetaInRad));
const double beamOffsetFromOrigin =
beamOffset +
samplePosition.scalar_prod(referenceFrame->vecPointingAlongBeam());

auto moveAlg = createChildAlgorithm("MoveInstrumentComponent");
moveAlg->initialize();
moveAlg->setProperty("Workspace", outWS);
moveAlg->setProperty("ComponentName", detectorName);
moveAlg->setProperty("RelativePosition", false);
moveAlg->setProperty(beamAxis, detectorPosition.scalar_prod(
referenceFrame->vecPointingAlongBeam()));
moveAlg->setProperty(beamAxis, beamOffsetFromOrigin);
moveAlg->setProperty(horizontalAxis, 0.0);
moveAlg->setProperty(upAxis, upOffset);
moveAlg->execute();
Expand Down
18 changes: 11 additions & 7 deletions Framework/Algorithms/test/ReflectometryReductionOneAuto2Test.h
Expand Up @@ -233,6 +233,7 @@ class ReflectometryReductionOneAuto2Test : public CxxTest::TestSuite {
void test_correct_detector_position_INTER() {
auto inter = loadRun("INTER00013460.nxs");

// Use the default correction type, which is a vertical shift
ReflectometryReductionOneAuto2 alg;
alg.initialize();
alg.setChild(true);
Expand Down Expand Up @@ -282,15 +283,17 @@ class ReflectometryReductionOneAuto2Test : public CxxTest::TestSuite {
std::tan(0.7 * 2 * M_PI / 180), 1e-4);
}

void test_correct_detector_position_POLREF() {
void test_correct_detector_position_rotation_POLREF() {
// Histograms in this run correspond to 'OSMOND' component
auto polref = loadRun("POLREF00014966.raw");

// Correct by rotating detectors around the sample
ReflectometryReductionOneAuto2 alg;
alg.initialize();
alg.setChild(true);
alg.setProperty("InputWorkspace", polref);
alg.setProperty("ThetaIn", 1.5);
alg.setProperty("DetectorCorrectionType", "RotateAroundSample");
alg.setProperty("AnalysisMode", "MultiDetectorAnalysis");
alg.setProperty("CorrectionAlgorithm", "None");
alg.setProperty("MomentumTransferStep", 0.01);
Expand All @@ -316,27 +319,28 @@ class ReflectometryReductionOneAuto2Test : public CxxTest::TestSuite {
TS_ASSERT_EQUALS(instIn->getComponentByName("lineardetector")->getPos(),
instOut->getComponentByName("lineardetector")->getPos());

// Only 'OSMOND' should have been moved vertically (along Z)
// Only 'OSMOND' should have been moved both vertically and in the beam
// direction (along X and Z)

auto detectorIn = instIn->getComponentByName("OSMOND")->getPos();
auto detectorOut = instOut->getComponentByName("OSMOND")->getPos();

TS_ASSERT_EQUALS(detectorIn.X(), detectorOut.X());
TS_ASSERT_DELTA(detectorOut.X(), 25.99589, 1e-5);
TS_ASSERT_EQUALS(detectorIn.Y(), detectorOut.Y());
TS_ASSERT_DELTA(detectorOut.Z() /
(detectorOut.X() - instOut->getSample()->getPos().X()),
std::tan(1.5 * 2 * M_PI / 180), 1e-4);
TS_ASSERT_DELTA(detectorOut.Z(), 0.1570, 1e-5);
}

void test_correct_detector_position_CRISP() {
void test_correct_detector_position_vertical_CRISP() {
// Histogram in this run corresponds to 'point-detector' component
auto polref = loadRun("CSP79590.raw");

// Correct by shifting detectors vertically
ReflectometryReductionOneAuto2 alg;
alg.initialize();
alg.setChild(true);
alg.setProperty("InputWorkspace", polref);
alg.setProperty("ThetaIn", 0.25);
alg.setProperty("DetectorCorrectionType", "VerticalShift");
alg.setProperty("CorrectionAlgorithm", "None");
alg.setProperty("MomentumTransferStep", 0.01);
alg.setProperty("OutputWorkspace", "IvsQ");
Expand Down
97 changes: 75 additions & 22 deletions Framework/Algorithms/test/SpecularReflectionPositionCorrect2Test.h
Expand Up @@ -17,6 +17,31 @@ class SpecularReflectionPositionCorrect2Test : public CxxTest::TestSuite {
private:
MatrixWorkspace_sptr m_interWS;

// Initialise the algorithm and set the properties
void setupAlgorithm(SpecularReflectionPositionCorrect2 &alg,
const double twoTheta, const std::string &correctionType,
const std::string &detectorName) {
if (!alg.isInitialized())
alg.initialize();
alg.setChild(true);
alg.setProperty("InputWorkspace", m_interWS);
alg.setProperty("TwoTheta", twoTheta);
if (!correctionType.empty())
alg.setProperty("DetectorCorrectionType", correctionType);
if (!detectorName.empty())
alg.setProperty("DetectorComponentName", detectorName);
alg.setPropertyValue("OutputWorkspace", "test_out");
}

// Run the algorithm and do some basic checks. Returns the output workspace.
MatrixWorkspace_const_sptr
runAlgorithm(SpecularReflectionPositionCorrect2 &alg) {
TS_ASSERT_THROWS_NOTHING(alg.execute());
MatrixWorkspace_sptr outWS = alg.getProperty("OutputWorkspace");
TS_ASSERT(outWS);
return outWS;
}

public:
// This pair of boilerplate methods prevent the suite being created statically
// This means the constructor isn't called when running other tests
Expand Down Expand Up @@ -100,18 +125,12 @@ class SpecularReflectionPositionCorrect2Test : public CxxTest::TestSuite {
TS_ASSERT_THROWS_ANYTHING(alg.execute());
}

void test_correct_point_detector() {
void test_correct_point_detector_vertical_shift_default() {
// Omit the DetectorCorrectionType property to check that a vertical shift
// is done by default
SpecularReflectionPositionCorrect2 alg;
alg.initialize();
alg.setChild(true);
alg.setProperty("InputWorkspace", m_interWS);
alg.setProperty("TwoTheta", 1.4);
alg.setProperty("DetectorComponentName", "point-detector");
alg.setPropertyValue("OutputWorkspace", "test_out");
TS_ASSERT_THROWS_NOTHING(alg.execute());
MatrixWorkspace_sptr outWS = alg.getProperty("OutputWorkspace");

TS_ASSERT(outWS);
setupAlgorithm(alg, 1.4, "", "point-detector");
MatrixWorkspace_const_sptr outWS = runAlgorithm(alg);

auto instrIn = m_interWS->getInstrument();
auto instrOut = outWS->getInstrument();
Expand All @@ -128,18 +147,31 @@ class SpecularReflectionPositionCorrect2Test : public CxxTest::TestSuite {
TS_ASSERT_DELTA(detOut.Y(), 0.06508, 1e-5);
}

void test_correct_linear_detector() {
void test_correct_point_detector_rotation() {
SpecularReflectionPositionCorrect2 alg;
alg.initialize();
alg.setChild(true);
alg.setProperty("InputWorkspace", m_interWS);
alg.setProperty("TwoTheta", 1.4);
alg.setProperty("DetectorComponentName", "linear-detector");
alg.setPropertyValue("OutputWorkspace", "test_out");
TS_ASSERT_THROWS_NOTHING(alg.execute());
MatrixWorkspace_sptr outWS = alg.getProperty("OutputWorkspace");
setupAlgorithm(alg, 1.4, "RotateAroundSample", "point-detector");
MatrixWorkspace_const_sptr outWS = runAlgorithm(alg);

TS_ASSERT(outWS);
auto instrIn = m_interWS->getInstrument();
auto instrOut = outWS->getInstrument();

// Sample should not have moved
auto sampleIn = instrIn->getSample()->getPos();
auto sampleOut = instrOut->getSample()->getPos();
TS_ASSERT_EQUALS(sampleIn, sampleOut);
// 'point-detector' should have been moved both vertically and in
// the beam direction
auto detIn = instrIn->getComponentByName("point-detector")->getPos();
auto detOut = instrOut->getComponentByName("point-detector")->getPos();
TS_ASSERT_EQUALS(detIn.X(), detOut.X());
TS_ASSERT_DELTA(detOut.Z(), 19.69921, 1e-5);
TS_ASSERT_DELTA(detOut.Y(), 0.06506, 1e-5);
}

void test_correct_linear_detector_vertical_shift() {
SpecularReflectionPositionCorrect2 alg;
setupAlgorithm(alg, 1.4, "VerticalShift", "linear-detector");
MatrixWorkspace_const_sptr outWS = runAlgorithm(alg);

auto instrIn = m_interWS->getInstrument();
auto instrOut = outWS->getInstrument();
Expand All @@ -148,13 +180,34 @@ class SpecularReflectionPositionCorrect2Test : public CxxTest::TestSuite {
auto sampleIn = instrIn->getSample()->getPos();
auto sampleOut = instrOut->getSample()->getPos();
TS_ASSERT_EQUALS(sampleIn, sampleOut);
// 'point-detector' should have been moved vertically only
// 'linear-detector' should have been moved vertically only
auto detIn = instrIn->getComponentByName("linear-detector")->getPos();
auto detOut = instrOut->getComponentByName("linear-detector")->getPos();
TS_ASSERT_EQUALS(detIn.X(), detOut.X());
TS_ASSERT_EQUALS(detIn.Z(), detOut.Z());
TS_ASSERT_DELTA(detOut.Y(), 0.07730, 1e-5);
}

void test_correct_linear_detector_rotation() {
SpecularReflectionPositionCorrect2 alg;
setupAlgorithm(alg, 1.4, "RotateAroundSample", "linear-detector");
MatrixWorkspace_const_sptr outWS = runAlgorithm(alg);

auto instrIn = m_interWS->getInstrument();
auto instrOut = outWS->getInstrument();

// Sample should not have moved
auto sampleIn = instrIn->getSample()->getPos();
auto sampleOut = instrOut->getSample()->getPos();
TS_ASSERT_EQUALS(sampleIn, sampleOut);
// 'linear-detector' should have been moved both vertically and in
// the beam direction
auto detIn = instrIn->getComponentByName("linear-detector")->getPos();
auto detOut = instrOut->getComponentByName("linear-detector")->getPos();
TS_ASSERT_EQUALS(detIn.X(), detOut.X());
TS_ASSERT_DELTA(detOut.Z(), 20.19906, 1e-5);
TS_ASSERT_DELTA(detOut.Y(), 0.07728, 1e-5);
}
};

#endif /* MANTID_ALGORITHMS_SPECULARREFLECTIONPOSITIONCORRECT2TEST_H_ */
Expand Up @@ -75,10 +75,12 @@ class DLLExport IReflSettingsView {
virtual std::string getLambdaMax() const = 0;
virtual std::string getI0MonitorIndex() const = 0;
virtual std::string getProcessingInstructions() const = 0;
virtual std::string getDetectorCorrectionType() const = 0;

/// Set default values for settings
virtual void setExpDefaults(const std::vector<std::string> &) const = 0;
virtual void setInstDefaults(const std::vector<double> &) const = 0;
virtual void setInstDefaults(const std::vector<double> &,
const std::vector<std::string> &) const = 0;

/// Set polarisation corrections and parameters enabled/disabled
virtual void setPolarisationOptionsEnabled(bool enable) const = 0;
Expand Down
Expand Up @@ -88,9 +88,12 @@ class QtReflSettingsView : public QWidget, public IReflSettingsView {
std::string getI0MonitorIndex() const override;
/// Return processing instructions
std::string getProcessingInstructions() const override;
/// Return selected detector correction type
std::string getDetectorCorrectionType() const override;
/// Set default values for experiment and instrument settings
void setExpDefaults(const std::vector<std::string> &) const override;
void setInstDefaults(const std::vector<double> &) const override;
void setInstDefaults(const std::vector<double> &,
const std::vector<std::string> &) const override;

/// Creates hints for 'Stitch1DMany'
void
Expand Down

0 comments on commit 1a69ca2

Please sign in to comment.