From 61141309dff34e17047fd172f44d7c0faf84a6a3 Mon Sep 17 00:00:00 2001 From: Roman Tolchenov <roman.tolchenov@stfc.ac.uk> Date: Tue, 3 Apr 2018 15:10:36 +0100 Subject: [PATCH] Move detectors after summing. Re #21742 --- .../ReflectometryReductionOne2.h | 5 + .../src/ReflectometryReductionOne2.cpp | 44 +++++++ .../test/ReflectometryReductionOne2Test.h | 113 ++++++++++++++++++ 3 files changed, 162 insertions(+) diff --git a/Framework/Algorithms/inc/MantidAlgorithms/ReflectometryReductionOne2.h b/Framework/Algorithms/inc/MantidAlgorithms/ReflectometryReductionOne2.h index 49a8f680da0..e5627b9f462 100644 --- a/Framework/Algorithms/inc/MantidAlgorithms/ReflectometryReductionOne2.h +++ b/Framework/Algorithms/inc/MantidAlgorithms/ReflectometryReductionOne2.h @@ -141,6 +141,10 @@ private: void verifySpectrumMaps(API::MatrixWorkspace_const_sptr ws1, API::MatrixWorkspace_const_sptr ws2, const bool severe); + // Correct the detector angle + Mantid::API::MatrixWorkspace_sptr + correctDetectorAngle(Mantid::API::MatrixWorkspace_sptr inputWS); + // Find and cache constants void findDetectorGroups(); @@ -162,6 +166,7 @@ private: bool m_normaliseMonitors; // normalise by monitors and direct beam bool m_normaliseTransmission; // transmission or algorithmic correction bool m_sum; // whether to do summation + bool m_correctAngleInLambda; // whether to correct the angle of detectors double m_theta0; // horizon angle // groups of spectrum indices of the detectors of interest std::vector<std::vector<size_t>> m_detectorGroups; diff --git a/Framework/Algorithms/src/ReflectometryReductionOne2.cpp b/Framework/Algorithms/src/ReflectometryReductionOne2.cpp index 28612fa314a..30e4667a32a 100644 --- a/Framework/Algorithms/src/ReflectometryReductionOne2.cpp +++ b/Framework/Algorithms/src/ReflectometryReductionOne2.cpp @@ -7,6 +7,7 @@ #include "MantidGeometry/Objects/BoundingBox.h" #include "MantidHistogramData/LinearGenerator.h" #include "MantidIndexing/IndexInfo.h" +#include "MantidKernel/ListValidator.h" #include "MantidKernel/MandatoryValidator.h" #include "MantidKernel/StringTokenizer.h" #include "MantidKernel/Unit.h" @@ -361,6 +362,16 @@ void ReflectometryReductionOne2::init() { "ThetaIn", Mantid::EMPTY_DBL(), Direction::Input), "Angle in degrees"); + // Angle correction type + const std::vector<std::string> correctionType{"VerticalShift", + "RotateAroundSample"}; + auto correctionTypeValidator = boost::make_shared<StringListValidator>(correctionType); + declareProperty( + "DetectorCorrectionType", correctionType[0], correctionTypeValidator, + "Whether detectors should be shifted vertically or rotated around the " + "sample position if angle correction is applied.", + Direction::Input); + // Processing instructions declareProperty(Kernel::make_unique<PropertyWithValue<std::string>>( "ProcessingInstructions", "", @@ -460,6 +471,8 @@ void ReflectometryReductionOne2::exec() { m_normaliseMonitors = false; m_sum = false; } + // Angle correction must be done if ThetaIn is set + m_correctAngleInLambda = !(*getProperty("ThetaIn")).isDefault() && !summingInQ(); // Create the output workspace in wavelength MatrixWorkspace_sptr IvsLam = makeIvsLam(); @@ -624,6 +637,10 @@ MatrixWorkspace_sptr ReflectometryReductionOne2::makeIvsLam() { result = transOrAlgCorrection(result, true); outputDebugWorkspace(result, wsName, "_norm_trans", debug, step); } + if (m_correctAngleInLambda) { + g_log.debug("Correcting the angles\n"); + result = correctDetectorAngle(result); + } } return result; @@ -1334,5 +1351,32 @@ void ReflectometryReductionOne2::verifySpectrumMaps( } } } + +/** Apply angle correction to the detectors. + + @param inputWS [in] :: A workspace to correct. + @return :: The corrected workspace. + */ +Mantid::API::MatrixWorkspace_sptr +ReflectometryReductionOne2::correctDetectorAngle( + Mantid::API::MatrixWorkspace_sptr inputWS) { + const auto detectorIDs = inputWS->getSpectrum(0).getDetectorIDs(); + auto result = inputWS; + double const thetaIn = getProperty("ThetaIn"); + double const twoTheta = 2.0 * thetaIn; + const std::string correctionType = getProperty("DetectorCorrectionType"); + for (auto detectorID : detectorIDs) { + auto correctAngle = this->createChildAlgorithm("SpecularReflectionPositionCorrect"); + correctAngle->initialize(); + correctAngle->setProperty("InputWorkspace", result); + correctAngle->setProperty("TwoTheta", twoTheta); + correctAngle->setProperty("DetectorCorrectionType", correctionType); + correctAngle->setProperty("DetectorID", detectorID); + correctAngle->execute(); + result = correctAngle->getProperty("OutputWorkspace"); + } + return result; +} + } // namespace Algorithms } // namespace Mantid diff --git a/Framework/Algorithms/test/ReflectometryReductionOne2Test.h b/Framework/Algorithms/test/ReflectometryReductionOne2Test.h index 5ea8486ee85..5e637af2401 100644 --- a/Framework/Algorithms/test/ReflectometryReductionOne2Test.h +++ b/Framework/Algorithms/test/ReflectometryReductionOne2Test.h @@ -7,6 +7,8 @@ #include "MantidAPI/Axis.h" #include "MantidAPI/FrameworkManager.h" #include "MantidAPI/MatrixWorkspace.h" +#include "MantidGeometry/Instrument.h" +#include "MantidGeometry/Instrument/ReferenceFrame.h" #include "MantidHistogramData/HistogramY.h" #include "MantidTestHelpers/WorkspaceCreationHelper.h" @@ -581,6 +583,82 @@ public: TS_ASSERT_DELTA(outQ->y(0)[7], 2.607359, 1e-6); } + void test_angle_correction() { + ReflectometryReductionOne2 alg; + setupAlgorithm(alg, 1.5, 15.0, "1+2"); + alg.setProperty("ThetaIn", 22.0); + MatrixWorkspace_sptr outLam = runAlgorithmLam(alg); + + TS_ASSERT_DELTA(outLam->y(0)[0], 4.0, 1e-14); + TS_ASSERT_DELTA(outLam->y(0)[7], 4.0, 1e-14); + + auto detector = outLam->getDetector(0); + TS_ASSERT_DELTA(calculateTwoTheta(outLam, -1, detector), 44.0, 1e-14); + TS_ASSERT_DELTA(calculateTwoTheta(outLam, 2), 44.0, 1e-14); + TS_ASSERT_DELTA(calculateTwoTheta(outLam, 3), 44.0, 1e-14); + + auto shift2 = calculateShift(m_multiDetectorWS, outLam, 2); + TS_ASSERT_DELTA(shift2.X(), 0, 1e-14); + TS_ASSERT_DELTA(shift2.Y(), -0.0715561259, 1e-10); + TS_ASSERT_DELTA(shift2.Z(), 0, 1e-14); + + auto shift3 = calculateShift(m_multiDetectorWS, outLam, 3); + TS_ASSERT_DELTA(shift3.X(), 0, 1e-14); + TS_ASSERT_DELTA(shift3.Y(), -0.1715561259, 1e-10); + TS_ASSERT_DELTA(shift3.Z(), 0, 1e-14); + } + + void test_angle_correction_multi() { + ReflectometryReductionOne2 alg; + setupAlgorithm(alg, 1.5, 15.0, "1:2"); + alg.setProperty("ThetaIn", 22.0); + MatrixWorkspace_sptr outLam = runAlgorithmLam(alg, 14, 2); + + TS_ASSERT_DELTA(outLam->y(0)[0], 2.0, 1e-14); + TS_ASSERT_DELTA(outLam->y(0)[7], 2.0, 1e-14); + + auto detector = outLam->getDetector(0); + TS_ASSERT_DELTA(calculateTwoTheta(outLam, -1, detector), 44.0, 1e-14); + TS_ASSERT_DELTA(calculateTwoTheta(outLam, 2), 44.0, 1e-14); + TS_ASSERT_DELTA(calculateTwoTheta(outLam, 3), 45.0, 1e-14); + + auto shift2 = calculateShift(m_multiDetectorWS, outLam, 2); + TS_ASSERT_DELTA(shift2.X(), 0, 1e-14); + TS_ASSERT_DELTA(shift2.Y(), -0.0715561259, 1e-10); + TS_ASSERT_DELTA(shift2.Z(), 0, 1e-14); + + auto shift3 = calculateShift(m_multiDetectorWS, outLam, 3); + TS_ASSERT_DELTA(shift3.X(), 0, 1e-14); + TS_ASSERT_DELTA(shift3.Y(), 0, 1e-10); + TS_ASSERT_DELTA(shift3.Z(), 0, 1e-14); + } + + void test_angle_correction_rotation() { + ReflectometryReductionOne2 alg; + setupAlgorithm(alg, 1.5, 15.0, "1+2"); + alg.setProperty("ThetaIn", 22.0); + alg.setProperty("DetectorCorrectionType", "RotateAroundSample"); + MatrixWorkspace_sptr outLam = runAlgorithmLam(alg); + + TS_ASSERT_DELTA(outLam->y(0)[0], 4.0, 1e-14); + TS_ASSERT_DELTA(outLam->y(0)[7], 4.0, 1e-14); + + auto detector = outLam->getDetector(0); + TS_ASSERT_DELTA(calculateTwoTheta(outLam, -1, detector), 44.0, 1e-13); + TS_ASSERT_DELTA(calculateTwoTheta(outLam, 2), 44.0, 1e-14); + TS_ASSERT_DELTA(calculateTwoTheta(outLam, 3), 44.0, 1e-14); + + auto shift2 = calculateShift(m_multiDetectorWS, outLam, 2); + TS_ASSERT_DELTA(shift2.X(), 0.0358923903, 1e-10); + TS_ASSERT_DELTA(shift2.Y(), -0.0368952475, 1e-10); + TS_ASSERT_DELTA(shift2.Z(), 0, 1e-14); + + auto shift3 = calculateShift(m_multiDetectorWS, outLam, 3); + TS_ASSERT_DELTA(shift3.X(), 0.0865005079, 1e-10); + TS_ASSERT_DELTA(shift3.Y(), -0.0880235564, 1e-10); + TS_ASSERT_DELTA(shift3.Z(), 0, 1e-14); + } + private: // Do standard algorithm setup void setupAlgorithm(ReflectometryReductionOne2 &alg, @@ -661,6 +739,41 @@ private: return outQ; } + + // Calculate the two theta angle of a detector + double calculateTwoTheta(MatrixWorkspace_sptr ws, Mantid::detid_t detid, + Mantid::Geometry::IDetector_const_sptr detector = + Mantid::Geometry::IDetector_const_sptr()) { + auto instrument = ws->getInstrument(); + auto sample = instrument->getComponentByName("some-surface-holder"); + if (!detector) { + detector = instrument->getDetector(detid); + } + auto detSample = detector->getPos() - sample->getPos(); + + auto refFrame = instrument->getReferenceFrame(); + + const double upoffset = refFrame->vecPointingUp().scalar_prod(detSample); + const double beamoffset = + refFrame->vecPointingAlongBeam().scalar_prod(detSample); + + return std::atan2(upoffset, beamoffset) * 180 / M_PI; + } + + // Calculate the shift in detector position + Mantid::Kernel::V3D calculateShift(MatrixWorkspace_sptr inputWS, + MatrixWorkspace_sptr outputWS, + Mantid::detid_t detid) { + auto inputInstrument = inputWS->getInstrument(); + auto inputDetector = inputInstrument->getDetector(detid); + auto inPos = inputDetector->getPos(); + + auto outputInstrument = outputWS->getInstrument(); + auto outputDetector = outputInstrument->getDetector(detid); + auto outPos = outputDetector->getPos(); + + return outPos - inPos; + } }; #endif /* ALGORITHMS_TEST_REFLECTOMETRYREDUCTIONONE2TEST_H_ */ -- GitLab