diff --git a/Framework/Algorithms/inc/MantidAlgorithms/DiscusMultipleScatteringCorrection.h b/Framework/Algorithms/inc/MantidAlgorithms/DiscusMultipleScatteringCorrection.h index c87790b7b4fe..4ee188bdccde 100644 --- a/Framework/Algorithms/inc/MantidAlgorithms/DiscusMultipleScatteringCorrection.h +++ b/Framework/Algorithms/inc/MantidAlgorithms/DiscusMultipleScatteringCorrection.h @@ -16,9 +16,10 @@ #include "MantidAlgorithms/SampleCorrections/SparseWorkspace.h" #include "MantidGeometry/IComponent.h" #include "MantidGeometry/Instrument/SampleEnvironment.h" +#include "MantidGeometry/Objects/CSGObject.h" #include "MantidKernel/PseudoRandomNumberGenerator.h" - #include +#include namespace Mantid { namespace API { @@ -69,6 +70,15 @@ struct ComponentWorkspaceMapping { std::shared_ptr scatterCount = std::make_shared(0); }; +/** Object for holding collimator parameteres loaded from instrument parameters file + */ +struct CollimatorInfo { + double m_innerRadius; + double m_halfAngularExtent; + double m_plateHeight; + Kernel::V3D m_axisVec; +}; + /** Calculates a multiple scattering correction * Based on Muscat Fortran code provided by Spencer Howells @@ -112,6 +122,9 @@ class MANTID_ALGORITHMS_DLL DiscusMultipleScatteringCorrection : public API::Alg API::MatrixWorkspace_sptr integrateWS(const API::MatrixWorkspace_sptr &ws); void getXMinMax(const Mantid::API::MatrixWorkspace &ws, double &xmin, double &xmax) const; void prepareSampleBeamGeometry(const API::MatrixWorkspace_sptr &inputWS); + const std::shared_ptr + createCollimatorHexahedronShape(const Kernel::V3D &samplePos, const Mantid::Geometry::DetectorInfo &detectorInfo, + const size_t &histogramIndex); private: void init() override; @@ -122,11 +135,15 @@ class MANTID_ALGORITHMS_DLL DiscusMultipleScatteringCorrection : public API::Alg std::tuple, std::vector> simulatePaths(const int nEvents, const int nScatters, Kernel::PseudoRandomNumberGenerator &rng, const ComponentWorkspaceMappings &componentWorkspaces, const double kinc, - const std::vector &wValues, const Kernel::V3D &detPos, bool specialSingleScatterCalc); + const std::vector &wValues, bool specialSingleScatterCalc, + const Mantid::Geometry::DetectorInfo &detectorInfo, const size_t &histogramIndex); std::tuple> scatter(const int nScatters, Kernel::PseudoRandomNumberGenerator &rng, const ComponentWorkspaceMappings &componentWorkspaces, const double kinc, const std::vector &wValues, - const Kernel::V3D &detPos, bool specialSingleScatterCalc); + bool specialSingleScatterCalc, + const Mantid::Geometry::DetectorInfo &detectorInfo, + const size_t &histogramIndex); + Geometry::Track start_point(Kernel::PseudoRandomNumberGenerator &rng); Geometry::Track generateInitialTrack(Kernel::PseudoRandomNumberGenerator &rng); void inc_xyz(Geometry::Track &track, double vl); @@ -160,6 +177,12 @@ class MANTID_ALGORITHMS_DLL DiscusMultipleScatteringCorrection : public API::Alg const Geometry::IObject *shapeObjectWithScatter); void addWorkspaceToDiscus2DData(const Geometry::IObject_const_sptr &shape, const std::string_view &matName, API::MatrixWorkspace_sptr ws); + void loadCollimatorInfo(); + double getDoubleParamFromIDF(std::string paramName); + Kernel::V3D getV3DParamFromIDF(std::string paramName); + const std::shared_ptr readFromCollimatorCorridorCache(const std::size_t &histogramIndex); + void writeToCollimatorCorridorCache(const std::size_t &histogramIndex, + const std::shared_ptr &collimatorCorridorCsgObj); long long m_callsToInterceptSurface{0}; long long m_IkCalculations{0}; std::map m_attemptsToGenerateInitialTrack; @@ -177,6 +200,10 @@ class MANTID_ALGORITHMS_DLL DiscusMultipleScatteringCorrection : public API::Alg bool m_NormalizeSQ{}; Geometry::BoundingBox m_activeRegion; std::unique_ptr m_beamProfile; + Mantid::Geometry::Instrument_const_sptr m_instrument; + std::unique_ptr m_collimatorInfo; + std::map> m_collimatorCorridorCache; + mutable std::shared_mutex m_mutexCorridorCache; }; } // namespace Algorithms } // namespace Mantid diff --git a/Framework/Algorithms/src/DiscusMultipleScatteringCorrection.cpp b/Framework/Algorithms/src/DiscusMultipleScatteringCorrection.cpp index 74b1bd28e947..920e31d74bfa 100644 --- a/Framework/Algorithms/src/DiscusMultipleScatteringCorrection.cpp +++ b/Framework/Algorithms/src/DiscusMultipleScatteringCorrection.cpp @@ -21,6 +21,8 @@ #include "MantidGeometry/Instrument.h" #include "MantidGeometry/Instrument/DetectorInfo.h" #include "MantidGeometry/Instrument/ReferenceFrame.h" +#include "MantidGeometry/Objects/BoundingBox.h" +#include "MantidGeometry/Objects/ShapeFactory.h" #include "MantidKernel/BoundedValidator.h" #include "MantidKernel/CompositeValidator.h" #include "MantidKernel/EnabledWhenProperty.h" @@ -182,6 +184,10 @@ void DiscusMultipleScatteringCorrection::init() { "Enable normalization of supplied structure factor(s). May be required when running a calculation " "involving more than one material where the normalization of the default S(Q)=1 structure factor " "doesn't match the normalization of a supplied non-isotropic structure factor"); + declareProperty("RadialCollimator", false, + "Enable use of a radial collimator that assign zero weights to tracks where the final scatter " + "is not in a position that allows the final track segment to pass through the collimator corridor " + "which spans from the guage volume toward the each detector"); } /** @@ -494,6 +500,7 @@ void DiscusMultipleScatteringCorrection::exec() { prepareSampleBeamGeometry(inputWS); prepareStructureFactors(); + loadCollimatorInfo(); MatrixWorkspace_sptr sigmaSSWS = getProperty("ScatteringCrossSection"); if (sigmaSSWS) @@ -578,6 +585,7 @@ void DiscusMultipleScatteringCorrection::exec() { enableParallelFor = enableParallelFor && Kernel::threadSafe(*noAbsOutputWS); const auto &spectrumInfo = instrumentWS.spectrumInfo(); + const auto &detectorInfo = instrumentWS.detectorInfo(); PARALLEL_FOR_IF(enableParallelFor) for (int64_t i = 0; i < static_cast(nhists); ++i) { // signed int for openMP loop @@ -600,8 +608,6 @@ void DiscusMultipleScatteringCorrection::exec() { const size_t nsteps = std::max(static_cast(1), nSimulationPoints - 1); const size_t xStepSize = nbins == 1 ? 1 : (nbins - 1) / nsteps; - const auto detPos = spectrumInfo.position(i); - // create copy of the SQ workspaces vector and fully copy any members that will be modified auto componentWorkspaces = m_SQWSs; @@ -627,7 +633,7 @@ void DiscusMultipleScatteringCorrection::exec() { prepareCumulativeProbForQ(kinc, componentWorkspaces); auto [weights, weightsErrors] = - simulatePaths(nSingleScatterEvents, 1, rng, componentWorkspaces, kinc, wValues, detPos, true); + simulatePaths(nSingleScatterEvents, 1, rng, componentWorkspaces, kinc, wValues, true, detectorInfo, i); if (std::get<1>(kInW[bin]) == -1) { noAbsSimulationWS->getSpectrum(i).mutableY() += weights; noAbsSimulationWS->getSpectrum(i).mutableE() += weightsErrors; @@ -640,7 +646,7 @@ void DiscusMultipleScatteringCorrection::exec() { int nEvents = ne == 0 ? nSingleScatterEvents : nMultiScatterEvents; std::tie(weights, weightsErrors) = - simulatePaths(nEvents, ne + 1, rng, componentWorkspaces, kinc, wValues, detPos, false); + simulatePaths(nEvents, ne + 1, rng, componentWorkspaces, kinc, wValues, false, detectorInfo, i); if (std::get<1>(kInW[bin]) == -1.0) { simulationWSs[ne]->getSpectrum(i).mutableY() += weights; simulationWSs[ne]->getSpectrum(i).mutableE() += weightsErrors; @@ -1348,14 +1354,15 @@ GNU_DIAG_OFF("free-nonheap-object") * @param componentWorkspaces list of workspaces related to the structure factor for each sample/env component * @param kinc The incident wavevector * @param wValues A vector of overall energy transfers - * @param detPos The position of the detector we're currently calculating a correction for * @param specialSingleScatterCalc Boolean indicating whether special single + * @param detectorInfo Obeject to get detector information + * @param histogramIndex Index for the current histogram being processed * @return An average weight across all of the paths */ std::tuple, std::vector> DiscusMultipleScatteringCorrection::simulatePaths( const int nPaths, const int nScatters, Kernel::PseudoRandomNumberGenerator &rng, const ComponentWorkspaceMappings &componentWorkspaces, const double kinc, const std::vector &wValues, - const Kernel::V3D &detPos, bool specialSingleScatterCalc) { + bool specialSingleScatterCalc, const Mantid::Geometry::DetectorInfo &detectorInfo, const size_t &histogramIndex) { // countZeroWeights for debugging and analysis of where importance sampling may help std::vector countZeroWeights(wValues.size(), 0); std::vector sumOfWeights(wValues.size(), 0.); @@ -1363,8 +1370,8 @@ std::tuple, std::vector> DiscusMultipleScatteringCor weightsErrors(wValues.size(), 0.); for (int ie = 0; ie < nPaths; ie++) { - auto [success, weights] = - scatter(nScatters, rng, componentWorkspaces, kinc, wValues, detPos, specialSingleScatterCalc); + auto [success, weights] = scatter(nScatters, rng, componentWorkspaces, kinc, wValues, specialSingleScatterCalc, + detectorInfo, histogramIndex); if (success) { std::transform(weights.begin(), weights.end(), sumOfWeights.begin(), sumOfWeights.begin(), std::plus()); std::transform(weights.begin(), weights.end(), countZeroWeights.begin(), countZeroWeights.begin(), @@ -1405,17 +1412,17 @@ GNU_DIAG_ON("free-nonheap-object") * @param componentWorkspaces list of workspaces related to the structure factor for each sample/env component * @param kinc The incident wavevector * @param wValues A vector of overall energy transfers - * @param detPos The detector position xyz coordinates * @param specialSingleScatterCalc Boolean indicating whether special single - * scatter calculation should be performed + * @param detectorInfo Obeject to get detector information + * @param histogramIndex Index of the current histogram being processed * @return A tuple containing a success/fail boolean and the calculated weights * across the n-1 multiple scatters */ -std::tuple> -DiscusMultipleScatteringCorrection::scatter(const int nScatters, Kernel::PseudoRandomNumberGenerator &rng, - const ComponentWorkspaceMappings &componentWorkspaces, const double kinc, - const std::vector &wValues, const Kernel::V3D &detPos, - bool specialSingleScatterCalc) { +std::tuple> DiscusMultipleScatteringCorrection::scatter( + const int nScatters, Kernel::PseudoRandomNumberGenerator &rng, + const ComponentWorkspaceMappings &componentWorkspaces, const double kinc, const std::vector &wValues, + bool specialSingleScatterCalc, const Mantid::Geometry::DetectorInfo &detectorInfo, const size_t &histogramIndex) { + double weight = 1; auto track = start_point(rng); @@ -1456,6 +1463,17 @@ DiscusMultipleScatteringCorrection::scatter(const int nScatters, Kernel::PseudoR new_vector(shapeObjectWithScatter->material(), k, specialSingleScatterCalc); } + bool considerCollimator = getProperty("RadialCollimator"); + if (considerCollimator) { + const auto &samplePos = detectorInfo.samplePosition(); + auto hexahedron = createCollimatorHexahedronShape(samplePos, detectorInfo, histogramIndex); + // zero the paths if the final scatter point is not inside the collimatorCorridor shape or the collimator shape is + // not as expected + if ((!hexahedron) || (!hexahedron->isValid(track.startPoint()))) + return {true, std::vector(wValues.size(), 0.)}; + } + + const auto &detPos = detectorInfo.position(histogramIndex); Kernel::V3D directionToDetector = detPos - track.startPoint(); Kernel::V3D prevDirection = track.direction(); directionToDetector.normalize(); @@ -1514,6 +1532,191 @@ DiscusMultipleScatteringCorrection::scatter(const int nScatters, Kernel::PseudoR return {true, weights}; } +/* + * Construct a hexahedron shape extending from the detector's front face across the collimator openning window toward + the sample with a legth as twice the distance from sample to detector. + */ +const std::shared_ptr DiscusMultipleScatteringCorrection::createCollimatorHexahedronShape( + const Kernel::V3D &samplePos, const Mantid::Geometry::DetectorInfo &detectorInfo, const size_t &histogramIndex) { + const auto shape = detectorInfo.detector(histogramIndex).shape(); + if (!shape || (shape->shape() != Mantid::Geometry::detail::ShapeInfo::GeometryShape::CUBOID)) { + return nullptr; + } + + try { + shape->shapeInfo(); + } catch (std::exception &) { + return nullptr; + } + + const auto colCorridorShape = readFromCollimatorCorridorCache(histogramIndex); + if (colCorridorShape) { + return colCorridorShape; + } + + const auto &detectorId = detectorInfo.detector(histogramIndex).getID(); + const auto &detectorAbsolPos = detectorInfo.position(detectorInfo.indexOf(detectorId)); + const auto cuboidGeometry = shape->shapeInfo().cuboidGeometry(); + + // Positions of the detector's front face + const auto &detLeftFrontBottomPos = detectorAbsolPos + cuboidGeometry.leftFrontBottom; + const auto &detLeftFrontTopPos = detectorAbsolPos + cuboidGeometry.leftFrontTop; + const auto &detRightFrontBottomPos = detectorAbsolPos + cuboidGeometry.rightFrontBottom; + const auto detRightFrontTopPos = detLeftFrontTopPos + detRightFrontBottomPos - detLeftFrontBottomPos; + + const auto detCentrePos = + (detLeftFrontBottomPos + detLeftFrontTopPos + detRightFrontBottomPos + detRightFrontTopPos) / 4.0; + const auto detTopMiddlePos = (detLeftFrontTopPos + detRightFrontTopPos) / 2.0; + + // Sanity check to avoid dividing by zero + if ((detRightFrontTopPos == detLeftFrontTopPos) || (detTopMiddlePos == detCentrePos) || (detCentrePos == samplePos)) { + return nullptr; + } + + // Define the unit vectors needed for calculations + const auto unitVecSampleToDet = Kernel::normalize(detCentrePos - samplePos); + const auto unitVecLeftToRight = Kernel::normalize( + V3D(-1.0 * unitVecSampleToDet.Z(), 0, + -1.0 * unitVecSampleToDet.X())); // this is a vector normal to unitVecSampleToDet on XZ plane + + const auto colOpenningLeftTopPos = + (unitVecSampleToDet * m_collimatorInfo->m_innerRadius * cos(m_collimatorInfo->m_halfAngularExtent)) + samplePos + + (m_collimatorInfo->m_axisVec * (m_collimatorInfo->m_plateHeight / 2.0)) - + (unitVecLeftToRight * m_collimatorInfo->m_innerRadius * sin(m_collimatorInfo->m_halfAngularExtent)); + const auto colOpenningRightTopPos = + (unitVecSampleToDet * m_collimatorInfo->m_innerRadius * cos(m_collimatorInfo->m_halfAngularExtent)) + samplePos + + (m_collimatorInfo->m_axisVec * (m_collimatorInfo->m_plateHeight / 2.0)) + + (unitVecLeftToRight * m_collimatorInfo->m_innerRadius * sin(m_collimatorInfo->m_halfAngularExtent)); + const auto colOpenningLeftBottomPos = + (unitVecSampleToDet * m_collimatorInfo->m_innerRadius * cos(m_collimatorInfo->m_halfAngularExtent)) + samplePos - + (m_collimatorInfo->m_axisVec * (m_collimatorInfo->m_plateHeight / 2.0)) - + (unitVecLeftToRight * m_collimatorInfo->m_innerRadius * sin(m_collimatorInfo->m_halfAngularExtent)); + const auto colOpenningRightBottomPos = + (unitVecSampleToDet * m_collimatorInfo->m_innerRadius * cos(m_collimatorInfo->m_halfAngularExtent)) + samplePos - + (m_collimatorInfo->m_axisVec * (m_collimatorInfo->m_plateHeight / 2.0)) + + (unitVecLeftToRight * m_collimatorInfo->m_innerRadius * sin(m_collimatorInfo->m_halfAngularExtent)); + + // Sanity check to avoid dividing by zero + if ((colOpenningLeftTopPos == detLeftFrontTopPos) || (colOpenningLeftBottomPos == detLeftFrontBottomPos) || + (colOpenningRightTopPos == detRightFrontTopPos) || (colOpenningRightBottomPos == detRightFrontBottomPos)) { + return nullptr; + } + + // Unit vectors along the sides of hexahedron shape + const auto unitVecAlongLeftTopLeg = Kernel::normalize(colOpenningLeftTopPos - detLeftFrontTopPos); + const auto unitVecAlongLeftBottomLeg = Kernel::normalize(colOpenningLeftBottomPos - detLeftFrontBottomPos); + const auto unitVecAlongRightTopLeg = Kernel::normalize(colOpenningRightTopPos - detRightFrontTopPos); + const auto unitVecAlongRightBottomLeg = Kernel::normalize(colOpenningRightBottomPos - detRightFrontBottomPos); + + // Positions of the hexahedron extended towards the sample for each of its legs to have a length twice the lenght of + // sample to detector + double sampleCentreToDetDistance = (detCentrePos - samplePos).norm(); + const auto leftFrontBottomPoint = detRightFrontTopPos + unitVecAlongRightTopLeg * sampleCentreToDetDistance * 2.0; + const auto hexaHedronLegsLenRatio = + (leftFrontBottomPoint - detRightFrontTopPos).norm() / (colOpenningRightTopPos - detRightFrontTopPos).norm(); + const auto leftBackBottomPoint = detLeftFrontTopPos + unitVecAlongLeftTopLeg * hexaHedronLegsLenRatio * + (colOpenningLeftTopPos - detLeftFrontTopPos).norm(); + const auto rightFrontBottomPoint = + detRightFrontBottomPos + + unitVecAlongRightBottomLeg * hexaHedronLegsLenRatio * (colOpenningRightBottomPos - detRightFrontBottomPos).norm(); + const auto rightBackBottomPoint = + detLeftFrontBottomPos + + unitVecAlongLeftBottomLeg * hexaHedronLegsLenRatio * (colOpenningLeftBottomPos - detLeftFrontBottomPos).norm(); + std::ostringstream xmlShapeStream; + xmlShapeStream << "" + << "" + << "" + << "" + << "" + << "" + << "" + << "" + << "" + << ""; + Geometry::ShapeFactory shapeMaker; + const auto collimatorCorridorCsgObj = shapeMaker.createShape(xmlShapeStream.str()); + writeToCollimatorCorridorCache(histogramIndex, collimatorCorridorCsgObj); + return collimatorCorridorCsgObj; +} + +const std::shared_ptr +DiscusMultipleScatteringCorrection::readFromCollimatorCorridorCache(const std::size_t &histogramIndex) { + std::shared_lock guard(m_mutexCorridorCache); + const auto itCollimatorCorridor = m_collimatorCorridorCache.find(histogramIndex); + if (itCollimatorCorridor != m_collimatorCorridorCache.end()) { + return itCollimatorCorridor->second; + } + return nullptr; +} + +void DiscusMultipleScatteringCorrection::writeToCollimatorCorridorCache( + const std::size_t &histogramIndex, const std::shared_ptr &collimatorCorridorCsgObj) { + std::unique_lock guard(m_mutexCorridorCache); + m_collimatorCorridorCache[histogramIndex] = collimatorCorridorCsgObj; +} + +void DiscusMultipleScatteringCorrection::loadCollimatorInfo() { + m_collimatorCorridorCache.clear(); // Clear the cache for collimator corridor shapes + const bool radialCollimator = getProperty("RadialCollimator"); + if (radialCollimator) { + m_collimatorInfo = std::make_unique(); + // Collimator inner radius + m_collimatorInfo->m_innerRadius = getDoubleParamFromIDF("col-radius"); + // Half of the angular extent of the collimator seen from the sample + m_collimatorInfo->m_halfAngularExtent = 0.5 * getDoubleParamFromIDF("col-angular-extent"); + // Height of collimator plate + m_collimatorInfo->m_plateHeight = getDoubleParamFromIDF("col-plate-height"); + m_collimatorInfo->m_axisVec = getV3DParamFromIDF("col-axis"); + } +} + +double DiscusMultipleScatteringCorrection::getDoubleParamFromIDF(std::string paramName) { + if (!m_instrument->hasParameter(paramName)) { + throw std::runtime_error("Cannot find parameter:" + paramName + " from instrument parameter file"); + } + std::vector val_vec = m_instrument->getNumberParameter(paramName, true); + if (val_vec.empty()) { + throw std::runtime_error("No value specified for:" + paramName + " in the instrument parameter file"); + } + + return static_cast(val_vec.front()); +} + +Kernel::V3D DiscusMultipleScatteringCorrection::getV3DParamFromIDF(std::string paramName) { + if (!m_instrument->hasParameter(paramName)) { + throw std::runtime_error("Cannot find parameter:" + paramName + " from instrument parameter file"); + } + + std::string paramValStr = m_instrument->getStringParameter(paramName)[0]; + std::vector v3dStrComponent; + boost::split(v3dStrComponent, paramValStr, boost::is_any_of(",")); + if (v3dStrComponent.size() != 3) { + throw std::runtime_error("Invalid number of coordinates given for parameter:" + paramName + + " in instrument parameter file"); + } + std::vector v3dComponents(3); + std::transform(v3dStrComponent.begin(), v3dStrComponent.end(), v3dComponents.begin(), + [](const std::string &str) -> double { return std::stod(str); }); + + return Kernel::V3D(v3dComponents[0], v3dComponents[1], v3dComponents[2]); +} + double DiscusMultipleScatteringCorrection::getKf(const double deltaE, const double kinc) { double kf; if (deltaE == 0.) { @@ -1986,10 +2189,10 @@ void DiscusMultipleScatteringCorrection::prepareSampleBeamGeometry(const API::Ma const auto &envBox = m_env->boundingBox(); m_activeRegion.grow(envBox); } - auto instrument = inputWS->getInstrument(); - m_beamProfile = BeamProfileFactory::createBeamProfile(*instrument, inputWS->sample()); - m_refframe = instrument->getReferenceFrame(); - m_sourcePos = instrument->getSource()->getPos(); + m_instrument = inputWS->getInstrument(); + m_beamProfile = BeamProfileFactory::createBeamProfile(*m_instrument, inputWS->sample()); + m_refframe = m_instrument->getReferenceFrame(); + m_sourcePos = m_instrument->getSource()->getPos(); } } // namespace Mantid::Algorithms diff --git a/Framework/Algorithms/test/DiscusMultipleScatteringCorrectionTest.h b/Framework/Algorithms/test/DiscusMultipleScatteringCorrectionTest.h index cf94ab5a4bdc..80d28a2210a9 100644 --- a/Framework/Algorithms/test/DiscusMultipleScatteringCorrectionTest.h +++ b/Framework/Algorithms/test/DiscusMultipleScatteringCorrectionTest.h @@ -163,6 +163,43 @@ class DiscusMultipleScatteringCorrectionTest : public CxxTest::TestSuite { } } + void test_output_workspaces_with_collimator() { + const double THICKNESS = 0.001; // metres + auto inputWorkspace = SetupFlatPlateWorkspace(46, 1, 1.0, 1, 0.5, 1.0, 10 * THICKNESS, 10 * THICKNESS, THICKNESS); + auto &pmap = inputWorkspace->instrumentParameters(); + Instrument_const_sptr instrument = inputWorkspace->getInstrument(); + pmap.addDouble(instrument.get(), "col-radius", 0.5); + pmap.addDouble(instrument.get(), "col-angular-extent", 0.034); + pmap.addDouble(instrument.get(), "col-plate-height", 0.2); + pmap.addString(instrument.get(), "col-axis", "0,1,0"); + + auto alg = createAlgorithm(); + TS_ASSERT_THROWS_NOTHING(alg->setProperty("InputWorkspace", inputWorkspace)); + const int NSCATTERINGS = 3; + TS_ASSERT_THROWS_NOTHING(alg->setProperty("NumberScatterings", NSCATTERINGS)); + TS_ASSERT_THROWS_NOTHING(alg->setProperty("NeutronPathsSingle", 10)); + TS_ASSERT_THROWS_NOTHING(alg->setProperty("NeutronPathsMultiple", 10)); + TS_ASSERT_THROWS_NOTHING(alg->setProperty("RadialCollimator", true)); + TS_ASSERT_THROWS_NOTHING(alg->execute();); + TS_ASSERT(alg->isExecuted()); + if (alg->isExecuted()) { + auto output = + Mantid::API::AnalysisDataService::Instance().retrieveWS("MuscatResults"); + std::vector wsNames = {"MuscatResults_Scatter_1_NoAbs", "MuscatResults_Scatter_1", + "MuscatResults_Scatter_1_Integrated", "MuscatResults_Scatter_2", + "MuscatResults_Scatter_2_Integrated", "MuscatResults_Scatter_3", + "MuscatResults_Scatter_3_Integrated", "MuscatResults_Scatter_2_3_Summed", + "MuscatResults_Scatter_1_3_Summed", "MuscatResults_Ratio_Single_To_All"}; + for (auto &name : wsNames) { + Mantid::API::Workspace_sptr wsPtr; + TS_ASSERT_THROWS_NOTHING(wsPtr = output->getItem(name)); + auto matrixWsPtr = std::dynamic_pointer_cast(wsPtr); + TS_ASSERT(matrixWsPtr); + } + Mantid::API::AnalysisDataService::Instance().deepRemoveGroup("MuscatResults"); + } + } + void test_flat_plate_sample_single_scatter() { // generate a result corresponding to Figure 4 in the Mancinelli paper (flat // plate sample for once scattered neutrons) where there's an analytical solution diff --git a/buildconfig/CMake/CppCheck_Suppressions.txt.in b/buildconfig/CMake/CppCheck_Suppressions.txt.in index c3006b12b6ff..be03244400a6 100644 --- a/buildconfig/CMake/CppCheck_Suppressions.txt.in +++ b/buildconfig/CMake/CppCheck_Suppressions.txt.in @@ -236,11 +236,10 @@ uninitMemberVarPrivate:${CMAKE_SOURCE_DIR}/Framework/Algorithms/inc/MantidAlgori uninitMemberVarPrivate:${CMAKE_SOURCE_DIR}/Framework/Algorithms/inc/MantidAlgorithms/GetDetectorOffsets.h:60 uselessOverride:${CMAKE_SOURCE_DIR}/Framework/Algorithms/inc/MantidAlgorithms/Logarithm.h:52 shadowVariable:${CMAKE_SOURCE_DIR}/Framework/Algorithms/src/GetDetectorOffsets.cpp:148 -missingOverride:${CMAKE_SOURCE_DIR}/Framework/Algorithms/inc/MantidAlgorithms/DiscusMultipleScatteringCorrection.h:82 +missingOverride:${CMAKE_SOURCE_DIR}/Framework/Algorithms/inc/MantidAlgorithms/DiscusMultipleScatteringCorrection.h:92 constVariableReference:${CMAKE_SOURCE_DIR}/Framework/Algorithms/src/GenerateGoniometerIndependentBackground.cpp:189 returnByReference:${CMAKE_SOURCE_DIR}/Framework/Algorithms/inc/MantidAlgorithms/FitPeak.h:67 returnByReference:${CMAKE_SOURCE_DIR}/Framework/Algorithms/inc/MantidAlgorithms/FitPeak.h:70 -constParameterReference:${CMAKE_SOURCE_DIR}/Framework/Algorithms/src/DiscusMultipleScatteringCorrection.cpp:1354 constParameterReference:${CMAKE_SOURCE_DIR}/Framework/Algorithms/src/GetEiMonDet3.cpp:218 constParameterReference:${CMAKE_SOURCE_DIR}/Framework/Algorithms/src/GetEiMonDet3.cpp:261 shadowVariable:${CMAKE_SOURCE_DIR}/Framework/Algorithms/src/FitPeak.cpp:1410 diff --git a/docs/source/release/v6.11.0/Framework/Algorithms/New_features/35373.rst b/docs/source/release/v6.11.0/Framework/Algorithms/New_features/35373.rst new file mode 100644 index 000000000000..b2e22580d607 --- /dev/null +++ b/docs/source/release/v6.11.0/Framework/Algorithms/New_features/35373.rst @@ -0,0 +1 @@ +- Add support for a radial collimator in :ref:`DiscusMultipleScatteringCorrection ` algorithm that restricts scatter points within a small region within the larger sample volume. The algorithm was modified to assign zero weight to tracks where the final scatter is not in a position that allows the final track segment to pass through the collimator toward detectors. diff --git a/instrument/ENGIN-X_Parameters.xml b/instrument/ENGIN-X_Parameters.xml index 383e5c122c24..dcee4c97742a 100644 --- a/instrument/ENGIN-X_Parameters.xml +++ b/instrument/ENGIN-X_Parameters.xml @@ -115,4 +115,27 @@ the create a distinct ENTITY for each bank--> + + + + + + + + + + + + + + + + + + + + + + +